Skip to content

core.compressible_flow

Compressible flow relations for convergent-divergent nozzle analysis.

  • Isentropic flow — Critical pressure ratio, exit Mach from expansion ratio, exit pressure, choked-flow detection.
  • Nozzle performance — Ideal and corrected thrust coefficient (Cf), optimal expansion ratio for a given altitude, effective exit conditions under overexpanded flow separation, thrust from Cf.

machwave.core.compressible_flow

Compressible flow theory and analysis.

get_critical_pressure_ratio(k)

Get critical pressure ratio for choked flow.

Parameters:

Name Type Description Default
k float

Isentropic exponent.

required

Returns:

Type Description
float

Critical pressure ratio.

Source code in machwave/core/compressible_flow/isentropic.py
def get_critical_pressure_ratio(k: float) -> float:
    """
    Get critical pressure ratio for choked flow.

    Args:
        k: Isentropic exponent.

    Returns:
        Critical pressure ratio.
    """
    return (2 / (k + 1)) ** (k / (k - 1))

get_exit_mach_from_expansion_ratio(k, expansion_ratio)

Get exit Mach number from expansion ratio.

Parameters:

Name Type Description Default
k float

Isentropic exponent.

required
expansion_ratio float

Expansion ratio (A_exit / A_throat).

required

Returns:

Type Description
float

Exit Mach number.

Raises:

Type Description
ValueError

If solver fails to converge.

Source code in machwave/core/compressible_flow/isentropic.py
def get_exit_mach_from_expansion_ratio(k: float, expansion_ratio: float) -> float:
    """
    Get exit Mach number from expansion ratio.

    Args:
        k: Isentropic exponent.
        expansion_ratio: Expansion ratio (A_exit / A_throat).

    Returns:
        Exit Mach number.

    Raises:
        ValueError: If solver fails to converge.
    """
    try:
        exit_mach = cast(
            float,
            scipy.optimize.brentq(
                lambda m: get_expansion_ratio_from_exit_mach(m, k) - expansion_ratio,
                a=1.001,  # Just above sonic
                b=20.0,  # High supersonic
            ),
        )
        return exit_mach
    except ValueError as e:
        raise ValueError(
            f"Failed to converge for expansion_ratio={expansion_ratio}, k={k}"
        ) from e

get_exit_pressure(k_exhaust, expansion_ratio, chamber_pressure)

Get exit pressure from isentropic relations.

Parameters:

Name Type Description Default
k_exhaust float

Isentropic exponent at exit.

required
expansion_ratio float

Expansion ratio.

required
chamber_pressure float

Chamber pressure [Pa].

required

Returns:

Type Description
float

Exit pressure [Pa].

Source code in machwave/core/compressible_flow/isentropic.py
def get_exit_pressure(
    k_exhaust: float,
    expansion_ratio: float,
    chamber_pressure: float,
) -> float:
    """
    Get exit pressure from isentropic relations.

    Args:
        k_exhaust: Isentropic exponent at exit.
        expansion_ratio: Expansion ratio.
        chamber_pressure: Chamber pressure [Pa].

    Returns:
        Exit pressure [Pa].
    """
    exit_mach = get_exit_mach_from_expansion_ratio(k_exhaust, expansion_ratio)
    return chamber_pressure * (1 + 0.5 * (k_exhaust - 1) * exit_mach**2) ** (
        -k_exhaust / (k_exhaust - 1)
    )

get_expansion_ratio_from_exit_mach(mach, k)

Get expansion ratio from exit Mach number.

Parameters:

Name Type Description Default
mach float

Mach number.

required
k float

Isentropic exponent.

required

Returns:

Type Description
float

Expansion ratio (A / A_throat).

Source code in machwave/core/compressible_flow/isentropic.py
def get_expansion_ratio_from_exit_mach(mach: float, k: float) -> float:
    """
    Get expansion ratio from exit Mach number.

    Args:
        mach: Mach number.
        k: Isentropic exponent.

    Returns:
        Expansion ratio (A / A_throat).
    """
    term1 = (2 / (k + 1)) * (1 + 0.5 * (k - 1) * mach**2)
    term2 = (k + 1) / (2 * (k - 1))
    return (1 / mach) * (term1**term2)

