Fluid

Working fluid interface and equation of state implementations.

Fluid is the interface for computing thermodynamic properties of a working fluid, so that flow fields can be manipulated independently of the underlying equation of state. The abstraction separates thermodynamic relations from the flow solver and is the type other modules and downstream code accept; extending to a new real-gas or tabulated model is a matter of subclassing it.

Two implementations are provided: PerfectFluid, for ideal gases with constant specific heats, and RealFluid, a thermodynamically consistent real gas built from a fitted entropy surface. Coefficients for the latter are produced offline by ember.realgas_fit.

A fluid instance is immutable and only stores intrinsic fluid properties that never change, such as specific heats for a perfect gas, or the fluid species for a real fluid. These must passed into the constructor on initialisation. Storage of the actual flow solution is the responsibility of a Block.

Get and set methods

The basic state variables are density and internal energy, \((\rho, u)\), because these are the most natural in a conservative computational fluid dynamics solver. An equation of state must provide two types of methods: get_? and set_?_?.

  • set_x_y(x,y): Take thermodynamic properties \((x, y)\) and return \((\rho, u)\).

  • get_z(rho, u, out=None): Take \((\rho, u)\) and return thermodynamic property \(z\).

All methods support both scalar and array inputs, where the inputs must be broadcastable against each other. The output will have the broadcasted shape. Constructor inputs are cast to single-precision floats, and outputs will remain single-precision if all inputs are single-precision. Supplying an out keyword argument to get_? methods allows the output to be written into a pre-allocated array, following NumPy conventions, which may improve performance by avoiding temporary array allocations.

Datum state

Only changes in internal energy, enthalpy, and entropy are physically meaningful. Therefore, we have freedom to set the physical state at which these properties are zero, to improve numerics and reduce precision errors due to subtracting two large floats. We define a thermodynamic datum \((p_\mathrm{dtm}, T_\mathrm{dtm})\) where \(u = s = 0\) simultaneously. Enthalpy at the datum is not zero because of the pressure term in \(h = u + p/\rho\).

It is possible to shift the datum state of a fluid instance using change_datum, which returns a new instance with the same properties but shifted datum. The current datum is accessible via P_dtm and T_dtm attributes.

Reference scales

The constructors for fluid instances take optional reference scales for non-dimensionalisation, which default to unity such that all quantities are in SI units. If reference scales are provided, all inputs and outputs are taken as non-dimensional. The advantage of setting reference scales is improved numerical precision when working with non-dimensional quantities all of order unity.

The user specifies:

  • \(\rho_\mathrm{ref}\,\): density [kg/m3], rho_ref

  • \(V_\mathrm{ref}\,\): velocity [m/s], V_ref

  • \(R_\mathrm{ref}\,\): gas constant [J/kg/K], Rgas_ref

and the class forms the following derived reference scales:

  • \(p_\mathrm{ref} = \rho_\mathrm{ref} V_\mathrm{ref}^2\,\): dynamic pressure [Pa], P_ref

  • \(u_\mathrm{ref} = V_\mathrm{ref}^2\,\): specific energy [J/kg], u_ref

  • \(T_\mathrm{ref} = V_\mathrm{ref}^2 / R_\mathrm{ref}\,\): temperature [K], T_ref

  • \((\rho V)_\mathrm{ref} = \rho_\mathrm{ref} V_\mathrm{ref}\,\): mass flux [kg/m2/s], rhoV_ref

Equations of state are unchanged when all quantities are scaled consistently. For example, taking the ideal gas law \(p = \rho R T\) and dividing through by the reference pressure \(\rho_\mathrm{ref} V_\mathrm{ref}^2\) gives

\[\frac{p}{\rho_\mathrm{ref} V_\mathrm{ref}^2} = \frac{\rho}{\rho_\mathrm{ref}} \frac{R}{R_\mathrm{ref}} \frac{T}{V_\mathrm{ref}^2 / R_\mathrm{ref}} = \frac{\rho}{\rho_\mathrm{ref}} \frac{R}{R_\mathrm{ref}} \frac{T}{T_\mathrm{ref}}\]

Transport properties such as viscosity and thermal conductivity are an exception to this scaling, and would require an additional reference length to make fully non-dimensional. So when references are provided, transport properties have dimensions of meters: viscosity is divided by \(\rho_\mathrm{ref} V_\mathrm{ref}\) and conductivity by \(\rho_\mathrm{ref} V_\mathrm{ref} R_\mathrm{ref}\), which are the two scalings that leave the Prandtl number \(\mu c_p / \kappa\) dimensionless. Scaling the transport properties on their own, to sweep Reynolds number at a fixed flow field, is what Fluid.change_visc() is for.

We can get a new instance with different reference scales using the Fluid.change_ref() method.

class fluid.Fluid(rho_ref=1.0, V_ref=1.0, Rgas_ref=1.0)[source]

The equation-of-state interface: density and internal energy to and from other thermodynamic properties.

PerfectFluid and RealFluid implement it; the rest of the codebase and downstream code accept a Fluid and never test which. See the module documentation above for the \((\rho, u)\) convention, the datum state and the reference scales.

Every get_* method takes (rho, u, out=None) — density and internal energy, broadcastable against each other — and returns one array of the broadcast shape, optionally written into out (the NumPy out= convention). Every set_x_y method takes the two named properties, likewise broadcastable, and returns (rho, u). Outputs are single precision when the inputs are. With non-unity reference scales all quantities in and out are non-dimensional; transport properties are then only quasi-dimensional (see get_mu()).

Property inputs must be physically valid — pressures, temperatures and densities positive, every value finite. This layer does not check; ember.block.Block.set_P_T() and its siblings are the validated entry points.

A new equation of state is a subclass implementing the abstract methods below; from_dict() then reconstructs it by class name.

Thermodynamic state

get_P(rho, u[, out])

Static pressure.

get_T(rho, u[, out])

Static temperature.

get_h(rho, u[, out])

Specific enthalpy, relative to the datum (see Datum state).

get_s(rho, u[, out])

Specific entropy, relative to the datum (see Datum state).

get_a(rho, u[, out])

Speed of sound.

get_cp(rho, u[, out])

Specific heat at constant pressure.

get_cv(rho, u[, out])

Specific heat at constant volume.

get_gamma(rho, u[, out])

Ratio of specific heats, \(c_p / c_v\).

get_Rgas(rho, u[, out])

Specific gas constant.

Setters (return (rho, u))

set_P_T(P, T)

Density and internal energy from pressure and temperature.

set_P_h(P, h)

Density and internal energy from pressure and specific enthalpy.

set_P_s(P, s)

Density and internal energy from pressure and specific entropy.

set_P_rho(P, rho)

Density and internal energy from pressure and density.

set_h_s(h, s)

Density and internal energy from specific enthalpy and entropy.

set_rho_s(rho, s)

Density and internal energy from density and specific entropy.

