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

Functions

dict[str, object] P (float value, str unit, str source="manufacturer")
dict[str, object] node (str nid, str ctype, str label, **object data)
dict[str, object] edge (str eid, str a, str b, **object params)
dict[str, object] minimal ()
None test_a_drawing_reads_into_typed_records ()
None test_a_parameter_with_no_provenance_is_refused ()
None test_a_line_to_nowhere_is_refused ()
None test_a_drawing_with_no_source_is_refused ()
None test_an_inline_symbol_becomes_a_branch_with_a_node_either_side ()
None test_a_tank_is_one_symbol_and_two_pressures ()
None test_a_bend_line_builds_the_geometry_aware_bend ()
None test_pressurant_lands_on_the_ullage_not_the_liquid_side ()
None test_a_transducer_is_a_label_not_plumbing ()
None test_commandable_valves_are_found ()
None test_a_manual_valve_is_turned_by_hand_never_by_the_table ()
None test_the_stand_drawing_builds_and_solves ()
None test_the_control_regulator_sets_a_setpoint_rather_than_carrying_flow ()
None test_valve_position_moves_the_flow ()
None test_every_unstated_number_is_marked_as_such ()
None test_temperature_travels_with_the_fluid ()
None test_a_tank_with_no_fluid_says_so ()
None test_a_role_without_a_fluid_is_named_as_a_role ()
None test_a_liquid_tank_solved_as_a_gas_is_reported ()
None test_a_tank_that_states_its_temperature_is_left_alone ()
None test_a_warm_pressurant_bottle_is_not_warned_about ()
object _engine (str oxidiser="oxygen", str fuel="ethanol")
dict[str, object] _two_leg_stand ()
None test_both_injector_legs_are_attached_by_fluid ()
None test_a_line_matching_neither_propellant_is_reported ()
None test_an_engine_with_no_symbol_to_land_on_says_so ()
dict _valve_with_one_side_open ()
None test_a_valve_with_one_side_open_vents_to_atmosphere ()
None test_the_inferred_vent_is_reported ()
None test_a_valve_plumbed_both_ends_is_not_a_vent ()
None test_a_spare_manifold_port_is_a_plug_not_a_vent ()
None test_a_transducer_can_tap_the_downstream_side_of_a_valve ()
None test_upstream_is_still_the_default ()
None test_thermocouples_and_rtds_are_instruments_like_any_other ()
None test_ullage_side_nodes_are_declared_gas_and_the_outlet_liquid ()
None test_a_declared_gas_is_priced_as_gas_below_its_critical_temperature ()
None test_static_head_comes_from_the_tanks_own_geometry ()

Variables

float PSI = 6894.757293168361
dict FIRING
tuple STAND
 needs_stand = pytest.mark.skipif(not STAND.exists(), reason="stand drawing absent")
dict LINE

Detailed Description

Phase 11: reading a drawing and building a network from it.

The two graphs are not the same shape, and every test here is about a place
where a naive relabelling would go wrong: an inline symbol that has to become a
branch, a tank that is one symbol and two pressures, a transducer that is a
label rather than plumbing, and a control regulator that sets a setpoint rather
than carrying flow.

Function Documentation

◆ _engine()

object test_pid._engine ( str oxidiser = "oxygen",
str fuel = "ethanol" )
protected

◆ _two_leg_stand()

dict[str, object] test_pid._two_leg_stand ( )
protected
Two tanks into one engine -- the smallest thing an engine can sit on.

Definition at line 416 of file test_pid.py.

References edge(), and P().

Referenced by test_a_line_matching_neither_propellant_is_reported(), and test_both_injector_legs_are_attached_by_fluid().

◆ _valve_with_one_side_open()

dict test_pid._valve_with_one_side_open ( )
protected
The drawing pid-designer tells you to make for a vent.

Its `components/pid/vents.ts` says so outright: "A valve open on one side is
a vent to atmosphere. Not a symbol you place." It draws the arrow and passes
its own checks on that basis -- but the inference feeds the arrow and the
checks panel, not the export, so this arrived here as a valve with a dead end
behind it and the network would not solve.

Definition at line 479 of file test_pid.py.

References p.

Referenced by test_a_spare_manifold_port_is_a_plug_not_a_vent(), test_a_valve_plumbed_both_ends_is_not_a_vent(), test_a_valve_with_one_side_open_vents_to_atmosphere(), and test_the_inferred_vent_is_reported().

