20 """Warm-start from last good follow-up (~7354 N, dP_O/Pc≈0.131, MR≈3.68).
22 Keeps ``A_exit = A_throat * expansion_ratio`` so ``PintleEngineRunner.evaluate`` does not abort.
24 cg = cfg.chamber_geometry
26 raise ValueError(
"chamber_geometry required")
27 cg.A_throat = 0.001849
28 cg.expansion_ratio = 6.0
29 cg.A_exit = float(cg.A_throat) * float(cg.expansion_ratio)
31 cg.chamber_diameter = 0.15159999999999998
32 ox = cfg.injector.geometry.oxidizer
33 fu = cfg.injector.geometry.fuel
37 ox.impingement_angle = 63.70
38 ox.spacing = 0.0054755
41 fu.impingement_angle = 64.71
42 fu.spacing = 0.0061195
43 cfg.lox_tank.initial_pressure_psi = float(494.2608184424503)
44 cfg.fuel_tank.initial_pressure_psi = float(538.0149922949225)
48 ap = argparse.ArgumentParser(description=__doc__)
49 ap.add_argument(
"--config", default=str(ROOT /
"configs/impinging_lox_ch4_8000N.yaml"))
50 ap.add_argument(
"--max-it", type=int, default=95)
51 ap.add_argument(
"--restarts", type=int, default=2)
52 args = ap.parse_args()
54 cfg = load_config(args.config)
57 req = cfg.design_requirements.model_dump()
59 req[
"injector_dp_ratio_O_min"] = 0.15
60 req[
"injector_dp_ratio_O_soft_floor"] = 0.15
61 req[
"W_DP_O_FLOOR"] = 9000.0
62 req[
"W_DP_O"] = 2500.0
63 req[
"injector_dp_ratio_F_min"] = 0.32
64 req[
"injector_dp_ratio_F_max"] = 0.57
65 req[
"layer1_P_O_start_psi_min"] = 490.0
66 req[
"layer1_P_O_start_psi_max"] = 515.0
67 req[
"layer1_P_F_start_psi_min"] = 535.0
68 req[
"layer1_P_F_start_psi_max"] = 552.0
71 dr = cfg.design_requirements
73 "mode":
"optimizer_controlled",
74 "max_lox_pressure_psi": float(dr.max_lox_tank_pressure_psi),
75 "max_fuel_pressure_psi": float(dr.max_fuel_tank_pressure_psi),
78 opt_cfg, results = run_layer1_optimization(
82 target_burn_time=float(req.get(
"target_burn_time", 6.0)),
83 tolerances={
"thrust": 0.10,
"apogee": 0.15},
86 layer1_max_iterations=
max(1, int(args.max_it)),
87 layer1_cma_restarts=
max(1, int(args.restarts)),
90 perf = results.get(
"performance")
or {}
91 ox = opt_cfg.injector.geometry.oxidizer
92 fu = opt_cfg.injector.geometry.fuel
94 print(
"\n=== Follow-up Layer 1 (warm LOX dP/Pc toward ≥0.15, prefer ≤0.37) ===")
95 print(f
"req: LOX hinge [{req['injector_dp_ratio_O_min']},{req['injector_dp_ratio_O_max']}], "
96 f
"W_DP_O={req['W_DP_O']}, W_DP_O_FLOOR={req['W_DP_O_FLOOR']}, "
97 f
"fuel [{req['injector_dp_ratio_F_min']},{req['injector_dp_ratio_F_max']}]")
99 print(f
"thrust [N]: {perf.get('F')}")
100 print(f
"MR: {perf.get('MR')}")
101 print(f
"momentum_ratio_R: {perf.get('momentum_ratio_R')}")
102 print(f
"dP_O/Pc: {perf.get('injector_dp_ratio_O')}")
103 print(f
"dP_F/Pc: {perf.get('injector_dp_ratio_F')}")
104 print(f
"P_O / P_F [psi]: {perf.get('P_O_start_psi')} / {perf.get('P_F_start_psi')}")
105 cg = opt_cfg.chamber_geometry
107 eps_s = float(cg.A_exit) / float(cg.A_throat)
if cg.A_throat
and cg.A_exit
else float(
"nan")
109 f
"A_throat [m2] / A_exit [m2] / eps(sync check): "
110 f
"{getattr(cg, 'A_throat', None)} / {getattr(cg, 'A_exit', None)} / {eps_s:.5g}"
113 f
"n_O/n_F | d_jet_O/d_jet_F [mm] | sp_O/sp_F [mm] | ang_O/ang_F [deg]: "
114 f
"{int(ox.n_elements)}/{int(fu.n_elements)} | "
115 f
"{ox.d_jet*1000:.4f}/{fu.d_jet*1000:.4f} | "
116 f
"{ox.spacing*1000:.4f}/{fu.spacing*1000:.4f} | "
117 f
"{ox.impingement_angle:.2f}/{fu.impingement_angle:.2f}"
119 print(f
"pressure_candidate_valid: {perf.get('pressure_candidate_valid')}")