Neko 1.99.2
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
sponge_source_term.f90
Go to the documentation of this file.
1! Copyright (c) 2025, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
33!
36 use num_types, only : rp, dp, sp
37 use json_module, only : json_file
38 use registry, only : neko_registry
39 use field, only : field_t
41 use utils, only : neko_error
44 use time_state, only : time_state_t
45 use math, only : sub3, col2, add2s2
46 use logger, only : neko_log, neko_log_debug
48 use source_term, only : source_term_t
49 use case, only : case_t
52 use field_list, only : field_list_t
53 use coefs, only : coef_t
54 use utils, only : neko_fname_len
55 use file, only : file_t
57 use comm, only : pe_rank
59 implicit none
60 private
61
62 type, public, extends(source_term_t) :: sponge_source_term_t
63
65 type(field_t), pointer :: u => null()
66 type(field_t), pointer :: v => null()
67 type(field_t), pointer :: w => null()
69 type(field_t), pointer :: u_bf => null()
70 type(field_t), pointer :: v_bf => null()
71 type(field_t), pointer :: w_bf => null()
73 character(len=1024) :: bf_rgstry_pref
75 logical :: baseflow_set = .false.
78 logical :: baseflow_is_ic = .false.
81 type(field_t), pointer :: fringe => null()
83 real(kind=rp) :: amplitudes(3)
85 character(len=1024) :: fringe_registry_name
87 logical :: dump_fields = .false.
89 character(NEKO_FNAME_LEN) :: dump_fname
91 logical :: check = .true.
92 contains
94 procedure, pass(this) :: init => sponge_init_from_json
96 procedure, pass(this) :: init_constant => &
99 procedure, pass(this) :: init_user => &
102 procedure, pass(this) :: init_field => &
105 procedure, pass(this) :: init_common => &
108 procedure, pass(this) :: free => sponge_free
110 procedure, pass(this) :: compute_ => sponge_compute
111 end type sponge_source_term_t
112
113contains
114
116 subroutine sponge_init_from_json(this, json, fields, coef, variable_name)
117 class(sponge_source_term_t), intent(inout) :: this
118 type(json_file), intent(inout) :: json
119 type(field_list_t), intent(in), target :: fields
120 type(coef_t), intent(in), target :: coef
121 character(len=*), intent(in) :: variable_name
122
123 real(kind=rp), allocatable :: amplitudes(:)
124 character(len=:), allocatable :: baseflow_method
125 character(len=:), allocatable :: read_str, fringe_registry_name, &
126 bf_registry_pref, dump_fname
127 character(len=NEKO_FNAME_LEN) :: fname, mesh_fname
128 logical :: interpolate, dump_fields
129 real(kind=rp), allocatable :: constant_value(:)
130 real(kind=rp) :: start_time, end_time, tolerance
131 integer :: nzones
132
133 type(json_file) :: baseflow_subdict
134 integer :: i, izone
135
136 call neko_log%section("SPONGE SOURCE TERM", lvl = neko_log_debug)
137
138 call json_get_or_default(json, "dump_fields", dump_fields, .false.)
139 call json_get_or_default(json, "dump_file_name", dump_fname, &
140 "spng_fields")
141 call json_get_or_default(json, "fringe_registry_name", &
142 fringe_registry_name, "sponge_fringe")
143
144 call json_get(json, "amplitudes", amplitudes)
145 if (size(amplitudes) .ne. 3) then
146 call neko_error("(SPONGE) Expected 3 elements for 'amplitudes'")
147 end if
148
149 call json_get_or_default(json, "start_time", start_time, 0.0_rp)
150 call json_get_or_default(json, "end_time", end_time, huge(0.0_rp))
151
152
153 call json_get(json, 'baseflow', &
154 baseflow_subdict)
155 call json_get(baseflow_subdict, "method", baseflow_method)
156 call json_get_or_default(json, "baseflow_registry_prefix", &
157 bf_registry_pref, "sponge_bf")
158
159 select case (trim(baseflow_method))
160
161 ! Import the base flow from an fld file. The same parameters as field
162 ! initial condition apply since we use the same subroutine to read and
163 ! potentially interpolate from a field file. It would be nice to have
164 ! some kind of `gfldr` function to make this nicer.
165 case ("field")
166
167 ! The lines below are just copy pasted from set_flow_ic_int, because we
168 ! want to make sure to separate the JSON constructor
169 ! sponge_init_from_json and the constructor from attributes
170 ! sponge_init_field.
171 call json_get(baseflow_subdict, 'file_name', read_str)
172 fname = trim(read_str)
173 call json_get_or_default(baseflow_subdict, 'interpolate', interpolate, &
174 .false.)
175 call json_get_or_default(baseflow_subdict, 'tolerance', tolerance, &
176 0.000001_rp)
177 call json_get_or_default(baseflow_subdict, 'mesh_file_name', read_str, &
178 "none")
179 mesh_fname = trim(read_str)
180
181 call this%init_field(fields, coef, start_time, end_time, amplitudes, &
182 fringe_registry_name, bf_registry_pref, dump_fields, dump_fname, &
183 fname, interpolate, tolerance, mesh_fname)
184
185 ! Constant base flow
186 case ("constant")
187
188 call json_get(baseflow_subdict, "value", constant_value)
189 if (size(constant_value) .lt. 3) then
190 call neko_error("(SPONGE) Expected 3 elements for 'value'")
191 end if
192
193 call this%init_constant(fields, coef, start_time, end_time, &
194 amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, &
195 dump_fname, constant_value)
196
197 ! Let the user set the base flow.
198 case ("user")
199
200 call this%init_user(fields, coef, start_time, end_time, amplitudes, &
201 fringe_registry_name, bf_registry_pref, dump_fields, dump_fname)
202
203 case default
204 call neko_error("(SPONGE) " // trim(baseflow_method) // &
205 " is not a valid method")
206 end select
207
208 call neko_log%end_section(lvl = neko_log_debug)
209
210 end subroutine sponge_init_from_json
211
213 subroutine sponge_init_constant(this, fields, coef, start_time, end_time, &
214 amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, &
215 dump_fname, constant_values)
216 class(sponge_source_term_t), intent(inout) :: this
217 type(field_list_t), intent(in), target :: fields
218 type(coef_t), intent(in), target :: coef
219 real(kind=rp), intent(in) :: start_time, end_time
220 real(kind=rp), intent(in) :: amplitudes(:)
221 character(len=*), intent(in) :: fringe_registry_name, dump_fname, &
222 bf_registry_pref
223 logical, intent(in) :: dump_fields
224 real(kind=rp), intent(in) :: constant_values(:)
225
226 !
227 ! Common constructor
228 !
229 call sponge_init_common(this, fields, coef, start_time, end_time, &
230 amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, &
231 dump_fname)
232
233 !
234 ! Create the base flow fields in the registry
235 !
236 call neko_log%message("Initializing bf fields", &
237 lvl = neko_log_debug)
238
239 call neko_registry%add_field(this%u%dof, &
240 trim(bf_registry_pref) // "_u")
241 call neko_registry%add_field(this%v%dof, &
242 trim(bf_registry_pref) // "_v")
243 call neko_registry%add_field(this%w%dof, &
244 trim(bf_registry_pref) // "_w")
245
246 this%u_bf => neko_registry%get_field(trim(bf_registry_pref) // "_u")
247 this%v_bf => neko_registry%get_field(trim(bf_registry_pref) // "_v")
248 this%w_bf => neko_registry%get_field(trim(bf_registry_pref) // "_w")
249
250 !
251 ! Assign constant values
252 !
253 this%u_bf = constant_values(1)
254 this%v_bf = constant_values(2)
255 this%w_bf = constant_values(3)
256
257 this%baseflow_set = .true.
258
259 end subroutine sponge_init_constant
260
262 subroutine sponge_init_field(this, fields, coef, start_time, end_time, &
263 amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, &
264 dump_fname, file_name, interpolate, tolerance, mesh_file_name)
265 class(sponge_source_term_t), intent(inout) :: this
266 type(field_list_t), intent(in), target :: fields
267 type(coef_t), intent(in), target :: coef
268 real(kind=rp), intent(in) :: start_time, end_time
269 real(kind=rp), intent(in) :: amplitudes(:)
270 character(len=*), intent(in) :: fringe_registry_name, dump_fname, &
271 bf_registry_pref
272 logical, intent(in) :: dump_fields
273 character(len=*), intent(in) :: file_name
274 logical, intent(in) :: interpolate
275 real(kind=rp), intent(in) :: tolerance
276 character(len=*), intent(inout) :: mesh_file_name
277
278 type(field_t) :: wk
279 integer :: tmp_index
280
281 !
282 ! Common constructor
283 !
284 call sponge_init_common(this, fields, coef, start_time, end_time, &
285 amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, &
286 dump_fname)
287
288 !
289 ! Create the base flow fields in the registry
290 !
291 call neko_log%message("Initializing bf fields", &
292 lvl = neko_log_debug)
293
294 call neko_registry%add_field(this%u%dof, &
295 trim(bf_registry_pref) // "_u")
296 call neko_registry%add_field(this%v%dof, &
297 trim(bf_registry_pref) // "_v")
298 call neko_registry%add_field(this%w%dof, &
299 trim(bf_registry_pref) // "_w")
300
301 this%u_bf => neko_registry%get_field(trim(bf_registry_pref) // "_u")
302 this%v_bf => neko_registry%get_field(trim(bf_registry_pref) // "_v")
303 this%w_bf => neko_registry%get_field(trim(bf_registry_pref) // "_w")
304
305 !
306 ! Use the initial condition field subroutine to set a field as baseflow
307 !
308
309 ! TODO
310 ! This is a bit awkward, because the init for the source terms occurs
311 ! before the init of the scratch registry.
312 ! So we can't use the scratch registry here.
313 ! call neko_scratch_registry%request_field(wk, tmp_index)
314 call wk%init(this%u%dof)
315
316 call set_flow_ic_fld(this%u_bf, this%v_bf, this%w_bf, wk, &
317 file_name, interpolate, tolerance, mesh_file_name)
318
319 call wk%free()
320
321 if (neko_bcknd_device .eq. 1) then
322 call device_memcpy(this%u_bf%x, this%u_bf%x_d, this%u_bf%size(), &
323 host_to_device, .false.)
324 call device_memcpy(this%v_bf%x, this%v_bf%x_d, this%v_bf%size(), &
325 host_to_device, .false.)
326 call device_memcpy(this%w_bf%x, this%w_bf%x_d, this%w_bf%size(), &
327 host_to_device, .true.)
328 end if
329
330 this%baseflow_set = .true.
331
332 end subroutine sponge_init_field
333
335 subroutine sponge_init_user(this, fields, coef, start_time, end_time, &
336 amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, &
337 dump_fname)
338 class(sponge_source_term_t), intent(inout) :: this
339 type(field_list_t), intent(in), target :: fields
340 type(coef_t), intent(in), target :: coef
341 real(kind=rp), intent(in) :: start_time, end_time
342 real(kind=rp), intent(in) :: amplitudes(:)
343 character(len=*), intent(in) :: fringe_registry_name, dump_fname, &
344 bf_registry_pref
345 logical, intent(in) :: dump_fields
346
347 !
348 ! Common constructor
349 !
350 call sponge_init_common(this, fields, coef, start_time, end_time, &
351 amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, &
352 dump_fname)
353
354 end subroutine sponge_init_user
355
357 subroutine sponge_init_common(this, fields, coef, start_time, end_time, &
358 amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, &
359 dump_fname)
360 class(sponge_source_term_t), intent(inout) :: this
361 type(field_list_t), intent(in), target :: fields
362 type(coef_t), intent(in), target :: coef
363 real(kind=rp), intent(in) :: start_time, end_time
364 real(kind=rp), intent(in) :: amplitudes(:)
365 character(len=*), intent(in) :: fringe_registry_name, dump_fname, &
366 bf_registry_pref
367 logical, intent(in) :: dump_fields
368
369 integer :: i
370
371 call this%free()
372 call this%init_base(fields, coef, start_time, end_time)
373
374 this%amplitudes(1) = amplitudes(1)
375 this%amplitudes(2) = amplitudes(2)
376 this%amplitudes(3) = amplitudes(3)
377
378 this%fringe_registry_name = trim(fringe_registry_name)
379 this%bf_rgstry_pref = trim(bf_registry_pref)
380 this%dump_fields = dump_fields
381 this%dump_fname = trim(dump_fname)
382
383 call neko_log%message("Initializing sponge", lvl = neko_log_debug)
384
385 call neko_log%message("Pointing at fields u,v,w", &
386 lvl = neko_log_debug)
387 this%u => neko_registry%get_field_by_name("u")
388 this%v => neko_registry%get_field_by_name("v")
389 this%w => neko_registry%get_field_by_name("w")
390
391 end subroutine sponge_init_common
392
394 subroutine sponge_free(this)
395 class(sponge_source_term_t), intent(inout) :: this
396
397 call this%free_base()
398
399 nullify(this%u)
400 nullify(this%v)
401 nullify(this%w)
402 nullify(this%u_bf)
403 nullify(this%v_bf)
404 nullify(this%w_bf)
405 nullify(this%fringe)
406
407 this%fringe_registry_name = ""
408 this%bf_rgstry_pref = ""
409 this%baseflow_set = .false.
410
411 end subroutine sponge_free
412
425 subroutine sponge_compute(this, time)
426 class(sponge_source_term_t), intent(inout) :: this
427 type(time_state_t), intent(in) :: time
428
429 integer :: i, nfields
430 type(field_t), pointer :: fu, fv, fw
431
432 type(json_file) :: json_subdict
433 character(len=:), allocatable :: string_val
434
435 character(len=1024) :: u_name, v_name, w_name
436 type(fld_file_output_t) :: fout
437 integer :: tmp_index
438 type(field_t), pointer :: wk
439
440 !
441 ! Do some checks at the first timestep
442 !
443 if (this%check) then
444
445 u_name = trim(this%bf_rgstry_pref) // "_u"
446 v_name = trim(this%bf_rgstry_pref) // "_v"
447 w_name = trim(this%bf_rgstry_pref) // "_w"
448
449 ! Check if all the base flow fields exist in the registry
450 this%baseflow_set = neko_registry%field_exists(trim(u_name)) &
451 .and. neko_registry%field_exists(trim(v_name)) .and. &
452 neko_registry%field_exists(trim(w_name))
453
454 if (.not. this%baseflow_set) then
455 call neko_error("SPONGE: No baseflow set (searching for " // &
456 trim(this%bf_rgstry_pref) // "_u)")
457 end if
458
459 ! Check if the user has added the fringe field in the registry
460 if (.not. neko_registry%field_exists( &
461 trim(this%fringe_registry_name))) then
462 call neko_error("SPONGE: No fringe field set (" // &
463 this%fringe_registry_name // " not found)")
464 end if
465
466 ! This will throw an error if the user hasn't added 'sponge_fringe'
467 ! to the registry.
468 this%fringe => &
469 neko_registry%get_field(trim(this%fringe_registry_name))
470
471 ! This will throw an error if the user hasn't added the base flow fields
472 ! to the registry.
473 this%u_bf => neko_registry%get_field(trim(u_name))
474 this%v_bf => neko_registry%get_field(trim(v_name))
475 this%w_bf => neko_registry%get_field(trim(w_name))
476
477 ! Reset the flag
478 this%check = .false.
479
480 !
481 ! Dump the fringe and/or baseflow fields for visualization
482 !
483 if (this%dump_fields) then
484 call fout%init(sp, trim(this%dump_fname), 4)
485 call fout%fields%assign_to_ptr(1, this%fringe)
486 call fout%fields%assign_to_field(2, this%u_bf)
487 call fout%fields%assign_to_field(3, this%v_bf)
488 call fout%fields%assign_to_field(4, this%w_bf)
489 call fout%sample(time%t)
490 end if
491
492 end if
493
494
495 !
496 ! Start computation of source term
497 !
498
499 fu => this%fields%get(1)
500 fv => this%fields%get(2)
501 fw => this%fields%get(3)
502
503 call neko_scratch_registry%request_field(wk, tmp_index, .false.)
504
505 if (neko_bcknd_device .eq. 1) then
506 ! wk = u_bf - u
507 call device_sub3(wk%x_d, this%u_bf%x_d, this%u%x_d, this%u%size())
508 ! wk = fringe * wk = fringe * (u_bf - u)
509 call device_col2(wk%x_d, this%fringe%x_d, this%fringe%size())
510 ! fu = fu + amplitude(1)*wk = fu + amplitude(1)*fringe*(u_bf - u)
511 call device_add2s2(fu%x_d, wk%x_d, this%amplitudes(1), &
512 fu%dof%size())
513
514 call device_sub3(wk%x_d, this%v_bf%x_d, this%v%x_d, this%v%size())
515 call device_col2(wk%x_d, this%fringe%x_d, this%fringe%size())
516 call device_add2s2(fv%x_d, wk%x_d, this%amplitudes(2), &
517 fv%dof%size())
518
519 call device_sub3(wk%x_d, this%w_bf%x_d, this%w%x_d, this%w%size())
520 call device_col2(wk%x_d, this%fringe%x_d, this%fringe%size())
521 call device_add2s2(fw%x_d, wk%x_d, this%amplitudes(3), &
522 fw%dof%size())
523 else
524 call sub3(wk%x, this%u_bf%x, this%u%x, this%u%size())
525 call col2(wk%x, this%fringe%x, this%fringe%size())
526 call add2s2(fu%x, wk%x, this%amplitudes(1), fu%dof%size())
527
528 call sub3(wk%x, this%v_bf%x, this%v%x, this%v%size())
529 call col2(wk%x, this%fringe%x, this%fringe%size())
530 call add2s2(fv%x, wk%x, this%amplitudes(2), fv%dof%size())
531
532 call sub3(wk%x, this%w_bf%x, this%w%x, this%w%size())
533 call col2(wk%x, this%fringe%x, this%fringe%size())
534 call add2s2(fw%x, wk%x, this%amplitudes(3), fw%dof%size())
535 end if
536
537 call neko_scratch_registry%relinquish_field(tmp_index)
538
539 end subroutine sponge_compute
540
541end module sponge_source_term
Copy data between host and device (or device and device)
Definition device.F90:71
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Retrieves a parameter by name or throws an error.
Defines a simulation case.
Definition case.f90:34
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
integer, public pe_rank
MPI rank.
Definition comm.F90:56
subroutine, public device_sub3(a_d, b_d, c_d, n, strm)
Vector subtraction .
subroutine, public device_add2s2(a_d, b_d, c1, n, strm)
Vector addition with scalar multiplication (multiplication on first argument)
subroutine, public device_col2(a_d, b_d, n, strm)
Vector multiplication .
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:47
Defines a field.
Definition field.f90:34
Module for file I/O operations.
Definition file.f90:34
Implements fld_file_output_t.
Initial flow condition.
Definition flow_ic.f90:34
subroutine, public set_flow_ic_fld(u, v, w, p, file_name, interpolate, tolerance, mesh_file_name)
Set the initial condition of the flow based on a field. @detail The fields are read from an fld file....
Definition flow_ic.f90:411
Utilities for retrieving parameters from the case files.
Logging routines.
Definition log.f90:34
integer, parameter, public neko_log_debug
Debug log level.
Definition log.f90:84
type(log_t), public neko_log
Global log stream.
Definition log.f90:76
Definition math.f90:60
subroutine, public sub3(a, b, c, n)
Vector subtraction .
Definition math.f90:781
subroutine, public col2(a, b, n)
Vector multiplication .
Definition math.f90:854
subroutine, public add2s2(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on second argument)
Definition math.f90:812
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public sp
Definition num_types.f90:8
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines a registry for storing solution fields.
Definition registry.f90:34
type(registry_t), target, public neko_registry
Global field registry.
Definition registry.f90:128
Defines a registry for storing and requesting temporary objects This can be used when you have a func...
type(scratch_registry_t), target, public neko_scratch_registry
Global scratch registry.
Contains the simcomp_executor_t type.
type(simcomp_executor_t), target, public neko_simcomps
Global variable for the simulation component driver.
Implements the source_term_t type and a wrapper source_term_wrapper_t.
Implements the sponge_t type.
subroutine sponge_init_field(this, fields, coef, start_time, end_time, amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, dump_fname, file_name, interpolate, tolerance, mesh_file_name)
Initialize a sponge with a baseflow imported from a field file.
subroutine sponge_init_from_json(this, json, fields, coef, variable_name)
Constructor from json.
subroutine sponge_init_user(this, fields, coef, start_time, end_time, amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, dump_fname)
Initialize a sponge with a baseflow set by the user.
subroutine sponge_free(this)
Destructor.
subroutine sponge_compute(this, time)
Compute the sponge field. The sponge is applied according to the following definition: f_x = amp_x * ...
subroutine sponge_init_constant(this, fields, coef, start_time, end_time, amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, dump_fname, constant_values)
Initialize a sponge with a constant baseflow.
subroutine sponge_init_common(this, fields, coef, start_time, end_time, amplitudes, fringe_registry_name, bf_registry_pref, dump_fields, dump_fname)
Common constructor.
Module with things related to the simulation time.
Utilities.
Definition utils.f90:35
integer, parameter, public neko_fname_len
Definition utils.f90:40
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:56
field_list_t, To be able to group fields together
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition file.f90:55
A simple output saving a list of fields to a .fld file.
Base abstract type for source terms.
A struct that contains all info about the time, expand as needed.