Skip to content

ensim.core.engine#

The entry point for engine analysis: an operating point in, chamber state and performance out. See the Python API page for examples and nozzle expansion for the model.

Engine analysis in one call: chamber equilibrium, then nozzle performance.

>>> from ensim.core.engine import EngineInputs, analyze_engine
>>> result = analyze_engine(EngineInputs("RP-1", "LOX", of_ratio=2.6,
...                                      chamber_pressure=7e6, expansion_ratio=25))
>>> round(result.vacuum.isp)  # doctest: +SKIP
326

Propellants are named by the keys of :data:ensim.core.propellants.PROPELLANTS (LH2, LOX, RP-1, NTO, ...) and enter the chamber in their storage state. Any other name is looked up in the thermo database and treated as a gas.

The chamber composition comes from Gibbs energy minimisation. The nozzle expands that composition frozen, with temperature-dependent heat capacity (:mod:ensim.core.frozen_flow); this matches NASA CEA's frozen rocket problem and slightly understates Isp compared with shifting equilibrium.

Efficiencies scale the ideal result: c* by eta_cstar, the thrust coefficient by eta_cf, and the momentum term by the conical divergence factor (1 + cos alpha) / 2.

EngineInputs dataclass #

Operating point of a bipropellant engine. SI units.

EngineResult dataclass #

Chamber state and nozzle performance at three back pressures.

performance_at #

performance_at(ambient_pressure: float) -> PerformanceResult | None

Performance at another back pressure; None if the flow cannot stay choked.

to_dict #

to_dict() -> dict[str, Any]

Plain-JSON representation (SI units).

analyze_engine #

analyze_engine(inputs: EngineInputs, database: SpeciesDatabase | None = None) -> EngineResult

Solve the chamber equilibrium and the nozzle for inputs.

Parameters:

Name Type Description Default
inputs EngineInputs

Operating point.

required
database SpeciesDatabase | None

Species data; the packaged NASA Glenn set by default.

None

Raises:

Type Description
KeyError

A propellant is not in the database.

ConvergenceError

The equilibrium solver did not converge.

ValueError

The operating ambient pressure is too high for choked flow.

Building blocks#

frozen_flow #

Frozen-composition nozzle expansion with temperature-dependent heat capacity.

The chamber mixture keeps its composition and expands isentropically: s(T, p) = s_chamber, with s and h from the NASA polynomials of every product species. The throat is where the mass flux rho*v peaks, and the exit pressure follows from A_e/A_t = (rho v)_t / (rho v)_e. This is NASA CEA's "frozen" rocket problem; unlike the constant-gamma relations in :mod:ensim.core.propulsion, it keeps the drop of cp as the gas cools.

References

Gordon & McBride, NASA RP-1311 (1994), part I, section 6.

FrozenStation dataclass #

Flow state at one nozzle station, per unit mass of propellant.

FrozenNozzle dataclass #

Ideal (loss-free) frozen expansion to one area ratio.

frozen_nozzle #

frozen_nozzle(equilibrium: EquilibriumResult, database: SpeciesDatabase, area_ratio: float) -> FrozenNozzle

Expand the chamber state of equilibrium to area_ratio with frozen composition.

frozen_profile #

frozen_profile(equilibrium: EquilibriumResult, database: SpeciesDatabase, area_ratios: ndarray, supersonic: ndarray) -> dict[str, np.ndarray]

Flow state at stations of known A/A*, subsonic or supersonic per station.

The isentrope is tabulated once on a fine temperature grid and each station interpolated in ln(A/A*). Returns arrays pressure, temperature, mach and velocity.

geometry #

Advanced Nozzle Geometry - Rao Bell Contour.

Implements the Rao parabolic approximation for optimum thrust bell nozzle profiles.

ChamberContour dataclass #

Wall of a thrust chamber from injector face to nozzle exit.

x is measured from the throat (negative upstream); r is the wall radius. supersonic flags stations downstream of the throat.

chamber_contour #

chamber_contour(throat_area: float, expansion_ratio: float, contraction_ratio: float = 4.0, characteristic_length: float = 1.0, convergence_angle: float = 30.0, percent_bell: float = 80.0, n_points: int = 160) -> ChamberContour

Cylinder, conical convergence, throat arc and Rao bell.

The cylinder length is chosen so that the chamber volume up to the throat equals L* times the throat area. The upstream throat arc has radius 1.5 Rt (Huzel & Huang).

generate_bell_contour #

generate_bell_contour(throat_radius: float, expansion_ratio: float, theta_n: float = 35.0, theta_e: float = 8.0, percent_bell: float = 80.0, n_points: int = 100) -> NozzleContour

Generate Rao parabolic bell nozzle contour.

Uses the parabolic approximation method by G.V.R. Rao (1958).

Parameters:

Name Type Description Default
throat_radius float

Throat radius (m)

required
expansion_ratio float

Exit area ratio (Ae/At)

required
theta_n float

Initial expansion angle at throat (degrees)

35.0
theta_e float

Exit angle (degrees)

8.0
percent_bell float

Nozzle length as percent of 15° cone

80.0
n_points int

Number of contour points

100

Returns:

Type Description
NozzleContour

NozzleContour with full geometry definition

Reference

Rao, G.V.R. "Exhaust Nozzle Contour for Optimum Thrust", Jet Propulsion, Vol. 28, 1958, pp. 377-382.

analysis #

Reduced frozen-gas nozzle parameter sweeps.

EngineSweep dataclass #

Full engine analysis repeated over one input.

sweep_engine #

sweep_engine(inputs: EngineInputs, parameter: str, values: Sequence[float] | ndarray, progress: Callable[[float], None] | None = None, cancel: Callable[[], bool] | None = None) -> EngineSweep

Re-run :func:ensim.core.engine.analyze_engine for each value of one input.

Unlike :func:run_sweep, chamber composition and temperature are solved again at every point, so O/F and pressure sweeps are meaningful.

Parameters:

Name Type Description Default
inputs EngineInputs

Baseline :class:~ensim.core.engine.EngineInputs.

required
parameter str

"of_ratio", "chamber_pressure" (Pa) or "expansion_ratio".

required
values Sequence[float] | ndarray

Values of the parameter.

required
progress Callable[[float], None] | None

Optional callback(fraction).

None
cancel Callable[[], bool] | None

Optional callable() -> bool; True stops the sweep.

None