STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
engine.layerx.diag.start Namespace Reference

Classes

class  StartLine
class  StartChamber
class  StartSettings
class  Element
class  FeedLine

Functions

Dict[str, Any] inp (Any value, str unit, str provenance)
Dict[str, Any] model_block (str name, str source, Sequence[str] assumptions, Mapping[str, Dict[str, Any]] inputs)
Dict[str, Any] unavailable (str error)
Optional[float] finite (Any x)
str param_provenance (Any param, str note="")
float column_step (float m, float dp, float inertance, float resistance, float dt)
float chamber_step (float pc, float mdot_in, float rt_over_v, float at_over_cstar, float dt)
float gamma_function (float gamma)
float linear_characteristic (float x)
float _interp_time (float t0, float dt, float v0, float v1, float target)
Dict[str, Any] run_start (StartLine ox, StartLine fuel, StartChamber chamber, *, float dt=1.0e-5, float horizon_s=0.25, float settle_tol=0.01, float record_every_s=5.0e-4)
Tuple[float, int] _call (Callable[[float, float], float] fn, float a, float b)
Optional[float] _settle_time (List[Tuple[float, float, float, float]] trace, Tuple[float, float] m_end, float F_end, float tol, float t_ign)
Dict[str, float] fixed_load_deficit (*, Sequence[Tuple[float, float, float, float]] trace, float t_window, float F_settled, Tuple[float, float] mdot_settled, float scale_F=1.0, Tuple[float, float] scale_m=(1.0, 1.0), float c_end, float mr_end, Tuple[float, float] residual_extra)
List[str] feed_path (Any net, str inlet, str tank)
Dict[str, Dict[str, Any]] _params_inputs (str prefix, Any comp, Sequence[str] names, Mapping[str, str] notes={})
FeedLine feed_line (Any prep, str side, *, float mdot_ref, float p_ref, float T_ref)
Tuple[float, bool] exit_area (FeedLine feed)
Dict[str, Dict[str, Any]] manifold_volumes (Any config)
int _first_firing (Mapping[str, Any] series)
int _last_firing (Mapping[str, Any] series)
Callable[[float, float], Tuple[float, bool]] _card_fn (Any table, str label)
Dict[str, Any] settled_point (Mapping[str, Any] result)
Dict[str, Any] start_from_run (Any prep, Mapping[str, Any] result, Any config=None, StartSettings settings=StartSettings())
Dict[str, Any] _start_from_run (Any prep, Mapping[str, Any] result, Any config, StartSettings settings)

Variables

float PSI = 6894.757293168361
float G0 = 9.80665
tuple SIDES = (("oxidiser", "ox"), ("fuel", "fuel"))
str MODEL_NAME = "start_transient_rigid_column"

Detailed Description

Layer X start transient: Fire to settled flow, as a reduced-order model of its own.

``start_from_run(prep, result, config=None, settings=StartSettings())`` -> ``diagnostics.start``
(DATA-CONTRACT 3). ``run_start(ox, fuel, chamber, ...)`` is the model on plain inputs.

The main burn does not change. The twin's network is algebraic: its first firing step is
already at full flow (AUDIT 9.5 §1, §5), so the start is a diagnostic beside the burn and a
correction estimate (the impulse the start costs), never an edit of the burn.

The model
---------
Each side is one liquid column, tank outlet to injector orifices, in lumped (rigid-column)
form, the inertance-resistance line of AUDIT 7 item 1:

    I dm/dt = p_tank - p_end - R m|m|            I = sum L/A    [1/m],  R [Pa/(kg/s)^2]

* **Valve.** The drawing's main valve opens on command as a linear travel over its drawn
  ``travel_time``; its Cv follows the valve's own inherent characteristic (feedtwin
  ``Valve.effective_cv``), and its loss is feedtwin's (``fluids`` Cv-to-K), so
  ``R_valve(x) = R_valve(1) (Cv(1)/Cv(x))^2``.
