Date: 2026-01-30 Purpose: Quick reference and navigation guide for the gasmodels module Module: src/physics/gasmodels
Overview
The gasmodels module provides comprehensive fluid property models for gases, combining thermodynamic and transport properties with various equations of state (EoS). It builds on the gastables module to create complete gas models suitable for:
- Compressible flow analysis
- Chemical equilibrium calculations
- Cryogenic fluid simulations
- Real gas thermodynamics
- Gas mixture modeling
Key features:
- Multiple EoS options: Ideal gas, SRK, Peng-Robinson, Helmholtz free energy
- Gas mixtures with arbitrary composition and remixing capability
- Chemical equilibrium via Gibbs minimization
- Compressible flow utilities: Shock analysis, Prandtl-Meyer expansion, isentropic relations
- Transport properties with the NASA RP-1311 (Gordon & McBride) mixing rules, Eqs. (5.3)-(5.7): Wilke-type Φᵢⱼ with tabulated interaction viscosities where available, and the RP-1311 conductivity correction
- Cryogenic models: specialized Helmholtz EoS for H2 (para/normal/ortho), O2, CH4 and N2
Quick Reference
Key Classes
Key Enums
| Enum | Values | Purpose | Location |
| GasModel | IDGAS, SRK, PR, HELMHOLTZ | Select EoS type | en_GM_GasModel.hpp:17 |
| HelmholtzModel | ParaHydrogen, NormalHydrogen, OrthoHydrogen, Oxygen, Methane, Nitrogen | Select Helmholtz fluid | en_Helmholtz.hpp:17-26 |
Key Files
| File | Purpose |
| cl_Gas.{hpp,cpp} | Main Gas class with all property methods |
| cl_GM_EoS.{hpp,cpp} | Abstract EoS base class |
| cl_GM_EoS_Idgas.{hpp,cpp} | Ideal gas implementation |
| cl_GM_EoS_Cubic.{hpp,cpp} | SRK and PR cubic EoS |
| cl_GM_Helmholtz.{hpp,cpp} | Helmholtz free energy EoS |
| cl_GM_EoS_Hydrogen.{hpp,cpp} | H2 reference EoS (cryogenic) |
| cl_GM_EoS_Methane.{hpp,cpp} | CH4 reference EoS (cryogenic) |
| cl_GM_EoS_Oxygen.{hpp,cpp} | O2 reference EoS (cryogenic) |
| cl_GM_EoS_AlphaFunction.{hpp,cpp} | Alpha functions for cubic EoS temperature correction |
| cl_GM_Statevals.hpp | State variable container ( header only ) |
Common Operations
Create an Ideal Gas
The gas class that provides the fluid model.
Definition cl_Gas.hpp:81
real lambda(const real T, const real p) const
thermal conductivity in W/(m*K)
Definition cl_Gas.cpp:1772
virtual real h(const real T, const real p) const
Definition cl_Gas.cpp:1692
virtual real cv(const real T, const real p) const
Definition cl_Gas.cpp:1627
real rho(const real T, const real p) const
Definition cl_Gas.cpp:1562
virtual real gamma(const real T, const real p) const
Definition cl_Gas.cpp:1643
real mu(const real T, const real p) const
dynamic viscosity in Pa*s
Definition cl_Gas.cpp:1756
virtual real cp(const real T, const real p) const
Definition cl_Gas.cpp:1586
virtual real s(const real T, const real p) const
Definition cl_Gas.cpp:1708
USER GUIDES:
Definition cl_Capacitor.cpp:16
double real
Definition typedefs.hpp:36
Create a Gas Mixture
real T = 400.0, p = 200000.0;
real cp_mix = mixture.cp(T, p);
real mu_mix = mixture.mu(T, p);
Cell is a wrapper around the standard vector.
Definition cl_Cell.hpp:42
Column vector.
Definition cl_BZ_Vector.hpp:41
@ IDGAS
Definition en_GM_GasModel.hpp:19
Use Real Gas (Cubic EoS)
real v = nitrogen.v(T, p);
real Z = p * v / (nitrogen.R(T,p) * T);
real cp = nitrogen.cp(T, p);
real h = nitrogen.h(T, p);
real s = nitrogen.s(T, p);
@ PR
Definition en_GM_GasModel.hpp:21
Use Helmholtz EoS (Cryogenic)
real v = methane.v(T, p);
real h = methane.h(T, p);
real cp = methane.cp(T, p);
if (methane.is_liquid()) {
}
@ Methane
Definition en_Helmholtz.hpp:23
Gas Models (Equations of State)
IDGAS - Ideal Gas
Equation of state:
Use when:
- Pressure < 10 bar
- Temperature well above critical point
- Fast approximate calculations
Properties:
- Thermodynamic: From RefGas polynomials (NASA CEA)
- Transport: From RefGas polynomials with mixture rules
- No departure functions (ideal behavior)
Example:
real v = air.
v(300.0, 101325.0);
real v(const real T, const real p) const
Definition cl_Gas.cpp:1546
SRK - Soave-Redlich-Kwong
Equation of state:
p = R·T/(v-b) - a(T)/(v(v+b))
Use when:
- Moderate pressure (< 100 bar)
- Non-polar or weakly polar molecules
- Good accuracy/speed trade-off
Properties:
- Departure functions for h, s, cp from EoS
- Requires critical point data and acentric factor
Example:
real v = ethane.v(300.0, 2e6);
@ SRK
Definition en_GM_GasModel.hpp:20
PR - Peng-Robinson
Equation of state:
p = R·T/(v-b) - a(T)/(v(v+b) + b(v-b))
Use when:
- High pressure (up to 1000 bar)
- Polar molecules
- Better accuracy than SRK near critical point
Properties:
- More accurate density prediction than SRK
- Especially good for liquids and near-critical fluids
Example:
real v_subcritical = CO2.v(250.0, 5e6);
HELMHOLTZ - Fundamental Equation
Equation of state:
a(ρ, T) = a_ideal(ρ, T) + a_residual(ρ, T)
where a is Helmholtz free energy.
Use when:
- Cryogenic applications (H2, CH4, O2, N2)
- Maximum accuracy required
- Two-phase calculations
- Wide pressure/temperature range
Available fluids:
- HelmholtzModel::NormalHydrogen, ParaHydrogen, OrthoHydrogen - Leachman et al. (2009)
- HelmholtzModel::Methane - Setzmann & Wagner (1991)
- HelmholtzModel::Oxygen - Schmidt & Wagner (1985)
- HelmholtzModel::Nitrogen - Span et al. (2000)
Properties:
- Highly accurate reference equations
- Valid from triple point to high temperatures
- Can handle liquid, vapor, supercritical regions
Example:
real cp_cryo = hydrogen.cp(20.0, 101325.0);
real cp_high = hydrogen.cp(300.0, 100e6);
@ NormalHydrogen
Definition en_Helmholtz.hpp:20
Reference Pressure Convention
The heat splines hold the CEA standard state: the ideal gas at 1 bar. The ideal gas model evaluates them directly and never calls a departure function.
The cubic models add the departure at the requested state and subtract the departure at 1 bar:
cp( T, p ) = cp_spline( T ) + cpdep( T, p ) - cpdep( T, 1 bar )
At 1 bar the two departure terms cancel, so SRK and PR reduce exactly to the ideal gas model at the reference pressure. The subtraction enforces that continuity, and the departure splines are rebuilt whenever the gas model changes. Helmholtz does not use this path because it takes caloric properties from the equation of state.
Two consequences matter:
- At pressures other than 1 bar, the result differs from the true real gas property by the departure at 1 bar. For nitrogen that is about 6 % in cp near 80 K, falling below 0.2 % above 250 K, so it matters for cryogenic work and is negligible at ambient conditions.
- The per-component functions Gas::cp( aIndex, ... ) and Gas::h( aIndex, ... ) apply the same convention, carried inside the indexed departure functions. The finite rate combustion solver depends on this because it pairs those enthalpies with the ideal gas Gibbs energy.
BELFEM has not settled whether to keep this continuity convention or instead store real gas values at 1 bar and drop the subtraction. Both choices are self consistent. The current code combines the ideal gas spline with the reference pressure subtraction. See the note on Gas::realgas_cp in cl_Gas.cpp.
Property Evaluation API
Thermodynamic State
| Function | Returns | Units | Notes |
| p(T, v) | Pressure from T and specific volume | Pa | From EoS |
| v(T, p) | Specific volume from T and pressure | m³/kg | Iterative for real gas |
| T(p, v) | Temperature from p and specific volume | K | Iterative |
| rho(T, p) | Density | kg/m³ | 1/v(T,p) |
Caloric Properties
| Function | Returns | Units | Notes |
| cp(T, p) | Specific heat at constant pressure | J/(kg·K) | From RefGas + departure |
| cv(T, p) | Specific heat at constant volume | J/(kg·K) | From relations or EoS |
| gamma(T, p) | Heat capacity ratio (cp/cv) | - | Dimensionless |
| h(T, p) | Specific enthalpy | J/kg | From RefGas + departure |
| u(T, p) | Specific internal energy | J/kg | h - p·v |
| s(T, p) | Specific entropy | J/(kg·K) | From RefGas + departure |
| c(T, p) | Speed of sound | m/s | From thermodynamic relations |
Transport Properties
| Function | Returns | Units | Notes |
| mu(T, p) | Dynamic viscosity | Pa·s | RP-1311 Eqs. (5.3), (5.5), (5.7) for mixtures |
| lambda(T, p) | Thermal conductivity | W/(m·K) | RP-1311 Eqs. (5.4), (5.6) for mixtures |
| Pr(T, p) | Prandtl number | - | cp·μ/λ |
Thermodynamic Coefficients
| Function | Returns | Units | Notes |
| alpha(T, p) | Thermal expansion coefficient | 1/K | (1/v)(∂v/∂T)_p |
| beta(T, p) | Isochoric stress coefficient | 1/K | (1/p)(∂p/∂T)_v |
| kappa(T, p) | Isothermal compressibility | 1/Pa | -(1/v)(∂v/∂p)_T |
Derivatives
| Function | Returns | Units | Notes |
| dcpdT(T, p) | Temperature derivative of cp | J/(kg·K²) | For sensitivity |
| dsdT(T, p) | Temperature derivative of s | J/(kg·K²) | |
| dsdp(T, p) | Pressure derivative of s | J/(kg·K·Pa) | |
| dhdp(T, p) | Pressure derivative of h | J/(kg·Pa) | For total temperature |
Gas Mixture Operations
Remixing
mixture.remix(new_fractions);
real cp_new = mixture.cp(300.0, 101325.0);
Remix by Mass Fractions
mixture.remix_mass(mass_fractions);
Reset to Initial Composition
Chemical Equilibrium
Compute Equilibrium Composition
Vector<real> initial_guess = {0.3, 0.15, 0.5, 0.02, 0.01, 0.02};
combustion.compute_equilibrium(T, p, equilibrium_fractions);
combustion.remix(equilibrium_fractions);
size_t size() const
return the size of the Cell
Definition cl_Cell.hpp:181
Remix to Equilibrium (In-Place)
combustion.remix_to_equilibrium(T, p,
true,
true);
Gibbs Energy
combustion.Gibbs(T, gibbs);
combustion.dGibbsdT(T, dgibbs_dT);
combustion.Hf(T, formation_enthalpies);
Compressible Flow Utilities
Isentropic Relations
real T1 = 300.0, p1 = 101325.0;
real p2_calculated = air.
isen_p(T1, p1, T2_target);
real isen_p(const real T0, const real p0, const real T1) const
get an isentropic pressure
Definition cl_Gas.cpp:2352
real isen_T(const real T0, const real p0, const real p1) const
get an isentropic temperature
Definition cl_Gas.cpp:2312
Total (Stagnation) Conditions
real p_static = 101325.0;
air.
total(T_static, p_static, velocity, T_total, p_total);
void total(const real T, const real p, const real &u, real &aTt, real &aPt) const
calculate the total state
Definition cl_Gas.cpp:2382
Normal Shock
real T1 = 300.0, p1 = 101325.0, U1 = 500.0;
air.
shock(T1, p1, U1, T2, p2, U2);
void shock(const real T1, const real p1, const real &u1, real &T2, real &p2, real &u2) const
perpendicular shock
Definition cl_Gas.cpp:3469
Oblique Shock
real T1 = 300.0, p1 = 101325.0, U1 = 600.0;
air.
shock(T1, p1, U1, alpha, T2, p2, U2, beta);
const real deg
degree
Definition constants.hpp:55
Prandtl-Meyer Expansion
real T1 = 300.0, p1 = 101325.0, U1 = 500.0;
real prandtl_meyer(const real T1, const real p1, const real &u1, const real &alpha, real &T2, real &p2, real &u2) const
Prandtl-Meyer turn of a supersonic stream around a corner, for a thermally perfect ideal gas.
Definition cl_Gas.cpp:3373
The closed-form perfect-gas angle is a private helper that only seeds the iteration; prandtl_meyer() returns the downstream Mach number.
Advanced Features
Access Component Properties
For gas mixtures, access individual component properties:
real cp_N2 = air.
cp(i, 300.0, 101325.0);
real h_N2 = air.
h(i, 300.0, 101325.0);
real v_N2 = air.
v(i, 300.0, 101325.0);
uint32_t index_t
Definition typedefs.hpp:52
Access Underlying RefGas Objects
real cp_poly = N2_refgas->
cp(300.0);
gastables::RefGas *& component(const index_t aIndex)
expose one component
Definition cl_Gas.hpp:1260
A single chemical species with its caloric and transport properties.
Definition cl_GT_RefGas.hpp:76
real cp(const real T) const
Definition cl_GT_RefGas.cpp:1288
const real & M() const
molar mass in kg/Mol
Definition cl_GT_RefGas.hpp:800
Access GasData
gastables::GasData * data(const index_t aIndex)
expose the data object of a refgas
Definition cl_Gas.cpp:3840
The per species property record: the scalar data that describe a gas but do not depend on the state.
Definition cl_GT_GasData.hpp:58
const real & T_crit() const
Definition cl_GT_GasData.hpp:460
const real & p_crit() const
Definition cl_GT_GasData.hpp:468
const real & acentric() const
Definition cl_GT_GasData.hpp:386
Access Equation of State Directly
real p = eos->
p(300.0, 0.001);
real v = eos->
v(300.0, 101325.0);
real h_dep = eos->
hdep(300.0, 101325.0);
real s_dep = eos->
sdep(300.0, 101325.0);
virtual class for equation of state
Definition cl_GM_EoS.hpp:34
virtual real v(const real T, const real p) const =0
specific volume in m^3/kg
virtual real hdep(const real T, const real p) const
Definition cl_GM_EoS.cpp:189
virtual real p(const real T, const real v) const =0
pressure in Pa
virtual real sdep(const real T, const real p) const
Definition cl_GM_EoS.cpp:207
State Variables Container
#define BELFEM_STATEVAL_M
Definition cl_GM_Statevals.hpp:21
#define BELFEM_STATEVAL_R
Definition cl_GM_Statevals.hpp:22
gasmodels::Statevals & statevals()
expose statevals object
Definition cl_Gas.hpp:1292
The per state property cache of a Gas.
Definition cl_GM_Statevals.hpp:87
const real & get(const index_t aIndex) const
get a value of the state
Definition cl_GM_Statevals.hpp:232
Memory Management
Ownership model:
- Gas object owns its internal RefGas* components
- Gas destructor deletes all RefGas* objects
- Gas owns its EoS* object
Best practice:
{
real cp = air.
cp(300.0, 101325.0);
}
real cp = air->
cp(300.0, 101325.0);
delete air;
For long-lived objects:
std::unique_ptr<Gas> air(
new Gas() );
real cp = air->
cp(300.0, 101325.0);
Transport Properties of the Helmholtz Fluids
Viscosity and thermal conductivity for the cryogenic fluids come from published correlations. Each fluid family has its own source. These correlations are separate from the equation of state and were fitted independently.
| fluid | viscosity | thermal conductivity |
| nitrogen | Lemmon & Jacobsen 2004 | Lemmon & Jacobsen 2004 |
| oxygen | Lemmon & Jacobsen 2004 | Lemmon & Jacobsen 2004 |
| methane | Friend et al. 1989 | Friend et al. 1989 |
| parahydrogen | Muzny et al. 2013 + 2022 erratum | Assael et al. 2011, para tables |
| normal hydrogen | Muzny et al. 2013 + 2022 erratum | Assael et al. 2011, normal tables |
| orthohydrogen | Muzny et al. 2013 + 2022 erratum | Assael et al. 2011, normal tables |
Every fluid now answers both mu() and lambda(). A fluid with no correlation would raise BELFEM_ERROR from the HelmholtzTransport base. It would not return a wrong number. No current fluid takes that path.
Where a correlation does not match the isomer
Hydrogen needs extra explanation because the code cannot express this caveat by itself.
The viscosity correlation of Muzny et al. is for normal hydrogen only. No published correlation exists for the spin isomers, so BELFEM installs it for all three. REFPROP does the same.
The isomers can still return different values. The correlation uses the density from the gas's equation of state, and those equations of state are isomer specific. The correlation itself does not distinguish the isomers.
The thermal conductivity correlation of Assael et al. is different. It has separate coefficient tables for normal and parahydrogen, and BELFEM uses both. Orthohydrogen has no table of its own, so BELFEM uses the normal table for it.
So lambda() is isomer aware where mu() is not.
The near-critical caveat for hydrogen
Hydrogen thermal conductivity has a critical enhancement term. Its magnitude is inversely proportional to the background viscosity.
Assael et al. fitted that term in 2011 against the viscosity correlation that REFPROP carried at the time. That correlation predates Muzny et al. 2013. BELFEM uses the newer viscosity, so the enhancement is evaluated with a background it was not fitted against.
Away from the critical point, this makes no difference. The paper's own verification points reproduce to better than 0.01 %. Close to the critical point, the enhancement becomes a real fraction of the total, and the mismatch shows:
| state | contribution of the enhancement | resulting error in lambda() |
| 35 K, 30 kg/m^3, normal | 20 % of the total | +1.9 % |
| 35 K, 30 kg/m^3, para | 16 % of the total | +5.9 % |
Parahydrogen is the worse of the two for the same reason as above. Its background viscosity is the normal-hydrogen correlation, so the enhancement inherits that error on top.
Within a few kelvin of the critical point, treat hydrogen thermal conductivity as good to a few percent, not to the correlation's nominal uncertainty.
Const Correctness and Thread Safety
Property accessors are const. Calling one evaluates a property. It does not change what the gas is:
void report(
const Gas & aGas )
{
std::cout << aGas.
cp( 300.0, 101325.0 ) << std::endl ;
std::cout << aGas.
mu( 300.0, 101325.0 ) << std::endl ;
}
This rule applies across the module: Gas, EoS, EoS_Idgas, EoS_Cubic, AlphaFunction, Helmholtz, the species equations of state, and the transport models:
| Group | const | Examples |
| Evaluates a property of a fixed mixture | yes | cp, h, s, mu, lambda, alpha, shock, prandtl_meyer, Gibbs |
| Changes what the gas is | no | remix, remix_mass, reset_mixture, remix_to_equilibrium |
| Builds or rebuilds internal tables | no | the spline builders, init_departure_splines, set_reference_point |
The signature tells you which kind of call it is. A routine that only reads properties can take const Gas &. That keeps accidental remixing out of that routine.
What mutable covers
The evaluators are logically const, not bitwise const. They may update internal storage, but they do not change the fluid. That storage has two uses:
- memoization caches: Statevals in Gas, mHelmholtzVals/mHelmholtzBits in Helmholtz, mCubicStatevals in EoS_Cubic. A repeated call at the same state is served from the cache instead of recomputed.
- preallocated scratch: the mixture work matrices, the Cardano work vectors, and the delta^d and tau^t tables of the Helmholtz residual terms. These exist so the hot paths allocate nothing (see CLAUDE.md, "No temporary
`Vector`/`Matrix` in frequently-called member functions").
Those members are not part of the identity of the fluid. They are mutable for that reason. A second call with the same arguments still returns the same number.
Scratch for a non-const path is deliberately not mutable. This includes the RAND equilibrium block, mFormationTable, and the viscosity/conductivity spline build vectors. Leaving them plain keeps the compiler proving that the composition-changing code stays out of the const paths. Prefer adding a mutable only when the compiler demands it.
Paired accessors and returning by value
Accessors that expose an internal handle are paired. Gas::data( index ) returns GasData * for a writable gas. For a const gas, it returns const GasData *.
RefGas follows the same pattern for data() and for its three *_spline() getters. The caller does not choose the overload directly. C++ picks it from the constness of the handle.
Pointers are stored writable. mComponents is a Cell< RefGas * >, not a Cell< const RefGas * >. This keeps the build paths simple.
When a const method only reads a component, it binds a read-only handle at the point of use:
{
/ tComponent->
data()->
M()
+ mEoS->cpdep( aIndex, T, p );
}
real deval(const real aX) const
interpolate first derivative
Definition cl_Spline.hpp:471
const real & M() const
Definition cl_GT_GasData.hpp:378
Spline * heat_spline()
expose heat spline
Definition cl_GT_RefGas.hpp:857
GasData * data()
expose data object
Definition cl_GT_RefGas.hpp:768
unsigned int uint
Definition typedefs.hpp:30
Inside this function, tComponent is read-only. The compiler enforces that local rule, so heat_spline() resolves to the const overload. The guarantee is narrow: it holds inside this function, not across the class.
Scalar accessors return by value. M( T, p ) and R( T, p ) used to return references into the state cache. That made each result a live view. A later remix could change what the reference observed.
That behavior was useful if you expected it. It was a trap if you did not. A real is a register return, so the copy is free. The accessor now returns a value, not a live view.
Not a thread-safety guarantee
Warning: const here means logically const. It does not mean reentrant. Because the const evaluators write the shared cache, two threads must not call them on the same Gas object, even through a const Gas &.
This follows BELFEM's framework-wide policy. It is not a gap in this module. BELFEM parallelizes with MPI and is deliberately not internally thread safe. See doc/coding_philosophy.md.
Readers arriving from modern C++, where const usually implies a safe concurrent read, should note the difference. Give each thread its own Gas object, or serialize the calls.
Common Pitfalls
1. Confusing Molar and Mass Fractions
virtual void remix_mass(const Vector< real > &aMassFractions, bool aRemixHeat=true, bool aRemixTransport=true)
Definition cl_Gas.cpp:658
2. Real Gas Without Critical Data
}
bool has_crit() const
Definition cl_GT_GasData.hpp:325
3. Forgetting Pressure Dependence
real cp_ref = ref_N2->
cp(300.0);
real cp_gas = gas_N2.cp(300.0, 101325.0);
4. Equilibrium on Non-Reactive Mixture
void remix_to_equilibrium(const real T, const real p, const bool aRemixHeat=true, const bool aRemixTransport=true)
remix to equilibrium
Definition cl_Gas.cpp:2129
Further Reading
Module Documentation
Related Modules
External References
Equations of State:
- Soave (1972), "Equilibrium Constants from a Modified Redlich-Kwong Equation of State", Chemical Engineering Science, 27(6):1197-1203
- Peng & Robinson (1976), "A New Two-Constant Equation of State", Industrial & Engineering Chemistry Fundamentals, 15(1):59-64
Helmholtz Models:
- Leachman et al. (2009), "Fundamental Equations of State for Parahydrogen, Normal Hydrogen, and Orthohydrogen", J. Phys. Chem. Ref. Data, 38(3):721-748
- Setzmann & Wagner (1991), "A New Equation of State and Tables of Thermodynamic Properties for Methane", J. Phys. Chem. Ref. Data, 20(6):1061-1155
- Schmidt & Wagner (1985), "A New Form of the Equation of State for Pure Substances", Fluid Phase Equilibria, 19(3):175-200
Mixture Rules:
- Gordon & McBride (1994), "Computer Program for Calculation of Complex Chemical Equilibrium Compositions", NASA RP-1311, Eqs. (5.3)-(5.7)
- Wilke (1950), "A Viscosity Equation for Gas Mixtures", J. Chem. Phys., 18:517-519
Last Updated: 2026-08-25 Maintainer: BELFEM development team