Gas-dynamic library

Eilmer’s gas-dynamic library is accessible from your Lua scripts and is also available as a loadable library for Python and Ruby. It provides access to functions for the thermochemical gas model and, built on top of that, a number of functions for simple state-to-state and stream-tube flow analysis. This is the reference manual for the Python and Lua flavours of the library.

Lets start with a small example to set up a gas model and do a normal shock calculation. From within your Python script, you might try the following:

# Python
from eilmer.gas import GasModel, GasState, GasFlow

gmodel = GasModel('cea-air5species-gas-model.lua')
state1 = GasState(gmodel)
state1.p = 125.0e3 # Pa
state1.T = 300.0 # K
state1.update_thermo_from_pT()
state1.update_sound_speed()
print("# Initial test gas:")
print("#   state1: %s" % state1)

print("# Normal shock, given shock speed")
vs = 2414.0
print("#   vs=%g" % vs)
state2 = GasState(gmodel)
flow = GasFlow(gmodel)
v2, vg = flow.normal_shock(state1, vs, state2)
print("#   v2=%g vg=%g" % (v2, vg))
print("#   state2: %s" % state2)

The same functions are available to a Lua script given to the gas-calc program.

-- Lua
gmodel = GasModel:new{'cea-air5species-gas-model.lua'}
state1 = GasState:new{gmodel}
state1.p = 125.0e3; state1.T = 300.0
gmodel:updateThermoFromPT(state1)
print("state1:"); printValues(state1)

print("normal shock, given shock speed")
Vs = 2414.0
state2, V2, Vg = gasflow.normal_shock(state1, Vs)
print("    V2=", V2, "Vg=", Vg)
print("    state2:"); printValues(state2)

Note that there are small but significant differences in calling the functions from Lua, compared with Python3. If you have not yet read the Gas Models User Guide, this is a good time to do so.

1. Installing the library

The gas models library for is part of a larger gas-dynamics toolkit and general getting started notes can be found at https://gdtk.uqcloud.net/docs/getting-started/prerequisites . There, you will see how to get a copy of the source code, and a list of what other software you will need to build and install the tool kit, and a collection of environment variables that need to be set.

To install the library and the gas-calc program, move to the gas source directory and use the make utility.

cd dgd/src/gas
make install

Note that the loadable library needs to be built with the DMD64 compiler and that you need the Foreign-Function-Interface extensions for your Python and Ruby interpreters. On a LinuxMint system this package is python-cffi.

So that the Python interpreter can find the installed library, set your environment variables with something like:

export DGD=$HOME/dgdinst
export PYTHONPATH=${PYTHONPATH}:${DGD}/lib
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${DGD}/lib

2. Gas model and state objects

A number of gas models are encoded in D-language modules and are available via a generic interface.

2.1. GasModel

# Python
gmodel = GasModel(file_name)
-- Lua
gmodel = GasModel:new{file_name}
file_name

string, no default
Specifies the name of the detailed gas model configuration file. This is a Lua format file, constructed as described in the Gas Models User Guide.

2.1.1. Properties

# Python
gmodel.id

The index to the underlying D-language gas model that is initialized during construction of the Python GasModel object.

# Python
gmodel.n_species
-- Lua
gmodel:nSpecies()

Is the number of chemical species in the gas model.

# Python
gmodel.species_names
-- Lua
gmodel:speciesName(isp)

In Python we get the list of the chemical species names in the gas model as a list of strings. In Lua, we specify the index for each species and get its name. The indices of the particular species may be useful for some of the method calls below.

# Python
gmodel.n_modes
-- Lua
gmodel.nModes()

Is the number of internal energy modes (separate to the thermal internal energy) in the gas model.

# Python
gmodel.mol_masses
-- Lua
gmodel:molMasses()

Is a list of molecular masses in units of kg/m^3.

2.1.2. Methods

# Python
gmodel.update_thermo_from_pT(gstate)
-- Lua
gmodel:updateThermoFromPT(gstate)

Given a GasState object, and assuming that its pressure, temperature and mass fractions are set, compute the other thermodynamic properties of the gas state. The Python function returns None.

# Python
gmodel.update_thermo_from_rhou(gstate)
-- Lua
gmodel:updateThermoFromRHOU(gstate)

Given a GasState object, and assuming that its density, internal energy and mass fractions are set, compute the other thermodynamic properties of the gas state. The Python function returns None.

# Python
gmodel.update_thermo_from_rhoT(gstate)
-- Lua
gmodel:updateThermoFromRHOT(gstate)

Given a GasState object, and assuming that its density, temperature and mass fractions are set, compute the other thermodynamic properties of the gas state. The Python function returns None.

# Python
gmodel.update_thermo_from_rhop(gstate)
-- Lua
gmodel:updateThermoFromRHOP(gstate)

Given a GasState object, and assuming that its density, pressure and mass fractions are set, compute the other thermodynamic properties of the gas state. The Python function returns None.

# Python
gmodel.update_thermo_from_ps(gstate, s)
-- Lua
gmodel:updateThermoFromPS(gstate, s)

Given a GasState object and a value of entropy, and assuming that gas state pressure and mass fractions are set, compute the other thermodynamic properties of the gas state. The units of entropy, s, are J/kg.K. The Python function returns None.

# Python
gmodel.update_thermo_from_hs(gstate, h, s)
-- Lua
gmodel:updateThermoFromHS(gstate, h, s)

Given a GasState object and values of enthalpy and entropy, and assuming that gas state mass fractions are set, compute the other thermodynamic properties of the gas state. The units of enthalpy, h, are J/kg and the units of entropy, s, are J/kg.K. The Python function returns None.

