Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
compressible_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!
39 use field, only : field_t
40 use ax_product, only : ax_t
41 use coefs, only : coef_t
42 use gather_scatter, only : gs_t
43 use num_types, only : rp
44 use operators, only : div, grad, opgrad, rotate_cyc
45 use gs_ops, only : gs_op_add
48 use field_list, only : field_list_t
51 use bc_list, only : bc_list_t
52 use time_state, only : time_state_t
53 implicit none
54 private
55
57 contains
58 procedure, nopass :: step => advance_primitive_variables_cpu
59 procedure, nopass :: evaluate_rhs => evaluate_rhs_cpu
61
64 logical, public :: compressible_res_cpu_add_physical_flux = .false.
67 logical, public :: compressible_res_cpu_add_physical_stress = .false.
69 real(kind=rp), public :: compressible_res_cpu_gamma = 1.4_rp
70
71
72contains
90 subroutine advance_primitive_variables_cpu(rho_field, m_x, m_y, m_z, &
91 E, p, u, v, w, Ax, &
92 Ax_stress, coef, gs, artificial_visc, mu, kappa, bcs_vel, time, &
93 rk_scheme, dt)
94 type(field_t), intent(inout) :: rho_field, m_x, m_y, m_z, e
95 type(field_t), intent(in) :: p, u, v, w, artificial_visc, mu, kappa
96 class(ax_t), intent(inout) :: Ax, Ax_stress
97 type(coef_t), intent(inout) :: coef
98 type(gs_t), intent(inout) :: gs
99 type(bc_list_t), intent(inout) :: bcs_vel
100 type(time_state_t), intent(in) :: time
101 class(runge_kutta_time_scheme_t), intent(in) :: rk_scheme
102 real(kind=rp), intent(in) :: dt
103 integer :: n, s, i, j, l
104 type(field_t), pointer :: k_rho_1, k_rho_2, k_rho_3, k_rho_4, &
105 k_m_x_1, k_m_x_2, k_m_x_3, k_m_x_4, &
106 k_m_y_1, k_m_y_2, k_m_y_3, k_m_y_4, &
107 k_m_z_1, k_m_z_2, k_m_z_3, k_m_z_4, &
108 k_E_1, k_E_2, k_E_3, k_E_4, &
109 temp_rho, temp_m_x, temp_m_y, temp_m_z, temp_E, &
110 temp_p, temp_u, temp_v, temp_w, temp_ruvw
111 integer :: tmp_indices(30)
112 type(field_list_t) :: k_rho, k_m_x, k_m_y, k_m_z, k_E
113 ! These contiguous pointers are necessary to ensure that
114 ! the Fujitsu compiler properly vectorizes the loop nests
115 real(kind=rp), contiguous, pointer :: k_rho_ptr(:,:,:,:)
116 real(kind=rp), contiguous, pointer :: k_m_x_ptr(:,:,:,:)
117 real(kind=rp), contiguous, pointer :: k_m_y_ptr(:,:,:,:)
118 real(kind=rp), contiguous, pointer :: k_m_z_ptr(:,:,:,:)
119 real(kind=rp), contiguous, pointer :: k_e_ptr(:,:,:,:)
120
121 n = p%dof%size()
122 s = rk_scheme%order
123 call neko_scratch_registry%request_field(k_rho_1, tmp_indices(1), .true.)
124 call neko_scratch_registry%request_field(k_rho_2, tmp_indices(2), .true.)
125 call neko_scratch_registry%request_field(k_rho_3, tmp_indices(3), .true.)
126 call neko_scratch_registry%request_field(k_rho_4, tmp_indices(4), .true.)
127 call neko_scratch_registry%request_field(k_m_x_1, tmp_indices(5), .true.)
128 call neko_scratch_registry%request_field(k_m_x_2, tmp_indices(6), .true.)
129 call neko_scratch_registry%request_field(k_m_x_3, tmp_indices(7), .true.)
130 call neko_scratch_registry%request_field(k_m_x_4, tmp_indices(8), .true.)
131 call neko_scratch_registry%request_field(k_m_y_1, tmp_indices(9), .true.)
132 call neko_scratch_registry%request_field(k_m_y_2, tmp_indices(10), .true.)
133 call neko_scratch_registry%request_field(k_m_y_3, tmp_indices(11), .true.)
134 call neko_scratch_registry%request_field(k_m_y_4, tmp_indices(12), .true.)
135 call neko_scratch_registry%request_field(k_m_z_1, tmp_indices(13), .true.)
136 call neko_scratch_registry%request_field(k_m_z_2, tmp_indices(14), .true.)
137 call neko_scratch_registry%request_field(k_m_z_3, tmp_indices(15), .true.)
138 call neko_scratch_registry%request_field(k_m_z_4, tmp_indices(16), .true.)
139 call neko_scratch_registry%request_field(k_e_1, tmp_indices(17), .true.)
140 call neko_scratch_registry%request_field(k_e_2, tmp_indices(18), .true.)
141 call neko_scratch_registry%request_field(k_e_3, tmp_indices(19), .true.)
142 call neko_scratch_registry%request_field(k_e_4, tmp_indices(20), .true.)
143 call neko_scratch_registry%request_field(temp_rho, tmp_indices(21), .false.)
144 call neko_scratch_registry%request_field(temp_m_x, tmp_indices(22), .false.)
145 call neko_scratch_registry%request_field(temp_m_y, tmp_indices(23), .false.)
146 call neko_scratch_registry%request_field(temp_m_z, tmp_indices(24), .false.)
147 call neko_scratch_registry%request_field(temp_e, tmp_indices(25), .false.)
148 call neko_scratch_registry%request_field(temp_p, tmp_indices(26), .false.)
149 call neko_scratch_registry%request_field(temp_u, tmp_indices(27), .false.)
150 call neko_scratch_registry%request_field(temp_v, tmp_indices(28), .false.)
151 call neko_scratch_registry%request_field(temp_w, tmp_indices(29), .false.)
152 call neko_scratch_registry%request_field(temp_ruvw, tmp_indices(30), &
153 .false.)
154
155 ! Initialize Runge-Kutta stage variables for each conserved quantity
156 call k_rho%init(4)
157 call k_rho%assign(1, k_rho_1)
158 call k_rho%assign(2, k_rho_2)
159 call k_rho%assign(3, k_rho_3)
160 call k_rho%assign(4, k_rho_4)
161 call k_m_x%init(4)
162 call k_m_x%assign(1, k_m_x_1)
163 call k_m_x%assign(2, k_m_x_2)
164 call k_m_x%assign(3, k_m_x_3)
165 call k_m_x%assign(4, k_m_x_4)
166 call k_m_y%init(4)
167 call k_m_y%assign(1, k_m_y_1)
168 call k_m_y%assign(2, k_m_y_2)
169 call k_m_y%assign(3, k_m_y_3)
170 call k_m_y%assign(4, k_m_y_4)
171 call k_m_z%init(4)
172 call k_m_z%assign(1, k_m_z_1)
173 call k_m_z%assign(2, k_m_z_2)
174 call k_m_z%assign(3, k_m_z_3)
175 call k_m_z%assign(4, k_m_z_4)
176 call k_e%init(4)
177 call k_e%assign(1, k_e_1)
178 call k_e%assign(2, k_e_2)
179 call k_e%assign(3, k_e_3)
180 call k_e%assign(4, k_e_4)
181
182 ! Loop over Runge-Kutta stages. One parallel region per stage covers
183 ! both the initial copy and all (i-1) accumulation sweeps.
184 do i = 1, s
185 !$omp parallel private(j, l, k_rho_ptr) &
186 !$omp& private(k_m_x_ptr, k_m_y_ptr, k_m_z_ptr, k_E_ptr)
187
188 ! Copy current solution state to temporary arrays for this RK stage
189 !OCL NORECURRENCE, NOVREC, NOALIAS
190 !DIR$ CONCURRENT
191 !DIR$ IVDEP
192 !GCC$ ivdep
193 !$omp do simd
194 do l = 1, n
195 temp_rho%x(l,1,1,1) = rho_field%x(l,1,1,1)
196 temp_m_x%x(l,1,1,1) = m_x%x(l,1,1,1)
197 temp_m_y%x(l,1,1,1) = m_y%x(l,1,1,1)
198 temp_m_z%x(l,1,1,1) = m_z%x(l,1,1,1)
199 temp_e%x(l,1,1,1) = e%x(l,1,1,1)
200 end do
201 !$omp end do simd
202
203 ! Accumulate previous stage contributions using RK coefficients.
204 ! Each thread independently sets its private k_*_ptr aliases before
205 ! the worksharing loop; the implicit barrier at end of !$omp do simd
206 ! synchronises threads between j iterations.
207 do j = 1, i-1
208 k_rho_ptr => k_rho%items(j)%ptr%x
209 k_m_x_ptr => k_m_x%items(j)%ptr%x
210 k_m_y_ptr => k_m_y%items(j)%ptr%x
211 k_m_z_ptr => k_m_z%items(j)%ptr%x
212 k_e_ptr => k_e%items(j)%ptr%x
213
214 !OCL NORECURRENCE, NOVREC, NOALIAS
215 !DIR$ CONCURRENT
216 !DIR$ IVDEP
217 !GCC$ ivdep
218 !$omp do simd
219 do l = 1, n
220 temp_rho%x(l,1,1,1) = temp_rho%x(l,1,1,1) + &
221 dt * rk_scheme%coeffs_A(i, j) * k_rho_ptr(l,1,1,1)
222 temp_m_x%x(l,1,1,1) = temp_m_x%x(l,1,1,1) + &
223 dt * rk_scheme%coeffs_A(i, j) * k_m_x_ptr(l,1,1,1)
224 temp_m_y%x(l,1,1,1) = temp_m_y%x(l,1,1,1) + &
225 dt * rk_scheme%coeffs_A(i, j) * k_m_y_ptr(l,1,1,1)
226 temp_m_z%x(l,1,1,1) = temp_m_z%x(l,1,1,1) + &
227 dt * rk_scheme%coeffs_A(i, j) * k_m_z_ptr(l,1,1,1)
228 temp_e%x(l,1,1,1) = temp_e%x(l,1,1,1) + &
229 dt * rk_scheme%coeffs_A(i, j) * k_e_ptr(l,1,1,1)
230 end do
231 !$omp end do simd
232 end do
233 !$omp end parallel
234
235 ! Evaluate RHS terms using primitive variables from the RK stage state.
236 call compressible_ops_cpu_update_uvw(temp_u%x, temp_v%x, temp_w%x, &
237 temp_m_x%x, temp_m_y%x, temp_m_z%x, temp_rho%x, n)
239 call bcs_vel%apply_vector(temp_u%x, temp_v%x, temp_w%x, n, time, &
240 strong = .true.)
241 end if
242 call compressible_ops_cpu_update_mxyz_p_ruvw(temp_m_x%x, temp_m_y%x, &
243 temp_m_z%x, temp_p%x, temp_ruvw%x, temp_u%x, temp_v%x, temp_w%x, &
244 temp_e%x, temp_rho%x, compressible_res_cpu_gamma, n)
245
246 call evaluate_rhs_cpu(k_rho%items(i)%ptr, k_m_x%items(i)%ptr, &
247 k_m_y%items(i)%ptr, k_m_z%items(i)%ptr, &
248 k_e%items(i)%ptr, &
249 temp_rho, temp_m_x, temp_m_y, temp_m_z, temp_e, &
250 temp_p, temp_u, temp_v, temp_w, ax, &
251 ax_stress, coef, gs, artificial_visc, mu, kappa)
252 end do
253
254 ! Update the solution. Single parallel region covers all s stages.
255 !$omp parallel default(shared) private(i, l, k_rho_ptr) &
256 !$omp& private(k_m_x_ptr, k_m_y_ptr, k_m_z_ptr, k_E_ptr)
257 do i = 1, s
258 k_rho_ptr => k_rho%items(i)%ptr%x
259 k_m_x_ptr => k_m_x%items(i)%ptr%x
260 k_m_y_ptr => k_m_y%items(i)%ptr%x
261 k_m_z_ptr => k_m_z%items(i)%ptr%x
262 k_e_ptr => k_e%items(i)%ptr%x
263
264 !OCL NORECURRENCE, NOVREC, NOALIAS
265 !DIR$ CONCURRENT
266 !DIR$ IVDEP
267 !GCC$ ivdep
268 !$omp do simd
269 do l = 1, n
270 rho_field%x(l,1,1,1) = rho_field%x(l,1,1,1) + &
271 dt * rk_scheme%coeffs_b(i) * k_rho_ptr(l,1,1,1)
272 m_x%x(l,1,1,1) = m_x%x(l,1,1,1) + &
273 dt * rk_scheme%coeffs_b(i) * k_m_x_ptr(l,1,1,1)
274 m_y%x(l,1,1,1) = m_y%x(l,1,1,1) + &
275 dt * rk_scheme%coeffs_b(i) * k_m_y_ptr(l,1,1,1)
276 m_z%x(l,1,1,1) = m_z%x(l,1,1,1) + &
277 dt * rk_scheme%coeffs_b(i) * k_m_z_ptr(l,1,1,1)
278 e%x(l,1,1,1) = e%x(l,1,1,1) + &
279 dt * rk_scheme%coeffs_b(i) * k_e_ptr(l,1,1,1)
280 end do
281 !$omp end do simd
282 end do
283 !$omp end parallel
284
285 call neko_scratch_registry%relinquish_field(tmp_indices)
286
288
313 subroutine evaluate_rhs_cpu(rhs_rho_field, rhs_m_x, rhs_m_y, rhs_m_z, rhs_E, &
314 rho_field, m_x, m_y, m_z, E, p, u, v, w, Ax, &
315 Ax_stress, coef, gs, artificial_visc, mu, kappa)
316 type(field_t), intent(inout) :: rhs_rho_field, &
317 rhs_m_x, rhs_m_y, rhs_m_z, rhs_e
318 type(field_t), intent(inout) :: rho_field, m_x, m_y, m_z, E
319 type(field_t), intent(in) :: p, u, v, w, artificial_visc, mu, kappa
320 class(ax_t), intent(inout) :: Ax, Ax_stress
321 type(coef_t), intent(inout) :: coef
322 type(gs_t), intent(inout) :: gs
323 integer :: i, n
324 type(field_t), pointer :: f_x, f_y, f_z
325 type(field_t), pointer :: visc_rho, visc_m_x, visc_m_y, visc_m_z, visc_E
326 integer :: tmp_indices(8)
327
328 n = coef%dof%size()
329
330 call neko_scratch_registry%request_field(f_x, tmp_indices(1), .false.)
331 call neko_scratch_registry%request_field(f_y, tmp_indices(2), .false.)
332 call neko_scratch_registry%request_field(f_z, tmp_indices(3), .false.)
333
334 ! Hoisted from below so the registry calls are kept outside the
335 ! following !$omp parallel do simd regions.
336 ! fused into one !$omp parallel do simd (registry calls are not
337 ! thread-safe so they cannot sit between two !$omp do constructs).
338 call neko_scratch_registry%request_field(visc_rho, tmp_indices(4), .false.)
339 call neko_scratch_registry%request_field(visc_m_x, tmp_indices(5), .false.)
340 call neko_scratch_registry%request_field(visc_m_y, tmp_indices(6), .false.)
341 call neko_scratch_registry%request_field(visc_m_z, tmp_indices(7), .false.)
342 call neko_scratch_registry%request_field(visc_e, tmp_indices(8), .false.)
343
345 ! Compute density flux divergence
346 call div(rhs_rho_field%x, m_x%x, m_y%x, m_z%x, coef)
347
349 ! Compute momentum flux divergences
350 ! m_x
351 !OCL NORECURRENCE, NOVREC, NOALIAS
352 !DIR$ CONCURRENT
353 !DIR$ IVDEP
354 !GCC$ ivdep
355 !$omp parallel do simd
356 do i = 1, n
357 f_x%x(i,1,1,1) = m_x%x(i,1,1,1) * m_x%x(i,1,1,1) / &
358 rho_field%x(i,1,1,1) + p%x(i,1,1,1)
359 f_y%x(i,1,1,1) = m_x%x(i,1,1,1) * m_y%x(i,1,1,1) / &
360 rho_field%x(i,1,1,1)
361 f_z%x(i,1,1,1) = m_x%x(i,1,1,1) * m_z%x(i,1,1,1) / &
362 rho_field%x(i,1,1,1)
363 end do
364 !$omp end parallel do simd
365 call div(rhs_m_x%x, f_x%x, f_y%x, f_z%x, coef)
366 ! m_y
367 !OCL NORECURRENCE, NOVREC, NOALIAS
368 !DIR$ CONCURRENT
369 !DIR$ IVDEP
370 !GCC$ ivdep
371 !$omp parallel do simd
372 do i = 1, n
373 f_x%x(i,1,1,1) = m_y%x(i,1,1,1) * m_x%x(i,1,1,1) / &
374 rho_field%x(i,1,1,1)
375 f_y%x(i,1,1,1) = m_y%x(i,1,1,1) * m_y%x(i,1,1,1) / &
376 rho_field%x(i,1,1,1) + p%x(i,1,1,1)
377 f_z%x(i,1,1,1) = m_y%x(i,1,1,1) * m_z%x(i,1,1,1) / &
378 rho_field%x(i,1,1,1)
379 end do
380 !$omp end parallel do simd
381 call div(rhs_m_y%x, f_x%x, f_y%x, f_z%x, coef)
382 ! m_z
383 !OCL NORECURRENCE, NOVREC, NOALIAS
384 !DIR$ CONCURRENT
385 !DIR$ IVDEP
386 !GCC$ ivdep
387 !$omp parallel do simd
388 do i = 1, n
389 f_x%x(i,1,1,1) = m_z%x(i,1,1,1) * m_x%x(i,1,1,1) / &
390 rho_field%x(i,1,1,1)
391 f_y%x(i,1,1,1) = m_z%x(i,1,1,1) * m_y%x(i,1,1,1) / &
392 rho_field%x(i,1,1,1)
393 f_z%x(i,1,1,1) = m_z%x(i,1,1,1) * m_z%x(i,1,1,1) / &
394 rho_field%x(i,1,1,1) + p%x(i,1,1,1)
395 end do
396 !$omp end parallel do simd
397 call div(rhs_m_z%x, f_x%x, f_y%x, f_z%x, coef)
398
400 ! Compute energy flux divergence
401 !OCL NORECURRENCE, NOVREC, NOALIAS
402 !DIR$ CONCURRENT
403 !DIR$ IVDEP
404 !GCC$ ivdep
405 !$omp parallel do simd
406 do i = 1, n
407 f_x%x(i,1,1,1) = (e%x(i,1,1,1) + p%x(i,1,1,1)) * &
408 u%x(i,1,1,1)
409 f_y%x(i,1,1,1) = (e%x(i,1,1,1) + p%x(i,1,1,1)) * &
410 v%x(i,1,1,1)
411 f_z%x(i,1,1,1) = (e%x(i,1,1,1) + p%x(i,1,1,1)) * &
412 w%x(i,1,1,1)
413 end do
414 !$omp end parallel do simd
415 call div(rhs_e%x, f_x%x, f_y%x, f_z%x, coef)
416
417 call gs%op(rhs_rho_field, gs_op_add)
418 call rotate_cyc(rhs_m_x%x, rhs_m_y%x, rhs_m_z%x, 1, coef)
419 call gs%op(rhs_m_x%x, rhs_m_y%x, rhs_m_z%x, n, gs_op_add)
420 call rotate_cyc(rhs_m_x%x, rhs_m_y%x, rhs_m_z%x, 0, coef)
421 call gs%op(rhs_e, gs_op_add)
422
423 ! Apply multiplicity to the inviscid RHS and set h1 to the artificial
424 ! viscosity for the Laplacian (density, momentum and energy are all
425 ! stabilized by the same artificial viscosity). Fused: one fork-join
426 ! instead of two, and coef%mult / artificial_visc share L1.
427 !OCL NORECURRENCE, NOVREC, NOALIAS
428 !DIR$ CONCURRENT
429 !DIR$ IVDEP
430 !GCC$ ivdep
431 !$omp parallel do simd
432 do i = 1, n
433 rhs_rho_field%x(i,1,1,1) = rhs_rho_field%x(i,1,1,1) * &
434 coef%mult(i,1,1,1)
435 rhs_m_x%x(i,1,1,1) = rhs_m_x%x(i,1,1,1) * coef%mult(i,1,1,1)
436 rhs_m_y%x(i,1,1,1) = rhs_m_y%x(i,1,1,1) * coef%mult(i,1,1,1)
437 rhs_m_z%x(i,1,1,1) = rhs_m_z%x(i,1,1,1) * coef%mult(i,1,1,1)
438 rhs_e%x(i,1,1,1) = rhs_e%x(i,1,1,1) * coef%mult(i,1,1,1)
439 coef%h1(i,1,1,1) = artificial_visc%x(i,1,1,1)
440 end do
441 !$omp end parallel do simd
442
443 coef%ifh2 = .false.
444
445 ! Calculate artificial diffusion with variable viscosity. The momentum
446 ! components share the operator, so they use the fused vector apply
447 ! (geometric factors and h1 are loaded once for all three components).
448 call ax%compute(visc_rho%x, rho_field%x, coef, p%msh, p%Xh)
449 call ax%compute_vector(visc_m_x%x, visc_m_y%x, visc_m_z%x, &
450 m_x%x, m_y%x, m_z%x, coef, p%msh, p%Xh)
451 call ax%compute(visc_e%x, e%x, coef, p%msh, p%Xh)
452
454 call add_navier_stokes_flux_cpu(visc_m_x, visc_m_y, visc_m_z, visc_e, &
455 rho_field, p, u, v, w, mu, kappa, ax, ax_stress, coef)
456 end if
457
458 ! gs. h1=1.0 reset is deferred into the final accumulation below; safe
459 ! because nothing here (gs%op, rotate_cyc) reads coef%h1.
460 call gs%op(visc_rho, gs_op_add)
461 call rotate_cyc(visc_m_x%x, visc_m_y%x, visc_m_z%x, 1, coef)
462 call gs%op(visc_m_x%x, visc_m_y%x, visc_m_z%x, n, gs_op_add)
463 call rotate_cyc(visc_m_x%x, visc_m_y%x, visc_m_z%x, 0, coef)
464 call gs%op(visc_e, gs_op_add)
465
466 ! Move div to the rhs, apply artificial viscosity, and reset h1 to 1.
467 ! The viscosity coefficient is already included in the Laplacian operator.
468 ! Fused: one fork-join instead of two, and coef%Binv stays in L1.
469 !OCL NORECURRENCE, NOVREC, NOALIAS
470 !DIR$ CONCURRENT
471 !DIR$ IVDEP
472 !GCC$ ivdep
473 !$omp parallel do simd
474 do i = 1, n
475 rhs_rho_field%x(i,1,1,1) = -rhs_rho_field%x(i,1,1,1) - &
476 coef%Binv(i,1,1,1) * visc_rho%x(i,1,1,1)
477 rhs_m_x%x(i,1,1,1) = -rhs_m_x%x(i,1,1,1) - &
478 coef%Binv(i,1,1,1) * visc_m_x%x(i,1,1,1)
479 rhs_m_y%x(i,1,1,1) = -rhs_m_y%x(i,1,1,1) - &
480 coef%Binv(i,1,1,1) * visc_m_y%x(i,1,1,1)
481 rhs_m_z%x(i,1,1,1) = -rhs_m_z%x(i,1,1,1) - &
482 coef%Binv(i,1,1,1) * visc_m_z%x(i,1,1,1)
483 rhs_e%x(i,1,1,1) = -rhs_e%x(i,1,1,1) - &
484 coef%Binv(i,1,1,1) * visc_e%x(i,1,1,1)
485 coef%h1(i,1,1,1) = 1.0_rp
486 end do
487 !$omp end parallel do simd
488
489 call neko_scratch_registry%relinquish_field(tmp_indices)
490 end subroutine evaluate_rhs_cpu
491
507 subroutine add_navier_stokes_flux_cpu(visc_m_x, visc_m_y, visc_m_z, visc_E, &
508 rho_field, p, u, v, w, mu, kappa, Ax, Ax_stress, coef)
509 type(field_t), intent(inout) :: visc_m_x, visc_m_y, visc_m_z, visc_E
510 type(field_t), intent(in) :: rho_field
511 type(field_t), intent(in) :: p, u, v, w, mu, kappa
512 class(ax_t), intent(inout) :: Ax, Ax_stress
513 type(coef_t), intent(inout) :: coef
514 type(field_t), pointer :: dudx, dudy, dudz, dvdx, dvdy, dvdz, &
515 dwdx, dwdy, dwdz, tau_xx, tau_xy, tau_xz, tau_yy, tau_yz, &
516 tau_zz, f_x, f_y, f_z, div_flux, dissipation
517 integer :: tmp_indices(20)
518 integer :: i, n
519 real(kind=rp) :: div_u, two_thirds
520
521 n = coef%dof%size()
522 two_thirds = 2.0_rp / 3.0_rp
523
524 call neko_scratch_registry%request_field(dudx, tmp_indices(1), .false.)
525 call neko_scratch_registry%request_field(dudy, tmp_indices(2), .false.)
526 call neko_scratch_registry%request_field(dudz, tmp_indices(3), .false.)
527 call neko_scratch_registry%request_field(dvdx, tmp_indices(4), .false.)
528 call neko_scratch_registry%request_field(dvdy, tmp_indices(5), .false.)
529 call neko_scratch_registry%request_field(dvdz, tmp_indices(6), .false.)
530 call neko_scratch_registry%request_field(dwdx, tmp_indices(7), .false.)
531 call neko_scratch_registry%request_field(dwdy, tmp_indices(8), .false.)
532 call neko_scratch_registry%request_field(dwdz, tmp_indices(9), .false.)
533 call neko_scratch_registry%request_field(tau_xx, tmp_indices(10), .false.)
534 call neko_scratch_registry%request_field(tau_xy, tmp_indices(11), .false.)
535 call neko_scratch_registry%request_field(tau_xz, tmp_indices(12), .false.)
536 call neko_scratch_registry%request_field(tau_yy, tmp_indices(13), .false.)
537 call neko_scratch_registry%request_field(tau_yz, tmp_indices(14), .false.)
538 call neko_scratch_registry%request_field(tau_zz, tmp_indices(15), .false.)
539 call neko_scratch_registry%request_field(f_x, tmp_indices(16), .false.)
540 call neko_scratch_registry%request_field(f_y, tmp_indices(17), .false.)
541 call neko_scratch_registry%request_field(f_z, tmp_indices(18), .false.)
542 call neko_scratch_registry%request_field(div_flux, tmp_indices(19), .false.)
543 call neko_scratch_registry%request_field(dissipation, tmp_indices(20), &
544 .false.)
545
546 call grad(dudx%x, dudy%x, dudz%x, u%x, coef)
547 call grad(dvdx%x, dvdy%x, dvdz%x, v%x, coef)
548 call grad(dwdx%x, dwdy%x, dwdz%x, w%x, coef)
549
550 ! Viscous stress tensor, dilatational flux, viscous dissipation and
551 ! h1 = mu for the stress Laplacian, fused into a single sweep.
552 !OCL NORECURRENCE, NOVREC, NOALIAS
553 !DIR$ CONCURRENT
554 !DIR$ IVDEP
555 !GCC$ ivdep
556 !$omp parallel do simd private(div_u)
557 do i = 1, n
558 div_u = dudx%x(i,1,1,1) + dvdy%x(i,1,1,1) + dwdz%x(i,1,1,1)
559 div_flux%x(i,1,1,1) = mu%x(i,1,1,1) * div_u
560 coef%h1(i,1,1,1) = mu%x(i,1,1,1)
561 tau_xx%x(i,1,1,1) = mu%x(i,1,1,1) * &
562 (2.0_rp * dudx%x(i,1,1,1) - two_thirds * div_u)
563 tau_yy%x(i,1,1,1) = mu%x(i,1,1,1) * &
564 (2.0_rp * dvdy%x(i,1,1,1) - two_thirds * div_u)
565 tau_zz%x(i,1,1,1) = mu%x(i,1,1,1) * &
566 (2.0_rp * dwdz%x(i,1,1,1) - two_thirds * div_u)
567 tau_xy%x(i,1,1,1) = mu%x(i,1,1,1) * &
568 (dudy%x(i,1,1,1) + dvdx%x(i,1,1,1))
569 tau_xz%x(i,1,1,1) = mu%x(i,1,1,1) * &
570 (dudz%x(i,1,1,1) + dwdx%x(i,1,1,1))
571 tau_yz%x(i,1,1,1) = mu%x(i,1,1,1) * &
572 (dvdz%x(i,1,1,1) + dwdy%x(i,1,1,1))
573 dissipation%x(i,1,1,1) = &
574 tau_xx%x(i,1,1,1) * dudx%x(i,1,1,1) &
575 + tau_xy%x(i,1,1,1) * (dudy%x(i,1,1,1) + dvdx%x(i,1,1,1)) &
576 + tau_xz%x(i,1,1,1) * (dudz%x(i,1,1,1) + dwdx%x(i,1,1,1)) &
577 + tau_yy%x(i,1,1,1) * dvdy%x(i,1,1,1) &
578 + tau_yz%x(i,1,1,1) * (dvdz%x(i,1,1,1) + dwdy%x(i,1,1,1)) &
579 + tau_zz%x(i,1,1,1) * dwdz%x(i,1,1,1)
580 end do
581 !$omp end parallel do simd
582
583 call ax_stress%compute_vector(f_x%x, f_y%x, f_z%x, u%x, v%x, w%x, coef, &
584 p%msh, p%Xh)
585 call opgrad(dudx%x, dudy%x, dudz%x, div_flux%x, coef)
586
587 ! Accumulate the stress contribution into the viscous residual, add
588 ! the dissipation to the energy residual, compute the internal energy
589 ! (temperature) for the heat flux and set h1 = kappa for its Laplacian.
590 ! Fused: one fork-join instead of four.
591 !OCL NORECURRENCE, NOVREC, NOALIAS
592 !DIR$ CONCURRENT
593 !DIR$ IVDEP
594 !GCC$ ivdep
595 !$omp parallel do simd
596 do i = 1, n
597 f_x%x(i,1,1,1) = f_x%x(i,1,1,1) &
598 - two_thirds * dudx%x(i,1,1,1)
599 f_y%x(i,1,1,1) = f_y%x(i,1,1,1) &
600 - two_thirds * dudy%x(i,1,1,1)
601 f_z%x(i,1,1,1) = f_z%x(i,1,1,1) &
602 - two_thirds * dudz%x(i,1,1,1)
603 visc_m_x%x(i,1,1,1) = visc_m_x%x(i,1,1,1) + f_x%x(i,1,1,1)
604 visc_m_y%x(i,1,1,1) = visc_m_y%x(i,1,1,1) + f_y%x(i,1,1,1)
605 visc_m_z%x(i,1,1,1) = visc_m_z%x(i,1,1,1) + f_z%x(i,1,1,1)
606 visc_e%x(i,1,1,1) = visc_e%x(i,1,1,1) &
607 + u%x(i,1,1,1) * f_x%x(i,1,1,1) &
608 + v%x(i,1,1,1) * f_y%x(i,1,1,1) &
609 + w%x(i,1,1,1) * f_z%x(i,1,1,1) &
610 - coef%B(i,1,1,1) * dissipation%x(i,1,1,1)
611 div_flux%x(i,1,1,1) = p%x(i,1,1,1) / &
612 (rho_field%x(i,1,1,1) * (compressible_res_cpu_gamma - 1.0_rp))
613 coef%h1(i,1,1,1) = kappa%x(i,1,1,1)
614 end do
615 !$omp end parallel do simd
616
617 call ax%compute(dudx%x, div_flux%x, coef, p%msh, p%Xh)
618
619 !OCL NORECURRENCE, NOVREC, NOALIAS
620 !DIR$ CONCURRENT
621 !DIR$ IVDEP
622 !GCC$ ivdep
623 !$omp parallel do simd
624 do i = 1, n
625 visc_e%x(i,1,1,1) = visc_e%x(i,1,1,1) + dudx%x(i,1,1,1)
626 end do
627 !$omp end parallel do simd
628
629 call neko_scratch_registry%relinquish_field(tmp_indices)
630
631 end subroutine add_navier_stokes_flux_cpu
632
633end module compressible_res_cpu
Compute the divergence of a vector field.
Definition operators.f90:86
Compute the gradient of a scalar field, multiplied by the mass matrix.
Definition operators.f90:92
Apply cyclic boundary condition to a vector field.
Defines a Matrix-vector product.
Definition ax.f90:34
Defines a list of bc_t.
Definition bc_list.f90:34
Coefficients.
Definition coef.f90:34
CPU implementation of compressible flow operations.
subroutine, public compressible_ops_cpu_update_uvw(u, v, w, m_x, m_y, m_z, rho, n)
Update u,v,w fields.
subroutine, public compressible_ops_cpu_update_mxyz_p_ruvw(m_x, m_y, m_z, p, ruvw, u, v, w, e, rho, gamma, n)
Update m_x, m_y, m_z, p, ruvw, fields.
This implements CPU-based residual calculations for the compressible equations. It handles the time a...
subroutine add_navier_stokes_flux_cpu(visc_m_x, visc_m_y, visc_m_z, visc_e, rho_field, p, u, v, w, mu, kappa, ax, ax_stress, coef)
Add the physical Navier-Stokes flux contribution to the viscous residual.
subroutine advance_primitive_variables_cpu(rho_field, m_x, m_y, m_z, e, p, u, v, w, ax, ax_stress, coef, gs, artificial_visc, mu, kappa, bcs_vel, time, rk_scheme, dt)
Advances the primitive variables (density, momentum, energy) in time using a Runge-Kutta scheme.
logical, public compressible_res_cpu_add_physical_stress
Whether physical viscous stress is active for the current step. Set by compressible_rhs_set_physical_...
logical, public compressible_res_cpu_add_physical_flux
Whether physical Navier-Stokes fluxes are active for the current step. Set by compressible_rhs_set_ph...
real(kind=rp), public compressible_res_cpu_gamma
Module variable to store thermodynamic parameter set by factory.
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, ax_stress, coef, gs, artificial_visc, mu, kappa)
Evaluates the right-hand side of the compressible equations. Inviscid terms are evaluated through div...
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:14
Operators.
Definition operators.f90:34
subroutine, public opgrad(ux, uy, uz, u, coef, es, ee)
Compute the weak gradient of a scalar field, i.e. the gradient multiplied by the mass matrix.
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.
Base type for a matrix-vector product providing .
Definition ax.f90:43
A list of allocatable `bc_t`. Follows the standard interface of lists.
Definition bc_list.f90:49
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:135
field_list_t, To be able to group fields together
Gather-scatter kernel.
A struct that contains all info about the time, expand as needed.