Maintainer triage (June 29, 2026)
- Status: Verified bug against the current
master source in this fork.
- Severity: Low.
- Area labels: area:phases.
- Tackle batch: P6 - low-risk cleanup defects.
The source review confirmed that the cited code path and failure mode are still present. The original audit details are preserved below for reproduction notes and suggested fixes.
Original audit details
Part of the model-correctness audit — see #17.
Severity: low | Category: units | Location: PharmaPy/Phases.py lines 795-804
What's wrong
VaporPhase.getDensity computes densGas = pres_gas/(8.314*temp_gas) and is declared with default basis='mole'. With pressure in Pa and R=8.314 J/mol/K, this yields mol/m3. Every other molar density in the codebase (getDensityPure: rhoMass/mw with mw in kg/kmol, returning kmol/m3 == mol/L, see ThermoModule.py line 290; conc_to_conc comments) uses kmol/m**3 (mol/L) for the 'mole' basis. This vapor routine therefore differs by a factor of 1000 from the liquid/solid molar-density basis, and it ignores the 'basis' argument entirely (never returns a mass density). It also reads self.pres_gas, which VaporPhase never sets.
Why it's incorrect
Ideal-gas molar density n/V = P/(R T) with SI units gives mol/m3. The library convention for molar density is kmol/m3 (= mol/L), as established by rhoMole = rhoMass[kg/m3]/mw[kg/kmol]. Mixing a mol/m3 vapor density into any expression expecting the library's kmol/m3 convention introduces a 1000x error; and a basis='mass' caller silently receives a molar density.
Suggested regression test
Search for callers passing a VaporPhase molar density into a balance expecting mol/L (kmol/m3); compare units. To make it consistent, return P/(R T)/1000 for kmol/m3 on the 'mole' basis and multiply by mw_av for the 'mass' basis (kg/m3).
Verification: 2/2 adversarial reviewers confirmed (refuted: 0).
Maintainer triage (June 29, 2026)
mastersource in this fork.The source review confirmed that the cited code path and failure mode are still present. The original audit details are preserved below for reproduction notes and suggested fixes.
Original audit details
Part of the model-correctness audit — see #17.
Severity: low | Category: units | Location:
PharmaPy/Phases.pylines 795-804What's wrong
VaporPhase.getDensity computes densGas = pres_gas/(8.314*temp_gas) and is declared with default basis='mole'. With pressure in Pa and R=8.314 J/mol/K, this yields mol/m3. Every other molar density in the codebase (getDensityPure: rhoMass/mw with mw in kg/kmol, returning kmol/m3 == mol/L, see ThermoModule.py line 290; conc_to_conc comments) uses kmol/m**3 (mol/L) for the 'mole' basis. This vapor routine therefore differs by a factor of 1000 from the liquid/solid molar-density basis, and it ignores the 'basis' argument entirely (never returns a mass density). It also reads self.pres_gas, which VaporPhase never sets.
Why it's incorrect
Ideal-gas molar density n/V = P/(R T) with SI units gives mol/m3. The library convention for molar density is kmol/m3 (= mol/L), as established by rhoMole = rhoMass[kg/m3]/mw[kg/kmol]. Mixing a mol/m3 vapor density into any expression expecting the library's kmol/m3 convention introduces a 1000x error; and a basis='mass' caller silently receives a molar density.
Suggested regression test
Search for callers passing a VaporPhase molar density into a balance expecting mol/L (kmol/m3); compare units. To make it consistent, return P/(R T)/1000 for kmol/m3 on the 'mole' basis and multiply by mw_av for the 'mass' basis (kg/m3).
Verification: 2/2 adversarial reviewers confirmed (refuted: 0).