1"""Piecewise injector ΔP/Pc hinge penalty for Layer 1 (per-stream bands)."""
6 injector_dp_bands_from_requirements,
7 injector_dp_ratio_penalty_weighted,
8 injector_dp_ratios_from_eval_result,
9 injector_dp_ratio_within_gate,
10 stream_injector_dp_band_hinge_squared,
11 stream_injector_dp_raw_terms,
12 stream_injector_dp_soft_floor_squared,
18 """Doubling W_DP doubles weighted penalty for identical ratios."""
19 band_o = band_f = (0.20, 0.35)
21 p_lo = injector_dp_ratio_penalty_weighted(
22 r_o, r_f, 40.0, 120.0, o_band=band_o, f_band=band_f
24 p_hi = injector_dp_ratio_penalty_weighted(
25 r_o, r_f, 80.0, 240.0, o_band=band_o, f_band=band_f
27 self.assertAlmostEqual(p_hi, 2.0 * p_lo, places=9)
30 """Defaults: O and F preferred intervals yield zero penalty."""
31 p = injector_dp_ratio_penalty_weighted(0.25, 0.85, 1.0, 1.0)
32 self.assertAlmostEqual(p, 0.0, places=12)
35 for r
in (0.20, 0.27, 0.35):
36 self.assertAlmostEqual(stream_injector_dp_band_hinge_squared(r, 0.20, 0.35), 0.0, places=12)
39 """Fuel at 0.85 is penalized under narrow fuel band but not under default wide fuel band."""
40 narrow_all = (0.20, 0.35)
41 p_narrow = injector_dp_ratio_penalty_weighted(
42 0.25, 0.85, 1.0, 0.0, o_band=narrow_all, f_band=narrow_all
44 p_default = injector_dp_ratio_penalty_weighted(0.25, 0.85, 1.0, 0.0)
45 self.assertGreater(p_narrow, 0.0)
46 self.assertAlmostEqual(p_default, 0.0, places=12)
49 self.assertGreater(stream_injector_dp_band_hinge_squared(0.10, 0.20, 0.35), 0.0)
52 self.assertAlmostEqual(stream_injector_dp_soft_floor_squared(0.02, 0.15), (0.15 - 0.02) ** 2)
53 self.assertAlmostEqual(stream_injector_dp_soft_floor_squared(0.40, 0.15), 0.0, places=12)
55 p_base = injector_dp_ratio_penalty_weighted(
56 0.014, 0.45, 100.0, 0.0, o_band=band, f_band=band, w_dp_o=100.0, w_dp_f=100.0
58 p_floor = injector_dp_ratio_penalty_weighted(
70 self.assertGreater(p_floor, p_base)
73 """w_dp_o and w_dp_f scale hinges independently."""
74 p_sym = injector_dp_ratio_penalty_weighted(
82 p_asym = injector_dp_ratio_penalty_weighted(
91 self.assertAlmostEqual(p_asym, 3.0 * p_sym, places=9)
95 p_o = injector_dp_ratio_penalty_weighted(
96 0.10, 0.27, 1.0, 0.0, o_band=band, f_band=band
98 p_f = injector_dp_ratio_penalty_weighted(
99 0.27, 0.10, 1.0, 0.0, o_band=band, f_band=band
101 self.assertAlmostEqual(p_o, p_f, places=12)
104 d, h = stream_injector_dp_raw_terms(0.40)
106 expected = ((0.40 - 0.35) / span) ** 2
107 self.assertAlmostEqual(d, expected, places=12)
108 self.assertAlmostEqual(h, 0.0, places=12)
113 "diagnostics": {
"delta_p_injector_O": 0.5e6,
"delta_p_injector_F": 0.7e6},
115 ro, rf = injector_dp_ratios_from_eval_result(pc, res)
116 self.assertAlmostEqual(ro, 0.25)
117 self.assertAlmostEqual(rf, 0.35)
122 "diagnostics": {
"P_injector_O": 1.4e6,
"P_injector_F": 1.35e6},
124 ro, rf = injector_dp_ratios_from_eval_result(pc, res)
125 self.assertAlmostEqual(ro, 0.4)
126 self.assertAlmostEqual(rf, 0.35)
130 "injector_dp_ratio_O_min": 0.15,
131 "injector_dp_ratio_O_max": 0.35,
132 "injector_dp_ratio_F_min": 0.15,
133 "injector_dp_ratio_F_max": 0.35,
135 o_band, f_band = injector_dp_bands_from_requirements(reqs)
136 self.assertEqual(o_band, (0.20, 0.40))
137 self.assertEqual(f_band, (0.20, 0.40))
138 self.assertTrue(injector_dp_ratio_within_gate(0.352, *o_band))
139 self.assertTrue(injector_dp_ratio_within_gate(0.342, *f_band))
142 """Closure noise can yield ΔP/Pc ≡ hi plus float dust; hinge is ~zero but plain ``<= hi`` can fail."""
144 self.assertTrue(injector_dp_ratio_within_gate(0.35, lo, hi))
146 self.assertTrue(injector_dp_ratio_within_gate(creep, lo, hi))
148 self.assertFalse(injector_dp_ratio_within_gate(far, lo, hi))
149 self.assertIsNone(injector_dp_ratio_within_gate(
None, lo, hi))
152if __name__ ==
"__main__":
test_positive_below_low_edge(self)
test_legacy_yaml_band_migrates_to_020_040(self)
test_deprecated_raw_terms_matches_lox_band(self)
test_fuel_wide_band_reduces_penalty_vs_narrow_reference(self)
test_ratios_fallback_to_p_inj_minus_pc(self)
test_weight_linear_scaling(self)
test_zero_inside_default_bands(self)
test_two_streams_independent_bands(self)
test_ratios_from_eval_result_prefers_delta_p(self)
test_oxidizer_soft_floor_penalizes_small_ratio_only(self)
test_zero_on_oxidizer_band_explicit(self)
test_ratio_within_gate_allows_micro_creep_above_upper_edge(self)
test_asymmetric_stream_weights(self)