Skip to content

models.feed_systems.components

Static, immutable descriptions of the physical components a feed-system cycle is built from. The classes in this sub-package do not contain integration state and never mutate during a simulation — they sit alongside propellant definitions as part of the engine configuration. Cycle implementations in machwave.models.feed_systems.cycles read these specifications and combine them with the live tank state and chamber conditions to compute mass flow, head rise, and shaft power.

Every spec is implemented as a @dataclass(frozen=True, kw_only=True) with __post_init__ validation, mirroring the convention used by ThermochemicalProperties. Construction with an out-of-range value raises ValueError at the call site rather than producing nonsensical numbers downstream.

Specs that carry property curves (e.g. pump head versus volumetric flow, turbine efficiency versus pressure ratio) wrap their tabulated data in machwave.core.interpolation.BoundedCubicSpline, which raises rather than extrapolating outside the calibrated knots.

When you need which spec

Cycle topology Needs Why
Pressure-fed (stacked, regulated, blowdown) nothing in this package The injector orifice equation and tank pressure are sufficient.
Electric-pump PumpSpec Each pump still needs design-point data even though the drive is electric, because head rise is interpolated from the pump curve.
Gas-generator PumpSpec, TurbineSpec, GasGeneratorSpec The gas generator burns a small fraction of the propellants to drive the turbine, which in turn drives the pumps.
Expander PumpSpec, TurbineSpec, RegenerativeJacketSpec Heat absorbed by the coolant in the jacket vaporises one propellant; that vapor drives the turbine.
Staged combustion PumpSpec, TurbineSpec, GasGeneratorSpec (as preburner), RegenerativeJacketSpec The full pre-combusted flow is routed through the turbine and then into the main chamber.

See Sutton & Biblarz, Rocket Propulsion Elements (Wiley, 2017), chapter 10, and Huzel & Huang, Modern Engineering for Design of Liquid-Propellant Rocket Engines (AIAA, 1992), chapter 6, for the underlying engine-cycle theory these specs describe.


PumpSpec

Captures a propellant pump at its design point. The fields are deliberately limited to what a cycle integrator needs to evaluate head rise and shaft power from a single operating point — anything that varies with operating condition (head-flow curve, NPSH margin) belongs in a BoundedCubicSpline and stored alongside the spec by the cycle that owns it.

Field Units Constraint
name Free-form identifier used in logs and reports.
isentropic_efficiency \(\eta_p \in (0, 1]\)
pressure_rise Pa Strictly positive
volumetric_flow_design m³/s Strictly positive
shaft_speed_design rad/s Strictly positive

Shaft power at the design point follows directly from the fields, assuming an incompressible working fluid:

\[ \dot{W}_{\text{shaft}} = \frac{\dot{V} \cdot \Delta P}{\eta_p} \]

TurbineSpec

Captures a turbine at its design point. Cycle integrators evaluate the specific work extracted from the working fluid using the inlet temperature and pressure ratio, then deliver the resulting shaft power to the coupled pump(s).

Field Units Constraint
name Free-form identifier.
isentropic_efficiency \(\eta_t \in (0, 1]\)
pressure_ratio \(\pi_t > 1\)
inlet_temperature_design K Strictly positive
mass_flow_design kg/s Strictly positive

Isentropic specific work for a perfect gas across the turbine:

\[ w_t = c_p \cdot T_{t,\text{in}} \cdot \left[1 - \pi_t^{-(\gamma - 1)/\gamma}\right] \cdot \eta_t \]

mass_flow_design is recorded for sizing checks: the cycle solver verifies that the working-fluid mass flow it computes (for a gas generator, the burned fraction; for an expander, the regen flow) stays close to the design point used to specify the turbine.


GasGeneratorSpec

Describes the gas generator that drives the turbine in a gas-generator-cycle engine or the preburner in a staged-combustion engine. The defining design choice is the operating mixture ratio, which is typically held well off-stoichiometric so the combustion-product temperature stays below the metal limits of the downstream turbine (whether uncooled or actively cooled).

Field Units Constraint
name Free-form identifier.
mixture_ratio Strictly positive (oxidizer/fuel mass ratio).
chamber_pressure Pa Strictly positive
gas_temperature K Strictly positive
mass_flow kg/s Strictly positive

