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

Classes

class  TestAccelMatchesPython
class  TestRandomizedSweep
class  TestCoolingIsActuallyApplied
class  TestDeliveredIspInvariant
class  TestChugKernelMatchesPython

Functions

 _chamber_gate ()
 _python_only ()
 _rel (got, want)
 _assert_close (name, got, want, rtol=RTOL)
 _py_field (ref, key)
 _rig (cfg_rel)
 _default_path (r, p)
 _need_numba ()
 test_injector_solve_matches_python (cfg_rel)
 test_default_path_matches_python_on_the_shipped_engine ()
 test_chamber_kernel_serves_the_designs ()
 test_heatup_tables_match_coolprop ()

Variables

 ROOT = Path(__file__).resolve().parents[1]
float PSI_TO_PA = 6894.76
float PA_AMBIENT = 101325.0
 _ab_parity
list POINTS_PSI = [(563.467, 567.644), (518.4, 550.6), (597.3, 584.7)]
int RTOL = 1e-6
list CONFIGS
list CORE_FIELDS
list DIAG_FIELDS
dict _RIGS = {}
list _INJ_CONFIGS
int _INJ_CORE_KEYS = 18
list _INJ_KEYS

Detailed Description

Live A/B parity for the Numba accelerator against the authoritative Python physics.

Runs both implementations on the same inputs at test time and diffs them field by
field, so a drift on EITHER side fails regardless of which one moved. This is the
sole numeric guard on the accelerated path now that the C port is gone.

TOLERANCE. RTOL is 1e-6, not the 2e-3 the retired C suite used. Measured agreement
on 120 randomized points across both configs is ~2.5e-9 -- the accelerated and
Python paths run the same physics and differ only by Brent's convergence
tolerance, so 1e-6 leaves ~400x headroom while still being three orders tighter
than the old contract. If a change pushes this above 1e-6, that is a physics
divergence, not rounding: fix it rather than widening the bound.

THE REFERENCE MUST BE FORCED TO PYTHON. With the accelerator enabled,
runner.evaluate reaches chamber_solver._accel_chamber_pc -> accel.chamber_solve
and closure.flows -> accel.solve, so an unguarded "Python" reference is largely
the same numba kernels and the comparison is self-referential (it reads as ~1e-15
agreement, which is the tell). _python_only() below disables the accelerator for
the reference computation; without it this suite proves nothing.

THE CONFIG LIST IS DELIBERATE. canonical/impinging.yaml has ablative cooling ON and
a back-channel ring manifold, impinging_lox_ch4_8000N.yaml has neither (plenum, no
liner), canonical/pintle.yaml exercises the pintle injector -- a different solve
(kernels.injector_solve_pintle) and a different mixing input: no Rupe M, so E_m is
rupe_Em_opt flat and the drops leave axially -- and the 6.5 kN ethalox fixture is the
design as drawn, where both liquids heat up on CoolProp tables (engine.accel.chamber).

Function Documentation

◆ _assert_close()

◆ _chamber_gate()

◆ _default_path()

test_numba_ab_parity._default_path ( r,
p )
protected
What Layer 1 actually consumes: accel.evaluate, else (None) the runner on the DEFAULT,
accelerator-enabled path -- which still routes the injector through accel.solve and the chug
scan through the kernel.

Definition at line 148 of file test_numba_ab_parity.py.

References _chamber_gate(), and split().

Referenced by test_numba_ab_parity.TestAccelMatchesPython.test_diagnostics(), test_numba_ab_parity.TestRandomizedSweep.test_sweep(), and test_numba_ab_parity.TestAccelMatchesPython.test_wrapper_fields().

◆ _need_numba()

◆ _py_field()

◆ _python_only()

test_numba_ab_parity._python_only ( )
protected
Force the authoritative Python path for the reference computation.

Disables strict mode as well as the accelerator. Under ED_REQUIRE_ACCEL=1 (the
CI parity job) closure._try_native_flows treats "disabled + strict" as a
genuine accelerator failure and raises -- which is exactly right in
production, and exactly wrong here, where the accelerator is off ON PURPOSE.
Without this the whole suite fails under CI's env while passing locally.

Definition at line 81 of file test_numba_ab_parity.py.

Referenced by _rig(), test_default_path_matches_python_on_the_shipped_engine(), and test_numba_ab_parity.TestRandomizedSweep.test_sweep().

◆ _rel()

◆ _rig()

◆ test_chamber_kernel_serves_the_designs()

test_numba_ab_parity.test_chamber_kernel_serves_the_designs ( )
Every chamber piece is mirrored, so the shipped design and the one drawn from CAD run on
the kernel (NOT_HANDLED here would put Layer 1 back on the ~60 ms Python solve).

Definition at line 470 of file test_numba_ab_parity.py.

References _need_numba().

◆ test_default_path_matches_python_on_the_shipped_engine()

test_numba_ab_parity.test_default_path_matches_python_on_the_shipped_engine ( )
The shipped 6.5 kN at its tank pressure and pad ambient: what the default (accelerated)
path returns -- the thing Layer 1 and the UI read -- must be the ED_ACCEL=off answer.

Definition at line 444 of file test_numba_ab_parity.py.

References _assert_close(), _need_numba(), _py_field(), and _python_only().

◆ test_heatup_tables_match_coolprop()

test_numba_ab_parity.test_heatup_tables_match_coolprop ( )
The one tabulation in the chamber kernel: CoolProp's liquid cp(T) and density at the
chamber pressure (combustion_physics.liquid_heatup_properties), for both liquids of the 6.5 kN
engine over the whole Pc window. A point the table refuses is allowed (the kernel returns no
solution and the caller runs Python); a point it answers must answer right.

Definition at line 486 of file test_numba_ab_parity.py.

References _need_numba().

