Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
fluid_pnpn.f90
Go to the documentation of this file.
1! Copyright (c) 2022-2026, 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!
35 use coefs, only : coef_t
36 use registry, only : neko_registry
37 use logger, only : neko_log, log_size
38 use num_types, only : rp, dp
39 use krylov, only : ksp_monitor_t
41 pnpn_prs_res_factory, pnpn_vel_res_factory, &
42 pnpn_prs_res_stress_factory, pnpn_vel_res_stress_factory
44 rhs_maker_oifs_t, rhs_maker_sumab_fctry, rhs_maker_bdf_fctry, &
45 rhs_maker_ext_fctry, rhs_maker_oifs_fctry
50 use fluid_aux, only : fluid_step_info
51 use projection, only : projection_t
55 use advection, only : advection_t, advection_factory
57 use json_module, only : json_file, json_core, json_value
60 use ax_product, only : ax_t, ax_helm_allocator
61 use ax_helm_svv, only : ax_helm_svv_t
63 use field, only : field_t
64 use dirichlet, only : dirichlet_t
69 use non_normal, only : non_normal_t
71 use symmetry, only : symmetry_t
72 use checkpoint, only : chkp_t
74 use mesh, only : mesh_t
75 use user_intf, only : user_t
77 use gs_ops, only : gs_op_add
79 use mathops, only : opadd2cm, opcolv
83 use bc, only : bc_t, bc_dirichlet
84 use mixed_bc, only : mixed_bc_t
88 use file, only : file_t
89 use operators, only : ortho, rotate_cyc
90 use opr_device, only : device_ortho
91 use time_state, only : time_state_t
92 use comm, only : neko_comm
93 use ale_manager, only : ale_manager_t
95 use mpi_f08, only : mpi_allreduce, mpi_in_place, mpi_max, mpi_lor, &
96 mpi_integer, mpi_logical
97 implicit none
98 private
99
100
101
103
106 integer :: schwarz_iterations = 0
107
109 type(field_t) :: p_res, u_res, v_res, w_res
110
113 type(field_t) :: dp, du, dv, dw
114
116 type(ale_manager_t) :: ale
117
118 ! ! Implicit operators, i.e. the left-hand-side of the Helmholz problem.
119 !
120
121 ! Coupled Helmholz operator for velocity
122 class(ax_t), allocatable :: ax_vel
123 ! Helmholz operator for pressure
124 class(ax_t), allocatable :: ax_prs
125
126 !
127 ! Projections for solver speed-up
128 !
129
131 type(projection_t) :: proj_prs
132 type(projection_vel_t) :: proj_vel
133
134 !
135 ! Special Karniadakis scheme boundary conditions in the pressure equation
136 !
137
139 type(facet_normal_t) :: bc_prs_surface
140
142 type(facet_normal_t) :: bc_sym_surface
143
145 class(vector_bc_projector_t), allocatable :: bcs_vel_projector
147 type(scalar_bc_projector_t) :: bcs_prs_projector
148
149
150 ! Checker for wether we have a strong pressure bc. If not, the pressure
151 ! is demeaned at every time step.
152 logical :: prs_dirichlet = .false.
153
154
155 ! The advection operator.
156 class(advection_t), allocatable :: adv
157
158 ! Time OIFS interpolation scheme for advection.
159 logical :: oifs
160
161 ! Time variables
162 type(field_t) :: abx1, aby1, abz1
163 type(field_t) :: abx2, aby2, abz2
164
165 ! Advection terms for the oifs method
166 type(field_t) :: advx, advy, advz
167
169 class(pnpn_prs_res_t), allocatable :: prs_res
170
172 class(pnpn_vel_res_t), allocatable :: vel_res
173
175 class(rhs_maker_sumab_t), allocatable :: sumab
176
178 class(rhs_maker_ext_t), allocatable :: makeabf
179
181 class(rhs_maker_bdf_t), allocatable :: makebdf
182
184 class(rhs_maker_oifs_t), allocatable :: makeoifs
185
187 type(fluid_volflow_t) :: vol_flow
188
190 logical :: full_stress_formulation = .false.
191
192 contains
194 procedure, pass(this) :: init => fluid_pnpn_init
196 procedure, pass(this) :: free => fluid_pnpn_free
198 procedure, pass(this) :: step => fluid_pnpn_step
200 procedure, pass(this) :: restart => fluid_pnpn_restart
202 procedure, pass(this) :: setup_bcs => fluid_pnpn_setup_bcs
204 procedure, pass(this) :: write_boundary_conditions => &
206 end type fluid_pnpn_t
207
208 interface
209
216 module subroutine fluid_pnpn_bc_split(json, velocity_json, &
217 pressure_json, has_velocity, has_pressure)
218 type(json_file), intent(inout) :: json
219 type(json_file), intent(inout) :: velocity_json
220 type(json_file), intent(inout) :: pressure_json
221 logical, intent(out) :: has_velocity
222 logical, intent(out) :: has_pressure
223 end subroutine fluid_pnpn_bc_split
224 end interface
225
226 interface
227
234 module subroutine pressure_bc_factory(object, scheme, json, coef, user)
235 class(bc_t), pointer, intent(inout) :: object
236 type(fluid_pnpn_t), intent(in) :: scheme
237 type(json_file), intent(inout) :: json
238 type(coef_t), target, intent(in) :: coef
239 type(user_t), target, intent(in) :: user
240 end subroutine pressure_bc_factory
241 end interface
242
243 interface
244
251 module subroutine velocity_bc_factory(object, scheme, json, coef, user)
252 class(bc_t), pointer, intent(inout) :: object
253 type(fluid_pnpn_t), intent(in) :: scheme
254 type(json_file), intent(inout) :: json
255 type(coef_t), target, intent(in) :: coef
256 type(user_t), target, intent(in) :: user
257 end subroutine velocity_bc_factory
258 end interface
259
260 interface
261
266 module subroutine fluid_pnpn_velocity_bc_allocator(object, type_name, &
267 full_stress_formulation)
268 class(bc_t), pointer, intent(inout) :: object
269 character(len=*), intent(in) :: type_name
270 logical, intent(in) :: full_stress_formulation
271 end subroutine fluid_pnpn_velocity_bc_allocator
272 end interface
273
274 interface
275
278 module subroutine fluid_pnpn_pressure_bc_allocator(object, type_name)
279 class(bc_t), pointer, intent(inout) :: object
280 character(len=*), intent(in) :: type_name
281 end subroutine fluid_pnpn_pressure_bc_allocator
282 end interface
283
284 !
285 ! Machinery for injecting user-defined types
286 !
287
291 abstract interface
292 subroutine fluid_pnpn_bc_allocate(obj)
293 import bc_t
294 class(bc_t), pointer, intent(inout) :: obj
295 end subroutine fluid_pnpn_bc_allocate
296 end interface
297
298 interface
299
303 module subroutine register_fluid_pnpn_velocity_bc(type_name, allocator)
304 character(len=*), intent(in) :: type_name
305 procedure(fluid_pnpn_bc_allocate), pointer, intent(in) :: allocator
306 end subroutine register_fluid_pnpn_velocity_bc
307 end interface
308
309 interface
310
314 module subroutine register_fluid_pnpn_pressure_bc(type_name, allocator)
315 character(len=*), intent(in) :: type_name
316 procedure(fluid_pnpn_bc_allocate), pointer, intent(in) :: allocator
317 end subroutine register_fluid_pnpn_pressure_bc
318 end interface
319
321 type fluid_pnpn_bc_allocator_entry
322 character(len=NEKO_TYPENAME_LEN) :: type_name
323 procedure(fluid_pnpn_bc_allocate), pointer, nopass :: allocator => null()
324 end type fluid_pnpn_bc_allocator_entry
325
327 type(fluid_pnpn_bc_allocator_entry), allocatable, private :: &
328 fluid_pnpn_velocity_bc_registry(:)
329
331 integer, private :: fluid_pnpn_velocity_bc_registry_size = 0
332
334 type(fluid_pnpn_bc_allocator_entry), allocatable, private :: &
335 fluid_pnpn_pressure_bc_registry(:)
336
338 integer, private :: fluid_pnpn_pressure_bc_registry_size = 0
339
340 public :: fluid_pnpn_bc_split, fluid_pnpn_bc_allocate, &
341 fluid_pnpn_velocity_bc_allocator, fluid_pnpn_pressure_bc_allocator, &
342 register_fluid_pnpn_velocity_bc, register_fluid_pnpn_pressure_bc
343
344contains
345
346 subroutine fluid_pnpn_init(this, msh, lx, params, user, chkp)
347 class(fluid_pnpn_t), target, intent(inout) :: this
348 type(mesh_t), target, intent(inout) :: msh
349 integer, intent(in) :: lx
350 type(json_file), target, intent(inout) :: params
351 type(user_t), target, intent(in) :: user
352 type(chkp_t), target, intent(inout) :: chkp
353 character(len=15), parameter :: scheme = 'Modular (Pn/Pn)'
354 integer :: i
355 class(bc_t), pointer :: bc_i, vel_bc
356 real(kind=rp) :: abs_tol
357 character(len=LOG_SIZE) :: log_buf
358 integer :: ierr, integer_val, solver_maxiter
359 character(len=:), allocatable :: solver_type, precon_type
360 logical :: monitor, found
361 logical :: advection
362 type(json_file) :: numerics_params, precon_params
363 type(checkpoint_payload_t), pointer :: payload
364 real(kind=dp), pointer :: tlag(:), dtlag(:)
365
366 call this%free()
367
368 ! Initialize base class
369 call this%init_base(msh, lx, params, scheme, user, .true.)
370
371 ! Add pressure field to the registry. For this scheme it is in the same
372 ! Xh as the velocity
373 call neko_registry%add_field(this%dm_Xh, 'p')
374 this%p => neko_registry%get_field('p')
375
376 !
377 ! Select governing equations via associated residual and Ax types
378 !
379
380 call json_get_or_lookup(params, 'case.numerics.time_order', integer_val)
381 allocate(this%ext_bdf)
382 call this%ext_bdf%init(integer_val)
383
384 call json_get_or_default(params, "case.fluid.full_stress_formulation", &
385 this%full_stress_formulation, .false.)
386
387 call json_get_or_default(params, "case.fluid.cyclic", this%c_Xh%cyclic, &
388 .false.)
389 call this%c_Xh%generate_cyclic_bc()
390
391 ! Setup backend dependent Ax routines for the velocity
392 call fluid_pnpn_ax_vel_factory(this)
393
394 if (this%full_stress_formulation) then
395 ! Setup backend dependent prs residual routines
396 call pnpn_prs_res_stress_factory(this%prs_res)
397
398 ! Setup backend dependent vel residual routines
399 call pnpn_vel_res_stress_factory(this%vel_res)
400
401 ! Allocate coupled projector for velocity boundary conditions
402 allocate(coupled_vector_bc_projector_t :: this%bcs_vel_projector)
403 else
404 ! Setup backend dependent prs residual routines
405 call pnpn_prs_res_factory(this%prs_res)
406
407 ! Setup backend dependent vel residual routines
408 call pnpn_vel_res_factory(this%vel_res)
409
410 ! Allocate segregated projector for velocity boundary conditions
411 allocate(segregated_vector_bc_projector_t :: this%bcs_vel_projector)
412 end if
413
414 ! Initialize the velocity bc projector
415 call this%bcs_vel_projector%init(this%c_Xh)
416
417 if (params%valid_path('case.fluid.nut_field')) then
418 if (.not. this%full_stress_formulation) then
419 call neko_error("You need to set full_stress_formulation to " // &
420 "true for the fluid to have a spatially varying " // &
421 "viscocity field.")
422 end if
423 call json_get(params, 'case.fluid.nut_field', this%nut_field_name)
424 else
425 this%nut_field_name = ""
426 end if
427
428 ! Setup Ax for the pressure
429 if (this%c_Xh%geo_compression) then
430 call ax_helm_allocator(this%Ax_prs, type_name = "standard_compr")
431 else
432 call ax_helm_allocator(this%Ax_prs, type_name = "standard")
433 end if
434
435
436 ! Setup backend dependent summation of AB/BDF
437 call rhs_maker_sumab_fctry(this%sumab)
438
439 ! Setup backend dependent summation of extrapolation scheme
440 call rhs_maker_ext_fctry(this%makeabf)
441
442 ! Setup backend depenent contributions to F from lagged BD terms
443 call rhs_maker_bdf_fctry(this%makebdf)
444
445 ! Setup backend dependent summations of the OIFS method
446 call rhs_maker_oifs_fctry(this%makeoifs)
447
448 ! Initialize variables specific to this plan
449 associate(xh_lx => this%Xh%lx, xh_ly => this%Xh%ly, xh_lz => this%Xh%lz, &
450 dm_xh => this%dm_Xh, nelv => this%msh%nelv)
451
452 call this%p_res%init(dm_xh, "p_res")
453 call this%u_res%init(dm_xh, "u_res")
454 call this%v_res%init(dm_xh, "v_res")
455 call this%w_res%init(dm_xh, "w_res")
456 call this%abx1%init(dm_xh, "abx1")
457 call this%aby1%init(dm_xh, "aby1")
458 call this%abz1%init(dm_xh, "abz1")
459 call this%abx2%init(dm_xh, "abx2")
460 call this%aby2%init(dm_xh, "aby2")
461 call this%abz2%init(dm_xh, "abz2")
462 call this%advx%init(dm_xh, "advx")
463 call this%advy%init(dm_xh, "advy")
464 call this%advz%init(dm_xh, "advz")
465 end associate
466
467 call this%du%init(this%dm_Xh, 'du')
468 call this%dv%init(this%dm_Xh, 'dv')
469 call this%dw%init(this%dm_Xh, 'dw')
470 call this%dp%init(this%dm_Xh, 'dp')
471 ! Initialize ALE
472 call this%ale%init(this%c_Xh, params, user, chkp)
473
474 call neko_log%section("Fluid boundary conditions")
475 ! Set up boundary conditions
476 call this%setup_bcs(user, params)
477
478 ! Check if we need to output boundaries
479 call json_get_or_default(params, 'case.output_boundary', found, .false.)
480 if (found) call this%write_boundary_conditions()
481 call neko_log%end_section()
482
483 call this%proj_prs%init(this%dm_Xh%size(), this%pr_projection_dim, &
484 this%pr_projection_activ_step, &
485 this%pr_projection_reorthogonalize_basis)
486
487 call this%proj_vel%init(this%dm_Xh%size(), this%vel_projection_dim, &
488 this%vel_projection_activ_step)
489
490
491
492 ! Determine the time-interpolation scheme
493 call json_get_or_default(params, 'case.numerics.oifs', this%oifs, .false.)
494 if (params%valid_path('case.fluid.flow_rate_force')) then
495 call this%vol_flow%init(this%dm_Xh, params)
496 end if
497
498 ! Setup pressure solver
499 call neko_log%section("Pressure solver")
500
501 call json_get_or_lookup_or_default(params, &
502 'case.fluid.pressure_solver.max_iterations', &
503 solver_maxiter, 800)
504 call json_get(params, 'case.fluid.pressure_solver.type', solver_type)
505 call json_get(params, 'case.fluid.pressure_solver.preconditioner.type', &
506 precon_type)
507 call json_get(params, &
508 'case.fluid.pressure_solver.preconditioner', precon_params)
509 call json_get_or_lookup(params, &
510 'case.fluid.pressure_solver.absolute_tolerance', &
511 abs_tol)
512 call json_get_or_default(params, 'case.fluid.pressure_solver.monitor', &
513 monitor, .false.)
514 call neko_log%message('Type : ('// trim(solver_type) // &
515 ', ' // trim(precon_type) // ')')
516 write(log_buf, '(A,ES13.6)') 'Abs tol :', abs_tol
517 call neko_log%message(log_buf)
518
519 call this%solver_factory(this%ksp_prs, this%dm_Xh%size(), &
520 solver_type, solver_maxiter, abs_tol, monitor)
521 call this%precon_factory_(this%pc_prs, this%ksp_prs, &
522 this%c_Xh, this%bcs_prs, &
523 precon_type, precon_params)
524 call neko_log%end_section()
525
526 ! Initialize the advection factory
527 call json_get_or_default(params, 'case.fluid.advection', advection, .true.)
528 ! OIFS integrates the advection term. With advection disabled, fall back to
529 ! the standard BDF history assembly.
530 this%oifs = this%oifs .and. advection
531 call json_get(params, 'case.numerics', numerics_params)
532 call chkp%get_time_history(tlag, dtlag)
533 call advection_factory(this%adv, numerics_params, this%c_Xh, &
534 this%ulag, this%vlag, this%wlag, &
535 dtlag, tlag, this%ext_bdf, &
536 .not. advection)
537 ! Should be in init_base maybe?
538 this%chkp => chkp
539 ! Register the scheme state for checkpointing.
540 payload => this%chkp%add_payload("fluid")
541 call payload%add_field(this%u)
542 call payload%add_field(this%v)
543 call payload%add_field(this%w)
544 call payload%add_field(this%p)
545 call payload%add_field(this%abx1)
546 call payload%add_field(this%abx2)
547 call payload%add_field(this%aby1)
548 call payload%add_field(this%aby2)
549 call payload%add_field(this%abz1)
550 call payload%add_field(this%abz2)
551 call payload%add_series(this%ulag)
552 call payload%add_series(this%vlag)
553 call payload%add_series(this%wlag)
554
556 call json_get_or_default(params, 'case.fluid.schwarz_iterations', &
557 this%schwarz_iterations, 0)
558
559 call neko_log%end_section()
560
561 nullify(bc_i, vel_bc)
562
563 end subroutine fluid_pnpn_init
564
567 subroutine fluid_pnpn_ax_vel_factory(this)
568 class(fluid_pnpn_t), target, intent(inout) :: this
569
570 if (this%full_stress_formulation) then
571 if (this%svv_enabled) then
572 call ax_helm_allocator(this%Ax_vel, type_name = "full_svv")
573 select type (operator => this%Ax_vel)
574 class is (ax_helm_svv_full_t)
575 operator%svv => this%svv
576 end select
577 else
578 call ax_helm_allocator(this%Ax_vel, type_name = "full")
579 end if
580 else
581 if (this%svv_enabled) then
582 call ax_helm_allocator(this%Ax_vel, type_name = "standard_svv")
583 select type (operator => this%Ax_vel)
584 class is (ax_helm_svv_t)
585 operator%svv => this%svv
586 end select
587 else if (this%c_Xh%geo_compression) then
588 call ax_helm_allocator(this%Ax_vel, &
589 type_name = "standard_compr")
590 else
591 call ax_helm_allocator(this%Ax_vel, type_name = "standard")
592 end if
593 end if
594
595 end subroutine fluid_pnpn_ax_vel_factory
596
597 subroutine fluid_pnpn_restart(this, chkp)
598 class(fluid_pnpn_t), target, intent(inout) :: this
599 type(chkp_t), intent(inout) :: chkp
600 integer :: i, j, n
601 class(bc_t), pointer :: bc_i
602
603 n = this%u%dof%size()
604 if (allocated(chkp%previous_mesh%elements) .or. &
605 chkp%previous_Xh%lx .ne. this%Xh%lx) then
606 associate(u => this%u, v => this%v, w => this%w, p => this%p, &
607 c_xh => this%c_Xh, ulag => this%ulag, vlag => this%vlag, &
608 wlag => this%wlag)
609 do concurrent(j = 1:n)
610 u%x(j,1,1,1) = u%x(j,1,1,1) * c_xh%mult(j,1,1,1)
611 v%x(j,1,1,1) = v%x(j,1,1,1) * c_xh%mult(j,1,1,1)
612 w%x(j,1,1,1) = w%x(j,1,1,1) * c_xh%mult(j,1,1,1)
613 p%x(j,1,1,1) = p%x(j,1,1,1) * c_xh%mult(j,1,1,1)
614 end do
615 do i = 1, this%ulag%size()
616 do concurrent(j = 1:n)
617 ulag%lf(i)%x(j,1,1,1) = ulag%lf(i)%x(j,1,1,1) &
618 * c_xh%mult(j,1,1,1)
619 vlag%lf(i)%x(j,1,1,1) = vlag%lf(i)%x(j,1,1,1) &
620 * c_xh%mult(j,1,1,1)
621 wlag%lf(i)%x(j,1,1,1) = wlag%lf(i)%x(j,1,1,1) &
622 * c_xh%mult(j,1,1,1)
623 end do
624 end do
625 end associate
626 end if
627
628 if (neko_bcknd_device .eq. 1) then
629 associate(u => this%u, v => this%v, w => this%w, &
630 ulag => this%ulag, vlag => this%vlag, wlag => this%wlag,&
631 p => this%p)
632 call device_memcpy(u%x, u%x_d, u%dof%size(), &
633 host_to_device, sync = .false.)
634 call device_memcpy(v%x, v%x_d, v%dof%size(), &
635 host_to_device, sync = .false.)
636 call device_memcpy(w%x, w%x_d, w%dof%size(), &
637 host_to_device, sync = .false.)
638 call device_memcpy(p%x, p%x_d, p%dof%size(), &
639 host_to_device, sync = .false.)
640 call device_memcpy(ulag%lf(1)%x, ulag%lf(1)%x_d, &
641 u%dof%size(), host_to_device, sync = .false.)
642 call device_memcpy(ulag%lf(2)%x, ulag%lf(2)%x_d, &
643 u%dof%size(), host_to_device, sync = .false.)
644
645 call device_memcpy(vlag%lf(1)%x, vlag%lf(1)%x_d, &
646 v%dof%size(), host_to_device, sync = .false.)
647 call device_memcpy(vlag%lf(2)%x, vlag%lf(2)%x_d, &
648 v%dof%size(), host_to_device, sync = .false.)
649
650 call device_memcpy(wlag%lf(1)%x, wlag%lf(1)%x_d, &
651 w%dof%size(), host_to_device, sync = .false.)
652 call device_memcpy(wlag%lf(2)%x, wlag%lf(2)%x_d, &
653 w%dof%size(), host_to_device, sync = .false.)
654 call device_memcpy(this%abx1%x, this%abx1%x_d, &
655 w%dof%size(), host_to_device, sync = .false.)
656 call device_memcpy(this%abx2%x, this%abx2%x_d, &
657 w%dof%size(), host_to_device, sync = .false.)
658 call device_memcpy(this%aby1%x, this%aby1%x_d, &
659 w%dof%size(), host_to_device, sync = .false.)
660 call device_memcpy(this%aby2%x, this%aby2%x_d, &
661 w%dof%size(), host_to_device, sync = .false.)
662 call device_memcpy(this%abz1%x, this%abz1%x_d, &
663 w%dof%size(), host_to_device, sync = .false.)
664 call device_memcpy(this%abz2%x, this%abz2%x_d, &
665 w%dof%size(), host_to_device, sync = .false.)
666 call device_memcpy(this%advx%x, this%advx%x_d, &
667 w%dof%size(), host_to_device, sync = .false.)
668 call device_memcpy(this%advy%x, this%advy%x_d, &
669 w%dof%size(), host_to_device, sync = .false.)
670 call device_memcpy(this%advz%x, this%advz%x_d, &
671 w%dof%size(), host_to_device, sync = .false.)
672 end associate
673 end if
674 ! Make sure that continuity is maintained (important for interpolation)
675 ! Do not do this for lagged rhs
676 ! (derivatives are not necessairly coninous across elements)
677
678 if (allocated(chkp%previous_mesh%elements) &
679 .or. chkp%previous_Xh%lx .ne. this%Xh%lx) then
680
681 call rotate_cyc(this%u, this%v, this%w, 1, this%c_Xh)
682 call this%gs_Xh%op(this%u, gs_op_add)
683 call this%gs_Xh%op(this%v, gs_op_add)
684 call this%gs_Xh%op(this%w, gs_op_add)
685 call this%gs_Xh%op(this%p, gs_op_add)
686 call rotate_cyc(this%u, this%v, this%w, 0, this%c_Xh)
687
688 do i = 1, this%ulag%size()
689 call rotate_cyc(this%ulag%lf(i), this%vlag%lf(i), &
690 this%wlag%lf(i), 1, this%c_Xh)
691 call this%gs_Xh%op(this%ulag%lf(i), gs_op_add)
692 call this%gs_Xh%op(this%vlag%lf(i), gs_op_add)
693 call this%gs_Xh%op(this%wlag%lf(i), gs_op_add)
694 call rotate_cyc(this%ulag%lf(i), this%vlag%lf(i), &
695 this%wlag%lf(i), 0, this%c_Xh)
696 end do
697 end if
698
699 call this%ale%sync_chkp(this%c_Xh, this%Xh, this%adv, chkp, this%gs_Xh)
700 if (this%ale%active) then
701 call this%bc_prs_surface%recompute_normals()
702 call this%bc_sym_surface%recompute_normals()
703 end if
704
705 ! Restore velocity bcs that need it (overset mostly)
706 do i = 1, this%bcs_vel%size()
707 bc_i => this%bcs_vel%get(i)
708 call bc_i%restart(this%u, this%v, this%w, &
709 this%ulag, this%vlag, this%wlag)
710 end do
711
712 ! Restore pressure bcs that need it (overset mostly)
713 do i = 1, this%bcs_prs%size()
714 bc_i => this%bcs_prs%get(i)
715 call bc_i%restart(this%p)
716 end do
717
718 nullify(bc_i)
719
720 end subroutine fluid_pnpn_restart
721
722 subroutine fluid_pnpn_free(this)
723 class(fluid_pnpn_t), intent(inout) :: this
724
725 if (allocated(this%Ax_vel)) then
726 call this%Ax_vel%free()
727 deallocate(this%Ax_vel)
728 end if
729
730 if (allocated(this%Ax_prs)) then
731 call this%Ax_prs%free()
732 deallocate(this%Ax_prs)
733 end if
734
735 !Deallocate velocity and pressure fields
736 call this%scheme_free()
737
738 if (allocated(this%ext_bdf)) then
739 call this%ext_bdf%free()
740 deallocate(this%ext_bdf)
741 end if
742
743 call this%bc_prs_surface%free()
744 call this%bc_sym_surface%free()
745 if (allocated(this%bcs_vel_projector)) then
746 call this%bcs_vel_projector%free()
747 deallocate(this%bcs_vel_projector)
748 end if
749 call this%bcs_prs_projector%free()
750 call this%proj_prs%free()
751 call this%proj_vel%free()
752
753 call this%p_res%free()
754 call this%u_res%free()
755 call this%v_res%free()
756 call this%w_res%free()
757
758 call this%ale%free()
759
760 call this%du%free()
761 call this%dv%free()
762 call this%dw%free()
763 call this%dp%free()
764
765 call this%abx1%free()
766 call this%aby1%free()
767 call this%abz1%free()
768
769 call this%abx2%free()
770 call this%aby2%free()
771 call this%abz2%free()
772
773 call this%advx%free()
774 call this%advy%free()
775 call this%advz%free()
776
777 if (allocated(this%adv)) then
778 call this%adv%free()
779 deallocate(this%adv)
780 end if
781
782 if (allocated(this%prs_res)) then
783 deallocate(this%prs_res)
784 end if
785
786 if (allocated(this%vel_res)) then
787 deallocate(this%vel_res)
788 end if
789
790 if (allocated(this%sumab)) then
791 deallocate(this%sumab)
792 end if
793
794 if (allocated(this%makeabf)) then
795 deallocate(this%makeabf)
796 end if
797
798 if (allocated(this%makebdf)) then
799 deallocate(this%makebdf)
800 end if
801
802 if (allocated(this%makeoifs)) then
803 deallocate(this%makeoifs)
804 end if
805
806 if (allocated(this%ext_bdf)) then
807 deallocate(this%ext_bdf)
808 end if
809
810 call this%vol_flow%free()
811
812 end subroutine fluid_pnpn_free
813
820 subroutine fluid_pnpn_step(this, time, dt_controller)
821 class(fluid_pnpn_t), target, intent(inout) :: this
822 type(time_state_t), intent(in) :: time
823 type(time_step_controller_t), intent(in) :: dt_controller
824 ! number of degrees of freedom
825 integer :: n
826 ! Solver results monitors (pressure + 3 velocity)
827 type(ksp_monitor_t) :: ksp_results(4)
828 integer :: iter
829
830 type(file_t) :: dump_file
831 class(bc_t), pointer :: bc_i
832
833 if (this%freeze) return
834
835 n = this%dm_Xh%size()
836
837 call profiler_start_region('Fluid', 1)
838 associate(u => this%u, v => this%v, w => this%w, p => this%p, &
839 u_e => this%u_e, v_e => this%v_e, w_e => this%w_e, &
840 du => this%du, dv => this%dv, dw => this%dw, dp => this%dp, &
841 u_res => this%u_res, v_res => this%v_res, w_res => this%w_res, &
842 p_res => this%p_res, ax_vel => this%Ax_vel, ax_prs => this%Ax_prs, &
843 xh => this%Xh, &
844 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
845 ulag => this%ulag, vlag => this%vlag, wlag => this%wlag, &
846 msh => this%msh, prs_res => this%prs_res, &
847 source_term => this%source_term, vel_res => this%vel_res, &
848 sumab => this%sumab, makeoifs => this%makeoifs, &
849 makeabf => this%makeabf, makebdf => this%makebdf, &
850 vel_projection_dim => this%vel_projection_dim, &
851 pr_projection_dim => this%pr_projection_dim, &
852 oifs => this%oifs, &
853 rho => this%rho, mu_tot => this%mu_tot, &
854 f_x => this%f_x, f_y => this%f_y, f_z => this%f_z, &
855 t => time%t, tstep => time%tstep, dt => time%dt, &
856 ext_bdf => this%ext_bdf, event => glb_cmd_event, &
857 ale => this%ale)
858
859 ! Extrapolate the velocity if it's not done in nut_field estimation
860 call sumab%compute_fluid(u_e, v_e, w_e, u, v, w, &
861 ulag, vlag, wlag, ext_bdf%advection_coeffs%x, ext_bdf%nadv)
862
863 ! Compute the source terms that are extrapolated in time below
864 call this%source_term%compute(time, extrapolate = .true.)
865
866 ! Add Neumann bc contributions to the RHS
867 call this%bcs_vel%apply_vector(f_x%x, f_y%x, f_z%x, &
868 this%dm_Xh%size(), time, strong = .false.)
869
870 if (this%ale%active) then
871 if (oifs) then
872 call neko_error("ALE is not yet supported " // &
873 "with OIFS time integration.")
874 end if
876 call this%adv%compute_ale(u, v, w, &
877 ale%wm_x, ale%wm_y, ale%wm_z, &
878 f_x, f_y, f_z, &
879 xh, c_xh, dm_xh%size())
880 end if
881
882
883 if (oifs) then
884 ! Add the advection operators to the right-hand-side.
885 call this%adv%compute(u, v, w, &
886 this%advx, this%advy, this%advz, &
887 xh, this%c_Xh, dm_xh%size(), real(dt, kind=rp))
888
889 ! At this point the RHS contains the sum of the advection operator and
890 ! additional source terms, evaluated using the velocity field from the
891 ! previous time-step. Now, this value is used in the explicit time
892 ! scheme to advance both terms in time.
893
894 call makeabf%compute_fluid(this%abx1, this%aby1, this%abz1,&
895 this%abx2, this%aby2, this%abz2, &
896 f_x%x, f_y%x, f_z%x, &
897 rho%x(1,1,1,1), ext_bdf%advection_coeffs%x, n)
898
899 ! Now, the source terms from the previous time step are added to the
900 ! RHS.
901 call makeoifs%compute_fluid(this%advx%x, this%advy%x, this%advz%x, &
902 f_x%x, f_y%x, f_z%x, &
903 rho%x(1,1,1,1), real(dt, kind=rp), n)
904 else
905 ! Add the advection operators to the right-hand-side.
906 call this%adv%compute(u, v, w, &
907 f_x, f_y, f_z, &
908 xh, this%c_Xh, dm_xh%size())
909
910 ! At this point the RHS contains the sum of the advection operator and
911 ! additional source terms, evaluated using the velocity field from the
912 ! previous time-step. Now, this value is used in the explicit time
913 ! scheme to advance both terms in time.
914
915 call makeabf%compute_fluid(this%abx1, this%aby1, this%abz1,&
916 this%abx2, this%aby2, this%abz2, &
917 f_x%x, f_y%x, f_z%x, &
918 rho%x(1,1,1,1), ext_bdf%advection_coeffs%x, n)
919
920 ! Add the RHS contributions coming from the BDF scheme.
921 ! Blag and Blaglag are history of B matrices, mainly used for ALE.
922 ! For a normal simulation (no moving mesh), Blag and Blaglag
923 ! are just the initial B matrix, filled at initialization.
924 call makebdf%compute_fluid(ulag, vlag, wlag, f_x%x, f_y%x, f_z%x, &
925 u, v, w, c_xh%B, c_xh%Blag, c_xh%Blaglag, rho%x(1,1,1,1), &
926 real(dt, kind=rp), &
927 ext_bdf%diffusion_coeffs%x, ext_bdf%ndiff, n)
928
929 end if
930
931 ! Source terms that must not be extrapolated in time are added as
932 ! computed, weighted by the mass matrix and the density like the
933 ! extrapolated terms above.
934 call this%source_term%compute(time, extrapolate = .false., scale = rho)
935
936 if (this%ale%active) then
937 ! Advance Mesh (Moves points, updates B history, updates wm_lags)
938 call this%ale%advance_mesh(c_xh, time, ext_bdf%nadv)
939
940 call profiler_start_region('ALE recompute metrics')
941 ! Update Metrics
942 call c_xh%recompute_metrics()
943 ! Update the metrics used by the adv operator for delaiasing (coef_GL)
944 ! Maps the updated coef_GLL to coef_GL.
945 call this%adv%recompute_metrics(c_xh, .true.)
946
947 call this%bc_prs_surface%recompute_normals()
948 call this%bc_sym_surface%recompute_normals()
949 call profiler_end_region('ALE recompute metrics')
950 end if
951
952 call ulag%update()
953 call vlag%update()
954 call wlag%update()
955
956 ! Update material properties if necessary
957 call this%update_material_properties(time)
958
959 ! Update the SVV coefficient if necessary
960 if (this%svv_enabled) then
961 call this%svv%update(rho, tstep)
962 end if
963
964 do iter = 1, 1 + this%schwarz_iterations
965
966 call this%bc_apply_vel(time, strong = .true.)
967 call this%bc_apply_prs(time)
968
969 ! Compute pressure residual.
970 call profiler_start_region('Pressure_residual', 18)
971 call prs_res%compute(p, p_res,&
972 u, v, w, &
973 u_e, v_e, w_e, &
974 f_x, f_y, f_z, &
975 c_xh, gs_xh, &
976 this%bc_prs_surface, this%bc_sym_surface,&
977 ax_prs, ext_bdf%diffusion_coeffs%x(1), real(dt, kind=rp), &
978 mu_tot, rho, event)
979
980
981 ! De-mean the pressure residual when no strong pressure boundaries present
982 if (.not. this%prs_dirichlet .and. neko_bcknd_device .eq. 1) then
983 call device_ortho(p_res%x_d, this%glb_n_points, n)
984 else if (.not. this%prs_dirichlet) then
985 call ortho(p_res%x, this%glb_n_points, n)
986 end if
987
988 call gs_xh%op(p_res, gs_op_add, event)
989 call device_event_sync(event)
990
991 ! Set the residual to zero at strong pressure boundaries.
992 call this%bcs_prs_projector%apply(p_res%x, p%dof%size())
993
994
995 call profiler_end_region('Pressure_residual', 18)
996
997 ! Do projections only on the actual solutions of the tstep
998 ! not intermediate solutions from the subiterations.
999 if (iter .eq. 1) then
1000 call this%proj_prs%pre_solving(p_res%x, tstep, c_xh, n, &
1001 dt_controller, ax = ax_prs, gs_h = gs_xh, &
1002 bclst = this%bcs_prs_projector, string = 'Pressure')
1003 end if
1004
1005 call this%pc_prs%update()
1006
1007 call profiler_start_region('Pressure_solve', 3)
1008
1009 ! Solve for the pressure increment.
1010 ksp_results(1) = &
1011 this%ksp_prs%solve(ax_prs, dp, p_res%x, n, c_xh, &
1012 this%bcs_prs_projector, gs_xh)
1013 ksp_results(1)%name = 'Pressure'
1014
1015
1016 call profiler_end_region('Pressure_solve', 3)
1017
1018 if (iter .eq. 1) then
1019 call this%proj_prs%post_solving(dp%x, ax_prs, c_xh, &
1020 this%bcs_prs_projector, gs_xh, n, tstep, dt_controller)
1021 end if
1022
1023 ! Update the pressure with the increment. Demean if necessary.
1024 call field_add2(p, dp, n)
1025 if (.not. this%prs_dirichlet .and. neko_bcknd_device .eq. 1) then
1026 call device_ortho(p%x_d, this%glb_n_points, n)
1027 else if (.not. this%prs_dirichlet) then
1028 call ortho(p%x, this%glb_n_points, n)
1029 end if
1030
1031 ! Compute velocity residual.
1032 call profiler_start_region('Velocity_residual', 19)
1033 call vel_res%compute(ax_vel, u, v, w, &
1034 u_res, v_res, w_res, &
1035 p, &
1036 f_x, f_y, f_z, &
1037 c_xh, msh, xh, &
1038 mu_tot, rho, ext_bdf%diffusion_coeffs%x(1), &
1039 real(dt, kind=rp), dm_xh%size())
1040
1041 call rotate_cyc(u_res, v_res, w_res, 1, c_xh)
1042 call gs_xh%op(u_res%x, v_res%x, w_res%x, dm_xh%size(), &
1043 gs_op_add, event)
1044 call device_event_sync(event)
1045 call rotate_cyc(u_res, v_res, w_res, 0, c_xh)
1046
1047 ! Set residual to zero at strong velocity boundaries.
1048 call this%bcs_vel_projector%apply(u_res%x, v_res%x, w_res%x, &
1049 dm_xh%size())
1050
1051
1052 call profiler_end_region('Velocity_residual', 19)
1053
1054 if (iter .eq. 1) then
1055 call this%proj_vel%pre_solving(u_res%x, v_res%x, w_res%x, &
1056 tstep, c_xh, n, dt_controller, 'Velocity')
1057 end if
1058
1059 call this%pc_vel%update()
1060
1061 call profiler_start_region("Velocity_solve", 4)
1062 ksp_results(2:4) = this%ksp_vel%solve_coupled(ax_vel, du, dv, dw, &
1063 u_res%x, v_res%x, w_res%x, n, c_xh, &
1064 this%bcs_vel_projector, gs_xh, &
1065 this%ksp_vel%max_iter)
1066 call profiler_end_region("Velocity_solve", 4)
1067 if (this%full_stress_formulation) then
1068 ksp_results(2)%name = 'Momentum'
1069 else
1070 ksp_results(2)%name = 'X-Velocity'
1071 ksp_results(3)%name = 'Y-Velocity'
1072 ksp_results(4)%name = 'Z-Velocity'
1073 end if
1074
1075 if (iter .eq. 1) then
1076 call this%proj_vel%post_solving(du%x, dv%x, dw%x, ax_vel, c_xh, &
1077 this%bcs_vel_projector, gs_xh, n, tstep, &
1078 dt_controller)
1079 end if
1080
1081 if (neko_bcknd_device .eq. 1) then
1082 call device_opadd2cm(u%x_d, v%x_d, w%x_d, &
1083 du%x_d, dv%x_d, dw%x_d, 1.0_rp, n, msh%gdim)
1084 else
1085 call opadd2cm(u%x, v%x, w%x, du%x, dv%x, dw%x, 1.0_rp, n, msh%gdim)
1086 end if
1087
1088 call fluid_step_info(time, ksp_results, &
1089 this%full_stress_formulation, this%strict_convergence, &
1090 this%allow_stabilization, iter)
1091
1092 end do
1093
1094 if (this%forced_flow_rate) then
1095 ! Horrible mu hack?!
1096 call this%vol_flow%adjust( u, v, w, p, u_res, v_res, w_res, p_res, &
1097 c_xh, gs_xh, ext_bdf, rho%x(1,1,1,1), mu_tot, &
1098 real(dt, kind=rp), time, this%bcs_prs_projector, &
1099 this%bcs_vel_projector, ax_vel, ax_prs, this%ksp_prs, &
1100 this%ksp_vel, this%pc_prs, this%pc_vel, this%ksp_prs%max_iter, &
1101 this%ksp_vel%max_iter)
1102 end if
1103
1104 ! Update mesh velocities for ALE
1105 ! We update them here (end of step) for the next step.
1106 ! Returns if .not. ale.
1107 call this%ale%update_mesh_velocity(c_xh, time)
1108
1109 end associate
1110
1111 nullify(bc_i)
1112
1113 call profiler_end_region('Fluid', 1)
1114 end subroutine fluid_pnpn_step
1115
1126 subroutine fluid_pnpn_setup_bcs(this, user, params)
1127 class(fluid_pnpn_t), target, intent(inout) :: this
1128 type(user_t), target, intent(in) :: user
1129 type(json_file), intent(inout) :: params
1130 integer :: i, n_bcs, j, k, l, zone_size, global_zone_size, ierr
1131 integer :: facet_value
1132 class(bc_t), pointer :: bc_i
1133 type(json_core) :: core
1134 type(json_value), pointer :: bc_object
1135 type(json_file) :: bc_subdict, velocity_subdict, pressure_subdict
1136 logical :: moving_, has_velocity, has_pressure, pressure_dirichlet
1137 logical :: found
1138 ! Monitor which boundary zones have been marked
1139 logical, allocatable :: marked_zones(:)
1140 integer, allocatable :: zone_indices(:)
1141 character(len=256) :: error_msg
1142 character(len=:), allocatable :: bc_type_str
1143
1144 this%ale%has_moving_boundary = .false.
1145
1146 ! Special PnPn boundary conditions for pressure
1147 call this%bc_prs_surface%init_from_components(this%c_Xh)
1148 call this%bc_sym_surface%init_from_components(this%c_Xh)
1149
1150 ! Populate bcs_vel and bcs_prs based on the case file
1151 if (params%valid_path('case.fluid.boundary_conditions')) then
1152 call params%info('case.fluid.boundary_conditions', n_children = n_bcs)
1153 call params%get_core(core)
1154 call params%get('case.fluid.boundary_conditions', bc_object, found)
1155
1156 call this%bcs_vel%init(n_bcs)
1157 call this%bcs_prs%init(n_bcs)
1158
1159 allocate(marked_zones(size(this%msh%labeled_zones)))
1160 marked_zones = .false.
1161
1162 do i = 1, n_bcs
1163 ! Create a new json containing just the subdict for this bc
1164 call json_extract_item(core, bc_object, i, bc_subdict)
1165
1166 call json_get_or_lookup(bc_subdict, "zone_indices", zone_indices)
1167
1168 ! Check that we are not trying to assing a bc to zone, for which one
1169 ! has already been assigned and that the zone has more than 0 size
1170 ! in the mesh.
1171 do j = 1, size(zone_indices)
1172 zone_size = this%msh%labeled_zones(zone_indices(j))%size
1173 call mpi_allreduce(zone_size, global_zone_size, 1, &
1174 mpi_integer, mpi_max, neko_comm, ierr)
1175
1176 if (global_zone_size .eq. 0) then
1177 write(error_msg, '(A, I0, A, A, I0, A)') &
1178 "Zone index ", zone_indices(j), &
1179 " is invalid as this zone has 0 size, meaning it ", &
1180 "is not in the mesh. Check fluid boundary condition ", &
1181 i, "."
1182 call neko_error(error_msg)
1183 end if
1184
1185 if (marked_zones(zone_indices(j))) then
1186 write(error_msg, '(A, I0, A, A, A, A)') &
1187 "Zone with index ", zone_indices(j), &
1188 " has already been assigned a boundary condition. ", &
1189 "Please check your boundary_conditions entry for the ", &
1190 "fluid and make sure that each zone index appears only ", &
1191 "in a single boundary condition."
1192 call neko_error(error_msg)
1193 else
1194 marked_zones(zone_indices(j)) = .true.
1195 end if
1196 end do
1197
1198 call fluid_pnpn_bc_split(bc_subdict, velocity_subdict, &
1199 pressure_subdict, has_velocity, has_pressure)
1200
1201 !
1202 ! Velocity
1203 !
1204 bc_i => null()
1205 if (has_velocity) then
1206 ! Set the ALE flag to true if there is any moving no_slip wall
1207 call json_get(velocity_subdict, "type", bc_type_str)
1208 if (trim(bc_type_str) .eq. "no_slip") then
1209 call json_get_or_default(velocity_subdict, "moving", moving_, &
1210 .false.)
1211 if (moving_) this%ale%has_moving_boundary = .true.
1212 end if
1213
1214 call velocity_bc_factory(bc_i, this, velocity_subdict, &
1215 this%c_Xh, user)
1216 end if
1217
1218 ! A homogeneous Neumann condition for velocity does not create an
1219 ! object, so we check.
1220 if (associated(bc_i)) then
1221
1222 select type (bc_i)
1223 type is (symmetry_aligned_t)
1224 ! In this case we need to tell the segregated projector where
1225 ! we have the dirichlet dofs component-wise. This is stored
1226 ! in the nested bcs. Of course, we rely on axis-alignment of
1227 ! the geometry.
1228 call this%bcs_vel_projector%mark(bc_i%bc_x, component = 'x')
1229 call this%bcs_vel_projector%mark(bc_i%bc_y, component = 'y')
1230 call this%bcs_vel_projector%mark(bc_i%bc_z, component = 'z')
1231 call this%bcs_vel%append(bc_i)
1232 call this%bc_sym_surface%mark_facets(bc_i%marked_facet)
1233 type is (symmetry_t)
1234 ! In this case we add the bc itself to the projector, which
1235 ! should be coupled.
1236 if (.not. this%full_stress_formulation) then
1237 call neko_error("The symmetry boundary condition " // &
1238 "requires the full stress formulation to be enabled.")
1239 end if
1240 call this%bcs_vel_projector%mark(bc_i)
1241 call this%bcs_vel%append(bc_i)
1242 call this%bc_sym_surface%mark_facets(bc_i%marked_facet)
1243 type is (non_normal_aligned_t)
1244 ! The situation is the same as symmetry.
1245 call this%bcs_vel_projector%mark(bc_i%bc_x, component = 'x')
1246 call this%bcs_vel_projector%mark(bc_i%bc_y, component = 'y')
1247 call this%bcs_vel_projector%mark(bc_i%bc_z, component = 'z')
1248 call this%bcs_vel%append(bc_i)
1249 type is (non_normal_t)
1250 call this%bcs_vel_projector%mark(bc_i)
1251 call this%bcs_vel%append(bc_i)
1252 type is (shear_stress_t)
1253 if (.not. this%full_stress_formulation) then
1254 call neko_error("The shear_stress boundary condition " // &
1255 "requires the full stress formulation to be enabled.")
1256 end if
1257 call this%bcs_vel_projector%mark(bc_i)
1258 call this%bcs_vel%append(bc_i)
1259 type is (wall_model_bc_t)
1260 if (.not. this%full_stress_formulation) then
1261 call neko_error("The wall_model boundary condition " // &
1262 "requires the full stress formulation to be enabled.")
1263 end if
1264 call this%bcs_vel_projector%mark(bc_i)
1265 call this%bcs_vel%append(bc_i)
1266 class is (mixed_bc_t)
1267 ! User-defined mixed conditions, resolved by the coupled
1268 ! projector.
1269 if (.not. this%full_stress_formulation) then
1270 call neko_error("The " // trim(bc_i%name) // &
1271 " boundary condition is a mixed condition and " // &
1272 "requires the full stress formulation to be enabled.")
1273 end if
1274 call this%bcs_vel_projector%mark(bc_i)
1275 call this%bcs_vel%append(bc_i)
1276 class default
1277
1278 ! Additionally we mark the special PnPn pressure bc.
1279 if (bc_i%bc_type .eq. bc_dirichlet) then
1280 call this%bc_prs_surface%mark_labeled_zones( &
1281 bc_i%zone_indices)
1282 if (this%full_stress_formulation) then
1283 call this%bcs_vel_projector%mark(bc_i)
1284 else
1285 call this%bcs_vel_projector%mark(bc_i, component = 'x')
1286 call this%bcs_vel_projector%mark(bc_i, component = 'y')
1287 call this%bcs_vel_projector%mark(bc_i, component = 'z')
1288 end if
1289 end if
1290
1291 call this%bcs_vel%append(bc_i)
1292 end select
1293 end if
1294
1295 !
1296 ! Pressure
1297 !
1298 bc_i => null()
1299 pressure_dirichlet = .false.
1300 if (has_pressure) then
1301 call pressure_bc_factory(bc_i, this, pressure_subdict, &
1302 this%c_Xh, user)
1303 end if
1304
1305 ! The natural pressure condition does not create an object, so we
1306 ! check.
1307 if (associated(bc_i)) then
1308 call this%bcs_prs%append(bc_i)
1309
1310 ! Mark strong pressure bcs in the projector to force zero change.
1311 if (bc_i%bc_type .eq. bc_dirichlet) then
1312 call this%bcs_prs_projector%mark(bc_i)
1313 pressure_dirichlet = .true.
1314 end if
1315 end if
1316
1317 ! Mark the facets of the zones for the FDM preconditioner: 1 where
1318 ! the pressure is strongly imposed, 2 otherwise.
1319 if (pressure_dirichlet) then
1320 facet_value = 1
1321 else
1322 facet_value = 2
1323 end if
1324
1325 do j = 1, size(zone_indices)
1326 do k = 1, this%msh%nelv
1327 do l = 1, 2 * this%msh%gdim
1328 if (this%msh%facet_type(l, k) .eq. -zone_indices(j)) then
1329 this%msh%facet_type(l, k) = facet_value
1330 end if
1331 end do
1332 end do
1333 end do
1334 end do
1335
1336 call velocity_subdict%destroy()
1337 call pressure_subdict%destroy()
1338
1339 if (this%ale%active .and. (.not. this%ale%has_moving_boundary)) then
1340 call neko_error("Case file error: ALE is active, " // &
1341 "but no moving wall was found. " // &
1342 "Use type = 'no_slip' with 'moving': true in case file.")
1343 end if
1344
1345 ! Make sure all labeled zones with non-zero size have been marked
1346 do i = 1, size(this%msh%labeled_zones)
1347 if ((this%msh%labeled_zones(i)%size .gt. 0) .and. &
1348 (.not. marked_zones(i))) then
1349 write(error_msg, '(A, I0)') &
1350 "No fluid boundary condition assigned to zone ", i
1351 call neko_error(error_msg)
1352 end if
1353 end do
1354 else
1355 ! Check that there are no labeled zones, i.e. all are periodic.
1356 do i = 1, size(this%msh%labeled_zones)
1357 if (this%msh%labeled_zones(i)%size .gt. 0) then
1358 call neko_error("No boundary_conditions entry in the case file!")
1359 end if
1360 end do
1361
1362 ! For a pure periodic case, we still need to initilise the bc lists
1363 ! to a zero size to avoid issues with apply() in step()
1364 call this%bcs_vel%init()
1365 call this%bcs_prs%init()
1366
1367 end if
1368
1369 call this%bc_prs_surface%finalize()
1370 call this%bc_sym_surface%finalize()
1371 call this%bcs_vel_projector%finalize(rebuild_mask = .true.)
1372
1373 ! If we have no strong pressure bcs, we will demean the pressure
1374 this%prs_dirichlet = this%bcs_prs_projector%dof_mask%is_set()
1375 call mpi_allreduce(mpi_in_place, this%prs_dirichlet, 1, &
1376 mpi_logical, mpi_lor, neko_comm)
1377
1378 if (allocated(marked_zones)) then
1379 deallocate(marked_zones)
1380 end if
1381
1382 if (allocated(zone_indices)) then
1383 deallocate(zone_indices)
1384 end if
1385
1386 nullify(bc_i, bc_object)
1387
1388 end subroutine fluid_pnpn_setup_bcs
1389
1391 subroutine fluid_pnpn_write_boundary_conditions(this)
1392 use inflow, only : inflow_t
1394 use blasius, only : blasius_t
1396 use dong_outflow, only : dong_outflow_t
1397 use no_slip, only : no_slip_t
1398 class(fluid_pnpn_t), target, intent(inout) :: this
1399 type(dirichlet_t) :: bdry_mask
1400 type(field_t), pointer :: bdry_field
1401 type(file_t) :: bdry_file
1402 integer :: temp_index, i
1403 class(bc_t), pointer :: bci
1404 character(len=LOG_SIZE) :: log_buf
1405
1406 write(log_buf, '(A)') 'Marking using integer keys in bdry0.f00000'
1407 call neko_log%message(log_buf)
1408 write(log_buf, '(A)') 'Condition-value pairs: '
1409 call neko_log%message(log_buf)
1410 write(log_buf, '(A)') ' no_slip (stationary wall) = 1'
1411 call neko_log%message(log_buf)
1412 write(log_buf, '(A)') ' velocity_value = 2'
1413 call neko_log%message(log_buf)
1414 write(log_buf, '(A)') ' outflow, normal_outflow (+dong) = 3'
1415 call neko_log%message(log_buf)
1416 write(log_buf, '(A)') ' symmetry = 4'
1417 call neko_log%message(log_buf)
1418 write(log_buf, '(A)') ' periodic = 6'
1419 call neko_log%message(log_buf)
1420 write(log_buf, '(A)') ' user_velocity = 7'
1421 call neko_log%message(log_buf)
1422 write(log_buf, '(A)') ' user_pressure = 8'
1423 call neko_log%message(log_buf)
1424 write(log_buf, '(A)') ' shear_stress = 9'
1425 call neko_log%message(log_buf)
1426 write(log_buf, '(A)') ' wall_modelling = 10'
1427 call neko_log%message(log_buf)
1428 write(log_buf, '(A)') ' blasius_profile = 11'
1429 call neko_log%message(log_buf)
1430 write(log_buf, '(A)') ' no_slip (moving wall) = 12'
1431 call neko_log%message(log_buf)
1432
1433 call neko_scratch_registry%request_field(bdry_field, temp_index, .true.)
1434
1435
1436
1437 call bdry_mask%init_from_components(this%c_Xh, 6.0_rp)
1438 call bdry_mask%mark_zone(this%msh%periodic)
1439 call bdry_mask%finalize()
1440 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1441 call bdry_mask%free()
1442
1443 do i = 1, this%bcs_prs%size()
1444 bci => this%bcs_prs%get(i)
1445 select type (bc => bci)
1446 type is (zero_dirichlet_t)
1447 call bdry_mask%init_from_components(this%c_Xh, 3.0_rp)
1448 call bdry_mask%mark_facets(bci%marked_facet)
1449 call bdry_mask%finalize()
1450 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1451 call bdry_mask%free()
1452 type is (dong_outflow_t)
1453 call bdry_mask%init_from_components(this%c_Xh, 3.0_rp)
1454 call bdry_mask%mark_facets(bci%marked_facet)
1455 call bdry_mask%finalize()
1456 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1457 call bdry_mask%free()
1458 type is (field_dirichlet_t)
1459 call bdry_mask%init_from_components(this%c_Xh, 8.0_rp)
1460 call bdry_mask%mark_facets(bci%marked_facet)
1461 call bdry_mask%finalize()
1462 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1463 call bdry_mask%free()
1464 end select
1465 end do
1466
1467 do i = 1, this%bcs_vel%size()
1468 bci => this%bcs_vel%get(i)
1469 select type (bc => bci)
1470 type is (no_slip_t)
1471 if (bc%is_moving) then
1472 ! moving wall
1473 call bdry_mask%init_from_components(this%c_Xh, 12.0_rp)
1474 else
1475 ! stationary wall
1476 call bdry_mask%init_from_components(this%c_Xh, 1.0_rp)
1477 end if
1478 call bdry_mask%mark_facets(bci%marked_facet)
1479 call bdry_mask%finalize()
1480 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1481 call bdry_mask%free()
1482 type is (inflow_t)
1483 call bdry_mask%init_from_components(this%c_Xh, 2.0_rp)
1484 call bdry_mask%mark_facets(bci%marked_facet)
1485 call bdry_mask%finalize()
1486 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1487 call bdry_mask%free()
1488 type is (symmetry_aligned_t)
1489 call bdry_mask%init_from_components(this%c_Xh, 4.0_rp)
1490 call bdry_mask%mark_facets(bci%marked_facet)
1491 call bdry_mask%finalize()
1492 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1493 call bdry_mask%free()
1494 type is (symmetry_t)
1495 call bdry_mask%init_from_components(this%c_Xh, 4.0_rp)
1496 call bdry_mask%mark_facets(bci%marked_facet)
1497 call bdry_mask%finalize()
1498 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1499 call bdry_mask%free()
1500 type is (field_dirichlet_vector_t)
1501 call bdry_mask%init_from_components(this%c_Xh, 7.0_rp)
1502 call bdry_mask%mark_facets(bci%marked_facet)
1503 call bdry_mask%finalize()
1504 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1505 call bdry_mask%free()
1506 type is (shear_stress_t)
1507 call bdry_mask%init_from_components(this%c_Xh, 9.0_rp)
1508 call bdry_mask%mark_facets(bci%marked_facet)
1509 call bdry_mask%finalize()
1510 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1511 call bdry_mask%free()
1512 type is (wall_model_bc_t)
1513 call bdry_mask%init_from_components(this%c_Xh, 10.0_rp)
1514 call bdry_mask%mark_facets(bci%marked_facet)
1515 call bdry_mask%finalize()
1516 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1517 call bdry_mask%free()
1518 type is (blasius_t)
1519 call bdry_mask%init_from_components(this%c_Xh, 11.0_rp)
1520 call bdry_mask%mark_facets(bci%marked_facet)
1521 call bdry_mask%finalize()
1522 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1523 call bdry_mask%free()
1524 end select
1525 end do
1526
1527
1528 call bdry_file%init('bdry.fld')
1529 call bdry_file%write(bdry_field)
1530
1531 call neko_scratch_registry%relinquish_field(temp_index)
1532
1533 nullify(bdry_field, bci)
1534
1535 end subroutine fluid_pnpn_write_boundary_conditions
1536
1537end module fluid_pnpn
double real
Copy data between host and device (or device and device)
Definition device.F90:72
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.
Apply cyclic boundary condition to a vector field.
Subroutines to add advection terms to the RHS of a transport equation.
Definition advection.f90:34
ALE Manager: Handles Mesh Motion.
Defines the full-stress SVV Helmholtz operator.
Base type for an SVV Helmholtz operator.
Defines a Matrix-vector product.
Definition ax.f90:34
Defines a boundary condition.
Definition bc.f90:34
integer, parameter, public bc_dirichlet
Supported boundary condition types. The values are set in order of precedence for global resolution....
Definition bc.f90:67
Defines a Blasius profile dirichlet condition.
Definition blasius.f90:34
Format-independent checkpoint payloads.
Defines format-independent checkpoint registration and restart state.
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
subroutine, public device_opadd2cm(a1_d, a2_d, a3_d, b1_d, b2_d, b3_d, c, n, gdim)
subroutine, public device_opcolv(a1_d, a2_d, a3_d, c_d, gdim, n)
Device abstraction, common interface for various accelerators.
Definition device.F90:34
subroutine, public device_event_sync(event)
Synchronize an event.
Definition device.F90:1667
integer, parameter, public host_to_device
Definition device.F90:48
type(c_ptr), bind(C), public glb_cmd_event
Event for the global command queue.
Definition device.F90:63
Defines a dirichlet boundary condition.
Definition dirichlet.f90:34
Defines a dong outflow condition.
Dirichlet condition applied in the facet normal direction.
Defines inflow dirichlet conditions.
Defines user dirichlet condition for a scalar field.
subroutine, public field_add2(a, b, n)
Vector addition .
subroutine, public field_copy(a, b, n)
Copy a vector .
Contains the field_serties_t type.
Defines a field.
Definition field.f90:34
Module for file I/O operations.
Definition file.f90:34
Auxiliary routines for fluid solvers.
Definition fluid_aux.f90:34
subroutine, public fluid_step_info(time, ksp_results, full_stress_formulation, strict_convergence, allow_stabilization, iteration)
Prints for prs, velx, vely, velz the following: Number of iterations, start residual,...
Definition fluid_aux.f90:54
Modular version of the Classic Nek5000 Pn/Pn formulation for fluids.
subroutine fluid_pnpn_setup_bcs(this, user, params)
Sets up the boundary conditions for the scheme.
subroutine fluid_pnpn_restart(this, chkp)
subroutine fluid_pnpn_write_boundary_conditions(this)
Write a field with boundary condition specifications.
subroutine fluid_pnpn_step(this, time, dt_controller)
Advance fluid simulation in time.
subroutine fluid_pnpn_free(this)
subroutine fluid_pnpn_init(this, msh, lx, params, user, chkp)
Defines Gather-scatter operations.
Definition gs_ops.f90:34
integer, parameter, public gs_op_add
Definition gs_ops.f90:36
Defines inflow dirichlet conditions.
Definition inflow.f90:34
Utilities for retrieving parameters from the case files.
Implements the base abstract type for Krylov solvers plus helper types.
Definition krylov.f90:34
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:92
integer, parameter, public log_size
Definition log.f90:46
Collection of vector field operations operating on and . Note that in general the indices and ....
Definition mathops.f90:67
subroutine, public opcolv(a1, a2, a3, c, gdim, n)
Definition mathops.f90:103
subroutine, public opadd2cm(a1, a2, a3, b1, b2, b3, c, n, gdim)
Definition mathops.f90:156
Defines a mesh.
Definition mesh.f90:34
Implements mixed_bc_t.
Definition mixed_bc.f90:31
Build configurations.
integer, parameter neko_bcknd_device
Defines no-slip boundary condition (extends zero_dirichlet)
Definition no_slip.f90:34
Implements non_normal_aligned_t.
Implements non_normal_t.
integer, parameter, public dp
Definition num_types.f90:10
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Operators.
Definition operators.f90:34
subroutine, public ortho(x, glb_n_points, n)
Othogonalize with regard to vector (1,1,1,1,1,1...,1)^T.
Operators accelerator backends.
subroutine, public device_ortho(x_d, glb_n_points, n)
Othogonalize with regard to vector (1,1,1,1,1,1...,1)^T.
Defines Pressure and velocity residuals in the Pn-Pn formulation.
Definition pnpn_res.f90:34
Profiling interface.
Definition profiler.F90:34
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
Definition profiler.F90:79
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Definition profiler.F90:116
Project x onto X , the space of old solutions and back again Couple projections for velocity.
Project x onto X, the space of old solutions and back again.
Defines a registry for storing solution fields.
Definition registry.f90:34
type(registry_t), target, public neko_registry
Global field registry.
Definition registry.f90:158
Routines to generate the right-hand sides for the convection-diffusion equation. Employs the EXT/BDF ...
Definition rhs_maker.f90:38
Implements scalar_projector_t.
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.
Defines a shear stress boundary condition for a vector field. Maintainer: Timofey Mukha.
Implements the source_term_t type and a wrapper source_term_wrapper_t.
Implements symmetry_aligned_t.
Implements symmetry_t.
Definition symmetry.f90:34
Module with things related to the simulation time.
Implements type time_step_controller.
Interfaces for user interaction with NEKO.
Definition user_intf.f90:34
Utilities.
Definition utils.f90:35
integer, parameter, public neko_typename_len
Definition utils.f90:44
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.
Base abstract type for computing the advection operator.
Definition advection.f90:46
Helmholtz operator carrying a non-owning SVV object.
Matrix-vector product for a Helmholtz problem.
Base type for a matrix-vector product providing .
Definition ax.f90:44
Base type for a boundary condition.
Definition bc.f90:73
Blasius profile for inlet (vector valued).
Definition blasius.f90:55
Collection of live simulation data registered for checkpointing.
A named collection of live fields to checkpoint together.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:136
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 in facet normal direction.
User defined dirichlet condition, for which the user can work with an entire field....
Extension of the user defined dirichlet condition field_dirichlet
Stores a series (sequence) of fields, logically connected to a base field, and arranged according to ...
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition file.f90:56
Dirichlet condition for inlet (vector valued)
Definition inflow.f90:48
Type for storing initial and final residuals in a Krylov solver.
Definition krylov.f90:57
Base type for mixed boundary conditions that need projector-provided local-basis data on the physical...
Definition mixed_bc.f90:50
Mixed Dirichlet condition constraining the tangential vector components.
Axis-aligned mixed Dirichlet condition in the non-normal direction.
Abstract type to compute pressure residual.
Definition pnpn_res.f90:48
Abstract type to compute velocity residual.
Definition pnpn_res.f90:54
Abstract type to add contributions to F from lagged BD terms.
Definition rhs_maker.f90:59
Abstract type to sum up contributions to kth order extrapolation scheme.
Definition rhs_maker.f90:52
Abstract type to add contributions of kth order OIFS scheme.
Definition rhs_maker.f90:66
Abstract type to compute extrapolated velocity field for the pressure equation.
Definition rhs_maker.f90:46
Projector for scalar boundary conditions.
A shear stress boundary condition.
Symmetry boundary condition constraining the normal vector component.
Definition symmetry.f90:50
Axis-aligned symmetry boundary condition.
A struct that contains all info about the time, expand as needed.
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.
Abstract type for resolving vector boundary conditions.
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...