Cooled, uncooled, and research configurations operate over a wide temperature range, so gas_temperature is only checked for physical positivity; the caller is responsible for selecting a value compatible with the turbine they are driving.


RegenerativeJacketSpec

Describes a regenerative cooling jacket wrapping the combustion chamber and nozzle. One propellant — typically the fuel, sometimes the oxidizer in oxidizer-rich cycles — is routed through cooling passages to absorb heat from the chamber walls before injection. The jacket therefore acts simultaneously as a heat exchanger and a pressure-loss component in the feed train.

Field Units Constraint
name Free-form identifier.
pressure_drop Pa Strictly positive
coolant_temperature_rise K Strictly positive
heat_pickup W Non-negative

heat_pickup and coolant_temperature_rise are not independent — once a coolant mass flow is fixed they are linked by \(\dot{Q} = \dot{m} \cdot c_p \cdot \Delta T\). Both are stored because the cycle solver needs heat_pickup to compute the turbine inlet enthalpy in an expander cycle, and coolant_temperature_rise to verify the jacket is not over-pushed thermally.


machwave.models.feed_systems.components

Shared component specifications consumed by feed-system cycle implementations.

GasGeneratorSpec dataclass

Gas generator driving a turbopump turbine.

Attributes:

Name Type Description
name str

Identifier used in logs and reports.

mixture_ratio float

Oxidizer to fuel mass ratio in the gas generator (>0).

chamber_pressure float

Combustion chamber pressure of the gas generator [Pa] (>0).

gas_temperature float

Combustion total temperature delivered to the turbine inlet [K] (>0).

mass_flow float

Total propellant mass flow through the gas generator [kg/s] (>0).

Raises:

Type Description
ValueError

If any field is outside its valid physical range.

Source code in machwave/models/feed_systems/components/gas_generator.py
@dataclasses.dataclass(frozen=True, kw_only=True)
class GasGeneratorSpec:
    """
    Gas generator driving a turbopump turbine.

    Attributes:
        name: Identifier used in logs and reports.
        mixture_ratio: Oxidizer to fuel mass ratio in the gas generator (>0).
        chamber_pressure: Combustion chamber pressure of the gas generator [Pa] (>0).
        gas_temperature: Combustion total temperature delivered to the turbine inlet
            [K] (>0).
        mass_flow: Total propellant mass flow through the gas generator [kg/s] (>0).

    Raises:
        ValueError: If any field is outside its valid physical range.
    """

    name: str
    mixture_ratio: float
    chamber_pressure: float
    gas_temperature: float
    mass_flow: float

    def __post_init__(self) -> None:
        """Validate that every field lies in its physical range."""
        if self.mixture_ratio <= 0.0:
            raise ValueError(
                f"mixture_ratio must be strictly positive, got {self.mixture_ratio}"
            )
        if self.chamber_pressure <= 0.0:
            raise ValueError(
                "chamber_pressure must be strictly positive, "
                f"got {self.chamber_pressure}"
            )
        if self.gas_temperature <= 0.0:
            raise ValueError(
                f"gas_temperature must be strictly positive, got {self.gas_temperature}"
            )
        if self.mass_flow <= 0.0:
            raise ValueError(
                f"mass_flow must be strictly positive, got {self.mass_flow}"
            )

__post_init__()

Validate that every field lies in its physical range.

Source code in machwave/models/feed_systems/components/gas_generator.py
def __post_init__(self) -> None:
    """Validate that every field lies in its physical range."""
    if self.mixture_ratio <= 0.0:
        raise ValueError(
            f"mixture_ratio must be strictly positive, got {self.mixture_ratio}"
        )
    if self.chamber_pressure <= 0.0:
        raise ValueError(
            "chamber_pressure must be strictly positive, "
            f"got {self.chamber_pressure}"
        )
    if self.gas_temperature <= 0.0:
        raise ValueError(
            f"gas_temperature must be strictly positive, got {self.gas_temperature}"
        )
    if self.mass_flow <= 0.0:
        raise ValueError(
            f"mass_flow must be strictly positive, got {self.mass_flow}"
        )

PumpSpec dataclass

Propellant pump used by turbopump cycles.

Attributes:

Name Type Description
name str

Identifier used in logs and reports.

isentropic_efficiency float

Ratio of isentropic enthalpy rise to actual enthalpy rise. Must lie between 0 and 1.