get_ideal_thrust_coefficient_terms(chamber_pressure, exit_pressure, external_pressure, expansion_ratio, k_exhaust)

Get the momentum and pressure terms of the ideal thrust coefficient.

Parameters:

Name Type Description Default
chamber_pressure float

Chamber pressure [Pa].

required
exit_pressure float

Exit pressure [Pa].

required
external_pressure float

External pressure [Pa].

required
expansion_ratio float

Expansion ratio.

required
k_exhaust float

Isentropic exponent at exit.

required

Returns:

Type Description
float

Momentum term then pressure term. The pressure term is positive when under

float

expanded and negative when over expanded.

References

https://www.nakka-rocketry.net/th_thrst.html

Source code in machwave/core/compressible_flow/nozzle.py
def get_ideal_thrust_coefficient_terms(
    chamber_pressure: float,
    exit_pressure: float,
    external_pressure: float,
    expansion_ratio: float,
    k_exhaust: float,
) -> tuple[float, float]:
    """
    Get the momentum and pressure terms of the ideal thrust coefficient.

    Args:
        chamber_pressure: Chamber pressure [Pa].
        exit_pressure: Exit pressure [Pa].
        external_pressure: External pressure [Pa].
        expansion_ratio: Expansion ratio.
        k_exhaust: Isentropic exponent at exit.

    Returns:
        Momentum term then pressure term. The pressure term is positive when under
        expanded and negative when over expanded.

    References:
        https://www.nakka-rocketry.net/th_thrst.html
    """
    pressure_ratio = exit_pressure / chamber_pressure
    momentum_term = np.sqrt(
        (2 * (k_exhaust**2) / (k_exhaust - 1))
        * ((2 / (k_exhaust + 1)) ** ((k_exhaust + 1) / (k_exhaust - 1)))
        * (1 - (pressure_ratio ** ((k_exhaust - 1) / k_exhaust)))
    )
    pressure_term = (
        expansion_ratio * (exit_pressure - external_pressure) / chamber_pressure
    )
    return momentum_term, pressure_term

get_optimal_expansion_ratio(k, chamber_pressure, atmospheric_pressure)

Get optimal expansion ratio for DeLaval nozzle.

Parameters:

Name Type Description Default
k float

Isentropic exponent.

required
chamber_pressure float

Chamber pressure [Pa].

required
atmospheric_pressure float

External pressure [Pa].

required

Returns:

Type Description
float

Optimal expansion ratio.

Source code in machwave/core/compressible_flow/nozzle.py
def get_optimal_expansion_ratio(
    k: float, chamber_pressure: float, atmospheric_pressure: float
) -> float:
    """
    Get optimal expansion ratio for DeLaval nozzle.

    Args:
        k: Isentropic exponent.
        chamber_pressure: Chamber pressure [Pa].
        atmospheric_pressure: External pressure [Pa].

    Returns:
        Optimal expansion ratio.
    """
    return (
        (((k + 1) / 2) ** (1 / (k - 1)))
        * ((atmospheric_pressure / chamber_pressure) ** (1 / k))
        * np.sqrt(
            ((k + 1) / (k - 1))
            * (1 - (atmospheric_pressure / chamber_pressure) ** ((k - 1) / k))
        )
    ) ** -1

get_separated_exit_conditions(k_exhaust, expansion_ratio, chamber_pressure, external_pressure, separation_pressure_ratio)

Get the effective exit conditions accounting for flow separation.

The model implemented is based on the work of Summerfield et al. (1954) and assumes that flow separation occurs when the exit pressure is below a certain fraction of the ambient pressure.

Parameters:

Name Type Description Default
k_exhaust float

Isentropic exponent at exit.

required
expansion_ratio float

Geometric expansion ratio.

required
chamber_pressure float

Chamber pressure [Pa].

required
external_pressure float

Ambient pressure [Pa].

required
separation_pressure_ratio float

Separation-to-ambient pressure ratio.

