|
| frozenset[str] | _ground (Model model) |
| list[str] | _bottle_ids (Model model) |
| tuple[dict[str, str], dict[str, str]] | drawn_fills (Model model) |
| dict[str, list[str]] | _pressed_supplies (Model model) |
| dict[str, str] | builtin_rows (StateMachine machine, Model model, Collection[str]|None drawn=None) |
| str | _not_a_liquid_tank (str label, str species, float temperature, Exception exc) |
| CylindricalTank | _bottle_geometry (float volume) |
| CylindricalTank | _tank_geometry (float volume, float diameter) |
| float | _skin_conductance (object node, float air_film, list[str] assumptions) |
| float | _trip_limit (object node, float safety_factor, list[str] assumptions) |
| tuple[float, float, float] | _vessel_wall (object node, float litres, dict[str, Any] defaults, list[str] assumptions, Callable[[], GasFilm]|None estimate=None) |
A stand that exists in time.
Everything before this was a calculator with a state label on it: each request
re-solved from scratch with the tanks *pinned* at the regulator's setpoint. So
the tanks were always pressurised, "Fuel Press" changed nothing you could see,
and transducers read pressures that had no business existing. Nothing
accumulated, so nothing behaved.
A session fixes that by holding the thing a stand actually has -- **inventory**.
Each tank is a real vessel with a gas mass, a gas energy, a liquid mass and a
wall temperature, and those integrate forward. That single change is what makes
the sequence mean something:
* A tank starts **empty and at atmosphere**. Its transducer reads 14.7 psi,
because that is what a vented tank reads.
* ``Ox Fill`` puts propellant in it. The level rises; the ullage shrinks.
* ``Ox Press`` opens the path from the regulator, gas flows into the ullage, and
the pressure *climbs over several seconds* the way a real tank does -- fast at
first into a small ullage, slower as it fills.
* ``Ox Vent`` opens it to atmosphere and it blows down.
* ``Fire`` opens the mains, propellant leaves, and the ullage cools and droops
because the gas behind it is doing expansion work.
None of that is scripted. It falls out of integrating the vessels against a
network solved at each instant.
How a tick works
----------------
The system is a semi-explicit index-1 DAE: the vessels are differential, the
network is algebraic. Rather than hand the whole thing to a stiff integrator --
which is what Phase 07 did, and what would not converge on an imported
network -- this marches it at a fixed small step, which is what a flight
simulator does and is stable for the same reason:
1. Write each vessel's current pressure into its network boundary node.
2. Solve the network for flows. Pure algebra at frozen vessel state.
3. Hand those flows back to the vessels as inflow and outflow.
4. Advance the vessels by ``dt``.
A tick that fails to converge does not abort the session -- it holds the last
good flows and keeps going, because a stand does not stop existing because one
solve was hard, and the alternative is a simulator that dies mid-sequence.
| float feedtwin.session.core._trip_limit |
( |
object | node, |
|
|
float | safety_factor, |
|
|
list[str] | assumptions ) |
|
protected |
Absolute pressure a vessel trips the stand at, or 0 for no limit.
The drawing says what the vessel will take as a burst pressure -- what a
team that built it knows -- and the stand stops at that over a stated
factor of safety. An older drawing carrying an MAWP trips at the MAWP.
Both are read as the drawing reads them (feedtwin.model.pressure): bare
"psi" is gauge, so ``.si`` is already absolute. The safety factor divides
what the wall carries -- the pressure across it, gauge -- not the absolute.
Definition at line 1082 of file core.py.
References max.
Referenced by feedtwin.session.core.Session._build_vessels().
| tuple[float, float, float] feedtwin.session.core._vessel_wall |
( |
object | node, |
|
|
float | litres, |
|
|
dict[str, Any] | defaults, |
|
|
list[str] | assumptions, |
|
|
Callable[[], GasFilm] | None | estimate = None ) |
|
protected |
``(wall_mass, wall_capacity, wall_conductance)`` for one vessel.
From the drawing where it says; from the scaled defaults where it does
not, with a note. Reading the three separately, so a drawing that weighed
the vessel but has no idea of its film coefficient still gets credit for
the number it knows.
Definition at line 1108 of file core.py.
References max, and read().
Referenced by feedtwin.session.core.Session._build_vessels().
| dict[str, str] feedtwin.session.core.builtin_rows |
( |
StateMachine | machine, |
|
|
Model | model, |
|
|
Collection[str] | None | drawn = None ) |
The table's rows the session reads by name and acts on itself with no
valve wired to them, with what each does: the built-in COPV charge and
dump, and the cart's press on a transfer tank
(:meth:`Session._supply_press`). Such a row is not "wired to nothing" --
renaming or dropping it stops what it does, and an editor must say so.
Only where the session would act on ``model``: the charge and dump while
a vehicle bottle's fill is not drawn (a cart drawn charging it charges it
through its own valves, and an unwired GSE High Press Control then
charges nothing), the press while a transfer tank of the row's side has a
drawn pressure. Rocket only, give it the cut model: the cart's fill went
with the cart. ``drawn``: the vessels the drawing fills, when a session
has found them already (:attr:`Session.builtin`); else found here.
Definition at line 419 of file core.py.
References _bottle_ids(), _ground(), _pressed_supplies(), and drawn_fills().
Referenced by feedtwin.session.core.Session.builtin().
| tuple[dict[str, str], dict[str, str]] feedtwin.session.core.drawn_fills |
( |
Model | model | ) |
|
The vessels the drawing itself fills, each with what fills it:
``(tanks, bottles)``, vessel id -> supply id.
Tanks a drawn dewar reaches, and bottles another drawn bottle or dewar
reaches, through the drawing's lines and valves (open or shut -- a valve
is how the fill is commanded, not whether it exists) without passing
through another vessel -- from another page of the drawing, which is
where pid-designer puts the cart. Two flight bottles manifolded together
on the vehicle page are not one filling the other. A cart's own tank and
bottles are supplies and never listed. The session's built-in fill steps
aside for every one (:attr:`Session._drawn_fill`).
Definition at line 324 of file core.py.
References _bottle_ids(), and _ground().
Referenced by feedtwin.session.core.Session._find_drawn_fills(), and builtin_rows().