pressure_rise float

Pressure rise across the pump [Pa] (>0).

volumetric_flow_design float

Volumetric flow through the pump [m^3/s] (>0).

shaft_speed_design float

Shaft angular speed [rad/s] (>0).

Raises:

Type Description
ValueError

If any field is outside its valid physical range.

Source code in machwave/models/feed_systems/components/pump.py
@dataclasses.dataclass(frozen=True, kw_only=True)
class PumpSpec:
    """
    Propellant pump used by turbopump cycles.

    Attributes:
        name: Identifier used in logs and reports.
        isentropic_efficiency: Ratio of isentropic enthalpy rise to actual
            enthalpy rise. Must lie between 0 and 1.
        pressure_rise: Pressure rise across the pump [Pa] (>0).
        volumetric_flow_design: Volumetric flow through the pump
            [m^3/s] (>0).
        shaft_speed_design: Shaft angular speed [rad/s] (>0).

    Raises:
        ValueError: If any field is outside its valid physical range.
    """

    name: str
    isentropic_efficiency: float
    pressure_rise: float
    volumetric_flow_design: float
    shaft_speed_design: float

    def __post_init__(self) -> None:
        """Validate that every field lies in its physical range."""
        if not (0.0 < self.isentropic_efficiency <= 1.0):
            raise ValueError(
                "isentropic_efficiency must be in the interval (0, 1], "
                f"got {self.isentropic_efficiency}"
            )
        if self.pressure_rise <= 0.0:
            raise ValueError(
                f"pressure_rise must be strictly positive, got {self.pressure_rise}"
            )
        if self.volumetric_flow_design <= 0.0:
            raise ValueError(
                "volumetric_flow_design must be strictly positive, "
                f"got {self.volumetric_flow_design}"
            )
        if self.shaft_speed_design <= 0.0:
            raise ValueError(
                "shaft_speed_design must be strictly positive, "
                f"got {self.shaft_speed_design}"
            )

__post_init__()

Validate that every field lies in its physical range.

Source code in machwave/models/feed_systems/components/pump.py
def __post_init__(self) -> None:
    """Validate that every field lies in its physical range."""
    if not (0.0 < self.isentropic_efficiency <= 1.0):
        raise ValueError(
            "isentropic_efficiency must be in the interval (0, 1], "
            f"got {self.isentropic_efficiency}"
        )
    if self.pressure_rise <= 0.0:
        raise ValueError(
            f"pressure_rise must be strictly positive, got {self.pressure_rise}"
        )
    if self.volumetric_flow_design <= 0.0:
        raise ValueError(
            "volumetric_flow_design must be strictly positive, "
            f"got {self.volumetric_flow_design}"
        )
    if self.shaft_speed_design <= 0.0:
        raise ValueError(
            "shaft_speed_design must be strictly positive, "
            f"got {self.shaft_speed_design}"
        )

RegenerativeJacketSpec dataclass

Regenerative cooling component around the chamber and nozzle.

Attributes:

Name Type Description
name str

Identifier used in logs and reports.

pressure_drop float

Total coolant pressure drop across the jacket [Pa] (>0).

coolant_temperature_rise float

Coolant total temperature rise from jacket inlet to outlet [K] (>0).

heat_pickup float

Heat power absorbed by the coolant across the jacket [W] (>=0).

Raises:

Type Description
ValueError

If any field is outside its valid physical range.

Source code in machwave/models/feed_systems/components/regenerative_jacket.py
@dataclasses.dataclass(frozen=True, kw_only=True)
class RegenerativeJacketSpec:
    """
    Regenerative cooling component around the chamber and nozzle.

    Attributes:
        name: Identifier used in logs and reports.
        pressure_drop: Total coolant pressure drop across the jacket [Pa] (>0).
        coolant_temperature_rise: Coolant total temperature rise from jacket
            inlet to outlet [K] (>0).
        heat_pickup: Heat power absorbed by the coolant across the jacket [W] (>=0).

    Raises:
        ValueError: If any field is outside its valid physical range.
    """

    name: str
    pressure_drop: float
    coolant_temperature_rise: float
    heat_pickup: float

    def __post_init__(self) -> None:
        """Validate that every field lies in its physical range."""
        if self.pressure_drop <= 0.0:
            raise ValueError(
                f"pressure_drop must be strictly positive, got {self.pressure_drop}"
            )
        if self.coolant_temperature_rise <= 0.0:
            raise ValueError(
                "coolant_temperature_rise must be strictly positive, "
                f"got {self.coolant_temperature_rise}"
            )
        if self.heat_pickup < 0.0:
            raise ValueError(
                f"heat_pickup must be non-negative, got {self.heat_pickup}"
            )

