Skip to content

models.thrust_chamber

Thrust chamber assembly and sub-components.

  • Nozzle — Conical nozzle defined by throat diameter, expansion ratio, and convergent/divergent half-angles. Computes throat area and outlet diameter.
  • CombustionChamber — Cylindrical casing with thermal liner. Provides internal volume from casing dimensions and liner thickness.
  • InjectorElement — The orifices one propellant line flows through, characterized by a discharge coefficient, a flow area, and a MassFlowModel. Owns the orifice mass-flow dispatch: get_mass_flow(*, inlet, chamber_pressure).
  • Injector — One InjectorElement per propellant line, keyed by the feed system's line names. get_mass_flows(*, inlet_states, chamber_pressure) takes the inlet state of every line and returns the flow of every line. Each element is fed a FluidState — fluid name, pressure, temperature, and density at the injector face — and is a pure function of it. An element stops flowing once the chamber has caught up with its inlet.
  • MassFlowModel — Enum selecting the orifice flow model. SPI (single-phase incompressible) for subcooled liquid propellants; HEM (homogeneous-equilibrium two-phase) for self-pressurized propellants such as nitrous oxide, where flow can choke on the two-phase sound speed.
  • SolidMotorThrustChamber — Bundles nozzle + chamber + the distance from nozzle exit to grain port.
  • BiliquidEngineThrustChamber — Bundles nozzle + chamber + injector.

machwave.models.thrust_chamber

BiliquidEngineThrustChamber dataclass

Bases: ThrustChamber

Thrust chamber assembly specialized for biliquid rocket engines.

Attributes:

Name Type Description
nozzle Nozzle

Nozzle instance.

injector Injector

Injector instance, with one element per propellant line.

combustion_chamber CombustionChamber

Combustion chamber instance.

dry_mass_properties DryMassProperties | None

Mass, center of gravity, and inertia of the thrust chamber. Optional, not used by the internal ballistics simulation.

Source code in machwave/models/thrust_chamber/base.py
@dataclasses.dataclass(kw_only=True)
class BiliquidEngineThrustChamber(ThrustChamber):
    """
    Thrust chamber assembly specialized for biliquid rocket engines.

    Attributes:
        nozzle: Nozzle instance.
        injector: Injector instance, with one element per propellant line.
        combustion_chamber: Combustion chamber instance.
        dry_mass_properties: Mass, center of gravity, and inertia of the thrust
            chamber. Optional, not used by the internal ballistics simulation.
    """

    injector: injector_models.Injector

CombustionChamber dataclass

Represents a cylindrical combustion chamber.

Attributes:

Name Type Description
casing_inner_diameter float

Internal diameter [m].

casing_outer_diameter float

Outer diameter [m].

internal_length float

Distance from combustion chamber inlet to nozzle inlet [m].

thermal_liner_thickness float

Thermal liner thickness [m]. Defaults to 0.0.

Source code in machwave/models/thrust_chamber/combustion_chamber.py
@dataclasses.dataclass(kw_only=True)
class CombustionChamber:
    """
    Represents a cylindrical combustion chamber.

    Attributes:
        casing_inner_diameter: Internal diameter [m].
        casing_outer_diameter: Outer diameter [m].
        internal_length: Distance from combustion chamber inlet to nozzle inlet [m].
        thermal_liner_thickness: Thermal liner thickness [m]. Defaults to 0.0.
    """

    casing_inner_diameter: float
    casing_outer_diameter: float
    internal_length: float
    thermal_liner_thickness: float = 0.0

    def __post_init__(self) -> None:
        """
        Validate the combustion chamber geometry.

        Raises:
            ValueError: If any field is outside its valid physical range.
        """
        if self.casing_inner_diameter <= 0.0:
            raise ValueError(
                "casing_inner_diameter must be strictly positive, got "
                f"{self.casing_inner_diameter}"
            )
        if self.casing_outer_diameter <= self.casing_inner_diameter:
            raise ValueError(
                f"casing_outer_diameter ({self.casing_outer_diameter}) must be larger "
                f"than casing_inner_diameter ({self.casing_inner_diameter})"
            )
        if self.internal_length <= 0.0:
            raise ValueError(
                f"internal_length must be strictly positive, got {self.internal_length}"
            )
        if self.thermal_liner_thickness < 0.0:
            raise ValueError(
                "thermal_liner_thickness must be non-negative, got "
                f"{self.thermal_liner_thickness}"
            )
        if self.thermal_liner_thickness >= 0.5 * self.casing_inner_diameter:
            raise ValueError(
                f"thermal_liner_thickness ({self.thermal_liner_thickness}) leaves no "
                f"open bore for casing_inner_diameter ({self.casing_inner_diameter})"
            )

    @property
    def inner_diameter(self) -> float:
        """Inner diameter of the combustion chamber [m]."""
        return self.casing_inner_diameter - 2 * self.thermal_liner_thickness

    @property
    def outer_diameter(self) -> float:
        """Outer diameter of the combustion chamber [m]."""
        return self.casing_outer_diameter

    @property
    def inner_radius(self) -> float:
        """Inner radius of the combustion chamber [m]."""
        return 0.5 * self.inner_diameter

    @property
    def outer_radius(self) -> float:
        """Outer radius of the combustion chamber [m]."""
        return 0.5 * self.outer_diameter

    @property
    def internal_volume(self) -> float:
        """Internal volume of the combustion chamber [m^3]."""
        r = self.inner_radius
        return np.pi * r * r * self.internal_length

