Skip to content

models.feed_systems

Feed-system models for biliquid rocket engines. The package describes how propellant is delivered from the tanks to the combustion chamber, and is organised around three concerns:

Concern Where it lives What it contains
Contract feed_systems.base The abstract FeedSystem interface every cycle must satisfy.
Cycle implementations feed_systems.cycles One module per cycle topology (pressure-fed today; electric-pump, gas-generator, expander, staged-combustion to follow).
Shared component descriptions feed_systems.components Static descriptions of pumps, turbines, gas generators, regenerative jackets, plus a tabulated-curve helper that cycle implementations consume.
Tank thermodynamics feed_systems.tank Two-phase tank model backed by CoolProp.

The FeedSystem contract

Every cycle implementation extends FeedSystem and exposes four methods used by the simulation loop:

  • get_mass_flow_ox(chamber_pressure, *, injector, oxidizer_mass) -> float
  • get_mass_flow_fuel(chamber_pressure, *, injector, fuel_mass, oxidizer_mass) -> float
  • get_oxidizer_tank_pressure(*, oxidizer_mass) -> float
  • get_fuel_tank_pressure(*, oxidizer_mass, fuel_mass) -> float

The mass-flow methods take a BipropellantInjector and delegate the orifice dispatch to it. The feed system is responsible for computing the upstream pressure (tank state, piston losses, pump discharge); the injector owns the orifice physics (discharge coefficient, area, and the per-side MassFlowModel that selects between single-phase incompressible and homogeneous-equilibrium two-phase flow). This split lets pump-fed cycles substitute a different upstream-pressure source without touching orifice physics.

The concrete propellant mass-flow consumer is machwave.simulation.biliquid.states.BiliquidEngineState.run_timestep, which calls these methods once per integration step with the current chamber_pressure and the BipropellantInjector from the thrust chamber.

Public surface

Importing from machwave.models.feed_systems exposes the abstract base, every concrete cycle, and the components sub-package:

from machwave.models.feed_systems import (
    FeedSystem,
    StackedTankPressureFedFeedSystem,
    components,
)

pump_spec = components.PumpSpec(
    name="oxidizer pump",
    isentropic_efficiency=0.7,
    pressure_rise=5.0e6,
    volumetric_flow_design=2.0e-3,
    shaft_speed_design=3000.0,
)

The top-level machwave package additionally re-exports feed_systems as a shortcut, so from machwave import feed_systems and feed_systems.StackedTankPressureFedFeedSystem work identically.

machwave.models.feed_systems

FeedSystem

Bases: ABC

Abstract base class for a bipropellant feed system in a biliquid rocket engine.

Source code in machwave/models/feed_systems/base.py
class FeedSystem(ABC):
    """Abstract base class for a bipropellant feed system in a biliquid rocket engine."""

    def __init__(self, fuel_tank: tank.Tank, oxidizer_tank: tank.Tank):
        """
        Initialize the FeedSystem with associated tank objects.

        Args:
            fuel_tank: Instance representing the fuel tank.
            oxidizer_tank: Instance representing the oxidizer tank.
        """
        self.fuel_tank = fuel_tank
        self.oxidizer_tank = oxidizer_tank

    def get_initial_propellant_mass(self) -> float:
        """Compute and return the initial propellant mass in the system [kg]."""
        return self.fuel_tank.initial_fluid_mass + self.oxidizer_tank.initial_fluid_mass

    @abstractmethod
    def get_mass_flow_ox(
        self,
        chamber_pressure: float,
        *,
        injector: injector_models.BipropellantInjector,
        oxidizer_mass: float,
    ) -> float:
        """
        Compute and return the current oxidizer mass flow rate [kg/s].

        Args:
            chamber_pressure: Chamber pressure [Pa].
            injector: Bipropellant injector handling the orifice dispatch.
            oxidizer_mass: Current oxidizer mass in the tank [kg].

        Returns:
            Oxidizer mass flow rate [kg/s].
        """
        pass

    @abstractmethod
    def get_mass_flow_fuel(
        self,
        chamber_pressure: float,
        *,
        injector: injector_models.BipropellantInjector,
        fuel_mass: float,
        oxidizer_mass: float,
    ) -> float:
        """
        Compute and return the current fuel mass flow rate [kg/s].

        Args:
            chamber_pressure: Chamber pressure [Pa].
            injector: Bipropellant injector handling the orifice dispatch.
            fuel_mass: Current fuel mass in the tank [kg].
            oxidizer_mass: Current oxidizer mass in the tank [kg]. Needed because
                some feed systems pressurize the fuel from the oxidizer side.

        Returns:
            Fuel mass flow rate [kg/s].
        """
        pass

    @abstractmethod
    def get_oxidizer_tank_pressure(self, *, oxidizer_mass: float) -> float:
        """
        Compute and return the current oxidizer tank pressure [Pa].

        Args:
            oxidizer_mass: Current oxidizer mass in the tank [kg].
        """
        pass

    @abstractmethod
    def get_fuel_tank_pressure(
        self, *, oxidizer_mass: float, fuel_mass: float
    ) -> float:
        """
        Compute and return the current fuel-side upstream pressure [Pa].

        Args:
            oxidizer_mass: Current oxidizer mass in the tank [kg].
            fuel_mass: Current fuel mass in the tank [kg].
        """
        pass