set_T_s(T, s)

Density and internal energy from temperature and specific entropy.

set_T_rho(T, rho)

Density and internal energy from temperature and density.

Partial derivatives

get_dhdP_rho(rho, u[, out])

Derivative of enthalpy with respect to pressure at constant density.

get_dhdrho_P(rho, u[, out])

Derivative of enthalpy with respect to density at constant pressure.

get_dsdP_rho(rho, u[, out])

Derivative of entropy with respect to pressure at constant density.

get_dsdrho_P(rho, u[, out])

Derivative of entropy with respect to density at constant pressure.

get_dudP_rho(rho, u[, out])

Derivative of internal energy with respect to pressure at constant density.

get_dudrho_P(rho, u[, out])

Derivative of internal energy with respect to density at constant pressure.

Transport

get_mu(rho, u[, out])

Quasi-dimensional dynamic viscosity, mu / (rho_ref * V_ref) [m].

get_kappa(rho, u[, out])

Quasi-dimensional thermal conductivity, kappa / (rho_ref * V_ref * Rgas_ref) [m].

get_Pr(rho, u[, out])

Prandtl number, \(\mu c_p / \kappa\).

Batched evaluation and factories

get_P_h_T(rho, u[, out_P, out_h, out_T])

Pressure, enthalpy and temperature together, from density and energy.

from_dict(data)

Build a fluid from a dict written by to_dict().

to_dict()

Return a portable record of this fluid, ready for from_dict().

change_datum(P_dtm, T_dtm)

Return a new instance with datum shifted to (P_dtm, T_dtm).

change_ref([rho_ref, V_ref, Rgas_ref])

Return a new instance with different reference scales.

change_visc(scale_visc)

Return a new instance with the viscosity scaled by a factor.

classmethod from_dict(data)[source]

Build a fluid from a dict written by to_dict().

Called on Fluid it dispatches on the type key, so a saved fluid can be read back without the caller knowing which equation of state wrote it. Called on a concrete class it checks that type names that class, so loading the wrong file is an error rather than a constructor failure several arguments deep.

Parameters:

data (dict) – As returned by to_dict(). Not modified.

Returns:

fluid – A new instance of the class named by data["type"].

Return type:

Fluid

abstractmethod set_h_s(h, s)[source]

Density and internal energy from specific enthalpy and entropy.

abstractmethod set_P_h(P, h)[source]

Density and internal energy from pressure and specific enthalpy.

abstractmethod set_P_rho(P, rho)[source]

Density and internal energy from pressure and density.

abstractmethod set_P_s(P, s)[source]

Density and internal energy from pressure and specific entropy.

abstractmethod set_P_T(P, T)[source]

Density and internal energy from pressure and temperature.

abstractmethod set_rho_s(rho, s)[source]

Density and internal energy from density and specific entropy.

abstractmethod set_T_rho(T, rho)[source]

Density and internal energy from temperature and density.

abstractmethod set_T_s(T, s)[source]

Density and internal energy from temperature and specific entropy.

abstractmethod get_a(rho, u, out=None)[source]

Speed of sound.

abstractmethod get_cp(rho, u, out=None)[source]

Specific heat at constant pressure.

abstractmethod get_cv(rho, u, out=None)[source]

Specific heat at constant volume.

abstractmethod get_dhdP_rho(rho, u, out=None)[source]

Derivative of enthalpy with respect to pressure at constant density.

abstractmethod get_dhdrho_P(rho, u, out=None)[source]

Derivative of enthalpy with respect to density at constant pressure.

abstractmethod get_dsdP_rho(rho, u, out=None)[source]

Derivative of entropy with respect to pressure at constant density.

abstractmethod get_dsdrho_P(rho, u, out=None)[source]

Derivative of entropy with respect to density at constant pressure.

abstractmethod get_dudP_rho(rho, u, out=None)[source]

Derivative of internal energy with respect to pressure at constant density.

abstractmethod get_dudrho_P(rho, u, out=None)[source]

Derivative of internal energy with respect to density at constant pressure.

abstractmethod get_gamma(rho, u, out=None)[source]

Ratio of specific heats, \(c_p / c_v\).

abstractmethod get_h(rho, u, out=None)[source]

Specific enthalpy, relative to the datum (see Datum state).

abstractmethod get_kappa(rho, u, out=None)[source]

Quasi-dimensional thermal conductivity, kappa / (rho_ref * V_ref * Rgas_ref) [m].

Conductivity and viscosity are the two transport properties an equation of state owns; the Prandtl number relating them is a derived quantity whichever of the three a given fluid happens to store.

abstractmethod get_mu(rho, u, out=None)[source]

Quasi-dimensional dynamic viscosity, mu / (rho_ref * V_ref) [m].

abstractmethod get_P(rho, u, out=None)[source]

Static pressure.

get_P_h_T(rho, u, out_P=None, out_h=None, out_T=None)[source]

Pressure, enthalpy and temperature together, from density and energy.

A batched form of get_P(), get_h() and get_T(), for callers that want all three from the same state – the solver does, once per Runge-Kutta stage. Evaluating them separately re-reads rho and u three times, and for most equations of state the three share nearly all of their work.

Deliberately NOT abstract: this base implementation simply delegates to the three single-property methods, so every fluid – present or future – is correct without implementing anything. A subclass may override it with a fused evaluation purely as an optimisation, and is not obliged to. PerfectFluid does.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out_P (ndarray, optional) – Pre-allocated output arrays.

  • out_h (ndarray, optional) – Pre-allocated output arrays.

  • out_T (ndarray, optional) – Pre-allocated output arrays.

Returns:

(P, h, T).

Return type:

tuple of ndarray

abstractmethod get_Pr(rho, u, out=None)[source]

Prandtl number, \(\mu c_p / \kappa\).

abstractmethod get_Rgas(rho, u, out=None)[source]

Specific gas constant.

abstractmethod get_s(rho, u, out=None)[source]

Specific entropy, relative to the datum (see Datum state).

abstractmethod get_T(rho, u, out=None)[source]

Static temperature.

abstractmethod change_datum(P_dtm, T_dtm)[source]

Return a new instance with datum shifted to (P_dtm, T_dtm).

A pure factory: the returned fluid carries the same properties on the new datum, and no field values are transformed. To move a stored flow field onto another datum, pass the new fluid to ember.block.Block.set_fluid(), which reads the state out through the old fluid and re-expresses it through the new one.

Note that T_dtm = 0 is not representable: the datum sets u = s = 0 simultaneously, and entropy carries a \(\ln(T/T_\mathrm{dtm})\) term that is singular there.

abstractmethod change_ref(rho_ref=None, V_ref=None, Rgas_ref=None)[source]

Return a new instance with different reference scales.

A pure factory, like change_datum(): the fitted or stored properties are untouched, only the scales the non-dimensionalisation uses. An omitted scale keeps this instance’s value, so a call need name only the scales that change. See Reference scales.