◆ test_injector_solve_matches_python()

test_numba_ab_parity.test_injector_solve_matches_python ( cfg_rel)
closure.flows runs accel.solve on the DEFAULT path, on every residual of the Python chamber
solve. It must reproduce the Python injector: one closure pass with Cd untouched (impinging),
the feed exit dump K_exit on d_exit, the passage at A_hydraulic, pintle's fixed-K x*.

Definition at line 409 of file test_numba_ab_parity.py.

References _assert_close(), and _need_numba().

Variable Documentation

◆ _ab_parity

test_numba_ab_parity._ab_parity
protected
Initial value:
1= pytest.mark.skipif(
2 os.environ.get("ED_REQUIRE_ACCEL") != "1" and os.environ.get("ED_AB_PARITY") != "1",
3 reason="A/B parity runs in the accel-parity CI job; set ED_AB_PARITY=1 to run locally",
4)

Definition at line 46 of file test_numba_ab_parity.py.

◆ _INJ_CONFIGS

list test_numba_ab_parity._INJ_CONFIGS
protected
Initial value:
1= ["configs/ethalox_6500N.yaml", "configs/canonical/impinging.yaml",
2 "configs/impinging_lox_ch4_8000N.yaml", "configs/canonical/pintle.yaml",
3 "tests/fixtures/ethalox_6500N_doublet_cad_2026-09-28.yaml"]

Definition at line 388 of file test_numba_ab_parity.py.

◆ _INJ_CORE_KEYS

int test_numba_ab_parity._INJ_CORE_KEYS = 18
protected

Definition at line 391 of file test_numba_ab_parity.py.

◆ _INJ_KEYS

list test_numba_ab_parity._INJ_KEYS
protected
Initial value:
1= ["Cd_O", "Cd_F", "delta_p_feed_O", "delta_p_feed_F", "delta_p_injector_O",
2 "delta_p_injector_F", "D32_O", "D32_F", "x_star", "u_O", "u_F", "We_O", "We_F",
3 "momentum_ratio_R", "rupe_M", "u_axial_spray", "iterations",
4 "constraints_satisfied",
5 # spray/doublet geometry Layer 1 reads out of the diagnostics (geometry-fit term,
6 # final report); None on the accelerated path until the extras were added
7 "L_imp", "D_pitch_O", "D_pitch_F", "element_gap_O", "element_gap_F", "s_pair",
8 "vaporization_length_total", "L_sheet_breakup", "k_evap_O", "k_evap_F",
9 "tau_evap_O", "tau_evap_F", "J", "TMR", "theta", "Oh_O", "Oh_F", "rho_gas_breakup",
10 # the back-channel ring, hole by hole (impinging._manifold_diagnostics)
11 "element_flow_ratio_min_O", "element_flow_ratio_max_O", "element_flow_ratio_min_F",
12 "element_flow_ratio_max_F", "element_mixture_ratio_min", "element_mixture_ratio_max",
13 "manifold_branch_velocity_O", "manifold_branch_velocity_F", "Cd_eff_manifold_O",
14 "Cd_eff_manifold_F"]

Definition at line 392 of file test_numba_ab_parity.py.

◆ _RIGS

dict test_numba_ab_parity._RIGS = {}
protected

Definition at line 116 of file test_numba_ab_parity.py.

◆ CONFIGS

list test_numba_ab_parity.CONFIGS
Initial value:
1= [
2 ("configs/canonical/impinging.yaml", True), # impinging, ring manifold, ablative ON
3 ("configs/impinging_lox_ch4_8000N.yaml", False), # impinging, plenum, ablative off
4 ("configs/canonical/pintle.yaml", True), # pintle, ablative ON
5 # the 6.5 kN LOX/ethanol doublet as drawn (ring manifold, CoolProp heat-up of both liquids)
6 ("tests/fixtures/ethalox_6500N_doublet_cad_2026-09-28.yaml", True),
7]

Definition at line 61 of file test_numba_ab_parity.py.

◆ CORE_FIELDS

list test_numba_ab_parity.CORE_FIELDS
Initial value:
1= ["Pc", "F", "Isp", "MR", "cstar_actual", "eta_cstar",
2 "mdot_total", "mdot_O", "mdot_F", "Cf_actual",
3 "P_exit", "T_exit", "v_exit"]

Definition at line 69 of file test_numba_ab_parity.py.

◆ DIAG_FIELDS

list test_numba_ab_parity.DIAG_FIELDS
Initial value:
1= ["D32_O", "D32_F", "Cd_O", "Cd_F", "momentum_ratio_R",
2 "delta_p_feed_O", "delta_p_feed_F", "delta_p_injector_O",
3 "delta_p_injector_F", "A_geom_O", "A_geom_F", "A_eff_O", "A_eff_F",
4 "turbulence_intensity_mix", "u_O", "u_F", "We_O", "We_F"]

Definition at line 74 of file test_numba_ab_parity.py.

◆ PA_AMBIENT

float test_numba_ab_parity.PA_AMBIENT = 101325.0

Definition at line 39 of file test_numba_ab_parity.py.

◆ POINTS_PSI

list test_numba_ab_parity.POINTS_PSI = [(563.467, 567.644), (518.4, 550.6), (597.3, 584.7)]

Definition at line 57 of file test_numba_ab_parity.py.

◆ PSI_TO_PA

float test_numba_ab_parity.PSI_TO_PA = 6894.76

Definition at line 38 of file test_numba_ab_parity.py.

◆ ROOT

test_numba_ab_parity.ROOT = Path(__file__).resolve().parents[1]

Definition at line 37 of file test_numba_ab_parity.py.

◆ RTOL

int test_numba_ab_parity.RTOL = 1e-6

Definition at line 59 of file test_numba_ab_parity.py.