STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_spray_report.py
Go to the documentation of this file.
1"""The spray and mixing report (engine/core/injectors/spray_report.py) against the solve it reads
2and against hand numbers for the checks it makes itself."""
3import copy
4import math
5
6import pytest
7
8PSI = 6894.757
9CFG = "tests/fixtures/ethalox_6500N_doublet_cad_2026-09-28.yaml"
10
11
12@pytest.fixture(scope="module")
13def solved():
14 from engine.pipeline.io import load_config
15 from engine.core.injectors.spray_report import _solve
16 cfg = load_config(CFG)
17 return cfg, _solve(cfg)
18
19
20def _rows(rep):
21 return {r["label"]: r for s in rep["sections"] for r in s["rows"]}
22
23
25 from engine.core.injectors.spray_report import spray_mixing_report
26 cfg, r = solved
27 rows = _rows(spray_mixing_report(cfg, r, with_sensitivity=False))
28 d = r["diagnostics"]
29 ce = d["cstar_efficiency"]
30 assert rows["fuel D32"]["value"] == pytest.approx(d["D32_F"] * 1e6, rel=1e-12)
31 assert rows["Rupe M"]["value"] == d["rupe_M"]
32 assert rows["η mixing"]["value"] == ce["eta_mixing"]
33 assert rows["fuel 95 % vaporized, from the face"]["value"] == pytest.approx(
34 (ce["x_vap95_F"] + ce["x_drop_formation"]) * 1000, rel=1e-12)
35
36
38 """Core: 7 d sqrt(rho_l/rho_g) (Chehroudi et al. 1985, low C). Lean: the momentum resultant
39 of the two jets, LOX inner and aiming outward (as scripts/design_handcheck.py)."""
40 from engine.core.injectors.spray_report import spray_mixing_report
41 cfg, r = solved
42 rows = _rows(spray_mixing_report(cfg, r, with_sensitivity=False))
43 d = r["diagnostics"]
44 rho_g = d["rho_gas_breakup"]
45 assert rows["LOX intact core (low bound)"]["value"] == pytest.approx(7.0 * math.sqrt(1140.0 / rho_g), rel=1e-12)
46 g = cfg.injector.geometry
47 vO = r["mdot_O"] / (1140.0 * 24 * math.pi * g.oxidizer.d_jet ** 2 / 4)
48 vF = r["mdot_F"] / (789.0 * 24 * math.pi * g.fuel.d_jet ** 2 / 4)
49 pO, pF = r["mdot_O"] * vO, r["mdot_F"] * vF
50 s35, s48 = math.radians(35.0), math.radians(48.0)
51 lean = math.degrees(math.atan2(pO * math.sin(s35) - pF * math.sin(s48), pO * math.cos(s35) + pF * math.cos(s48)))
52 assert rows["spray lean"]["value"] == pytest.approx(lean, rel=1e-6)
53 assert rows["LOX jet velocity"]["value"] == pytest.approx(vO, rel=1e-9)
54
55
57 from engine.core.injectors.spray_report import sensitivity
58 cfg, r = solved
59 cases = {c["case"]: c for c in sensitivity(cfg, r)}
60 assert all(c["applied"] and "error" not in c for c in cases.values())
61 base = cases["as configured"]
62 # E_m moves mixing and leaves vaporization alone; the SMD transfer does the reverse.
63 lo, hi = cases["Rupe E_m opt 0.70"], cases["Rupe E_m opt 0.85"]
64 assert lo["eta_mix"] < base["eta_mix"] < hi["eta_mix"] and lo["F"] < base["F"] < hi["F"]
65 dj = cases["SMD transfer: Dombrowski & Johns"]
66 assert dj["eta_vap"] > base["eta_vap"] and dj["eta_mix"] == pytest.approx(base["eta_mix"], abs=2e-3)
67 # the config itself is untouched by the sweep
68 assert cfg.combustion.efficiency.rupe_Em_opt == 0.80 and cfg.spray.smd.smd_property_transfer == "tn4087"
test_every_sensitivity_case_is_honoured_and_moves_what_it_should(solved)
test_rows_are_the_solvers_numbers(solved)
test_intact_core_and_lean_by_hand(solved)