Parameters:
  • rho_ref (float, optional) – New reference density, velocity and gas constant. Any left out keep their current value.

  • V_ref (float, optional) – New reference density, velocity and gas constant. Any left out keep their current value.

  • Rgas_ref (float, optional) – New reference density, velocity and gas constant. Any left out keep their current value.

Returns:

fluid_new – New fluid instance with the same properties on the new scales.

Return type:

Fluid

abstractmethod change_visc(scale_visc)[source]

Return a new instance with the viscosity scaled by a factor.

A pure factory in the manner of change_datum(): nothing else about the fluid moves, and no field values are transformed. Sweeping Reynolds number is what this is for — the geometry, the boundary conditions and the thermodynamics all stay put, and only the transport scale changes.

The thermal conductivity scales by the same factor, leaving the Prandtl number where it was, so the Peclet number follows the Reynolds number.

The scaling is relative to this fluid, so the factors of a chain of calls multiply together.

Parameters:

scale_visc (float) – Factor to multiply this fluid’s viscosity by. Must be positive.

Returns:

fluid_new – New fluid instance with scaled viscosity.

Return type:

Fluid

to_dict()[source]

Return a portable record of this fluid, ready for from_dict().

The dict holds plain floats, strings and nested lists only, so it can be written with json or a plain YAML dumper and read by anything. That is the point of it: a RealFluid surface costs a CoolProp table and an offline fit to produce, and until now the only way to keep one was to pickle the grid it happened to be attached to.

Everything the constructor takes is included, the reference scales and the datum among them, so the round trip is exact. A fluid reloaded into another run therefore arrives with the scales of the run that wrote it; change_ref() is how to move it onto new ones.

Returns:

data – Constructor arguments plus a type key naming the class.

Return type:

dict

property P_dtm

Datum pressure \(p_\mathrm{dtm}\) where \(u = s = 0\) [Pa].

User-selectable as discussed in Datum state.

property P_ref

Reference pressure for nondimensionalisation, \(p_\mathrm{ref}\) [Pa].

See Reference scales; derived from

\[p_\mathrm{ref} = \rho_\mathrm{ref} V_\mathrm{ref}^2\]
property Rgas_ref

Reference gas constant for nondimensionalisation, \(R_\mathrm{ref}\) [J/kg/K].

User-specified; see Reference scales.

property rho_ref

Reference density for nondimensionalisation, \(\rho_\mathrm{ref}\) [kg/m³].

User-specified; see Reference scales.

property rhoV_ref

Reference mass flux for nondimensionalisation, \((\rho V)_\mathrm{ref}\) [kg/m²/s].

See Reference scales; derived from

\[(\rho V)_\mathrm{ref} = \rho_\mathrm{ref} V_\mathrm{ref}\]
property T_dtm

Datum temperature \(T_\mathrm{dtm}\) where \(u = s = 0\) [K].

User-selectable as discussed in Datum state.

property T_ref

Reference temperature for nondimensionalisation, \(T_\mathrm{ref}\) [K].

See Reference scales; derived from

\[T_\mathrm{ref} = V_\mathrm{ref}^2 / R_\mathrm{ref}\]
property u_ref

Reference specific energy for nondimensionalisation, \(u_\mathrm{ref}\) [J/kg].

See Reference scales; derived from

\[u_\mathrm{ref} = V_\mathrm{ref}^2\]
property V_ref

Reference velocity for nondimensionalisation, \(V_\mathrm{ref}\) [m/s].

User-specified; see Reference scales.

class fluid.PerfectFluid(cp, gamma, mu, Pr, P_dtm=100000.0, T_dtm=300.0, rho_ref=1.0, V_ref=1.0, Rgas_ref=1.0)[source]

Bases: Fluid

Perfect gas with constant specific heats.

Parameters:
  • cp (float) – Specific heat at constant pressure [J/kg/K].

  • gamma (float) – Ratio of specific heats [–].

  • mu (float) – Dynamic viscosity [kg/m/s].

  • Pr (float) – Prandtl number [–].

  • P_dtm (float, optional) – Datum pressure where u = 0 and s = 0 [Pa].

  • T_dtm (float, optional) – Datum temperature where u = 0 and s = 0 [K].

  • rho_ref (float, optional) – Reference density for non-dimensionalisation.

  • V_ref (float, optional) – Reference velocity for non-dimensionalisation.

  • Rgas_ref (float, optional) – Reference gas constant for non-dimensionalisation.

Methods:

set_h_s(h, s)

Density and internal energy from specific enthalpy and entropy.

set_P_h(P, h)

Density and internal energy from pressure and specific enthalpy.

set_P_rho(P, rho)

Density and internal energy from pressure and density.

set_P_s(P, s)

Density and internal energy from pressure and specific entropy.

set_P_T(P, T)

Density and internal energy from pressure and temperature.

set_rho_s(rho, s)

Density and internal energy from density and specific entropy.

set_T_rho(T, rho)

Density and internal energy from temperature and density.

set_T_s(T, s)

Density and internal energy from temperature and specific entropy.

get_a(rho, u[, out])

Speed of sound from density and internal energy.

get_cp(rho, u[, out])

Specific heat at constant pressure (constant for a perfect gas).

get_cv(rho, u[, out])

Specific heat at constant volume (constant for a perfect gas).

get_dhdP_rho(rho, u[, out])

Derivative of specific enthalpy with respect to pressure at constant density.

get_dhdrho_P(rho, u[, out])

Derivative of specific enthalpy with respect to density at constant pressure.

get_dsdP_rho(rho, u[, out])

Derivative of specific entropy with respect to pressure at constant density.

get_dsdrho_P(rho, u[, out])

Derivative of specific entropy with respect to density at constant pressure.

get_dudP_rho(rho, u[, out])

Derivative of specific internal energy with respect to pressure at constant density.

get_dudrho_P(rho, u[, out])

Derivative of specific internal energy with respect to density at constant pressure.

get_gamma(rho, u[, out])

Ratio of specific heats (constant for a perfect gas).

get_h(rho, u[, out])

Specific enthalpy from density and internal energy.

get_kappa(rho, u[, out])

Thermal conductivity (constant for a perfect gas).

get_mu(rho, u[, out])

Dynamic viscosity (constant for a perfect gas).

get_P(rho, u[, out])

Pressure from density and internal energy.

get_P_h_T(rho, u[, out_P, out_h, out_T])

Batched evaluation of pressure, enthalpy and temperature.

get_Pr(rho, u[, out])

Prandtl number (constant for a perfect gas).

get_Rgas(rho, u[, out])

Specific gas constant (constant for a perfect gas).

get_s(rho, u[, out])

Specific entropy from density and internal energy.

get_T(rho, u[, out])

Temperature from density and internal energy.

change_datum(P_dtm, T_dtm)