# Python
gmodel.update_sound_speed(gstate)
-- Lua
gmodel:updateSoundSpeed(gstate)

The underlying D-language gas model has the sound-speed calculation separate to the other calculations for other thermodynamic properties. This function reflects that separation, hovever, the other Python methods mentioned above actually do update the sound-speed along with the other thermodynamic properties of the gas state; the Lua methods do not. The Python function returns None.

# Python
gmodel.update_trans_coeffs(gstate)
-- Lua
gmodel:updateTransCoeffs(gstate)

Update the transport coefficients of viscosity and thermal conductivity. The Python function returns None.

# Python
gmodel.Cv(gstate)
-- Lua
gmodel:Cv(gstate)

Returns the specific heat capacity for a constant volume process, J/kg.K.

# Python
gmodel.Cp(gstate)
-- Lua
gmodel:Cp(gstate)

Returns the specific heat capacity for a constant pressure process, J/kg.K.

# Python
gmodel.dpdrho_const_T(gstate)
-- Lua
gmodel:dpdrhoConstT(gstate)

Returns the derivative. Equivalent to RT for a thermally perfect gas.

# Python
gmodel.R(gstate)
-- Lua
gmodel:R(gstate)

Returns the gas constant for the gas state. Units are J/kg.K.

# Python
gmodel.gamma(gstate)
-- Lua
gmodel:gamma(gstate)

Returns the ratio of specific heats for the gas state. Nondimensional.

# Python
gmodel.Prandtl(gstate)
-- Lua
gmodel:Prandtl(gstate)

Returns the ratio of momentum diffusivity to thermal diffusivity. Nondimensional.

# Python
gmodel.internal_energy(gstate)
-- Lua
gmodel:intEnergy(gstate)

Returns the full internal energy of the gas state. This is the sum of thermal internal energy and any other internal energy modes of the gas model. Units are J/kg.

# Python
gmodel.enthalpy(gstate)
-- Lua
gmodel:enthalpy(gstate)

Returns the specific enthalpy of the gas state, in J/kg.

# Python
gmodel.entropy(gstate)
-- Lua
gmodel:entropy(gstate)

Returns the specific entropy of the gas state, in J/kg.K.

# Python
gmodel.molecular_mass(gstate)
-- Lua
gmodel:molMass(gstate)

Returns the molecular mass of the gas state, in kg/m^3. This is most useful for chemically-reacting gases where the value will change with mixture fractions of the species.

# Python
gmodel.enthalpy_isp(gstate, isp)
-- Lua
gmodel:enthalpy(gstate, isp)

Returns the specific enthalpy for a particular chemical species, at index isp, of the gas state. Units are J/kg.

# Python
gmodel.entropy_isp(gstate, isp)
-- Lua
gmodel:entropy(gstate, isp)

Returns the specific entropy for a particular chemical species, at index isp, of the gas state. Units are J/kg.K.

# Python
gmodel.gibbs_free_energy_isp(gstate, isp)
-- Lua
gmodel:gibbsFreeEnergy(gstate, isp)

Returns the Gibbs Free Energy value for a particular chemical species, at index isp, of the gas state. Units are J/kg.

# Python
gmodel.massf2molef(massf)
-- Lua
gmodel:massf2molef(gstate)

Given the mass fractions of a gas mixture, returns the list of equivalent mole fractions. In Python, the mass-fraction values may be supplied in a dictionary. In Lua, the mass fractions are taken from the GasState object.

# Python
gmodel.molef2massf(molef)
-- Lua
gmodel:molef2massf(molef, gstate)

Given the mole fractions of a gas mixture, returns the list of equivalent mass fractions. The mole-fraction values may be supplied in a dictionary. In the Lua call, the table of mass fractions in the GasState object is also updated.

2.2. GasState

Any number of GasState objects may be constructed in the context of a GasModel object.

# Python
gstate = GasState(gmodel)
-- Lua
gstate = GasState:new{gmodel}

In Python, the GasState object retains a reference to the gas model used in its construction. In Lua, the GasState object is a Lua table with named entries.

2.2.1. Properties

# Python
gstate.id

The index to the underlying D-language gas state that is initialized during the construction of the Python GasState object.

# Python
gstate.rho
-- Lua
gstate.rho

Gas density, in kg/m^3. This property may be used in an expression or a new value may be assigned.

# Python
gstate.p
-- Lua
gstate.p

Gas pressure, in Pa. This property may be used in an expression or a new value may be assigned.

# Python
gstate.T
-- Lua
gstate.T

Gas temperature, in K. This property may be used in an expression or a new value may be assigned.

# Python
gstate.u
-- Lua
gstate.u

Thermal internal energy, in J/kg. This property may be used in an expression or a new value may be assigned.

# Python
gstate.a
-- Lua
gstate.a

Sound speed, m/s. This property is read-only.

# Python
gstate.k
-- Lua
gstate.k

Thermal conductivity, in W/m.K. This property is read-only.

# Python
gstate.mu
-- Lua
gstate.mu

Dynamic viscosity, Pa.s. This property is read-only.

# Python
gstate.massf
-- Lua
gstate.massf

In Python, this a list of the mass fractions of the chemical species. It may be assigned a list with all of the species mass fraction values in order. It may also be assigned a dictionary, with named entries. In the dictionary form, you need provide only the non-zero values. In any case, the mass fractions should sum to 1.0.

In Lua, it is a table with named entries.

# Python
gstate.massf_as_dict

Is a dictionary of named mass-fraction values. It is a read-only property. You may, however, assign to the massf property.

# Python
gstate.molef

