STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_ullage_storage.py
Go to the documentation of this file.
1"""An ullage is solved with the network, not held at its start-of-step pressure.
2
3A 0.41 L ullage behind a Cv 4 press solenoid moves a psi on about two grams,
4and the solenoid passes a hundred grams a second on that psi. Held fixed for a
5coupling step, two such tanks on one manifold flip-flopped: one a few psi high
6dumping into the manifold, the other taking 100 g/s and refusing nearly all of
7it at its supply clip, while the regulator drooped at a phantom 60 g/s that no
8vessel ever kept. LE4's pair sat 25 psi under lockup for as long as the press
9valves were held open, and Ox Press topped out near 455 psig in a cockpit walk.
10
11``solve_steady(storage=...)`` makes the ullage an unknown with a backward-Euler
12storage term; ``Session._ullage_storage`` reads the term off the vessel.
13"""
14
15from __future__ import annotations
16
17import pytest
18from test_press_path_coupling import _helium_stand
19from test_solve_steady import _valve
20
21from feedtwin.session import core as C
22from feedtwin.session.burn import press_valves
23from feedtwin.session.gauge import psig
24from feedtwin.solve import Network, solve_steady
25
26
27def _gas_line() -> Network:
28 net = Network()
29 net.add_node("supply", "helium", 293.0, pressure=40.0e5)
30 net.add_node("tank", "helium", 293.0, pressure=38.0e5)
31 net.add_branch("SOL", _valve("SOL", 4.0), "supply", "tank") # type: ignore[arg-type]
32 return net
33
34
36 net = _gas_line()
37 fixed = solve_steady(net)
38 admittance, reference = 1.0e-6, 38.0e5 # kg/s per Pa: ~7 g/s a psi
39 stored = solve_steady(net, storage={"tank": (admittance, reference)})
40
41 assert stored.converged
42 p, flow = stored.pressures["tank"], stored.flows["SOL"]
43 assert flow == pytest.approx(admittance * (p - reference), rel=1e-6)
44 assert stored.max_mass_residual < 1e-9
45 # The vessel rises toward its supply, so less flows than into a wall.
46 assert reference < p < 40.0e5
47 assert 0.0 < flow < fixed.flows["SOL"]
48 # The boundary the network was built with is untouched.
49 assert net.nodes["tank"].pressure == 38.0e5
50
51
53 net = _gas_line()
54 shut = {"SOL.command": 0.0}
55 plain = solve_steady(net, signals=shut)
56 stored = solve_steady(net, signals=shut, storage={"tank": (1.0e-6, 30.0e5)})
57 assert stored.pressures == plain.pressures
58 assert stored.flows == plain.flows
59
60
61def _hold(seconds: float = 1.5) -> tuple[C.Session, list[float], float, float]:
62 """Pad hold with both press valves open: the LOX ullage collapsing, the
63 mains shut. Returns the session, the tank spread over the last half, and
64 the gas the bottle gave and the ullages kept over the whole hold [kg]."""
65 session = _helium_stand()
66 for symbol in press_valves(session):
67 session.set_valve(symbol, True)
68
69 def bottles() -> float:
70 return sum(b.state.mass for b in session.bottles.values())
71
72 def ullages() -> float:
73 return sum(
74 s.state.ullage.mass + s.state.vapour_mass for s in session.tanks.values()
75 )
76
77 gave, kept = bottles(), ullages()
78 spread = []
79 while session.t < seconds:
80 session.step(0.05)
81 if session.t > seconds / 2:
82 p = [psig(s.pressure) for s in session.tanks.values()]
83 spread.append(max(p) - min(p))
84 return session, spread, gave - bottles(), ullages() - kept
85
86
88 session, spread, gave, kept = _hold()
89 pressures = [psig(s.pressure) for s in session.tanks.values()]
90 # 560 psi regulator, 20 psi droop at 20 g/s: a few g/s of collapse
91 # costs it a few psi, and nothing else should.
92 assert all(555.0 < p < 561.0 for p in pressures), pressures
93 assert max(spread) < 0.5
94 # What the bottle gives is what the ullages keep, less the little the
95 # LOX boils into its own ullage. The flip-flop had the regulator passing
96 # sixty times what any vessel kept, and handing the rest back.
97 assert 0.0 < gave <= kept
98 assert gave == pytest.approx(kept, rel=0.1)
99
100
102 monkeypatch: pytest.MonkeyPatch,
103) -> None:
104 monkeypatch.setattr(C.Session, "_ullage_storage", lambda *a: {})
105 _, spread, _, _ = _hold()
106 assert max(spread) > 20.0
#define min(a, b)
Definition Arduino.h:42
#define max(a, b)
Definition Arduino.h:43
None test_and_without_storage_the_pair_flip_flops(pytest.MonkeyPatch monkeypatch)
None test_storage_on_a_cut_off_node_changes_nothing()
None test_two_tanks_held_at_lockup_sit_on_it()
None test_a_stored_node_lands_where_its_inflow_puts_it()
tuple[C.Session, list[float], float, float] _hold(float seconds=1.5)