* **Lines.** Each element's quadratic loss is the twin's own ``pressure_drop`` (Darcy with the
  drawing's friction correlation and ``K_minor``) at the main burn's first settled flow, divided
  by that flow squared: the friction factor is frozen there.
* **Priming.** Downstream of the main valve the line, the injector manifold and the orifices are
  gas-filled at Fire (AUDIT 9.5 §4: the twin holds them liquid at 101 kPa, which would flash).
  The liquid front fills that volume; the gas it displaces vents through the orifices into the
  chamber. While it fills, the column's inertance grows with the length of downstream tube it
  occupies, its end pressure is the chamber's (ambient before ignition: the displaced gas's
  orifice drop, ``rho_g/2 (Q/A_orifices)^2``, is under 7 kPa at LE4's arrival flows against ~3.9 MPa of
  drive, and is neglected), and the liquid
  entering the gas volume loses ``K_exit_prime`` velocity heads at the last drawn tube's bore (1: the
  "1" of Liou & Hunt's ``(1 + K)``, the velocity head the growing column carries, which is also the
  Borda dump of a front entering a larger volume; their entrance ``K`` is the drawing's tank-exit
  ``K_minor``, already in the line loss). This is the
  rigid-column filling model: the unsteady Bernoulli/momentum balance on a column of growing
  length entering from a reservoir, ``rho l dv/dt = p_res - p_front - (1 + K) rho v^2/2 - f l rho v^2/(2D)``
  (Liou & Hunt, "Filling of pipelines with undulating elevation profiles", J. Hydraul. Eng.
  122(10), 1996, rigid-column model). Once the manifold is full the injector's capacity takes
  over: ``m = phi sqrt(p_line_exit - Pc)`` (the engine card's capacity, which owns the dump and
  the orifices, engine/layerx/card.py), and the orifice passages add their inertance.
* **Ignition** is when both manifolds are primed, plus ``ignition_delay_s`` (an explicit input:
  0 = the igniter is lit and propellant ignites on arrival). Before it the chamber is at
  ambient (cold flow through the throat costs ~1 kPa).
* **Chamber filling** after ignition: ``dPc/dt = (R T / V)(m_in - Pc A_t / c*)`` with
  ``R T = (Gamma c*)^2`` (the ideal-rocket identity c* = sqrt(R T)/Gamma, Sutton & Biblarz,
  Rocket Propulsion Elements, the characteristic-velocity relation), c* from the engine card at the instantaneous O/F and
  flow, and propellant burning on arrival (no vaporisation lag; the chug model owns that lag).
  The chamber's time constant is ``L* / (Gamma^2 c*)`` (AUDIT 9.5 §1: 2.1 ms on LE4).
* **Thrust** is the card's vacuum exhaust velocity times the nozzle flow, less ``p_a A_e``,
  floored at zero (a separated nozzle at low Pc is not modelled; it would give more thrust than
  this, so the deficit here is the larger figure).

Integration is backward Euler on each column with the quadratic loss solved exactly (stable for
any valve opening, exact for an inertance-only line), and backward Euler on the chamber, at a
fixed ``dt`` (10 us default, 200x below the shortest line constant on LE4).

What it reports
---------------
* ``prime_ox_s``, ``prime_fuel_s``, ``ignition_s``; Pc, flows and O/F through the start.
* ``impulse_deficit_Ns``: the total impulse a burn with this start delivers less than the main
  burn, at a **fixed propellant load**. The start window (Fire to settled) is credited at the
  main burn's first settled thrust in the main burn (its first firing step is at full flow and
  is copied back to Fire, replay.timeseries_payload); the propellant the start did not spend is
  burned at the end at the main burn's end-of-burn exhaust velocity, limited by whichever tank
  runs dry, so a fuel lead that eats into fuel the main burn strands costs less than its mass.
  The mass that fills the downstream line and manifold is not charged: like the twin's massless
  lines, it is pushed through at burnout.
* ``hard_start``: a **heuristic** (no cited criterion): propellant both sides have injected and
  not yet burned at ignition, paired at the design O/F, against the chamber's own steady gas
  inventory ``Pc V / (Gamma c*)^2``. Over ``hard_start_ratio`` (1.0) of it, burning that pair at
  once in the chamber volume would by itself exceed the steady chamber pressure.

Limits (stated in the model block): tank pressure held at its T-0 value through the start; the
line is incompressible (the arrival surge at the orifices is reported as the rigid-column
orifice back-pressure; its compressible part is water hammer, ``diag.waterhammer``); the
manifold fills before any orifice flows; the friction factor is frozen at the settled flow; the
engine card is clipped to its table (flagged by how often).

Function Documentation

◆ _call()

Tuple[float, int] engine.layerx.diag.start._call ( Callable[[float, float], float] fn,
float a,
float b )
protected
``fn(a, b)``; a function that clips (an engine card table) says so through a
``(value, clipped)`` tuple, a plain function returns a float.

Definition at line 412 of file start.py.

Referenced by run_start().

◆ _card_fn()

Callable[[float, float], Tuple[float, bool]] engine.layerx.diag.start._card_fn ( Any table,
str label )
protected

Definition at line 726 of file start.py.

References max, and min.

Referenced by _start_from_run().

◆ _first_firing()

int engine.layerx.diag.start._first_firing ( Mapping[str, Any] series)
protected

Definition at line 712 of file start.py.

Referenced by settled_point().

◆ _interp_time()

