STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
feedtwin.comps.elements Namespace Reference

Classes

class  Pipe
class  Fitting
class  Bend
class  FlexHose
class  OrificeCd
class  OrificeISO5167
class  Valve
class  ValveCd
class  CheckValve
class  CheckValveCd
class  MeasuredElement
class  SegmentedPipe

Functions

float _calibrate_choke ()
float _dynamic_head (float mdot, float bore, float rho)
float cv_from_cd (float cd, float bore)
float _curve_dp (Curve curve, float mdot)
HydraulicComponent _segmented (ComponentInstance instance)
HydraulicComponent _measured (ComponentInstance instance)
FlowConditions conditions_from_fluid (object fluid, float p, float T, Mapping[str, float]|None signals=None, *, bool multiphase=False, str|None phase=None, float gravity=GRAVITY)
float _off_the_dew_point (Fluid fluid, float p, float T)
float _ideal_gamma (Fluid fluid, float T)
tuple[float, float, float, float, float]|None _liquid_state (object fluid, float T)

Variables

float GRAVITY = 9.80665
float _CHOKE_COEFFICIENT = None
float KV_PER_CV = 1.0 / 1.1560992283536566
 XT_DEFAULT = XT_TYPICAL
float SHUT_POSITION = 1.0e-3
float GPM_PER_IN2_AT_1PSI = 38.0
float DEW_POINT_MARGIN_K = 0.05
dict _IDEAL_GAMMA_CACHE = {}
float _IDEAL_GAMMA_RESOLUTION = 1.0
dict _LIQUID_CACHE = {}
float _CACHE_RESOLUTION = 0.01

Detailed Description

The liquid-side components: pipe, fitting, orifice, valve, check valve.

Every correlation here comes from ``fluids``, which is validated against the
books it implements -- Crane TP-410, IEC 60534, ISO 5167. This module contributes
the adapters and the bookkeeping, and deliberately nothing else. Where a number
in this package disagrees with the source, the fault is in an adapter.

The one thing worth reading before using any of these: **pressure drop is
expressed as a function of mass flow**, not the other way round. A network solve
carries flows and solves for pressures, so this is the direction that avoids an
inner root-find per component per iteration.

Function Documentation

◆ _calibrate_choke()

float feedtwin.comps.elements._calibrate_choke ( )
protected
One call to ``fluids``, cached, giving the coefficient for Cv/kPa/kg-m^3.

Definition at line 77 of file elements.py.

Referenced by feedtwin.comps.elements.Valve._legacy_liquid_ceiling().

◆ _curve_dp()

float feedtwin.comps.elements._curve_dp ( Curve curve,
float mdot )
protected
A measured curve, continued quadratically past the ends it was measured over.

:class:`MeasuredElement` raises outside its range, and for a whole component
declared ``measured`` that is right -- the run is the measurement, and there
is nothing else to fall back on.

A *segment* is different in two ways. It is one part of a run whose other
parts still have physics, so refusing the point throws away everything that
is known about the rest of the line. And a Newton iterate overshoots by its
nature: killing a transient because the solver probed 1.1x the top of a flow
bench sweep would make a measured segment worse to have than no measurement.

So it is continued, and continued *quadratically* -- ``dp ~ mdot^2`` is the
turbulent law the curve is a measurement of, so this is the shape the data
already has rather than a shape invented to fill a gap. Clamping instead
would be worse than either: a flat dp above the last point takes the flow
dependence out of the branch equation, and a branch whose loss does not
respond to its own flow makes the Jacobian singular.

Definition at line 1112 of file elements.py.

Referenced by feedtwin.comps.elements.SegmentedPipe._segment_dp(), and feedtwin.comps.elements.MeasuredElement.pressure_drop().

◆ _dynamic_head()

◆ _ideal_gamma()

float feedtwin.comps.elements._ideal_gamma ( Fluid fluid,
float T )
protected
cp/cv at 1 kPa and ``T``: the ideal-gas limit, or 0 when unpriceable.

For :mod:`feedtwin.comps.iec_gas` only (``FlowConditions.gamma_ideal``);
nothing else reads it. Cached by species and whole kelvin, because a solve
asks for the same few gas temperatures thousands of times.

Definition at line 1299 of file elements.py.

Referenced by conditions_from_fluid().

◆ _liquid_state()

tuple[float, float, float, float, float] | None feedtwin.comps.elements._liquid_state ( object fluid,
float T )
protected
``(rho, mu, gamma, p_sat, molar_mass)`` on the saturated-liquid line.

``None`` when the fluid has no liquid line at this temperature -- above the
critical point, which is where every pressurant lives -- and the caller
falls back to evaluating at ``(p, T)``.

Cached because with phase inference off these depend on **temperature
alone**: a Newton solve walks the pressures and holds the temperatures, so
a feed line's properties are constant across the entire solve and were
being recomputed a thousand times a tick. That was two thirds of the cost
of a live tick, and none of it bought a different number.

Definition at line 1333 of file elements.py.

Referenced by conditions_from_fluid().

◆ _measured()

HydraulicComponent feedtwin.comps.elements._measured ( ComponentInstance instance)
protected

