JWL equation of state: single-material and multi-fluid mixture implementation#1586
JWL equation of state: single-material and multi-fluid mixture implementation#1586fahnab666 wants to merge 9 commits into
Conversation
Add Jones-Wilkins-Lee equation of state with four mixture closures (isobaric, Kuhl-Khasainov, p-T equilibrium, Rocflu blend) via jwl_mix_type. New shared m_jwl module, per-fluid eos selector, GPU-resident parameter arrays, example cases, and inverse-function test suite.
Without this, the device copy of jwl_mix_type was uninitialized; non-zero mixture closures (Kuhl, p-T equil, Rocflu) silently executed the wrong branch on GPU.
… rocflu fix - s_initialize_jwl_module: add f_is_default sentinel checks on all JWL parameters, positivity checks on R1/R2/omega/rho0, n_jwl>1 guard; upgrade cv check with f_is_default; use local use statements (m_mpi_common, m_helper_basic) instead of module-level import - s_jwl_sound_speed_squared: refactor to reuse s_jwl_pcold / s_jwl_dpcold_drho helpers instead of inlining the same algebra - s_jwl_ptequil_pressure_er/energy_pr: add 1e-12 early-exit to both bisection loops; add bracket sign check in energy_pr fallback - s_jwl_rocflu_pressure_er/energy_pr: widen high-Y guard to 1-1e-4 (symmetric with low-Y guard) to close the 0.99 discontinuity - m_variables_conversion: remove dead s_mpi_allreduce_integer_sum import - tests: add golden files for jwl_single_material_shocktube, 1D/2D jwl_mixture_test
73700a5 to
d83068f
Compare
…s (5-eq model) Wire the JWL EOS into the solver hot path for the five-equation model (model_eqns = 2, Allaire et al. JCP 2002). All changes are guarded by jwl_idx > 0 and model_eqns == model_eqns_5eq so non-JWL cases are unaffected. m_variables_conversion: - s_convert_conservative_to_primitive_variables: after s_compute_pressure gives the stiffened-gas pressure, override it with s_jwl_mix_pressure_er using Y = alpha_rho(jwl_idx)/rho and alpha = alpha(jwl_idx). Without this, the solver uses the wrong EOS to recover pressure from conserved variables, giving thermodynamically inconsistent primitive fields. - s_convert_primitive_to_conservative_variables: add JWL branch that computes E = rho*e_mix(rho,p,Y,alpha) + 0.5*rho|u|^2 + qv via s_jwl_mix_energy_pr instead of the stiffened-gas E = gamma*p + pi_inf formula, keeping prim->cons consistent with cons->prim. - s_compute_speed_of_sound: add JWL branch using s_jwl_mixture_sound_speed_squared (frozen mass-weighted rule). Accepts an optional alpha_rho_j argument for the correct Y_j = alpha_rho_j/rho; falls back to the rho0 proxy alpha_j*rho0/rho when not supplied (e.g. avg-state calls). - Export s_jwl_mixture_sound_speed_squared via the module public list. m_riemann_solver_hll / m_riemann_solver_hllc: - Add use m_jwl to both modules. - In every E_L/E_R reconstruction block: when jwl_idx > 0 and 5-eq, compute e_L/e_R from pressure via s_jwl_mix_energy_pr and form E = rho*e + 0.5*rho|u|^2 instead of the stiffened-gas gamma*p + pi_inf formula. This keeps the Riemann wave-speed estimates thermodynamically consistent with the JWL EOS for both HLL and HLLC solvers. - In m_riemann_solver_hll: pass alpha_rho_j to both s_compute_speed_of_sound calls so the sound speed uses the actual phasic partial density for Y_j rather than the rho0 proxy.
Convert the 1D JWL CJ products example from the slow six-equation pTg relaxation setup to a cheap five-equation JWL mixture smoke case. The case now uses fixed timestepping, HLL, periodic boundaries, and an 8-step stop so it runs in seconds instead of spending minutes in relaxation/adaptive CFL work. Finish the JWL sound-speed and energy consistency wiring by passing actual JWL partial densities through the HLL sound-speed calls, using JWL inverse energy during primitive/flux conversion, and adding guards for invalid JWL pressure, energy, and RK energy updates. Add the generated 52A7542F golden test files for the updated jwl_cj_products case. Validation before push: ./mfc.sh build -j 8, ./mfc.sh test --generate --no-build -f 52A7542F -t 52A7542F -j 1, and the commit-hook precheck all passed.
0998f4b to
cdb34a7
Compare
… case to 5-eq s_compute_speed_of_sound used 'present(alpha_rho_j) .and. alpha_rho_j == alpha_rho_j' in a single expression. Fortran does not guarantee short-circuit evaluation of .and., so gfortran evaluated alpha_rho_j (null pointer) even when it was absent, causing a SIGSEGV in every HLLC test. Fix: separate into a nested if-block, compute the rho0-proxy Y_j first, then conditionally override when alpha_rho_j is present and not NaN. Also converts examples/1D_jwl_cj_products from the expensive 6-equation pTg relaxation model (model_eqns=3, relax_model=6) to the 5-equation model (model_eqns=2) with the isobaric JWL closure, restoring physical CJ detonation parameters (D=6900 m/s, CR=1.80) that keep the initial pressure (34.5 GPa) above the JWL cold curve (7.1 GPa). All four JWL tests now pass: 52A7542F, E3460991, DB95E4F7, 25B9827F.
… guard LF solver (riemann_solver=5) was missing the JWL E_L/E_R reconstruction block present in HLL and HLLC, producing completely wrong energy fluxes for any JWL case with the Lax-Friedrichs solver. Add the s_jwl_mix_energy_pr block and alpha_rho_j argument to both sound-speed calls, matching the HLL pattern. Add use m_jwl to the module. All four HLLC model branches were calling s_compute_speed_of_sound without the optional alpha_rho_j argument. This caused the JWL mixture sound speed to use the rho0-proxy mass fraction Y_j = alpha_j*rho0/rho instead of the correct Y_j = alpha_rho_j/rho, giving wrong wave-speed estimates for all HLLC JWL runs. Fix all 12 call sites; the 5eq and bubbles sections use qL/R_prim_rsx_vf(*,max(1,jwl_idx)) directly; the 4eq section uses alpha_rho_L/R(max(1,jwl_idx)) which is already populated there. Add a runtime guard in s_initialize_jwl_module that aborts if fluid_pp%eos=2 is used with model_eqns != 2. JWL is only wired into the five-equation prim/cons conversion and Riemann solver paths; using it with any other model_eqns silently falls through to the stiffened-gas path. Regenerate tests/DB95E4F7 golden files (1D jwl_mixture_test, HLLC) since the corrected alpha_rho_j changes the numerical output.
…construction The JWL mixture pressure inversion was applied only in the field-conversion path, so probe output and pre_process fell back to the stiffened-gas formula and reported the wrong pressure. Move the inversion into s_compute_pressure behind new optional jwl_Y/jwl_alpha arguments so every caller shares one correct code path. Also fix two numerical bugs: s_jwl_rocflu_sound_speed_squared omitted the omega-density term in its derivative, giving an incorrect sound speed in the blended region; and the HLL and LF JWL energy reconstruction double-counted qv. Regenerate the four JWL golden files to match the corrected output.
c7db505 to
87a0281
Compare
Maintainer review — full issue listThanks for this. The physics is genuinely thoughtful — four mixture closures, exact inverses for the linear ones, fail-fast parameter validation in init, and an honest validation tracker that separates what's verified from what isn't. That part I'm not asking you to change. The engineering, however, isn't yet at MFC standards. Below is the complete list of what needs to be addressed before this can merge, grouped by severity, with the reason each one matters. Numbering is for ease of reference in replies. Blocking — correctness & maintainability1. Six near-identical copies of the JWL energy-reconstruction block. 2. HLLC and HLL/LF feed the sound-speed routine different inputs for the same physics. 3. alpha_rho_j = q_prim_vf(max(1, jwl_idx))%sf(j, k, l)Why it matters: when no JWL fluid is present ( 4. Runtime branch added to the hottest kernel in every build. 5. Per-face 60-iteration bisection with transcendentals, on GPU. 6. Silent NaN/floor squashing masks divergence. if (pres /= pres) pres = sgm_eps
if (pres < sgm_eps) pres = sgm_epsand if (c2 /= c2) c2 = jwl_omegas(jwl_idx)*max(pres, 1._wp)/max(rho, sgm_eps)
c2 = max(c2, jwl_omegas(jwl_idx)*max(pres, 1._wp)/max(rho, sgm_eps))Why it matters: a diverged bisection or a NaN pressure gets converted to a 1e-16 floor and the solver keeps running with garbage instead of aborting — a classic silent-failure mode that makes bugs nearly impossible to localize. Additionally Blocking — validation & test integration7. The unit test exercises a Python re-implementation, not the compiled Fortran. 8. Golden cases not wired into the test registry, generated on a dirty tree. 9. Promote validation tiers only with reports. The tracker lists Kamm/Tarver/PBX as exploratory and TNT-air as stress-only. Non-blocking — quality & style10. Hardcoded air defaults as non-sentinel values, triple-duplicated. fluid_pp(i)%jwl_air_e0 = 2.5575e5_wp
fluid_pp(i)%jwl_air_rho0 = 1._wp
fluid_pp(i)%jwl_air_gamma = 0.4_wpWhy it matters: every neighboring field defaults to 11. Dead/over-broad public API. 12. rj = max(Y_s*rho_s/a_lo, sgm_eps); ra = max((1._wp - Y_s)*rho_s/(1._wp - a_lo), sgm_eps); V = rho0/rjWhy it matters: MFC is one-statement-per-line throughout; this hurts readability and makes 13. Unnamed magic thresholds. 14. Possibly-negative denominator flooring in the Kuhl closure. 15. Energy floor ignores the cold-curve offset. 16. LLM-style verbosity vs MFC norms. 17. Leftover dev cruft in SummaryThe closures are the strong part — leave them. The asks, in priority order: de-dup the six energy blocks (1), unify the sound-speed input path (2, 3), gate the JWL branch at compile time (4), justify-or-host-gate the bisection (5), replace silent floors with assertions (6), and fix the test/golden story (7, 8). The rest are cleanup. Happy to discuss any of these. |
| else | ||
| E_L = gamma_L*pres_L + pi_inf_L + 5.e-1*rho_L*vel_L_rms + qv_L | ||
| E_R = gamma_R*pres_R + pi_inf_R + 5.e-1*rho_R*vel_R_rms + qv_R | ||
| if (jwl_idx > 0 .and. model_eqns == model_eqns_5eq) then |
There was a problem hiding this comment.
You should change the level of this loop back a layer to make it consistent with the surrounding code. Make the previous line an else if and leave the previous line at the same level as the previous loop.
| else | ||
| E_L = gamma_L*pres_L + pi_inf_L + 5.e-1*rho_L*vel_L_rms + qv_L | ||
| E_R = gamma_R*pres_R + pi_inf_R + 5.e-1*rho_R*vel_R_rms + qv_R | ||
| if (jwl_idx > 0 .and. model_eqns == model_eqns_5eq) then |
There was a problem hiding this comment.
Same issue here. Don't add unnecessary if-tree nesting if you can prevent it
|
I unsure why you created the file Also, for your tests added, you add 3 1D cases and a 2D case. It is not inherently bad to add them, but a feature like this really requires a 3D example to be added with comparison to some sort of example. I know that I have seen comparisons of your code to published examples, and those comparisons should make it into the readme if you are going to provide a readme. The only concern I have about the fortran code outside of the minor comments that I left are with the size of the jwl module. I need to actually take a look at it in an IDE where I have access to |
JWL EOS PR Description and Capability Tracker
Use this as the copy-paste source for the MFC feature PR. It is written to keep
the five-equation JWL work review-ready while clearly separating validated
capabilities from stress tests and follow-up work.
PR Description
Implements the Jones-Wilkins-Lee (JWL) equation of state in MFC for
detonation-products modeling and five-equation multi-fluid JWL/ideal-gas
mixtures.
This PR adds:
fluid_pp(i)%eos.Closes #TBD.
Type of Change
Implemented Capabilities
fluid_pp(i)%eos = 1selects stiffened gas;fluid_pp(i)%eos = 2selects JWL.(rho, p)for JWL reconstruction and initialization.alpha_rho_L(:)andalpha_rho_R(:)before JWL energy reconstruction.JWL EOS Form
The pressure is modeled as a Mie-Gruneisen EOS with a two-exponential JWL cold
curve:
where
The sound speed follows the Mie-Gruneisen/Rocflu-style form used by the
reference solver:
This avoids explicit temperature evaluation in the hot EOS path.
EOS Selection
Each material selects its EOS with
fluid_pp(i)%eos.fluid_pp(i)%jwl_A,jwl_B,jwl_R1,jwl_R2,jwl_omega,jwl_rho0, and mixture parameters when applicableBelow-cold-curve states require careful interpretation. If a requested state
has
p < p_cold(rho), exact round-trip identity is not generally expected oncethe implementation applies the non-negative-energy or temperature floor. These
states should be described as cold-floor-sensitive rather than as ordinary
positive-temperature JWL states.
Validation Evidence Tracker
(rho, p) -> e -> p'residualsReviewer-Facing Summary
The reviewable feature is the five-equation JWL foundation: single-material JWL,
JWL/ideal-gas five-equation mixtures, EOS conversion routines, and JWL-aware
HLL/HLLC reconstruction. The strongest validation stack is exact-reference JWL
Riemann testing, exact two-material JWL/air convergence, smooth EOS
code-verification, and 2D quasi-1D invariance.
The six-equation JWL/air model is intentionally not claimed as complete in this
PR. Existing six-equation results are useful diagnostics, but longer final-time
comparisons still fail and should remain future work.
PR Checklist
#TBDwith the issue number before opening the PR.jwl_contact_blendparameter should be removed before review.@coderabbitai reviewfor incremental review.@coderabbitai full reviewfor full review from scratch./reviewfor Qodo review./improvefor Qodo suggestions.@claude full reviewor labelclaude-full-reviewfor Claude review.Known Limitations and Follow-Up
jwl_contact_blendparameter if it remains unused insolver logic.
exploratory/supporting evidence to validation evidence.
Kingery-Bulmash blast validation.
PR foundation.