57 """Two designs that differ only in delivered Isp must not tie (they did: 0 and 0)."""
58 _req, _result, _x =
_setup()
59 c =
_constants(layer1_W_ISP=1000.0, layer1_Isp_ref_s=264.0)
60 assert (L1._compute_objective_value(_result(Isp=237.0), _x(), _req(), c)
61 < L1._compute_objective_value(_result(Isp=230.0), _x(), _req(), c))
62 lo = L1._compute_objective_value(_result(Isp=230.0), _x(), _req(), c, return_terms=
True)
63 hi = L1._compute_objective_value(_result(Isp=237.0), _x(), _req(), c, return_terms=
True)
65 assert lo[
"terms"][
"isp_penalty"] == pytest.approx(1000.0 * (264.0 / 230.0 - 1.0), rel=1e-12)
66 assert hi[
"terms"][
"isp_penalty"] == pytest.approx(1000.0 * (264.0 / 237.0 - 1.0), rel=1e-12)
70 """O/F is a requirement: a design that runs at 1.6 against 1.5 gets no thermodynamic
71 credit for the 1.6 (ideal Isp 1.1 % higher there). Ratio from rocketcea."""
72 pc_psi, eps = 431.1, 5.3
73 ratio =
_rc_isp(rc, pc_psi, 1.5, eps) /
_rc_isp(rc, pc_psi, 1.6, eps)
74 res = {
"Isp": 237.0,
"MR": 1.6,
"Pc": pc_psi * PSI,
"eps": eps}
75 merit = L1._layer1_isp_merit_s(res, {
"optimal_of": 1.5,
"P_ambient": PA}, cea)
76 assert merit / 237.0 == pytest.approx(ratio, rel=3e-4)
78 on_target = dict(res, MR=1.5)
79 assert L1._layer1_isp_merit_s(on_target, {
"optimal_of": 1.5,
"P_ambient": PA}, cea) == 237.0
92 """DEF-07: a blank design (W_MASS null) had W_MASS = W_LSTAR = 0 and nothing to choose L*
93 with. The defaults price a kilogram of chamber like a kilogram of propellant."""
95 w = L1._layer1_merit_weights({}, cea, 1.5, pc, PA, (4.0, 14.0), 6500.0, 3.9, 0.0, 5.0)
96 eps_rc = rc.get_eps_at_PcOvPe(Pc=430.0, MR=1.5, PcOvPe=pc / PA)
97 isp_ref =
_rc_isp(rc, 430.0, 1.5, eps_rc)
98 assert w[
"Isp_ref_s"] == pytest.approx(isp_ref, rel=1e-3)
99 m_prop = 6500.0 * 3.9 / (G0 * isp_ref)
100 assert w[
"m_prop_ref_kg"] == pytest.approx(m_prop, rel=1e-3)
101 assert w[
"W_ISP"] == 1000.0
103 assert 2.0 * w[
"W_MASS"] / 5.0 == pytest.approx(1000.0 / m_prop, rel=1e-3)
105 w2 = L1._layer1_merit_weights({
"layer1_W_MASS": 3000.0}, cea, 1.5, pc, PA, (4.0, 14.0),
106 6500.0, 3.9, 3000.0, 5.0)
107 assert w2[
"W_MASS"] == 3000.0
111 """DEF-07 test (b): L* 1.14 and 1.49 m scored identically (0.0) on the blank config."""
112 _req, _result, _x =
_setup()
113 w = L1._layer1_merit_weights({}, cea, 1.5, 430.0 * PSI, PA, (4.0, 14.0), 6500.0, 3.9, 0.0, 5.0)
114 c =
_constants(layer1_W_ISP=w[
"W_ISP"], layer1_Isp_ref_s=w[
"Isp_ref_s"],
115 layer1_W_MASS=w[
"W_MASS"], layer1_chamber_wall_density_kg_m3=2000.0)
116 a = L1._compute_objective_value(_result(), _x(lstar=1.14), _req(), c)
117 b = L1._compute_objective_value(_result(), _x(lstar=1.49), _req(), c)
118 assert a < 1e6
and b < 1e6
and b > a
122 """L1-12: the blank impinging template keeps O/F 2.8; ethalox's table stops at 2.5 and
123 Layer 1 aborted every run. It now designs to the peak ideal Isp O/F (rocketcea) and says so."""
125 cfg = load_config(str(ROOT /
"configs" /
"ethalox_6500N.yaml"))
127 of, msg = L1._layer1_resolve_of_target(cfg, 2.8, cea, pc_psi * PSI, PA)
128 grid = np.linspace(1.0, 2.5, 151)
129 isp = [
_rc_isp(rc, pc_psi, m, rc.get_eps_at_PcOvPe(Pc=pc_psi, MR=m, PcOvPe=pc_psi * PSI / PA))
131 assert of == pytest.approx(float(grid[int(np.argmax(isp))]), abs=0.03)
132 assert msg
and "outside the CEA table" in msg
133 assert L1._layer1_resolve_of_target(cfg, 1.5, cea, pc_psi * PSI, PA) == (1.5,
None)
134 of_edge, msg_edge = L1._layer1_resolve_of_target(cfg, 2.8,
None)
135 assert of_edge == 2.5
and msg_edge
139 """L1-12, end to end: run_layer1_optimization raised ValueError before any work."""
141 from unittest.mock
import MagicMock, patch
143 real_cfg = load_config(str(ROOT /
"configs" /
"impinging_smoke.yaml"))
144 lo, hi = real_cfg.combustion.cea.MR_range
145 mock_engine = MagicMock()
146 mock_engine.evaluate.return_value = {
"F": 7000.0,
"Pc": 2.5e6,
"MR": float(hi),
"Cf": 1.55,
147 "Cf_actual": 1.55,
"mdot_O": 1.0,
"mdot_F": 0.45,
148 "stability_results": {}}
149 x13 = [0.002, 1.0, 8.0, 0.14, 12.0, 0.002, 45.0, 0.012, 0.0022, 45.0, 0.011, 550.0, 650.0]
151 def _dc(obj, memo=None):
152 return real_cfg
if obj
is real_cfg
else copy.deepcopy(obj)
154 with patch(
"engine.optimizer.layers.layer1_static_optimization.copy.deepcopy", side_effect=_dc), \
155 patch(
"engine.optimizer.layers.layer1_static_optimization.PintleEngineRunner",
156 return_value=mock_engine), \
157 patch(
"engine.optimizer.layers.layer1_static_optimization.cma.CMAEvolutionStrategy")
as mcma, \
158 patch(
"engine.optimizer.layers.layer1_static_optimization.minimize")
as mmin, \
159 patch(
"engine.optimizer.layers.layer1_static_optimization.ProcessPoolExecutor"):
160 mcma.return_value.stop.return_value =
True
161 mcma.return_value.result.xbest = x13
162 mcma.return_value.result.fbest = 0.1
163 lb = MagicMock(); lb.x = np.array(x13); lb.fun = 0.05; lb.success =
True
164 mmin.return_value = lb
165 req = real_cfg.design_requirements.model_dump()
166 req[
"optimal_of_ratio"] = float(hi) + 1.3
167 _, results = L1.run_layer1_optimization(
168 config_obj=real_cfg, runner=MagicMock(), requirements=req, target_burn_time=10.0,
169 tolerances={
"thrust": 0.1}, pressure_config={
"mode":
"optimizer_controlled"},
170 layer1_max_iterations=1, layer1_cma_restarts=1)
171 warns = results[
"performance"].get(
"layer1_warnings")
or []
172 assert any(
"outside the CEA table" in w
for w
in warns)
176 """L1-13: the chamber-gamma isentrope gave eps 5.60 at 433.9 psia, Pe/Pa 0.93 in CEA;
177 rocketcea's matched eps there is 5.30."""
179 res = {
"Pc": pc_psi * PSI,
"MR": 1.5,
"gamma": 1.1375}
180 eps = L1._layer1_matched_eps(res, PA, cea, 5.6)
181 pe = pc_psi * PSI / rc.get_PcOvPe(Pc=pc_psi, MR=1.5, eps=eps)
182 assert pe == pytest.approx(PA, rel=0.01)
183 assert eps == pytest.approx(rc.get_eps_at_PcOvPe(Pc=pc_psi, MR=1.5, PcOvPe=pc_psi * PSI / PA),