◆ edge()

dict[str, object] test_pid.edge ( str eid,
str a,
str b,
**object params )

Definition at line 65 of file test_pid.py.

Referenced by _two_leg_stand(), minimal(), and test_a_line_to_nowhere_is_refused().

◆ minimal()

◆ node()

dict[str, object] test_pid.node ( str nid,
str ctype,
str label,
**object data )

Definition at line 57 of file test_pid.py.

◆ P()

dict[str, object] test_pid.P ( float value,
str unit,
str source = "manufacturer" )

◆ test_a_bend_line_builds_the_geometry_aware_bend()

None test_pid.test_a_bend_line_builds_the_geometry_aware_bend ( )
``lineType: bend`` is the hardline Bend, whose only correlation model is
``rounded``. It used to ask for a ``darcy`` bend, which has no builder, so
the drawing could not be built at all.

Definition at line 194 of file test_pid.py.

References minimal(), and P().

◆ test_a_declared_gas_is_priced_as_gas_below_its_critical_temperature()

None test_pid.test_a_declared_gas_is_priced_as_gas_below_its_critical_temperature ( )
Ethanol vapour at 400 K and 1 bar -- well above its 351 K boiling point
and well below its 514 K critical temperature. Undeclared it is priced as
liquid ethanol at ~700 kg/m^3; declared gas, at (p, T) it is ~1.4.

Definition at line 747 of file test_pid.py.

◆ test_a_drawing_reads_into_typed_records()

None test_pid.test_a_drawing_reads_into_typed_records ( )

Definition at line 118 of file test_pid.py.

References minimal().

◆ test_a_drawing_with_no_source_is_refused()

None test_pid.test_a_drawing_with_no_source_is_refused ( )
A drawing missing its tank solves as an empty system and reports zero
flow, which looks like an answer.

Definition at line 147 of file test_pid.py.

References minimal().

◆ test_a_line_matching_neither_propellant_is_reported()

None test_pid.test_a_line_matching_neither_propellant_is_reported ( )
It used to be skipped in silence, which left the engine with one leg and
a mixture ratio taken against a zero -- and every number after it looked
perfectly ordinary.

Definition at line 455 of file test_pid.py.

References _engine(), and _two_leg_stand().

◆ test_a_line_to_nowhere_is_refused()

None test_pid.test_a_line_to_nowhere_is_refused ( )

Definition at line 140 of file test_pid.py.

References edge(), and minimal().

◆ test_a_liquid_tank_solved_as_a_gas_is_reported()

None test_pid.test_a_liquid_tank_solved_as_a_gas_is_reported ( )
The expensive one. A tank named for a cryogen, holding its species, at
the ambient default: oxygen is then ~40 kg/m^3 where LOX is 1140, so every
density and flow on that leg is out by thirty and the solve still
converges on plausible-looking numbers.

Definition at line 369 of file test_pid.py.

References minimal().

◆ test_a_manual_valve_is_turned_by_hand_never_by_the_table()

None test_pid.test_a_manual_valve_is_turned_by_hand_never_by_the_table ( )
A hand valve is not something a state machine can command: it is turned
on the P&ID, and the binding never offers it to an actuator. Plumbed both
sides or not, it rests shut until a hand opens it.

Definition at line 229 of file test_pid.py.

References minimal().

◆ test_a_parameter_with_no_provenance_is_refused()

None test_pid.test_a_parameter_with_no_provenance_is_refused ( )
The drawing always asks for a source, so a missing one is a format
mismatch -- and calling it a default would turn that into a number nobody
checked.

Definition at line 130 of file test_pid.py.

References minimal().

◆ test_a_role_without_a_fluid_is_named_as_a_role()

None test_pid.test_a_role_without_a_fluid_is_named_as_a_role ( )
pid-designer colours a symbol by role -- fuel, lox, pressurant. That is
not a species, and the difference is worth spelling out rather than letting
somebody wonder why the colour they set had no effect.

Definition at line 356 of file test_pid.py.

References minimal().

◆ test_a_spare_manifold_port_is_a_plug_not_a_vent()