Definition at line 1145 of file elements.py.

◆ _off_the_dew_point()

float feedtwin.comps.elements._off_the_dew_point ( Fluid fluid,
float p,
float T )
protected
``T``, or just above the dew point at ``p`` if ``T`` is not above it.

Re-raises the property layer's refusal when the state is not a gas at its
dew point -- a gas line below the line it cannot be helped from here.

Definition at line 1277 of file elements.py.

Referenced by conditions_from_fluid().

◆ _segmented()

HydraulicComponent feedtwin.comps.elements._segmented ( ComponentInstance instance)
protected

Definition at line 1141 of file elements.py.

◆ conditions_from_fluid()

FlowConditions feedtwin.comps.elements.conditions_from_fluid ( object fluid,
float p,
float T,
Mapping[str, float] | None signals = None,
* ,
bool multiphase = False,
str | None phase = None,
float gravity = GRAVITY )
Build :class:`FlowConditions` from a :class:`~feedtwin.props.Fluid`.

``phase`` is what the network *declares* the node to hold, and it wins over
the temperature rule below: ``"gas"`` is priced at ``(p, T)`` whatever the
temperature, ``"liquid"`` on the saturated-liquid line, ``None`` falls back
to the rule. A drawing knows which side of a tank a line is on; a
temperature does not, and an ethanol *vapour* line at 350 K is below
ethanol's critical temperature and would otherwise be priced as liquid.

The bridge between Phase 01 and Phase 03, kept as a free function so that
components never hold a fluid and stay testable with two floats.

Saturation pressure comes from the fluid where the state has one; above the
critical temperature there is no saturation line, and reporting zero there
disables the cavitation checks honestly rather than inventing a limit.

Phase, and why it is not inferred by default
-------------------------------------------
Asking the property layer for ``rho(p, T)`` lets it decide the phase, and
when the temperature reaching it is wrong that decision is *silently*
catastrophic: oxygen at the ambient default is a gas at 40 kg/m^3 where LOX
is 1140, so the leg solves at a thirtieth of the density and every number
after it stays plausible. It has happened twice here, from two different
causes, and both times it looked like a flow-rate discrepancy rather than a
property lookup.

So ``multiphase`` is **off**. With it off, a fluid that is below its
critical temperature is evaluated on its saturated-liquid line at ``T`` --
it cannot come back as a gas, whatever pressure the solve is currently
guessing. Real feed lines run subcooled and a few per cent stiffer than
saturated, which is well inside what a lumped ``K`` already assumes.

Turn it on when flashing and cavitation are the subject rather than the
hazard. It is not ready for that yet, which is the other reason it is off.

Definition at line 1169 of file elements.py.

References _ideal_gamma(), _liquid_state(), and _off_the_dew_point().

◆ cv_from_cd()

float feedtwin.comps.elements.cv_from_cd ( float cd,
float bore )
The Cv a discharge coefficient and a bore [m] amount to.

``Cv = 38.0 . Cd . A[in^2]``. A team that measured a valve's Cd rather
than its Cv gets the same element with the number they have; the rest of
the valve -- position, characteristic, choking -- is unchanged, because it
is the same physics stated the other way round.

Definition at line 740 of file elements.py.

Variable Documentation

◆ _CACHE_RESOLUTION

float feedtwin.comps.elements._CACHE_RESOLUTION = 0.01
protected

Definition at line 1330 of file elements.py.

◆ _CHOKE_COEFFICIENT

float feedtwin.comps.elements._CHOKE_COEFFICIENT = None
protected

Definition at line 74 of file elements.py.

◆ _IDEAL_GAMMA_CACHE

dict feedtwin.comps.elements._IDEAL_GAMMA_CACHE = {}
protected

Definition at line 1292 of file elements.py.

◆ _IDEAL_GAMMA_RESOLUTION

float feedtwin.comps.elements._IDEAL_GAMMA_RESOLUTION = 1.0
protected

Definition at line 1296 of file elements.py.

◆ _LIQUID_CACHE

dict feedtwin.comps.elements._LIQUID_CACHE = {}
protected

Definition at line 1323 of file elements.py.

◆ DEW_POINT_MARGIN_K

float feedtwin.comps.elements.DEW_POINT_MARGIN_K = 0.05

Definition at line 1274 of file elements.py.

◆ GPM_PER_IN2_AT_1PSI

float feedtwin.comps.elements.GPM_PER_IN2_AT_1PSI = 38.0

Definition at line 737 of file elements.py.

◆ GRAVITY

float feedtwin.comps.elements.GRAVITY = 9.80665

Definition at line 55 of file elements.py.

◆ KV_PER_CV

float feedtwin.comps.elements.KV_PER_CV = 1.0 / 1.1560992283536566

Definition at line 108 of file elements.py.

◆ SHUT_POSITION

float feedtwin.comps.elements.SHUT_POSITION = 1.0e-3

Definition at line 547 of file elements.py.

◆ XT_DEFAULT

feedtwin.comps.elements.XT_DEFAULT = XT_TYPICAL

Definition at line 112 of file elements.py.