STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_injector_ring_manifold.py
Go to the documentation of this file.
1"""Back channels are dividing-flow rings, not a plenum; holes cavitate when K < (Cd/Cc)^2.
2
3The old solve fed all 24 holes from one manifold pressure. With one port per ring the LOX channel
4runs faster than its jets (velocity head ~ the injector drop), so holes near the port starve and
5the far ones gain (Rohde, Richards & Metger, NASA TN D-5467; Acrivos, Babcock & Pigford 1959).
6"""
7import copy
8import math
9
10import pytest
11
12PSI = 6894.757
13CFG = "tests/fixtures/doublet_6500N_autochannel.yaml"
14
15
16def _run(mutate):
17 from engine.pipeline.io import load_config
18 from engine.core.runner import PintleEngineRunner
19 import os
20 path = CFG if os.path.exists(CFG) else "configs/ethalox_6500N_doublet_2026-09-26.yaml"
21 c = copy.deepcopy(load_config(path))
22 mutate(c)
23 r = PintleEngineRunner(c).evaluate(c.lox_tank.initial_pressure_psi * PSI,
24 c.fuel_tank.initial_pressure_psi * PSI, silent=True)
25 return r, r["diagnostics"]
26
27
29 _, d = _run(lambda c: setattr(c.injector.plate, "channel_inlets", 1))
30 assert d["manifold_model"] == "ring_network"
31 assert d["element_flow_ratio_min_O"] < 0.8 < 1.1 < d["element_flow_ratio_max_O"]
32 assert d["element_mass_flows_O"][0] == min(d["element_mass_flows_O"]) # port hole flows least
33 assert d["Cd_O"] == pytest.approx(0.79, abs=0.01) # the holes' own Cd
34 assert d["Cd_eff_manifold_O"] < d["Cd_O"] - 0.05 # the manifold's loss, separately
35
36
38 r4, d4 = _run(lambda c: setattr(c.injector.plate, "channel_inlets", 4))
39 r1, d1 = _run(lambda c: setattr(c.injector.plate, "channel_inlets", 1))
40 rp, _ = _run(lambda c: setattr(c.injector.plate, "manifold_model", "plenum"))
41 spread = lambda d: d["element_flow_ratio_max_O"] - d["element_flow_ratio_min_O"]
42 assert spread(d4) < 0.05 < spread(d1)
43 assert abs(r4["MR"] - rp["MR"]) < abs(r1["MR"] - rp["MR"])
44 assert r1["Pc"] < r4["Pc"] < rp["Pc"] * 1.0001
45
46
48 from engine.core.injectors.impinging import _RingManifold
49 rho, mu, dh = 1140.0, 2e-4, 1.6e-3
50 cd_of = lambda Re, p: 0.8
51 kw = dict(n_holes=24, n_ports=1, D_h=0.05, r_ring=0.035, A_hole=math.pi * dh ** 2 / 4, d_hole=dh,
52 rho=rho, mu=mu, K_ent=0.5, C_R=1.0, roughness=0.0)
53 wide = _RingManifold(A_ch=1.0, **kw)
54 P, Pc = 3.5e6, 2.6e6
55 per_hole = 0.8 * kw["A_hole"] * math.sqrt(2 * rho * (P - Pc))
56 total, holes, _ = wide.march(24 * per_hole, P, Pc, cd_of)
57 assert total == pytest.approx(24 * per_hole, rel=1e-6)
58 assert max(holes) / min(holes) == pytest.approx(1.0, abs=1e-6)
59
60
62 from engine.core.injectors.impinging import _RingManifold, _churchill_f
63 rho, mu, A_ch, dh = 1000.0, 1e-3, 2e-5, 1.5e-3
64 net = _RingManifold(n_holes=2, n_ports=1, A_ch=A_ch, D_h=4e-3, r_ring=0.03,
65 A_hole=math.pi * dh ** 2 / 4, d_hole=dh, rho=rho, mu=mu, K_ent=0.5, C_R=0.0,
66 roughness=0.0)
67 m, P, Pc = 0.05, 1.0e6, 0.2e6
68 u = (m / 2) / (rho * A_ch)
69 p = P - 1.5 * 0.5 * rho * u * u
70 s = 2 * math.pi * 0.03 / 2
71 p -= _churchill_f(rho * u * 4e-3 / mu, 0.0) * (0.5 * s / 4e-3) * 0.5 * rho * u * u
72 q = 0.8 * math.pi * dh ** 2 / 4 * math.sqrt(2 * rho * (p - Pc))
73 total, holes, _ = net.march(m, P, Pc, lambda Re, pp: 0.8)
74 assert holes[0] == pytest.approx(q, rel=1e-12)
75 assert total == pytest.approx(2 * q, rel=1e-12)
76
77
79 from engine.core.injectors.impinging import _churchill_f
80 assert _churchill_f(1000.0, 0.0) == pytest.approx(64 / 1000.0, rel=0.02)
81 assert _churchill_f(1e5, 0.0) == pytest.approx(0.316 * 1e5 ** -0.25, rel=0.05)
82
83
85 from engine.core.injectors.impinging import _stream_flow
86 from engine.core.discharge import contraction_coefficient
87 from engine.pipeline.io import load_config
88 cfg = load_config("configs/ethalox_6500N.yaml")
89 dc = cfg.discharge["oxidizer"]
90 A, d = 24 * math.pi * 1.6e-3 ** 2 / 4, 1.6e-3
91 feed = lambda m: 0.0
92 P_tank, Pc, Pv = 3.6e6, 101325.0, 101325.0
93 m0, Cd0, *_ = _stream_flow(Pc, P_tank, 1140.0, A, d, 2e-4, dc, 90.0, 0.80, feed)
94 m1, Cd1, *_ = _stream_flow(Pc, P_tank, 1140.0, A, d, 2e-4, dc, 90.0, 0.80, feed,
95 cav=(Pv, contraction_coefficient(0.0)))
96 K = (P_tank - Pv) / (P_tank - Pc)
97 assert Cd1 == pytest.approx(0.62 * math.sqrt(K), rel=1e-6)
98 assert m1 < 0.8 * m0
99 # hot fire (K ~ 4): the limit does nothing
100 m2, Cd2, *_ = _stream_flow(2.6e6, P_tank, 1140.0, A, d, 2e-4, dc, 90.0, 0.80, feed,
101 cav=(Pv, contraction_coefficient(0.0)))
102 m3, Cd3, *_ = _stream_flow(2.6e6, P_tank, 1140.0, A, d, 2e-4, dc, 90.0, 0.80, feed)
103 assert m2 == pytest.approx(m3, rel=1e-12)
104
105
107 """At Pc = 1 atm the LOX holes cavitate; the numba injector must give the Python flow."""
108 from engine import accel
109 from engine.core.injectors import get_injector_model
110 from engine.pipeline.io import load_config
111 if not accel.available():
112 pytest.skip("numba unavailable")
113 cfg = load_config("configs/ethalox_6500N.yaml")
114 if getattr(cfg.injector, "plate", None) is not None:
115 cfg.injector.plate.manifold_model = "plenum"
116 assert accel.can_handle(cfg)
117 P = 584.27 * PSI
118 got = accel.solve(cfg, P, P, 101325.0)
119 mO, mF, d = get_injector_model(cfg).solve(P, P, 101325.0)
120 assert d["Cd_O"] < 0.7 # the limit binds (Cc sqrt(K) ~ 0.62)
121 assert got[0] == pytest.approx(mO, rel=1e-9)
122 assert got[1] == pytest.approx(mF, rel=1e-9)
123
124
126 """The CAD's channel (0.300 x 0.487 in LOX, 2 ports) is ~5x the auto-drawn one: the ring is
127 then effectively a plenum (holes within +-1 %), and O/F returns to the plenum value."""
128 IN = 0.0254
129
130 def cad(c):
131 pl = c.injector.plate
132 pl.channel_inlets, pl.channel_width = 2, 0.3 * IN
133 pl.channel_flow_height_O, pl.channel_flow_height_F = 0.487 * IN, 0.54 * IN
134
135 r, d = _run(cad)
136 from engine.core.injectors.layout import layout_from_config
137 rp, _ = _run(lambda c: setattr(c.injector.plate, "manifold_model", "plenum"))
138 assert d["element_flow_ratio_max_O"] - d["element_flow_ratio_min_O"] < 0.02
139 assert r["MR"] == pytest.approx(rp["MR"], rel=0.01)
#define min(a, b)
Definition Arduino.h:42
#define max(a, b)
Definition Arduino.h:43