inner_diameter property

Inner diameter of the combustion chamber [m].

inner_radius property

Inner radius of the combustion chamber [m].

internal_volume property

Internal volume of the combustion chamber [m^3].

outer_diameter property

Outer diameter of the combustion chamber [m].

outer_radius property

Outer radius of the combustion chamber [m].

__post_init__()

Validate the combustion chamber geometry.

Raises:

Type Description
ValueError

If any field is outside its valid physical range.

Source code in machwave/models/thrust_chamber/combustion_chamber.py
def __post_init__(self) -> None:
    """
    Validate the combustion chamber geometry.

    Raises:
        ValueError: If any field is outside its valid physical range.
    """
    if self.casing_inner_diameter <= 0.0:
        raise ValueError(
            "casing_inner_diameter must be strictly positive, got "
            f"{self.casing_inner_diameter}"
        )
    if self.casing_outer_diameter <= self.casing_inner_diameter:
        raise ValueError(
            f"casing_outer_diameter ({self.casing_outer_diameter}) must be larger "
            f"than casing_inner_diameter ({self.casing_inner_diameter})"
        )
    if self.internal_length <= 0.0:
        raise ValueError(
            f"internal_length must be strictly positive, got {self.internal_length}"
        )
    if self.thermal_liner_thickness < 0.0:
        raise ValueError(
            "thermal_liner_thickness must be non-negative, got "
            f"{self.thermal_liner_thickness}"
        )
    if self.thermal_liner_thickness >= 0.5 * self.casing_inner_diameter:
        raise ValueError(
            f"thermal_liner_thickness ({self.thermal_liner_thickness}) leaves no "
            f"open bore for casing_inner_diameter ({self.casing_inner_diameter})"
        )

Injector dataclass

An injector, with one element per propellant line.

Attributes:

Name Type Description
elements dict[str, InjectorElement]

Injector element of every line, keyed by the feed system's line names.

Source code in machwave/models/thrust_chamber/injector.py
@dataclasses.dataclass(frozen=True, kw_only=True)
class Injector:
    """
    An injector, with one element per propellant line.

    Attributes:
        elements: Injector element of every line, keyed by the feed system's
            line names.
    """

    elements: dict[str, InjectorElement]

    def __post_init__(self) -> None:
        if not self.elements:
            raise ValueError("elements must hold at least one injector element")

    def get_mass_flows(
        self,
        *,
        inlet_states: Mapping[str, fluid_state_models.FluidState],
        chamber_pressure: float,
    ) -> dict[str, float]:
        """
        Compute the mass flow rate through every element.

        Args:
            inlet_states: Propellant state at the inlet of every line, keyed by
                line name.
            chamber_pressure: Chamber pressure [Pa].

        Returns:
            Mass flow rate of every line [kg/s], keyed by line name.

        Raises:
            ValueError: If any element of the injector has no inlet state.
        """
        missing = [name for name in self.elements if name not in inlet_states]
        if missing:
            raise ValueError(f"no inlet state was given for {missing}")

        return {
            name: element.get_mass_flow(
                inlet=inlet_states[name], chamber_pressure=chamber_pressure
            )
            for name, element in self.elements.items()
        }

