STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_cea_table_clamp_reported.py
Go to the documentation of this file.
1"""A solve that read CEA off the table's clamped edge says so.
2
3``CEACache.eval`` clamps an off-table Pc, O/F or ε to the table edge and returns the edge's c*, Tc
4and γ; chamber_solver recorded ``cea_clamped`` and nothing read it. On the LE4 (3) stand's engine
5(ethalox table O/F 1.0–2.5, Pc 1–9 MPa) 578/300 psia solves at O/F 3.52 on the 2.5 edge's c*
6(flat past it, though it falls ~116 m/s per unit O/F just inside), and 120/120 psia at Pc 99 psia
7below the 145 psia floor -- most of a blowdown Time-Series run on this engine. Forward mode showed
8no warning; the Time-Series summary none either.
9"""
10
11from __future__ import annotations
12
13import copy
14import types
15
16import numpy as np
17import pytest
18
19PSI = 6894.757
20CFG = "tests/fixtures/ethalox_6500N_doublet_cad_2026-09-28.yaml"
21
22
23@pytest.fixture(scope="module")
24def runner():
25 from engine.core.runner import PintleEngineRunner
26 from engine.pipeline.io import load_config
27
28 cfg = load_config(CFG)
29 return cfg, PintleEngineRunner(copy.deepcopy(cfg))
30
31
32def _verdict(cfg, r):
33 from engine.pipeline.forward_report import forward_report
34
35 return {v["key"]: v for v in forward_report(cfg, r)["verdicts"]}["cea_table"]
36
37
39 cfg, run = runner
40 r = run.evaluate(578 * PSI, 578 * PSI, silent=True, rich_stability=True)
41 assert r["diagnostics"]["cea_clamped"] == ()
42 v = _verdict(cfg, r)
43 assert v["status"] == "ok" and v["value"] == "inside"
44
45
47 cfg, run = runner
48 r = run.evaluate(578 * PSI, 300 * PSI, silent=True, rich_stability=True)
49 assert r["MR"] > 2.5, "the case no longer leaves the table; nothing tested"
50 rng = r["diagnostics"]["cea_table_range"]["MR"]
51 assert rng == pytest.approx([1.0, 2.5])
52 v = _verdict(cfg, r)
53 assert v["status"] == "bad"
54 assert "O/F 3.5" in v["basis"] and "1.00–2.50" in v["basis"], v["basis"]
55
56
58 cfg, run = runner
59 r = run.evaluate(120 * PSI, 120 * PSI, silent=True, rich_stability=True)
60 v = _verdict(cfg, r)
61 assert v["status"] == "bad" and "Pc" in v["basis"] and "psia" in v["basis"], v["basis"]
62
63
64class _Runner:
65 """evaluate_arrays with closure diagnostics; points 2 and 3 clamped on O/F."""
66
67 def __init__(self):
68 self.config = types.SimpleNamespace(ablative_cooling=None, press_tank=None)
69
70 def evaluate_arrays(self, P_O, P_F):
71 n = len(P_O)
72 one = np.ones(n)
73 diags = [{"cea_clamped": (), "cea_table_range": {"MR": [1.0, 2.5]}} for _ in range(n)]
74 for i in (2, 3):
75 diags[i] = {"cea_clamped": ("MR",), "cea_table_range": {"MR": [1.0, 2.5]}}
76 return {
77 "Pc": 2.0e6 * one, "F": 6000.0 * one, "Isp": 220.0 * one, "MR": np.array([1.5, 2.0, 3.0, 3.5, 1.5]),
78 "mdot_O": 1.8 * one, "mdot_F": 1.0 * one, "mdot_total": 2.8 * one,
79 "cstar_actual": 1550.0 * one, "gamma": 1.2 * one, "diagnostics": diags,
80 }
81
82
84 from backend.routers import timeseries as ts
85
86 times = np.linspace(0.0, 4.0, 5)
87 data, summary = ts.compute_timeseries_results(_Runner(), times, 500 * np.ones(5), 400 * np.ones(5), run_copv=False)
88 assert summary.get("cea_clamped_points") == 2, summary
89 assert summary["cea_clamped_axes"] == ["MR"]
90 assert data["cea_clamped"] == [False, False, True, True, False]
91 assert "t = 2.00 s" in summary["cea_clamped_note"] and "O/F 3.00 outside 1.00–2.50" in summary["cea_clamped_note"]
92
93
95 from backend.routers import timeseries as ts
96
97 times = np.linspace(0.0, 4.0, 5)
98 lox = np.array([5.0, 4.0, 3.0, 0.0, 0.0]) # dry from point 3
99 data, summary = ts.compute_timeseries_results(
100 _Runner(), times, 500 * np.ones(5), 400 * np.ones(5), run_copv=False, lox_mass_kg=lox, fuel_mass_kg=5 * np.ones(5)
101 )
102 assert summary["cea_clamped_points"] == 1 and data["cea_clamped"][3] is False
103
104
106 from backend.routers import timeseries as ts
107
108 r = _Runner()
109 real = r.evaluate_arrays
110
111 def clean(P_O, P_F):
112 out = real(P_O, P_F)
113 out["diagnostics"] = [{"cea_clamped": ()} for _ in P_O]
114 return out
115
116 r.evaluate_arrays = clean
117 data, summary = ts.compute_timeseries_results(r, np.linspace(0.0, 4.0, 5), 500 * np.ones(5), 400 * np.ones(5), run_copv=False)
118 assert "cea_clamped" not in data and "cea_clamped_note" not in summary