__init__(fuel_tank, oxidizer_tank)

Initialize the FeedSystem with associated tank objects.

Parameters:

Name Type Description Default
fuel_tank Tank

Instance representing the fuel tank.

required
oxidizer_tank Tank

Instance representing the oxidizer tank.

required
Source code in machwave/models/feed_systems/base.py
def __init__(self, fuel_tank: tank.Tank, oxidizer_tank: tank.Tank):
    """
    Initialize the FeedSystem with associated tank objects.

    Args:
        fuel_tank: Instance representing the fuel tank.
        oxidizer_tank: Instance representing the oxidizer tank.
    """
    self.fuel_tank = fuel_tank
    self.oxidizer_tank = oxidizer_tank

get_fuel_tank_pressure(*, oxidizer_mass, fuel_mass) abstractmethod

Compute and return the current fuel-side upstream pressure [Pa].

Parameters:

Name Type Description Default
oxidizer_mass float

Current oxidizer mass in the tank [kg].

required
fuel_mass float

Current fuel mass in the tank [kg].

required
Source code in machwave/models/feed_systems/base.py
@abstractmethod
def get_fuel_tank_pressure(
    self, *, oxidizer_mass: float, fuel_mass: float
) -> float:
    """
    Compute and return the current fuel-side upstream pressure [Pa].

    Args:
        oxidizer_mass: Current oxidizer mass in the tank [kg].
        fuel_mass: Current fuel mass in the tank [kg].
    """
    pass

get_initial_propellant_mass()

Compute and return the initial propellant mass in the system [kg].

Source code in machwave/models/feed_systems/base.py
def get_initial_propellant_mass(self) -> float:
    """Compute and return the initial propellant mass in the system [kg]."""
    return self.fuel_tank.initial_fluid_mass + self.oxidizer_tank.initial_fluid_mass

get_mass_flow_fuel(chamber_pressure, *, injector, fuel_mass, oxidizer_mass) abstractmethod

Compute and return the current fuel mass flow rate [kg/s].

Parameters:

Name Type Description Default
chamber_pressure float

Chamber pressure [Pa].

required
injector BipropellantInjector

Bipropellant injector handling the orifice dispatch.

required
fuel_mass float

Current fuel mass in the tank [kg].

required
oxidizer_mass float

Current oxidizer mass in the tank [kg]. Needed because some feed systems pressurize the fuel from the oxidizer side.

required

Returns:

Type Description
float

Fuel mass flow rate [kg/s].

Source code in machwave/models/feed_systems/base.py
@abstractmethod
def get_mass_flow_fuel(
    self,
    chamber_pressure: float,
    *,
    injector: injector_models.BipropellantInjector,
    fuel_mass: float,
    oxidizer_mass: float,
) -> float:
    """
    Compute and return the current fuel mass flow rate [kg/s].

    Args:
        chamber_pressure: Chamber pressure [Pa].
        injector: Bipropellant injector handling the orifice dispatch.
        fuel_mass: Current fuel mass in the tank [kg].
        oxidizer_mass: Current oxidizer mass in the tank [kg]. Needed because
            some feed systems pressurize the fuel from the oxidizer side.

    Returns:
        Fuel mass flow rate [kg/s].
    """
    pass

get_mass_flow_ox(chamber_pressure, *, injector, oxidizer_mass) abstractmethod

Compute and return the current oxidizer mass flow rate [kg/s].