get_mass_flows(*, inlet_states, chamber_pressure)

Compute the mass flow rate through every element.

Parameters:

Name Type Description Default
inlet_states Mapping[str, FluidState]

Propellant state at the inlet of every line, keyed by line name.

required
chamber_pressure float

Chamber pressure [Pa].

required

Returns:

Type Description
dict[str, float]

Mass flow rate of every line [kg/s], keyed by line name.

Raises:

Type Description
ValueError

If any element of the injector has no inlet state.

Source code in machwave/models/thrust_chamber/injector.py
def get_mass_flows(
    self,
    *,
    inlet_states: Mapping[str, fluid_state_models.FluidState],
    chamber_pressure: float,
) -> dict[str, float]:
    """
    Compute the mass flow rate through every element.

    Args:
        inlet_states: Propellant state at the inlet of every line, keyed by
            line name.
        chamber_pressure: Chamber pressure [Pa].

    Returns:
        Mass flow rate of every line [kg/s], keyed by line name.

    Raises:
        ValueError: If any element of the injector has no inlet state.
    """
    missing = [name for name in self.elements if name not in inlet_states]
    if missing:
        raise ValueError(f"no inlet state was given for {missing}")

    return {
        name: element.get_mass_flow(
            inlet=inlet_states[name], chamber_pressure=chamber_pressure
        )
        for name, element in self.elements.items()
    }

InjectorElement dataclass

The orifices one propellant line flows through at the injector face.

An element is a pure function of its own inlet: everything upstream of the face is the feed system's to account for.

Attributes:

Name Type Description
discharge_coefficient float

Discharge coefficient (dimensionless).

area float

Effective flow area [m^2].

mass_flow_model MassFlowModel

Model the orifice flow is computed with.

Source code in machwave/models/thrust_chamber/injector.py
@dataclasses.dataclass(frozen=True, kw_only=True)
class InjectorElement:
    """
    The orifices one propellant line flows through at the injector face.

    An element is a pure function of its own inlet: everything upstream of the
    face is the feed system's to account for.

    Attributes:
        discharge_coefficient: Discharge coefficient (dimensionless).
        area: Effective flow area [m^2].
        mass_flow_model: Model the orifice flow is computed with.
    """

    discharge_coefficient: float
    area: float
    mass_flow_model: MassFlowModel = MassFlowModel.SPI

    def __post_init__(self) -> None:
        if self.area <= 0.0:
            raise ValueError(f"area must be strictly positive, got {self.area}")
        if not 0.0 < self.discharge_coefficient <= 1.0:
            raise ValueError(
                "discharge_coefficient must be in (0, 1], got "
                f"{self.discharge_coefficient}"
            )

        object.__setattr__(self, "mass_flow_model", MassFlowModel(self.mass_flow_model))

    def get_mass_flow(
        self,
        *,
        inlet: fluid_state_models.FluidState,
        chamber_pressure: float,
    ) -> float:
        """
        Compute the mass flow rate through this element.

        Args:
            inlet: Propellant state at the injector inlet.
            chamber_pressure: Chamber pressure [Pa].

        Returns:
            Mass flow rate [kg/s]. Zero once the chamber has caught up with the
            inlet, which is where the line stops feeding.

        Raises:
            ValueError: If the mass flow model is unsupported.
        """
        if inlet.pressure <= chamber_pressure:
            return 0.0

        if self.mass_flow_model == MassFlowModel.HEM:
            mass_flux = two_phase_flow.get_homogeneous_equilibrium_mass_flux(
                fluid_name=inlet.fluid_name,
                temperature_upstream=inlet.temperature,
                pressure_downstream=chamber_pressure,
                pressure_upstream=inlet.pressure,
            )
            return self.discharge_coefficient * self.area * mass_flux
        elif self.mass_flow_model == MassFlowModel.SPI:
            return incompressible_flow.get_mass_flow_orifice(
                discharge_coefficient=self.discharge_coefficient,
                area=self.area,
                density=inlet.density,
                pressure_upstream=inlet.pressure,
                pressure_downstream=chamber_pressure,
            )

        raise ValueError(f"Unsupported mass flow model: {self.mass_flow_model}")

get_mass_flow(*, inlet, chamber_pressure)

Compute the mass flow rate through this element.

Parameters:

Name Type Description Default
inlet FluidState

Propellant state at the injector inlet.

required
chamber_pressure float