Is a list of the mole fractions of the chemical species. It may be assigned a list with all of the species mass fraction values in order. It may also be assigned a dictionary, with named entries. In the dictionary form, you need provide only the non-zero values. In any case, the mole fractions should sum to 1.0.

# Python
gstate.molef_as_dict

Is a dictionary of named mole-fraction values. It is a read-only property. You may, however, assign to the molef property.

# Python
gstate.conc

Is a list of the concentrations, in mole/m^3, of the chemical species. It is a read-only property.

# Python
gstate.conc_as_dict

Is a dictionary of named concentration values. It is a read-only property.

# Python
gstate.u_modes
-- Lua
gstate.u_modes

Is a list of internal-energy values for a multi-temperature gas. Units are J/kg. When assigning a list, the full list must be supplied.

# Python
gstate.T_modes
-- Lua
gstate.T_modes

Is a list of temperature values, in K, for a multi-temperature gas. When assigning a list, the full list must be supplied.

# Python
gstate.k_modes
-- Lua
gstate.k_modes

Is a list of thermal diffusivity coefficient values, in W/m.K, for a multi-temperature gas. It is a read-only property.

# Python
gstate.ceaSavedData
-- Lua
gstate.ceaSavedData

Is a dictionary of the data saved from the call out to the CEA2 program that was made when updating the thermodynamic properties for the gas state of the equilibrium mixture. This property is specific to the CEAgas model. If it exists, it contains the entries:

"p"

static pressure, Pa

"rho"

density, kg/m^3

"u"

specific internal energy, J/kg

"h"

specific enthalpy, J/kg

"T"

temperature, K

"a"

sound speed, m/s

"Mmass"

average molecular mass of the equilibrium mixture, kg/mole

"Rgas"

effective gas constant, J/kg/K

"gamma"

effective ratio of specific heats

"Cp"

effective specific heat, constant pressure, J/kg

"s"

specific entropy, J/kg.K

"mu"

effective viscosity coefficient, Pa.s

"mass"

dictionary of mass-fraction values for the species in the equilibrium mixture.

2.2.2. Methods

# Python
gstate.copy_values(other_gstate)

Copy property values from the other_gstate object. It is assumed that the GasModel is the same for east of the GasState objects.

# Python
gstate.update_thermo_from_pT()

Assuming that its pressure, temperature and mass fractions are set, compute the other thermodynamic properties of the gas state. Returns None.

# Python
gstate.update_thermo_from_rhou()

Assuming that its density, internal energy and mass fractions are set, compute the other thermodynamic properties of the gas state. Returns None.

# Python
gstate.update_thermo_from_rhoT()

Assuming that its density, temperature and mass fractions are set, compute the other thermodynamic properties of the gas state. Returns None.

# Python
gstate.update_thermo_from_rhop()

Assuming that its density, pressure and mass fractions are set, compute the other thermodynamic properties of the gas state. Returns None.

# Python
gstate.update_thermo_from_ps(s)

Given a value of entropy, and assuming that gas state pressure and mass fractions are set, compute the other thermodynamic properties of the gas state. The units of entropy, s, are J/kg.K. Returns None.

# Python
gstate.update_thermo_from_hs(h, s)

Given values of enthalpy and entropy, and assuming that gas state mass fractions are set, compute the other thermodynamic properties of the gas state. The units of enthalpy, h, are J/kg and the units of entropy, s, are J/kg.K. Returns None.

# Python
gstate.update_sound_speed()

The underlying D-language gas model has the sound-speed calculation separate to the other calculations for other thermodynamic properties. This function reflects that separation, hovever, the other Python methods mentiond above actually do update the sound-speed along with the other thermodynamic properties of the gas state. Returns None.

# Python
gstate.update_trans_coeffs()

Update the transport coefficients of viscosity and thermal conductivity. Returns None.

2.2.3. Other properties

These are for the Python library. In Lua, you can access the same data via the GasModel methods.

# Python
gstate.Cv

Returns the specific heat capacity for a constant volume process, J/kg.K.

# Python
gstate.Cp

Returns the specific heat capacity for a constant pressure process, J/kg.K.

# Python
gstate.dpdrho_const_T

Returns the derivative. Equivalent to RT for a thermally perfect gas.

# Python
gstate.R

Returns the gas constant for the gas state. Units are J/kg.K.

# Python
gstate.gamma

Returns the ratio of specific heats for the gas state. Nondimensional.

# Python
gmodel.Prandtl(gstate)

Returns the ratio of momentum diffusivity to thermal diffusivity. Nondimensional.

# Python
gstate.internal_energy

Returns the full internal energy of the gas state. This is the sum of thermal internal energy and any other internal energy modes of the gas model. Units are J/kg.

# Python
gstate.enthalpy

Returns the specific enthalpy of the gas state, in J/kg.

# Python
gstate.entropy

Returns the specific entropy of the gas state, in J/kg.K.

# Python
gstate.molecular_mass

Returns the molecular mass of the gas state, in kg/m^3. This is most useful for chemically-reacting gases where the value will change with mixture fractions of the species.

# Python
gstate.enthalpy_isp(isp)

Returns the specific enthalpy for a particular chemical species, at index isp, of the gas state. Units are J/kg.

# Python
gstate.entropy_isp(isp)

Returns the specific entropy for a particular chemical species, at index isp, of the gas state. Units are J/kg.K.

# Python
gstate.gibbs_free_energy_isp(isp)

Returns the Gibbs Free Energy value for a particular chemical species, at index isp, of the gas state. Units are J/kg.

3. Thermochemical kinetics

