STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_layerx_analytic Namespace Reference

Functions

 _choked_blowdown (str gas, bool isothermal, float duration, int steps=4000, *, float V=0.05, float p0=2.0e5, float T0=300.0, float bore=2.0e-3, float cd=0.85)
 test_a_choked_blowdown_follows_its_closed_form (gas, isothermal, duration)
 test_the_isothermal_and_adiabatic_bounds_bracket_a_real_wall ()
 test_a_network_solves_an_orifice_to_cd_a_sqrt_2_rho_dp (dp_bar, cd, bore_mm)
 _column (float gravity, float dp, float climb=1.3716)
 test_a_column_at_a_known_specific_force_holds_exactly_rho_a_h ()
float _rayleigh_kappa (float contraction, float gamma)
 le4_point ()
 test_enginedesign_closes_its_chamber_on_mdot_cstar_over_At_with_the_rayleigh_loss (le4_point)
 test_the_engine_card_returns_enginedesigns_pc_at_a_fixed_point (le4_point)

Variables

 feedtwin = pytest.importorskip("feedtwin", reason="lib/feedtwin is not installed (pip install -e ../lib/feedtwin)")
 M = Provenance.MANUFACTURER
float G0 = 9.80665
float PSI = 6894.757293168361
str BASELINE = Path(__file__).resolve().parents[1] / "docs" / "layerx" / "baseline-2026-10-02.json"
float LIFTOFF = 8.25 * G0

Detailed Description

Closed forms Layer X's physics must reproduce, through the components it actually burns with.

Each test sets up a case with a textbook answer, runs it through lib/feedtwin (or EngineDesign's
chamber solve and the Layer X engine card), and compares with the formula written out here. Each
was shown to fail when its formula is broken in the code (see the mutation notes in each docstring).

What lib/feedtwin already checks, and is not repeated here:

* ``tests/test_vessels.py::test_adiabatic_blowdown_matches_the_closed_form``: a vessel emptied at a
  *prescribed* flow follows T/T0 = (m/m0)^(g-1). Here the flow is the choked orifice's own, so the
  time history checks the orifice and the vessel together.
* ``tests/test_comps_validation.py::test_orifice_cd_inverts_the_bernoulli_relation``: the orifice
  component alone. Here it is solved inside a network between two pressures.
* ``tests/test_body_acceleration.py``: a pipe's static head and a session's tank head at 7 g. Here the
  network solve itself must balance a column at a non-standard specific force.
* ``tests/test_engine_card.py::test_card_chamber_pressure_and_thrust_follow_the_tables``: a constant
  card's Pc. Here the card is fitted to the LE4 engine and checked against EngineDesign's closure,
  whose Rayleigh stagnation loss is worked out by hand.

Function Documentation

◆ _choked_blowdown()

test_layerx_analytic._choked_blowdown ( str gas,
bool isothermal,
float duration,
int steps = 4000,
* ,
float V = 0.05,
float p0 = 2.0e5,
float T0 = 300.0,
float bore = 2.0e-3,
float cd = 0.85 )
protected
A vessel emptied through a choked gas orifice into vacuum: feedtwin's ``gas_orifice`` sets the
flow from the vessel's state at every step. ``isothermal``: the vessel wears a wall of effectively
infinite heat capacity, coupled tightly (500 W/K against ~80 J/K of gas), which holds the gas at
its temperature; otherwise the vessel has no wall and the expansion is adiabatic.

Definition at line 46 of file test_layerx_analytic.py.

References max.

Referenced by test_a_choked_blowdown_follows_its_closed_form(), and test_the_isothermal_and_adiabatic_bounds_bracket_a_real_wall().

◆ _column()

test_layerx_analytic._column ( float gravity,
float dp,
float climb = 1.3716 )
protected
Ethanol in a vertical 1/2 in x 0.035 in line, ``climb`` metres high (the team's 4.5 ft fuel
run), held at the bottom and ``dp`` lower at the top.

Definition at line 128 of file test_layerx_analytic.py.

Referenced by test_a_column_at_a_known_specific_force_holds_exactly_rho_a_h().

◆ _rayleigh_kappa()

float test_layerx_analytic._rayleigh_kappa ( float contraction,
float gamma )
protected
``P_injector_end / P0_nozzle`` of a constant-area combustor (heat added along a Rayleigh line):
``(1 + g M^2) / (1 + (g-1)/2 M^2)^(g/(g-1))`` with ``M`` the chamber-end Mach number on the
subsonic branch of ``A/A* = (1/M) [(2/(g+1)) (1 + (g-1)/2 M^2)]^((g+1)/(2(g-1)))`` (Sutton &
Biblarz, 9th ed., sec. 3.3 and Table 3-2; Huzel & Huang, sec. 2). Solved here by bisection.

Definition at line 169 of file test_layerx_analytic.py.

