STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_nozzle_cea_basis.py
Go to the documentation of this file.
1"""Nozzle exit state, ambient Cf and the finite-area combustor, on CEA's own basis.
2
3CN-4: the exit pressure came from an isentrope at the chamber's equilibrium gamma and landed
4 above both CEA bounds (94.0 kPa where CEA gives 87.2 equilibrium / 78.7 frozen).
5CN-6: the injector-end pressure was used as the nozzle's stagnation pressure at every
6 contraction ratio (no Rayleigh loss), so a skinny chamber cost nothing.
7CN-8: CEACache.eval ignored the Pa it was given (Cf_ideal was always the 14.7 psia value) and
8 clamped out-of-table inputs without a word.
9
10Reference values are NASA CEA (rocketcea 1.2.3), LOX/ethanol, quoted here:
11 * O/F 1.5013, Pc 433.65 psia, eps 5.5985, shifting equilibrium: Pc/Pe = 34.2806
12 (Pe = 87.22 kPa); the eps whose Pe is 94069.7 Pa is 5.2995.
13 * finite-area combustor ("fac", CR = 2 / 3 / 5): CEA's printed Pinj/Pinf 1.051824 / 1.022720
14 / 1.008126 at gamma_s 1.1375.
15 * Pc 433.97 psia, O/F 1.49930, eps 5.59852: get_PambCf at Pamb 13.6437 psia -> 1.50134.
16"""
17import copy
18import math
19import os
20import sys
21
22import pytest
23
24sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
25
26from engine.core.runner import PintleEngineRunner # noqa: E402
27from engine.pipeline.io import load_config # noqa: E402
28
29ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
30CFG = os.path.join(ROOT, "configs", "ethalox_6500N.yaml")
31PSI = 6894.757293168361
32P_TANK = 584.27 * PSI
33
34
35@pytest.fixture(autouse=True)
36def _python_physics(monkeypatch):
37 monkeypatch.setenv("ED_ACCEL", "off")
38
39
40@pytest.fixture(scope="module")
41def runner():
42 return PintleEngineRunner(load_config(CFG))
43
44
46 ex = runner.cea_cache.aux.exit_state(1.5013, 433.65 * PSI, 5.5985)
47 assert ex["P_exit"] == pytest.approx(433.65 * PSI / 34.2806, rel=0.005)
48
49
51 from engine.core.nozzle import expansion_ratio_for_exit_pressure
52 eps = expansion_ratio_for_exit_pressure(runner.cea_cache, 1.5013, 433.65 * PSI, 94069.7)
53 assert eps == pytest.approx(5.2995, rel=0.01)
54
55
57 """The reported Pe is the CEA expansion of the nozzle stagnation pressure the thrust uses."""
58 from engine.core.nozzle import calculate_thrust, contraction_ratio_of, nozzle_stagnation_loss
59 res = runner.evaluate(P_TANK, P_TANK, silent=True)
60 cg = runner.config.chamber_geometry
61 kappa = nozzle_stagnation_loss(contraction_ratio_of(cg), res["gamma"])
62 ex = runner.cea_cache.aux.exit_state(res["MR"], res["Pc"] / kappa, cg.expansion_ratio)
63 assert res["P_exit"] == pytest.approx(ex["P_exit"], rel=1e-9)
64 # the separation margin Pe/Pa is reported alongside
65 t = calculate_thrust(res["Pc"], res["MR"], res["mdot_total"], runner.cea_cache, runner.config,
66 res["P_ambient"])
67 assert t["exit_to_ambient_ratio"] == pytest.approx(res["P_exit"] / res["P_ambient"], rel=1e-9)
68
69
70@pytest.mark.parametrize("CR, ceas", [(2.0, 1.051824), (3.0, 1.022720), (5.0, 1.008126)])
72 from engine.core.nozzle import nozzle_stagnation_loss
73 assert nozzle_stagnation_loss(CR, 1.1375) == pytest.approx(ceas, rel=5e-4)
74
75
77 """At CR = 2 the throat sees Pc/1.0518: mdot c*_actual / At = Pc / kappa (was = Pc)."""
78 cfg = load_config(CFG)
79 At = cfg.chamber_geometry.A_throat
80 cfg.chamber_geometry.chamber_diameter = math.sqrt(4 * 2.0 * At / math.pi)
81 res = PintleEngineRunner(copy.deepcopy(cfg)).evaluate(P_TANK, P_TANK, silent=True)
82 ratio = res["mdot_total"] * res["cstar_actual"] / At / res["Pc"]
83 from engine.core.nozzle import nozzle_stagnation_loss
84 assert 1.0 / ratio == pytest.approx(nozzle_stagnation_loss(2.0, res["gamma"]), rel=2e-3)
85 assert 1.0 / ratio > 1.04
86
87
89 c = runner.cea_cache
90 Pc, MR, eps = 433.97 * PSI, 1.49930, 5.59852
91 at_site = c.eval(MR, Pc, 13.6437 * PSI, eps)
92 assert at_site["Cf_ideal"] == pytest.approx(1.50134, rel=5e-4)
93 vac = c.eval(MR, Pc, 0.0, eps)
94 assert vac["Cf_ideal"] == pytest.approx(vac["Cf_vac"], rel=1e-12)
95
96
98 c = runner.cea_cache
99 assert c.eval(1.5, 3.0e6, 101325.0, 5.6)["extrapolated"] is False
100 low = c.eval(0.8, 3.0e6, 101325.0, 5.6)
101 assert low["extrapolated"] is True and "MR" in low["clamped"]
102
103
105 """F = zeta Cf_vac P0 At - Pa Ae is what the runner delivers, so the sizing must depend on Pa
106 (it did not: vacuum and sea level gave the same throat)."""
107 from engine.core.chamber_geometry_solver import solve_chamber_geometry_with_cea
108 cg = runner.config.chamber_geometry
109 kw = dict(pc_design=cg.design_pressure, thrust_design=cg.design_thrust, cea_cache=runner.cea_cache,
110 MR=cg.design_MR, diameter_inner=cg.chamber_diameter, diameter_exit=cg.exit_diameter,
111 l_star=cg.Lstar, nozzle_efficiency=cg.nozzle_efficiency)
112 At_site = solve_chamber_geometry_with_cea(Pa=94069.7, **kw)[3]["final_A_throat"]
113 At_vac = solve_chamber_geometry_with_cea(Pa=0.0, **kw)[3]["final_A_throat"]
114 assert (At_site - At_vac) / At_vac > 0.10
test_runner_exit_state_is_on_the_thrust_basis(runner)
test_geometry_fallback_sizes_the_throat_on_the_delivered_basis(runner)
test_exit_pressure_is_ceas_shifting_equilibrium(runner)
test_cache_ambient_coefficient_uses_the_ambient_it_is_given(runner)
test_rayleigh_loss_matches_ceas_finite_area_combustor(CR, ceas)