If you have a gas model with several chemical species and/or with more than one temperature you may be interested in allowing the thermochemical processes to change the gas state in an otherwise isolated blob of gas.

Before trying the following functions, you should read the Reacting Gas Guide.

3.1. ThermochemicalReactor objects

# Python
reactor = ThermochemicalReactor(gmodel, filename1, filename2="")
-- Lua
reactor = ThermochemicalReactor:new{gasmodel=gmodel, filename1='fname1', filename2=''}
gmodel

GasModel object, no default
is a reference to a suitable gas model. Not all gas models will have associated reactors but some, such as the ThermallyPerfectGas model do.

filename1

string, no default.
File name for the detailed chemistry configuration file.

filename2

string, default: ""
File name for the second detailed thermochemical configuration file. Only a few files will require a second configuration file.

3.2. Methods

To update the gas state over a finite interval of time, call

# Python
reactor.update_state(gstate, t_interval, dt_suggest)
-- Lua
reactor:update_state(gstate, t_interval, dt_suggest)
gstate

GasState object, no default.
The gas state which will be altered. Because the hypothetical reactor is isolated, the density and internal energy of the blob of gas will remain fixed, while other thermochemical properties, including mass- and mole-fractions change.

t_interval

Float, no default.
The time interval, in seconds, over which to evolve the gas state.

dt_suggest

Float, default -1.0
The suggested time step size for the thermochemical update. The default value of -1.0 indicates to the reactor that we have no good idea and that it should select something suitable.

Returns the last successful time-step size, so that the value may be used in subsequent calls.

4. State-to-state flow processes

These functions are for computing simple processes involving the general gas models. In Python, the flow analysis functions are collected as methods of the GasFlow class. An object of this class needs to be constructed in the context of a particular gas model.

# Python
flow = GasFlow(gmodel)

In Lua, the functions are already available in the gas-calc program in a table called gasflow.

4.1. Normal shock

For shock processing when we want to restrict the processing to the ideal-gas behaviour, use the following function.

# Python
v2, vg = flow.ideal_shock(state1, vs, state2)
-- Lua
state2, v2, vg = gasflow.ideal_shock(state1, vs)

Parameters:

state1

GasState object, no default.
The initial gas state, before passing through the shock.

vs

Float, no default.
Speed of gas, in m/s, coming into the shock (in a shock stationary frame), or the speed of the shock into quiescent gas (lab frame).

state2

GasState object, no default.
The state of the gas after shock processing. In Python, you need to construct state2 first, then pass it into the function to have its values mutated.

v2

Float The post-shock gas speed, in m/s, relative to the shock front.

vg

Float The post-shock gas speed, in m/s, in the lab frame, for the case where the shock in moving into a quiescent gas.

For shock processing with more general, but still chemically-frozen, gas behaviour, use the following function.

# Python
v2, vg = flow.normal_shock(state1, vs, state2)
-- Lua
state2, v2, vg = gasflow.normal_shock(state1, vs)

Parameters:

state1

GasState object, no default.
The initial gas state, before passing through the shock.

vs

Float, no default.
Speed of gas, in m/s, coming into the shock (in a shock stationary frame), or the speed of the shock into quiescent gas (lab frame).

state2

GasState object, no default.
The state of the gas after shock processing. In Python, you need to construct state2 first, then pass it into the function to have its values mutated.

v2

Float The post-shock gas speed, in m/s, relative to the shock front.

vg

Float The post-shock gas speed, in m/s, in the lab frame, for the case where the shock in moving into a quiescent gas.

For the case where the pressure ratio is provided, use the function:

# Python
vs, v2, vg = flow.normal_shock_p2p1(state1, p2p1, state2)
-- Lua
vs, v2, vg = gasflow.normal_shock_p2p1(state1, p2p1)

Parameters:

state1

GasState object, no default.
The initial gas state, before passing through the shock.

p2p1

Float, no default.
Ratio of pressures p2/p1 across the shock.

state2

GasState object, no default for Python but not needed in Lua.
The state of the gas after shock processing.

vs

Float The incident shock speed, in m/s.

v2

Float The post-shock gas speed, in m/s, relative to the shock front.

vg

Float The post-shock gas speed, in m/s, in the lab frame, for the case where the shock in moving into a quiescent gas.

For a reflected shock, as would be observed in a shock tunnel, we have the function:

# Python
vr = flow.reflected_shock(state2, vg, state5)
-- Lua
state5, vr = gasflow.reflected_shock(state2, vg)

Parameters:

state1

GasState object, no default.
The state of the gas approaching the reflected-shock front.

vg

Float The speed of the incoming gas (in m/s) in the lab frame.

state5

GasState object, no default in Python.
The state of the gas after reflected-shock processing.

The function returns vr, the speed of the reflected shock (in m/s) in the lab frame. In Python, the values within the user-provided state5 are altered.

4.2. Reversible steady flow

Allow a gas to expand through a steady isentropic process, from stagnation to a lower pressure.

# Python
v = flow.expand_from_stagnation(state0, p_over_p0, state1)
-- Lua
state1, v = gasflow.expand_from_stagnation(state0, p_over_p0)

Parameters:

state0

GasState object, no default.
The initial stagnation state.

p_over_p0

Float, no default.
The pressure of the expanded gas divided by the stagnation pressure.

state1

GasState object, no default in Python.
The state of the gas after expansion. In Python, you need to construct state1 first and pass it into the function to have its values mutated.

v

The velocity (in m/s) of the expanded gas.

Allow a gas to expand through a steady isentropic process, from stagnation to a particular Mach number.

# Python
v = flow.expand_to_mach(state0, mach, state1)
-- Lua
state1, v = gasflow.expand_to_mach(state0, mach)