Parameters:

Name Type Description Default
chamber_pressure float

Chamber pressure [Pa].

required
injector BipropellantInjector

Bipropellant injector handling the orifice dispatch.

required
oxidizer_mass float

Current oxidizer mass in the tank [kg].

required

Returns:

Type Description
float

Oxidizer mass flow rate [kg/s].

Source code in machwave/models/feed_systems/base.py
@abstractmethod
def get_mass_flow_ox(
    self,
    chamber_pressure: float,
    *,
    injector: injector_models.BipropellantInjector,
    oxidizer_mass: float,
) -> float:
    """
    Compute and return the current oxidizer mass flow rate [kg/s].

    Args:
        chamber_pressure: Chamber pressure [Pa].
        injector: Bipropellant injector handling the orifice dispatch.
        oxidizer_mass: Current oxidizer mass in the tank [kg].

    Returns:
        Oxidizer mass flow rate [kg/s].
    """
    pass

get_oxidizer_tank_pressure(*, oxidizer_mass) abstractmethod

Compute and return the current oxidizer tank pressure [Pa].

Parameters:

Name Type Description Default
oxidizer_mass float

Current oxidizer mass in the tank [kg].

required
Source code in machwave/models/feed_systems/base.py
@abstractmethod
def get_oxidizer_tank_pressure(self, *, oxidizer_mass: float) -> float:
    """
    Compute and return the current oxidizer tank pressure [Pa].

    Args:
        oxidizer_mass: Current oxidizer mass in the tank [kg].
    """
    pass

StackedTankPressureFedFeedSystem

Bases: FeedSystem

Represents a bipropellant biliquid rocket engine feed system with stacked tanks.

A stacked tank system is a type of pressure-fed system where the oxidizer and fuel tanks are arranged in a vertical stack. The tanks are separated by a piston and the fuel is pressurized by the oxidizer tank.

Source code in machwave/models/feed_systems/cycles/stacked_tank_pressure_fed.py
class StackedTankPressureFedFeedSystem(feed_system_base.FeedSystem):
    """
    Represents a bipropellant biliquid rocket engine feed system with stacked tanks.

    A stacked tank system is a type of pressure-fed system where the oxidizer and fuel
    tanks are arranged in a vertical stack. The tanks are separated by a piston and the
    fuel is pressurized by the oxidizer tank.
    """

    def __init__(
        self,
        oxidizer_line_diameter: float,
        oxidizer_line_length: float,
        fuel_line_diameter: float,
        fuel_line_length: float,
        fuel_tank: tank.Tank,
        oxidizer_tank: tank.Tank,
        piston_loss: float = 0.0,
    ):
        """
        Initialize the StackedTankPressureFedFeedSystem.

        Args:
            oxidizer_line_diameter: Diameter of the oxidizer feedline [m].
            oxidizer_line_length: Length of the oxidizer feedline [m].
            fuel_line_diameter: Diameter of the fuel feedline [m].
            fuel_line_length: Length of the fuel feedline [m].
            fuel_tank: An instance representing the fuel tank.
            oxidizer_tank: An instance representing the oxidizer tank.
            piston_loss: Pressure loss across the piston [Pa]. Default is 0.0.
        """
        super().__init__(fuel_tank, oxidizer_tank)

        self.oxidizer_line_diameter = oxidizer_line_diameter
        self.oxidizer_line_length = oxidizer_line_length
        self.fuel_line_diameter = fuel_line_diameter
        self.fuel_line_length = fuel_line_length

        self.piston_loss = piston_loss

        self.fuel_tank = fuel_tank
        self.oxidizer_tank = oxidizer_tank

    def get_mass_flow_ox(
        self,
        chamber_pressure: float,
        *,
        injector: injector_models.BipropellantInjector,
        oxidizer_mass: float,
    ) -> float:
        """
        Compute the current oxidizer mass flow rate by delegating to the injector.

        Args:
            chamber_pressure: Chamber pressure [Pa].
            injector: Bipropellant injector handling the orifice dispatch.
            oxidizer_mass: Current oxidizer mass in the tank [kg].

        Returns:
            Oxidizer mass flow rate [kg/s].
        """
        return injector.get_mass_flow_ox(
            tank=self.oxidizer_tank,
            pressure_upstream=self.get_oxidizer_tank_pressure(
                oxidizer_mass=oxidizer_mass
            ),
            chamber_pressure=chamber_pressure,
            fluid_mass=oxidizer_mass,
        )

    def get_mass_flow_fuel(
        self,
        chamber_pressure: float,
        *,
        injector: injector_models.BipropellantInjector,
        fuel_mass: float,
        oxidizer_mass: float,
    ) -> float:
        """
        Compute the current fuel mass flow rate by delegating to the injector.

        The upstream pressure is the oxidizer tank pressure minus the piston
        loss, since this models a stacked tank pressurized through the piston.

        Args:
            chamber_pressure: Chamber pressure [Pa].
            injector: Bipropellant injector handling the orifice dispatch.
            fuel_mass: Current fuel mass in the tank [kg].
            oxidizer_mass: Current oxidizer mass in the tank [kg].

        Returns:
            Fuel mass flow rate [kg/s].
        """
        return injector.get_mass_flow_fuel(
            tank=self.fuel_tank,
            pressure_upstream=self.get_fuel_tank_pressure(
                oxidizer_mass=oxidizer_mass, fuel_mass=fuel_mass
            ),
            chamber_pressure=chamber_pressure,
            fluid_mass=fuel_mass,
        )

    def get_oxidizer_tank_pressure(self, *, oxidizer_mass: float) -> float:
        """Returns the tank pressure [Pa]."""
        return self.oxidizer_tank.get_pressure(oxidizer_mass)

    def get_fuel_tank_pressure(
        self, *, oxidizer_mass: float, fuel_mass: float
    ) -> float:
        """
        Returns the fuel-side upstream pressure [Pa].

        In a stacked-tank system the fuel is pressurized by the oxidizer
        through the piston, so the fuel-side pressure is the oxidizer tank
        pressure minus the piston pressure loss; ``fuel_mass`` is unused here.
        """
        return (
            self.get_oxidizer_tank_pressure(oxidizer_mass=oxidizer_mass)
            - self.piston_loss
        )