__post_init__()

Validate that every field lies in its physical range.

Source code in machwave/models/feed_systems/components/regenerative_jacket.py
def __post_init__(self) -> None:
    """Validate that every field lies in its physical range."""
    if self.pressure_drop <= 0.0:
        raise ValueError(
            f"pressure_drop must be strictly positive, got {self.pressure_drop}"
        )
    if self.coolant_temperature_rise <= 0.0:
        raise ValueError(
            "coolant_temperature_rise must be strictly positive, "
            f"got {self.coolant_temperature_rise}"
        )
    if self.heat_pickup < 0.0:
        raise ValueError(
            f"heat_pickup must be non-negative, got {self.heat_pickup}"
        )

TurbineSpec dataclass

Turbine used by turbopump cycles.

Attributes:

Name Type Description
name str

Identifier used in logs and reports.

isentropic_efficiency float

Ratio of actual specific work extracted to the isentropic specific work available across the turbine. Must be between 0 and 1.

pressure_ratio float

Ratio of turbine inlet total pressure to outlet total pressure. Greater than 1.

inlet_temperature_design float

Total temperature at the turbine inlet [K] (>0).

mass_flow_design float

Mass flow through the turbine [kg/s] (>0).

Raises:

Type Description
ValueError

If any field is outside its valid physical range.

Source code in machwave/models/feed_systems/components/turbine.py
@dataclasses.dataclass(frozen=True, kw_only=True)
class TurbineSpec:
    """
    Turbine used by turbopump cycles.

    Attributes:
        name: Identifier used in logs and reports.
        isentropic_efficiency: Ratio of actual specific work extracted to the
            isentropic specific work available across the turbine. Must be between 0
            and 1.
        pressure_ratio: Ratio of turbine inlet total pressure to outlet total
            pressure. Greater than 1.
        inlet_temperature_design: Total temperature at the turbine inlet [K] (>0).
        mass_flow_design: Mass flow through the turbine [kg/s] (>0).

    Raises:
        ValueError: If any field is outside its valid physical range.
    """

    name: str
    isentropic_efficiency: float
    pressure_ratio: float
    inlet_temperature_design: float
    mass_flow_design: float

    def __post_init__(self) -> None:
        """Validate that every field lies in its physical range."""
        if not (0.0 < self.isentropic_efficiency <= 1.0):
            raise ValueError(
                "isentropic_efficiency must be in the interval (0, 1], "
                f"got {self.isentropic_efficiency}"
            )
        if self.pressure_ratio <= 1.0:
            raise ValueError(
                "pressure_ratio must be strictly greater than one, "
                f"got {self.pressure_ratio}"
            )
        if self.inlet_temperature_design <= 0.0:
            raise ValueError(
                "inlet_temperature_design must be strictly positive, "
                f"got {self.inlet_temperature_design}"
            )
        if self.mass_flow_design <= 0.0:
            raise ValueError(
                "mass_flow_design must be strictly positive, "
                f"got {self.mass_flow_design}"
            )

__post_init__()

Validate that every field lies in its physical range.

Source code in machwave/models/feed_systems/components/turbine.py
def __post_init__(self) -> None:
    """Validate that every field lies in its physical range."""
    if not (0.0 < self.isentropic_efficiency <= 1.0):
        raise ValueError(
            "isentropic_efficiency must be in the interval (0, 1], "
            f"got {self.isentropic_efficiency}"
        )
    if self.pressure_ratio <= 1.0:
        raise ValueError(
            "pressure_ratio must be strictly greater than one, "
            f"got {self.pressure_ratio}"
        )
    if self.inlet_temperature_design <= 0.0:
        raise ValueError(
            "inlet_temperature_design must be strictly positive, "
            f"got {self.inlet_temperature_design}"
        )
    if self.mass_flow_design <= 0.0:
        raise ValueError(
            "mass_flow_design must be strictly positive, "
            f"got {self.mass_flow_design}"
        )