Neko 1.99.1
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
fluid_volflow.f90
Go to the documentation of this file.
1! Copyright (c) 2008-2020, UCHICAGO ARGONNE, LLC.
2! Copyright (c) 2025, The Neko Authors
3!
4! The UChicago Argonne, LLC as Operator of Argonne National
5! Laboratory holds copyright in the Software. The copyright holder
6! reserves all rights except those expressly granted to licensees,
7! and U.S. Government license rights.
8!
9! Redistribution and use in source and binary forms, with or without
10! modification, are permitted provided that the following conditions
11! are met:
12!
13! 1. Redistributions of source code must retain the above copyright
14! notice, this list of conditions and the disclaimer below.
15!
16! 2. Redistributions in binary form must reproduce the above copyright
17! notice, this list of conditions and the disclaimer (as noted below)
18! in the documentation and/or other materials provided with the
19! distribution.
20!
21! 3. Neither the name of ANL nor the names of its contributors
22! may be used to endorse or promote products derived from this software
23! without specific prior written permission.
24!
25! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
29! UCHICAGO ARGONNE, LLC, THE U.S. DEPARTMENT OF
30! ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
32! TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33! DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35! (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37!
38! Additional BSD Notice
39! ---------------------
40! 1. This notice is required to be provided under our contract with
41! the U.S. Department of Energy (DOE). This work was produced at
42! Argonne National Laboratory under Contract
43! No. DE-AC02-06CH11357 with the DOE.
44!
45! 2. Neither the United States Government nor UCHICAGO ARGONNE,
46! LLC nor any of their employees, makes any warranty,
47! express or implied, or assumes any liability or responsibility for the
48! accuracy, completeness, or usefulness of any information, apparatus,
49! product, or process disclosed, or represents that its use would not
50! infringe privately-owned rights.
51!
52! 3. Also, reference herein to any specific commercial products, process,
53! or services by trade name, trademark, manufacturer or otherwise does
54! not necessarily constitute or imply its endorsement, recommendation,
55! or favoring by the United States Government or UCHICAGO ARGONNE LLC.
56! The views and opinions of authors expressed
57! herein do not necessarily state or reflect those of the United States
58! Government or UCHICAGO ARGONNE, LLC, and shall
59! not be used for advertising or product endorsement purposes.
60!
62 use operators, only : opgrad, cdtp
63 use num_types, only : rp
64 use mathops, only : opchsign
65 use krylov, only : ksp_t, ksp_monitor_t
66 use precon, only : pc_t
67 use dofmap, only : dofmap_t
68 use field, only : field_t
69 use coefs, only : coef_t
71 use math, only : copy, glsc2, glmin, glmax, add2
76 use gather_scatter, only : gs_t, gs_op_add
77 use json_module, only : json_file
78 use json_utils, only: json_get
80 use bc_list, only : bc_list_t
81 use ax_product, only : ax_t
83 use mpi_f08, only : mpi_allreduce, mpi_in_place, mpi_sum
84 implicit none
85 private
86
88 type, public :: fluid_volflow_t
89 integer :: flow_dir
90 logical :: avflow
91 real(kind=rp) :: flow_rate
92 real(kind=rp) :: dtlag = 0d0
93 real(kind=rp) :: bdlag = 0d0
94 type(field_t) :: u_vol, v_vol, w_vol, p_vol
95 real(kind=rp) :: domain_length, base_flow
97 type(scratch_registry_t) :: scratch
98 contains
99 procedure, pass(this) :: init => fluid_vol_flow_init
100 procedure, pass(this) :: free => fluid_vol_flow_free
101 procedure, pass(this) :: adjust => fluid_vol_flow
102 procedure, private, pass(this) :: compute => fluid_vol_flow_compute
103 end type fluid_volflow_t
104
105contains
106
107 subroutine fluid_vol_flow_init(this, dm_Xh, params)
108 class(fluid_volflow_t), intent(inout) :: this
109 type(dofmap_t), target, intent(in) :: dm_Xh
110 type(json_file), intent(inout) :: params
111 logical average
112 integer :: direction
113 real(kind=rp) :: rate
114
115 call this%free()
116
117 !Initialize vol_flow (if there is a forced volume flow)
118 call json_get(params, 'case.fluid.flow_rate_force.direction', direction)
119 call json_get(params, 'case.fluid.flow_rate_force.value', rate)
120 call json_get(params, 'case.fluid.flow_rate_force.use_averaged_flow',&
121 average)
122
123 this%flow_dir = direction
124 this%avflow = average
125 this%flow_rate = rate
126
127 if (this%flow_dir .ne. 0) then
128 call this%u_vol%init(dm_xh, 'u_vol')
129 call this%v_vol%init(dm_xh, 'v_vol')
130 call this%w_vol%init(dm_xh, 'w_vol')
131 call this%p_vol%init(dm_xh, 'p_vol')
132 end if
133
134 call this%scratch%init(dm_xh, 3, 1)
135
136 end subroutine fluid_vol_flow_init
137
138 subroutine fluid_vol_flow_free(this)
139 class(fluid_volflow_t), intent(inout) :: this
140
141 call this%u_vol%free()
142 call this%v_vol%free()
143 call this%w_vol%free()
144 call this%p_vol%free()
145
146 call this%scratch%free()
147
148 end subroutine fluid_vol_flow_free
149
153 subroutine fluid_vol_flow_compute(this, u_res, v_res, w_res, p_res, &
154 ext_bdf, gs_Xh, c_Xh, rho, mu, bd, dt, &
155 bclst_dp, bclst_du, bclst_dv, bclst_dw, bclst_vel_res, &
156 Ax_vel, Ax_prs, ksp_prs, ksp_vel, pc_prs, pc_vel, prs_max_iter, vel_max_iter)
157 class(fluid_volflow_t), intent(inout) :: this
158 type(field_t), intent(inout) :: u_res, v_res, w_res, p_res
159 type(coef_t), intent(inout) :: c_Xh
160 type(gs_t), intent(inout) :: gs_Xh
161 type(time_scheme_controller_t), intent(in) :: ext_bdf
162 type(bc_list_t), intent(inout) :: bclst_dp, bclst_du, bclst_dv, bclst_dw
163 type(bc_list_t), intent(inout) :: bclst_vel_res
164 class(ax_t), intent(in) :: Ax_vel
165 class(ax_t), intent(in) :: Ax_prs
166 class(ksp_t), intent(inout) :: ksp_prs, ksp_vel
167 class(pc_t), intent(inout) :: pc_prs, pc_vel
168 real(kind=rp), intent(in) :: bd
169 real(kind=rp), intent(in) :: rho, dt
170 type(field_t) :: mu
171 integer, intent(in) :: vel_max_iter, prs_max_iter
172 integer :: n, i
173 real(kind=rp) :: xlmin, xlmax
174 real(kind=rp) :: ylmin, ylmax
175 real(kind=rp) :: zlmin, zlmax
176 type(ksp_monitor_t) :: ksp_results(4)
177 type(field_t), pointer :: ta1, ta2, ta3
178 integer :: temp_indices(3)
179
180 call this%scratch%request_field(ta1, temp_indices(1))
181 call this%scratch%request_field(ta2, temp_indices(2))
182 call this%scratch%request_field(ta3, temp_indices(3))
183
184
185 associate(msh => c_xh%msh, p_vol => this%p_vol, &
186 u_vol => this%u_vol, v_vol => this%v_vol, w_vol => this%w_vol)
187
188 n = c_xh%dof%size()
189 xlmin = glmin(c_xh%dof%x, n)
190 xlmax = glmax(c_xh%dof%x, n)
191 ylmin = glmin(c_xh%dof%y, n) ! for Y!
192 ylmax = glmax(c_xh%dof%y, n)
193 zlmin = glmin(c_xh%dof%z, n) ! for Z!
194 zlmax = glmax(c_xh%dof%z, n)
195 if (this%flow_dir .eq. 1) then
196 this%domain_length = xlmax - xlmin
197 end if
198 if (this%flow_dir .eq. 2) then
199 this%domain_length = ylmax - ylmin
200 end if
201 if (this%flow_dir .eq. 3) then
202 this%domain_length = zlmax - zlmin
203 end if
204
205 if (neko_bcknd_device .eq. 1) then
206 call device_cfill(c_xh%h1_d, 1.0_rp/rho, n)
207 call device_rzero(c_xh%h2_d, n)
208 else
209 do i = 1, n
210 c_xh%h1(i,1,1,1) = 1.0_rp / rho
211 c_xh%h2(i,1,1,1) = 0.0_rp
212 end do
213 end if
214 c_xh%ifh2 = .false.
215
216 ! Compute pressure
217
218 if (this%flow_dir .eq. 1) then
219 call cdtp(p_res%x, c_xh%h1, c_xh%drdx, c_xh%dsdx, c_xh%dtdx, c_xh)
220 end if
221
222 if (this%flow_dir .eq. 2) then
223 call cdtp(p_res%x, c_xh%h1, c_xh%drdy, c_xh%dsdy, c_xh%dtdy, c_xh)
224 end if
225
226 if (this%flow_dir .eq. 3) then
227 call cdtp(p_res%x, c_xh%h1, c_xh%drdz, c_xh%dsdz, c_xh%dtdz, c_xh)
228 end if
229
230 call gs_xh%op(p_res, gs_op_add)
231 call bclst_dp%apply_scalar(p_res%x, n)
232 call pc_prs%update()
233 ksp_results(1) = ksp_prs%solve(ax_prs, p_vol, p_res%x, n, &
234 c_xh, bclst_dp, gs_xh, prs_max_iter)
235
236 ! Compute velocity
237
238 call opgrad(u_res%x, v_res%x, w_res%x, p_vol%x, c_xh)
239
240 if (neko_bcknd_device .eq. 1) then
241 call device_opchsign(u_res%x_d, v_res%x_d, w_res%x_d, msh%gdim, n)
242 call device_copy(ta1%x_d, c_xh%B_d, n)
243 call device_copy(ta2%x_d, c_xh%B_d, n)
244 call device_copy(ta3%x_d, c_xh%B_d, n)
245 else
246 call opchsign(u_res%x, v_res%x, w_res%x, msh%gdim, n)
247 call copy(ta1%x, c_xh%B, n)
248 call copy(ta2%x, c_xh%B, n)
249 call copy(ta3%x, c_xh%B, n)
250 end if
251 call bclst_vel_res%apply_vector(ta1%x, ta2%x, ta3%x, n)
252
253 ! add forcing
254
255 if (neko_bcknd_device .eq. 1) then
256 if (this%flow_dir .eq. 1) then
257 call device_add2(u_res%x_d, ta1%x_d, n)
258 else if (this%flow_dir .eq. 2) then
259 call device_add2(v_res%x_d, ta2%x_d, n)
260 else if (this%flow_dir .eq. 3) then
261 call device_add2(w_res%x_d, ta3%x_d, n)
262 end if
263 else
264 if (this%flow_dir .eq. 1) then
265 call add2(u_res%x, ta1%x, n)
266 else if (this%flow_dir .eq. 2) then
267 call add2(v_res%x, ta2%x, n)
268 else if (this%flow_dir .eq. 3) then
269 call add2(w_res%x, ta3%x, n)
270 end if
271 end if
272
273 if (neko_bcknd_device .eq. 1) then
274 call device_copy(c_xh%h1_d, mu%x_d, n)
275 call device_cfill(c_xh%h2_d, rho * (bd / dt), n)
276 else
277 call copy(c_xh%h1, mu%x, n)
278 c_xh%h2 = rho * (bd / dt)
279 end if
280 c_xh%ifh2 = .true.
281
282 call gs_xh%op(u_res, gs_op_add)
283 call gs_xh%op(v_res, gs_op_add)
284 call gs_xh%op(w_res, gs_op_add)
285
286 call bclst_vel_res%apply_vector(u_res%x, v_res%x, w_res%x, n)
287 call pc_vel%update()
288
289 ksp_results(2:4) = ksp_vel%solve_coupled(ax_vel, &
290 u_vol, v_vol, w_vol, &
291 u_res%x, v_res%x, w_res%x, &
292 n, c_xh, &
293 bclst_du, bclst_dv, bclst_dw, &
294 gs_xh, vel_max_iter)
295
296 if (neko_bcknd_device .eq. 1) then
297 if (this%flow_dir .eq. 1) then
298 this%base_flow = &
299 device_glsc2(u_vol%x_d, c_xh%B_d, n) / this%domain_length
300 end if
301
302 if (this%flow_dir .eq. 2) then
303 this%base_flow = &
304 device_glsc2(v_vol%x_d, c_xh%B_d, n) / this%domain_length
305 end if
306
307 if (this%flow_dir .eq. 3) then
308 this%base_flow = &
309 device_glsc2(w_vol%x_d, c_xh%B_d, n) / this%domain_length
310 end if
311 else
312 if (this%flow_dir .eq. 1) then
313 this%base_flow = glsc2(u_vol%x, c_xh%B, n) / this%domain_length
314 end if
315
316 if (this%flow_dir .eq. 2) then
317 this%base_flow = glsc2(v_vol%x, c_xh%B, n) / this%domain_length
318 end if
319
320 if (this%flow_dir .eq. 3) then
321 this%base_flow = glsc2(w_vol%x, c_xh%B, n) / this%domain_length
322 end if
323 end if
324 end associate
325
326 call this%scratch%relinquish_field(temp_indices)
327 end subroutine fluid_vol_flow_compute
328
338 subroutine fluid_vol_flow(this, u, v, w, p, u_res, v_res, w_res, p_res, &
339 c_Xh, gs_Xh, ext_bdf, rho, mu, dt, &
340 bclst_dp, bclst_du, bclst_dv, bclst_dw, bclst_vel_res, &
341 Ax_vel, Ax_prs, ksp_prs, ksp_vel, pc_prs, pc_vel, prs_max_iter, vel_max_iter)
342
343 class(fluid_volflow_t), intent(inout) :: this
344 type(field_t), intent(inout) :: u, v, w, p
345 type(field_t), intent(inout) :: u_res, v_res, w_res, p_res
346 type(coef_t), intent(inout) :: c_Xh
347 type(gs_t), intent(inout) :: gs_Xh
348 type(time_scheme_controller_t), intent(in) :: ext_bdf
349 real(kind=rp), intent(in) :: rho, dt
350 type(field_t) :: mu
351 type(bc_list_t), intent(inout) :: bclst_dp, bclst_du, bclst_dv, bclst_dw
352 type(bc_list_t), intent(inout) :: bclst_vel_res
353 class(ax_t), intent(in) :: Ax_vel
354 class(ax_t), intent(in) :: Ax_prs
355 class(ksp_t), intent(inout) :: ksp_prs, ksp_vel
356 class(pc_t), intent(inout) :: pc_prs, pc_vel
357 integer, intent(in) :: prs_max_iter, vel_max_iter
358 real(kind=rp) :: ifcomp, flow_rate, xsec
359 real(kind=rp) :: current_flow, delta_flow, scale
360 integer :: n, ierr, i
361
362 associate(u_vol => this%u_vol, v_vol => this%v_vol, &
363 w_vol => this%w_vol, p_vol => this%p_vol)
364
365 n = c_xh%dof%size()
366
367 ! If either dt or the backwards difference coefficient change,
368 ! then recompute base flow solution corresponding to unit forcing:
369
370 ifcomp = 0.0_rp
371
372 if (dt .ne. this%dtlag .or. &
373 ext_bdf%diffusion_coeffs(1) .ne. this%bdlag) then
374 ifcomp = 1.0_rp
375 end if
376
377 this%dtlag = dt
378 this%bdlag = ext_bdf%diffusion_coeffs(1)
379
380 call mpi_allreduce(mpi_in_place, ifcomp, 1, &
381 mpi_real_precision, mpi_sum, neko_comm, ierr)
382
383 if (ifcomp .gt. 0d0) then
384 call this%compute(u_res, v_res, w_res, p_res, &
385 ext_bdf, gs_xh, c_xh, rho, mu, ext_bdf%diffusion_coeffs(1), dt, &
386 bclst_dp, bclst_du, bclst_dv, bclst_dw, bclst_vel_res, &
387 ax_vel, ax_prs, ksp_prs, ksp_vel, pc_prs, pc_vel, prs_max_iter, &
388 vel_max_iter)
389 end if
390
391 if (neko_bcknd_device .eq. 1) then
392 if (this%flow_dir .eq. 1) then
393 current_flow = &
394 device_glsc2(u%x_d, c_xh%B_d, n) / this%domain_length ! for X
395 else if (this%flow_dir .eq. 2) then
396 current_flow = &
397 device_glsc2(v%x_d, c_xh%B_d, n) / this%domain_length ! for Y
398 else if (this%flow_dir .eq. 3) then
399 current_flow = &
400 device_glsc2(w%x_d, c_xh%B_d, n) / this%domain_length ! for Z
401 end if
402 else
403 if (this%flow_dir .eq. 1) then
404 current_flow = glsc2(u%x, c_xh%B, n) / this%domain_length ! for X
405 else if (this%flow_dir .eq. 2) then
406 current_flow = glsc2(v%x, c_xh%B, n) / this%domain_length ! for Y
407 else if (this%flow_dir .eq. 3) then
408 current_flow = glsc2(w%x, c_xh%B, n) / this%domain_length ! for Z
409 end if
410 end if
411
412 if (this%avflow) then
413 xsec = c_xh%volume / this%domain_length
414 flow_rate = this%flow_rate*xsec
415 else
416 flow_rate = this%flow_rate
417 end if
418
419 delta_flow = flow_rate - current_flow
420 scale = delta_flow / this%base_flow
421
422 if (neko_bcknd_device .eq. 1) then
423 call device_add2s2(u%x_d, u_vol%x_d, scale, n)
424 call device_add2s2(v%x_d, v_vol%x_d, scale, n)
425 call device_add2s2(w%x_d, w_vol%x_d, scale, n)
426 call device_add2s2(p%x_d, p_vol%x_d, scale, n)
427 else
428 do concurrent(i = 1: n)
429 u%x(i,1,1,1) = u%x(i,1,1,1) + scale * u_vol%x(i,1,1,1)
430 v%x(i,1,1,1) = v%x(i,1,1,1) + scale * v_vol%x(i,1,1,1)
431 w%x(i,1,1,1) = w%x(i,1,1,1) + scale * w_vol%x(i,1,1,1)
432 p%x(i,1,1,1) = p%x(i,1,1,1) + scale * p_vol%x(i,1,1,1)
433 end do
434 end if
435 end associate
436
437 end subroutine fluid_vol_flow
438
439
440end module fluid_volflow
Retrieves a parameter by name or throws an error.
Defines a Matrix-vector product.
Definition ax.f90:34
Defines a list of bc_t.
Definition bc_list.f90:34
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
Definition comm.F90:50
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:42
subroutine, public device_add2s2(a_d, b_d, c1, n, strm)
Vector addition with scalar multiplication (multiplication on first argument)
subroutine, public device_add2(a_d, b_d, n, strm)
Vector addition .
subroutine, public device_rzero(a_d, n, strm)
Zero a real vector.
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
real(kind=rp) function, public device_glsc2(a_d, b_d, n, strm)
Weighted inner product .
subroutine, public device_cfill(a_d, c, n, strm)
Set all elements to a constant c .
subroutine, public device_opchsign(a1_d, a2_d, a3_d, gdim, n)
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Defines a field.
Definition field.f90:34
subroutine fluid_vol_flow(this, u, v, w, p, u_res, v_res, w_res, p_res, c_xh, gs_xh, ext_bdf, rho, mu, dt, bclst_dp, bclst_du, bclst_dv, bclst_dw, bclst_vel_res, ax_vel, ax_prs, ksp_prs, ksp_vel, pc_prs, pc_vel, prs_max_iter, vel_max_iter)
Adjust flow volume.
subroutine fluid_vol_flow_init(this, dm_xh, params)
subroutine fluid_vol_flow_compute(this, u_res, v_res, w_res, p_res, ext_bdf, gs_xh, c_xh, rho, mu, bd, dt, bclst_dp, bclst_du, bclst_dv, bclst_dw, bclst_vel_res, ax_vel, ax_prs, ksp_prs, ksp_vel, pc_prs, pc_vel, prs_max_iter, vel_max_iter)
Compute flow adjustment.
subroutine fluid_vol_flow_free(this)
Gather-scatter.
Utilities for retrieving parameters from the case files.
Implements the base abstract type for Krylov solvers plus helper types.
Definition krylov.f90:34
Definition math.f90:60
real(kind=rp) function, public glsc2(a, b, n)
Weighted inner product .
Definition math.f90:1007
subroutine, public add2(a, b, n)
Vector addition .
Definition math.f90:732
real(kind=rp) function, public glmax(a, n)
Max of a vector of length n.
Definition math.f90:522
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:255
real(kind=rp) function, public glmin(a, n)
Min of a vector of length n.
Definition math.f90:552
Collection of vector field operations operating on and . Note that in general the indices and ....
Definition mathops.f90:65
subroutine, public opchsign(a1, a2, a3, gdim, n)
for and .
Definition mathops.f90:76
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Operators.
Definition operators.f90:34
subroutine, public opgrad(ux, uy, uz, u, coef, es, ee)
Compute the weak gradient of a scalar field, i.e. the gradient multiplied by the mass matrix.
subroutine, public cdtp(dtx, x, dr, ds, dt, coef, es, ee)
Apply D^T to a scalar field, where D is the derivative matrix.
Krylov preconditioner.
Definition precon.f90:34
Defines a registry for storing and requesting temporary fields This can be used when you have a funct...
Compound scheme for the advection and diffusion operators in a transport equation.
Base type for a matrix-vector product providing .
Definition ax.f90:43
A list of allocatable `bc_t`. Follows the standard interface of lists.
Definition bc_list.f90:48
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:55
Type for storing initial and final residuals in a Krylov solver.
Definition krylov.f90:56
Base abstract type for a canonical Krylov method, solving .
Definition krylov.f90:73
Defines a canonical Krylov preconditioner.
Definition precon.f90:40
Implements the logic to compute the time coefficients for the advection and diffusion operators in a ...