required

Returns:

Type Description
tuple[float, float]

Effective expansion ratio and effective exit pressure [Pa].

References

Summerfield, M., Foster, C. R., & Swan, W. C. (1954). Flow separation in overexpanded supersonic exhaust nozzles.

Source code in machwave/core/compressible_flow/nozzle.py
def get_separated_exit_conditions(
    k_exhaust: float,
    expansion_ratio: float,
    chamber_pressure: float,
    external_pressure: float,
    separation_pressure_ratio: float,
) -> tuple[float, float]:
    """
    Get the effective exit conditions accounting for flow separation.

    The model implemented is based on the work of Summerfield et al. (1954) and assumes
    that flow separation occurs when the exit pressure is below a certain fraction of
    the ambient pressure.

    Args:
        k_exhaust: Isentropic exponent at exit.
        expansion_ratio: Geometric expansion ratio.
        chamber_pressure: Chamber pressure [Pa].
        external_pressure: Ambient pressure [Pa].
        separation_pressure_ratio: Separation-to-ambient pressure ratio.

    Returns:
        Effective expansion ratio and effective exit pressure [Pa].

    References:
        Summerfield, M., Foster, C. R., & Swan, W. C. (1954). Flow separation in
        overexpanded supersonic exhaust nozzles.
    """
    exit_pressure = isentropic.get_exit_pressure(
        k_exhaust, expansion_ratio, chamber_pressure
    )
    separation_pressure = separation_pressure_ratio * external_pressure
    if exit_pressure >= separation_pressure:
        return expansion_ratio, exit_pressure

    sonic_pressure = chamber_pressure * isentropic.get_critical_pressure_ratio(
        k_exhaust
    )
    if separation_pressure >= sonic_pressure:
        return 1.0, sonic_pressure

    effective_expansion_ratio = cast(
        float,
        scipy.optimize.brentq(
            lambda ratio: (
                isentropic.get_exit_pressure(k_exhaust, ratio, chamber_pressure)
                - separation_pressure
            ),
            a=1.001,
            b=expansion_ratio,
        ),
    )
    return effective_expansion_ratio, separation_pressure

get_thrust_from_thrust_coefficient(thrust_coefficient, chamber_pressure, nozzle_throat_area)

Get thrust from thrust coefficient.

Parameters:

Name Type Description Default
thrust_coefficient float

Thrust coefficient.

required
chamber_pressure float

Chamber stagnation pressure [Pa].

required
nozzle_throat_area float

Nozzle throat area [m^2].

required

Returns:

Type Description
float

Thrust [N].

Source code in machwave/core/compressible_flow/nozzle.py
def get_thrust_from_thrust_coefficient(
    thrust_coefficient: float, chamber_pressure: float, nozzle_throat_area: float
) -> float:
    """
    Get thrust from thrust coefficient.

    Args:
        thrust_coefficient: Thrust coefficient.
        chamber_pressure: Chamber stagnation pressure [Pa].
        nozzle_throat_area: Nozzle throat area [m^2].

    Returns:
        Thrust [N].
    """
    return thrust_coefficient * chamber_pressure * nozzle_throat_area

is_flow_choked(chamber_pressure, external_pressure, critical_pressure_ratio)

Check if flow is choked.

Parameters:

Name Type Description Default
chamber_pressure float

Chamber pressure [Pa].

required
external_pressure float

External pressure [Pa].

required
critical_pressure_ratio float

Critical pressure ratio.

required

Returns:

Type Description
bool

True if flow is choked, False otherwise.

Source code in machwave/core/compressible_flow/isentropic.py
def is_flow_choked(
    chamber_pressure: float,
    external_pressure: float,
    critical_pressure_ratio: float,
) -> bool:
    """
    Check if flow is choked.

    Args:
        chamber_pressure: Chamber pressure [Pa].
        external_pressure: External pressure [Pa].
        critical_pressure_ratio: Critical pressure ratio.

    Returns:
        True if flow is choked, False otherwise.
    """
    return chamber_pressure >= external_pressure / critical_pressure_ratio