float engine.layerx.diag.start._interp_time ( float t0,
float dt,
float v0,
float v1,
float target )
protected

Definition at line 271 of file start.py.

References max, and min.

Referenced by run_start().

◆ _last_firing()

int engine.layerx.diag.start._last_firing ( Mapping[str, Any] series)
protected

Definition at line 719 of file start.py.

Referenced by _start_from_run().

◆ _params_inputs()

Dict[str, Dict[str, Any]] engine.layerx.diag.start._params_inputs ( str prefix,
Any comp,
Sequence[str] names,
Mapping[str, str] notes = {} )
protected

Definition at line 575 of file start.py.

References finite(), inp(), and param_provenance().

Referenced by feed_line().

◆ _settle_time()

Optional[float] engine.layerx.diag.start._settle_time ( List[Tuple[float, float, float, float]] trace,
Tuple[float, float] m_end,
float F_end,
float tol,
float t_ign )
protected
The last instant thrust or either injected flow is outside ``tol`` of its final value.

Definition at line 421 of file start.py.

Referenced by run_start().

◆ _start_from_run()

Dict[str, Any] engine.layerx.diag.start._start_from_run ( Any prep,
Mapping[str, Any] result,
Any config,
StartSettings settings )
protected

◆ chamber_step()

float engine.layerx.diag.start.chamber_step ( float pc,
float mdot_in,
float rt_over_v,
float at_over_cstar,
float dt )
One backward-Euler step of ``dPc/dt = (RT/V)(m_in - Pc A_t/c*)``.

Definition at line 156 of file start.py.

Referenced by run_start().

◆ column_step()

float engine.layerx.diag.start.column_step ( float m,
float dp,
float inertance,
float resistance,
float dt )
One backward-Euler step of ``I dm/dt = dp - R m|m|``, the quadratic solved exactly.

``I (m' - m)/dt = dp - R m'|m'|``. Unconditionally stable for ``R >= 0`` (a nearly shut
valve is a huge R and a tiny time constant ``I/(2 R m)``), and exact when ``R = 0``.
With no inertance it is the quasi-steady ``m = sign(dp) sqrt(|dp|/R)``.

Definition at line 135 of file start.py.

Referenced by run_start().

◆ exit_area()

Tuple[float, bool] engine.layerx.diag.start.exit_area ( FeedLine feed)
The area the flow enters the injector manifold through [m^2], and whether it is the main
valve's own bore: the last drawn line below the main valve, else the last above it, else -- a
side drawn with no line at all, as LE4's LOX side is (tank outlet, OM-R, injector) -- the valve's
bore. That last case used to index an empty list, and the whole start went missing from the run.
With neither a line nor a valve bore on the drawing there is nothing to take it from: it raises.

Definition at line 656 of file start.py.

Referenced by _start_from_run().

◆ feed_line()

FeedLine engine.layerx.diag.start.feed_line ( Any prep,
str side,
* ,
float mdot_ref,
float p_ref,
float T_ref )
The drawn feed path of ``side`` with each element's loss priced by the twin's own
component at ``mdot_ref`` and the fluid's state at ``p_ref`` [Pa], ``T_ref`` [K].

Definition at line 587 of file start.py.

References _params_inputs(), feed_path(), and max.

Referenced by _start_from_run().

◆ feed_path()

List[str] engine.layerx.diag.start.feed_path ( Any net,
str inlet,
str tank )
Branch ids from the tank down to the injector inlet (a breadth-first walk upstream, so a
fill or vent tee meeting the path is not taken for the feed). Same walk as
engine/layerx/flight.py ``_path_to_tank``.

Definition at line 493 of file start.py.

Referenced by feed_line().

◆ finite()

Optional[float] engine.layerx.diag.start.finite ( Any x)

Definition at line 114 of file start.py.

Referenced by _params_inputs(), and _start_from_run().

◆ fixed_load_deficit()

Dict[str, float] engine.layerx.diag.start.fixed_load_deficit ( * ,
Sequence[Tuple[float, float, float, float]] trace,
float t_window,
float F_settled,
Tuple[float, float] mdot_settled,
float scale_F = 1.0,
Tuple[float, float] scale_m = (1.0, 1.0),
float c_end,
float mr_end,
Tuple[float, float] residual_extra )
Total impulse lost to the start at a fixed propellant load [N s].

The main burn credits ``F_settled`` from Fire to ``t_window`` and spends ``mdot_settled``
per side over it. The start delivers ``J_s`` and spends ``m_s`` (injected) over the same
window. After the window the two burns are the same burn, except at the end: the real one
has ``E = (mdot_settled t_w - m_s) + residual_extra`` more of each propellant than the main
burn had when it ended, burned at O/F ``mr_end`` until the first side runs out, at
``c_end`` [m/s]. ``residual_extra`` is each side's main-burn residual over the dry mass.

    deficit = (F_settled t_w - J_s) - c_end * min(E_ox, mr_end E_fu) (1 + 1/mr_end)

