Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
fluid_scheme_compressible.f90
Go to the documentation of this file.
1! Copyright (c) 2025-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!
34 use field, only : field_t
35 use field_math, only : field_col2, field_col3, &
38
39 use registry, only : neko_registry
40 use bc, only : bc_t
42 use json_module, only : json_file
43 use num_types, only : rp, dp
44 use mesh, only : mesh_t
46 use space, only : gll
51 use mpi_f08
52 use operators, only : cfl_compressible
54 use compressible_ops_cpu, only : &
56 use compressible_ops_device, only : &
59 use time_state, only : time_state_t
60 use logger, only : neko_log, log_size
61 use math, only : glsum, glamax
62 use device_math, only : device_glamax
63 use compressible_residual, only : compressible_rhs_set_physical_flux
64 use num_types, only : i8
65 implicit none
66 private
67
69 type, public, abstract, extends(fluid_scheme_base_t) :: &
72 type(field_t), pointer :: m_x => null()
73 type(field_t), pointer :: m_y => null()
74 type(field_t), pointer :: m_z => null()
75 type(field_t), pointer :: e => null()
76 type(field_t), pointer :: temperature => null()
77 type(field_t), pointer :: max_wave_speed => null()
78 type(field_t), pointer :: artificial_visc => null()
79 type(field_t), pointer :: kappa => null()
80
81 real(kind=rp) :: gamma
82
84 real(kind=rp) :: mu_amax = 0.0_rp
86 real(kind=rp) :: kappa_amax = 0.0_rp
87
89 logical :: add_physical_flux = .false.
91 logical :: add_physical_stress = .false.
94 logical :: variable_material_properties = .false.
95
97 integer(kind=i8) :: glb_n_points
99 integer(kind=i8) :: glb_unique_points
100
101 contains
103 procedure, pass(this) :: scheme_init => fluid_scheme_compressible_init
105 procedure, pass(this) :: scheme_free => fluid_scheme_compressible_free
106
108 procedure, pass(this) :: validate => fluid_scheme_compressible_validate
110 procedure, pass(this) :: compute_cfl &
113 procedure, pass(this) :: set_material_properties => &
116 procedure, pass(this) :: update_material_properties => &
119 procedure, pass(this) :: update_physical_flux => &
122 procedure, pass(this) :: compute_max_wave_speed => &
125 procedure, pass(this) :: log_solver_info => &
127
129
130contains
138 subroutine fluid_scheme_compressible_init(this, msh, lx, params, scheme, user)
139 class(fluid_scheme_compressible_t), target, intent(inout) :: this
140 type(mesh_t), target, intent(inout) :: msh
141 integer, intent(in) :: lx
142 character(len=*), intent(in) :: scheme
143 type(json_file), target, intent(inout) :: params
144 type(user_t), target, intent(in) :: user
145 logical :: compress_geo
146 real(kind=rp) :: compress_tol
147
148 !
149 ! SEM simulation fundamentals
150 !
151
152 this%msh => msh
153
154 if (msh%gdim .eq. 2) then
155 call this%Xh%init(gll, lx, lx)
156 else
157 call this%Xh%init(gll, lx, lx, lx)
158 end if
159
160 call this%dm_Xh%init(msh, this%Xh)
161
162 call this%gs_Xh%init(this%dm_Xh)
163
164 call this%c_Xh%init(this%gs_Xh)
165
166 ! Assign Dofmap to scratch registry
167 call neko_scratch_registry%set_dofmap(this%dm_Xh)
168
169 ! Case parameters
170 this%params => params
171
172 ! Assign a name
173 call json_get_or_default(params, 'case.fluid.name', this%name, "fluid")
174
175 ! Material properties will be set up via set_material_properties
176 call neko_registry%add_field(this%dm_Xh, this%name // "_rho")
177 this%rho => neko_registry%get_field(this%name // "_rho")
178
179 ! Assign momentum fields
180 call neko_registry%add_field(this%dm_Xh, "m_x")
181 call neko_registry%add_field(this%dm_Xh, "m_y")
182 call neko_registry%add_field(this%dm_Xh, "m_z")
183 this%m_x => neko_registry%get_field("m_x")
184 this%m_y => neko_registry%get_field("m_y")
185 this%m_z => neko_registry%get_field("m_z")
186 call this%m_x%init(this%dm_Xh, "m_x")
187 call this%m_y%init(this%dm_Xh, "m_y")
188 call this%m_z%init(this%dm_Xh, "m_z")
189
190 ! Assign energy field
191 call neko_registry%add_field(this%dm_Xh, "E")
192 this%E => neko_registry%get_field("E")
193 call this%E%init(this%dm_Xh, "E")
194
195 ! Assign temperature field
196 call neko_registry%add_field(this%dm_Xh, "temperature")
197 this%temperature => neko_registry%get_field("temperature")
198 call this%temperature%init(this%dm_Xh, "temperature")
199
200 ! Assign maximum wave speed field
201 call neko_registry%add_field(this%dm_Xh, "max_wave_speed")
202 this%max_wave_speed => neko_registry%get_field("max_wave_speed")
203 call this%max_wave_speed%init(this%dm_Xh, "max_wave_speed")
204
205 ! Assign artificial viscosity field (without physical viscosity)
206 call neko_registry%add_field(this%dm_Xh, "artificial_visc")
207 this%artificial_visc => neko_registry%get_field("artificial_visc")
208 call this%artificial_visc%init(this%dm_Xh, "artificial_visc")
209
210 ! ! Assign velocity fields
211 call neko_registry%add_field(this%dm_Xh, "u")
212 call neko_registry%add_field(this%dm_Xh, "v")
213 call neko_registry%add_field(this%dm_Xh, "w")
214 this%u => neko_registry%get_field("u")
215 this%v => neko_registry%get_field("v")
216 this%w => neko_registry%get_field("w")
217 call this%u%init(this%dm_Xh, "u")
218 call this%v%init(this%dm_Xh, "v")
219 call this%w%init(this%dm_Xh, "w")
220 call neko_registry%add_field(this%dm_Xh, 'p')
221 this%p => neko_registry%get_field('p')
222 call this%p%init(this%dm_Xh, "p")
223
224 !
225 ! Setup right-hand side fields.
226 !
227 allocate(this%f_x)
228 allocate(this%f_y)
229 allocate(this%f_z)
230 call this%f_x%init(this%dm_Xh, fld_name = "fluid_rhs_x")
231 call this%f_y%init(this%dm_Xh, fld_name = "fluid_rhs_y")
232 call this%f_z%init(this%dm_Xh, fld_name = "fluid_rhs_z")
233
234 ! Material properties
235 call this%set_material_properties(params, user)
236
237 ! Compressible parameters
238 call json_get_or_default(params, 'case.fluid.gamma', this%gamma, 1.4_rp)
239
240 ! Calculate global points for logging
241 this%glb_n_points = int(this%msh%glb_nelv, i8)*int(this%Xh%lxyz, i8)
242 this%glb_unique_points = int(glsum(this%c_Xh%mult, this%dm_Xh%size()), i8)
243
244 !
245 ! Log solver information
246 !
247 call this%log_solver_info(params, scheme, lx)
248
249 ! Compressed geometric factors, read by the standard Helmholtz operator
250 call json_get_or_default(params, &
251 'case.numerics.compress_geometric_factors', compress_geo, .false.)
252 if (compress_geo) then
253 if (params%valid_path( &
254 'case.numerics.compress_geometric_factors_tolerance')) then
255 call json_get_or_lookup(params, &
256 'case.numerics.compress_geometric_factors_tolerance', &
257 compress_tol)
258 call this%c_Xh%enable_geo_compression(compress_tol)
259 else
260 call this%c_Xh%enable_geo_compression()
261 end if
262 end if
263 end subroutine fluid_scheme_compressible_init
264
268 class(fluid_scheme_compressible_t), intent(inout) :: this
269 class(bc_t), pointer :: bc
270 integer :: i
271
272 do i = 1, this%bcs_vel%size()
273 bc => this%bcs_vel%get(i)
274 if (associated(bc)) then
275 call bc%free()
276 deallocate(bc)
277 end if
278 end do
279 call this%bcs_vel%free()
280
281 do i = 1, this%bcs_prs%size()
282 bc => this%bcs_prs%get(i)
283 if (associated(bc)) then
284 call bc%free()
285 deallocate(bc)
286 end if
287 end do
288 call this%bcs_prs%free()
289
290 call this%dm_Xh%free()
291 call this%gs_Xh%free()
292 call this%c_Xh%free()
293 call this%Xh%free()
294
295 if (associated(this%m_x)) then
296 call this%m_x%free()
297 end if
298
299 if (associated(this%m_y)) then
300 call this%m_y%free()
301 end if
302
303 if (associated(this%m_z)) then
304 call this%m_z%free()
305 end if
306
307 if (associated(this%E)) then
308 call this%E%free()
309 end if
310
311 if (associated(this%temperature)) then
312 call this%temperature%free()
313 end if
314
315 if (associated(this%max_wave_speed)) then
316 call this%max_wave_speed%free()
317 end if
318
319 if (associated(this%f_x)) then
320 call this%f_x%free()
321 deallocate(this%f_x)
322 end if
323
324 if (associated(this%f_y)) then
325 call this%f_y%free()
326 deallocate(this%f_y)
327 end if
328
329 if (associated(this%f_z)) then
330 call this%f_z%free()
331 deallocate(this%f_z)
332 end if
333
334 nullify(this%f_x)
335 nullify(this%f_y)
336 nullify(this%f_z)
337
338 nullify(this%m_x)
339 nullify(this%m_y)
340 nullify(this%m_z)
341 nullify(this%E)
342 nullify(this%temperature)
343 nullify(this%max_wave_speed)
344
345 nullify(this%u)
346 nullify(this%v)
347 nullify(this%w)
348 nullify(this%p)
349 nullify(this%rho)
350 nullify(this%mu)
351 nullify(this%kappa)
352
353 call this%material_properties%free()
354
355 end subroutine fluid_scheme_compressible_free
356
360 class(fluid_scheme_compressible_t), target, intent(inout) :: this
361 integer :: n, i
362 type(field_t), pointer :: temp
363 integer :: temp_indices(1)
364
365 n = this%dm_Xh%size()
366 call neko_scratch_registry%request_field(temp, temp_indices(1), .false.)
367
369 call field_col3(this%m_x, this%u, this%rho)
370 call field_col3(this%m_y, this%v, this%rho)
371 call field_col3(this%m_z, this%w, this%rho)
372
375 call field_cmult2(this%E, this%p, 1.0_rp/(this%gamma - 1.0_rp), n)
376 call field_col3(temp, this%u, this%u, n)
377 call field_addcol3(temp, this%v, this%v, n)
378 call field_addcol3(temp, this%w, this%w, n)
379 call field_col2(temp, this%rho, n)
380 call field_cmult(temp, 0.5_rp, n)
381 call field_add2(this%E, temp, n)
382
384 do i = 1, n
385 this%temperature%x(i,1,1,1) = this%p%x(i,1,1,1) / &
386 (this%rho%x(i,1,1,1) * (this%gamma - 1.0_rp))
387 end do
388
389 call neko_scratch_registry%relinquish_field(temp_indices)
390
392 call this%compute_max_wave_speed()
393
395
400 function fluid_scheme_compressible_compute_cfl(this, dt) result(c)
401 class(fluid_scheme_compressible_t), intent(in) :: this
402 real(kind=dp), intent(in) :: dt
403 real(kind=dp) :: c
404 integer :: n
405
406 associate(u => this%u, v => this%v, w => this%w, p => this%p, &
407 rho => this%rho, xh => this%Xh, c_xh => this%c_Xh, &
408 msh => this%msh, gamma => this%gamma, &
409 max_wave_speed => this%max_wave_speed)
410
411 n = xh%lx * xh%ly * xh%lz * msh%nelv
412
413 ! Use the compressible CFL function with precomputed maximum wave speed
414 c = cfl_compressible(dt, max_wave_speed%x, xh, c_xh, msh%nelv, msh%gdim)
415 end associate
416
418
424 params, user)
425 class(fluid_scheme_compressible_t), target, intent(inout) :: this
426 type(json_file), intent(inout) :: params
427 type(user_t), target, intent(in) :: user
428 procedure(user_material_properties_intf), pointer :: dummy_mp_ptr
429 type(time_state_t) :: dummy_time_state
430 real(kind=rp) :: const_mu, const_kappa
431
432 dummy_mp_ptr => dummy_user_material_properties
433
434 call neko_registry%add_field(this%dm_Xh, this%name // "_mu")
435 this%mu => neko_registry%get_field(this%name // "_mu")
436
437 call neko_registry%add_field(this%dm_Xh, this%name // "_kappa")
438 this%kappa => neko_registry%get_field(this%name // "_kappa")
439
440 call this%material_properties%init(3)
441 call this%material_properties%assign(1, this%rho)
442 call this%material_properties%assign(2, this%mu)
443 call this%material_properties%assign(3, this%kappa)
444
445 if (.not. associated(user%material_properties, dummy_mp_ptr)) then
446 this%user_material_properties => user%material_properties
447 this%variable_material_properties = .true.
448 call user%material_properties(this%name, this%material_properties, &
449 dummy_time_state)
450 else
451 this%variable_material_properties = .false.
452 this%user_material_properties => dummy_user_material_properties
453 call json_get_or_lookup_or_default(params, 'case.fluid.mu', const_mu, &
454 0.0_rp)
455 call json_get_or_lookup_or_default(params, 'case.fluid.kappa', &
456 const_kappa, 0.0_rp)
457
458 call field_cfill(this%mu, const_mu)
459 call field_cfill(this%kappa, const_kappa)
460 end if
461
462 ! Reported by log_solver_info, once the Fluid section is open.
463 call this%update_physical_flux()
464
466
472 class(fluid_scheme_compressible_t), intent(inout) :: this
473 type(time_state_t), intent(in) :: time
474
475 if (.not. this%variable_material_properties) return
476
477 call this%user_material_properties(this%name, this%material_properties, &
478 time)
479
480 call this%update_physical_flux()
481
483
500 class(fluid_scheme_compressible_t), intent(inout) :: this
501 real(kind=rp) :: mu_amax, kappa_amax
502 integer :: n
503
504 n = this%dm_Xh%size()
505
506 if (neko_bcknd_device .eq. 1) then
507 mu_amax = device_glamax(this%mu%x_d, n)
508 kappa_amax = device_glamax(this%kappa%x_d, n)
509 else
510 mu_amax = glamax(this%mu%x, n)
511 kappa_amax = glamax(this%kappa%x, n)
512 end if
513
514 this%mu_amax = mu_amax
515 this%kappa_amax = kappa_amax
516
517 this%add_physical_stress = (mu_amax .ne. 0.0_rp)
518 this%add_physical_flux = this%add_physical_stress .or. &
519 (kappa_amax .ne. 0.0_rp)
520
521 call compressible_rhs_set_physical_flux(this%add_physical_flux, &
522 this%add_physical_stress)
523
525
529 class(fluid_scheme_compressible_t), intent(inout) :: this
530 integer :: n
531
532 n = this%u%dof%size()
533
535 if (neko_bcknd_device .eq. 1) then
536 call compressible_ops_device_compute_max_wave_speed( &
537 this%max_wave_speed, this%u, this%v, this%w, this%gamma, this%p, &
538 this%rho, n)
539 else
540 call compressible_ops_cpu_compute_max_wave_speed(this%max_wave_speed%x, &
541 this%u%x, this%v%x, this%w%x, this%gamma, this%p%x, this%rho%x, n)
542 end if
543
545
551 subroutine fluid_scheme_compressible_log_solver_info(this, params, scheme, lx)
552 class(fluid_scheme_compressible_t), intent(inout) :: this
553 type(json_file), intent(inout) :: params
554 character(len=*), intent(in) :: scheme
555 integer, intent(in) :: lx
556 character(len=LOG_SIZE) :: log_buf
557 logical :: logical_val
558 integer :: integer_val
559
560 call neko_log%section('Fluid')
561 write(log_buf, '(A, A)') 'Type : ', trim(scheme)
562 call neko_log%message(log_buf)
563 write(log_buf, '(A, A)') 'Name : ', trim(this%name)
564 call neko_log%message(log_buf)
565
566 ! Polynomial order
567 if (lx .lt. 10) then
568 write(log_buf, '(A, I1)') 'Poly order : ', lx-1
569 else if (lx .ge. 10) then
570 write(log_buf, '(A, I2)') 'Poly order : ', lx-1
571 else
572 write(log_buf, '(A, I3)') 'Poly order : ', lx-1
573 end if
574 call neko_log%message(log_buf)
575
576 ! Global points information
577 write(log_buf, '(A, I0)') 'GLL points : ', this%glb_n_points
578 call neko_log%message(log_buf)
579 write(log_buf, '(A, I0)') 'Unique pts.: ', this%glb_unique_points
580 call neko_log%message(log_buf)
581
582 ! Material properties
583 write(log_buf, '(A,ES13.6)') 'gamma :', this%gamma
584 call neko_log%message(log_buf)
585
586 call json_get_or_default(params, 'case.numerics.time_order', integer_val, 4)
587 write(log_buf, '(A, I0)') 'RK order : ', integer_val
588 call neko_log%message(log_buf)
589
590 call json_get_or_default(params, &
591 'case.numerics.compress_geometric_factors', logical_val, .false.)
592 write(log_buf, '(A, L1)') 'Compress G : ', logical_val
593 call neko_log%message(log_buf)
594
595 ! Physical viscosity and conductivity. For user-defined properties the
596 ! fields need not be uniform, so report the largest magnitude found.
597 if (this%variable_material_properties) then
598 write(log_buf, '(A,ES13.6,A)') 'mu :', this%mu_amax, &
599 ' (user, max)'
600 call neko_log%message(log_buf)
601 write(log_buf, '(A,ES13.6,A)') 'kappa :', this%kappa_amax, &
602 ' (user, max)'
603 call neko_log%message(log_buf)
604 else
605 write(log_buf, '(A,ES13.6)') 'mu :', this%mu_amax
606 call neko_log%message(log_buf)
607 write(log_buf, '(A,ES13.6)') 'kappa :', this%kappa_amax
608 call neko_log%message(log_buf)
609 end if
610
611 if (this%add_physical_flux) then
612 write(log_buf, '(A, A)') 'NS fluxes : ', 'enabled'
613 else
614 write(log_buf, '(A, A)') 'NS fluxes : ', &
615 'disabled (mu = kappa = 0, Euler)'
616 end if
617 call neko_log%message(log_buf)
618
619 call neko_log%end_section()
620
622
Copy data between host and device (or device and device)
Definition device.F90:72
Abstract interface to sets rho and mu.
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Compute CFL condition for compressible flow.
Abstract interface for setting material properties.
Defines a boundary condition.
Definition bc.f90:34
CPU implementation of compressible flow operations.
subroutine, public compressible_ops_cpu_compute_max_wave_speed(max_wave_speed, u, v, w, gamma, p, rho, n)
Compute maximum wave speed for compressible flows on CPU.
Device implementation of compressible flow operations.
subroutine, public compressible_ops_device_compute_max_wave_speed(max_wave_speed, u, v, w, gamma, p, rho, n)
Compute maximum wave speed for compressible flows on device.
real(kind=rp) function, public device_glamax(a_d, n, strm)
Max of the absolute value of a vector of length n.
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
subroutine, public field_col2(a, b, n)
Vector multiplication .
subroutine, public field_cmult2(a, b, c, n)
Multiplication by constant c .
subroutine, public field_cfill(a, c, n)
Set all elements to a constant c .
subroutine, public field_addcol3(a, b, c, n)
Returns .
subroutine, public field_add2(a, b, n)
Vector addition .
subroutine, public field_col3(a, b, c, n)
Vector multiplication with 3 vectors .
subroutine, public field_cmult(a, c, n)
Multiplication by constant c .
Defines a field.
Definition field.f90:34
subroutine fluid_scheme_compressible_log_solver_info(this, params, scheme, lx)
Log comprehensive solver information.
subroutine fluid_scheme_compressible_free(this)
Free allocated memory and cleanup resources.
subroutine fluid_scheme_compressible_update_material_properties(this, time)
Update variable material properties.
subroutine fluid_scheme_compressible_set_material_properties(this, params, user)
Set material properties mu and rho.
real(kind=dp) function fluid_scheme_compressible_compute_cfl(this, dt)
Compute CFL number.
subroutine fluid_scheme_compressible_init(this, msh, lx, params, scheme, user)
Initialize common data for compressible fluid scheme.
subroutine fluid_scheme_compressible_update_physical_flux(this)
Refresh the physical-flux switches from the current material properties.
subroutine fluid_scheme_compressible_compute_max_wave_speed(this)
Compute maximum wave speed for compressible flows.
subroutine fluid_scheme_compressible_validate(this)
Validate field initialization and compute derived quantities.
Utilities for retrieving parameters from the case files.
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
Definition math.f90:60
real(kind=rp) function, public glamax(a, n)
Max of the absolute value of a vector of length n.
Definition math.f90:674
real(kind=rp) function, public glsum(a, n)
Sum a vector of length n.
Definition math.f90:633
Defines a mesh.
Definition mesh.f90:34
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public i8
Definition num_types.f90:7
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
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
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 function space.
Definition space.f90:34
integer, parameter, public gll
Definition space.f90:50
Module with things related to the simulation time.
Interfaces for user interaction with NEKO.
Definition user_intf.f90:34
subroutine, public dummy_user_material_properties(scheme_name, properties, time)
Base type for a boundary condition.
Definition bc.f90:73
Base type of all fluid formulations.
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...