STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_orifice_inlet_geometry_cd.py
Go to the documentation of this file.
1"""Cd comes from the orifice INLET and its L/d, and it is a per-side design knob.
2
3Two things this pins down.
4
51. THE ANCHORS. The widely-quoted "sharp-edged orifice, Cd = 0.61" is the THIN-PLATE value
6 (L/d -> 0), where the jet leaves at the vena contracta and never recovers. The same sharp
7 entry on a normally drilled hole (L/d 2-5) reattaches inside the bore and recovers to
8 ~0.80. Conflating them under-predicts a real injector's flow by ~24%, which is the same
9 class of error as the Cd-reduction loop this codebase already had.
10
11 Sources: Huzel & Huang, "Modern Engineering for Design of Liquid-Propellant Rocket
12 Engines" (injector orifice Cd table); Lichtarowicz, Duggins & Markland (1965),
13 "Discharge Coefficients for Incompressible Non-Cavitating Flow through Long Orifices"
14 (Cd peaks near L/d ~ 2, Re-independent above ~1e4); Nurick (1976) on inlet condition and
15 cavitation inception.
16
172. IT IS A KNOB. `discharge.oxidizer` and `discharge.fuel` are separate config blocks, so
18 filleting only ONE side's inlet raises that propellant's Cd and moves the momentum ratio
19 / O/F without touching hole size, element count or angles.
20"""
21from __future__ import annotations
22
23import pytest
24
25from engine.core.discharge import (
26 INLET_GEOMETRY_CD,
27 cd_from_inlet_radius_ratio,
28 cd_from_re,
29 cd_inf_from_inlet_geometry,
30 cd_length_factor,
31)
32from engine.pipeline.config_schemas import DischargeConfig
33
34_BASE = dict(Cd_inf=0.60, a_Re=0.18, Cd_min=0.35, use_geometry_cd=True, d_ref_m=0.002,
35 cd_small_hole_exponent=0.20, cd_large_hole_log_gain=0.015,
36 cd_inf_max=0.62, cd_inf_min_geom=0.48)
37
38
39@pytest.mark.parametrize("r_over_d,l_over_d,expected,label", [
40 (0.00, 0.001, 0.61, "thin plate, sharp"),
41 (0.00, 4.0, 0.80, "drilled hole, sharp"),
42 (0.10, 4.0, 0.88, "short tube, rounded entrance"),
43])
44def test_published_anchors(r_over_d, l_over_d, expected, label):
45 cd = cd_from_inlet_radius_ratio(r_over_d) * cd_length_factor(l_over_d)
46 assert cd == pytest.approx(expected, abs=0.01), f"{label}: got {cd:.4f}, published {expected}"
47
48
50 """The 24% gap is the whole point -- if these collapse, the model has lost the physics."""
51 thin = cd_from_inlet_radius_ratio(0.0) * cd_length_factor(0.001)
52 drilled = cd_from_inlet_radius_ratio(0.0) * cd_length_factor(4.0)
53 assert drilled / thin > 1.2, "a drilled hole must flow materially more than a thin plate"
54
55
57 """Cd rises to a maximum near L/d ~ 2 and falls slowly after; it does not rise forever."""
58 assert cd_length_factor(2.0, "piecewise") == pytest.approx(1.0)
59 assert cd_length_factor(4.0, "piecewise") == pytest.approx(1.0)
60 assert cd_length_factor(2.0) > cd_length_factor(4.0) # Lichtarowicz: no plateau
61 assert cd_length_factor(0.5) < cd_length_factor(2.0)
62 assert cd_length_factor(12.0) < cd_length_factor(4.0)
63
64
66 """Past r/d ~ 0.2 rounding buys almost nothing -- why bellmouths are specified there."""
67 gain_early = cd_from_inlet_radius_ratio(0.10) - cd_from_inlet_radius_ratio(0.0)
68 gain_late = cd_from_inlet_radius_ratio(0.30) - cd_from_inlet_radius_ratio(0.20)
69 # measured 4.59x on the fitted curve; the point is that the first 0.1 of rounding
70 # buys several times what the third 0.1 buys, not a specific multiple.
71 assert gain_early > 4.0 * gain_late
72
73
74@pytest.mark.parametrize("name", sorted(INLET_GEOMETRY_CD))
76 cfg = DischargeConfig(**_BASE, inlet_geometry=name, orifice_l_over_d=4.0)
77 cd = cd_from_re(3.5e5, cfg, d_hyd_m=2.1e-3)
78 assert 0.55 < cd < 0.98
79 assert cd == pytest.approx(INLET_GEOMETRY_CD[name], abs=0.02)
80
81
83 """Opt-in: a config that declares no inlet geometry must behave exactly as before."""
84 cfg = DischargeConfig(**_BASE)
85 assert cd_inf_from_inlet_geometry(cfg) is None
86 assert cd_from_re(3.5e5, cfg, d_hyd_m=2.1e-3) == pytest.approx(0.60, abs=0.02)
87
88
90 """The knob: same hole, same dP, one side filleted -> that side flows measurably more."""
91 sharp = cd_from_re(3.5e5, DischargeConfig(**_BASE, inlet_geometry="sharp",
92 orifice_l_over_d=4.0), d_hyd_m=2.1e-3)
93 filleted = cd_from_re(3.5e5, DischargeConfig(**_BASE, inlet_radius_ratio=0.10,
94 orifice_l_over_d=4.0), d_hyd_m=2.1e-3)
95 gain = filleted / sharp - 1.0
96 assert 0.08 < gain < 0.14, f"r/d 0.10 should buy ~10% flow, got {gain*100:.1f}%"
97
98
100 with pytest.raises(ValueError, match="Unknown inlet_geometry"):
101 cd_inf_from_inlet_geometry(DischargeConfig(**_BASE, inlet_geometry="polished"))
test_published_anchors(r_over_d, l_over_d, expected, label)