Neko 1.99.2
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
fluid_scheme_compressible_euler.f90
Go to the documentation of this file.
1! Copyright (c) 2025, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
34 use comm, only : neko_comm
35 use advection, only : advection_t
40 use math, only : col2
41 use device_math, only : device_col2
42 use field, only : field_t
45 use gs_ops, only : gs_op_add
46 use num_types, only : rp
47 use mesh, only : mesh_t
48 use checkpoint, only : chkp_t
49 use json_module, only : json_file, json_core, json_value
52 use user_intf, only : user_t
54 use ax_product, only : ax_t, ax_helm_factory
55 use coefs, only: coef_t
56 use euler_residual, only: euler_rhs_t, euler_rhs_factory
59 use bc_list, only: bc_list_t
60 use bc, only : bc_t
62 use logger, only : log_size
63 use time_state, only : time_state_t
64 use mpi_f08, only : mpi_allreduce, mpi_integer, mpi_max
65 implicit none
66 private
67
68 type, public, extends(fluid_scheme_compressible_t) &
70 type(field_t) :: rho_res, m_x_res, m_y_res, m_z_res, m_e_res
71 type(field_t) :: drho, dm_x, dm_y, dm_z, de
72 type(field_t) :: h
73 real(kind=rp) :: c_avisc_low
74 class(advection_t), allocatable :: adv
75 class(ax_t), allocatable :: ax
76 class(euler_rhs_t), allocatable :: euler_rhs
77 type(runge_kutta_time_scheme_t) :: rk_scheme
78
79 ! List of boundary conditions for velocity
80 type(bc_list_t) :: bcs_density
81 contains
82 procedure, pass(this) :: init => fluid_scheme_compressible_euler_init
83 procedure, pass(this) :: free => fluid_scheme_compressible_euler_free
84 procedure, pass(this) :: step => fluid_scheme_compressible_euler_step
85 procedure, pass(this) :: restart => fluid_scheme_compressible_euler_restart
87 procedure, pass(this) :: setup_bcs &
89 procedure, pass(this) :: compute_h
91
92 interface
93
100 module subroutine density_bc_factory(object, scheme, json, coef, user)
101 class(bc_t), pointer, intent(inout) :: object
102 type(fluid_scheme_compressible_euler_t), intent(in) :: scheme
103 type(json_file), intent(inout) :: json
104 type(coef_t), intent(in) :: coef
105 type(user_t), intent(in) :: user
106 end subroutine density_bc_factory
107 end interface
108
109 interface
110
117 module subroutine pressure_bc_factory(object, scheme, json, coef, user)
118 class(bc_t), pointer, intent(inout) :: object
119 type(fluid_scheme_compressible_euler_t), intent(inout) :: scheme
120 type(json_file), intent(inout) :: json
121 type(coef_t), intent(in) :: coef
122 type(user_t), intent(in) :: user
123 end subroutine pressure_bc_factory
124 end interface
125
126 interface
127
134 module subroutine velocity_bc_factory(object, scheme, json, coef, user)
135 class(bc_t), pointer, intent(inout) :: object
136 type(fluid_scheme_compressible_euler_t), intent(in) :: scheme
137 type(json_file), intent(inout) :: json
138 type(coef_t), intent(in) :: coef
139 type(user_t), intent(in) :: user
140 end subroutine velocity_bc_factory
141 end interface
142
143contains
151 subroutine fluid_scheme_compressible_euler_init(this, msh, lx, params, user, &
152 chkp)
153 class(fluid_scheme_compressible_euler_t), target, intent(inout) :: this
154 type(mesh_t), target, intent(inout) :: msh
155 integer, intent(in) :: lx
156 type(json_file), target, intent(inout) :: params
157 type(user_t), target, intent(in) :: user
158 type(chkp_t), target, intent(inout) :: chkp
159 character(len=12), parameter :: scheme = 'compressible'
160 integer :: rk_order
161
162 call this%free()
163
164 ! Initialize base class
165 call this%scheme_init(msh, lx, params, scheme, user)
166
167 call euler_rhs_factory(this%euler_rhs)
168
169 associate(xh_lx => this%Xh%lx, xh_ly => this%Xh%ly, xh_lz => this%Xh%lz, &
170 dm_xh => this%dm_Xh, nelv => this%msh%nelv)
171
172 call this%drho%init(dm_xh, 'drho')
173 call this%dm_x%init(dm_xh, 'dm_x')
174 call this%dm_y%init(dm_xh, 'dm_y')
175 call this%dm_z%init(dm_xh, 'dm_z')
176 call this%dE%init(dm_xh, 'dE')
177 call this%h%init(dm_xh, 'h')
178
179 end associate
180
181 if (neko_bcknd_device .eq. 1) then
182 associate(p => this%p, rho => this%rho, &
183 u => this%u, v => this%v, w => this%w, &
184 m_x => this%m_x, m_y => this%m_y, m_z => this%m_z)
185 call device_memcpy(p%x, p%x_d, p%dof%size(), &
186 host_to_device, sync = .false.)
187 call device_memcpy(rho%x, rho%x_d, rho%dof%size(), &
188 host_to_device, sync = .false.)
189 call device_memcpy(u%x, u%x_d, u%dof%size(), &
190 host_to_device, sync = .false.)
191 call device_memcpy(v%x, v%x_d, v%dof%size(), &
192 host_to_device, sync = .false.)
193 call device_memcpy(w%x, w%x_d, w%dof%size(), &
194 host_to_device, sync = .false.)
195 call device_memcpy(m_x%x, m_x%x_d, m_x%dof%size(), &
196 host_to_device, sync = .false.)
197 call device_memcpy(m_y%x, m_y%x_d, m_y%dof%size(), &
198 host_to_device, sync = .false.)
199 call device_memcpy(m_z%x, m_z%x_d, m_z%dof%size(), &
200 host_to_device, sync = .false.)
201 end associate
202 end if
203
204 ! Initialize the diffusion operator
205 call ax_helm_factory(this%Ax, full_formulation = .false.)
206
207 ! Compute h
208 call this%compute_h()
209 call json_get_or_default(params, 'case.numerics.c_avisc_low', &
210 this%c_avisc_low, 0.5_rp)
211
212 ! Initialize Runge-Kutta scheme
213 call json_get_or_default(params, 'case.numerics.time_order', rk_order, 4)
214 call this%rk_scheme%init(rk_order)
215
216 ! Set up boundary conditions
217 call this%setup_bcs(user, params)
218
219 end subroutine fluid_scheme_compressible_euler_init
220
223 subroutine fluid_scheme_compressible_euler_free(this)
224 class(fluid_scheme_compressible_euler_t), intent(inout) :: this
225
226 call this%scheme_free()
227
228 if (allocated(this%Ax)) then
229 deallocate(this%Ax)
230 end if
231
232 call this%drho%free()
233 call this%dm_x%free()
234 call this%dm_y%free()
235 call this%dm_z%free()
236 call this%dE%free()
237
238 ! call this%scheme_free()
239 end subroutine fluid_scheme_compressible_euler_free
240
246 subroutine fluid_scheme_compressible_euler_step(this, time, dt_controller)
247 class(fluid_scheme_compressible_euler_t), target, intent(inout) :: this
248 type(time_state_t), intent(in) :: time
249 type(time_step_controller_t), intent(in) :: dt_controller
250 type(field_t), pointer :: temp
251 integer :: temp_indices(1)
252 ! number of degrees of freedom
253 integer :: n
254 integer :: i
255 class(bc_t), pointer :: b
256
257 n = this%dm_Xh%size()
258 call neko_scratch_registry%request_field(temp, temp_indices(1), .false.)
259 b => null()
260
261 call profiler_start_region('Fluid compressible', 1)
262 associate(u => this%u, v => this%v, w => this%w, p => this%p, &
263 m_x=> this%m_x, m_y => this%m_y, m_z => this%m_z, &
264 xh => this%Xh, msh => this%msh, ax => this%Ax, &
265 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
266 e => this%E, rho => this%rho, mu => this%mu, &
267 f_x => this%f_x, f_y => this%f_y, f_z => this%f_z, &
268 drho => this%drho, dm_x => this%dm_x, dm_y => this%dm_y, &
269 dm_z => this%dm_z, de => this%dE, &
270 euler_rhs => this%euler_rhs, h => this%h, &
271 t => time%t, tstep => time%tstep, dt => time%dt, &
272 ext_bdf => this%ext_bdf, &
273 c_avisc_low => this%c_avisc_low, rk_scheme => this%rk_scheme)
274
275 call euler_rhs%step(rho, m_x, m_y, m_z, e, &
276 p, u, v, w, ax, &
277 c_xh, gs_xh, h, c_avisc_low, &
278 rk_scheme, dt)
279
281 call this%bcs_density%apply(rho, time)
282
284 ! Update u, v, w
285 call field_copy(u, m_x, n)
286 call field_invcol2(u, rho, n)
287 call field_copy(v, m_y, n)
288 call field_invcol2(v, rho, n)
289 call field_copy(w, m_z, n)
290 call field_invcol2(w, rho, n)
291
293 call this%bcs_vel%apply_vector(u%x, v%x, w%x, &
294 dm_xh%size(), time, strong = .true.)
295 call field_copy(m_x, u, n)
296 call field_col2(m_x, rho, n)
297 call field_copy(m_y, v, n)
298 call field_col2(m_y, rho, n)
299 call field_copy(m_z, w, n)
300 call field_col2(m_z, rho, n)
301
303 call field_col3(temp, u, u, n)
304 call field_addcol3(temp, v, v, n)
305 call field_addcol3(temp, w, w, n)
306 call field_col2(temp, rho, n)
307 call field_cmult(temp, 0.5_rp, n)
308 call field_copy(p, e, n)
309 call field_sub2(p, temp, n)
310 call field_cmult(p, this%gamma - 1.0_rp, n)
311
313 call this%bcs_prs%apply(p, time)
314 ! TODO: Make sure pressure is positive
315 ! E = p / (gamma - 1) + 0.5 * rho * (u^2 + v^2 + w^2)
316 call field_copy(e, p, n)
317 call field_cmult(e, 1.0_rp / (this%gamma - 1.0_rp), n)
318 ! temp = 0.5 * rho * (u^2 + v^2 + w^2)
319 call field_add2(e, temp, n)
320
322 call this%compute_entropy()
323
325 call this%compute_max_wave_speed()
326
327 do i = 1, this%bcs_vel%size()
328 b => this%bcs_vel%get(i)
329 b%updated = .false.
330 end do
331
332 do i = 1, this%bcs_prs%size()
333 b => this%bcs_prs%get(i)
334 b%updated = .false.
335 end do
336
337 do i = 1, this%bcs_density%size()
338 b => this%bcs_density%get(i)
339 b%updated = .false.
340 end do
341 nullify(b)
342
343 end associate
344 call profiler_end_region('Fluid compressible', 1)
345
346 call neko_scratch_registry%relinquish_field(temp_indices)
347
348 end subroutine fluid_scheme_compressible_euler_step
349
354 subroutine fluid_scheme_compressible_euler_setup_bcs(this, user, params)
355 class(fluid_scheme_compressible_euler_t), target, intent(inout) :: this
356 type(user_t), target, intent(in) :: user
357 type(json_file), intent(inout) :: params
358 integer :: i, n_bcs, zone_index, j, zone_size, global_zone_size, ierr
359 class(bc_t), pointer :: bc_i
360 type(json_core) :: core
361 type(json_value), pointer :: bc_object
362 type(json_file) :: bc_subdict
363 logical :: found
364 integer, allocatable :: zone_indices(:)
365 character(len=LOG_SIZE) :: log_buf
366
367 ! Process boundary conditions
368 if (params%valid_path('case.fluid.boundary_conditions')) then
369 call params%info('case.fluid.boundary_conditions', n_children = n_bcs)
370 call params%get_core(core)
371 call params%get('case.fluid.boundary_conditions', bc_object, found)
372
373 !
374 ! Velocity bcs
375 !
376 call this%bcs_vel%init(n_bcs)
377
378 do i = 1, n_bcs
379 ! Extract BC configuration
380 call json_extract_item(core, bc_object, i, bc_subdict)
381 call json_get(bc_subdict, "zone_indices", zone_indices)
382
383 ! Validate zones
384 do j = 1, size(zone_indices)
385 zone_size = this%msh%labeled_zones(zone_indices(j))%size
386 call mpi_allreduce(zone_size, global_zone_size, 1, &
387 mpi_integer, mpi_max, neko_comm, ierr)
388
389 if (global_zone_size .eq. 0) then
390 write(log_buf,'(A,I0,A)') "Error: Zone ", zone_indices(j), &
391 " has zero size"
392 call neko_error(log_buf)
393 end if
394 end do
395
396 ! Create BC
397 bc_i => null()
398 call velocity_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
399
400 ! Add to appropriate lists
401 if (associated(bc_i)) then
402 call this%bcs_vel%append(bc_i)
403 end if
404 end do
405
406 !
407 ! Pressure bcs
408 !
409 call this%bcs_prs%init(n_bcs)
410
411 do i = 1, n_bcs
412 ! Create a new json containing just the subdict for this bc
413 call json_extract_item(core, bc_object, i, bc_subdict)
414 bc_i => null()
415 call pressure_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
416
417 ! Not all bcs require an allocation for pressure in particular,
418 ! so we check.
419 if (associated(bc_i)) then
420 call this%bcs_prs%append(bc_i)
421 end if
422 end do
423
424 !
425 ! Density bcs
426 !
427 call this%bcs_density%init(n_bcs)
428
429 do i = 1, n_bcs
430 ! Create a new json containing just the subdict for this bc
431 call json_extract_item(core, bc_object, i, bc_subdict)
432 bc_i => null()
433 call density_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
434
435 ! Not all bcs require an allocation for pressure in particular,
436 ! so we check.
437 if (associated(bc_i)) then
438 call this%bcs_density%append(bc_i)
439 end if
440 end do
441 else
442 ! Check that there are no labeled zones, i.e. all are periodic.
443 do i = 1, size(this%msh%labeled_zones)
444 if (this%msh%labeled_zones(i)%size .gt. 0) then
445 call neko_error("No boundary_conditions entry in the case file!")
446 end if
447 end do
448
449 ! For a pure periodic case, we still need to initilise the bc lists
450 ! to a zero size to avoid issues with apply() in step()
451 call this%bcs_prs%init()
452 call this%bcs_vel%init()
453 call this%bcs_density%init()
454
455 end if
456 end subroutine fluid_scheme_compressible_euler_setup_bcs
457
462 subroutine compute_h(this)
463 class(fluid_scheme_compressible_euler_t), intent(inout) :: this
464 integer :: e, i, j, k
465 integer :: im, ip, jm, jp, km, kp
466 real(kind=rp) :: di, dj, dk, ndim_inv
467 integer :: lx_half, ly_half, lz_half
468
469 lx_half = this%c_Xh%Xh%lx / 2
470 ly_half = this%c_Xh%Xh%ly / 2
471 lz_half = this%c_Xh%Xh%lz / 2
472
473 do e = 1, this%c_Xh%msh%nelv
474 do k = 1, this%c_Xh%Xh%lz
475 km = max(1, k-1)
476 kp = min(this%c_Xh%Xh%lz, k+1)
477
478 do j = 1, this%c_Xh%Xh%ly
479 jm = max(1, j-1)
480 jp = min(this%c_Xh%Xh%ly, j+1)
481
482 do i = 1, this%c_Xh%Xh%lx
483 im = max(1, i-1)
484 ip = min(this%c_Xh%Xh%lx, i+1)
485
486 di = (this%c_Xh%dof%x(ip, j, k, e) - &
487 this%c_Xh%dof%x(im, j, k, e))**2 &
488 + (this%c_Xh%dof%y(ip, j, k, e) - &
489 this%c_Xh%dof%y(im, j, k, e))**2 &
490 + (this%c_Xh%dof%z(ip, j, k, e) - &
491 this%c_Xh%dof%z(im, j, k, e))**2
492
493 dj = (this%c_Xh%dof%x(i, jp, k, e) - &
494 this%c_Xh%dof%x(i, jm, k, e))**2 &
495 + (this%c_Xh%dof%y(i, jp, k, e) - &
496 this%c_Xh%dof%y(i, jm, k, e))**2 &
497 + (this%c_Xh%dof%z(i, jp, k, e) - &
498 this%c_Xh%dof%z(i, jm, k, e))**2
499
500 dk = (this%c_Xh%dof%x(i, j, kp, e) - &
501 this%c_Xh%dof%x(i, j, km, e))**2 &
502 + (this%c_Xh%dof%y(i, j, kp, e) - &
503 this%c_Xh%dof%y(i, j, km, e))**2 &
504 + (this%c_Xh%dof%z(i, j, kp, e) - &
505 this%c_Xh%dof%z(i, j, km, e))**2
506
507 di = sqrt(di) / (ip - im)
508 dj = sqrt(dj) / (jp - jm)
509 dk = sqrt(dk) / (kp - km)
510 this%h%x(i,j,k,e) = (di * dj * dk)**(1.0_rp / 3.0_rp)
511
512 end do
513 end do
514 end do
515 end do
516
517 if (neko_bcknd_device .eq. 1) then
518 call device_memcpy(this%h%x, this%h%x_d, this%h%dof%size(),&
519 host_to_device, sync = .false.)
520 call this%gs_Xh%op(this%h, gs_op_add)
521 call device_col2(this%h%x_d, this%c_Xh%mult_d, this%h%dof%size())
522 else
523 call this%gs_Xh%op(this%h, gs_op_add)
524 call col2(this%h%x, this%c_Xh%mult, this%h%dof%size())
525 end if
526
527 end subroutine compute_h
528
533 subroutine fluid_scheme_compressible_euler_restart(this, chkp)
534 class(fluid_scheme_compressible_euler_t), target, intent(inout) :: this
535 type(chkp_t), intent(inout) :: chkp
536 end subroutine fluid_scheme_compressible_euler_restart
537
Copy data between host and device (or device and device)
Definition device.F90:71
Abstract interface to evaluate rhs.
Definition euler_res.f90:51
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.
Subroutines to add advection terms to the RHS of a transport equation.
Definition advection.f90:34
Defines a Matrix-vector product.
Definition ax.f90:34
Defines a list of bc_t.
Definition bc_list.f90:34
Defines a boundary condition.
Definition bc.f90:34
Defines a checkpoint.
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:43
subroutine, public device_col2(a_d, b_d, n, strm)
Vector multiplication .
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:47
subroutine, public field_invcol2(a, b, n)
Vector division .
subroutine, public field_col2(a, b, n)
Vector multiplication .
subroutine, public field_sub2(a, b, n)
Vector substraction .
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_copy(a, b, n)
Copy a vector .
subroutine, public field_cmult(a, c, n)
Multiplication by constant c .
Defines a field.
Definition field.f90:34
subroutine compute_h(this)
Copied from les_model_compute_delta in les_model.f90 TODO: move to a separate module Compute characte...
subroutine fluid_scheme_compressible_euler_init(this, msh, lx, params, user, chkp)
Boundary condition factory for density.
subroutine fluid_scheme_compressible_euler_step(this, time, dt_controller)
Advance the fluid simulation one timestep.
subroutine fluid_scheme_compressible_euler_free(this)
Free allocated memory and cleanup.
subroutine fluid_scheme_compressible_euler_restart(this, chkp)
Restart the simulation from saved state.
subroutine fluid_scheme_compressible_euler_setup_bcs(this, user, params)
Set up boundary conditions for the fluid scheme.
Defines Gather-scatter operations.
Definition gs_ops.f90:34
integer, parameter, public gs_op_add
Definition gs_ops.f90:36
Utilities for retrieving parameters from the case files.
Logging routines.
Definition log.f90:34
integer, parameter, public log_size
Definition log.f90:46
Definition math.f90:60
subroutine, public col2(a, b, n)
Vector multiplication .
Definition math.f90:854
Defines a mesh.
Definition mesh.f90:34
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Profiling interface.
Definition profiler.F90:34
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
Definition profiler.F90:78
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Definition profiler.F90:107
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.
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
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:313
Base abstract type for computing the advection operator.
Definition advection.f90:46
Base type for a matrix-vector product providing .
Definition ax.f90:43
Base type for a boundary condition.
Definition bc.f90:61
A list of allocatable `bc_t`. Follows the standard interface of lists.
Definition bc_list.f90:48
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:56
Abstract type to compute rhs.
Definition euler_res.f90:44
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...
#define max(a, b)
Definition tensor.cu:40