Parameters:

state0

GasState object, no default.
The initial stagnation state.

mach

Float, no default.
The Mach number of the expanded gas.

state1

GasState object, no default.
The state of the gas after expansion. Although you might expect state1 as output, in Python, you need to construct it first and pass it into the function to have its values mutated.

The function returns v. the velocity (in m/s) of the expanded gas. The Lua flavour also returns state1.

Given a free-stream, compute the corresponding stagnation condition.

# Python
flow.total_condition(state1, v1, state0)
-- Lua
state0 = gasflow.total_condition(state1, v1)

Parameters:

state1

GasState object, no default.
The free-stream state.

v1

Float, no default.
The velocity (in m/s) of the free stream.

state0

GasState object, no default in Python.
The stagnation state, following an isentropic compression from the free-stream state. In Python, you need to construct state0 first and pass it into the function to have its values mutated.

4.3. Pitot probe flow

Compute the state of gas at the stagnation point on a Pitot probe. For a subsonic free-stream flow, this will be the same as for an isentropic compression. For a supersonic flow, there will be a normal shock, followed by an isentropic compression.

# Python
flow.pitot_condition(state1, v1, state2pitot)
-- Lua
state2pitot = gasflow.pitot_condition(state1, v1)

Parameters:

state1

GasState object, no default.
The free-stream state.

v1

Float, no default.
The velocity (in m/s) of the free stream.

state2pitot

GasState object, no default.
The stagnation state at the probe tip, after compression from the free-stream state.

4.4. Steady flow in a duct

Steady, isentropic flow through a variable-area duct. Internally, this function iterates guesses for the pressure ratio, in order to keep mass-flux equal.

# Python
v2 = flow.steady_flow_with_area_change(state1, v1, area2_over_area1, state2, tol=1.0e-4)
-- Lua
state2, v2 = gasflow.steady_flow_with_area_change(state1, v1, area2_over_area1, tol)

Parameters:

state1

GasState object, no default.
The state at point 1 in the duct.

v1

Float, no default.
The velocity (in m/s) at point 1.

area2_over_area1

Float, no default.
The ratio of areas of the two points.

state2

GasState object, no default.
The gas state at point 2.

tol

Float, default 1.0e-4
Tolerance on the mass-flux error.

4.5. Unsteady reversible flow

For compression and expansion processes that travel as a wave, the analysis steps along a characteristic trajectory that traverses the wave and integrates the effects numerically.

# Python
v2 = flow.finite_wave_dp(state1, v1, characteristic, p2, state2, steps=100)
-- Lua
state2, v2 = gasflow.finite_wave_dp(state1, v1, characteristic, p2, steps)

Parameters:

state1

GasState object, no default.
The state before wave processing.

v1

Float, no default.
The velocity (in m/s) before wave processing. Positive velocities are to the right.

characteristic

string, no default.
Name of the characteristic trajectory that the integration process follows. Options are "cplus" and "cminus". If the unsteady processing wave is moving left through the gas, the integration follows a "cplus" characteristic trajectory (from the left initial state to the right final state).

p2

Float, no default.
The pressure (in Pa) after wave processing.

state2

GasState object, no default.
The gas state after wave processing.

steps

Int, default: 100
The pressure change is divided into a number of steps and the effects are integrated numerically.

v2

Float:
the velocity of the gas following wave processing.

For the cases where we know the velocity of the expanded gas, we can take steps in velocity to get to the expanded state.

# Python
v2 = flow.finite_wave_dv(state1, v1, characteristic, v2_target, state2, steps=100, t_min=200.0)
-- Lua
state2, v2 = gasflow.finite_wave_dv(state1, v1, characteristic, v2_target, steps, t_min)

Input:

state1

GasState object, no default.
The state before wave processing.

v1

Float, no default.
The velocity (in m/s) before wave processing.

characteristic

string, no default.
Name of the characteristic trajectory that the integration process follows. Options are "cplus" and "cminus". If the unsteady processing wave is moving left through the gas, the integration follows a "cplus" characteristic trajectory (from the left initial state to the right final state).

v2_target

Float, no default.
The expected velocity (in m/s) after wave processing.

state2

GasState object, no default.
The gas state after wave processing. Although you might expect state2 as output, you need to construct it first and pass it into the function to have its values mutated.

steps

Int, default: 100
The velocity change is divided into a number of steps and the effects are integrated numerically.

t_min

Float, default: 200.0
Minimum temperature (in degrees K) of the gas through the expansion. Because we are stepping in velocity, it is easy to demand a final velocity that can exceed the maximum velocity for a physically realizable expansion. A typical symptom of demanding too strong an expansion is a negative temperature for the expanded gas.

v2

Float: the velocity of the gas following wave processing.

4.6. Riemann problem

The Riemann problem is at the core of our larger-scale CFD codes. Left and Right gas states are allowed to interact at their contact surface. Processing of each initial state is via a left-running wave (into the Left state) and a right-running wave (into the Right state). The results of wave processing are two intermediate states (labelled star) that have a common pressure and velocity at the contact surface. Osher’s approximate Riemann solver assumes that both processing waves are isentropic.

# Python
pstar, wstar, wL, wR, velX0 = flow.osher_riemann(stateL, stateR, velL, velR, stateLstar, stateRstar, stateX0)

Input:

stateL

GasState object, no default.
The state on the left of the contact surface.

stateR

GasState object, no default.
The state on the right of the contact surface.

velL

Float, no default.
The velocity of the gas (in m/s) in the left initial state.

velR

Float, no default.
The velocity of the gas (in m/s) in the right initial state.

stateLstar

