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
359 character(len=:), allocatable :: solver_type, precon_type
360 logical :: found
361 logical :: advection
362 type(json_file) :: numerics_params, precon_params, solver_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(params, 'case.fluid.pressure_solver', solver_params)
502 call json_get(params, 'case.fluid.pressure_solver.type', solver_type)
503 call json_get(params, 'case.fluid.pressure_solver.preconditioner.type', &
504 precon_type)
505 call json_get(params, &
506 'case.fluid.pressure_solver.preconditioner', precon_params)
507 call json_get_or_lookup(params, &
508 'case.fluid.pressure_solver.absolute_tolerance', &
509 abs_tol)
510 call neko_log%message('Type : ('// trim(solver_type) // &
511 ', ' // trim(precon_type) // ')')
512 write(log_buf, '(A,ES13.6)') 'Abs tol :', abs_tol
513 call neko_log%message(log_buf)
514
515 call this%solver_factory(this%ksp_prs, this%dm_Xh%size(), solver_params)
516 call this%precon_factory_(this%pc_prs, this%ksp_prs, &
517 this%c_Xh, this%bcs_prs, &
518 precon_type, precon_params)
519 call neko_log%end_section()
520
521 ! Initialize the advection factory
522 call json_get_or_default(params, 'case.fluid.advection', advection, .true.)
523 ! OIFS integrates the advection term. With advection disabled, fall back to
524 ! the standard BDF history assembly.
525 this%oifs = this%oifs .and. advection
526 call json_get(params, 'case.numerics', numerics_params)
527 call chkp%get_time_history(tlag, dtlag)
528 call advection_factory(this%adv, numerics_params, this%c_Xh, &
529 this%ulag, this%vlag, this%wlag, &
530 dtlag, tlag, this%ext_bdf, &
531 .not. advection)
532 ! Should be in init_base maybe?
533 this%chkp => chkp
534 ! Register the scheme state for checkpointing.
535 payload => this%chkp%add_payload("fluid")
536 call payload%add_field(this%u)
537 call payload%add_field(this%v)
538 call payload%add_field(this%w)
539 call payload%add_field(this%p)
540 call payload%add_field(this%abx1)
541 call payload%add_field(this%abx2)
542 call payload%add_field(this%aby1)
543 call payload%add_field(this%aby2)
544 call payload%add_field(this%abz1)
545 call payload%add_field(this%abz2)
546 call payload%add_series(this%ulag)
547 call payload%add_series(this%vlag)
548 call payload%add_series(this%wlag)
549
551 call json_get_or_default(params, 'case.fluid.schwarz_iterations', &
552 this%schwarz_iterations, 0)
553
554 call neko_log%end_section()
555
556 nullify(bc_i, vel_bc)
557
558 end subroutine fluid_pnpn_init
559
562 subroutine fluid_pnpn_ax_vel_factory(this)
563 class(fluid_pnpn_t), target, intent(inout) :: this
564
565 if (this%full_stress_formulation) then
566 if (this%svv_enabled) then
567 call ax_helm_allocator(this%Ax_vel, type_name = "full_svv")
568 select type (operator => this%Ax_vel)
569 class is (ax_helm_svv_full_t)
570 operator%svv => this%svv
571 end select
572 else
573 call ax_helm_allocator(this%Ax_vel, type_name = "full")
574 end if
575 else
576 if (this%svv_enabled) then
577 call ax_helm_allocator(this%Ax_vel, type_name = "standard_svv")
578 select type (operator => this%Ax_vel)
579 class is (ax_helm_svv_t)
580 operator%svv => this%svv
581 end select
582 else if (this%c_Xh%geo_compression) then
583 call ax_helm_allocator(this%Ax_vel, &
584 type_name = "standard_compr")
585 else
586 call ax_helm_allocator(this%Ax_vel, type_name = "standard")
587 end if
588 end if
589
590 end subroutine fluid_pnpn_ax_vel_factory
591
592 subroutine fluid_pnpn_restart(this, chkp)
593 class(fluid_pnpn_t), target, intent(inout) :: this
594 type(chkp_t), intent(inout) :: chkp
595 integer :: i, j, n
596 class(bc_t), pointer :: bc_i
597
598 n = this%u%dof%size()
599 if (allocated(chkp%previous_mesh%elements) .or. &
600 chkp%previous_Xh%lx .ne. this%Xh%lx) then
601 associate(u => this%u, v => this%v, w => this%w, p => this%p, &
602 c_xh => this%c_Xh, ulag => this%ulag, vlag => this%vlag, &
603 wlag => this%wlag)
604 do concurrent(j = 1:n)
605 u%x(j,1,1,1) = u%x(j,1,1,1) * c_xh%mult(j,1,1,1)
606 v%x(j,1,1,1) = v%x(j,1,1,1) * c_xh%mult(j,1,1,1)
607 w%x(j,1,1,1) = w%x(j,1,1,1) * c_xh%mult(j,1,1,1)
608 p%x(j,1,1,1) = p%x(j,1,1,1) * c_xh%mult(j,1,1,1)
609 end do
610 do i = 1, this%ulag%size()
611 do concurrent(j = 1:n)
612 ulag%lf(i)%x(j,1,1,1) = ulag%lf(i)%x(j,1,1,1) &
613 * c_xh%mult(j,1,1,1)
614 vlag%lf(i)%x(j,1,1,1) = vlag%lf(i)%x(j,1,1,1) &
615 * c_xh%mult(j,1,1,1)
616 wlag%lf(i)%x(j,1,1,1) = wlag%lf(i)%x(j,1,1,1) &
617 * c_xh%mult(j,1,1,1)
618 end do
619 end do
620 end associate
621 end if
622
623 if (neko_bcknd_device .eq. 1) then
624 associate(u => this%u, v => this%v, w => this%w, &
625 ulag => this%ulag, vlag => this%vlag, wlag => this%wlag,&
626 p => this%p)
627 call device_memcpy(u%x, u%x_d, u%dof%size(), &
628 host_to_device, sync = .false.)
629 call device_memcpy(v%x, v%x_d, v%dof%size(), &
630 host_to_device, sync = .false.)
631 call device_memcpy(w%x, w%x_d, w%dof%size(), &
632 host_to_device, sync = .false.)
633 call device_memcpy(p%x, p%x_d, p%dof%size(), &
634 host_to_device, sync = .false.)
635 call device_memcpy(ulag%lf(1)%x, ulag%lf(1)%x_d, &
636 u%dof%size(), host_to_device, sync = .false.)
637 call device_memcpy(ulag%lf(2)%x, ulag%lf(2)%x_d, &
638 u%dof%size(), host_to_device, sync = .false.)
639
640 call device_memcpy(vlag%lf(1)%x, vlag%lf(1)%x_d, &
641 v%dof%size(), host_to_device, sync = .false.)
642 call device_memcpy(vlag%lf(2)%x, vlag%lf(2)%x_d, &
643 v%dof%size(), host_to_device, sync = .false.)
644
645 call device_memcpy(wlag%lf(1)%x, wlag%lf(1)%x_d, &
646 w%dof%size(), host_to_device, sync = .false.)
647 call device_memcpy(wlag%lf(2)%x, wlag%lf(2)%x_d, &
648 w%dof%size(), host_to_device, sync = .false.)
649 call device_memcpy(this%abx1%x, this%abx1%x_d, &
650 w%dof%size(), host_to_device, sync = .false.)
651 call device_memcpy(this%abx2%x, this%abx2%x_d, &
652 w%dof%size(), host_to_device, sync = .false.)
653 call device_memcpy(this%aby1%x, this%aby1%x_d, &
654 w%dof%size(), host_to_device, sync = .false.)
655 call device_memcpy(this%aby2%x, this%aby2%x_d, &
656 w%dof%size(), host_to_device, sync = .false.)
657 call device_memcpy(this%abz1%x, this%abz1%x_d, &
658 w%dof%size(), host_to_device, sync = .false.)
659 call device_memcpy(this%abz2%x, this%abz2%x_d, &
660 w%dof%size(), host_to_device, sync = .false.)
661 call device_memcpy(this%advx%x, this%advx%x_d, &
662 w%dof%size(), host_to_device, sync = .false.)
663 call device_memcpy(this%advy%x, this%advy%x_d, &
664 w%dof%size(), host_to_device, sync = .false.)
665 call device_memcpy(this%advz%x, this%advz%x_d, &
666 w%dof%size(), host_to_device, sync = .false.)
667 end associate
668 end if
669 ! Make sure that continuity is maintained (important for interpolation)
670 ! Do not do this for lagged rhs
671 ! (derivatives are not necessairly coninous across elements)
672
673 if (allocated(chkp%previous_mesh%elements) &
674 .or. chkp%previous_Xh%lx .ne. this%Xh%lx) then
675
676 call rotate_cyc(this%u, this%v, this%w, 1, this%c_Xh)
677 call this%gs_Xh%op(this%u, gs_op_add)
678 call this%gs_Xh%op(this%v, gs_op_add)
679 call this%gs_Xh%op(this%w, gs_op_add)
680 call this%gs_Xh%op(this%p, gs_op_add)
681 call rotate_cyc(this%u, this%v, this%w, 0, this%c_Xh)
682
683 do i = 1, this%ulag%size()
684 call rotate_cyc(this%ulag%lf(i), this%vlag%lf(i), &
685 this%wlag%lf(i), 1, this%c_Xh)
686 call this%gs_Xh%op(this%ulag%lf(i), gs_op_add)
687 call this%gs_Xh%op(this%vlag%lf(i), gs_op_add)
688 call this%gs_Xh%op(this%wlag%lf(i), gs_op_add)
689 call rotate_cyc(this%ulag%lf(i), this%vlag%lf(i), &
690 this%wlag%lf(i), 0, this%c_Xh)
691 end do
692 end if
693
694 call this%ale%sync_chkp(this%c_Xh, this%Xh, this%adv, chkp, this%gs_Xh)
695 if (this%ale%active) then
696 call this%bc_prs_surface%recompute_normals()
697 call this%bc_sym_surface%recompute_normals()
698 end if
699
700 ! Restore velocity bcs that need it (overset mostly)
701 do i = 1, this%bcs_vel%size()
702 bc_i => this%bcs_vel%get(i)
703 call bc_i%restart(this%u, this%v, this%w, &
704 this%ulag, this%vlag, this%wlag)
705 end do
706
707 ! Restore pressure bcs that need it (overset mostly)
708 do i = 1, this%bcs_prs%size()
709 bc_i => this%bcs_prs%get(i)
710 call bc_i%restart(this%p)
711 end do
712
713 nullify(bc_i)
714
715 end subroutine fluid_pnpn_restart
716
717 subroutine fluid_pnpn_free(this)
718 class(fluid_pnpn_t), intent(inout) :: this
719
720 if (allocated(this%Ax_vel)) then
721 call this%Ax_vel%free()
722 deallocate(this%Ax_vel)
723 end if
724
725 if (allocated(this%Ax_prs)) then
726 call this%Ax_prs%free()
727 deallocate(this%Ax_prs)
728 end if
729
730 !Deallocate velocity and pressure fields
731 call this%scheme_free()
732
733 if (allocated(this%ext_bdf)) then
734 call this%ext_bdf%free()
735 deallocate(this%ext_bdf)
736 end if
737
738 call this%bc_prs_surface%free()
739 call this%bc_sym_surface%free()
740 if (allocated(this%bcs_vel_projector)) then
741 call this%bcs_vel_projector%free()
742 deallocate(this%bcs_vel_projector)
743 end if
744 call this%bcs_prs_projector%free()
745 call this%proj_prs%free()
746 call this%proj_vel%free()
747
748 call this%p_res%free()
749 call this%u_res%free()
750 call this%v_res%free()
751 call this%w_res%free()
752
753 call this%ale%free()
754
755 call this%du%free()
756 call this%dv%free()
757 call this%dw%free()
758 call this%dp%free()
759
760 call this%abx1%free()
761 call this%aby1%free()
762 call this%abz1%free()
763
764 call this%abx2%free()
765 call this%aby2%free()
766 call this%abz2%free()
767
768 call this%advx%free()
769 call this%advy%free()
770 call this%advz%free()
771
772 if (allocated(this%adv)) then
773 call this%adv%free()
774 deallocate(this%adv)
775 end if
776
777 if (allocated(this%prs_res)) then
778 deallocate(this%prs_res)
779 end if
780
781 if (allocated(this%vel_res)) then
782 deallocate(this%vel_res)
783 end if
784
785 if (allocated(this%sumab)) then
786 deallocate(this%sumab)
787 end if
788
789 if (allocated(this%makeabf)) then
790 deallocate(this%makeabf)
791 end if
792
793 if (allocated(this%makebdf)) then
794 deallocate(this%makebdf)
795 end if
796
797 if (allocated(this%makeoifs)) then
798 deallocate(this%makeoifs)
799 end if
800
801 if (allocated(this%ext_bdf)) then
802 deallocate(this%ext_bdf)
803 end if
804
805 call this%vol_flow%free()
806
807 end subroutine fluid_pnpn_free
808
815 subroutine fluid_pnpn_step(this, time, dt_controller)
816 class(fluid_pnpn_t), target, intent(inout) :: this
817 type(time_state_t), intent(in) :: time
818 type(time_step_controller_t), intent(in) :: dt_controller
819 ! number of degrees of freedom
820 integer :: n
821 ! Solver results monitors (pressure + 3 velocity)
822 type(ksp_monitor_t) :: ksp_results(4)
823 integer :: iter
824
825 type(file_t) :: dump_file
826 class(bc_t), pointer :: bc_i
827
828 if (this%freeze) return
829
830 n = this%dm_Xh%size()
831
832 call profiler_start_region('Fluid', 1)
833 associate(u => this%u, v => this%v, w => this%w, p => this%p, &
834 u_e => this%u_e, v_e => this%v_e, w_e => this%w_e, &
835 du => this%du, dv => this%dv, dw => this%dw, dp => this%dp, &
836 u_res => this%u_res, v_res => this%v_res, w_res => this%w_res, &
837 p_res => this%p_res, ax_vel => this%Ax_vel, ax_prs => this%Ax_prs, &
838 xh => this%Xh, &
839 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
840 ulag => this%ulag, vlag => this%vlag, wlag => this%wlag, &
841 msh => this%msh, prs_res => this%prs_res, &
842 source_term => this%source_term, vel_res => this%vel_res, &
843 sumab => this%sumab, makeoifs => this%makeoifs, &
844 makeabf => this%makeabf, makebdf => this%makebdf, &
845 vel_projection_dim => this%vel_projection_dim, &
846 pr_projection_dim => this%pr_projection_dim, &
847 oifs => this%oifs, &
848 rho => this%rho, mu_tot => this%mu_tot, &
849 f_x => this%f_x, f_y => this%f_y, f_z => this%f_z, &
850 t => time%t, tstep => time%tstep, dt => time%dt, &
851 ext_bdf => this%ext_bdf, event => glb_cmd_event, &
852 ale => this%ale)
853
854 ! Extrapolate the velocity if it's not done in nut_field estimation
855 call sumab%compute_fluid(u_e, v_e, w_e, u, v, w, &
856 ulag, vlag, wlag, ext_bdf%advection_coeffs%x, ext_bdf%nadv)
857
858 ! Compute the source terms that are extrapolated in time below
859 call this%source_term%compute(time, extrapolate = .true.)
860
861 ! Add Neumann bc contributions to the RHS
862 call this%bcs_vel%apply_vector(f_x%x, f_y%x, f_z%x, &
863 this%dm_Xh%size(), time, strong = .false.)
864
865 if (this%ale%active) then
866 if (oifs) then
867 call neko_error("ALE is not yet supported " // &
868 "with OIFS time integration.")
869 end if
871 call this%adv%compute_ale(u, v, w, &
872 ale%wm_x, ale%wm_y, ale%wm_z, &
873 f_x, f_y, f_z, &
874 xh, c_xh, dm_xh%size())
875 end if
876
877
878 if (oifs) then
879 ! Add the advection operators to the right-hand-side.
880 call this%adv%compute(u, v, w, &
881 this%advx, this%advy, this%advz, &
882 xh, this%c_Xh, dm_xh%size(), real(dt, kind=rp))
883
884 ! At this point the RHS contains the sum of the advection operator and
885 ! additional source terms, evaluated using the velocity field from the
886 ! previous time-step. Now, this value is used in the explicit time
887 ! scheme to advance both terms in time.
888
889 call makeabf%compute_fluid(this%abx1, this%aby1, this%abz1,&
890 this%abx2, this%aby2, this%abz2, &
891 f_x%x, f_y%x, f_z%x, &
892 rho%x(1,1,1,1), ext_bdf%advection_coeffs%x, n)
893
894 ! Now, the source terms from the previous time step are added to the
895 ! RHS.
896 call makeoifs%compute_fluid(this%advx%x, this%advy%x, this%advz%x, &
897 f_x%x, f_y%x, f_z%x, &
898 rho%x(1,1,1,1), real(dt, kind=rp), n)
899 else
900 ! Add the advection operators to the right-hand-side.
901 call this%adv%compute(u, v, w, &
902 f_x, f_y, f_z, &
903 xh, this%c_Xh, dm_xh%size())
904
905 ! At this point the RHS contains the sum of the advection operator and
906 ! additional source terms, evaluated using the velocity field from the
907 ! previous time-step. Now, this value is used in the explicit time
908 ! scheme to advance both terms in time.
909
910 call makeabf%compute_fluid(this%abx1, this%aby1, this%abz1,&
911 this%abx2, this%aby2, this%abz2, &
912 f_x%x, f_y%x, f_z%x, &
913 rho%x(1,1,1,1), ext_bdf%advection_coeffs%x, n)
914
915 ! Add the RHS contributions coming from the BDF scheme.
916 ! Blag and Blaglag are history of B matrices, mainly used for ALE.
917 ! For a normal simulation (no moving mesh), Blag and Blaglag
918 ! are just the initial B matrix, filled at initialization.
919 call makebdf%compute_fluid(ulag, vlag, wlag, f_x%x, f_y%x, f_z%x, &
920 u, v, w, c_xh%B, c_xh%Blag, c_xh%Blaglag, rho%x(1,1,1,1), &
921 real(dt, kind=rp), &
922 ext_bdf%diffusion_coeffs%x, ext_bdf%ndiff, n)
923
924 end if
925
926 ! Source terms that must not be extrapolated in time are added as
927 ! computed, weighted by the mass matrix and the density like the
928 ! extrapolated terms above.
929 call this%source_term%compute(time, extrapolate = .false., scale = rho)
930
931 if (this%ale%active) then
932 ! Advance Mesh (Moves points, updates B history, updates wm_lags)
933 call this%ale%advance_mesh(c_xh, time, ext_bdf%nadv)
934
935 call profiler_start_region('ALE recompute metrics')
936 ! Update Metrics
937 call c_xh%recompute_metrics()
938 ! Update the metrics used by the adv operator for delaiasing (coef_GL)
939 ! Maps the updated coef_GLL to coef_GL.
940 call this%adv%recompute_metrics(c_xh, .true.)
941
942 call this%bc_prs_surface%recompute_normals()
943 call this%bc_sym_surface%recompute_normals()
944 call profiler_end_region('ALE recompute metrics')
945 end if
946
947 call ulag%update()
948 call vlag%update()
949 call wlag%update()
950
951 ! Update material properties if necessary
952 call this%update_material_properties(time)
953
954 ! Update the SVV coefficient if necessary
955 if (this%svv_enabled) then
956 call this%svv%update(rho, tstep)
957 end if
958
959 do iter = 1, 1 + this%schwarz_iterations
960
961 call this%bc_apply_vel(time, strong = .true.)
962 call this%bc_apply_prs(time)
963
964 ! Compute pressure residual.
965 call profiler_start_region('Pressure_residual', 18)
966 call prs_res%compute(p, p_res,&
967 u, v, w, &
968 u_e, v_e, w_e, &
969 f_x, f_y, f_z, &
970 c_xh, gs_xh, &
971 this%bc_prs_surface, this%bc_sym_surface,&
972 ax_prs, ext_bdf%diffusion_coeffs%x(1), real(dt, kind=rp), &
973 mu_tot, rho, event)
974
975
976 ! De-mean the pressure residual when no strong pressure boundaries present
977 if (.not. this%prs_dirichlet .and. neko_bcknd_device .eq. 1) then
978 call device_ortho(p_res%x_d, this%glb_n_points, n)
979 else if (.not. this%prs_dirichlet) then
980 call ortho(p_res%x, this%glb_n_points, n)
981 end if
982
983 call gs_xh%op(p_res, gs_op_add, event)
984 call device_event_sync(event)
985
986 ! Set the residual to zero at strong pressure boundaries.
987 call this%bcs_prs_projector%apply(p_res%x, p%dof%size())
988
989
990 call profiler_end_region('Pressure_residual', 18)
991
992 ! Do projections only on the actual solutions of the tstep
993 ! not intermediate solutions from the subiterations.
994 if (iter .eq. 1) then
995 call this%proj_prs%pre_solving(p_res%x, tstep, c_xh, n, &
996 dt_controller, ax = ax_prs, gs_h = gs_xh, &
997 bclst = this%bcs_prs_projector, string = 'Pressure')
998 end if
999
1000 call this%pc_prs%update()
1001
1002 call profiler_start_region('Pressure_solve', 3)
1003
1004 ! Solve for the pressure increment.
1005 ksp_results(1) = &
1006 this%ksp_prs%solve(ax_prs, dp, p_res%x, n, c_xh, &
1007 this%bcs_prs_projector, gs_xh)
1008 ksp_results(1)%name = 'Pressure'
1009
1010
1011 call profiler_end_region('Pressure_solve', 3)
1012
1013 if (iter .eq. 1) then
1014 call this%proj_prs%post_solving(dp%x, ax_prs, c_xh, &
1015 this%bcs_prs_projector, gs_xh, n, tstep, dt_controller)
1016 end if
1017
1018 ! Update the pressure with the increment. Demean if necessary.
1019 call field_add2(p, dp, n)
1020 if (.not. this%prs_dirichlet .and. neko_bcknd_device .eq. 1) then
1021 call device_ortho(p%x_d, this%glb_n_points, n)
1022 else if (.not. this%prs_dirichlet) then
1023 call ortho(p%x, this%glb_n_points, n)
1024 end if
1025
1026 ! Compute velocity residual.
1027 call profiler_start_region('Velocity_residual', 19)
1028 call vel_res%compute(ax_vel, u, v, w, &
1029 u_res, v_res, w_res, &
1030 p, &
1031 f_x, f_y, f_z, &
1032 c_xh, msh, xh, &
1033 mu_tot, rho, ext_bdf%diffusion_coeffs%x(1), &
1034 real(dt, kind=rp), dm_xh%size())
1035
1036 call rotate_cyc(u_res, v_res, w_res, 1, c_xh)
1037 call gs_xh%op(u_res%x, v_res%x, w_res%x, dm_xh%size(), &
1038 gs_op_add, event)
1039 call device_event_sync(event)
1040 call rotate_cyc(u_res, v_res, w_res, 0, c_xh)
1041
1042 ! Set residual to zero at strong velocity boundaries.
1043 call this%bcs_vel_projector%apply(u_res%x, v_res%x, w_res%x, &
1044 dm_xh%size())
1045
1046
1047 call profiler_end_region('Velocity_residual', 19)
1048
1049 if (iter .eq. 1) then
1050 call this%proj_vel%pre_solving(u_res%x, v_res%x, w_res%x, &
1051 tstep, c_xh, n, dt_controller, 'Velocity')
1052 end if
1053
1054 call this%pc_vel%update()
1055
1056 call profiler_start_region("Velocity_solve", 4)
1057 ksp_results(2:4) = this%ksp_vel%solve_coupled(ax_vel, du, dv, dw, &
1058 u_res%x, v_res%x, w_res%x, n, c_xh, &
1059 this%bcs_vel_projector, gs_xh, &
1060 this%ksp_vel%max_iter)
1061 call profiler_end_region("Velocity_solve", 4)
1062 if (this%full_stress_formulation) then
1063 ksp_results(2)%name = 'Momentum'
1064 else
1065 ksp_results(2)%name = 'X-Velocity'
1066 ksp_results(3)%name = 'Y-Velocity'
1067 ksp_results(4)%name = 'Z-Velocity'
1068 end if
1069
1070 if (iter .eq. 1) then
1071 call this%proj_vel%post_solving(du%x, dv%x, dw%x, ax_vel, c_xh, &
1072 this%bcs_vel_projector, gs_xh, n, tstep, &
1073 dt_controller)
1074 end if
1075
1076 if (neko_bcknd_device .eq. 1) then
1077 call device_opadd2cm(u%x_d, v%x_d, w%x_d, &
1078 du%x_d, dv%x_d, dw%x_d, 1.0_rp, n, msh%gdim)
1079 else
1080 call opadd2cm(u%x, v%x, w%x, du%x, dv%x, dw%x, 1.0_rp, n, msh%gdim)
1081 end if
1082
1083 call fluid_step_info(time, ksp_results, &
1084 this%full_stress_formulation, this%strict_convergence, &
1085 this%allow_stabilization, iter)
1086
1087 end do
1088
1089 if (this%forced_flow_rate) then
1090 ! Horrible mu hack?!
1091 call this%vol_flow%adjust( u, v, w, p, u_res, v_res, w_res, p_res, &
1092 c_xh, gs_xh, ext_bdf, rho%x(1,1,1,1), mu_tot, &
1093 real(dt, kind=rp), time, this%bcs_prs_projector, &
1094 this%bcs_vel_projector, ax_vel, ax_prs, this%ksp_prs, &
1095 this%ksp_vel, this%pc_prs, this%pc_vel, this%ksp_prs%max_iter, &
1096 this%ksp_vel%max_iter)
1097 end if
1098
1099 ! Update mesh velocities for ALE
1100 ! We update them here (end of step) for the next step.
1101 ! Returns if .not. ale.
1102 call this%ale%update_mesh_velocity(c_xh, time)
1103
1104 end associate
1105
1106 nullify(bc_i)
1107
1108 call profiler_end_region('Fluid', 1)
1109 end subroutine fluid_pnpn_step
1110
1121 subroutine fluid_pnpn_setup_bcs(this, user, params)
1122 class(fluid_pnpn_t), target, intent(inout) :: this
1123 type(user_t), target, intent(in) :: user
1124 type(json_file), intent(inout) :: params
1125 integer :: i, n_bcs, j, k, l, zone_size, global_zone_size, ierr
1126 integer :: facet_value
1127 class(bc_t), pointer :: bc_i
1128 type(json_core) :: core
1129 type(json_value), pointer :: bc_object
1130 type(json_file) :: bc_subdict, velocity_subdict, pressure_subdict
1131 logical :: moving_, has_velocity, has_pressure, pressure_dirichlet
1132 logical :: found
1133 ! Monitor which boundary zones have been marked
1134 logical, allocatable :: marked_zones(:)
1135 integer, allocatable :: zone_indices(:)
1136 character(len=256) :: error_msg
1137 character(len=:), allocatable :: bc_type_str
1138
1139 this%ale%has_moving_boundary = .false.
1140
1141 ! Special PnPn boundary conditions for pressure
1142 call this%bc_prs_surface%init_from_components(this%c_Xh)
1143 call this%bc_sym_surface%init_from_components(this%c_Xh)
1144
1145 ! Populate bcs_vel and bcs_prs based on the case file
1146 if (params%valid_path('case.fluid.boundary_conditions')) then
1147 call params%info('case.fluid.boundary_conditions', n_children = n_bcs)
1148 call params%get_core(core)
1149 call params%get('case.fluid.boundary_conditions', bc_object, found)
1150
1151 call this%bcs_vel%init(n_bcs)
1152 call this%bcs_prs%init(n_bcs)
1153
1154 allocate(marked_zones(size(this%msh%labeled_zones)))
1155 marked_zones = .false.
1156
1157 do i = 1, n_bcs
1158 ! Create a new json containing just the subdict for this bc
1159 call json_extract_item(core, bc_object, i, bc_subdict)
1160
1161 call json_get_or_lookup(bc_subdict, "zone_indices", zone_indices)
1162
1163 ! Check that we are not trying to assing a bc to zone, for which one
1164 ! has already been assigned and that the zone has more than 0 size
1165 ! in the mesh.
1166 do j = 1, size(zone_indices)
1167 zone_size = this%msh%labeled_zones(zone_indices(j))%size
1168 call mpi_allreduce(zone_size, global_zone_size, 1, &
1169 mpi_integer, mpi_max, neko_comm, ierr)
1170
1171 if (global_zone_size .eq. 0) then
1172 write(error_msg, '(A, I0, A, A, I0, A)') &
1173 "Zone index ", zone_indices(j), &
1174 " is invalid as this zone has 0 size, meaning it ", &
1175 "is not in the mesh. Check fluid boundary condition ", &
1176 i, "."
1177 call neko_error(error_msg)
1178 end if
1179
1180 if (marked_zones(zone_indices(j))) then
1181 write(error_msg, '(A, I0, A, A, A, A)') &
1182 "Zone with index ", zone_indices(j), &
1183 " has already been assigned a boundary condition. ", &
1184 "Please check your boundary_conditions entry for the ", &
1185 "fluid and make sure that each zone index appears only ", &
1186 "in a single boundary condition."
1187 call neko_error(error_msg)
1188 else
1189 marked_zones(zone_indices(j)) = .true.
1190 end if
1191 end do
1192
1193 call fluid_pnpn_bc_split(bc_subdict, velocity_subdict, &
1194 pressure_subdict, has_velocity, has_pressure)
1195
1196 !
1197 ! Velocity
1198 !
1199 bc_i => null()
1200 if (has_velocity) then
1201 ! Set the ALE flag to true if there is any moving no_slip wall
1202 call json_get(velocity_subdict, "type", bc_type_str)
1203 if (trim(bc_type_str) .eq. "no_slip") then
1204 call json_get_or_default(velocity_subdict, "moving", moving_, &
1205 .false.)
1206 if (moving_) this%ale%has_moving_boundary = .true.
1207 end if
1208
1209 call velocity_bc_factory(bc_i, this, velocity_subdict, &
1210 this%c_Xh, user)
1211 end if
1212
1213 ! A homogeneous Neumann condition for velocity does not create an
1214 ! object, so we check.
1215 if (associated(bc_i)) then
1216
1217 select type (bc_i)
1218 type is (symmetry_aligned_t)
1219 ! In this case we need to tell the segregated projector where
1220 ! we have the dirichlet dofs component-wise. This is stored
1221 ! in the nested bcs. Of course, we rely on axis-alignment of
1222 ! the geometry.
1223 call this%bcs_vel_projector%mark(bc_i%bc_x, component = 'x')
1224 call this%bcs_vel_projector%mark(bc_i%bc_y, component = 'y')
1225 call this%bcs_vel_projector%mark(bc_i%bc_z, component = 'z')
1226 call this%bcs_vel%append(bc_i)
1227 call this%bc_sym_surface%mark_facets(bc_i%marked_facet)
1228 type is (symmetry_t)
1229 ! In this case we add the bc itself to the projector, which
1230 ! should be coupled.
1231 if (.not. this%full_stress_formulation) then
1232 call neko_error("The symmetry boundary condition " // &
1233 "requires the full stress formulation to be enabled.")
1234 end if
1235 call this%bcs_vel_projector%mark(bc_i)
1236 call this%bcs_vel%append(bc_i)
1237 call this%bc_sym_surface%mark_facets(bc_i%marked_facet)
1238 type is (non_normal_aligned_t)
1239 ! The situation is the same as symmetry.
1240 call this%bcs_vel_projector%mark(bc_i%bc_x, component = 'x')
1241 call this%bcs_vel_projector%mark(bc_i%bc_y, component = 'y')
1242 call this%bcs_vel_projector%mark(bc_i%bc_z, component = 'z')
1243 call this%bcs_vel%append(bc_i)
1244 type is (non_normal_t)
1245 call this%bcs_vel_projector%mark(bc_i)
1246 call this%bcs_vel%append(bc_i)
1247 type is (shear_stress_t)
1248 if (.not. this%full_stress_formulation) then
1249 call neko_error("The shear_stress boundary condition " // &
1250 "requires the full stress formulation to be enabled.")
1251 end if
1252 call this%bcs_vel_projector%mark(bc_i)
1253 call this%bcs_vel%append(bc_i)
1254 type is (wall_model_bc_t)
1255 if (.not. this%full_stress_formulation) then
1256 call neko_error("The wall_model boundary condition " // &
1257 "requires the full stress formulation to be enabled.")
1258 end if
1259 call this%bcs_vel_projector%mark(bc_i)
1260 call this%bcs_vel%append(bc_i)
1261 class is (mixed_bc_t)
1262 ! User-defined mixed conditions, resolved by the coupled
1263 ! projector.
1264 if (.not. this%full_stress_formulation) then
1265 call neko_error("The " // trim(bc_i%name) // &
1266 " boundary condition is a mixed condition and " // &
1267 "requires the full stress formulation to be enabled.")
1268 end if
1269 call this%bcs_vel_projector%mark(bc_i)
1270 call this%bcs_vel%append(bc_i)
1271 class default
1272
1273 ! Additionally we mark the special PnPn pressure bc.
1274 if (bc_i%bc_type .eq. bc_dirichlet) then
1275 call this%bc_prs_surface%mark_labeled_zones( &
1276 bc_i%zone_indices)
1277 if (this%full_stress_formulation) then
1278 call this%bcs_vel_projector%mark(bc_i)
1279 else
1280 call this%bcs_vel_projector%mark(bc_i, component = 'x')
1281 call this%bcs_vel_projector%mark(bc_i, component = 'y')
1282 call this%bcs_vel_projector%mark(bc_i, component = 'z')
1283 end if
1284 end if
1285
1286 call this%bcs_vel%append(bc_i)
1287 end select
1288 end if
1289
1290 !
1291 ! Pressure
1292 !
1293 bc_i => null()
1294 pressure_dirichlet = .false.
1295 if (has_pressure) then
1296 call pressure_bc_factory(bc_i, this, pressure_subdict, &
1297 this%c_Xh, user)
1298 end if
1299
1300 ! The natural pressure condition does not create an object, so we
1301 ! check.
1302 if (associated(bc_i)) then
1303 call this%bcs_prs%append(bc_i)
1304
1305 ! Mark strong pressure bcs in the projector to force zero change.
1306 if (bc_i%bc_type .eq. bc_dirichlet) then
1307 call this%bcs_prs_projector%mark(bc_i)
1308 pressure_dirichlet = .true.
1309 end if
1310 end if
1311
1312 ! Mark the facets of the zones for the FDM preconditioner: 1 where
1313 ! the pressure is strongly imposed, 2 otherwise.
1314 if (pressure_dirichlet) then
1315 facet_value = 1
1316 else
1317 facet_value = 2
1318 end if
1319
1320 do j = 1, size(zone_indices)
1321 do k = 1, this%msh%nelv
1322 do l = 1, 2 * this%msh%gdim
1323 if (this%msh%facet_type(l, k) .eq. -zone_indices(j)) then
1324 this%msh%facet_type(l, k) = facet_value
1325 end if
1326 end do
1327 end do
1328 end do
1329 end do
1330
1331 call velocity_subdict%destroy()
1332 call pressure_subdict%destroy()
1333
1334 if (this%ale%active .and. (.not. this%ale%has_moving_boundary)) then
1335 call neko_error("Case file error: ALE is active, " // &
1336 "but no moving wall was found. " // &
1337 "Use type = 'no_slip' with 'moving': true in case file.")
1338 end if
1339
1340 ! Make sure all labeled zones with non-zero size have been marked
1341 do i = 1, size(this%msh%labeled_zones)
1342 if ((this%msh%labeled_zones(i)%size .gt. 0) .and. &
1343 (.not. marked_zones(i))) then
1344 write(error_msg, '(A, I0)') &
1345 "No fluid boundary condition assigned to zone ", i
1346 call neko_error(error_msg)
1347 end if
1348 end do
1349 else
1350 ! Check that there are no labeled zones, i.e. all are periodic.
1351 do i = 1, size(this%msh%labeled_zones)
1352 if (this%msh%labeled_zones(i)%size .gt. 0) then
1353 call neko_error("No boundary_conditions entry in the case file!")
1354 end if
1355 end do
1356
1357 ! For a pure periodic case, we still need to initilise the bc lists
1358 ! to a zero size to avoid issues with apply() in step()
1359 call this%bcs_vel%init()
1360 call this%bcs_prs%init()
1361
1362 end if
1363
1364 call this%bc_prs_surface%finalize()
1365 call this%bc_sym_surface%finalize()
1366 call this%bcs_vel_projector%finalize(rebuild_mask = .true.)
1367
1368 ! If we have no strong pressure bcs, we will demean the pressure
1369 this%prs_dirichlet = this%bcs_prs_projector%dof_mask%is_set()
1370 call mpi_allreduce(mpi_in_place, this%prs_dirichlet, 1, &
1371 mpi_logical, mpi_lor, neko_comm)
1372
1373 if (allocated(marked_zones)) then
1374 deallocate(marked_zones)
1375 end if
1376
1377 if (allocated(zone_indices)) then
1378 deallocate(zone_indices)
1379 end if
1380
1381 nullify(bc_i, bc_object)
1382
1383 end subroutine fluid_pnpn_setup_bcs
1384
1386 subroutine fluid_pnpn_write_boundary_conditions(this)
1387 use inflow, only : inflow_t
1389 use blasius, only : blasius_t
1391 use dong_outflow, only : dong_outflow_t
1392 use no_slip, only : no_slip_t
1393 class(fluid_pnpn_t), target, intent(inout) :: this
1394 type(dirichlet_t) :: bdry_mask
1395 type(field_t), pointer :: bdry_field
1396 type(file_t) :: bdry_file
1397 integer :: temp_index, i
1398 class(bc_t), pointer :: bci
1399 character(len=LOG_SIZE) :: log_buf
1400
1401 write(log_buf, '(A)') 'Marking using integer keys in bdry0.f00000'
1402 call neko_log%message(log_buf)
1403 write(log_buf, '(A)') 'Condition-value pairs: '
1404 call neko_log%message(log_buf)
1405 write(log_buf, '(A)') ' no_slip (stationary wall) = 1'
1406 call neko_log%message(log_buf)
1407 write(log_buf, '(A)') ' velocity_value = 2'
1408 call neko_log%message(log_buf)
1409 write(log_buf, '(A)') ' outflow, normal_outflow (+dong) = 3'
1410 call neko_log%message(log_buf)
1411 write(log_buf, '(A)') ' symmetry = 4'
1412 call neko_log%message(log_buf)
1413 write(log_buf, '(A)') ' periodic = 6'
1414 call neko_log%message(log_buf)
1415 write(log_buf, '(A)') ' user_velocity = 7'
1416 call neko_log%message(log_buf)
1417 write(log_buf, '(A)') ' user_pressure = 8'
1418 call neko_log%message(log_buf)
1419 write(log_buf, '(A)') ' shear_stress = 9'
1420 call neko_log%message(log_buf)
1421 write(log_buf, '(A)') ' wall_modelling = 10'
1422 call neko_log%message(log_buf)
1423 write(log_buf, '(A)') ' blasius_profile = 11'
1424 call neko_log%message(log_buf)
1425 write(log_buf, '(A)') ' no_slip (moving wall) = 12'
1426 call neko_log%message(log_buf)
1427
1428 call neko_scratch_registry%request_field(bdry_field, temp_index, .true.)
1429
1430
1431
1432 call bdry_mask%init_from_components(this%c_Xh, 6.0_rp)
1433 call bdry_mask%mark_zone(this%msh%periodic)
1434 call bdry_mask%finalize()
1435 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1436 call bdry_mask%free()
1437
1438 do i = 1, this%bcs_prs%size()
1439 bci => this%bcs_prs%get(i)
1440 select type (bc => bci)
1441 type is (zero_dirichlet_t)
1442 call bdry_mask%init_from_components(this%c_Xh, 3.0_rp)
1443 call bdry_mask%mark_facets(bci%marked_facet)
1444 call bdry_mask%finalize()
1445 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1446 call bdry_mask%free()
1447 type is (dong_outflow_t)
1448 call bdry_mask%init_from_components(this%c_Xh, 3.0_rp)
1449 call bdry_mask%mark_facets(bci%marked_facet)
1450 call bdry_mask%finalize()
1451 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1452 call bdry_mask%free()
1453 type is (field_dirichlet_t)
1454 call bdry_mask%init_from_components(this%c_Xh, 8.0_rp)
1455 call bdry_mask%mark_facets(bci%marked_facet)
1456 call bdry_mask%finalize()
1457 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1458 call bdry_mask%free()
1459 end select
1460 end do
1461
1462 do i = 1, this%bcs_vel%size()
1463 bci => this%bcs_vel%get(i)
1464 select type (bc => bci)
1465 type is (no_slip_t)
1466 if (bc%is_moving) then
1467 ! moving wall
1468 call bdry_mask%init_from_components(this%c_Xh, 12.0_rp)
1469 else
1470 ! stationary wall
1471 call bdry_mask%init_from_components(this%c_Xh, 1.0_rp)
1472 end if
1473 call bdry_mask%mark_facets(bci%marked_facet)
1474 call bdry_mask%finalize()
1475 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1476 call bdry_mask%free()
1477 type is (inflow_t)
1478 call bdry_mask%init_from_components(this%c_Xh, 2.0_rp)
1479 call bdry_mask%mark_facets(bci%marked_facet)
1480 call bdry_mask%finalize()
1481 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1482 call bdry_mask%free()
1483 type is (symmetry_aligned_t)
1484 call bdry_mask%init_from_components(this%c_Xh, 4.0_rp)
1485 call bdry_mask%mark_facets(bci%marked_facet)
1486 call bdry_mask%finalize()
1487 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1488 call bdry_mask%free()
1489 type is (symmetry_t)
1490 call bdry_mask%init_from_components(this%c_Xh, 4.0_rp)
1491 call bdry_mask%mark_facets(bci%marked_facet)
1492 call bdry_mask%finalize()
1493 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1494 call bdry_mask%free()
1495 type is (field_dirichlet_vector_t)
1496 call bdry_mask%init_from_components(this%c_Xh, 7.0_rp)
1497 call bdry_mask%mark_facets(bci%marked_facet)
1498 call bdry_mask%finalize()
1499 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1500 call bdry_mask%free()
1501 type is (shear_stress_t)
1502 call bdry_mask%init_from_components(this%c_Xh, 9.0_rp)
1503 call bdry_mask%mark_facets(bci%marked_facet)
1504 call bdry_mask%finalize()
1505 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1506 call bdry_mask%free()
1507 type is (wall_model_bc_t)
1508 call bdry_mask%init_from_components(this%c_Xh, 10.0_rp)
1509 call bdry_mask%mark_facets(bci%marked_facet)
1510 call bdry_mask%finalize()
1511 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1512 call bdry_mask%free()
1513 type is (blasius_t)
1514 call bdry_mask%init_from_components(this%c_Xh, 11.0_rp)
1515 call bdry_mask%mark_facets(bci%marked_facet)
1516 call bdry_mask%finalize()
1517 call bdry_mask%apply_scalar(bdry_field%x, this%dm_Xh%size())
1518 call bdry_mask%free()
1519 end select
1520 end do
1521
1522
1523 call bdry_file%init('bdry.fld')
1524 call bdry_file%write(bdry_field)
1525
1526 call neko_scratch_registry%relinquish_field(temp_index)
1527
1528 nullify(bdry_field, bci)
1529
1530 end subroutine fluid_pnpn_write_boundary_conditions
1531
1532end 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:1705
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:60
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...