Repository navigation
EOS algebra is duplicated across call sites; needs a single source of truth #1708
Description
Summary
The stiffened-gas EOS algebra has canonical definitions in src/common/m_variables_conversion.fpp — s_compute_pressure, s_compute_internal_energy, s_compute_speed_of_sound — but several call sites open-code the same expressions instead of calling them. Two have already drifted into real bugs (#1706, #1707). This issue tracks making the algebra DRY, which is prerequisite groundwork for the multi-EOS interface in #1638: a second EOS cannot be introduced safely while the first one has several independent definitions.
Pressure inversion
Canonical, m_variables_conversion.fpp:71:
pres = (energy - dyn_p - pi_inf - qv)/gammaOpen-coded copies:
| Site | Expression | Status |
|---|---|---|
simulation/m_pressure_relaxation.fpp:311 |
(E - dyn_pres - qv_mix - pi_inf)/gamma |
correct; operand order differs |
simulation/m_data_output.fpp:1558 |
((E - KE)/(1 - alf) - pi_inf - qv)/gamma |
correct; duplicates the bubble branch |
simulation/m_data_output.fpp:1621 |
((E - KE)/(1 - alf) - pi_inf - qv)/gamma |
correct; duplicates the bubble branch |
simulation/m_bubbles_EL.fpp:374 |
(E - dynP - pi_inf)/gamma |
wrong — omits qv (#1706) |
Specific total enthalpy at sound-speed call sites
s_compute_speed_of_sound requires an H that includes qv (it subtracts qv/rho internally). The 27 call sites split into two conventions:
- Solver paths derive it from conserved energy —
H_L = (E_L + pres_L)/rho_L— which is correct and cannot drift. - Four diagnostic sites open-code the closed form instead.
post_process/m_data_output.fpp:1289includesqvand is correct;simulation/m_data_output.fpp:1297,1379,1438omit it and are wrong (bug: simulation probe sound speed omits qv from enthalpy, disagreeing with post-process #1707).
A fifth site, s_compute_cson_from_pinf in simulation/m_bubbles_EL.fpp:844-846,
reconstructs the energy rather than reading it:
E = gamma*pinf + pi_inf + 0.5_wp*rhol*dot_product(vel, vel) ! no qv
H = (E + pinf)/rhol
cson = sqrt((H - 0.5_wp*dot_product(vel, vel))/gamma) ! no -qv/rhoThis one is correct, and must not be "fixed." It omits qv from the
reconstructed E and from the subtraction, and the two omissions cancel
exactly, leaving c^2 = ((gamma+1)*p + pi_inf)/(rho*gamma) — the same result the
canonical routine produces. Adding qv to only one of the two halves would
introduce a bug where none exists today.
It is listed here because it is a fifth independent copy of the algebra whose
correctness depends on a coincidence between two separate omissions. That is
precisely the fragility this issue is about: the next person to touch it has to
rederive the cancellation to know it is safe.
Why this matters beyond the two bugs
Both defects are the same failure: an expression was copied, the canonical version later gained a term, and the copy did not. The golden suite does not catch either one, because qv = 0 in every case it covers.
Adding Mie-Gruneisen or JWL under #1638 multiplies this. Each open-coded site is a place a second EOS silently does not reach — the selector says mie_gruneisen, and m_bubbles_EL keeps computing a stiffened-gas pressure. Deduplicating first turns "add a backend" into a change with a bounded blast radius.
Scope
Route every open-coded site through the canonical routines. Deliberately not in scope here: moving the routines into a new module, or adding backend dispatch. Those are the next steps in #1638; this issue is only about there being one definition of each operation.
Note that folding the sites in changes floating-point operand order in places (- qv_mix - pi_inf vs - pi_inf - qv), so results move in the last bits. The golden tolerance is 1e-12 for double precision (toolchain/mfc/test/case.py:338), roughly four orders of magnitude above that, so no goldens need regenerating — but the two bug fixes above will legitimately move qv /= 0 results and should be reviewed on their own merits.
Activity
sbryngelson commentedon Aug 8, 2026
Adding a fifth site to the enumeration above, found while checking whether the initial Lagrange bubble pressure in #1706 was really meant to be the ordinary liquid pressure.
s_compute_cson_from_pinf(simulation/m_bubbles_EL.fpp:844-846) reconstructs the energy from the driving pressure instead of reading it:My first read was that this is another instance of #1707 — the reconstructed
Eis missing theqvterm thatE = gamma*p + pi_inf + qv + rho*KEcarries. It is not. The subtraction is missingqv/rhoas well, and the two cancel:Same answer. It is correct and should not be "fixed." Adding
qvto the reconstructedEwithout also restoring the- qv/rho— the obvious patch if someone pattern-matches this against #1707 — would introduce a bug where none exists.I am flagging it precisely because it is a trap. Its correctness rests on a coincidence between two independent omissions, several lines apart, with nothing saying so. Anyone auditing the sound-speed sites after #1707 lands will find it, see a missing
qv, and be one keystroke from breaking it.That is the argument for this issue in miniature. Counting the open-coded copies across both operations:
Nine hand-written copies of two expressions, four of them wrong and one right for a reason no reader can see locally.
When the deduplication happens, this site should route through the shared routine with the true enthalpy and let the canonical subtraction do its job, replacing the coincidence with something verifiable on sight.
sbryngelson commentedon Aug 26, 2026
Audit of where the EOS actually lives, surveyed by parameter array (
gammas,pi_infs,qvs,gs_min,ps_inf,cvs,qvps). Searching for a guessed expression shape missed whole subsystems twice, so this starts from the parameters and assigns every file that consumes one.It is ten expression families, not two: sound speed, mixture coefficients, energy, pressure inversion, enthalpy, bulk modulus, temperature inversion, entropy, caloric relations, and the Tait-named forms (which turn out to be stiffened gas under different names, not a separate EOS).
#1762 closes three of them — mixture coefficients, energy, sound speed — across the five Riemann solvers, CBC, the viscous fluxes and the acoustic source. Zero sound-speed computations remain outside the operator.
Still open: 13 files, 96 parameter references.
m_phase_changecvs/qvpsm_igrm_pressure_relaxationm_rhs,m_hypoelasticm_bubbles_EE,m_qbmmm_assign_variables,m_data_output)m_ibmm_derived_variables)m_sim_helpersm_reactive_burn,m_start_upm_phase_changealone is a comparable body of EOS algebra to everything #1762 changed.One constraint found along the way that is easy to miss:
advdoes not mean the same thing in every model. Underbubbles_eulerwithnum_fluids == 1,eqn_idx%alf == eqn_idx%adv%end, so the sole advection slot is the void fraction and the mixture rule does not apply — the coefficients are the liquid's. Any operator takingadvhas to go through something that knows this.sbryngelson commentedon Aug 28, 2026
Audit against the current
fix/speed-of-sound-from-statebranch: every site listed here is now routedthrough the canonical operators.
m_pressure_relaxationopen-coded pressuref_pressure(...)at:220m_data_outputbubble-branch pressure (×2)s_compute_pressure(...), six call sitesm_bubbles_EL:374— omittedqv(#1706)f_pressure(..., gamma, pi_inf, qv)— theqvterm is presentm_data_outputenthalpy sites (#1707)H = ...remainss_compute_cson_from_pinf— must not changeqvfrom both the reconstructedEand the subtraction, so the cancellation standsThat last one is worth calling out:
m_bubbles_EL.fppwas modified on this branch, so the routine wasedited around deliberately rather than left alone by luck.
Since this issue was filed, the same treatment has been extended past its original list:
m_igr's CFL routine was the last place writing the stiffened-gas pressure and sound speed inline;it now uses
f_pressureandf_bulk_modulus.n_tait*(pres + B_tait), which isf_bulk_moduluswritten out.
f_pressure_on_isentrope.s_compute_mixture_coefficients_dt, mirrorings_compute_mixture_coefficientsbranch for branch.p + B = (n-1) cv rho Twas written out separately inm_phase_changeandm_reactive_burn; both now callf_sg_thermal.pi_infandqvterms; it now usesf_phase_internal_energy(post_process gas internal energy diagnostic drops pi_inf and qv, and hard-codes fluid 2 #1781).Your tolerance analysis was right and mine was wrong. This issue predicted that folding the sites in
moves results only in the last bits, and that the
1e-12golden tolerance is four orders of magnitudeabove that, so nothing needs regenerating. I predicted golden movement twice while doing this work - once
for the IGR substitution and once for QBMM - and both times every golden held. Reading this issue's
analysis first would have saved both wrong calls.
Still deliberately outside the scope:
m_phase_change's caloric relations and Newton solve,m_pressure_relaxation's isentrope inversion, and a few single-fluidgammas(1)diagnosticshortcuts. Those need a thermodynamically complete EOS interface rather than deduplication.
sbryngelson commentedon Sep 2, 2026
Fixed by #1762, merged as c9c8b0f. This issue was listed in that PR's
Closesline but GitHub only auto-closes the first reference in a comma-separated list, so it stayed open; closing manually.