GasState object, no default.
The left intermediate state after wave processing.

stateRstar

GasState object, no default.
The right intermediate state after wave processing.

stateX0

GasState object, no default.
The interpolated state at the initial contact-surface location, after wave processing. As part of a flow simulation code, the details of this state may be used to compute the flux of mass, momentum and energy across the initial constact-surface location.

Although you might expect stateLstar and statRstar as output, you need to construct them first and pass them into the function to have their values mutated.

The function returns:

pstar

Float The common pressure at the contact surface between the intermediate states.

wstar

Float The common velocity at the contact surface between the intermediate states.

wL

Float The leading-edge wave speed of the left-moving wave. If the wave is a compression, this is the shock speed.

wR

Float The leading-edge wave speed of the right-moving wave. If the wave is a compression, this is the shock speed.

velX0

Float The velocity of the gas, interpolated at the initial location of the contact-surface.

4.7. Riemann subproblem for L1d

The Lagrangian flow solver has a specialized Riemann solver at its core.

# Python
pstar, wstar = flow.lrivp(stateL, stateR, velL, velR)

Input:

stateL

GasState object, no default.
The state on the left of the contact surface.

stateR

GasState object, no default.
The state on the right of the contact surface.

velL

Float, no default.
The velocity of the gas (in m/s) in the left initial state.

velR

Float, no default.
The velocity of the gas (in m/s) in the right initial state.

The function returns:

pstar

Float The common pressure at the contact surface between the intermediate states.

wstar

Float The common velocity at the contact surface between the intermediate states.

When the gas is up against a solid face of a piston, we have the contact-surface velocity as known and we need to compute just the gas pressure at the contact-surface.

# Python
pstar = flow.piston_at_left(stateR, velR, wstar)

Input:

stateR

GasState object, no default.
The state on the right of the contact surface.

velR

Float, no default.
The velocity of the gas (in m/s) in the right initial state.

wstar

Float, no default.
The velocity (in m/s) of the gas at the contact (piston) surface.

The function returns pstar (in Pa), the pressure at the contact surface.

# Python
pstar = flow.piston_at_right(stateL, velL, wstar)

Input:

stateL

GasState object, no default.
The state on the left of the contact surface.

velL

Float, no default.
The velocity of the gas (in m/s) in the left initial state.

wstar

Float, no default.
The velocity (in m/s) of the gas at the contact (piston) surface.

The function returns pstar (in Pa), the pressure at the contact surface.

4.8. Oblique shock

Oblique straight shocks are analysed by splitting the velocity into normal and tangential components. The shock angle, with respect to the initial stream direction, is beta. The streamline deflection angle is theta.

Given a shock angle, we can get the flow state after shock processing directly.

# Python
theta, v2 = flow.theta_oblique(state1, v1, beta, state2)
-- Lua
state2, theta, v2 = gasflow.theta_oblique(state1, v1, beta)

Parameters:

state1

GasState object, no default.
The state before shock wave processing.

v1

Float, no default.
The velocity of the gas (in m/s) before shock wave processing.

beta

Float, no default.
Angle, in radians, of the shock with respect to the initial flow direction.

state2

GasState object, no default.
The gas state after wave processing. Although you might expect state2 as output, you need to construct it first and pass it into the function to have its values mutated.

theta

Float the stream deflection angle (in radians)

v2

Float the speed of the gas in that deflected stream.

When you know the deflection angle and you want the shock angle, use the following function.

# Python
beta = flow.beta_oblique(state1, v1, theta)
-- Lua
beta = gasflow.beta_oblique(state1, v1, theta)

Input:

state1

GasState object, no default.
The state before shock wave processing.

v1

Float, no default.
The velocity of the gas (in m/s) before shock wave processing.

theta

Float, no default.
Deflection angle, in radians, of the streamlines through the shock.

The function returns shock angle beta for the weak shock solution for the given streamline deflection angle. The flow is assumed to remain supersonic following the shock. The strong-shock solution, resulting in subsonic downstream flow, would be sensitive the (unspecified) details of whatever is downstream and supporting the shock.

4.9. Conical shock

For the limits of thermochemically-frozen and thermochemical-equilibrium gases, there is a conical flow analysis for shock waves.

Given the free-stream condition and a conical shock angle, the radial flow conditions can be integrated from just after the shock to the supporting conical body. The axis of the supporting cone is aligned with the free-stream direction.

# Python
theta_c, v2_c = flow.theta_cone(state1, v1, beta, state_c)

Input:

state1

GasState object, no default.
The free-stream state, before shock wave processing.

v1

Float, no default.
The velocity of the gas (in m/s) in the free stream, before shock wave processing.

beta

Float, no default.
Angle, in radians, of the conical shock with respect to the initial flow direction.

state_c

GasState object, no default.
The gas state at the cone surface. Although you might expect state_c as output, you need to construct it first and pass it into the function to have its values mutated.

The function returns theta_c the stream deflection angle (in radians) at the cone surface and v2_c, the speed of the gas in that deflected stream up the conical surface.

When you know the deflecting cone angle and you want the shock angle, use the following function.

# Python
beta = flow.beta_cone(state1, v1, theta)

Input:

state1

GasState object, no default.
The free-stream state, before shock wave processing.

v1

Float, no default.
The velocity of the gas (in m/s) in the free stream, before shock wave processing.

theta

Float, no default.
Angle, in radians, of the deflecting cone.

The function returns shock angle beta for the weak shock solution. The flow is assumed to remain supersonic following the shock. A subsonic post-shock flow would be associated with a detached shock and the flow field would not match the assumed conical arrangement.

5. State-to-state processes (ideal gas)

