76 cfg_base = load_config(str(ROOT /
"configs/impinging_lox_ch4_8000N.yaml"))
79 rho_o = float(cfg_base.fluids[
"oxidizer"].density)
80 rho_f = float(cfg_base.fluids[
"fuel"].density)
81 sqrt_density_ratio = math.sqrt(rho_o / rho_f)
82 ao_af_for_mr35_at_R1 = TARGET_MR / sqrt_density_ratio
87 a_o = n_o * math.pi * (d_o / 2.0) ** 2
91 ao_af_list = np.linspace(1.65, 2.55, 7)
92 p_o_grid = np.linspace(400.0, 600.0, 5)
93 p_f_grid = np.linspace(500.0, 780.0, 5)
94 cd_mults = [0.9, 1.0, 1.1]
102 for ao_af
in ao_af_list:
104 if not (0.00035 <= d_f <= 0.0065):
106 for p_o_psi
in p_o_grid:
107 for p_f_psi
in p_f_grid:
108 cfg = copy.deepcopy(cfg_base)
110 cfg.injector.geometry.oxidizer.n_elements = n_o
111 cfg.injector.geometry.oxidizer.d_jet = d_o
112 cfg.injector.geometry.fuel.n_elements = n_f
113 cfg.injector.geometry.fuel.d_jet = d_f
117 res = runner.evaluate(
118 float(p_o_psi) * PSI_TO_PA,
119 float(p_f_psi) * PSI_TO_PA,
128 F = float(res.get(
"F", float(
"nan")))
129 MR = float(res.get(
"MR", float(
"nan")))
130 pc = float(res.get(
"Pc", float(
"nan")))
131 diag = res.get(
"diagnostics")
or {}
132 R_mom = float(diag.get(
"momentum_ratio_R", float(
"nan")))
133 dp_o = diag.get(
"delta_p_injector_O")
134 dp_f = diag.get(
"delta_p_injector_F")
135 cd_o = float(diag.get(
"Cd_O", float(
"nan")))
136 cd_f = float(diag.get(
"Cd_F", float(
"nan")))
142 or not np.isfinite(F)
143 or not np.isfinite(MR)
150 p_o_psi=float(p_o_psi),
151 p_f_psi=float(p_f_psi),
152 cd_o_mult=float(m_o),
153 cd_f_mult=float(m_f),
158 r_dp_o=float(dp_o) / pc,
159 r_dp_f=float(dp_f) / pc,
165 print(
"=== Sweep summary ===")
166 print(f
"Ambient P_a used in evaluate: {p_amb:.2f} Pa ({p_amb/101325:.4f} atm)")
167 print(f
"Fixed oxidizer: n_O={n_o}, d_O={d_o*1000:.3f} mm, A_O={a_o*1e6:.4f} mm²")
168 print(f
"Fuel elements n_F={n_f}; d_F recomputed per AO/AF")
169 print(f
"rho_O/rho_F = {rho_o/rho_f:.4f}, sqrt(rho_O/rho_F) = {sqrt_density_ratio:.4f}")
170 print(f
"AO/AF needed for MR≈{TARGET_MR} if R=1 exactly (MR=R*sqrt(rho_O/rho_F)*AO/AF → AO/AF={TARGET_MR}/(R*sqrt…)): {ao_af_for_mr35_at_R1:.4f}")
171 print(f
"Successful evaluates stored: {len(rows)}, exceptions: {n_fail}, total attempts: {n_eval}")
174 def filt(rel_F: float, band_R: float, mr_lo: float, mr_hi: float) -> list[Row]:
177 if abs(r.F / TARGET_F - 1.0) > rel_F:
179 if not np.isfinite(r.R_mom):
181 if abs(r.R_mom - 1.0) > band_R:
183 if r.MR < mr_lo
or r.MR > mr_hi:
189 (
"strict", 0.03, 0.06, 3.45, 3.55),
190 (
"medium", 0.05, 0.08, 3.40, 3.60),
191 (
"loose", 0.08, 0.10, 3.30, 3.70),
194 for name, rf, br, ml, mh
in scenarios:
195 sel = filt(rf, br, ml, mh)
196 print(f
"\n--- Filter [{name}]: |F/F_tgt-1|<={rf}, |R-1|<={br}, MR∈[{ml},{mh}] → N={len(sel)} ---")
199 rf_vals = [x.r_dp_f
for x
in sel]
200 ro_vals = [x.r_dp_o
for x
in sel]
201 print(f
" ΔP_F/Pc: min={min(rf_vals):.4f} med={np.median(rf_vals):.4f} max={max(rf_vals):.4f}")
202 print(f
" ΔP_O/Pc: min={min(ro_vals):.4f} med={np.median(ro_vals):.4f} max={max(ro_vals):.4f}")
203 print(f
" MR: min={min(x.MR for x in sel):.4f} med={np.median([x.MR for x in sel]):.4f} max={max(x.MR for x in sel):.4f}")
204 below = sum(1
for x
in sel
if x.r_dp_f <= 0.35)
205 above = sum(1
for x
in sel
if x.r_dp_f > 0.35)
206 print(f
" Fuel ΔP/Pc<=0.35: {below}/{len(sel)} ({100*below/len(sel):.1f}%), >0.35: {above}")
208 sel_sorted = sorted(sel, key=
lambda x: x.r_dp_f)
211 f
" Lowest ΔP_F/Pc sample: ΔP_F/Pc={ex.r_dp_f:.4f}, ΔP_O/Pc={ex.r_dp_o:.4f}, "
212 f
"MR={ex.MR:.4f}, R={ex.R_mom:.4f}, F={ex.F:.1f}, AO/AF={ex.ao_af:.3f}, "
213 f
"P_O={ex.p_o_psi:.0f} psi, P_F={ex.p_f_psi:.0f} psi, Cd×=({ex.cd_o_mult:.2f},{ex.cd_f_mult:.2f})"
219 sel2 = [r
for r
in rows
if np.isfinite(r.R_mom)
and abs(r.R_mom - 1.0) <= loose_br
and abs(r.F / TARGET_F - 1.0) <= loose_rf]
220 print(f
"\n--- MR distribution when only |F-8000|/8000<= {loose_rf} and |R-1|<={loose_br} (no MR filter): N={len(sel2)} ---")
222 mrs = [x.MR
for x
in sel2]
223 print(f
" MR min/med/max: {min(mrs):.4f} / {np.median(mrs):.4f} / {max(mrs):.4f}")
224 pred = [sqrt_density_ratio * x.ao_af
for x
in sel2]
225 err = [abs(sel2[i].MR - pred[i])
for i
in range(len(sel2))]
226 print(f
" |MR - sqrt(rho_O/rho_F)*AO/AF| median: {np.median(err):.4f} (injector closure breaks pure analytic relation)")