Return a new instance with datum shifted to (P_dtm, T_dtm).

change_ref([rho_ref, V_ref, Rgas_ref])

Return a new instance with different reference scales.

change_visc(scale_visc)

Scale the stored constant mu (and kappa with it).

set_h_s(h, s)[source]

Density and internal energy from specific enthalpy and entropy.

Temperature is recovered from \(h\), then pressure from \(s\) , then \(\rho\) and \(u\) follow from set_P_T(),

\[T = \frac{h}{c_p} + \frac{T_\mathrm{dtm}}{\gamma}, \qquad p = p_\mathrm{dtm} \exp\!\left(\frac{c_p\ln(T/T_\mathrm{dtm}) - s}{R}\right)\]
Parameters:
  • h (array_like) – Specific enthalpy [J/kg].

  • s (array_like) – Specific entropy [J/kg/K].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

set_P_h(P, h)[source]

Density and internal energy from pressure and specific enthalpy.

Temperature is recovered from \(h\),

\[T = \frac{h}{c_p} + \frac{T_\mathrm{dtm}}{\gamma}\]

Then \(\rho\) and \(u\) follow from set_P_T().

Parameters:
  • P (array_like) – Pressure [Pa].

  • h (array_like) – Specific enthalpy [J/kg].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

set_P_rho(P, rho)[source]

Density and internal energy from pressure and density.

Temperature follows from the ideal gas law, giving,

\[u = c_v\!\left(\frac{p}{\rho R} - T_\mathrm{dtm}\right)\]
Parameters:
  • P (array_like) – Pressure [Pa].

  • rho (array_like) – Density [kg/m³].

Returns:

  • rho (ndarray) – Density [kg/m³] (returned unchanged).

  • u (ndarray) – Specific internal energy [J/kg].

set_P_s(P, s)[source]

Density and internal energy from pressure and specific entropy.

Inverting the Gibbs relation gives temperature, then \(\rho\) and \(u\) follow from set_P_T(),

\[T = T_\mathrm{dtm} \exp\!\left(\frac{s + R\ln(p/p_\mathrm{dtm})}{c_p}\right)\]
Parameters:
  • P (array_like) – Pressure [Pa].

  • s (array_like) – Specific entropy [J/kg/K].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

set_P_T(P, T)[source]

Density and internal energy from pressure and temperature.

From the ideal gas law and the definition of internal energy,

\[\rho = \frac{p}{RT}, \qquad u = c_v(T - T_\mathrm{dtm})\]
Parameters:
  • P (array_like) – Pressure [Pa].

  • T (array_like) – Temperature [K].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

set_rho_s(rho, s)[source]

Density and internal energy from density and specific entropy.

Inverting the entropy relation for a perfect gas at fixed density gives temperature directly:

\[T = T_\mathrm{dtm} \exp\!\left(\frac{s}{c_v} + (\gamma-1)\ln\!\frac{\rho}{\rho_\mathrm{dtm}}\right)\]

where \(\rho_\mathrm{dtm} = p_\mathrm{dtm}/(R T_\mathrm{dtm})\), then:

