Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
fluid_pnpn_bc_fctry.f90
Go to the documentation of this file.
1
2! Copyright (c) 2024-2026, The Neko Authors
3! All rights reserved.
4!
5! Redistribution and use in source and binary forms, with or without
6! modification, are permitted provided that the following conditions
7! are met:
8!
9! * Redistributions of source code must retain the above copyright
10! notice, this list of conditions and the following disclaimer.
11!
12! * Redistributions in binary form must reproduce the above
13! copyright notice, this list of conditions and the following
14! disclaimer in the documentation and/or other materials provided
15! with the distribution.
16!
17! * Neither the name of the authors nor the names of its
18! contributors may be used to endorse or promote products derived
19! from this software without specific prior written permission.
20!
21! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32! POSSIBILITY OF SUCH DAMAGE.
33!
36submodule(fluid_pnpn) fluid_pnpn_bc_fctry
37 ! We explicitly import all necessary modules to work around an ifx 2026.1
38 ! internal compiler error even when they are only available through the
39 ! parent. Generic interfaces (neko_error, json_get, json_file, ...) are the
40 ! exception, since gfortran rejects importing them a second time, so they
41 ! are only accessed through the parent.
44 use user_intf, only : user_t
46 use json_module, only : json_array
47 use neumann, only : neumann_t
49 use inflow, only : inflow_t
50 use blasius, only : blasius_t
51 use dirichlet, only : dirichlet_t
54 use symmetry, only : symmetry_t
56 use non_normal, only : non_normal_t
57 use no_slip, only : no_slip_t
66 implicit none
67
72 type :: fluid_pnpn_bc_preset_t
73 character(len=25) :: name
74 character(len=25) :: velocity
75 character(len=25) :: pressure
76 end type fluid_pnpn_bc_preset_t
77
82 type(fluid_pnpn_bc_preset_t), parameter :: FLUID_PNPN_BC_PRESETS(17) = [ &
83 fluid_pnpn_bc_preset_t("symmetry", "symmetry", ""), &
84 fluid_pnpn_bc_preset_t("velocity_value", "dirichlet", ""), &
85 fluid_pnpn_bc_preset_t("expression_velocity", "expression", ""), &
86 fluid_pnpn_bc_preset_t("expression_pressure", "", "expression"), &
87 fluid_pnpn_bc_preset_t("no_slip", "no_slip", ""), &
88 fluid_pnpn_bc_preset_t("outflow", "", "zero_dirichlet"), &
89 fluid_pnpn_bc_preset_t("normal_outflow", "non_normal", &
90 "zero_dirichlet"), &
91 fluid_pnpn_bc_preset_t("outflow+user", "", "user_dirichlet"), &
92 fluid_pnpn_bc_preset_t("normal_outflow+user", "non_normal", &
93 "user_dirichlet"), &
94 fluid_pnpn_bc_preset_t("outflow+dong", "", "dong"), &
95 fluid_pnpn_bc_preset_t("normal_outflow+dong", "non_normal", "dong"), &
96 fluid_pnpn_bc_preset_t("shear_stress", "shear_stress", ""), &
97 fluid_pnpn_bc_preset_t("user_velocity", "user_dirichlet", ""), &
98 fluid_pnpn_bc_preset_t("user_pressure", "", "user_dirichlet"), &
99 fluid_pnpn_bc_preset_t("blasius_profile", "blasius_profile", ""), &
100 fluid_pnpn_bc_preset_t("wall_model", "wall_model", ""), &
101 fluid_pnpn_bc_preset_t("overset_interface", "overset_interface", &
102 "overset_interface")]
103
105 character(len=25), parameter :: FLUID_PNPN_VELOCITY_BCS(11) = [ &
106 character(len=25) :: &
107 "dirichlet", &
108 "expression", &
109 "no_slip", &
110 "symmetry", &
111 "non_normal", &
112 "neumann", &
113 "shear_stress", &
114 "wall_model", &
115 "blasius_profile", &
116 "user_dirichlet", &
117 "overset_interface"]
118
120 character(len=25), parameter :: FLUID_PNPN_PRESSURE_BCS(7) = [ &
121 character(len=25) :: &
122 "dirichlet", &
123 "zero_dirichlet", &
124 "expression", &
125 "dong", &
126 "neumann", &
127 "user_dirichlet", &
128 "overset_interface"]
129
130contains
131
144 module subroutine fluid_pnpn_bc_split(json, velocity_json, pressure_json, &
145 has_velocity, has_pressure)
146 type(json_file), intent(inout) :: json
147 type(json_file), intent(inout) :: velocity_json
148 type(json_file), intent(inout) :: pressure_json
149 logical, intent(out) :: has_velocity
150 logical, intent(out) :: has_pressure
151 character(len=:), allocatable :: type
152 character(len=25) :: velocity_type, pressure_type
153 logical :: couple_pressure
154 integer :: i
155
156 velocity_type = ""
157 pressure_type = ""
158 has_velocity = json%valid_path("velocity")
159 has_pressure = json%valid_path("pressure")
160
161 if (json%valid_path("type")) then
162 if (has_velocity .or. has_pressure) then
163 call neko_error("A fluid boundary condition cannot have both a " // &
164 "'type' keyword and a 'velocity' or 'pressure' object.")
165 end if
166
167 call json_get(json, "type", type)
168
169 do i = 1, size(fluid_pnpn_bc_presets)
170 if (trim(type) .eq. trim(fluid_pnpn_bc_presets(i)%name)) exit
171 end do
172
173 if (i .gt. size(fluid_pnpn_bc_presets)) then
174 call neko_type_error("fluid_pnpn boundary conditions", type, &
175 FLUID_PNPN_BC_PRESETS%name)
176 end if
177
178 velocity_type = fluid_pnpn_bc_presets(i)%velocity
179 pressure_type = fluid_pnpn_bc_presets(i)%pressure
180
181 ! The overset interface only constrains the pressure on request.
182 if (trim(type) .eq. "overset_interface") then
183 call json_get_or_default(json, "couple_pressure", couple_pressure, &
184 .false.)
185 if (.not. couple_pressure) pressure_type = ""
186 end if
187
188 has_velocity = len_trim(velocity_type) .gt. 0
189 has_pressure = len_trim(pressure_type) .gt. 0
190 else if (.not. (has_velocity .and. has_pressure)) then
191 call neko_error("A fluid boundary condition needs either a 'type' " // &
192 "keyword, or both a 'velocity' and a 'pressure' object.")
193 end if
194
195 if (has_velocity) then
196 call fluid_pnpn_bc_extract_part(json, "velocity", velocity_type, &
197 velocity_json)
198 end if
199
200 if (has_pressure) then
201 call fluid_pnpn_bc_extract_part(json, "pressure", pressure_type, &
202 pressure_json)
203 end if
204 end subroutine fluid_pnpn_bc_split
205
216 subroutine fluid_pnpn_bc_extract_part(entry, key, preset_type, part)
217 type(json_file), intent(inout) :: entry
218 character(len=*), intent(in) :: key
219 character(len=*), intent(in) :: preset_type
220 type(json_file), intent(inout) :: part
221 type(json_core) :: core
222 type(json_value), pointer :: root, sub, child, existing, child_clone
223 character(len=:), allocatable :: buffer, child_name
224 logical :: found
225 integer :: i, n
226
227 ! Start from an independent copy of the entry
228 call entry%print_to_string(buffer)
229 call part%destroy()
230 call part%initialize(strict_type_checking = .true.)
231 call part%load_from_string(buffer)
232
233 ! Retain only the top-level stuff like the zone indices
234 call part%remove("type")
235 call part%remove("velocity")
236 call part%remove("pressure")
237
238 if (len_trim(preset_type) .gt. 0) then
239 call part%add("type", trim(preset_type))
240 end if
241
242 ! The sub-object is read from the unmodified entry, not from the copy.
243 call entry%get(key, sub, found)
244 if (found) then
245 call part%get_core(core)
246 call part%get(root)
247 n = core%count(sub)
248 do i = 1, n
249 call core%get_child(sub, i, child, found)
250 call core%info(child, name = child_name)
251
252 call core%get_child(root, child_name, existing, found)
253 if (found) call core%remove(existing, destroy = .true.)
254
255 nullify(child_clone)
256 call core%clone(child, child_clone)
257 call core%add(root, child_clone)
258 end do
259 end if
260 end subroutine fluid_pnpn_bc_extract_part
261
268 module subroutine fluid_pnpn_velocity_bc_allocator(object, type_name, &
269 full_stress_formulation)
270 class(bc_t), pointer, intent(inout) :: object
271 character(len=*), intent(in) :: type_name
272 logical, intent(in) :: full_stress_formulation
273 integer :: i
274
275 if (associated(object)) then
276 call object%free()
277 deallocate(object)
278 end if
279
280 select case (trim(type_name))
281 case ("dirichlet")
282 allocate(inflow_t::object)
283 case ("expression")
284 allocate(expression_dirichlet_vector_t::object)
285 case ("neumann")
286 allocate(neumann_t::object)
287 case ("no_slip")
288 allocate(no_slip_t::object)
289 case ("symmetry")
290 if (full_stress_formulation) then
291 allocate(symmetry_t::object)
292 else
293 allocate(symmetry_aligned_t::object)
294 end if
295 case ("non_normal")
296 if (full_stress_formulation) then
297 allocate(non_normal_t::object)
298 else
299 allocate(non_normal_aligned_t::object)
300 end if
301 case ("shear_stress")
302 allocate(shear_stress_t::object)
303 case ("wall_model")
304 allocate(wall_model_bc_t::object)
305 case ("blasius_profile")
306 allocate(blasius_t::object)
307 case ("user_dirichlet")
308 allocate(field_dirichlet_vector_t::object)
309 case ("overset_interface")
310 allocate(overset_interface_vector_t::object)
311 case default
312 do i = 1, fluid_pnpn_velocity_bc_registry_size
313 if (trim(type_name) .eq. &
314 trim(fluid_pnpn_velocity_bc_registry(i)%type_name)) then
315 call fluid_pnpn_velocity_bc_registry(i)%allocator(object)
316 return
317 end if
318 end do
319
320 call neko_type_error("fluid_pnpn velocity boundary conditions", &
321 type_name, fluid_pnpn_velocity_bcs)
322 end select
323 end subroutine fluid_pnpn_velocity_bc_allocator
324
328 module subroutine fluid_pnpn_pressure_bc_allocator(object, type_name)
329 class(bc_t), pointer, intent(inout) :: object
330 character(len=*), intent(in) :: type_name
331 integer :: i
332
333 if (associated(object)) then
334 call object%free()
335 deallocate(object)
336 end if
337
338 select case (trim(type_name))
339 case ("dirichlet")
340 allocate(dirichlet_t::object)
341 case ("zero_dirichlet")
342 allocate(zero_dirichlet_t::object)
343 case ("expression")
344 allocate(expression_dirichlet_t::object)
345 case ("dong")
346 allocate(dong_outflow_t::object)
347 case ("user_dirichlet")
348 allocate(field_dirichlet_t::object)
349 case ("overset_interface")
350 allocate(overset_interface_t::object)
351 case default
352 do i = 1, fluid_pnpn_pressure_bc_registry_size
353 if (trim(type_name) .eq. &
354 trim(fluid_pnpn_pressure_bc_registry(i)%type_name)) then
355 call fluid_pnpn_pressure_bc_registry(i)%allocator(object)
356 return
357 end if
358 end do
359
360 call neko_type_error("fluid_pnpn pressure boundary conditions", &
361 type_name, fluid_pnpn_pressure_bcs)
362 end select
363 end subroutine fluid_pnpn_pressure_bc_allocator
364
370 module subroutine register_fluid_pnpn_velocity_bc(type_name, allocator)
371 character(len=*), intent(in) :: type_name
372 procedure(fluid_pnpn_bc_allocate), pointer, intent(in) :: allocator
373
374 call fluid_pnpn_bc_register(fluid_pnpn_velocity_bc_registry, &
375 fluid_pnpn_velocity_bc_registry_size, fluid_pnpn_velocity_bcs, &
376 "fluid_pnpn velocity boundary condition", type_name, allocator)
377 end subroutine register_fluid_pnpn_velocity_bc
378
384 module subroutine register_fluid_pnpn_pressure_bc(type_name, allocator)
385 character(len=*), intent(in) :: type_name
386 procedure(fluid_pnpn_bc_allocate), pointer, intent(in) :: allocator
387
388 call fluid_pnpn_bc_register(fluid_pnpn_pressure_bc_registry, &
389 fluid_pnpn_pressure_bc_registry_size, fluid_pnpn_pressure_bcs, &
390 "fluid_pnpn pressure boundary condition", type_name, allocator)
391 end subroutine register_fluid_pnpn_pressure_bc
392
401 subroutine fluid_pnpn_bc_register(registry, registry_size, known_bcs, &
402 base_type, type_name, allocator)
403 type(fluid_pnpn_bc_allocator_entry), allocatable, intent(inout) :: &
404 registry(:)
405 integer, intent(inout) :: registry_size
406 character(len=*), intent(in) :: known_bcs(:)
407 character(len=*), intent(in) :: base_type
408 character(len=*), intent(in) :: type_name
409 procedure(fluid_pnpn_bc_allocate), pointer, intent(in) :: allocator
410 type(fluid_pnpn_bc_allocator_entry), allocatable :: temp(:)
411 integer :: i
412
413 do i = 1, size(known_bcs)
414 if (trim(type_name) .eq. trim(known_bcs(i))) then
415 call neko_type_registration_error(base_type, type_name, .true.)
416 end if
417 end do
418
419 do i = 1, registry_size
420 if (trim(type_name) .eq. trim(registry(i)%type_name)) then
421 call neko_type_registration_error(base_type, type_name, .false.)
422 end if
423 end do
424
425 if (registry_size .eq. 0) then
426 allocate(registry(1))
427 else
428 allocate(temp(registry_size + 1))
429 temp(1:registry_size) = registry
430 call move_alloc(temp, registry)
431 end if
432
433 registry_size = registry_size + 1
434 registry(registry_size)%type_name = type_name
435 registry(registry_size)%allocator => allocator
436 end subroutine fluid_pnpn_bc_register
437
450 module subroutine pressure_bc_factory(object, scheme, json, coef, user)
451 class(bc_t), pointer, intent(inout) :: object
452 type(fluid_pnpn_t), intent(in) :: scheme
453 type(json_file), intent(inout) :: json
454 type(coef_t), target, intent(in) :: coef
455 type(user_t), target, intent(in) :: user
456 character(len=:), allocatable :: type
457 integer :: i
458 integer, allocatable :: zone_indices(:)
459 character(len=:), allocatable :: default_name
460 character(len=64) :: buf
461
462 call json_get(json, "type", type)
463
464 if (trim(type) .eq. "neumann") then
465 ! The flux is set by the scheme and is not a user input.
466 if (json%valid_path("flux")) then
467 call neko_error("The 'neumann' pressure boundary condition " // &
468 "does not accept a 'flux' keyword, the flux is set by the " // &
469 "scheme.")
470 end if
471
472 if (associated(object)) then
473 call object%free()
474 deallocate(object)
475 end if
476 return
477 end if
478
479 call fluid_pnpn_pressure_bc_allocator(object, type)
480
481 select case (trim(type))
482 case ("user_dirichlet")
483 select type (obj => object)
484 type is (field_dirichlet_t)
485 obj%update => user%dirichlet_conditions
486 call json%add("field_name", scheme%p%name)
487 end select
488 case ("overset_interface")
489 select type (obj => object)
490 type is (overset_interface_t)
491 call json%add("field_name", scheme%p%name)
492 obj%morph_interface => user%morph_interface
493 end select
494 end select
495
496 call json_get_or_lookup(json, "zone_indices", zone_indices)
497 call object%init(coef, json)
498
499 do i = 1, size(zone_indices)
500 call object%mark_labeled_zone(zone_indices(i))
501 end do
502
503 write(buf, '("pressure_bc_", I0)') zone_indices(1)
504 default_name = trim(buf)
505 call json_get_or_default(json, "name", object%name, default_name)
506 object%zone_indices = zone_indices
507 call object%finalize()
508
509 deallocate(type)
510 deallocate(zone_indices)
511 deallocate(default_name)
512 end subroutine pressure_bc_factory
513
527 module subroutine velocity_bc_factory(object, scheme, json, coef, user)
528 class(bc_t), pointer, intent(inout) :: object
529 type(fluid_pnpn_t), intent(in) :: scheme
530 type(json_file), intent(inout) :: json
531 type(coef_t), target, intent(in) :: coef
532 type(user_t), target, intent(in) :: user
533 character(len=:), allocatable :: type
534 integer :: i
535 integer, allocatable :: zone_indices(:)
536 character(len=:), allocatable :: default_name
537 character(len=:), allocatable :: bc_name
538 character(len=64) :: buf
539 integer :: var_type, n_children
540
541 call json_get(json, "type", type)
542
543 if (trim(type) .eq. "neumann") then
544 if (.not. json%valid_path("flux")) then
545 if (associated(object)) then
546 call object%free()
547 deallocate(object)
548 end if
549 return
550 end if
551
552 ! neumann_t applies the flux component-wise to a vector, so a scalar
553 ! flux is not enough.
554 call json%info("flux", var_type = var_type, n_children = n_children)
555 if (var_type .ne. json_array .or. n_children .ne. 3) then
556 call neko_error("The 'flux' of the 'neumann' velocity boundary " // &
557 "condition must be an array of 3 reals.")
558 end if
559 end if
560
561 call fluid_pnpn_velocity_bc_allocator(object, type, &
562 scheme%full_stress_formulation)
563
564 select case (trim(type))
565 case ("wall_model")
566 ! Kind of hack, but OK for now
567 call json%add("scheme_name", scheme%name)
568
569 select type (wall_bc => object)
570 type is (wall_model_bc_t)
571 wall_bc%user => user
572 end select
573 case ("user_dirichlet")
574 select type (obj => object)
576 obj%update => user%dirichlet_conditions
577 end select
578 case ("overset_interface")
579 select type (obj => object)
581 obj%morph_interface => user%morph_interface
582 end select
583 end select
584
585 call json_get_or_lookup(json, "zone_indices", zone_indices)
586 write(buf,'("velocity_bc_",I0)') zone_indices(1)
587 default_name = trim(buf)
588 call json_get_or_default(json, "name", bc_name, default_name)
589
590 call object%init(coef, json)
591 do i = 1, size(zone_indices)
592 call object%mark_labeled_zone(zone_indices(i))
593 end do
594
595 object%name = bc_name
596 object%zone_indices = zone_indices
597
598 call object%finalize()
599
600 deallocate(type)
601 deallocate(zone_indices)
602 deallocate(default_name)
603 deallocate(bc_name)
604 end subroutine velocity_bc_factory
605
606end submodule fluid_pnpn_bc_fctry
Defines a Blasius profile dirichlet condition.
Definition blasius.f90:34
Generic buffer that is extended with buffers of varying rank.
Definition buffer.F90:34
Defines a dirichlet boundary condition.
Definition dirichlet.f90:34
Defines a dong outflow condition.
Defines a vector valued Dirichlet condition prescribed by mathematical expressions.
Defines a Dirichlet condition prescribed by a mathematical expression.
Defines inflow dirichlet conditions.
Defines user dirichlet condition for a scalar field.
Modular version of the Classic Nek5000 Pn/Pn formulation for fluids.
Defines inflow dirichlet conditions.
Definition inflow.f90:34
Defines a Neumann boundary condition.
Definition neumann.f90:34
Defines no-slip boundary condition (extends zero_dirichlet)
Definition no_slip.f90:34
Implements non_normal_aligned_t.
Implements non_normal_t.
Defines overset interface vector boundary conditions.
Defines overset interface scalar boundary conditions.
Defines a registry for storing solution fields.
Definition registry.f90:34
Defines a shear stress boundary condition for a vector field. Maintainer: Timofey Mukha.
Implements symmetry_aligned_t.
Implements symmetry_t.
Definition symmetry.f90:34
Interfaces for user interaction with NEKO.
Definition user_intf.f90:34
Utilities.
Definition utils.f90:35
subroutine, public neko_type_registration_error(base_type, wrong_type, known)
Definition utils.f90:433
subroutine, public neko_type_error(base_type, wrong_type, known_types)
Reports an error allocating a type for a particular base pointer class.
Definition utils.f90:415
Implements boundary condition projectors for vector fields. Two types concrete types are provided: se...
Defines the wall_model_bc_t type. Maintainer: Timofey Mukha.
Defines a zero-valued Dirichlet boundary condition.
Blasius profile for inlet (vector valued).
Definition blasius.f90:55
Generic Dirichlet boundary condition on .
Definition dirichlet.f90:49
Dong outflow condition Follows "A Convective-like Energy-Stable Open Boundary Condition for Simulati...
Dirichlet condition on , where is a mathematical expression given in the case file.
Vector valued Dirichlet condition, with one mathematical expression per component,...
User defined dirichlet condition, for which the user can work with an entire field....
Extension of the user defined dirichlet condition field_dirichlet
Dirichlet condition for inlet (vector valued)
Definition inflow.f90:48
A Neumann boundary condition. Sets the flux of the field to the chosen values.
Definition neumann.f90:60
Mixed Dirichlet condition constraining the tangential vector components.
Axis-aligned mixed Dirichlet condition in the non-normal direction.
Overset interface BC for a scalar field.
Extension of the user defined dirichlet condition overset_interface
A shear stress boundary condition.
Symmetry boundary condition constraining the normal vector component.
Definition symmetry.f90:50
Axis-aligned symmetry boundary condition.
A type collecting all the overridable user routines and flag to suppress type injection from custom m...
A coupled projector for vector fields, suitable for mixed boundary conditions.
A projector for vector fields that acts component-wise.
A shear stress boundary condition, computing the stress values using a wall model.
Zero-valued Dirichlet boundary condition. Used for no-slip walls, but also for various auxillary cond...