``trace`` is ``(t, F, m_ox_injected, m_fuel_injected)`` at a fixed step from the start's
first valve command; ``scale_*`` put the model's own steady state on the main burn's scale.

Definition at line 437 of file start.py.

References max, and min.

Referenced by _start_from_run().

◆ gamma_function()

float engine.layerx.diag.start.gamma_function ( float gamma)
Vandenkerckhove's Gamma = sqrt(g) (2/(g+1))^((g+1)/(2(g-1))); the ideal-rocket mass-flow function (Sutton & Biblarz, Rocket Propulsion Elements).

Definition at line 162 of file start.py.

Referenced by run_start().

◆ inp()

Dict[str, Any] engine.layerx.diag.start.inp ( Any value,
str unit,
str provenance )
One entry of a model block's ``inputs`` (DATA-CONTRACT).

Definition at line 96 of file start.py.

Referenced by _params_inputs(), _start_from_run(), and manifold_volumes().

◆ linear_characteristic()

float engine.layerx.diag.start.linear_characteristic ( float x)

Definition at line 167 of file start.py.

References max, and min.

◆ manifold_volumes()

Dict[str, Dict[str, Any]] engine.layerx.diag.start.manifold_volumes ( Any config)
Each side's injector volume downstream of its feed port, from the config's injector layout
(engine/core/injectors/layout.py): the ring channel (cross-section x 2 pi r_center) and the
orifice passages (n x pi/4 d^2 x through-length). Returns per ``ox``/``fuel``: ``V_m3``,
``I_inj`` (passage length over total passage area) and the inputs. The plate's feed ports and
any back-cover passages are not in the layout and are not counted.

Definition at line 672 of file start.py.

References inp().

Referenced by _start_from_run().

◆ model_block()

Dict[str, Any] engine.layerx.diag.start.model_block ( str name,
str source,
Sequence[str] assumptions,
Mapping[str, Dict[str, Any]] inputs )
DATA-CONTRACT ``model``: what produced a block, so the run record can list it.

Definition at line 103 of file start.py.

Referenced by _start_from_run().

◆ param_provenance()

str engine.layerx.diag.start.param_provenance ( Any param,
str note = "" )
``"<source>: <reference>"`` for a feedtwin ``Param`` (a drawing value), plus a note.

Definition at line 122 of file start.py.

Referenced by _params_inputs().

◆ run_start()

Dict[str, Any] engine.layerx.diag.start.run_start ( StartLine ox,
StartLine fuel,
StartChamber chamber,
* ,
float dt = 1.0e-5,
float horizon_s = 0.25,
float settle_tol = 0.01,
float record_every_s = 5.0e-4 )
Integrate the start. Returns the time histories and the event times (SI, Pa).

Definition at line 277 of file start.py.

References _call(), _interp_time(), _settle_time(), chamber_step(), column_step(), gamma_function(), max, and min.

Referenced by _start_from_run().

◆ settled_point()

Dict[str, Any] engine.layerx.diag.start.settled_point ( Mapping[str, Any] result)
The main burn's first settled operating point: the delivered (replay) first point when the
replay ran, else the twin's first firing step.

Definition at line 738 of file start.py.

References _first_firing().

Referenced by _start_from_run().

◆ start_from_run()

Dict[str, Any] engine.layerx.diag.start.start_from_run ( Any prep,
Mapping[str, Any] result,
Any config = None,
StartSettings settings = StartSettings() )
``diagnostics.start`` for a finished Layer X run. Never raises.

Definition at line 760 of file start.py.

References _start_from_run(), and unavailable().

◆ unavailable()

Dict[str, Any] engine.layerx.diag.start.unavailable ( str error)
DATA-CONTRACT: a block that could not be computed. It never raises.

Definition at line 109 of file start.py.

Referenced by start_from_run().

Variable Documentation

◆ G0

float engine.layerx.diag.start.G0 = 9.80665

Definition at line 87 of file start.py.

◆ MODEL_NAME

str engine.layerx.diag.start.MODEL_NAME = "start_transient_rigid_column"

Definition at line 90 of file start.py.

◆ PSI

float engine.layerx.diag.start.PSI = 6894.757293168361

Definition at line 86 of file start.py.

◆ SIDES

tuple engine.layerx.diag.start.SIDES = (("oxidiser", "ox"), ("fuel", "fuel"))

Definition at line 88 of file start.py.