Chamber pressure [Pa].

required

Returns:

Type Description
float

Mass flow rate [kg/s]. Zero once the chamber has caught up with the

float

inlet, which is where the line stops feeding.

Raises:

Type Description
ValueError

If the mass flow model is unsupported.

Source code in machwave/models/thrust_chamber/injector.py
def get_mass_flow(
    self,
    *,
    inlet: fluid_state_models.FluidState,
    chamber_pressure: float,
) -> float:
    """
    Compute the mass flow rate through this element.

    Args:
        inlet: Propellant state at the injector inlet.
        chamber_pressure: Chamber pressure [Pa].

    Returns:
        Mass flow rate [kg/s]. Zero once the chamber has caught up with the
        inlet, which is where the line stops feeding.

    Raises:
        ValueError: If the mass flow model is unsupported.
    """
    if inlet.pressure <= chamber_pressure:
        return 0.0

    if self.mass_flow_model == MassFlowModel.HEM:
        mass_flux = two_phase_flow.get_homogeneous_equilibrium_mass_flux(
            fluid_name=inlet.fluid_name,
            temperature_upstream=inlet.temperature,
            pressure_downstream=chamber_pressure,
            pressure_upstream=inlet.pressure,
        )
        return self.discharge_coefficient * self.area * mass_flux
    elif self.mass_flow_model == MassFlowModel.SPI:
        return incompressible_flow.get_mass_flow_orifice(
            discharge_coefficient=self.discharge_coefficient,
            area=self.area,
            density=inlet.density,
            pressure_upstream=inlet.pressure,
            pressure_downstream=chamber_pressure,
        )

    raise ValueError(f"Unsupported mass flow model: {self.mass_flow_model}")

MassFlowModel

Bases: StrEnum

Models for computing mass flow through an injector orifice.

Single-phase incompressible orifice equation. Valid for subcooled liquid

propellants.

HEM: Homogeneous-equilibrium two-phase model. Required for self-pressurized propellants such as nitrous oxide, where flow can choke at the injector due to flash boiling.

Source code in machwave/models/thrust_chamber/injector.py
class MassFlowModel(enum.StrEnum):
    """
    Models for computing mass flow through an injector orifice.

    SPI: Single-phase incompressible orifice equation. Valid for subcooled liquid
        propellants.
    HEM: Homogeneous-equilibrium two-phase model. Required for self-pressurized
        propellants such as nitrous oxide, where flow can choke at the injector due to
        flash boiling.
    """

    SPI = "spi"
    HEM = "hem"

Nozzle dataclass

Converging-diverging nozzle geometry.

Attributes:

Name Type Description
inlet_diameter float

Inlet diameter [m].

throat_diameter float

Throat diameter [m].

divergent_angle float

Divergent half-angle [deg].

convergent_angle float

Convergent half-angle [deg].

expansion_ratio float

Area ratio of exit to throat.

discharge_coefficient float

Throat discharge coefficient.

separation_pressure_ratio float

Pressure ratio at which the overexpanded flow separates from the nozzle wall (Summerfield criterion).

