First-principles 1D thermal / hydraulic / structural solver for regeneratively-cooled liquid rocket engine chambers — real-gas combustion, real-fluid coolant properties, coupled Bartz–Gnielinski–Chen heat transfer, and seven independent design margins that either pass or don't. No curve-fit shortcuts, no black box.
Most of the tools available to a university propulsion team are one of two things: a CEA-only performance spreadsheet that never touches the wall, or a single-point 1D model that assumes constant coolant properties and reports one number for the whole chamber. Neither catches a throat that dry-boils, a rib that fatigues in 40 cycles, or a channel that seizes 6× over its pressure budget.
Hot-wall temperature and thermal stress peak at the throat because heat flux tracks At/A to the 0.9 power. Coolant-side film coefficient is lowest exactly where the tube is narrowest for structural reasons. Two-phase boiling, if it happens, happens downstream of the throat where bulk temperature has climbed — and dryout there is a wall-burnthrough event, not a performance hit.
Every run produces: max hot-wall temperature vs. melt/service limit, max thermal hoop stress vs. 0.67σy(T), coolant ΔP vs. 25% of inlet pressure, max coolant velocity vs. an erosion limit, coolant-wall and bulk temperature vs. coking limits, critical-heat-flux margin, and estimated low-cycle-fatigue life via Coffin–Manson. All seven, every station, every run.
Inputs flow forward through combustion → gas dynamics → a per-station coupled solve → structural margins. The same physics core is exposed at three speeds, because a 4000-point optimizer sweep and a single certified design case have very different runtime budgets.
| Path | Used by | Notes |
|---|---|---|
run_analysis_stream | Live UI (WS) | Full-fidelity, streams per-station |
run_analysis / _march | /api/analyze, tests | Full-fidelity, single shot |
run_batch_analysis_fast | Optimizer sweep | Vectorised, documented simplifications |
Counter-current cooling (the default, and the harder case) integrates the coolant energy balance backward from the nozzle exit while the gas-side march runs forward from the chamber — the two loops meet through the fixed-point iteration at each station, not through a global relaxation sweep.
Numbered the way the solver actually walks through them — gas side, through the wall, into the coolant, and out as a pressure drop and a stress. Every correlation is cited; none of the constants are guessed.
The WebGL nozzle view is colour-mapped directly from solver arrays (heat flux, Twg, Twc, thermal stress) — the same numbers driving the Plotly traces beside it, streamed station-by-station over a WebSocket as the march runs.
The shipped default (45 kN, RP-1/LOX, 90 channels, CuCrZr) is under-cooled. That's deliberate: a tool that always shows green checkmarks in its own screenshots is a tool you can't trust. Below is the actual margins table from the run captured above.
| Check | Value | Limit | Units | Ratio | Status |
|---|---|---|---|---|---|
| Max hot-wall temp Twg | 1.18k | 1.35k | K | 1.14 | PASS |
| Max thermal stress | 575.10M | 93.26M | Pa | 0.16 | FAIL |
| Coolant ΔP (w/ SF) | 7.69M | 2.00M | Pa | 0.26 | FAIL |
| Max coolant velocity | 67.17 | 80.00 | m/s | 1.19 | PASS |
| Coolant-wall temp Twc | 820.86 | 700.00 | K | 0.85 | FAIL |
| Coolant bulk temp | 645.26 | 560.00 | K | 0.87 | FAIL |
| Estimated LCF life | 387.56 | 100.00 | cycles | 3.88 | PASS |
Regression coverage (test_margin_agreement.py) sweeps a grid of channel geometries through both the vectorised optimizer surrogate and the full march, and asserts the two never flip a pass/fail decision and agree on total ΔP within 15% — the fast path used for a 4000-point sweep is checked against the slow path used for the final number.
Sweep channel count, height, width, rib width, wall thickness and coolant flow rate; pre-filter anything that fails packing (channels + ribs exceeding the throat circumference); vectorised-batch solve every survivor; then let differential evolution refine continuously past the grid.
Two known gaps, left out on purpose rather than papered over with a guessed constant.
The Kutateladze/Zuber pool-boiling bound used today is a conservative stand-in — it has no mass-flux (G) term, so it doesn't capture forced-convection CHF enhancement. The correct upgrade is Katto–Ohno (1984), a five-regime correlation whose constants sit behind paywalled primary literature. Rather than guess coefficients for a safety-critical wall-burnthrough margin, it's left out until a verifiable source (textbook table or the original paper) is in hand.
Combustion products are equilibrated once, at chamber conditions, and expanded with frozen composition (constant γ, T₀) — standard practice, and conservative for Isp. True shifting equilibrium would re-run a Cantera SP-flash at every station, which changes Isp, which changes required ṁ, which cascades through the entire coupled solve. Real, but high blast-radius; not added silently.