16from test_layerx_flight
import SITE_PA, built_flight, le4_arrays, le4_config, le4_loads, le4_payload
37 """No drag, no pressure thrust, constant F and mdot: the specific force is F/m(t) exactly, and
38 v = c ln(m0/m) - g0 t, z = c [t - (m/mdot) ln(m0/m)] - g0 t^2/2 with c = F/mdot (Sutton &
39 Biblarz, Rocket Propulsion Elements, 9th ed., ch. 4, vertical flight without drag)."""
40 m0, F, md = 80.0, 7000.0, 3.0
41 t = np.linspace(0.0, 3.5, 71)
42 ascent = flt.InlineAscent(mass_kg=m0, reference_area_m2=0.0193, nozzle_exit_area_m2=0.0, elevation_m=626.67,
43 reference_pressure_pa=
None, drag=
None, dt_max=0.01)
46 a = ascent.advance(float(tk), F, md)
48 assert a == pytest.approx(F / m, rel=1e-12)
49 assert ascent.m == pytest.approx(m, rel=1e-12)
50 assert ascent.v == pytest.approx(c * math.log(m0 / m) - G0 * tk, abs=1e-6)
51 assert ascent.z == pytest.approx(c * (tk - m / md * math.log(m0 / m)) - 0.5 * G0 * tk * tk, abs=1e-6)
52 assert ascent.liftoff_time_s == 0.0
59 """LE4's saved delivered curve, the same vehicle (mass, drag, nozzle, pad): the inline ascent's
60 specific force against RocketPy's at every firing sample while RocketPy's motor burns."""
61 t, F, mO, mF = le4_arrays()
63 mass = flt.liftoff_mass(config, le4_loads(), ambient_pa=SITE_PA)
64 assert mass[
"value"] == pytest.approx(float(fl.rocket.total_mass(0.0)), abs=1e-3)
65 out = flt.inline_specific_force(config, F, mO + mF, t, mass[
"value"], SITE_PA)
66 tb = float(fl.rocket.motor.burn_out_time)
68 assert burning.sum() == len(t) - 1
69 ours = np.asarray(out[
"accel_m_s2"])[burning]
70 theirs = np.array([flt.axial_acceleration(fl, float(x))
for x
in t[burning]])
71 assert np.max(np.abs(ours / theirs - 1.0)) < 1e-4
72 assert out[
"held"] == [
False] * len(t)
and out[
"liftoff_time_s"] == 0.0
74 k = int(np.flatnonzero(burning)[-1])
75 assert out[
"altitude_m"][k] == pytest.approx(float(fl.z(t[k])) - config.environment.elevation, rel=2e-3)
76 assert out[
"velocity_m_s"][k] == pytest.approx(float(fl.vz(t[k])), rel=1e-3)
80 """RocketPy's ``Flight.R3`` is a cubic spline over its solution nodes, and the drag steps at
81 burnout (power-on to power-off Cd). Across the step the spline rings: on the LE4 helium flight it
82 read -423 N 36 ms before cutoff, between -646 N and -747 N while the speed rose, so RocketPy's
83 specific force jumped 3.4 % and the inline check (vs_rocketpy 0.0338 against 0.005) failed under
84 rocketpy 1.11.0 and 1.13.0 alike. Read linearly between its nodes, the drag is bounded by them."""
85 from types
import SimpleNamespace
87 from rocketpy
import Function
90 x = list(np.arange(3.30, 3.44, 0.02)) + [3.45, tb, tb + 1e-5, 3.49, 3.51, 3.53]
91 y = [-600.0 - 300.0 * (t - 3.30)
for t
in x[:-5]] + [-648.0, -722.2, -722.0, -721.5, -721.0]
92 r3 = Function(np.column_stack([x, y]), interpolation=
"spline")
93 assert abs(float(r3(3.46)) - float(np.interp(3.46, x, y))) > 100.0
94 motor = SimpleNamespace(nozzle_radius=0.0, reference_pressure=
None, burn_start_time=0.0, burn_out_time=tb,
95 thrust=
lambda t: 7200.0
if t <= tb
else 0.0)
96 flight = SimpleNamespace(rocket=SimpleNamespace(motor=motor, total_mass=
lambda t: 70.0), R3=r3,
97 out_of_rail_time=0.5, inclination=90.0)
98 for t
in (3.43, 3.46, 3.47, 3.48):
99 drag = float(np.interp(t, x, y))
100 assert -722.2 <= drag <= -600.0
101 assert flt.axial_acceleration(flight, t) == pytest.approx((7200.0 + drag) / 70.0, rel=1e-12)
105 """``{t, accel_m_s2}`` on the burn's clock, as ``fly``'s schedule: the outer loop's own measure
106 of change between them is far inside its tolerance."""
107 t, F, mO, mF = le4_arrays()
108 flown = flt.fly(config, le4_payload(), le4_loads(), SITE_PA)
109 assert flown[
"ok"], flown.get(
"error")
110 out = flt.inline_specific_force(config, F, mO + mF, t, flown[
"liftoff_mass_kg"], SITE_PA)
111 assert out[
"t"] == flown[
"schedule"][
"t"]
112 assert flt.schedule_change(flown[
"schedule"], out) < 0.02 * flt.ACCEL_TOLERANCE
119 """Before Fire (zero thrust) and while thrust is below the weight the stand carries the vehicle:
120 it does not move and its columns feel exactly g0, the pad's ``Setup.body_acceleration``. The
121 first sample whose thrust beats the weight releases it."""
124 t = [-0.5, -0.25, 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30]
125 F = [0.0, 0.0, 0.0, 0.3 * w, 0.6 * w, 0.9 * w, 1.5 * w, 8.0 * w, 8.0 * w]
126 md = [0.0, 0.0, 0.0, 0.5, 1.0, 1.5, 2.5, 3.0, 3.0]
127 out = flt.inline_specific_force(config, F, md, t, m0, SITE_PA)
129 assert out[
"accel_m_s2"][k] == G0
and out[
"held"][k], k
130 assert out[
"altitude_m"][k] == 0.0
and out[
"velocity_m_s"][k] == 0.0, k
132 assert out[
"mass_kg"][5] == pytest.approx(m0 - (0.25 + 0.75 + 1.25) * 0.05, rel=1e-12)
133 assert not out[
"held"][7]
and out[
"accel_m_s2"][7] > 7.0 * G0
134 assert 0.15 <= out[
"liftoff_time_s"] <= 0.20
135 assert out[
"velocity_m_s"][8] > 0.0
and out[
"altitude_m"][8] > 0.0
139 """Causal: a burn pass that drives the ascent step by step gets what the batch call returns."""
140 t, F, mO, mF = le4_arrays()
142 batch = flt.inline_specific_force(config, F, mO + mF, t, m0, SITE_PA)
143 ascent = flt.InlineAscent.from_config(config, m0, SITE_PA)
144 stepped = [ascent.advance(float(a), float(b), float(c))
for a, b, c
in zip(t, F, mO + mF)]
145 assert stepped == batch[
"accel_m_s2"]
149 t, F, mO, mF = le4_arrays()
150 out = flt.inline_specific_force(config, F, mO + mF, t, 80.0, SITE_PA)
152 assert model[
"name"] ==
"inline_vertical_1dof" and "Sutton" in model[
"source"]
and model[
"assumptions"]
153 for name, row
in model[
"inputs"].items():
154 assert set(row) == {
"value",
"unit",
"provenance"}
and row[
"provenance"], name
155 assert "schema default" in model[
"inputs"][
"surface_roughness_m"][
"provenance"]
159 with pytest.raises(ValueError):
160 flt.inline_specific_force(config, [1.0, 2.0], [1.0], [0.0, 1.0], 80.0, SITE_PA)
161 with pytest.raises(ValueError):
162 flt.inline_specific_force(config, [1.0, 2.0], [1.0, 1.0], [1.0, 0.0], 80.0, SITE_PA)
163 with pytest.raises(ValueError):
164 flt.InlineAscent(mass_kg=0.0, reference_area_m2=0.0, nozzle_exit_area_m2=0.0, elevation_m=0.0,
165 reference_pressure_pa=
None)