Referenced by test_enginedesign_closes_its_chamber_on_mdot_cstar_over_At_with_the_rayleigh_loss(), and test_the_engine_card_returns_enginedesigns_pc_at_a_fixed_point().

◆ le4_point()

test_layerx_analytic.le4_point ( )

Definition at line 188 of file test_layerx_analytic.py.

◆ test_a_choked_blowdown_follows_its_closed_form()

test_layerx_analytic.test_a_choked_blowdown_follows_its_closed_form ( gas,
isothermal,
duration )
At two bar both gases are ideal to ~0.05 % (the reference's premise); the residual is that and
the change of the real gamma with temperature, ~0.3 % at most by p/p0 = 0.2. Mutation: scaling
``feedtwin.comps.gas.choked_mass_flow`` by 1.02 (or dropping its sqrt(gamma)) fails this.

Definition at line 84 of file test_layerx_analytic.py.

References _choked_blowdown().

◆ test_a_column_at_a_known_specific_force_holds_exactly_rho_a_h()

test_layerx_analytic.test_a_column_at_a_known_specific_force_holds_exactly_rho_a_h ( )
``dp = rho a h`` (hydrostatics in the vehicle frame, a the specific force along the axis). Held
at exactly that difference, the column does not move; held at the pad's rho g0 h under the same
specific force, it falls. Mutation: a pipe whose static head uses standard gravity fails this.

Definition at line 147 of file test_layerx_analytic.py.

References _column().

◆ test_a_network_solves_an_orifice_to_cd_a_sqrt_2_rho_dp()

test_layerx_analytic.test_a_network_solves_an_orifice_to_cd_a_sqrt_2_rho_dp ( dp_bar,
cd,
bore_mm )
``mdot = Cd A sqrt(2 rho dp)`` for an incompressible liquid through a sharp orifice between two
held pressures (Sutton & Biblarz eq. 8-1). Mutation: dropping the 2 in ``OrificeCd`` fails this.

Definition at line 107 of file test_layerx_analytic.py.

◆ test_enginedesign_closes_its_chamber_on_mdot_cstar_over_At_with_the_rayleigh_loss()

test_layerx_analytic.test_enginedesign_closes_its_chamber_on_mdot_cstar_over_At_with_the_rayleigh_loss ( le4_point)
``Pc = kappa mdot c*/A_t``: c* = eta_c* c*_ideal is referred to the nozzle's stagnation
pressure, and Pc is the injector end, kappa = 1.004 above it on LE4 (contraction 7.06). Mutation:
EngineDesign's ``nozzle_stagnation_loss`` returning 1.0 fails this by 0.4 %.

Definition at line 202 of file test_layerx_analytic.py.

References _rayleigh_kappa().

◆ test_the_engine_card_returns_enginedesigns_pc_at_a_fixed_point()

test_layerx_analytic.test_the_engine_card_returns_enginedesigns_pc_at_a_fixed_point ( le4_point)
The Layer X card stores c*_card = Pc A_t / mdot (the injector-end c*), so its chamber returns
``Pc = mdot c*_card / A_t`` = EngineDesign's Pc at a point it was fitted through, to the table's
interpolation error. Mutation: the card chamber's Pc without the 1/A_t, or c* scaled, fails this.

Definition at line 216 of file test_layerx_analytic.py.

References _rayleigh_kappa().

◆ test_the_isothermal_and_adiabatic_bounds_bracket_a_real_wall()

test_layerx_analytic.test_the_isothermal_and_adiabatic_bounds_bracket_a_real_wall ( )
Physical ordering, not a closed form: a wall that exchanges heat keeps the gas warmer than
adiabatic and cooler than isothermal, so its pressure lies between the two closed forms.

Definition at line 94 of file test_layerx_analytic.py.

References _choked_blowdown().

Variable Documentation

◆ BASELINE

str test_layerx_analytic.BASELINE = Path(__file__).resolve().parents[1] / "docs" / "layerx" / "baseline-2026-10-02.json"

Definition at line 40 of file test_layerx_analytic.py.

◆ feedtwin

test_layerx_analytic.feedtwin = pytest.importorskip("feedtwin", reason="lib/feedtwin is not installed (pip install -e ../lib/feedtwin)")

Definition at line 29 of file test_layerx_analytic.py.

◆ G0

float test_layerx_analytic.G0 = 9.80665

Definition at line 38 of file test_layerx_analytic.py.

◆ LIFTOFF

float test_layerx_analytic.LIFTOFF = 8.25 * G0

Definition at line 143 of file test_layerx_analytic.py.

◆ M

test_layerx_analytic.M = Provenance.MANUFACTURER

Definition at line 37 of file test_layerx_analytic.py.

◆ PSI

float test_layerx_analytic.PSI = 6894.757293168361

Definition at line 39 of file test_layerx_analytic.py.