Source code in machwave/models/thrust_chamber/nozzle.py
@dataclasses.dataclass(kw_only=True)
class Nozzle:
    """
    Converging-diverging nozzle geometry.

    Attributes:
        inlet_diameter: Inlet diameter [m].
        throat_diameter: Throat diameter [m].
        divergent_angle: Divergent half-angle [deg].
        convergent_angle: Convergent half-angle [deg].
        expansion_ratio: Area ratio of exit to throat.
        discharge_coefficient: Throat discharge coefficient.
        separation_pressure_ratio: Pressure ratio at which the overexpanded flow
            separates from the nozzle wall (Summerfield criterion).
    """

    inlet_diameter: float
    throat_diameter: float
    divergent_angle: float
    convergent_angle: float
    expansion_ratio: float
    discharge_coefficient: float = 1.0
    separation_pressure_ratio: float = DEFAULT_SEPARATION_PRESSURE_RATIO

    def __post_init__(self) -> None:
        """
        Validate the nozzle geometry.

        Raises:
            ValueError: If any field is outside its valid physical range.
        """
        if self.inlet_diameter <= 0.0:
            raise ValueError(
                f"inlet_diameter must be strictly positive, got {self.inlet_diameter}"
            )
        if self.throat_diameter <= 0.0:
            raise ValueError(
                f"throat_diameter must be strictly positive, got {self.throat_diameter}"
            )
        if self.throat_diameter >= self.inlet_diameter:
            raise ValueError(
                f"throat_diameter ({self.throat_diameter}) must be smaller than "
                f"inlet_diameter ({self.inlet_diameter})"
            )
        if self.expansion_ratio <= 1.0:
            raise ValueError(
                f"expansion_ratio must be greater than 1, got {self.expansion_ratio}"
            )
        if not 0.0 < self.discharge_coefficient <= 1.0:
            raise ValueError(
                "discharge_coefficient must be in (0, 1], got "
                f"{self.discharge_coefficient}"
            )
        if not 0.0 < self.separation_pressure_ratio < 1.0:
            raise ValueError(
                "separation_pressure_ratio must be in (0, 1), got "
                f"{self.separation_pressure_ratio}"
            )
        if not 0.0 < self.divergent_angle < 90.0:
            raise ValueError(
                f"divergent_angle must be in (0, 90) deg, got {self.divergent_angle}"
            )
        if not 0.0 < self.convergent_angle < 90.0:
            raise ValueError(
                f"convergent_angle must be in (0, 90) deg, got {self.convergent_angle}"
            )

    @property
    def outlet_diameter(self) -> float:
        """Return the nozzle exit diameter [m]."""
        return self.throat_diameter * np.sqrt(self.expansion_ratio)

    def get_throat_area(self) -> float:
        """Return the nozzle throat area [m^2]."""
        return geometric.get_circle_area(self.throat_diameter)

outlet_diameter property

Return the nozzle exit diameter [m].

__post_init__()

Validate the nozzle geometry.

Raises:

Type Description
ValueError

If any field is outside its valid physical range.

Source code in machwave/models/thrust_chamber/nozzle.py
def __post_init__(self) -> None:
    """
    Validate the nozzle geometry.

    Raises:
        ValueError: If any field is outside its valid physical range.
    """
    if self.inlet_diameter <= 0.0:
        raise ValueError(
            f"inlet_diameter must be strictly positive, got {self.inlet_diameter}"
        )
    if self.throat_diameter <= 0.0:
        raise ValueError(
            f"throat_diameter must be strictly positive, got {self.throat_diameter}"
        )
    if self.throat_diameter >= self.inlet_diameter:
        raise ValueError(
            f"throat_diameter ({self.throat_diameter}) must be smaller than "
            f"inlet_diameter ({self.inlet_diameter})"
        )
    if self.expansion_ratio <= 1.0:
        raise ValueError(
            f"expansion_ratio must be greater than 1, got {self.expansion_ratio}"
        )
    if not 0.0 < self.discharge_coefficient <= 1.0:
        raise ValueError(
            "discharge_coefficient must be in (0, 1], got "
            f"{self.discharge_coefficient}"
        )
    if not 0.0 < self.separation_pressure_ratio < 1.0:
        raise ValueError(
            "separation_pressure_ratio must be in (0, 1), got "
            f"{self.separation_pressure_ratio}"
        )
    if not 0.0 < self.divergent_angle < 90.0:
        raise ValueError(
            f"divergent_angle must be in (0, 90) deg, got {self.divergent_angle}"
        )
    if not 0.0 < self.convergent_angle < 90.0:
        raise ValueError(
            f"convergent_angle must be in (0, 90) deg, got {self.convergent_angle}"
        )

get_throat_area()

Return the nozzle throat area [m^2].

Source code in machwave/models/thrust_chamber/nozzle.py
def get_throat_area(self) -> float:
    """Return the nozzle throat area [m^2]."""
    return geometric.get_circle_area(self.throat_diameter)

SolidMotorThrustChamber dataclass

Bases: ThrustChamber

Thrust chamber assembly specialized for solid rocket motors.

Attributes:

Name Type Description
nozzle Nozzle

Nozzle instance.

combustion_chamber CombustionChamber

Combustion chamber instance.

nozzle_exit_to_grain_port_distance float

Axial distance from the nozzle exit plane to the grain port [m]. Shifts grain mass properties into the motor frame, whose origin is the nozzle exit.

dry_mass_properties DryMassProperties | None

Mass, center of gravity, and inertia of the thrust chamber. Optional, not used by the internal ballistics simulation.