\[u = c_v(T - T_\mathrm{dtm})\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • s (array_like) – Specific entropy [J/kg/K].

Returns:

  • rho (ndarray) – Density [kg/m³] (returned unchanged).

  • u (ndarray) – Specific internal energy [J/kg].

set_T_rho(T, rho)[source]

Density and internal energy from temperature and density.

From the definition of internal energy,

\[u = c_v(T - T_\mathrm{dtm})\]
Parameters:
  • T (array_like) – Temperature [K].

  • rho (array_like) – Density [kg/m³].

Returns:

  • rho (ndarray) – Density [kg/m³] (returned unchanged).

  • u (ndarray) – Specific internal energy [J/kg].

set_T_s(T, s)[source]

Density and internal energy from temperature and specific entropy.

Inverting the Gibbs relation gives pressure, then \(\rho\) and \(u\) follow from set_P_T():

\[p = p_\mathrm{dtm} \exp\!\left(\frac{c_p\ln(T/T_\mathrm{dtm}) - s}{R}\right)\]
Parameters:
  • T (array_like) – Temperature [K].

  • s (array_like) – Specific entropy [J/kg/K].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

get_a(rho, u, out=None)[source]

Speed of sound from density and internal energy.

For a perfect gas, \(a^2 = \gamma R T\), combined with the definition of internal energy \(u = c_v (T - T_\mathrm{dtm})\) gives

\[a = \sqrt{\gamma R \left(\frac{u}{c_v} + T_\mathrm{dtm}\right)}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

a – Speed of sound [m/s].

Return type:

ndarray

get_cp(rho, u, out=None)[source]

Specific heat at constant pressure (constant for a perfect gas).

\[c_p = \frac{\gamma R}{\gamma - 1}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

cp – Specific heat at constant pressure [J/kg/K].

Return type:

ndarray

get_cv(rho, u, out=None)[source]

Specific heat at constant volume (constant for a perfect gas).

\[c_v = \frac{R}{\gamma - 1} = \frac{c_p}{\gamma}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

cv – Specific heat at constant volume [J/kg/K].

Return type:

ndarray

get_dhdP_rho(rho, u, out=None)[source]

Derivative of specific enthalpy with respect to pressure at constant density.

From \(h = \gamma u + R T_\mathrm{dtm}\) and \(p = \rho R T\), differentiating at constant \(\rho\):

\[\left.\frac{\partial h}{\partial p}\right|_\rho = \frac{\gamma}{\rho(\gamma-1)}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dhdP_rho – Derivative \((\partial h/\partial p)_\rho\) [m³/kg].

Return type:

ndarray

get_dhdrho_P(rho, u, out=None)[source]

Derivative of specific enthalpy with respect to density at constant pressure.

From \(h = c_p T\) and the ideal gas law \(T = p / (\rho R)\), differentiating at constant \(p\):

\[\left.\frac{\partial h}{\partial \rho}\right|_p = -\frac{c_p T}{\rho}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dhdrho_P – Derivative \((\partial h/\partial \rho)_p\) [J·m³/kg²].

Return type:

ndarray

get_dsdP_rho(rho, u, out=None)[source]

Derivative of specific entropy with respect to pressure at constant density.

From the Gibbs relation for a perfect gas, differentiating at constant \(\rho\) (so \(T \propto p\)):

\[\left.\frac{\partial s}{\partial p}\right|_\rho = \frac{c_v}{p}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dsdP_rho – Derivative \((\partial s/\partial p)_\rho\) [J/kg/K/Pa].

Return type:

ndarray

get_dsdrho_P(rho, u, out=None)[source]

Derivative of specific entropy with respect to density at constant pressure.

From the Gibbs relation for a perfect gas, differentiating at constant \(p\) (so \(T \propto 1/\rho\)):

\[\left.\frac{\partial s}{\partial \rho}\right|_p = -\frac{c_p}{\rho}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dsdrho_P – Derivative \((\partial s/\partial \rho)_p\) [J·m³/kg²/K].

Return type:

ndarray

get_dudP_rho(rho, u, out=None)[source]

Derivative of specific internal energy with respect to pressure at constant density.

From \(u = c_v(T - T_\mathrm{dtm})\) and \(p = \rho R T\), differentiating at constant \(\rho\):

\[\left.\frac{\partial u}{\partial p}\right|_\rho = \frac{1}{\rho(\gamma-1)}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dudP_rho – Derivative \((\partial u/\partial p)_\rho\) [m³/kg].

Return type:

ndarray

get_dudrho_P(rho, u, out=None)[source]

Derivative of specific internal energy with respect to density at constant pressure.

From \(u = c_v(T - T_\mathrm{dtm})\) and \(T = p/(\rho R)\), differentiating at constant \(p\):

\[\left.\frac{\partial u}{\partial \rho}\right|_p = -\frac{p}{\rho^2(\gamma-1)}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dudrho_P – Derivative \((\partial u/\partial \rho)_p\) [J·m³/kg²].

Return type:

ndarray

get_gamma(rho, u, out=None)[source]

Ratio of specific heats (constant for a perfect gas).

\[\gamma = \frac{c_p}{c_v}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

gamma – Ratio of specific heats [–].

Return type:

ndarray

get_h(rho, u, out=None)[source]

Specific enthalpy from density and internal energy.

Using the definitions of enthalpy \(h = u + p/\rho\), internal energy \(u = c_v(T-T_\mathrm{dtm})\), and the ideal gas law \(p = \rho R T\) gives

\[h = \gamma u + R T_\mathrm{dtm}\]

Enthalpy carries an offset dependent on the arbitrary datum state where \(u = s = 0\) at \((p_\mathrm{dtm}, T_\mathrm{dtm})\); only changes in \(h\) are physically meaningful, so \(h \neq c_p T\). See Datum state.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

h – Specific enthalpy [J/kg].

Return type:

ndarray

get_kappa(rho, u, out=None)[source]

Thermal conductivity (constant for a perfect gas).

\[\kappa = \frac{\mu c_p}{\mathit{Pr}}\]

If reference scales are set, then this method returns a quasi-dimensional conductivity in units of [m] — see Reference scales for details.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

kappa – Thermal conductivity [W/m/K].

Return type:

ndarray

get_mu(rho, u, out=None)[source]

Dynamic viscosity (constant for a perfect gas).

If reference scales are set, then this method returns a quasi-dimensional viscosity in units of [m] — see Reference Scales for details.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

mu – Dynamic viscosity [kg/m/s].

Return type:

ndarray

get_P(rho, u, out=None)[source]

Pressure from density and internal energy.

From the ideal gas law and the definition of internal energy for a perfect gas, \(u = c_v (T - T_\mathrm{dtm})\)

\[p = \rho R \left(\frac{u}{c_v} + T_\mathrm{dtm}\right)\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

P – Pressure [Pa].

Return type:

ndarray

get_P_h_T(rho, u, out_P=None, out_h=None, out_T=None)[source]

Batched evaluation of pressure, enthalpy and temperature.

The base class calls get_P(), get_h() and get_T() in sequence, so this method is an optional override for subclasses that can compute all three in a single pass over the state. The CFD solver calls this method once per Runge-Kutta stage, so a fused evaluation can save time.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out_P (ndarray, optional) – Pre-allocated output arrays.

  • out_h (ndarray, optional) – Pre-allocated output arrays.

  • out_T (ndarray, optional) – Pre-allocated output arrays.

Returns:

(P, h, T).

Return type:

tuple of ndarray

get_Pr(rho, u, out=None)[source]

Prandtl number (constant for a perfect gas).

\[\mathit{Pr} = \frac{\mu c_p}{\kappa}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

Pr – Prandtl number [–].

Return type:

ndarray

get_Rgas(rho, u, out=None)[source]

Specific gas constant (constant for a perfect gas).

\[R = c_p - c_v = \frac{(\gamma - 1)\, c_p}{\gamma}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

R – Specific gas constant [J/kg/K].

Return type:

ndarray

get_s(rho, u, out=None)[source]

Specific entropy from density and internal energy.

Using the Gibbs relation for a perfect gas, with the datum state \((p_\mathrm{dtm}, T_\mathrm{dtm})\) defining zero entropy

\[s = c_p \ln\!\frac{T}{T_\mathrm{dtm}} - R \ln\!\frac{p}{p_\mathrm{dtm}}\]

where \(T = u/c_v + T_\mathrm{dtm}\) and \(p = \rho R T\).

Entropy is defined relative to the arbitrary datum state where \(u = s = 0\) at \((p_\mathrm{dtm}, T_\mathrm{dtm})\); only changes in \(s\) are physically meaningful. See Datum state.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

s – Specific entropy [J/kg/K].

Return type:

ndarray

get_T(rho, u, out=None)[source]

Temperature from density and internal energy.

Rearranging the definition of internal energy for a perfect gas \(u = c_v (T - T_\mathrm{dtm})\) gives

\[T = \frac{u}{c_v} + T_\mathrm{dtm}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

T – Temperature [K].

Return type:

ndarray

change_datum(P_dtm, T_dtm)[source]

Return a new instance with datum shifted to (P_dtm, T_dtm).

A pure factory: the returned fluid carries the same properties on the new datum, and no field values are transformed. To move a stored flow field onto another datum, pass the new fluid to ember.block.Block.set_fluid(), which reads the state out through the old fluid and re-expresses it through the new one.

Note that T_dtm = 0 is not representable: the datum sets u = s = 0 simultaneously, and entropy carries a \(\ln(T/T_\mathrm{dtm})\) term that is singular there.

change_ref(rho_ref=None, V_ref=None, Rgas_ref=None)[source]

Return a new instance with different reference scales.

A pure factory, like change_datum(): the fitted or stored properties are untouched, only the scales the non-dimensionalisation uses. An omitted scale keeps this instance’s value, so a call need name only the scales that change. See Reference scales.

Parameters:
  • rho_ref (float, optional) – New reference density, velocity and gas constant. Any left out keep their current value.

  • V_ref (float, optional) – New reference density, velocity and gas constant. Any left out keep their current value.

  • Rgas_ref (float, optional) – New reference density, velocity and gas constant. Any left out keep their current value.

Returns:

fluid_new – New fluid instance with the same properties on the new scales.

Return type:

Fluid

change_visc(scale_visc)[source]

Scale the stored constant mu (and kappa with it).

See Fluid.change_visc() for the contract.

class fluid.RealFluid(alpha, beta, delta, gamma, rho_lim, u_lim, Rgas, mu_c, kappa_c, scale_visc=1.0, P_dtm=None, T_dtm=None, rho_ref=1.0, V_ref=1.0, Rgas_ref=1.0)[source]

Bases: Fluid

Real gas defined by a fitted entropy surface.

Implements the thermodynamically consistent equation of state of Wheeler [1]. A polynomial surface is fitted offline to the compressibility factor and integrated analytically to give entropy; temperature and pressure are then derived from that one surface rather than fitted separately, so the thermodynamic relations between them hold exactly. Use ember.realgas_fit to produce the coefficients.

The consistency is the point. An interpolated lookup table satisfies its own tabulated values but not the relations between them, and the resulting mismatch acts like a non-equilibrium process, creating spurious entropy wherever gradients are steep. Wheeler shows a 62k-point table was needed to bring turbine entropy rise within 1.4 percent of this method.

Evaluation

Everything descends from the entropy surface and its partials, via the combined first and second law \(\mathrm{d}u = T\,\mathrm{d}s + (p/\rho^2)\,\mathrm{d}\rho\):

\[T = \left[\left(\frac{\partial s}{\partial u}\right)_\rho\right]^{-1}, \qquad p = -\rho^2 T \left(\frac{\partial s}{\partial \rho}\right)_u\]

The inverse set_* methods have no closed form and are solved by Newton iteration; see set_P_rho() and set_P_T().

Domain of validity

The polynomials mean nothing outside the box they were fitted over, so rho_lim and u_lim are enforced: iterates are clamped to the box, and a solve that cannot meet its tolerance, or that returns no number at all, raises rather than returning a state the fit does not describe.

A density passed in rather than solved for – by set_rho_s(), set_P_rho() and set_T_rho() – is checked against the box before the iteration starts. Nothing later could catch it: the fitted surface extrapolates smoothly, so the solve would converge on a state that is self-consistent with a polynomial nobody fitted out there.

Transport properties

Viscosity and conductivity are fitted surfaces of their own, in the same normalised coordinates as \(Z\) and produced by the same offline tool. They are independent least-squares fits and take no part in the consistency argument above — nothing relates them to entropy, and neither is ever differentiated. Each is normalised by its value at the centre of the fit box, which mu_c and kappa_c carry, so the coefficients are of order unity. The Prandtl number is not stored; get_Pr() derives it from the two surfaces and the specific heat.

The solver reads both surfaces at every node: mu_nd and kappa_nd are nodal fields, and the viscous kernel takes them as such.

type alpha:

array_like

param alpha:

Two-dimensional Legendre coefficients of the compressibility factor \(Z(\hat\rho, \hat u)\) [–], in density and internal energy each scaled onto \([-1, 1]\) by the fit-box bounds.

type alpha:

array_like

type beta:

array_like

param beta:

One-dimensional Legendre coefficients of \(s/R\) along the reference isochor, the one through the centre of the density box.

type beta:

array_like

type delta:

array_like

param delta:

Two-dimensional Legendre coefficients of the viscosity surface [–], normalised by mu_c.

type delta:

array_like

type gamma:

array_like

param gamma:

Two-dimensional Legendre coefficients of the conductivity surface [–], normalised by kappa_c.

type gamma:

array_like

type rho_lim:

tuple

param rho_lim:

(min, max) density bounds of the fit box [kg/m³].

type rho_lim:

tuple

type u_lim:

tuple

param u_lim:

(min, max) internal energy bounds of the fit box [J/kg], on the same datum as the data beta was fitted to.

type u_lim:

tuple

type Rgas:

float

param Rgas:

Specific gas constant [J/kg/K]. Converts the two dimensionless coefficient arrays into entropy, and is what get_Rgas() reports.

type Rgas:

float

type mu_c:

float

param mu_c:

Dynamic viscosity at the centre of the fit box [kg/m/s], the scale the delta surface is normalised by.

type mu_c:

float

type kappa_c:

float

param kappa_c:

Thermal conductivity at the centre of the fit box [W/m/K], the scale the gamma surface is normalised by.

type kappa_c:

float

type scale_visc:

float, optional

param scale_visc:

Factor multiplying the viscosity, for sweeping Reynolds number without touching the fit; see change_visc().

type scale_visc:

float, optional

type P_dtm:

float, optional

param P_dtm:

Datum pressure where u = 0 and s = 0 [Pa]. Must lie in the fit box. Defaults to this fluid’s own pressure at the centre of that box, which is inside it by construction; see Datum state.

type P_dtm:

float, optional

type T_dtm:

float, optional

param T_dtm:

Datum temperature where u = 0 and s = 0 [K]. Must lie in the fit box. Defaults to the temperature at the same point. Either may be given on its own, the other still defaulting.

type T_dtm:

float, optional

type rho_ref:

float, optional

param rho_ref:

Reference density for non-dimensionalisation.

type rho_ref:

float, optional

type V_ref:

float, optional

param V_ref:

Reference velocity for non-dimensionalisation.

type V_ref:

float, optional

type Rgas_ref:

float, optional

param Rgas_ref:

Reference gas constant for non-dimensionalisation.

type Rgas_ref:

float, optional

Methods:

set_h_s(h, s)

Density and internal energy from specific enthalpy and entropy.

set_P_h(P, h)

Density and internal energy from pressure and specific enthalpy.

set_P_rho(P, rho)

Density and internal energy from pressure and density.

set_P_s(P, s)

Density and internal energy from pressure and specific entropy.

set_P_T(P, T)

Density and internal energy from pressure and temperature.

set_rho_s(rho, s)

Density and internal energy from density and specific entropy.

set_T_rho(T, rho)

Density and internal energy from temperature and density.

set_T_s(T, s)

Density and internal energy from temperature and specific entropy.

get_a(rho, u[, out])

Speed of sound from density and internal energy.

get_cp(rho, u[, out])

Specific heat at constant pressure from density and internal energy.

get_cv(rho, u[, out])

Specific heat at constant volume from density and internal energy.

get_dhdP_rho(rho, u[, out])

Derivative of specific enthalpy with respect to pressure at constant density.

get_dhdrho_P(rho, u[, out])

Derivative of specific enthalpy with respect to density at constant pressure.

get_dsdP_rho(rho, u[, out])

Derivative of specific entropy with respect to pressure at constant density.

get_dsdrho_P(rho, u[, out])

Derivative of specific entropy with respect to density at constant pressure.

get_dudP_rho(rho, u[, out])

Derivative of specific internal energy with respect to pressure at constant density.

get_dudrho_P(rho, u[, out])

Derivative of specific internal energy with respect to density at constant pressure.

get_gamma(rho, u[, out])

Isentropic exponent from density and internal energy.

get_h(rho, u[, out])

Specific enthalpy from density and internal energy.

get_kappa(rho, u[, out])

Thermal conductivity from the fitted transport surface.

get_mu(rho, u[, out])

Dynamic viscosity from the fitted transport surface.

get_P(rho, u[, out])

Pressure from density and internal energy.

get_P_h_T(rho, u[, out_P, out_h, out_T])

Batched evaluation of pressure, enthalpy and temperature.

get_Pr(rho, u[, out])

Prandtl number, derived from the two transport surfaces.

get_Rgas(rho, u[, out])

Specific gas constant (a constant property of the species).

get_s(rho, u[, out])

Specific entropy from density and internal energy.

get_T(rho, u[, out])

Temperature from density and internal energy.

change_datum(P_dtm, T_dtm)

Shift the datum.

change_ref([rho_ref, V_ref, Rgas_ref])

Rescale.

change_visc(scale_visc)

Scale the two fitted transport surfaces together --- there is no stored viscosity, only a polynomial in \((\rho, u)\).

Attributes:

rho_lim_nd

Density bounds of the fit box \(\rho/\rho_\mathrm{ref}\) [--].

u_lim_nd

Internal energy bounds of the fit box \(u/u_\mathrm{ref}\) [--].

set_h_s(h, s)[source]

Density and internal energy from specific enthalpy and entropy.

Solved by two-dimensional Newton iteration; see set_P_T().

Parameters:
  • h (array_like) – Specific enthalpy [J/kg].

  • s (array_like) – Specific entropy [J/kg/K].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

set_P_h(P, h)[source]

Density and internal energy from pressure and specific enthalpy.

Solved by two-dimensional Newton iteration; see set_P_T().

Parameters:
  • P (array_like) – Pressure [Pa].

  • h (array_like) – Specific enthalpy [J/kg].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

set_P_rho(P, rho)[source]

Density and internal energy from pressure and density.

Density is already known, so this is a scalar Newton solve for the internal energy satisfying \(p(\rho, u) = p\), seeded from the companion perfect gas. The residual is monotone in \(u\), since heating at constant volume raises pressure.

This is on the per-step nonreflecting boundary path, so it is solved for the whole array at once rather than node by node.

Parameters:
  • P (array_like) – Pressure [Pa].

  • rho (array_like) – Density [kg/m³].

Returns:

  • rho (ndarray) – Density [kg/m³] (returned unchanged).

  • u (ndarray) – Specific internal energy [J/kg].

set_P_s(P, s)[source]

Density and internal energy from pressure and specific entropy.

Solved by two-dimensional Newton iteration; see set_P_T().

Parameters:
  • P (array_like) – Pressure [Pa].

  • s (array_like) – Specific entropy [J/kg/K].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

set_P_T(P, T)[source]

Density and internal energy from pressure and temperature.

Neither variable is known directly, so both are found together by Newton iteration on the 2x2 system \(p(\rho, u) = p\), \(T(\rho, u) = T\), with the Jacobian assembled analytically from the entropy surface and inverted in closed form.

Conditioning degrades near the critical point, where \((\partial p/\partial\rho)_T \rightarrow 0\) and the Jacobian determinant vanishes. That is physical rather than numerical – pressure and temperature stop being independent coordinates on the saturation line – and lies outside any sensible fit box, but it will surface as a convergence failure rather than a wrong answer.

Parameters:
  • P (array_like) – Pressure [Pa].

  • T (array_like) – Temperature [K].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

set_rho_s(rho, s)[source]

Density and internal energy from density and specific entropy.

A scalar Newton solve for the internal energy satisfying \(s(\rho, u) = s\). The residual is monotone in \(u\) because \((\partial s/\partial u)_\rho = 1/T > 0\), so convergence is assured from any starting point in the box.

This is on the per-step nonreflecting boundary path, so it is solved for the whole array at once rather than node by node.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • s (array_like) – Specific entropy [J/kg/K].

Returns:

  • rho (ndarray) – Density [kg/m³] (returned unchanged).

  • u (ndarray) – Specific internal energy [J/kg].

set_T_rho(T, rho)[source]

Density and internal energy from temperature and density.

A scalar Newton solve for the internal energy satisfying \(T(\rho, u) = T\). The residual is monotone in \(u\) because the specific heat at constant volume is positive.

Parameters:
  • T (array_like) – Temperature [K].

  • rho (array_like) – Density [kg/m³].

Returns:

  • rho (ndarray) – Density [kg/m³] (returned unchanged).

  • u (ndarray) – Specific internal energy [J/kg].

set_T_s(T, s)[source]

Density and internal energy from temperature and specific entropy.

Solved by two-dimensional Newton iteration; see set_P_T().

Parameters:
  • T (array_like) – Temperature [K].

  • s (array_like) – Specific entropy [J/kg/K].

Returns:

  • rho (ndarray) – Density [kg/m³].

  • u (ndarray) – Specific internal energy [J/kg].

get_a(rho, u, out=None)[source]

Speed of sound from density and internal energy.

\[a = \sqrt{k\, p / \rho}\]

where \(k\) is the isentropic exponent of get_gamma(). Note this is the isentropic exponent and not the ratio of specific heats, which for a real gas is a different number.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

a – Speed of sound [m/s].

Return type:

ndarray

get_cp(rho, u, out=None)[source]

Specific heat at constant pressure from density and internal energy.

Obtained from the specific heat at constant volume and the ratio of the isentropic and isothermal density derivatives of pressure,

\[\frac{c_p}{c_v} = \frac{(\partial p/\partial\rho)_s}{(\partial p/\partial\rho)_T}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

cp – Specific heat at constant pressure [J/kg/K].

Return type:

ndarray

get_cv(rho, u, out=None)[source]

Specific heat at constant volume from density and internal energy.

\[c_v = \left(\frac{\partial u}{\partial T}\right)_\rho\]

evaluated by inverting the temperature derivative, which comes from the second derivative of the entropy surface.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

cv – Specific heat at constant volume [J/kg/K].

Return type:

ndarray

get_dhdP_rho(rho, u, out=None)[source]

Derivative of specific enthalpy with respect to pressure at constant density.

\[\left.\frac{\partial h}{\partial p}\right|_\rho = \left.\frac{\partial u}{\partial p}\right|_\rho + \frac{1}{\rho}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dhdP_rho – Derivative \((\partial h/\partial p)_\rho\) [m³/kg].

Return type:

ndarray

get_dhdrho_P(rho, u, out=None)[source]

Derivative of specific enthalpy with respect to density at constant pressure.

\[\left.\frac{\partial h}{\partial \rho}\right|_p = \left.\frac{\partial u}{\partial \rho}\right|_p - \frac{p}{\rho^2}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dhdrho_P – Derivative \((\partial h/\partial \rho)_p\) [J·m³/kg²].

Return type:

ndarray

get_dsdP_rho(rho, u, out=None)[source]

Derivative of specific entropy with respect to pressure at constant density.

Obtained by chain rule through internal energy at fixed density,

\[\left.\frac{\partial s}{\partial p}\right|_\rho = \frac{(\partial s/\partial u)_\rho}{(\partial p/\partial u)_\rho}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dsdP_rho – Derivative \((\partial s/\partial p)_\rho\) [J/kg/K/Pa].

Return type:

ndarray

get_dsdrho_P(rho, u, out=None)[source]

Derivative of specific entropy with respect to density at constant pressure.

\[\left.\frac{\partial s}{\partial \rho}\right|_p = \left.\frac{\partial s}{\partial \rho}\right|_u + \left.\frac{\partial s}{\partial u}\right|_\rho \left.\frac{\partial u}{\partial \rho}\right|_p\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dsdrho_P – Derivative \((\partial s/\partial \rho)_p\) [J·m³/kg²/K].

Return type:

ndarray

get_dudP_rho(rho, u, out=None)[source]

Derivative of specific internal energy with respect to pressure at constant density.

The reciprocal of the pressure derivative taken directly from the surface,

\[\left.\frac{\partial u}{\partial p}\right|_\rho = \left[\left.\frac{\partial p}{\partial u}\right|_\rho\right]^{-1}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dudP_rho – Derivative \((\partial u/\partial p)_\rho\) [m³/kg].

Return type:

ndarray

get_dudrho_P(rho, u, out=None)[source]

Derivative of specific internal energy with respect to density at constant pressure.

\[\left.\frac{\partial u}{\partial \rho}\right|_p = -\frac{(\partial p/\partial \rho)_u}{(\partial p/\partial u)_\rho}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

dudrho_P – Derivative \((\partial u/\partial \rho)_p\) [J·m³/kg²].

Return type:

ndarray

get_gamma(rho, u, out=None)[source]

Isentropic exponent from density and internal energy.

\[k = \frac{\rho}{p}\left.\frac{\partial p}{\partial \rho}\right|_s\]

This is the exponent that governs acoustics and the characteristic decomposition, and it is what get_a() uses. For a real gas it is not the ratio of specific heats \(c_p/c_v\), which is available separately from get_cp() and get_cv(); the two coincide only when the specific heats are constant.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

gamma – Isentropic exponent [–].

Return type:

ndarray

get_h(rho, u, out=None)[source]

Specific enthalpy from density and internal energy.

\[h = u + p/\rho\]

Enthalpy carries an offset dependent on the arbitrary datum state where \(u = s = 0\); only changes in \(h\) are physically meaningful. See Datum state.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

h – Specific enthalpy [J/kg].

Return type:

ndarray

get_kappa(rho, u, out=None)[source]

Thermal conductivity from the fitted transport surface.

One polynomial evaluation and nothing else: unlike pressure and temperature, conductivity is not derived from the entropy surface and so needs none of its derivatives.

If reference scales are set, then this method returns a quasi-dimensional conductivity in units of [m] — see Reference scales for details.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

kappa – Thermal conductivity [W/m/K].

Return type:

ndarray

get_mu(rho, u, out=None)[source]

Dynamic viscosity from the fitted transport surface.

As get_kappa(), and scaled by scale_visc.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

mu – Dynamic viscosity [kg/m/s].

Return type:

ndarray

get_P(rho, u, out=None)[source]

Pressure from density and internal energy.

From the combined first and second law, at constant internal energy,

\[p = -\rho^2 T \left(\frac{\partial s}{\partial \rho}\right)_u\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

P – Pressure [Pa].

Return type:

ndarray

get_P_h_T(rho, u, out_P=None, out_h=None, out_T=None)[source]

Batched evaluation of pressure, enthalpy and temperature.

All three come from the same entropy partials, so evaluating them together costs barely more than any one of them, where the base class would walk the polynomial surface three times. The solver calls this once per Runge-Kutta stage.

A float32 call with all three outputs supplied – which is what the solver makes – goes to a Fortran kernel instead. Anything else falls back to the numpy body below rather than to the base class: that body is already fused, and three separate calls would be three times the work.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out_P (ndarray, optional) – Pre-allocated output arrays.

  • out_h (ndarray, optional) – Pre-allocated output arrays.

  • out_T (ndarray, optional) – Pre-allocated output arrays.

Returns:

(P, h, T).

Return type:

tuple of ndarray

get_Pr(rho, u, out=None)[source]

Prandtl number, derived from the two transport surfaces.

\[\mathit{Pr} = \frac{\mu c_p}{\kappa}\]

Nothing here is stored: viscosity and conductivity are what this fluid is given, and the ratio of the two is a property of the state like any other. It is also the most expensive of the three, the specific heat costing the second derivatives of the entropy surface, so a caller after a heat flux wants get_kappa() rather than this.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

Pr – Prandtl number [–].

Return type:

ndarray

get_Rgas(rho, u, out=None)[source]

Specific gas constant (a constant property of the species).

Note that for a real gas this is not \(p/(\rho T)\), which is larger by the compressibility factor.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

R – Specific gas constant [J/kg/K].

Return type:

ndarray

get_s(rho, u, out=None)[source]

Specific entropy from density and internal energy.

Evaluated directly from the fitted surface: an isochor polynomial in internal energy, less the analytic density integral of the compressibility factor.

Entropy is defined relative to the arbitrary datum state where \(u = s = 0\); only changes in \(s\) are physically meaningful. See Datum state.

Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

s – Specific entropy [J/kg/K].

Return type:

ndarray

get_T(rho, u, out=None)[source]

Temperature from density and internal energy.

From the combined first and second law, at constant density,

\[T = \left[\left(\frac{\partial s}{\partial u}\right)_\rho\right]^{-1}\]
Parameters:
  • rho (array_like) – Density [kg/m³].

  • u (array_like) – Specific internal energy [J/kg].

  • out (ndarray, optional) – Pre-allocated output array.

Returns:

T – Temperature [K].

Return type:

ndarray

change_datum(P_dtm, T_dtm)[source]

Shift the datum. The fitted coefficients are untouched — the datum enters only through the affine constants composed at construction, so there is no refit. See Fluid.change_datum().

change_ref(rho_ref=None, V_ref=None, Rgas_ref=None)[source]

Rescale. No refit, as for change_datum(); see Fluid.change_ref().

change_visc(scale_visc)[source]

Scale the two fitted transport surfaces together — there is no stored viscosity, only a polynomial in \((\rho, u)\).

See Fluid.change_visc() for the contract.

property rho_lim_nd

Density bounds of the fit box \(\rho/\rho_\mathrm{ref}\) [–].

The constructor takes the box in SI, but get_* and set_* work in non-dimensional units, so this is the form a caller needs to check that a state is in range. Outside these bounds the fitted polynomials are meaningless and the set_* solves will refuse to converge.

property u_lim_nd

Internal energy bounds of the fit box \(u/u_\mathrm{ref}\) [–].

As rho_lim_nd, and additionally shifted onto this fluid’s datum: the constructor’s u_lim is on whatever datum the coefficients were fitted against, whereas get_* and set_* take internal energy measured from P_dtm, T_dtm. Changing the datum moves these bounds even though the underlying box is unchanged.