None test_pid.test_a_spare_manifold_port_is_a_plug_not_a_vent ( )
The rule is valves only, for pid-designer's stated reason: a blanked tee
branch or spare manifold port is a plug, and plugs are not drawn.

Definition at line 626 of file test_pid.py.

References _valve_with_one_side_open().

◆ test_a_tank_is_one_symbol_and_two_pressures()

None test_pid.test_a_tank_is_one_symbol_and_two_pressures ( )
Pressurant arrives at the top and propellant leaves the bottom.

Definition at line 179 of file test_pid.py.

References minimal().

◆ test_a_tank_that_states_its_temperature_is_left_alone()

None test_pid.test_a_tank_that_states_its_temperature_is_left_alone ( )
LOX at 90 K is exactly right, and a warning here would train people to
ignore the one above.

Definition at line 385 of file test_pid.py.

References minimal().

◆ test_a_tank_with_no_fluid_says_so()

None test_pid.test_a_tank_with_no_fluid_says_so ( )
Downstream of a tank is a whole propellant leg. Defaulting it silently
reprices every line on that side, and nothing in the answer looks wrong.

Definition at line 344 of file test_pid.py.

References minimal().

◆ test_a_transducer_can_tap_the_downstream_side_of_a_valve()

None test_pid.test_a_transducer_can_tap_the_downstream_side_of_a_valve ( )
A main valve's downstream PT is the pressure that sets injector delta-p.

Instruments resolve to a symbol's *upstream* node by default, which is right
for most taps and cannot express this one. Without `side: downstream` the
only clip that resolved past a main valve was the ENGINE symbol -- a fixed
boundary at the chamber -- so the gauge sat at design chamber pressure
forever, including on a cold stand with every valve shut.

Definition at line 671 of file test_pid.py.

◆ test_a_transducer_is_a_label_not_plumbing()

None test_pid.test_a_transducer_is_a_label_not_plumbing ( )
Making one a node puts a fictitious branch in every mass balance.

Definition at line 214 of file test_pid.py.

References minimal().

◆ test_a_valve_plumbed_both_ends_is_not_a_vent()

None test_pid.test_a_valve_plumbed_both_ends_is_not_a_vent ( )

Definition at line 617 of file test_pid.py.

References _valve_with_one_side_open().

◆ test_a_valve_with_one_side_open_vents_to_atmosphere()

None test_pid.test_a_valve_with_one_side_open_vents_to_atmosphere ( )

Definition at line 603 of file test_pid.py.

References _valve_with_one_side_open().

◆ test_a_warm_pressurant_bottle_is_not_warned_about()

None test_pid.test_a_warm_pressurant_bottle_is_not_warned_about ( )
Nitrogen at ambient is a gas because it is supposed to be. The check is
for tanks, and a K-bottle is not one.

Definition at line 393 of file test_pid.py.

References minimal().

◆ test_an_engine_with_no_symbol_to_land_on_says_so()

None test_pid.test_an_engine_with_no_symbol_to_land_on_says_so ( )
Attaching a config to a drawing that has no engine leaves the run
uncoupled. Reported, because 'coupled' is a claim about the physics.

Definition at line 471 of file test_pid.py.

References _engine(), and minimal().

◆ test_an_inline_symbol_becomes_a_branch_with_a_node_either_side()

None test_pid.test_an_inline_symbol_becomes_a_branch_with_a_node_either_side ( )
The case that matters. A drawing with six valves that solves as a
drawing with none converges beautifully and means nothing.

Definition at line 167 of file test_pid.py.

References minimal().

◆ test_both_injector_legs_are_attached_by_fluid()

None test_pid.test_both_injector_legs_are_attached_by_fluid ( )

Definition at line 448 of file test_pid.py.

References _engine(), and _two_leg_stand().

◆ test_commandable_valves_are_found()

None test_pid.test_commandable_valves_are_found ( )

Definition at line 222 of file test_pid.py.

References minimal().

◆ test_every_unstated_number_is_marked_as_such()

None test_pid.test_every_unstated_number_is_marked_as_such ( )
A drawing that omits a bore should produce an answer with a visible hole
in it, not a confident one.

Definition at line 293 of file test_pid.py.

◆ test_pressurant_lands_on_the_ullage_not_the_liquid_side()

None test_pid.test_pressurant_lands_on_the_ullage_not_the_liquid_side ( )

