Neko 1.99.3
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
euler_res_cpu.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!? It handles the time advancement of primitive variables using Runge-Kutta methods
35!? and evaluates the right-hand side terms of the Euler equations including artificial viscosity.
37 use euler_residual, only : euler_rhs_t
38 use field, only : field_t
39 use ax_product, only : ax_t
40 use coefs, only : coef_t
41 use gather_scatter, only : gs_t
42 use num_types, only : rp
43 use operators, only : div, rotate_cyc
44 use gs_ops, only : gs_op_add
47 use field_list, only : field_list_t
48 implicit none
49 private
50
51 type, public, extends(euler_rhs_t) :: euler_res_cpu_t
52 contains
53 procedure, nopass :: step => advance_primitive_variables_cpu
54 procedure, nopass :: evaluate_rhs_cpu
55 end type euler_res_cpu_t
56
57contains
72 subroutine advance_primitive_variables_cpu(rho_field, m_x, m_y, m_z, &
73 E, p, u, v, w, Ax, &
74 coef, gs, h, effective_visc, rk_scheme, dt)
75 type(field_t), intent(inout) :: rho_field, m_x, m_y, m_z, E
76 type(field_t), intent(in) :: p, u, v, w, h, effective_visc
77 class(ax_t), intent(inout) :: Ax
78 type(coef_t), intent(inout) :: coef
79 type(gs_t), intent(inout) :: gs
80 class(runge_kutta_time_scheme_t), intent(in) :: rk_scheme
81 real(kind=rp), intent(in) :: dt
82 integer :: n, s, i, j, k
83 type(field_t), pointer :: k_rho_1, k_rho_2, k_rho_3, k_rho_4, &
84 k_m_x_1, k_m_x_2, k_m_x_3, k_m_x_4, &
85 k_m_y_1, k_m_y_2, k_m_y_3, k_m_y_4, &
86 k_m_z_1, k_m_z_2, k_m_z_3, k_m_z_4, &
87 k_E_1, k_E_2, k_E_3, k_E_4, &
88 temp_rho, temp_m_x, temp_m_y, temp_m_z, temp_E
89 integer :: tmp_indices(25)
90 type(field_list_t) :: k_rho, k_m_x, k_m_y, k_m_z, k_E
91 ! These contiguous pointers are necessary to ensure that
92 ! the Fujitsu compiler properly vectorizes the loop nests
93 real(kind=rp), contiguous, pointer :: k_rho_ptr(:,:,:,:)
94 real(kind=rp), contiguous, pointer :: k_m_x_ptr(:,:,:,:)
95 real(kind=rp), contiguous, pointer :: k_m_y_ptr(:,:,:,:)
96 real(kind=rp), contiguous, pointer :: k_m_z_ptr(:,:,:,:)
97 real(kind=rp), contiguous, pointer :: k_e_ptr(:,:,:,:)
98
99 n = p%dof%size()
100 s = rk_scheme%order
101 call neko_scratch_registry%request_field(k_rho_1, tmp_indices(1), .true.)
102 call neko_scratch_registry%request_field(k_rho_2, tmp_indices(2), .true.)
103 call neko_scratch_registry%request_field(k_rho_3, tmp_indices(3), .true.)
104 call neko_scratch_registry%request_field(k_rho_4, tmp_indices(4), .true.)
105 call neko_scratch_registry%request_field(k_m_x_1, tmp_indices(5), .true.)
106 call neko_scratch_registry%request_field(k_m_x_2, tmp_indices(6), .true.)
107 call neko_scratch_registry%request_field(k_m_x_3, tmp_indices(7), .true.)
108 call neko_scratch_registry%request_field(k_m_x_4, tmp_indices(8), .true.)
109 call neko_scratch_registry%request_field(k_m_y_1, tmp_indices(9), .true.)
110 call neko_scratch_registry%request_field(k_m_y_2, tmp_indices(10), .true.)
111 call neko_scratch_registry%request_field(k_m_y_3, tmp_indices(11), .true.)
112 call neko_scratch_registry%request_field(k_m_y_4, tmp_indices(12), .true.)
113 call neko_scratch_registry%request_field(k_m_z_1, tmp_indices(13), .true.)
114 call neko_scratch_registry%request_field(k_m_z_2, tmp_indices(14), .true.)
115 call neko_scratch_registry%request_field(k_m_z_3, tmp_indices(15), .true.)
116 call neko_scratch_registry%request_field(k_m_z_4, tmp_indices(16), .true.)
117 call neko_scratch_registry%request_field(k_e_1, tmp_indices(17), .true.)
118 call neko_scratch_registry%request_field(k_e_2, tmp_indices(18), .true.)
119 call neko_scratch_registry%request_field(k_e_3, tmp_indices(19), .true.)
120 call neko_scratch_registry%request_field(k_e_4, tmp_indices(20), .true.)
121 call neko_scratch_registry%request_field(temp_rho, tmp_indices(21), .false.)
122 call neko_scratch_registry%request_field(temp_m_x, tmp_indices(22), .false.)
123 call neko_scratch_registry%request_field(temp_m_y, tmp_indices(23), .false.)
124 call neko_scratch_registry%request_field(temp_m_z, tmp_indices(24), .false.)
125 call neko_scratch_registry%request_field(temp_e, tmp_indices(25), .false.)
126
127 ! Initialize Runge-Kutta stage variables for each conserved quantity
128 call k_rho%init(4)
129 call k_rho%assign(1, k_rho_1)
130 call k_rho%assign(2, k_rho_2)
131 call k_rho%assign(3, k_rho_3)
132 call k_rho%assign(4, k_rho_4)
133 call k_m_x%init(4)
134 call k_m_x%assign(1, k_m_x_1)
135 call k_m_x%assign(2, k_m_x_2)
136 call k_m_x%assign(3, k_m_x_3)
137 call k_m_x%assign(4, k_m_x_4)
138 call k_m_y%init(4)
139 call k_m_y%assign(1, k_m_y_1)
140 call k_m_y%assign(2, k_m_y_2)
141 call k_m_y%assign(3, k_m_y_3)
142 call k_m_y%assign(4, k_m_y_4)
143 call k_m_z%init(4)
144 call k_m_z%assign(1, k_m_z_1)
145 call k_m_z%assign(2, k_m_z_2)
146 call k_m_z%assign(3, k_m_z_3)
147 call k_m_z%assign(4, k_m_z_4)
148 call k_e%init(4)
149 call k_e%assign(1, k_e_1)
150 call k_e%assign(2, k_e_2)
151 call k_e%assign(3, k_e_3)
152 call k_e%assign(4, k_e_4)
153
154 ! Loop over Runge-Kutta stages
155 do i = 1, s
156 ! Copy current solution state to temporary arrays for this RK stage
157 do concurrent(k = 1:n)
158 temp_rho%x(k,1,1,1) = rho_field%x(k,1,1,1)
159 temp_m_x%x(k,1,1,1) = m_x%x(k,1,1,1)
160 temp_m_y%x(k,1,1,1) = m_y%x(k,1,1,1)
161 temp_m_z%x(k,1,1,1) = m_z%x(k,1,1,1)
162 temp_e%x(k,1,1,1) = e%x(k,1,1,1)
163 end do
164
165 ! Accumulate previous stage contributions using RK coefficients
166 do j = 1, i-1
167 k_rho_ptr => k_rho%items(j)%ptr%x
168 k_m_x_ptr => k_m_x%items(j)%ptr%x
169 k_m_y_ptr => k_m_y%items(j)%ptr%x
170 k_m_z_ptr => k_m_z%items(j)%ptr%x
171 k_e_ptr => k_e%items(j)%ptr%x
172 do concurrent(k = 1:n)
173 temp_rho%x(k,1,1,1) = temp_rho%x(k,1,1,1) &
174 + dt * rk_scheme%coeffs_A(i, j) * k_rho_ptr(k,1,1,1)
175 temp_m_x%x(k,1,1,1) = temp_m_x%x(k,1,1,1) &
176 + dt * rk_scheme%coeffs_A(i, j) * k_m_x_ptr(k,1,1,1)
177 temp_m_y%x(k,1,1,1) = temp_m_y%x(k,1,1,1) &
178 + dt * rk_scheme%coeffs_A(i, j) * k_m_y_ptr(k,1,1,1)
179 temp_m_z%x(k,1,1,1) = temp_m_z%x(k,1,1,1) &
180 + dt * rk_scheme%coeffs_A(i, j) * k_m_z_ptr(k,1,1,1)
181 temp_e%x(k,1,1,1) = temp_e%x(k,1,1,1) &
182 + dt * rk_scheme%coeffs_A(i, j) * k_e_ptr(k,1,1,1)
183 end do
184 end do
185
186 ! Evaluate RHS terms for current stage using intermediate solution values
187 call evaluate_rhs_cpu(k_rho%items(i)%ptr, k_m_x%items(i)%ptr, &
188 k_m_y%items(i)%ptr, k_m_z%items(i)%ptr, &
189 k_e%items(i)%ptr, &
190 temp_rho, temp_m_x, temp_m_y, temp_m_z, temp_e, &
191 p, u, v, w, ax, &
192 coef, gs, h, effective_visc)
193 end do
194
195 ! Update the solution
196 do i = 1, s
197 k_rho_ptr => k_rho%items(i)%ptr%x
198 k_m_x_ptr => k_m_x%items(i)%ptr%x
199 k_m_y_ptr => k_m_y%items(i)%ptr%x
200 k_m_z_ptr => k_m_z%items(i)%ptr%x
201 k_e_ptr => k_e%items(i)%ptr%x
202 do concurrent(k = 1:n)
203 rho_field%x(k,1,1,1) = rho_field%x(k,1,1,1) &
204 + dt * rk_scheme%coeffs_b(i) * k_rho_ptr(k,1,1,1)
205 m_x%x(k,1,1,1) = m_x%x(k,1,1,1) &
206 + dt * rk_scheme%coeffs_b(i) * k_m_x_ptr(k,1,1,1)
207 m_y%x(k,1,1,1) = m_y%x(k,1,1,1) &
208 + dt * rk_scheme%coeffs_b(i) * k_m_y_ptr(k,1,1,1)
209 m_z%x(k,1,1,1) = m_z%x(k,1,1,1) &
210 + dt * rk_scheme%coeffs_b(i) * k_m_z_ptr(k,1,1,1)
211 e%x(k,1,1,1) = e%x(k,1,1,1) &
212 + dt * rk_scheme%coeffs_b(i) * k_e_ptr(k,1,1,1)
213 end do
214 end do
215
216 call neko_scratch_registry%relinquish_field(tmp_indices)
217
219
241 subroutine evaluate_rhs_cpu(rhs_rho_field, rhs_m_x, rhs_m_y, rhs_m_z, rhs_E, &
242 rho_field, m_x, m_y, m_z, E, p, u, v, w, Ax, &
243 coef, gs, h, effective_visc)
244 type(field_t), intent(inout) :: rhs_rho_field, &
245 rhs_m_x, rhs_m_y, rhs_m_z, rhs_e
246 type(field_t), intent(inout) :: rho_field, m_x, m_y, m_z, E
247 type(field_t), intent(in) :: p, u, v, w, h, effective_visc
248 class(ax_t), intent(inout) :: Ax
249 type(coef_t), intent(inout) :: coef
250 type(gs_t), intent(inout) :: gs
251 integer :: i, n
252 type(field_t), pointer :: f_x, f_y, f_z, &
253 visc_rho, visc_m_x, visc_m_y, visc_m_z, visc_E
254 integer :: tmp_indices(8)
255
256 n = coef%dof%size()
257 call neko_scratch_registry%request_field(f_x, tmp_indices(1), .false.)
258 call neko_scratch_registry%request_field(f_y, tmp_indices(2), .false.)
259 call neko_scratch_registry%request_field(f_z, tmp_indices(3), .false.)
260
262 ! Compute density flux divergence
263 call div(rhs_rho_field%x, m_x%x, m_y%x, m_z%x, coef)
264
266 ! Compute momentum flux divergences
267 ! m_x
268 do concurrent(i = 1:n)
269 f_x%x(i,1,1,1) = m_x%x(i,1,1,1) * m_x%x(i,1,1,1) / &
270 rho_field%x(i, 1, 1, 1) + p%x(i,1,1,1)
271 f_y%x(i,1,1,1) = m_x%x(i,1,1,1) * m_y%x(i,1,1,1) / &
272 rho_field%x(i, 1, 1, 1)
273 f_z%x(i,1,1,1) = m_x%x(i,1,1,1) * m_z%x(i,1,1,1) / &
274 rho_field%x(i, 1, 1, 1)
275 end do
276 call div(rhs_m_x%x, f_x%x, f_y%x, f_z%x, coef)
277 ! m_y
278 do concurrent(i = 1:n)
279 f_x%x(i,1,1,1) = m_y%x(i,1,1,1) * m_x%x(i,1,1,1) / &
280 rho_field%x(i, 1, 1, 1)
281 f_y%x(i,1,1,1) = m_y%x(i,1,1,1) * m_y%x(i,1,1,1) / &
282 rho_field%x(i, 1, 1, 1) + p%x(i,1,1,1)
283 f_z%x(i,1,1,1) = m_y%x(i,1,1,1) * m_z%x(i,1,1,1) / &
284 rho_field%x(i, 1, 1, 1)
285 end do
286 call div(rhs_m_y%x, f_x%x, f_y%x, f_z%x, coef)
287 ! m_z
288 do concurrent(i = 1:n)
289 f_x%x(i,1,1,1) = m_z%x(i,1,1,1) * m_x%x(i,1,1,1) / &
290 rho_field%x(i, 1, 1, 1)
291 f_y%x(i,1,1,1) = m_z%x(i,1,1,1) * m_y%x(i,1,1,1) / &
292 rho_field%x(i, 1, 1, 1)
293 f_z%x(i,1,1,1) = m_z%x(i,1,1,1) * m_z%x(i,1,1,1) / &
294 rho_field%x(i, 1, 1, 1) + p%x(i,1,1,1)
295 end do
296 call div(rhs_m_z%x, f_x%x, f_y%x, f_z%x, coef)
297
299 ! Compute energy flux divergence
300 do concurrent(i = 1:n)
301 f_x%x(i,1,1,1) = (e%x(i,1,1,1) + p%x(i,1,1,1)) * u%x(i,1,1,1)
302 f_y%x(i,1,1,1) = (e%x(i,1,1,1) + p%x(i,1,1,1)) * v%x(i,1,1,1)
303 f_z%x(i,1,1,1) = (e%x(i,1,1,1) + p%x(i,1,1,1)) * w%x(i,1,1,1)
304 end do
305 call div(rhs_e%x, f_x%x, f_y%x, f_z%x, coef)
306
307 ! gs
308 call gs%op(rhs_rho_field, gs_op_add)
309 call rotate_cyc(rhs_m_x%x, rhs_m_y%x, rhs_m_z%x, 1, coef)
310 call gs%op(rhs_m_x, gs_op_add)
311 call gs%op(rhs_m_y, gs_op_add)
312 call gs%op(rhs_m_z, gs_op_add)
313 call rotate_cyc(rhs_m_x%x, rhs_m_y%x, rhs_m_z%x, 0, coef)
314 call gs%op(rhs_e, gs_op_add)
315 do concurrent(i = 1:rhs_e%dof%size())
316 rhs_rho_field%x(i,1,1,1) = rhs_rho_field%x(i,1,1,1) * coef%mult(i,1,1,1)
317 rhs_m_x%x(i,1,1,1) = rhs_m_x%x(i,1,1,1) * coef%mult(i,1,1,1)
318 rhs_m_y%x(i,1,1,1) = rhs_m_y%x(i,1,1,1) * coef%mult(i,1,1,1)
319 rhs_m_z%x(i,1,1,1) = rhs_m_z%x(i,1,1,1) * coef%mult(i,1,1,1)
320 rhs_e%x(i,1,1,1) = rhs_e%x(i,1,1,1) * coef%mult(i,1,1,1)
321 end do
322
323 call neko_scratch_registry%request_field(visc_rho, tmp_indices(4), .false.)
324 call neko_scratch_registry%request_field(visc_m_x, tmp_indices(5), .false.)
325 call neko_scratch_registry%request_field(visc_m_y, tmp_indices(6), .false.)
326 call neko_scratch_registry%request_field(visc_m_z, tmp_indices(7), .false.)
327 call neko_scratch_registry%request_field(visc_e, tmp_indices(8), .false.)
328
329 ! Set h1 coefficient to the effective viscosity for the Laplacian operator
330 do concurrent(i = 1:n)
331 coef%h1(i,1,1,1) = effective_visc%x(i,1,1,1)
332 end do
333
334 ! Calculate artificial diffusion with variable viscosity
335 call ax%compute(visc_rho%x, rho_field%x, coef, p%msh, p%Xh)
336 call ax%compute(visc_m_x%x, m_x%x, coef, p%msh, p%Xh)
337 call ax%compute(visc_m_y%x, m_y%x, coef, p%msh, p%Xh)
338 call ax%compute(visc_m_z%x, m_z%x, coef, p%msh, p%Xh)
339 call ax%compute(visc_e%x, e%x, coef, p%msh, p%Xh)
340
341 ! Reset h1 coefficient back to 1.0 for other operations
342 do concurrent(i = 1:n)
343 coef%h1(i,1,1,1) = 1.0_rp
344 end do
345
346 ! gs
347 call gs%op(visc_rho, gs_op_add)
348 call rotate_cyc(visc_m_x%x, visc_m_y%x, visc_m_z%x, 1, coef)
349 call gs%op(visc_m_x, gs_op_add)
350 call gs%op(visc_m_y, gs_op_add)
351 call gs%op(visc_m_z, gs_op_add)
352 call rotate_cyc(visc_m_x%x, visc_m_y%x, visc_m_z%x, 0, coef)
353 call gs%op(visc_e, gs_op_add)
354
355 ! Move div to the rhs and apply artificial viscosity
356 ! The viscosity coefficient is already included in the Laplacian operator
357 do concurrent(i = 1:n)
358 rhs_rho_field%x(i,1,1,1) = -rhs_rho_field%x(i,1,1,1) &
359 - coef%Binv(i,1,1,1) * visc_rho%x(i,1,1,1)
360 rhs_m_x%x(i,1,1,1) = -rhs_m_x%x(i,1,1,1) &
361 - coef%Binv(i,1,1,1) * visc_m_x%x(i,1,1,1)
362 rhs_m_y%x(i,1,1,1) = -rhs_m_y%x(i,1,1,1) &
363 - coef%Binv(i,1,1,1) * visc_m_y%x(i,1,1,1)
364 rhs_m_z%x(i,1,1,1) = -rhs_m_z%x(i,1,1,1) &
365 - coef%Binv(i,1,1,1) * visc_m_z%x(i,1,1,1)
366 rhs_e%x(i,1,1,1) = -rhs_e%x(i,1,1,1) &
367 - coef%Binv(i,1,1,1) * visc_e%x(i,1,1,1)
368 end do
369
370 call neko_scratch_registry%relinquish_field(tmp_indices)
371 end subroutine evaluate_rhs_cpu
372
373end module euler_res_cpu
Defines a Matrix-vector product.
Definition ax.f90:34
Coefficients.
Definition coef.f90:34
This module implements CPU-based residual calculations for the Euler equations.
subroutine evaluate_rhs_cpu(rhs_rho_field, rhs_m_x, rhs_m_y, rhs_m_z, rhs_e, rho_field, m_x, m_y, m_z, e, p, u, v, w, ax, coef, gs, h, effective_visc)
Evaluates the right-hand side of the Euler equations Computes fluxes, divergence terms,...
subroutine advance_primitive_variables_cpu(rho_field, m_x, m_y, m_z, e, p, u, v, w, ax, coef, gs, h, effective_visc, rk_scheme, dt)
Advances the primitive variables (density, momentum, energy) in time using a Runge-Kutta scheme.
Defines a field.
Definition field.f90:34
Gather-scatter.
Defines Gather-scatter operations.
Definition gs_ops.f90:34
integer, parameter, public gs_op_add
Definition gs_ops.f90:36
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Operators.
Definition operators.f90:34
subroutine, public div(res, ux, uy, uz, coef)
Compute the divergence of a vector field.
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.
Base type for a matrix-vector product providing .
Definition ax.f90:43
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:58
Abstract type to compute rhs.
Definition euler_res.f90:44
field_list_t, To be able to group fields together