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