STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_graphite_oxidation.py
Go to the documentation of this file.
1"""Graphite throat chemistry: H2O, CO2 and OH are the oxidisers, and they absorb heat (TH-7).
2
3The old model attacked carbon with O2 only, at an invented 3.75 % mole fraction (CEA has
40.34 %), and heated the surface with the C + O2 -> CO2 enthalpy (+32.8 MJ/kg). Expected
5values below are independent:
6 * CEA equilibrium throat composition, LOX/ethanol O/F 1.50, 433.65 psia (rocketcea
7 get_SpeciesMoleFractions, throat column);
8 * reaction enthalpies from JANAF heats of formation at 298 K;
9 * the diffusion limit g ln(1 + B') of film theory (Spalding), B' = MW_C sum(nu_i X_i)/MW.
10"""
11import math
12import os
13import sys
14
15import pytest
16
17sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
18
19from engine.pipeline.config_schemas import GraphiteInsertConfig, SurfaceReactionConfig # noqa: E402
20from engine.pipeline.thermal.graphite_cooling import carbon_oxidation # noqa: E402
21
22THROAT = {"H2O": 0.4659, "CO": 0.2412, "CO2": 0.1491, "H2": 0.1006, "OH": 0.0241,
23 "H": 0.0139, "O2": 0.00341, "O": 0.00187, "MW": 22.475}
24P_THROAT = 433.65 * 6894.757 / 1.735 # Pc / (Pc/Pt), CEA
25G0 = 4.8 # h/cp at the throat, Bartz, kg/(m^2 s)
26RHO = 2260.0
27
28# JANAF 298 K heats of formation [kJ/mol]
29HF = {"H2O": -241.826, "CO": -110.527, "CO2": -393.522, "OH": 37.3, "H": 217.999, "O": 249.18}
30MWC = 12.0107
31
32
33def _cfg(**kw):
34 return GraphiteInsertConfig(enabled=True, **kw)
35
36
38 no_o2 = dict(THROAT, O2=0.0, O=0.0)
39 ox = carbon_oxidation(2500.0, P_THROAT, no_o2, THROAT["MW"], G0, _cfg())
40 rate = ox["mass_flux"] / RHO
41 assert rate > 0.15e-3 # ~0.3 mm/s; the O2-only model gave 0.00026 mm/s
42 assert ox["species"]["H2O"] > ox["species"]["CO2"] > 0
43
44
46 ox = carbon_oxidation(2400.0, P_THROAT, THROAT, THROAT["MW"], G0, _cfg())
47 assert ox["q_chem"] > 0 # absorbed at the surface (old: +1.5 MW/m^2 heating)
48 only_h2o = {"H2O": 0.4659, "MW": THROAT["MW"]}
49 ox = carbon_oxidation(2400.0, P_THROAT, only_h2o, THROAT["MW"], G0, _cfg())
50 dH = (HF["CO"] - HF["H2O"]) * 1e3 / (MWC * 1e-3) # C + H2O -> CO + H2
51 assert ox["q_chem"] / ox["mass_flux"] == pytest.approx(dH, rel=0.005)
52 only_co2 = {"CO2": 0.1491, "MW": THROAT["MW"]}
53 ox = carbon_oxidation(2400.0, P_THROAT, only_co2, THROAT["MW"], G0, _cfg())
54 dH = (2 * HF["CO"] - HF["CO2"]) * 1e3 / (MWC * 1e-3) # C + CO2 -> 2 CO
55 assert ox["q_chem"] / ox["mass_flux"] == pytest.approx(dH, rel=0.005)
56
57
59 fast = SurfaceReactionConfig(A=1e12, E=0.0, n=0.5)
60 cfg = _cfg(oxidation_H2O=fast, oxidation_CO2=fast, oxidation_OH=fast)
61 ox = carbon_oxidation(3000.0, P_THROAT, THROAT, THROAT["MW"], G0, cfg)
62 Bp = MWC * (THROAT["H2O"] + THROAT["CO2"] + THROAT["OH"] + 2 * THROAT["O2"] + THROAT["O"]) / THROAT["MW"]
63 assert Bp == pytest.approx(0.346, abs=0.002)
64 assert ox["mass_flux"] == pytest.approx(G0 * math.log1p(Bp), rel=0.03)
65
66
68 """The surface temperature is an input from the insert's conduction, and the kinetics
69 make the rate climb steeply with it (the old loop returned 1.02e-4 m/s for any T_s)."""
70 r = [carbon_oxidation(T, P_THROAT, THROAT, THROAT["MW"], G0, _cfg())["mass_flux"] for T in (1800, 2200, 2600)]
71 assert r[0] < r[1] < r[2]
72 assert r[2] / r[0] > 3