If the calorically-perfect ideal gas model is sufficient for your analysis needs, there is simple set of ideal-gas relations collected into the eilmer.ideal_gas package.

The following functions do not use the generalized gas models but assume a gas bahaviour for fixed ratio of specific heats.

To get access to the functions, import the module into your Python script. For example:

# Python
import eilmer.ideal_gas_flow as igf
M = 2.0
print("Normal shock jump...")
print("Computed: M=%g: M2=%g, T2/T1=%g, p2/p1=%g, r2/r1=%g" %
      (M, igf.m2_shock(M), igf.T2_T1(M), igf.p2_p1(M), igf.r2_r1(M)))
print("Expected: M1=2, M2=0.5774, T2/T1=1.687, p2/p1=4.50, r2/r1=2.667")

In a Lua script given to the gas-calc program, the functions are already available in the table idealgasflow.

5.1. Isentropic/adiabatic steady flow

# Python
igf.A_Astar(M, g=1.4)
-- Lua
idealgasflow.A_Astar(M, g)

Input:

M

Float, no default. Mach number at area A, assuming sonic condition at area Astar

g

Float, default: 1.4
Ratio of specific heats

Returns area ratio, A/Astar, for an isentropic, quasi-one-dimensional flow.

# Python
igf.T0_T(M, g=1.4)
-- Lua
idealgasflow.T0_T(M, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns T0/T, the ratio of total temperature over static temperature for adiabatic flow.

# Python
igf.p0_p(M, g=1.4)
-- Lua
idealgasflow.p0_p(M, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns p0/p, the ratio of total pressure over static pressure for isentropic flow.

# Python
igf.r0_r(M, g=1.4)
-- Lua
idealgasflow.r0_r(M, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns rho0/rho, the ratio of stagnation density over local for isentropic flow.

5.2. Normal shock

# Python
igf.m2_shock(M1, g=1.4)
-- Lua
idealgasflow.m2_shock(M1, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns m2, Mach number following the shock processing.

# Python
igf.r2_r1(M1, g=1.4)
-- Lua
idealgasflow.r2_r1(M1, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns density ratio, r2/r1, across a normal shock.

# Python
igf.v2_v1(M1, g=1.4)
-- Lua
idealgasflow.u2_u1(M1, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns velocity ratio, v2/v1, across a normal shock.

# Python
igf.p2_p1(M1, g=1.4)
-- Lua
idealgasflow.p2_p1(M1, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns static pressure ratio, p2/p1, across a normal shock.

# Python
igf.T2_T1(M1, g=1.4)
-- Lua
idealgasflow.T2_T1(M1, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns static temperature ratio, T2/T1, across a normal shock.

# Python
igf.p02_p01(M1, g=1.4)
-- Lua
idealgasflow.p02_p01(M1, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns stagnation pressure ratio, p02/p01, across a normal shock.

# Python
igf.ds_Cv(M1, g=1.4)
-- Lua
idealgasflow.DS_Cv(M1, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns nondimensional entropy change, ds/Cv, across a normal shock.

# Python
igf.pitot_p(p1, M1, g=1.4)
-- Lua
idealgasflow.pitot_p(p1, M1, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns pitot pressure for a specified Mach number free-stream flow. The value will have the same units as input p1.

5.3. Flow with heat addition.

One-dimensional flow with heat addition is also known as Rayleigh-line flow. The flow starts with local Mach number, M, and (hypothetically) enough heat is added for the flow to reach sonic (Mstar=1) condition.

# Python
igf.T0_T0star(M, g=1.4)
-- Lua
idealgasflow.T0_T0star(M, g)

Input:

M

Float, no default. initial Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns T0/T0star where T0 is the total temperature of the initial flow and T0star is the total temperature that would be achieved if enough heat is added to get to the sonic condition.

# Python
igf.M_Rayleigh(T0T0star, g=1.4)
-- Lua
idealgasflow.M_Rayleigh(T0T0star, g)

Input:

T0T0star

Float, no default. T0/T0star where T0 is the total temperature of the initial flow and T0star is the total temperature that would be achieved if enough heat is added to get to the sonic condition.

g

Float, default: 1.4
Ratio of specific heats

Returns the initial Mach number, M, of the flow.

# Python
igf.T_Tstar(M, g=1.4)
-- Lua
idealgasflow.T_Tstar(M, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns T/Tstar where T is the static temperature of the initial flow and Tstar is the static temperature that would be achieved if enough heat is added to get to sonic condition.

# Python
igf.p_pstar(M, g=1.4)
-- Lua
idealgasflow.p_pstar(M, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns p/pstar where p is the static pressure of the initial flow and pstar is the static pressure that would be achieved if enough heat is added to get to sonic conditions.

# Python
igf.r_rstar(M, g=1.4)
-- Lua
idealgasflow.r_rstar(M, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns density ratio, rho/rhostar, where rho is the density of the initial flow and rhostar is the density that would be achieved if enough heat is added to get to sonic conditions.

# Python
igf.p0_p0star(M, g=1.4)
-- Lua
idealgasflow.p0_p0star(M, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns p0/p0star where p0 is the total pressure of the initial flow and p0star is the total pressure that would be achieved if enough heat is added to get to sonic conditions.

5.4. Supersonic turning

# Python
igf.PM1(M, g=1.4)
-- Lua
idealgasflow.PM1(M, g)

Input:

M

Float, no default. Mach number.

g

Float, default: 1.4
Ratio of specific heats

Returns Prandtl-Meyer function value, in radians.

# Python
igf.PM2(nu, g=1.4)
-- Lua
idealgasflow.PM2(nu, g)

Input:

nu

Float, no default. Prandtl-Meyer function value, in radians.

g

Float, default: 1.4
Ratio of specific heats

Returns corresponding Mach number.

-- Lua
MachAngle(M)

Returns the Mach angle in radians.

5.5. Oblique shock

# Python
igf.beta_obl(M1, theta, g=1.4, tol=1.0e-6)
-- Lua
idealgasflow.beta_obl(M1, theta, g, tol)

Input:

M1

Float, no default. Mach number of gas before the shock.

theta

Float, no default. Steamline deflection angle, in radians.

g

Float, default: 1.4
Ratio of specific heats

Returns shock angle, beta (in radians), with respect to the original stream direction.

# Python
igf.beta_obl2(M1, p2_p1, g=1.4)
-- Lua
idealgasflow.beta_obl2(M1, p2_p1, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

p2_p1

Float, no default.
Static pressure ratio, p2/p1, across the shock.

g

Float, default: 1.4
Ratio of specific heats

Returns shock angle, beta (in radians), with respect to the original stream direction.

# Python
igf.theta_obl(M1, beta, g=1.4)
-- Lua
idealgasflow.theta_obl(M1, beta, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

g

Float, default: 1.4
Ratio of specific heats

Returns deflection angle of the stream, theta (in radians).

# Python
igf.M2_obl(M1, beta, theta, g=1.4)
-- Lua
idealgasflow.M2_obl(M1, beta, theta, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

theta

Float, no default. Steamline deflection angle, in radians.

g

Float, default: 1.4
Ratio of specific heats

Returns M2, Mach number in flow after the shock.

# Python
igf.r2_r1_obl(M1, beta, g=1.4)
-- Lua
idealgasflow.r2_r1_obl(M1, beta, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

g

Float, default: 1.4
Ratio of specific heats

Returns density ratio, rho2/rho1 across an oblique shock.

# Python
igf.vn2_vn1_obl(M1, beta, g=1.4)
-- Lua
idealgasflow.Vn2_Vn1_obl(M1, beta, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

g

Float, default: 1.4
Ratio of specific heats

Returns normal-velocity ratio, vn1/vn2, across an oblique shock.

# Python
igf.v2_v1_obl(M1, beta, g=1.4)
-- Lua
idealgasflow.V2_V1_obl(M1, beta, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

g

Float, default: 1.4
Ratio of specific heats

Returns flow-speed ratio, v2/v1, across an oblique shock.

# Python
igf.p2_p1_obl(M1, beta, g=1.4)
-- Lua
idealgasflow.p2_p1_obl(M1, beta, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

g

Float, default: 1.4
Ratio of specific heats

Returns static pressure ratio, p2/p1, across an oblique shock.

# Python
igf.T2_T1_obl(M1, beta, g=1.4)
-- Lua
idealgasflow.T2_T1_obl(M1, beta, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

g

Float, default: 1.4
Ratio of specific heats

Returns static temperature ratio, T2/T1, across an oblique shock.

# Python
igf.p02_p01_obl(M1, beta, g=1.4)
-- Lua
idealgasflow.p02_p01_obl(M1, beta, g)

Input:

M1

Float, no default. Mach number of gas before the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

g

Float, default: 1.4
Ratio of specific heats

Returns ratio of stagnation pressures, p02/p01, across an oblique shock.

5.6. Taylor-Maccoll cone flow

Compute the cone-surface angle and conditions given the shock wave angle. The computation starts with the oblique-shock jump and then integrates across theta until V_theta goes through zero. The cone surface corresponds to V_theta == 0.

# Python
igf.theta_cone(V1, p1, T1, beta, R=287.1, g=1.4)
-- Lua
idealgasflow.theta_cone(V1, p1, T1, beta, R, g)

Input:

V1

Float, no default. Speed of gas (in m/s) entering the shock.

p1

Float, no default. Static pressure of gas (in Pa) entering the shock.

T1

Float, no default. Static temperature of gas (in K) entering the shock.

beta

Float, no default.
Shock angle, in radians, relative to the original stream direction.

R

Float, default: 287.1
Gas constant, in J/kg.K

g

Float, default: 1.4
Ratio of specific heats

Returns tuple of (theta_c, V_c, p_c, T_c).

theta_c

stream deflection angle, in radians

V_c

the cone-surface speed of gas, in m/s

p_c

the cone-surface pressure, in Pa

T_c

the cone-surface static temperature, in K

# Python
igf.beta_cone(V1, p1, T1, theta, R=287.1, g=1.4)
-- Lua
idealgasflow.beta_cone(V1, p1, T1, theta, R, g)

Input:

V1

Float, no default. Speed of gas (in m/s) entering the shock.

p1

Float, no default. Static pressure of gas (in Pa) entering the shock.

T1

Float, no default. Static temperature of gas (in K) entering the shock.

theta

Float, no default.
Cone deflection angle, in radians.

R

Float, default: 287.1
Gas constant, in J/kg.K

g

Float, default: 1.4
Ratio of specific heats

Returns beta, the shock wave angle (in radians) with respect to the free-stream flow direction.

# Python
igf.beta_cone2(M1, theta, R=287.1, g=1.4)
-- Lua
idealgasflow.beta_cone2(M1, theta, R, g)

Input:

M1

Float, no default. Mach number of gas entering the shock.

theta

Float, no default.
Cone deflection angle, in radians.

R

Float, default: 287.1
Gas constant, in J/kg.K

g

Float, default: 1.4
Ratio of specific heats

Returns beta, the shock wave angle (in radians) with respect to the free-stream flow direction.