88 session = open_session(
_model(), load_machine(tables=TABLES), setup=burn_setup())
89 session.prime(tank_psi=550.0, copv_psi=4500.0, loads={
"OXT": 6.611})
90 assert session.tanks[
"OXT"].state.liquid_mass == pytest.approx(6.611, rel=1e-12)
92 fuel = session.tanks[
"FUT"]
93 rho = fuel.tank.liquid.get(
"rho", T=fuel.state.liquid_temperature, q=0.0)
94 expected = fuel.tank.geometry.total_volume * 0.95 * rho
95 assert fuel.state.liquid_mass == pytest.approx(expected, rel=1e-12)
100 """Without ``loads`` every tank holds ``fill_fraction`` of its volume as liquid, by
101 hand from the volume and the density: the behaviour before ``loads`` existed."""
102 a = open_session(
_model(), load_machine(tables=TABLES), setup=burn_setup())
103 a.prime(fill_fraction=0.8, tank_psi=500.0)
104 for sim
in a.tanks.values():
105 rho = sim.tank.liquid.get(
"rho", T=sim.state.liquid_temperature, q=0.0)
106 expected = sim.tank.geometry.total_volume * 0.8 * rho
107 assert sim.state.liquid_mass == pytest.approx(expected, rel=1e-12), sim.id
136 """Fire for a third of a second and check the bookkeeping holds.
138 Conservation is the check worth having here: the propellant that left the
139 tanks has to be the propellant the chamber says it burned, integrated over
140 the same steps. It is independent of every correlation in the model.
142 session = open_session(
143 _model(engine=
True), load_machine(tables=TABLES), setup=burn_setup()
145 loads = {
"OXT": 6.0,
"FUT": 4.0}
147 tank_psi=550.0, loads=loads, settle=
False, lead_in_s=0.1, horizon_s=0.3
149 trace = run_burn(session, plan)
151 assert trace.end
is not None and not trace.end.cancelled
153 assert n == trace.end.steps
154 assert trace.firing.count(
False) == 2
155 assert set(trace.probes.injector_inlet) == {
"oxidiser",
"fuel"}
156 for node
in trace.nodes():
157 assert len(trace.pressure[node]) == n
159 firing = [i
for i, f
in enumerate(trace.firing)
if f]
160 pc = trace.chamber[
"pressure_Pa"]
161 assert all(pc[i] > 2.0 * ATMOSPHERE
for i
in firing[1:])
162 assert all(trace.chamber[
"thrust_N"][i] > 0.0
for i
in firing[1:])
164 for side, tank
in ((
"oxidiser",
"OXT"), (
"fuel",
"FUT")):
165 inlet = trace.pressure[trace.probes.injector_inlet[side]]
166 tank_p = trace.tank[tank][
"pressure_Pa"]
168 assert pc[i] < inlet[i] < tank_p[i] + 5.0 * PSI
171 for tank, key
in ((
"OXT",
"mdot_oxidiser"), (
"FUT",
"mdot_fuel")):
172 left = loads[tank] - trace.tank[tank][
"liquid_mass_kg"][-1]
173 burned = sum(trace.chamber[key][i] * dt
for i
in firing)
174 assert burned == pytest.approx(left, rel=0.03), tank
179 """A session writes its run into the model's network; a second session on the same model
180 would start from the first one's end state. open_session refuses it."""
182 open_session(model, load_machine(tables=TABLES), setup=burn_setup())
183 with pytest.raises(ValueError, match=
"fresh model"):
184 open_session(model, load_machine(tables=TABLES), setup=burn_setup())
186 open_session(
_model(), load_machine(tables=TABLES), setup=burn_setup())
202 """With ``end_on_depletion`` the last step lands the first tank on ``dry_kg``, so
203 the impulse grows smoothly with the load. On whole steps it moves in jumps of a
204 step's worth as the depletion crosses a step boundary; that is the default, and
205 the study keeps it."""
207 def fire(ox_kg: float, end: bool):
208 session = open_session(
209 _model(engine=
True), load_machine(tables=TABLES), setup=burn_setup()
213 loads={
"OXT": ox_kg,
"FUT": 4.0},
217 end_on_depletion=end,
220 trace = run_burn(session, plan)
221 assert trace.end
is not None and trace.end.tank ==
"OXT"
225 loads = [0.40 + 0.015 * k
for k
in range(8)]
226 smooth, stepped = [], []
228 trace, plan = fire(ox,
True)
229 assert trace.tank[
"OXT"][
"liquid_mass_kg"][-1] == pytest.approx(
230 plan.dry_kg, abs=0.003
232 smooth.append(
_impulse(trace, plan))
233 trace, plan = fire(ox,
False)
234 stepped.append(
_impulse(trace, plan))
235 d_smooth = [b - a
for a, b
in zip(smooth, smooth[1:])]
236 d_stepped = [b - a
for a, b
in zip(stepped, stepped[1:])]
238 assert all(d > 0.0
for d
in d_smooth), d_smooth
239 assert max(d_smooth) < 2.0 *
min(d_smooth), d_smooth
241 assert max(d_stepped) > 3.0 *
max(d_smooth), (d_stepped, d_smooth)