Definition at line 209 of file test_pid.py.

References minimal().

◆ test_static_head_comes_from_the_tanks_own_geometry()

None test_pid.test_static_head_comes_from_the_tanks_own_geometry ( )
rho g h with h from the drawn volume and bore at the stated fill --
not a bare 0.75 on an assumed 152 mm bore, which is what this was.

Definition at line 763 of file test_pid.py.

References minimal().

◆ test_temperature_travels_with_the_fluid()

None test_pid.test_temperature_travels_with_the_fluid ( )
The bug this test exists for was worth 25x in density.

A feed line downstream of a LOX tank carries oxygen at 90 K. Inherit the
species and leave the temperature at an ambient default and the line solves
as *gaseous* oxygen at 46 kg/m^3 instead of liquid at 1140 -- so the flow
comes out confidently wrong rather than obviously so, and the oxidiser leg
of a bigger line reads as flowing less than the fuel leg of a smaller one.

Definition at line 309 of file test_pid.py.

◆ test_the_control_regulator_sets_a_setpoint_rather_than_carrying_flow()

None test_pid.test_the_control_regulator_sets_a_setpoint_rather_than_carrying_flow ( )
A dome line carries almost nothing; what it carries is a number.

Definition at line 268 of file test_pid.py.

◆ test_the_inferred_vent_is_reported()

None test_pid.test_the_inferred_vent_is_reported ( )
Inferring a boundary is a real modelling decision, so it is said aloud.

Definition at line 611 of file test_pid.py.

References _valve_with_one_side_open().

◆ test_the_stand_drawing_builds_and_solves()

None test_pid.test_the_stand_drawing_builds_and_solves ( )

Definition at line 243 of file test_pid.py.

◆ test_thermocouples_and_rtds_are_instruments_like_any_other()

None test_pid.test_thermocouples_and_rtds_are_instruments_like_any_other ( )
A TC clips to a node and reads it, the same way a transducer does.

Definition at line 708 of file test_pid.py.

◆ test_ullage_side_nodes_are_declared_gas_and_the_outlet_liquid()

None test_pid.test_ullage_side_nodes_are_declared_gas_and_the_outlet_liquid ( )
The property layer's fallback -- below the critical temperature means
liquid -- is right for LOX and wrong for a vapour line. Only the drawing
knows which side of the tank a line is on, so the drawing says.

Definition at line 722 of file test_pid.py.

◆ test_upstream_is_still_the_default()

None test_pid.test_upstream_is_still_the_default ( )
The option must not change where an unmarked instrument reads.

Every instrument, not just the transducers. This stripped `PT` alone and
then asserted over the whole list, so the first thermocouple to ask for a
downstream node failed a test about transducers.

Definition at line 689 of file test_pid.py.

◆ test_valve_position_moves_the_flow()

None test_pid.test_valve_position_moves_the_flow ( )

Definition at line 277 of file test_pid.py.

Variable Documentation

◆ FIRING

dict test_pid.FIRING
Initial value:
1= {
2 "MV-OX.command": 1.0,
3 "MV-FU.command": 1.0,
4 "SV-LOX-PRESS.command": 1.0,
5 "SV-FUEL-PRESS.command": 1.0,
6 "SV-LOX-VENT.command": 0.0,
7 "SV-FUEL-VENT.command": 0.0,
8 "SV-GN2-VENT.command": 0.0,
9 "SV-LOX-FILL.command": 0.0,
10}

Definition at line 33 of file test_pid.py.

◆ LINE

dict test_pid.LINE
Initial value:
1= {
2 "length": P(1.0, "m"),
3 "bore": P(9.5, "mm"),
4 "roughness": P(0.0015, "mm"),
5}

Definition at line 74 of file test_pid.py.

◆ needs_stand

test_pid.needs_stand = pytest.mark.skipif(not STAND.exists(), reason="stand drawing absent")

Definition at line 50 of file test_pid.py.

◆ PSI

float test_pid.PSI = 6894.757293168361

Definition at line 26 of file test_pid.py.

◆ STAND

tuple test_pid.STAND
Initial value:
1= (
2 Path(__file__).resolve().parents[3]
3 / "feed-twin"
4 / "backend"
5 / "diagrams"
6 / "ethalox_stand.json"
7)

Definition at line 43 of file test_pid.py.