Neko 1.99.1
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
44 use gs_ops, only : gs_op_add
45 use num_types, only : rp
46 use mesh, only : mesh_t
47 use checkpoint, only : chkp_t
48 use json_module, only : json_file, json_core, json_value
51 use user_intf, only : user_t
53 use ax_product, only : ax_t, ax_helm_factory
54 use coefs, only: coef_t
55 use euler_residual, only: euler_rhs_t, euler_rhs_factory
58 use bc_list, only: bc_list_t
59 use bc, only : bc_t
61 use logger, only : log_size
62 use time_state, only : time_state_t
63 use mpi_f08, only : mpi_allreduce, mpi_integer, mpi_max
64 implicit none
65 private
66
67 type, public, extends(fluid_scheme_compressible_t) &
69 type(field_t) :: rho_res, m_x_res, m_y_res, m_z_res, m_e_res
70 type(field_t) :: drho, dm_x, dm_y, dm_z, de
71 type(field_t) :: h
72 real(kind=rp) :: c_avisc_low
73 class(advection_t), allocatable :: adv
74 class(ax_t), allocatable :: ax
75 class(euler_rhs_t), allocatable :: euler_rhs
76 type(runge_kutta_time_scheme_t) :: rk_scheme
77
78 ! List of boundary conditions for velocity
79 type(bc_list_t) :: bcs_density
80 contains
81 procedure, pass(this) :: init => fluid_scheme_compressible_euler_init
82 procedure, pass(this) :: free => fluid_scheme_compressible_euler_free
83 procedure, pass(this) :: step => fluid_scheme_compressible_euler_step
84 procedure, pass(this) :: restart => fluid_scheme_compressible_euler_restart
86 procedure, pass(this) :: setup_bcs &
88 procedure, pass(this) :: compute_h
90
91 interface
92
99 module subroutine density_bc_factory(object, scheme, json, coef, user)
100 class(bc_t), pointer, intent(inout) :: object
101 type(fluid_scheme_compressible_euler_t), intent(in) :: scheme
102 type(json_file), intent(inout) :: json
103 type(coef_t), intent(in) :: coef
104 type(user_t), intent(in) :: user
105 end subroutine density_bc_factory
106 end interface
107
108 interface
109
116 module subroutine pressure_bc_factory(object, scheme, json, coef, user)
117 class(bc_t), pointer, intent(inout) :: object
118 type(fluid_scheme_compressible_euler_t), intent(inout) :: scheme
119 type(json_file), intent(inout) :: json
120 type(coef_t), intent(in) :: coef
121 type(user_t), intent(in) :: user
122 end subroutine pressure_bc_factory
123 end interface
124
125 interface
126
133 module subroutine velocity_bc_factory(object, scheme, json, coef, user)
134 class(bc_t), pointer, intent(inout) :: object
135 type(fluid_scheme_compressible_euler_t), intent(in) :: scheme
136 type(json_file), intent(inout) :: json
137 type(coef_t), intent(in) :: coef
138 type(user_t), intent(in) :: user
139 end subroutine velocity_bc_factory
140 end interface
141
142contains
150 subroutine fluid_scheme_compressible_euler_init(this, msh, lx, params, user, &
151 chkp)
152 class(fluid_scheme_compressible_euler_t), target, intent(inout) :: this
153 type(mesh_t), target, intent(inout) :: msh
154 integer, intent(in) :: lx
155 type(json_file), target, intent(inout) :: params
156 type(user_t), target, intent(in) :: user
157 type(chkp_t), target, intent(inout) :: chkp
158 character(len=12), parameter :: scheme = 'compressible'
159 integer :: rk_order
160
161 call this%free()
162
163 ! Initialize base class
164 call this%scheme_init(msh, lx, params, scheme, user)
165
166 call euler_rhs_factory(this%euler_rhs)
167
168 associate(xh_lx => this%Xh%lx, xh_ly => this%Xh%ly, xh_lz => this%Xh%lz, &
169 dm_xh => this%dm_Xh, nelv => this%msh%nelv)
170
171 call this%drho%init(dm_xh, 'drho')
172 call this%dm_x%init(dm_xh, 'dm_x')
173 call this%dm_y%init(dm_xh, 'dm_y')
174 call this%dm_z%init(dm_xh, 'dm_z')
175 call this%dE%init(dm_xh, 'dE')
176 call this%h%init(dm_xh, 'h')
177
178 end associate
179
180 if (neko_bcknd_device .eq. 1) then
181 associate(p => this%p, rho => this%rho, &
182 u => this%u, v => this%v, w => this%w, &
183 m_x => this%m_x, m_y => this%m_y, m_z => this%m_z)
184 call device_memcpy(p%x, p%x_d, p%dof%size(), &
185 host_to_device, sync = .false.)
186 call device_memcpy(rho%x, rho%x_d, rho%dof%size(), &
187 host_to_device, sync = .false.)
188 call device_memcpy(u%x, u%x_d, u%dof%size(), &
189 host_to_device, sync = .false.)
190 call device_memcpy(v%x, v%x_d, v%dof%size(), &
191 host_to_device, sync = .false.)
192 call device_memcpy(w%x, w%x_d, w%dof%size(), &
193 host_to_device, sync = .false.)
194 call device_memcpy(m_x%x, m_x%x_d, m_x%dof%size(), &
195 host_to_device, sync = .false.)
196 call device_memcpy(m_y%x, m_y%x_d, m_y%dof%size(), &
197 host_to_device, sync = .false.)
198 call device_memcpy(m_z%x, m_z%x_d, m_z%dof%size(), &
199 host_to_device, sync = .false.)
200 end associate
201 end if
202
203 ! Initialize the diffusion operator
204 call ax_helm_factory(this%Ax, full_formulation = .false.)
205
206 ! Compute h
207 call this%compute_h()
208 call json_get_or_default(params, 'case.numerics.c_avisc_low', &
209 this%c_avisc_low, 0.5_rp)
210
211 ! Initialize Runge-Kutta scheme
212 call json_get_or_default(params, 'case.numerics.time_order', rk_order, 4)
213 call this%rk_scheme%init(rk_order)
214
215 ! Set up boundary conditions
216 call this%setup_bcs(user, params)
217
218 end subroutine fluid_scheme_compressible_euler_init
219
222 subroutine fluid_scheme_compressible_euler_free(this)
223 class(fluid_scheme_compressible_euler_t), intent(inout) :: this
224
225 call this%scheme_free()
226
227 if (allocated(this%Ax)) then
228 deallocate(this%Ax)
229 end if
230
231 call this%drho%free()
232 call this%dm_x%free()
233 call this%dm_y%free()
234 call this%dm_z%free()
235 call this%dE%free()
236
237 ! call this%scheme_free()
238 end subroutine fluid_scheme_compressible_euler_free
239
245 subroutine fluid_scheme_compressible_euler_step(this, time, dt_controller)
246 class(fluid_scheme_compressible_euler_t), target, intent(inout) :: this
247 type(time_state_t), intent(in) :: time
248 type(time_step_controller_t), intent(in) :: dt_controller
249 type(field_t), pointer :: temp
250 integer :: temp_indices(1)
251 ! number of degrees of freedom
252 integer :: n
253 integer :: i
254 class(bc_t), pointer :: b
255
256 n = this%dm_Xh%size()
257 call this%scratch%request_field(temp, temp_indices(1))
258 b => null()
259
260 call profiler_start_region('Fluid compressible', 1)
261 associate(u => this%u, v => this%v, w => this%w, p => this%p, &
262 m_x=> this%m_x, m_y => this%m_y, m_z => this%m_z, &
263 xh => this%Xh, msh => this%msh, ax => this%Ax, &
264 c_xh => this%c_Xh, dm_xh => this%dm_Xh, gs_xh => this%gs_Xh, &
265 e => this%E, rho => this%rho, mu => this%mu, &
266 f_x => this%f_x, f_y => this%f_y, f_z => this%f_z, &
267 drho => this%drho, dm_x => this%dm_x, dm_y => this%dm_y, &
268 dm_z => this%dm_z, de => this%dE, &
269 euler_rhs => this%euler_rhs, h => this%h, &
270 t => time%t, tstep => time%tstep, dt => time%dt, &
271 ext_bdf => this%ext_bdf, &
272 c_avisc_low => this%c_avisc_low, rk_scheme => this%rk_scheme)
273
274 call euler_rhs%step(rho, m_x, m_y, m_z, e, &
275 p, u, v, w, ax, &
276 c_xh, gs_xh, h, c_avisc_low, &
277 rk_scheme, dt)
278
280 call this%bcs_density%apply(rho, time)
281
283 ! Update u, v, w
284 call field_copy(u, m_x, n)
285 call field_invcol2(u, rho, n)
286 call field_copy(v, m_y, n)
287 call field_invcol2(v, rho, n)
288 call field_copy(w, m_z, n)
289 call field_invcol2(w, rho, n)
290
292 call this%bcs_vel%apply_vector(u%x, v%x, w%x, &
293 dm_xh%size(), time, strong = .true.)
294 call field_copy(m_x, u, n)
295 call field_col2(m_x, rho, n)
296 call field_copy(m_y, v, n)
297 call field_col2(m_y, rho, n)
298 call field_copy(m_z, w, n)
299 call field_col2(m_z, rho, n)
300
302 call field_col3(temp, u, u, n)
303 call field_addcol3(temp, v, v, n)
304 call field_addcol3(temp, w, w, n)
305 call field_col2(temp, rho, n)
306 call field_cmult(temp, 0.5_rp, n)
307 call field_copy(p, e, n)
308 call field_sub2(p, temp, n)
309 call field_cmult(p, this%gamma - 1.0_rp, n)
310
312 call this%bcs_prs%apply(p, time)
313 ! TODO: Make sure pressure is positive
314 ! E = p / (gamma - 1) + 0.5 * rho * (u^2 + v^2 + w^2)
315 call field_copy(e, p, n)
316 call field_cmult(e, 1.0_rp / (this%gamma - 1.0_rp), n)
317 ! temp = 0.5 * rho * (u^2 + v^2 + w^2)
318 call field_add2(e, temp, n)
319
321 call this%compute_entropy()
322
324 call this%compute_max_wave_speed()
325
326 do i = 1, this%bcs_vel%size()
327 b => this%bcs_vel%get(i)
328 b%updated = .false.
329 end do
330
331 do i = 1, this%bcs_prs%size()
332 b => this%bcs_prs%get(i)
333 b%updated = .false.
334 end do
335
336 do i = 1, this%bcs_density%size()
337 b => this%bcs_density%get(i)
338 b%updated = .false.
339 end do
340 nullify(b)
341
342 end associate
343 call profiler_end_region('Fluid compressible', 1)
344
345 call this%scratch%relinquish_field(temp_indices)
346
347 end subroutine fluid_scheme_compressible_euler_step
348
353 subroutine fluid_scheme_compressible_euler_setup_bcs(this, user, params)
354 class(fluid_scheme_compressible_euler_t), target, intent(inout) :: this
355 type(user_t), target, intent(in) :: user
356 type(json_file), intent(inout) :: params
357 integer :: i, n_bcs, zone_index, j, zone_size, global_zone_size, ierr
358 class(bc_t), pointer :: bc_i
359 type(json_core) :: core
360 type(json_value), pointer :: bc_object
361 type(json_file) :: bc_subdict
362 logical :: found
363 integer, allocatable :: zone_indices(:)
364 character(len=LOG_SIZE) :: log_buf
365
366 ! Process boundary conditions
367 if (params%valid_path('case.fluid.boundary_conditions')) then
368 call params%info('case.fluid.boundary_conditions', n_children = n_bcs)
369 call params%get_core(core)
370 call params%get('case.fluid.boundary_conditions', bc_object, found)
371
372 !
373 ! Velocity bcs
374 !
375 call this%bcs_vel%init(n_bcs)
376
377 do i = 1, n_bcs
378 ! Extract BC configuration
379 call json_extract_item(core, bc_object, i, bc_subdict)
380 call json_get(bc_subdict, "zone_indices", zone_indices)
381
382 ! Validate zones
383 do j = 1, size(zone_indices)
384 zone_size = this%msh%labeled_zones(zone_indices(j))%size
385 call mpi_allreduce(zone_size, global_zone_size, 1, &
386 mpi_integer, mpi_max, neko_comm, ierr)
387
388 if (global_zone_size .eq. 0) then
389 write(log_buf,'(A,I0,A)') "Error: Zone ", zone_indices(j), &
390 " has zero size"
391 call neko_error(log_buf)
392 end if
393 end do
394
395 ! Create BC
396 bc_i => null()
397 call velocity_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
398
399 ! Add to appropriate lists
400 if (associated(bc_i)) then
401 call this%bcs_vel%append(bc_i)
402 end if
403 end do
404
405 !
406 ! Pressure bcs
407 !
408 call this%bcs_prs%init(n_bcs)
409
410 do i = 1, n_bcs
411 ! Create a new json containing just the subdict for this bc
412 call json_extract_item(core, bc_object, i, bc_subdict)
413 bc_i => null()
414 call pressure_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
415
416 ! Not all bcs require an allocation for pressure in particular,
417 ! so we check.
418 if (associated(bc_i)) then
419 call this%bcs_prs%append(bc_i)
420 end if
421 end do
422
423 !
424 ! Density bcs
425 !
426 call this%bcs_density%init(n_bcs)
427
428 do i = 1, n_bcs
429 ! Create a new json containing just the subdict for this bc
430 call json_extract_item(core, bc_object, i, bc_subdict)
431 bc_i => null()
432 call density_bc_factory(bc_i, this, bc_subdict, this%c_Xh, user)
433
434 ! Not all bcs require an allocation for pressure in particular,
435 ! so we check.
436 if (associated(bc_i)) then
437 call this%bcs_density%append(bc_i)
438 end if
439 end do
440 else
441 ! Check that there are no labeled zones, i.e. all are periodic.
442 do i = 1, size(this%msh%labeled_zones)
443 if (this%msh%labeled_zones(i)%size .gt. 0) then
444 call neko_error("No boundary_conditions entry in the case file!")
445 end if
446 end do
447
448 ! For a pure periodic case, we still need to initilise the bc lists
449 ! to a zero size to avoid issues with apply() in step()
450 call this%bcs_prs%init()
451 call this%bcs_vel%init()
452 call this%bcs_density%init()
453
454 end if
455 end subroutine fluid_scheme_compressible_euler_setup_bcs
456
461 subroutine compute_h(this)
462 class(fluid_scheme_compressible_euler_t), intent(inout) :: this
463 integer :: e, i, j, k
464 integer :: im, ip, jm, jp, km, kp
465 real(kind=rp) :: di, dj, dk, ndim_inv
466 integer :: lx_half, ly_half, lz_half
467
468 lx_half = this%c_Xh%Xh%lx / 2
469 ly_half = this%c_Xh%Xh%ly / 2
470 lz_half = this%c_Xh%Xh%lz / 2
471
472 do e = 1, this%c_Xh%msh%nelv
473 do k = 1, this%c_Xh%Xh%lz
474 km = max(1, k-1)
475 kp = min(this%c_Xh%Xh%lz, k+1)
476
477 do j = 1, this%c_Xh%Xh%ly
478 jm = max(1, j-1)
479 jp = min(this%c_Xh%Xh%ly, j+1)
480
481 do i = 1, this%c_Xh%Xh%lx
482 im = max(1, i-1)
483 ip = min(this%c_Xh%Xh%lx, i+1)
484
485 di = (this%c_Xh%dof%x(ip, j, k, e) - &
486 this%c_Xh%dof%x(im, j, k, e))**2 &
487 + (this%c_Xh%dof%y(ip, j, k, e) - &
488 this%c_Xh%dof%y(im, j, k, e))**2 &
489 + (this%c_Xh%dof%z(ip, j, k, e) - &
490 this%c_Xh%dof%z(im, j, k, e))**2
491
492 dj = (this%c_Xh%dof%x(i, jp, k, e) - &
493 this%c_Xh%dof%x(i, jm, k, e))**2 &
494 + (this%c_Xh%dof%y(i, jp, k, e) - &
495 this%c_Xh%dof%y(i, jm, k, e))**2 &
496 + (this%c_Xh%dof%z(i, jp, k, e) - &
497 this%c_Xh%dof%z(i, jm, k, e))**2
498
499 dk = (this%c_Xh%dof%x(i, j, kp, e) - &
500 this%c_Xh%dof%x(i, j, km, e))**2 &
501 + (this%c_Xh%dof%y(i, j, kp, e) - &
502 this%c_Xh%dof%y(i, j, km, e))**2 &
503 + (this%c_Xh%dof%z(i, j, kp, e) - &
504 this%c_Xh%dof%z(i, j, km, e))**2
505
506 di = sqrt(di) / (ip - im)
507 dj = sqrt(dj) / (jp - jm)
508 dk = sqrt(dk) / (kp - km)
509 this%h%x(i,j,k,e) = (di * dj * dk)**(1.0_rp / 3.0_rp)
510
511 end do
512 end do
513 end do
514 end do
515
516 if (neko_bcknd_device .eq. 1) then
517 call device_memcpy(this%h%x, this%h%x_d, this%h%dof%size(),&
518 host_to_device, sync = .false.)
519 call this%gs_Xh%op(this%h, gs_op_add)
520 call device_col2(this%h%x_d, this%c_Xh%mult_d, this%h%dof%size())
521 else
522 call this%gs_Xh%op(this%h, gs_op_add)
523 call col2(this%h%x, this%c_Xh%mult, this%h%dof%size())
524 end if
525
526 end subroutine compute_h
527
532 subroutine fluid_scheme_compressible_euler_restart(this, chkp)
533 class(fluid_scheme_compressible_euler_t), target, intent(inout) :: this
534 type(chkp_t), intent(inout) :: chkp
535 end subroutine fluid_scheme_compressible_euler_restart
536
Copy data between host and device (or device and device)
Definition device.F90:66
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:42
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:860
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:109
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:251
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:55
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