Source code in machwave/models/thrust_chamber/base.py
@dataclasses.dataclass(kw_only=True)
class SolidMotorThrustChamber(ThrustChamber):
    """
    Thrust chamber assembly specialized for solid rocket motors.

    Attributes:
        nozzle: Nozzle instance.
        combustion_chamber: Combustion chamber instance.
        nozzle_exit_to_grain_port_distance: Axial distance from the nozzle exit
            plane to the grain port [m]. Shifts grain mass properties into the motor
            frame, whose origin is the nozzle exit.
        dry_mass_properties: Mass, center of gravity, and inertia of the thrust
            chamber. Optional, not used by the internal ballistics simulation.
    """

    nozzle_exit_to_grain_port_distance: float

    def __post_init__(self) -> None:
        """
        Validate the assembly geometry.

        Raises:
            ValueError: If the nozzle inlet diameter is larger than the combustion
                chamber casing inner diameter, or if the nozzle exit to grain port
                distance is negative.
        """
        super().__post_init__()

        if self.nozzle_exit_to_grain_port_distance < 0.0:
            raise ValueError(
                "nozzle_exit_to_grain_port_distance must be non-negative, got "
                f"{self.nozzle_exit_to_grain_port_distance}"
            )

__post_init__()

Validate the assembly geometry.

Raises:

Type Description
ValueError

If the nozzle inlet diameter is larger than the combustion chamber casing inner diameter, or if the nozzle exit to grain port distance is negative.

Source code in machwave/models/thrust_chamber/base.py
def __post_init__(self) -> None:
    """
    Validate the assembly geometry.

    Raises:
        ValueError: If the nozzle inlet diameter is larger than the combustion
            chamber casing inner diameter, or if the nozzle exit to grain port
            distance is negative.
    """
    super().__post_init__()

    if self.nozzle_exit_to_grain_port_distance < 0.0:
        raise ValueError(
            "nozzle_exit_to_grain_port_distance must be non-negative, got "
            f"{self.nozzle_exit_to_grain_port_distance}"
        )

ThrustChamber dataclass

Bases: ABC

Base class for a thrust chamber assembly.

Attributes:

Name Type Description
nozzle Nozzle

Nozzle instance.

combustion_chamber CombustionChamber

Combustion chamber instance.

dry_mass_properties DryMassProperties | None

Mass, center of gravity, and inertia of the thrust chamber. Optional, not used by the internal ballistics simulation.

Source code in machwave/models/thrust_chamber/base.py
@dataclasses.dataclass(kw_only=True)
class ThrustChamber(abc.ABC):
    """
    Base class for a thrust chamber assembly.

    Attributes:
        nozzle: Nozzle instance.
        combustion_chamber: Combustion chamber instance.
        dry_mass_properties: Mass, center of gravity, and inertia of the thrust
            chamber. Optional, not used by the internal ballistics simulation.
    """

    nozzle: nozzle_models.Nozzle
    combustion_chamber: combustion_chamber_models.CombustionChamber
    dry_mass_properties: mass_properties.DryMassProperties | None = None

    def __post_init__(self) -> None:
        """
        Validate that the nozzle fits the combustion chamber.

        Raises:
            ValueError: If the nozzle inlet diameter is larger than the combustion
                chamber casing inner diameter.
        """
        if self.nozzle.inlet_diameter > self.combustion_chamber.casing_inner_diameter:
            raise ValueError(
                f"Nozzle inlet diameter ({self.nozzle.inlet_diameter}) does not fit "
                "within combustion chamber casing_inner_diameter "
                f"({self.combustion_chamber.casing_inner_diameter})"
            )

__post_init__()

Validate that the nozzle fits the combustion chamber.

Raises:

Type Description
ValueError

If the nozzle inlet diameter is larger than the combustion chamber casing inner diameter.

Source code in machwave/models/thrust_chamber/base.py
def __post_init__(self) -> None:
    """
    Validate that the nozzle fits the combustion chamber.

    Raises:
        ValueError: If the nozzle inlet diameter is larger than the combustion
            chamber casing inner diameter.
    """
    if self.nozzle.inlet_diameter > self.combustion_chamber.casing_inner_diameter:
        raise ValueError(
            f"Nozzle inlet diameter ({self.nozzle.inlet_diameter}) does not fit "
            "within combustion chamber casing_inner_diameter "
            f"({self.combustion_chamber.casing_inner_diameter})"
        )