STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
run_layer1_long_w_mom_compare.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Long Layer-1 runs: compare W_MOM at fixed W_geom_ao_af_momentum (8000 N impinging config)."""
3
4from __future__ import annotations
5
6import argparse
7import copy
8import math
9import sys
10from pathlib import Path
11from typing import Any, Dict, List
12
13ROOT = Path(__file__).resolve().parents[1]
14sys.path.insert(0, str(ROOT))
15
16from engine.core.runner import PintleEngineRunner # noqa: E402
17from engine.optimizer.layers.layer1_static_optimization import run_layer1_optimization # noqa: E402
18from engine.pipeline.io import load_config # noqa: E402
19
20
21def _geom_row(cfg: Any) -> Dict[str, Any]:
22 geom = getattr(getattr(cfg, "injector", None), "geometry", None)
23 if geom is None:
24 return {}
25 ox = geom.oxidizer
26 fu = geom.fuel
27 return {
28 "n_O": int(ox.n_elements),
29 "n_F": int(fu.n_elements),
30 "d_O_mm": float(ox.d_jet) * 1000.0,
31 "d_F_mm": float(fu.d_jet) * 1000.0,
32 "spacing_O_mm": float(ox.spacing) * 1000.0,
33 "spacing_F_mm": float(fu.spacing) * 1000.0,
34 "imp_deg_O": float(ox.impingement_angle),
35 "imp_deg_F": float(fu.impingement_angle),
36 }
37
38
39def _collect(w_mom: float, opt_cfg: Any, perf: Dict[str, Any]) -> Dict[str, Any]:
40 g = _geom_row(opt_cfg)
41 row = {
42 "W_MOM": w_mom,
43 "F": perf.get("F"),
44 "MR": perf.get("MR"),
45 "R": perf.get("momentum_ratio_R"),
46 "dP_O_Pc": perf.get("injector_dp_ratio_O"),
47 "dP_F_Pc": perf.get("injector_dp_ratio_F"),
48 "AoAf_geom": perf.get("geom_ao_af"),
49 "expected_AO_AF_R1": perf.get("expected_ao_af_for_R1"),
50 "P_O_psi": perf.get("P_O_start_psi"),
51 "P_F_psi": perf.get("P_F_start_psi"),
52 "injector_dp_oors": perf.get("injector_dp_out_of_range"),
53 **g,
54 }
55 return row
56
57
58def _f(x: Any, default: float = float("nan")) -> float:
59 try:
60 if x is None:
61 return default
62 v = float(x)
63 return v if math.isfinite(v) else default
64 except (TypeError, ValueError):
65 return default
66
67
68def _score(row: Dict[str, Any]) -> float:
69 """Lower is better (soft targets: R=1, MR=3.5, F=8000 N)."""
70 R = _f(row.get("R"), 1.0)
71 MR = _f(row.get("MR"), 3.5)
72 F = _f(row.get("F"), 8000.0)
73 dpf = _f(row.get("dP_F_Pc"), 1.0)
74
75 e_r = (math.log(max(R, 1e-9))) ** 2
76 e_mr = ((MR - 3.5) / 3.5) ** 2
77 e_f = ((F - 8000.0) / 8000.0) ** 2
78 e_dpf = max(0.0, dpf - 1.2) ** 2 # prefer fuel ΔP/Pc not far above 1.2
79
80 return 2.0 * e_r + 2.0 * e_mr + 1.5 * e_f + 0.8 * e_dpf
81
82
83def main() -> None:
84 ap = argparse.ArgumentParser(description=__doc__)
85 ap.add_argument("--config", type=str, default=str(ROOT / "configs/impinging_lox_ch4_8000N.yaml"))
86 ap.add_argument("--layer1-max-iterations", type=int, default=120)
87 ap.add_argument("--layer1-cma-restarts", type=int, default=1)
88 ap.add_argument("--w-geom-ao-af-momentum", type=float, default=2800.0)
89 ap.add_argument("--w-mom-list", type=float, nargs="+", default=[300.0, 1000.0])
90 args = ap.parse_args()
91
92 base = load_config(args.config)
93 rows: List[Dict[str, Any]] = []
94
95 print(
96 f"\n=== Long Layer-1 comparison ===\n"
97 f"config={args.config}\n"
98 f"W_geom_ao_af_momentum={args.w_geom_ao_af_momentum:g}\n"
99 f"W_MOM values={args.w_mom_list}\n"
100 f"layer1_max_iterations={args.layer1_max_iterations}\n"
101 f"layer1_cma_restarts={args.layer1_cma_restarts}\n"
102 )
103
104 for w_mom in args.w_mom_list:
105 cfg = copy.deepcopy(base)
106 req = cfg.design_requirements.model_dump()
107 req["W_MOM"] = float(w_mom)
108 req["W_geom_ao_af_momentum"] = float(args.w_geom_ao_af_momentum)
109
110 pcfg = {
111 "mode": "optimizer_controlled",
112 "max_lox_pressure_psi": float(req["max_lox_tank_pressure_psi"]),
113 "max_fuel_pressure_psi": float(req["max_fuel_tank_pressure_psi"]),
114 }
115
116 print(f"\n--- Starting run W_MOM={w_mom:g} ---\n")
117
118 opt_cfg, results = run_layer1_optimization(
119 cfg,
120 PintleEngineRunner(copy.deepcopy(base)),
121 req,
122 target_burn_time=float(req.get("target_burn_time", 6.0)),
123 tolerances={"thrust": 0.10, "apogee": 0.15},
124 pressure_config=pcfg,
125 layer1_smoke=False,
126 layer1_max_iterations=int(args.layer1_max_iterations),
127 layer1_cma_restarts=int(args.layer1_cma_restarts),
128 )
129 perf = results.get("performance") or {}
130 rows.append(_collect(float(w_mom), opt_cfg, perf))
131
132 print("\n" + "=" * 100)
133 print("SUMMARY TABLE")
134 print("=" * 100)
135 hdr = (
136 f"{'W_MOM':>8} {'F[N]':>10} {'MR':>8} {'R':>8} {'dP_O/Pc':>10} {'dP_F/Pc':>10} "
137 f"{'AoAf':>8} {'exp_R1':>8} {'P_O_psi':>10} {'P_F_psi':>10} {'dp_oors':>8}"
138 )
139 print(hdr)
140 print("-" * 100)
141 for r in rows:
142 print(
143 f"{r['W_MOM']:>8g} {_f(r['F']):>10.2f} {_f(r['MR']):>8.4f} {_f(r['R']):>8.4f} "
144 f"{_f(r['dP_O_Pc']):>10.4f} {_f(r['dP_F_Pc']):>10.4f} "
145 f"{_f(r['AoAf_geom']):>8.4f} {_f(r['expected_AO_AF_R1']):>8.4f} "
146 f"{_f(r['P_O_psi']):>10.2f} {_f(r['P_F_psi']):>10.2f} {str(r['injector_dp_oors']):>8}"
147 )
148
149 print("\n--- Injector geometry ---\n")
150 for r in rows:
151 print(
152 f"W_MOM={r['W_MOM']:g}: n_O={r.get('n_O')} d_O={_f(r.get('d_O_mm')):.4f} mm "
153 f"spacing_O={_f(r.get('spacing_O_mm')):.4f} mm imp_O={_f(r.get('imp_deg_O')):.2f}° | "
154 f"n_F={r.get('n_F')} d_F={_f(r.get('d_F_mm')):.4f} mm "
155 f"spacing_F={_f(r.get('spacing_F_mm')):.4f} mm imp_F={_f(r.get('imp_deg_F')):.2f}°"
156 )
157
158 scored = [( _score(r), r["W_MOM"], r) for r in rows]
159 scored.sort(key=lambda x: x[0])
160 best_score, best_w, best_row = scored[0]
161 print("\n" + "=" * 100)
162 print("COMPROMISE VERDICT (weighted distance to R≈1, MR≈3.5, F≈8000 N, fuel ΔP/Pc ≤ ~1.2)")
163 print("=" * 100)
164 for s, wm, rr in scored:
165 print(f" W_MOM={wm:g} composite_score={s:.6f}")
166 print(
167 f"\nBest compromise by this scalar: **W_MOM = {best_w:g}** "
168 f"(score={best_score:.6f}). Inspect row above for thrust / ΔP trade-offs.\n"
169 )
170
171
172if __name__ == "__main__":
173 main()
#define max(a, b)
Definition Arduino.h:43
Dict[str, Any] _collect(float w_mom, Any opt_cfg, Dict[str, Any] perf)
float _f(Any x, float default=float("nan"))