__init__(oxidizer_line_diameter, oxidizer_line_length, fuel_line_diameter, fuel_line_length, fuel_tank, oxidizer_tank, piston_loss=0.0)

Initialize the StackedTankPressureFedFeedSystem.

Parameters:

Name Type Description Default
oxidizer_line_diameter float

Diameter of the oxidizer feedline [m].

required
oxidizer_line_length float

Length of the oxidizer feedline [m].

required
fuel_line_diameter float

Diameter of the fuel feedline [m].

required
fuel_line_length float

Length of the fuel feedline [m].

required
fuel_tank Tank

An instance representing the fuel tank.

required
oxidizer_tank Tank

An instance representing the oxidizer tank.

required
piston_loss float

Pressure loss across the piston [Pa]. Default is 0.0.

0.0
Source code in machwave/models/feed_systems/cycles/stacked_tank_pressure_fed.py
def __init__(
    self,
    oxidizer_line_diameter: float,
    oxidizer_line_length: float,
    fuel_line_diameter: float,
    fuel_line_length: float,
    fuel_tank: tank.Tank,
    oxidizer_tank: tank.Tank,
    piston_loss: float = 0.0,
):
    """
    Initialize the StackedTankPressureFedFeedSystem.

    Args:
        oxidizer_line_diameter: Diameter of the oxidizer feedline [m].
        oxidizer_line_length: Length of the oxidizer feedline [m].
        fuel_line_diameter: Diameter of the fuel feedline [m].
        fuel_line_length: Length of the fuel feedline [m].
        fuel_tank: An instance representing the fuel tank.
        oxidizer_tank: An instance representing the oxidizer tank.
        piston_loss: Pressure loss across the piston [Pa]. Default is 0.0.
    """
    super().__init__(fuel_tank, oxidizer_tank)

    self.oxidizer_line_diameter = oxidizer_line_diameter
    self.oxidizer_line_length = oxidizer_line_length
    self.fuel_line_diameter = fuel_line_diameter
    self.fuel_line_length = fuel_line_length

    self.piston_loss = piston_loss

    self.fuel_tank = fuel_tank
    self.oxidizer_tank = oxidizer_tank

get_fuel_tank_pressure(*, oxidizer_mass, fuel_mass)

Returns the fuel-side upstream pressure [Pa].

In a stacked-tank system the fuel is pressurized by the oxidizer through the piston, so the fuel-side pressure is the oxidizer tank pressure minus the piston pressure loss; fuel_mass is unused here.

