STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_solver_record.py
Go to the documentation of this file.
1"""The solver tab's record (feedtwin.session.diagnostics): residuals per tick, and a
2mass balance that a leak cannot hide from.
3
4Checked against conservation itself: through a press and a burn, everything the
5vessels gained or lost is either what crossed the boundary (engine, vents, the
6built-in loads) or what the vessels' own guards booked -- to rounding. And the
7check can fail: a bottle that quietly loses gas shows up as unexplained mass.
8"""
9
10from __future__ import annotations
11
12import pytest
13from test_press_path_coupling import _helium_stand
14from test_session_burn import TABLES, _model, needs_engine, needs_stand
15
16from feedtwin.session.burn import press_valves
17from feedtwin.session.core import BottleSim
18
19
20def _press_and_burn(): # type: ignore[no-untyped-def]
21 session = _helium_stand()
22 for valve in press_valves(session):
23 session.set_valve(valve, True)
24 for _ in range(25):
25 session.step(0.02)
26 for symbol, signal in session.model.built.actuators.items():
27 if not signal.endswith(".dome"):
28 session.set_valve(symbol, True)
29 for _ in range(50):
30 session.step(0.02)
31 return session
32
33
35 session = _press_and_burn()
36 log = list(session.solver_log)
37 assert len(log) == 75
38 assert all(r.converged for r in log)
39 assert all(r.couplings >= 1 and r.iterations >= r.couplings for r in log)
40 assert max(r.residual for r in log) < 1e-3
41
42
44 session = _press_and_burn()
45 last = session.solver_log[-1]
46 assert last.crossed_out_kg > 1.0, "the mains drained the tanks"
47 # Everything not explained by the boundary is the guards' own booking.
48 assert last.mass_error_kg == pytest.approx(last.guard_kg, abs=1e-9)
49 assert abs(last.mass_error_kg) < 1e-4 * last.throughput_kg
50
51
52def test_a_leak_shows_up(monkeypatch: pytest.MonkeyPatch) -> None:
53 """The check can fail: a bottle that loses a milligram a step it books
54 nowhere is mass the balance cannot explain."""
55 real = BottleSim.advance
56
57 def leaky(self, dt, **kw): # type: ignore[no-untyped-def]
58 real(self, dt, **kw)
59 self.state = type(self.state)(
60 mass=self.state.mass - 1e-6,
61 energy=self.state.energy,
62 wall_temperature=self.state.wall_temperature,
63 )
64
65 monkeypatch.setattr(BottleSim, "advance", leaky)
66 session = _press_and_burn()
67 last = session.solver_log[-1]
68 assert abs(last.mass_error_kg - last.guard_kg) > 1e-4
69
70
71@needs_stand
72@needs_engine
74 from feedtwin.session import load_machine
75 from feedtwin.session.burn import BurnPlan, burn_setup, open_session, run_burn
76
77 session = open_session(
78 _model(engine=True), load_machine(tables=TABLES), setup=burn_setup()
79 )
80 run_burn(
81 session,
82 BurnPlan(
83 tank_psi=550.0,
84 loads={"OXT": 6.0, "FUT": 4.0},
85 settle=False,
86 lead_in_s=0.1,
87 horizon_s=0.3,
88 ),
89 )
90 firing = [r for r in session.solver_log if r.chamber_residual_psi > 0.0]
91 assert firing, "the chamber closure was recorded"
92 tolerance = session.setup.chamber_tolerance_psi
93 assert max(r.chamber_residual_psi for r in firing[1:]) <= tolerance * 1.0001
#define max(a, b)
Definition Arduino.h:43
None test_a_leak_shows_up(pytest.MonkeyPatch monkeypatch)
None test_the_mass_that_moved_is_the_mass_that_crossed_or_was_guarded()
None test_every_tick_is_recorded_and_converged()
None test_the_chamber_closure_is_recorded_below_its_tolerance()