MFC
Exascale flow solver
Loading...
Searching...
No Matches
m_derived_variables.fpp.f90
Go to the documentation of this file.
1# 1 "/home/runner/work/MFC/MFC/src/post_process/m_derived_variables.fpp"
2!>
3!! @file
4!! @brief Contains module m_derived_variables
5
6!> @brief Computes derived flow quantities (sound speed, vorticity, Schlieren, etc.) from conservative and primitive variables
7
9
12 use m_mpi_proxy
15 use m_eos
17
18 implicit none
19
23
24 !> Finite-difference state: density gradient magnitude and centered FD coefficients in x-, y-, and z-directions.
25 type(fd_context) :: fd
26
27contains
28
29 !> Computation of parameters, allocation procedures, and/or any other tasks needed to properly setup the module
31
32 ! Allocate density gradient magnitude if Schlieren output requested
33 if (schlieren_wrt) then
34 allocate (fd%gm_rho_sf(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end))
35 end if
36
37 ! Allocate FD coefficients (up to 4th order; higher orders need extension)
38
39 if (omega_wrt(2) .or. omega_wrt(3) .or. qm_wrt .or. schlieren_wrt .or. liutex_wrt) then
40 allocate (fd%fd_coeff_x(-fd_number:fd_number,-offset_x%beg:m + offset_x%end))
41 end if
42
43 if (omega_wrt(1) .or. omega_wrt(3) .or. qm_wrt .or. liutex_wrt .or. (n > 0 .and. schlieren_wrt)) then
44 allocate (fd%fd_coeff_y(-fd_number:fd_number,-offset_y%beg:n + offset_y%end))
45 end if
46
47 if (omega_wrt(1) .or. omega_wrt(2) .or. qm_wrt .or. liutex_wrt .or. (p > 0 .and. schlieren_wrt)) then
48 allocate (fd%fd_coeff_z(-fd_number:fd_number,-offset_z%beg:p + offset_z%end))
49 end if
50
52
53 !> Derive the specific heat ratio from the specific heat ratio function gamma_sf. The latter is stored in the derived flow
54 !! quantity storage variable, q_sf.
56
57 real(wp), dimension(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end), &
58 & intent(inout) :: q_sf
59
60 integer :: i, j, k
61 do k = -offset_z%beg, p + offset_z%end
62 do j = -offset_y%beg, n + offset_y%end
63 do i = -offset_x%beg, m + offset_x%end
64 q_sf(i, j, k) = f_isentrope_exponent(gamma_sf(i, j, k))
65 end do
66 end do
67 end do
68
69 end subroutine s_derive_specific_heat_ratio
70
71 !> Compute the liquid stiffness from the specific heat ratio function gamma_sf and the liquid stiffness function pi_inf_sf,
72 !! respectively. These are used to calculate the values of the liquid stiffness, which are stored in the derived flow quantity
73 !! storage variable, q_sf.
75
76 real(wp), dimension(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end), &
77 & intent(inout) :: q_sf
78
79 integer :: i, j, k
80 do k = -offset_z%beg, p + offset_z%end
81 do j = -offset_y%beg, n + offset_y%end
82 do i = -offset_x%beg, m + offset_x%end
83 q_sf(i, j, k) = f_isentrope_pressure(pi_inf_sf(i, j, k), gamma_sf(i, j, k))
84 end do
85 end do
86 end do
87
88 end subroutine s_derive_liquid_stiffness
89
90 !> Derive the flux limiter at cell boundary i+1/2. This is an approximation because the velocity used to determine the upwind
91 !! direction is the velocity at the cell center i instead of the contact velocity at the cell boundary from the Riemann solver.
92 subroutine s_derive_flux_limiter(i, q_prim_vf, q_sf)
93
94 integer, intent(in) :: i
95 type(scalar_field), dimension(sys_size), intent(in) :: q_prim_vf
96
97 real(wp), dimension(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end), &
98 & intent(inout) :: q_sf
99
100 real(wp) :: top, bottom, slope
101 integer :: j, k, l
102 do l = -offset_z%beg, p + offset_z%end
103 do k = -offset_y%beg, n + offset_y%end
104 do j = -offset_x%beg, m + offset_x%end
105 if (i == 1) then
106 if (q_prim_vf(eqn_idx%cont%end + i)%sf(j, k, l) >= 0._wp) then
107 top = q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j - 1, k, l)
108 bottom = q_prim_vf(eqn_idx%adv%beg)%sf(j + 1, k, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l)
109 else
110 top = q_prim_vf(eqn_idx%adv%beg)%sf(j + 2, k, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j + 1, k, l)
111 bottom = q_prim_vf(eqn_idx%adv%beg)%sf(j + 1, k, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l)
112 end if
113 else if (i == 2) then
114 if (q_prim_vf(eqn_idx%cont%end + i)%sf(j, k, l) >= 0._wp) then
115 top = q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k - 1, l)
116 bottom = q_prim_vf(eqn_idx%adv%beg)%sf(j, k + 1, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l)
117 else
118 top = q_prim_vf(eqn_idx%adv%beg)%sf(j, k + 2, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k + 1, l)
119 bottom = q_prim_vf(eqn_idx%adv%beg)%sf(j, k + 1, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l)
120 end if
121 else
122 if (q_prim_vf(eqn_idx%cont%end + i)%sf(j, k, l) >= 0._wp) then
123 top = q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l - 1)
124 bottom = q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l + 1) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l)
125 else
126 top = q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l + 2) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l + 1)
127 bottom = q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l + 1) - q_prim_vf(eqn_idx%adv%beg)%sf(j, k, l)
128 end if
129 end if
130
131 if (abs(top) < 1.e-8_wp) top = 0._wp
132 if (abs(bottom) < 1.e-8_wp) bottom = 0._wp
133
134 if (f_approx_equal(top, bottom)) then
135 slope = 1._wp
136 else
137 slope = (top*bottom)/(bottom**2._wp + 1.e-16_wp)
138 end if
139
140 if (flux_lim == 1) then ! MINMOD (MM)
141 q_sf(j, k, l) = max(0._wp, min(1._wp, slope))
142 else if (flux_lim == 2) then ! MUSCL (MC)
143 q_sf(j, k, l) = max(0._wp, min(2._wp*slope, 5.e-1_wp*(1._wp + slope), 2._wp))
144 else if (flux_lim == 3) then ! OSPRE (OP)
145 q_sf(j, k, l) = (15.e-1_wp*(slope**2._wp + slope))/(slope**2._wp + slope + 1._wp)
146 else if (flux_lim == 4) then ! SUPERBEE (SB)
147 q_sf(j, k, l) = max(0._wp, min(1._wp, 2._wp*slope), min(slope, 2._wp))
148 else if (flux_lim == 5) then ! SWEBY (SW) (beta = 1.5)
149 q_sf(j, k, l) = max(0._wp, min(15.e-1_wp*slope, 1._wp), min(slope, 15.e-1_wp))
150 else if (flux_lim == 6) then ! VAN ALBADA (VA)
151 q_sf(j, k, l) = (slope**2._wp + slope)/(slope**2._wp + 1._wp)
152 else if (flux_lim == 7) then ! VAN LEER (VL)
153 q_sf(j, k, l) = (abs(slope) + slope)/(1._wp + abs(slope))
154 end if
155 end do
156 end do
157 end do
158
159 end subroutine s_derive_flux_limiter
160
161 !> Compute the specified component of the vorticity from the primitive variables. From those inputs, it proceeds to calculate
162 !! values of the desired vorticity component, which are subsequently stored in derived flow quantity storage variable, q_sf.
163 subroutine s_derive_vorticity_component(i, q_prim_vf, q_sf)
164
165 integer, intent(in) :: i
166 type(scalar_field), dimension(sys_size), intent(in) :: q_prim_vf
167
168 real(wp), dimension(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end), &
169 & intent(inout) :: q_sf
170
171 integer :: j, k, l, r
172 if (i == 1) then
173 do l = -offset_z%beg, p + offset_z%end
174 do k = -offset_y%beg, n + offset_y%end
175 do j = -offset_x%beg, m + offset_x%end
176 q_sf(j, k, l) = 0._wp
177
178 do r = -fd_number, fd_number
179 if (grid_geometry == 3) then
180 q_sf(j, k, l) = q_sf(j, k, l) + 1._wp/y_cc(k)*(fd%fd_coeff_y(r, &
181 & k)*y_cc(r + k)*q_prim_vf(eqn_idx%mom%end)%sf(j, r + k, l) - fd%fd_coeff_z(r, &
182 & l)*q_prim_vf(eqn_idx%mom%beg + 1)%sf(j, k, r + l))
183 else
184 q_sf(j, k, l) = q_sf(j, k, l) + fd%fd_coeff_y(r, k)*q_prim_vf(eqn_idx%mom%end)%sf(j, r + k, &
185 & l) - fd%fd_coeff_z(r, l)*q_prim_vf(eqn_idx%mom%beg + 1)%sf(j, k, r + l)
186 end if
187 end do
188 end do
189 end do
190 end do
191 else if (i == 2) then
192 do l = -offset_z%beg, p + offset_z%end
193 do k = -offset_y%beg, n + offset_y%end
194 do j = -offset_x%beg, m + offset_x%end
195 q_sf(j, k, l) = 0._wp
196
197 do r = -fd_number, fd_number
198 if (grid_geometry == 3) then
199 q_sf(j, k, l) = q_sf(j, k, l) + fd%fd_coeff_z(r, l)/y_cc(k)*q_prim_vf(eqn_idx%mom%beg)%sf(j, k, &
200 & r + l) - fd%fd_coeff_x(r, j)*q_prim_vf(eqn_idx%mom%end)%sf(r + j, k, l)
201 else
202 q_sf(j, k, l) = q_sf(j, k, l) + fd%fd_coeff_z(r, l)*q_prim_vf(eqn_idx%mom%beg)%sf(j, k, &
203 & r + l) - fd%fd_coeff_x(r, j)*q_prim_vf(eqn_idx%mom%end)%sf(r + j, k, l)
204 end if
205 end do
206 end do
207 end do
208 end do
209 else
210 do l = -offset_z%beg, p + offset_z%end
211 do k = -offset_y%beg, n + offset_y%end
212 do j = -offset_x%beg, m + offset_x%end
213 q_sf(j, k, l) = 0._wp
214
215 do r = -fd_number, fd_number
216 q_sf(j, k, l) = q_sf(j, k, l) + fd%fd_coeff_x(r, j)*q_prim_vf(eqn_idx%mom%beg + 1)%sf(r + j, k, &
217 & l) - fd%fd_coeff_y(r, k)*q_prim_vf(eqn_idx%mom%beg)%sf(j, r + k, l)
218 end do
219 end do
220 end do
221 end do
222 end if
223
224 end subroutine s_derive_vorticity_component
225
226 !> Compute the Q_M criterion from the primitive variables. The Q_M function, which are subsequently stored in the derived flow
227 !! quantity storage variable, q_sf.
228 subroutine s_derive_qm(q_prim_vf, q_sf)
229
230 type(scalar_field), dimension(sys_size), intent(in) :: q_prim_vf
231
232 real(wp), dimension(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end), &
233 & intent(inout) :: q_sf
234
235 real(wp), dimension(1:3,1:3) :: q_jacobian_sf, s, s2, o, o2
236 real(wp) :: trs, q, iis
237 integer :: j, k, l, r, jj, kk
238 do l = -offset_z%beg, p + offset_z%end
239 do k = -offset_y%beg, n + offset_y%end
240 do j = -offset_x%beg, m + offset_x%end
241 ! Get velocity gradient tensor
242 q_jacobian_sf(:,:) = 0._wp
243
244 do r = -fd_number, fd_number
245 do jj = 1, 3
246 ! d()/dx
247 q_jacobian_sf(jj, 1) = q_jacobian_sf(jj, 1) + fd%fd_coeff_x(r, &
248 & j)*q_prim_vf(eqn_idx%mom%beg + jj - 1)%sf(r + j, k, l)
249 ! d()/dy
250 q_jacobian_sf(jj, 2) = q_jacobian_sf(jj, 2) + fd%fd_coeff_y(r, &
251 & k)*q_prim_vf(eqn_idx%mom%beg + jj - 1)%sf(j, r + k, l)
252 ! d()/dz
253 q_jacobian_sf(jj, 3) = q_jacobian_sf(jj, 3) + fd%fd_coeff_z(r, &
254 & l)*q_prim_vf(eqn_idx%mom%beg + jj - 1)%sf(j, k, r + l)
255 end do
256 end do
257
258 ! Decompose velocity gradient into symmetric strain-rate S and skew-symmetric rotation-rate O
259 do jj = 1, 3
260 do kk = 1, 3
261 s(jj, kk) = 0.5_wp*(q_jacobian_sf(jj, kk) + q_jacobian_sf(kk, jj))
262 o(jj, kk) = 0.5_wp*(q_jacobian_sf(jj, kk) - q_jacobian_sf(kk, jj))
263 end do
264 end do
265
266 do jj = 1, 3
267 do kk = 1, 3
268 o2(jj, kk) = o(jj, 1)*o(kk, 1) + o(jj, 2)*o(kk, 2) + o(jj, 3)*o(kk, 3)
269 s2(jj, kk) = s(jj, 1)*s(kk, 1) + s(jj, 2)*s(kk, 2) + s(jj, 3)*s(kk, 3)
270 end do
271 end do
272
273 ! Q-criterion: Q = (||O||^2 - ||S||^2)/2, Hunt et al. CTR (1988)
274 q = 0.5_wp*((o2(1, 1) + o2(2, 2) + o2(3, 3)) - (s2(1, 1) + s2(2, 2) + s2(3, 3)))
275 trs = s(1, 1) + s(2, 2) + s(3, 3)
276 ! Second invariant of strain-rate tensor
277 iis = 0.5_wp*((s(1, 1) + s(2, 2) + s(3, 3))**2 - (s2(1, 1) + s2(2, 2) + s2(3, 3)))
278 q_sf(j, k, l) = q + iis
279 end do
280 end do
281 end do
282
283 end subroutine s_derive_qm
284
285 !> Compute the Liutex vector and its magnitude based on Xu et al. (2019).
286 impure subroutine s_derive_liutex(q_prim_vf, liutex_mag, liutex_axis)
287
288 ! Liutex vortex identification via real eigenvector of velocity gradient, Xu et al. PoF (2019)
289
290 integer, parameter :: nm = 3
291 type(scalar_field), dimension(sys_size), intent(in) :: q_prim_vf
292
293 !> Liutex magnitude
294
295 real(wp), dimension(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end), &
296 & intent(out) :: liutex_mag
297 !> Liutex rigid rotation axis
298 real(wp), dimension(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end,nm), &
299 & intent(out) :: liutex_axis
300 character, parameter :: ivl = 'N' !< compute left eigenvectors
301 character, parameter :: ivr = 'V' !< compute right eigenvectors
302 real(wp), dimension(nm, nm) :: vgt !< velocity gradient tensor
303 real(wp), dimension(nm) :: lr, li !< real and imaginary parts of eigenvalues
304 real(wp), dimension(nm, nm) :: vl, vr !< left and right eigenvectors
305 integer, parameter :: lwork = 4*nm !< size of work array (4*nm recommended)
306 real(wp), dimension(lwork) :: work !< work array
307 integer :: info
308 real(wp), dimension(nm) :: eigvec !< real eigenvector
309 real(wp) :: eigvec_mag !< magnitude of real eigenvector
310 real(wp) :: omega_proj !< projection of vorticity on real eigenvector
311 real(wp) :: lci !< imaginary part of complex eigenvalue
312 real(wp) :: alpha
313 integer :: j, k, l, r, i
314 integer :: idx
315
316 do l = -offset_z%beg, p + offset_z%end
317 do k = -offset_y%beg, n + offset_y%end
318 do j = -offset_x%beg, m + offset_x%end
319 ! Get velocity gradient tensor (VGT)
320 vgt(:,:) = 0._wp
321
322 do r = -fd_number, fd_number
323 do i = 1, 3
324 ! d()/dx
325 vgt(i, 1) = vgt(i, 1) + fd%fd_coeff_x(r, j)*q_prim_vf(eqn_idx%mom%beg + i - 1)%sf(r + j, k, l)
326 ! d()/dy
327 vgt(i, 2) = vgt(i, 2) + fd%fd_coeff_y(r, k)*q_prim_vf(eqn_idx%mom%beg + i - 1)%sf(j, r + k, l)
328 ! d()/dz
329 vgt(i, 3) = vgt(i, 3) + fd%fd_coeff_z(r, l)*q_prim_vf(eqn_idx%mom%beg + i - 1)%sf(j, k, r + l)
330 end do
331 end do
332
333 ! Call appropriate LAPACK routine based on precision
334#ifdef MFC_SINGLE_PRECISION
335 call sgeev(ivl, ivr, nm, vgt, nm, lr, li, vl, nm, vr, nm, work, lwork, info)
336#else
337 call dgeev(ivl, ivr, nm, vgt, nm, lr, li, vl, nm, vr, nm, work, lwork, info)
338#endif
339
340 ! Find eigenvector with smallest imaginary eigenvalue (real eigenvector of VGT)
341 idx = 1
342 do r = 2, 3
343 if (abs(li(r)) < abs(li(idx))) then
344 idx = r
345 end if
346 end do
347 eigvec = vr(:,idx)
348
349 ! Normalize real eigenvector if it is effectively non-zero
350 eigvec_mag = sqrt(eigvec(1)**2._wp + eigvec(2)**2._wp + eigvec(3)**2._wp)
351 if (eigvec_mag > sgm_eps) then
352 eigvec = eigvec/eigvec_mag
353 else
354 eigvec = 0._wp
355 end if
356
357 ! Compute vorticity projected on the eigenvector
358 omega_proj = (vgt(3, 2) - vgt(2, 3))*eigvec(1) + (vgt(1, 3) - vgt(3, 1))*eigvec(2) + (vgt(2, 1) - vgt(1, &
359 & 2))*eigvec(3)
360
361 ! As eigenvector can have +/- signs, we can choose the sign so that omega_proj is positive
362 if (omega_proj < 0._wp) then
363 eigvec = -eigvec
364 omega_proj = -omega_proj
365 end if
366
367 ! Imaginary eigenvalue of the complex conjugate pair (cyclic index selection)
368 lci = li(mod(idx, 3) + 1)
369
370 ! Discriminant: determines whether rotation dominates strain
371 alpha = omega_proj**2._wp - 4._wp*lci**2._wp
372 ! Liutex magnitude = omega_proj - sqrt(discriminant) when rotation dominates
373 if (alpha > 0._wp) then
374 liutex_mag(j, k, l) = omega_proj - sqrt(alpha)
375 else
376 liutex_mag(j, k, l) = omega_proj
377 end if
378
379 ! Compute Liutex axis
380 liutex_axis(j, k, l, 1) = eigvec(1)
381 liutex_axis(j, k, l, 2) = eigvec(2)
382 liutex_axis(j, k, l, 3) = eigvec(3)
383 end do
384 end do
385 end do
386
387 end subroutine s_derive_liutex
388
389 !> Compute the values of the numerical Schlieren function, which are subsequently stored in the derived flow quantity storage
390 !! variable, q_sf.
391 impure subroutine s_derive_numerical_schlieren_function(q_cons_vf, q_sf)
392
393 type(scalar_field), dimension(sys_size), intent(in) :: q_cons_vf
394
395 real(wp), dimension(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end), &
396 & intent(inout) :: q_sf
397
398 real(wp) :: drho_dx, drho_dy, drho_dz !< Spatial derivatives of the density in the x-, y- and z-directions
399 real(wp), dimension(2) :: gm_rho_max !< Global (max gradient magnitude, rank) pair for density
400 real(wp) :: alpha_last !< Volume fraction of the fluid not explicitly stored (IGR)
401 integer :: i, j, k, l
402
403 do l = -offset_z%beg, p + offset_z%end
404 do k = -offset_y%beg, n + offset_y%end
405 do j = -offset_x%beg, m + offset_x%end
406 drho_dx = 0._wp
407 drho_dy = 0._wp
408
409 do i = -fd_number, fd_number
410 drho_dx = drho_dx + fd%fd_coeff_x(i, j)*rho_sf(i + j, k, l)
411 drho_dy = drho_dy + fd%fd_coeff_y(i, k)*rho_sf(j, i + k, l)
412 end do
413
414 fd%gm_rho_sf(j, k, l) = drho_dx*drho_dx + drho_dy*drho_dy
415 end do
416 end do
417 end do
418
419 if (p > 0) then
420 do l = -offset_z%beg, p + offset_z%end
421 do k = -offset_y%beg, n + offset_y%end
422 do j = -offset_x%beg, m + offset_x%end
423 drho_dz = 0._wp
424
425 do i = -fd_number, fd_number
426 if (grid_geometry == 3) then
427 drho_dz = drho_dz + fd%fd_coeff_z(i, l)/y_cc(k)*rho_sf(j, k, i + l)
428 else
429 drho_dz = drho_dz + fd%fd_coeff_z(i, l)*rho_sf(j, k, i + l)
430 end if
431 end do
432
433 fd%gm_rho_sf(j, k, l) = fd%gm_rho_sf(j, k, l) + drho_dz*drho_dz
434 end do
435 end do
436 end do
437 end if
438
439 fd%gm_rho_sf = sqrt(fd%gm_rho_sf)
440
441 gm_rho_max = (/maxval(fd%gm_rho_sf), real(proc_rank, wp)/)
442
443 if (num_procs > 1) call s_mpi_reduce_maxloc(gm_rho_max)
444
445 ! The form of the numerical Schlieren function depends on the choice of the multicomponent flow model. For the gamma/pi_inf
446 ! model, the exponential of the negative, normalized, gradient magnitude of the density is computed. For the volume fraction
447 ! model, the amplitude of the exponential's inside is also modulated with respect to the identity of the fluid in which the
448 ! function is evaluated. For more information, refer to Marquina and Mulet (2003).
449
450 if (model_eqns == model_eqns_gamma_law) then ! Gamma/pi_inf model
451 q_sf = -fd%gm_rho_sf/gm_rho_max(1)
452 else ! Volume fraction model
453 do l = -offset_z%beg, p + offset_z%end
454 do k = -offset_y%beg, n + offset_y%end
455 do j = -offset_x%beg, m + offset_x%end
456 q_sf(j, k, l) = 0._wp
457
458 ! Tracks the volume fraction of the fluid not explicitly stored (IGR reconstructs it as 1 - sum)
459 if (igr) then
460 ! IGR stores only num_fluids-1 volume fractions; the last fluid's volume fraction is untracked.
461 ! For a single fluid this is simply 1.0 everywhere. Without this term, the entire single-fluid
462 ! Schlieren field is dropped, leaving exp(0) = 1 everywhere. Compute that term below.
463 alpha_last = 1._wp
464 do i = 1, eqn_idx%adv%end - eqn_idx%E
465 q_sf(j, k, l) = q_sf(j, k, l) - schlieren_alpha(i)*q_cons_vf(i + eqn_idx%E)%sf(j, k, &
466 & l)*fd%gm_rho_sf(j, k, l)/gm_rho_max(1)
467 alpha_last = alpha_last - q_cons_vf(i + eqn_idx%E)%sf(j, k, l)
468 end do
469 q_sf(j, k, l) = q_sf(j, k, l) - schlieren_alpha(num_fluids)*alpha_last*fd%gm_rho_sf(j, k, &
470 & l)/gm_rho_max(1)
471 else
472 do i = 1, eqn_idx%adv%end - eqn_idx%E
473 q_sf(j, k, l) = q_sf(j, k, l) - schlieren_alpha(i)*q_cons_vf(i + eqn_idx%E)%sf(j, k, &
474 & l)*fd%gm_rho_sf(j, k, l)/gm_rho_max(1)
475 end do
476 end if
477 end do
478 end do
479 end do
480 end if
481
482 ! Up until now, only the inside of the exponential of the numerical Schlieren function has been evaluated and stored. Then,
483 ! to finish the computation, the exponential of the inside quantity is taken.
484 q_sf = exp(q_sf)
485
487
488 !> Deallocation procedures for the module
490
491 ! Deallocating the variable containing the gradient magnitude of the density field provided that the numerical Schlieren
492 ! function was was outputted during the post-process
493 if (schlieren_wrt) deallocate (fd%gm_rho_sf)
494
495 ! Deallocating the variables that might have been used to bookkeep the finite-difference coefficients in the x-, y- and
496 ! z-directions
497 if (allocated(fd%fd_coeff_x)) deallocate (fd%fd_coeff_x)
498 if (allocated(fd%fd_coeff_y)) deallocate (fd%fd_coeff_y)
499 if (allocated(fd%fd_coeff_z)) deallocate (fd%fd_coeff_z)
500
502
503end module m_derived_variables
type(scalar_field), dimension(sys_size), intent(inout) q_cons_vf
integer, intent(in) k
integer, intent(in) j
integer, intent(in) l
Compile-time constant parameters: default values, tolerances, and physical constants.
real(wp), parameter sgm_eps
Segmentation tolerance.
integer, parameter model_eqns_gamma_law
Shared derived types for field data, patch geometry, bubble dynamics, and MPI I/O structures.
Computes derived flow quantities (sound speed, vorticity, Schlieren, etc.) from conservative and prim...
type(fd_context), public fd
Finite-difference state: density gradient magnitude and centered FD coefficients in x-,...
impure subroutine, public s_derive_liutex(q_prim_vf, liutex_mag, liutex_axis)
Compute the Liutex vector and its magnitude based on Xu et al. (2019).
subroutine, public s_derive_specific_heat_ratio(q_sf)
Derive the specific heat ratio from the specific heat ratio function gamma_sf. The latter is stored i...
subroutine, public s_derive_liquid_stiffness(q_sf)
Compute the liquid stiffness from the specific heat ratio function gamma_sf and the liquid stiffness ...
impure subroutine, public s_initialize_derived_variables_module
Computation of parameters, allocation procedures, and/or any other tasks needed to properly setup the...
subroutine, public s_derive_vorticity_component(i, q_prim_vf, q_sf)
Compute the specified component of the vorticity from the primitive variables. From those inputs,...
impure subroutine, public s_derive_numerical_schlieren_function(q_cons_vf, q_sf)
Compute the values of the numerical Schlieren function, which are subsequently stored in the derived ...
subroutine, public s_derive_flux_limiter(i, q_prim_vf, q_sf)
Derive the flux limiter at cell boundary i+1/2. This is an approximation because the velocity used to...
impure subroutine, public s_finalize_derived_variables_module
Deallocation procedures for the module.
subroutine, public s_derive_qm(q_prim_vf, q_sf)
Compute the Q_M criterion from the primitive variables. The Q_M function, which are subsequently stor...
Equations of state in Gamma/Pi form, rho e = Gamma(rho) p + Pi(rho).
real(wp) function, public f_isentrope_pressure(pi_inf, gamma)
Reference pressure of that isentrope. Precomputed per fluid as isentrope_B.
subroutine, public s_compute_speed_of_sound(pres, rho, gamma, pi_inf, adv, c, alpha_rho)
Speed of sound of a thermodynamic state. Enthalpy is not an argument: for a real state H,...
real(wp) function, public f_isentrope_exponent(gamma)
Exponent of the stiffened-gas isentrope p + B = const rho**n. Precomputed per fluid as isentrope_n.
Global parameters for the post-process: domain geometry, equation of state, and output database setti...
type(int_bounds_info) offset_y
real(wp), dimension(:), allocatable y_cc
integer proc_rank
Rank of the local processor.
integer fd_number
Finite-difference half-stencil size: MAX(1, fd_order/2).
type(int_bounds_info) offset_x
integer num_procs
Number of processors.
type(int_bounds_info) offset_z
Basic floating-point utilities: approximate equality, default detection, and coordinate bounds.
logical elemental function, public f_approx_equal(a, b, tol_input)
Check if two floating point numbers of wp are within tolerance.
MPI gather and scatter operations for distributing post-process grid and flow-variable data.
Conservative-to-primitive variable conversion, mixture property evaluation, and pressure computation.
real(wp), dimension(:,:,:), allocatable, public pi_inf_sf
Scalar liquid stiffness function.
real(wp), dimension(:,:,:), allocatable, public gamma_sf
Scalar sp. heat ratio function.
real(wp), dimension(:,:,:), allocatable, public rho_sf
Scalar density function.
Finite-difference state for post_process: density gradient magnitude for numerical Schlieren and cent...
Derived type annexing a scalar field (SF).