Source code in machwave/models/feed_systems/cycles/stacked_tank_pressure_fed.py
def get_fuel_tank_pressure(
    self, *, oxidizer_mass: float, fuel_mass: float
) -> float:
    """
    Returns the fuel-side upstream pressure [Pa].

    In a stacked-tank system the fuel is pressurized by the oxidizer
    through the piston, so the fuel-side pressure is the oxidizer tank
    pressure minus the piston pressure loss; ``fuel_mass`` is unused here.
    """
    return (
        self.get_oxidizer_tank_pressure(oxidizer_mass=oxidizer_mass)
        - self.piston_loss
    )

get_mass_flow_fuel(chamber_pressure, *, injector, fuel_mass, oxidizer_mass)

Compute the current fuel mass flow rate by delegating to the injector.

The upstream pressure is the oxidizer tank pressure minus the piston loss, since this models a stacked tank pressurized through the piston.

Parameters:

Name Type Description Default
chamber_pressure float

Chamber pressure [Pa].

required
injector BipropellantInjector

Bipropellant injector handling the orifice dispatch.

required
fuel_mass float

Current fuel mass in the tank [kg].

required
oxidizer_mass float

Current oxidizer mass in the tank [kg].

required

Returns:

Type Description
float

Fuel mass flow rate [kg/s].

Source code in machwave/models/feed_systems/cycles/stacked_tank_pressure_fed.py
def get_mass_flow_fuel(
    self,
    chamber_pressure: float,
    *,
    injector: injector_models.BipropellantInjector,
    fuel_mass: float,
    oxidizer_mass: float,
) -> float:
    """
    Compute the current fuel mass flow rate by delegating to the injector.

    The upstream pressure is the oxidizer tank pressure minus the piston
    loss, since this models a stacked tank pressurized through the piston.

    Args:
        chamber_pressure: Chamber pressure [Pa].
        injector: Bipropellant injector handling the orifice dispatch.
        fuel_mass: Current fuel mass in the tank [kg].
        oxidizer_mass: Current oxidizer mass in the tank [kg].

    Returns:
        Fuel mass flow rate [kg/s].
    """
    return injector.get_mass_flow_fuel(
        tank=self.fuel_tank,
        pressure_upstream=self.get_fuel_tank_pressure(
            oxidizer_mass=oxidizer_mass, fuel_mass=fuel_mass
        ),
        chamber_pressure=chamber_pressure,
        fluid_mass=fuel_mass,
    )

get_mass_flow_ox(chamber_pressure, *, injector, oxidizer_mass)

Compute the current oxidizer mass flow rate by delegating to the injector.

Parameters:

Name Type Description Default
chamber_pressure float

Chamber pressure [Pa].

required
injector BipropellantInjector

Bipropellant injector handling the orifice dispatch.

required
oxidizer_mass float

Current oxidizer mass in the tank [kg].

required

Returns:

Type Description
float

Oxidizer mass flow rate [kg/s].

Source code in machwave/models/feed_systems/cycles/stacked_tank_pressure_fed.py
def get_mass_flow_ox(
    self,
    chamber_pressure: float,
    *,
    injector: injector_models.BipropellantInjector,
    oxidizer_mass: float,
) -> float:
    """
    Compute the current oxidizer mass flow rate by delegating to the injector.

    Args:
        chamber_pressure: Chamber pressure [Pa].
        injector: Bipropellant injector handling the orifice dispatch.
        oxidizer_mass: Current oxidizer mass in the tank [kg].

    Returns:
        Oxidizer mass flow rate [kg/s].
    """
    return injector.get_mass_flow_ox(
        tank=self.oxidizer_tank,
        pressure_upstream=self.get_oxidizer_tank_pressure(
            oxidizer_mass=oxidizer_mass
        ),
        chamber_pressure=chamber_pressure,
        fluid_mass=oxidizer_mass,
    )

get_oxidizer_tank_pressure(*, oxidizer_mass)

Returns the tank pressure [Pa].

Source code in machwave/models/feed_systems/cycles/stacked_tank_pressure_fed.py
def get_oxidizer_tank_pressure(self, *, oxidizer_mass: float) -> float:
    """Returns the tank pressure [Pa]."""
    return self.oxidizer_tank.get_pressure(oxidizer_mass)