from __future__ import annotations from dataclasses import dataclass from typing import Callable from PythonModels.components.amesim_pneumatic import ( AmesimPneumaticGas, AmesimPneumaticOrifice, AmesimPneumaticVolume, ) from PythonModels.components.amesim_pneumatic_line import ( AmesimPnl0001Pipe, AmesimPnl0002Pipe, AmesimPnl0003Pipe, AmesimPnl00rPipe, ) from PythonModels.core.medium import ThermodynamicProperties from PythonModels.core.ports import PortState from PythonModels.core.state import VolumeState from PythonModels.systems.test_mql_nodes import ( TestMqlPneumaticNode3, TestMqlPneumaticNode3Balance, TestMqlPneumaticNode4, TestMqlPneumaticNode4Balance, ) @dataclass(frozen=True) class TestMqlPneumaticBranchSpec: name: str upstream_volume_alias: str orifice_alias: str downstream_volume_alias: str source: str = "manual" @dataclass(frozen=True) class TestMqlPneumaticTopologyCandidate: connection_alias: str line_submodel: str source_component: str source_port: str target_component: str target_port: str source_is_typed_pneumatic: bool target_is_typed_pneumatic: bool category: str reason: str @dataclass(frozen=True) class TestMqlPneumaticChamberSegmentSpec: name: str inlet_node_alias: str inlet_line_alias: str inlet_orifice_alias: str inlet_orifice_boundary_port: str inlet_orifice_volume_port: str volume_alias: str volume_inlet_port: str volume_outlet_port: str outlet_orifice_alias: str outlet_orifice_volume_port: str outlet_orifice_boundary_port: str outlet_line_alias: str outlet_node_alias: str source: str = "amesim-cir-topology" @dataclass(frozen=True) class TestMqlPneumaticTopologyDiscovery: branch_specs: tuple[TestMqlPneumaticBranchSpec, ...] chamber_segment_specs: tuple[TestMqlPneumaticChamberSegmentSpec, ...] blocked_candidates: tuple[TestMqlPneumaticTopologyCandidate, ...] @dataclass(frozen=True) class TestMqlPneumaticBoundaryCondition: pressure_pa: float temperature_k: float def properties(self, gas: AmesimPneumaticGas) -> ThermodynamicProperties: if self.pressure_pa <= 0.0: raise ValueError("boundary pressure must be positive") if self.temperature_k <= 0.0: raise ValueError("boundary temperature must be positive") return ThermodynamicProperties( p=self.pressure_pa, T=self.temperature_k, rho=gas.density(self.pressure_pa, self.temperature_k), u=gas.specific_internal_energy(self.temperature_k), h=gas.specific_enthalpy(self.temperature_k), ) @dataclass(frozen=True) class TestMqlPneumaticChamberSegmentComponents: volume: AmesimPneumaticVolume inlet_orifice: AmesimPneumaticOrifice outlet_orifice: AmesimPneumaticOrifice spec: TestMqlPneumaticChamberSegmentSpec @dataclass(frozen=True) class TestMqlPneumaticChamberSegmentSnapshot: chamber: ThermodynamicProperties inlet_boundary: ThermodynamicProperties outlet_boundary: ThermodynamicProperties inlet_flow: float outlet_flow: float @dataclass(frozen=True) class TestMqlPnl0001ChamberSegmentComponents: inlet_line: AmesimPnl0001Pipe volume: AmesimPneumaticVolume inlet_orifice: AmesimPneumaticOrifice outlet_orifice: AmesimPneumaticOrifice spec: TestMqlPneumaticChamberSegmentSpec @dataclass(frozen=True) class TestMqlPnl0001ChamberSegmentSnapshot: inlet_line: ThermodynamicProperties chamber: ThermodynamicProperties inlet_node: ThermodynamicProperties outlet_boundary: ThermodynamicProperties node_to_line_flow: float line_to_chamber_flow: float outlet_flow: float @dataclass(frozen=True) class TestMqlPnl0001PairChamberSegmentComponents: inlet_line: AmesimPnl0001Pipe outlet_line: AmesimPnl0001Pipe volume: AmesimPneumaticVolume inlet_orifice: AmesimPneumaticOrifice outlet_orifice: AmesimPneumaticOrifice spec: TestMqlPneumaticChamberSegmentSpec @dataclass(frozen=True) class TestMqlPnl0001PairChamberSegmentSnapshot: inlet_line: ThermodynamicProperties chamber: ThermodynamicProperties outlet_line: ThermodynamicProperties inlet_node: ThermodynamicProperties outlet_node: ThermodynamicProperties inlet_node_to_line_flow: float inlet_line_to_chamber_flow: float outlet_node_to_line_flow: float outlet_line_to_chamber_flow: float @dataclass(frozen=True) class TestMqlPn3NodeChamberSegmentComponents: inlet_line: AmesimPnl0001Pipe outlet_line: AmesimPnl0001Pipe node_line: AmesimPnl0003Pipe node_resistance: AmesimPnl00rPipe node_orifice: AmesimPneumaticOrifice node: TestMqlPneumaticNode3 volume: AmesimPneumaticVolume inlet_orifice: AmesimPneumaticOrifice outlet_orifice: AmesimPneumaticOrifice spec: TestMqlPneumaticChamberSegmentSpec @dataclass(frozen=True) class TestMqlPn3NodeChamberSegmentSnapshot: inlet_line: ThermodynamicProperties chamber: ThermodynamicProperties outlet_line: ThermodynamicProperties node_line_port_1: ThermodynamicProperties node_line_port_2: ThermodynamicProperties inlet_node: ThermodynamicProperties resistance_boundary: ThermodynamicProperties p4_boundary: ThermodynamicProperties node_balance: TestMqlPneumaticNode3Balance inlet_node_to_line_flow: float inlet_line_to_chamber_flow: float outlet_node_to_line_flow: float outlet_line_to_chamber_flow: float node_to_resistance_flow: float node_to_pnl0003_flow: float pnl0003_center_flow: float pnl0003_to_p4_flow: float @dataclass(frozen=True) class TestMqlPn3P4NodeChamberSegmentComponents: inlet_line: AmesimPnl0001Pipe outlet_line: AmesimPnl0001Pipe node_line: AmesimPnl0003Pipe node_resistance: AmesimPnl00rPipe node_orifice: AmesimPneumaticOrifice node: TestMqlPneumaticNode3 p4_node: TestMqlPneumaticNode4 p4_primary_line: AmesimPnl0001Pipe p4_primary_chamber: AmesimPneumaticVolume p4_port1_line: AmesimPnl0002Pipe p4_port1_remote_node: TestMqlPneumaticNode4 p4_port1_remote_primary_line: AmesimPnl0001Pipe p4_port1_remote_primary_chamber: AmesimPneumaticVolume p4_port1_remote_port1_line: AmesimPnl0002Pipe p4_port1_far_node: TestMqlPneumaticNode4 p4_port1_far_primary_line: AmesimPnl0001Pipe p4_port1_far_primary_chamber: AmesimPneumaticVolume p4_port1_far_port1_line: AmesimPnl0002Pipe p4_port1_next_node: TestMqlPneumaticNode4 p4_port1_next_primary_line: AmesimPnl0001Pipe p4_port1_next_primary_chamber: AmesimPneumaticVolume p4_port1_remote_orifice: AmesimPneumaticOrifice p4_port1_remote_orifice_line: AmesimPnl0003Pipe p4_port1_remote_orifice_node: TestMqlPneumaticNode3 p4_port3_line: AmesimPnl0002Pipe p4_port3_remote_node: TestMqlPneumaticNode4 p4_port3_remote_primary_line: AmesimPnl0001Pipe p4_port3_remote_primary_chamber: AmesimPneumaticVolume p4_port3_remote_port3_line: AmesimPnl0002Pipe p4_port3_far_node: TestMqlPneumaticNode4 p4_port3_far_primary_line: AmesimPnl0001Pipe p4_port3_far_primary_chamber: AmesimPneumaticVolume p4_port3_far_port3_line: AmesimPnl0002Pipe p4_port3_next_node: TestMqlPneumaticNode4 p4_port3_next_primary_line: AmesimPnl0001Pipe p4_port3_next_primary_chamber: AmesimPneumaticVolume p4_port3_remote_orifice: AmesimPneumaticOrifice p4_port3_remote_orifice_line: AmesimPnl0003Pipe p4_port3_remote_orifice_node: TestMqlPneumaticNode3 p4_port3_remote_orifice_resistance: AmesimPnl00rPipe p4_port3_remote_resistance_node: TestMqlPneumaticNode3 p4_port3_remote_resistance_node_line: AmesimPnl0003Pipe p4_port3_remote_resistance_orifice: AmesimPneumaticOrifice volume: AmesimPneumaticVolume inlet_orifice: AmesimPneumaticOrifice outlet_orifice: AmesimPneumaticOrifice spec: TestMqlPneumaticChamberSegmentSpec @dataclass(frozen=True) class TestMqlPn3P4NodeChamberSegmentSnapshot: inlet_line: ThermodynamicProperties chamber: ThermodynamicProperties outlet_line: ThermodynamicProperties node_line_port_1: ThermodynamicProperties node_line_port_2: ThermodynamicProperties p4_primary_line: ThermodynamicProperties p4_boundary: ThermodynamicProperties p4_primary_chamber: ThermodynamicProperties p4_port1_line: ThermodynamicProperties p4_port1_remote_primary_line: ThermodynamicProperties p4_port1_remote_primary_chamber: ThermodynamicProperties p4_port1_remote_port1_line: ThermodynamicProperties p4_port1_far_primary_line: ThermodynamicProperties p4_port1_far_primary_chamber: ThermodynamicProperties p4_port1_far_port1_line: ThermodynamicProperties p4_port1_next_primary_line: ThermodynamicProperties p4_port1_next_primary_chamber: ThermodynamicProperties p4_port1_remote_orifice_line_port_1: ThermodynamicProperties p4_port1_remote_orifice_line_port_2: ThermodynamicProperties p4_port3_line: ThermodynamicProperties p4_port3_remote_primary_line: ThermodynamicProperties p4_port3_remote_primary_chamber: ThermodynamicProperties p4_port3_remote_port3_line: ThermodynamicProperties p4_port3_far_primary_line: ThermodynamicProperties p4_port3_far_primary_chamber: ThermodynamicProperties p4_port3_far_port3_line: ThermodynamicProperties p4_port3_next_primary_line: ThermodynamicProperties p4_port3_next_primary_chamber: ThermodynamicProperties p4_port3_remote_orifice_line_port_1: ThermodynamicProperties p4_port3_remote_orifice_line_port_2: ThermodynamicProperties p4_port3_remote_resistance_node_line_port_1: ThermodynamicProperties p4_port3_remote_resistance_node_line_port_2: ThermodynamicProperties inlet_node: ThermodynamicProperties resistance_boundary: ThermodynamicProperties node_balance: TestMqlPneumaticNode3Balance p4_balance: TestMqlPneumaticNode4Balance p4_port1_remote_balance: TestMqlPneumaticNode4Balance p4_port1_far_balance: TestMqlPneumaticNode4Balance p4_port1_next_balance: TestMqlPneumaticNode4Balance p4_port1_remote_orifice_node_balance: TestMqlPneumaticNode3Balance p4_port3_remote_balance: TestMqlPneumaticNode4Balance p4_port3_far_balance: TestMqlPneumaticNode4Balance p4_port3_next_balance: TestMqlPneumaticNode4Balance p4_port3_remote_orifice_node_balance: TestMqlPneumaticNode3Balance p4_port3_remote_resistance_node_balance: TestMqlPneumaticNode3Balance inlet_node_to_line_flow: float inlet_line_to_chamber_flow: float outlet_node_to_line_flow: float outlet_line_to_chamber_flow: float node_to_resistance_flow: float node_to_pnl0003_flow: float pnl0003_center_flow: float pnl0003_to_p4_flow: float p4_primary_chamber_to_line_flow: float p4_node_to_primary_line_flow: float p4_to_port1_line_flow: float p4_port1_remote_node_to_line_flow: float p4_port1_remote_chamber_to_line_flow: float p4_port1_remote_node_to_primary_line_flow: float p4_port1_remote_to_port1_line_flow: float p4_port1_far_node_to_line_flow: float p4_port1_far_chamber_to_line_flow: float p4_port1_far_node_to_primary_line_flow: float p4_port1_far_to_next_line_flow: float p4_port1_next_node_to_line_flow: float p4_port1_next_chamber_to_line_flow: float p4_port1_next_node_to_primary_line_flow: float p4_port1_remote_node_to_orifice_line_flow: float p4_port1_remote_orifice_line_center_flow: float p4_port1_remote_orifice_to_node_flow: float p4_to_port3_line_flow: float p4_port3_remote_node_to_line_flow: float p4_port3_remote_chamber_to_line_flow: float p4_port3_remote_node_to_primary_line_flow: float p4_port3_remote_to_port3_line_flow: float p4_port3_far_node_to_line_flow: float p4_port3_far_chamber_to_line_flow: float p4_port3_far_node_to_primary_line_flow: float p4_port3_far_to_next_line_flow: float p4_port3_next_node_to_line_flow: float p4_port3_next_chamber_to_line_flow: float p4_port3_next_node_to_primary_line_flow: float p4_port3_remote_node_to_orifice_line_flow: float p4_port3_remote_node_to_resistance_flow: float p4_port3_remote_resistance_node_to_line_flow: float p4_port3_remote_resistance_line_center_flow: float p4_port3_remote_resistance_to_p4_flow: float p4_port3_remote_orifice_line_center_flow: float p4_port3_remote_orifice_to_node_flow: float class TestMqlPn3P4NodeChamberSegmentClosure: """PN3 chamber segment closed through the adjacent real P4 node. The P4 primary pressure/temperature comes from the PNL0001 storage on ``port_2``. P4 ports 1 and 3 are represented by the adjacent PNL0002 center compliances; their far nodes remain prescribed pressure boundaries. """ def __init__( self, *, components: TestMqlPn3P4NodeChamberSegmentComponents, inlet_node: TestMqlPneumaticBoundaryCondition, resistance_boundary: TestMqlPneumaticBoundaryCondition, ) -> None: self.components = components self.inlet_node = inlet_node self.resistance_boundary = resistance_boundary def initial_state_vector(self) -> list[float]: return [ *self.components.inlet_line.get_state_vector(), *self.components.volume.get_state_vector(), *self.components.outlet_line.get_state_vector(), *self.components.node_line.get_state_vector(), *self.components.p4_primary_line.get_state_vector(), *self.components.p4_primary_chamber.get_state_vector(), *self.components.p4_port1_line.get_state_vector(), *self.components.p4_port1_remote_primary_line.get_state_vector(), *self.components.p4_port1_remote_primary_chamber.get_state_vector(), *self.components.p4_port1_remote_port1_line.get_state_vector(), *self.components.p4_port1_far_primary_line.get_state_vector(), *self.components.p4_port1_far_primary_chamber.get_state_vector(), *self.components.p4_port1_far_port1_line.get_state_vector(), *self.components.p4_port1_next_primary_line.get_state_vector(), *self.components.p4_port1_next_primary_chamber.get_state_vector(), *self.components.p4_port1_remote_orifice_line.get_state_vector(), *self.components.p4_port3_line.get_state_vector(), *self.components.p4_port3_remote_primary_line.get_state_vector(), *self.components.p4_port3_remote_primary_chamber.get_state_vector(), *self.components.p4_port3_remote_port3_line.get_state_vector(), *self.components.p4_port3_far_primary_line.get_state_vector(), *self.components.p4_port3_far_primary_chamber.get_state_vector(), *self.components.p4_port3_far_port3_line.get_state_vector(), *self.components.p4_port3_next_primary_line.get_state_vector(), *self.components.p4_port3_next_primary_chamber.get_state_vector(), *self.components.p4_port3_remote_resistance_node_line.get_state_vector(), *self.components.p4_port3_remote_orifice_line.get_state_vector(), ] def apply_state_vector(self, values: list[float]) -> None: if len(values) != 62: raise ValueError("PN3/P4 node chamber segment state vector requires sixty-two values") self.components.inlet_line.set_state_vector(values[:2]) self.components.volume.set_state_vector(values[2:4]) self.components.outlet_line.set_state_vector(values[4:6]) self.components.node_line.set_state_vector(values[6:10]) self.components.p4_primary_line.set_state_vector(values[10:12]) self.components.p4_primary_chamber.set_state_vector(values[12:14]) self.components.p4_port1_line.set_state_vector(values[14:16]) self.components.p4_port1_remote_primary_line.set_state_vector(values[16:18]) self.components.p4_port1_remote_primary_chamber.set_state_vector(values[18:20]) self.components.p4_port1_remote_port1_line.set_state_vector(values[20:22]) self.components.p4_port1_far_primary_line.set_state_vector(values[22:24]) self.components.p4_port1_far_primary_chamber.set_state_vector(values[24:26]) self.components.p4_port1_far_port1_line.set_state_vector(values[26:28]) self.components.p4_port1_next_primary_line.set_state_vector(values[28:30]) self.components.p4_port1_next_primary_chamber.set_state_vector(values[30:32]) self.components.p4_port1_remote_orifice_line.set_state_vector(values[32:36]) self.components.p4_port3_line.set_state_vector(values[36:38]) self.components.p4_port3_remote_primary_line.set_state_vector(values[38:40]) self.components.p4_port3_remote_primary_chamber.set_state_vector(values[40:42]) self.components.p4_port3_remote_port3_line.set_state_vector(values[42:44]) self.components.p4_port3_far_primary_line.set_state_vector(values[44:46]) self.components.p4_port3_far_primary_chamber.set_state_vector(values[46:48]) self.components.p4_port3_far_port3_line.set_state_vector(values[48:50]) self.components.p4_port3_next_primary_line.set_state_vector(values[50:52]) self.components.p4_port3_next_primary_chamber.set_state_vector(values[52:54]) self.components.p4_port3_remote_resistance_node_line.set_state_vector(values[54:58]) self.components.p4_port3_remote_orifice_line.set_state_vector(values[58:]) def snapshot( self, state_vector: list[float] | None = None, ) -> TestMqlPn3P4NodeChamberSegmentSnapshot: if state_vector is not None: self.apply_state_vector(state_vector) inlet_line = self.components.inlet_line.properties() chamber = self.components.volume.properties() outlet_line = self.components.outlet_line.properties() node_line_port_1 = self.components.node_line.properties_1() node_line_port_2 = self.components.node_line.properties_2() p4_primary_line = self.components.p4_primary_line.properties() p4_primary_chamber = self.components.p4_primary_chamber.properties() p4_port1_line = self.components.p4_port1_line.properties() p4_port1_remote_primary_line = ( self.components.p4_port1_remote_primary_line.properties() ) p4_port1_remote_primary_chamber = ( self.components.p4_port1_remote_primary_chamber.properties() ) p4_port1_remote_port1_line = ( self.components.p4_port1_remote_port1_line.properties() ) p4_port1_far_primary_line = self.components.p4_port1_far_primary_line.properties() p4_port1_far_primary_chamber = ( self.components.p4_port1_far_primary_chamber.properties() ) p4_port1_far_port1_line = self.components.p4_port1_far_port1_line.properties() p4_port1_next_primary_line = self.components.p4_port1_next_primary_line.properties() p4_port1_next_primary_chamber = ( self.components.p4_port1_next_primary_chamber.properties() ) p4_port1_remote_orifice_line_port_1 = ( self.components.p4_port1_remote_orifice_line.properties_1() ) p4_port1_remote_orifice_line_port_2 = ( self.components.p4_port1_remote_orifice_line.properties_2() ) p4_port3_line = self.components.p4_port3_line.properties() p4_port3_remote_primary_line = ( self.components.p4_port3_remote_primary_line.properties() ) p4_port3_remote_primary_chamber = ( self.components.p4_port3_remote_primary_chamber.properties() ) p4_port3_remote_port3_line = ( self.components.p4_port3_remote_port3_line.properties() ) p4_port3_far_primary_line = self.components.p4_port3_far_primary_line.properties() p4_port3_far_primary_chamber = ( self.components.p4_port3_far_primary_chamber.properties() ) p4_port3_far_port3_line = self.components.p4_port3_far_port3_line.properties() p4_port3_next_primary_line = self.components.p4_port3_next_primary_line.properties() p4_port3_next_primary_chamber = ( self.components.p4_port3_next_primary_chamber.properties() ) p4_port3_remote_orifice_line_port_1 = ( self.components.p4_port3_remote_orifice_line.properties_1() ) p4_port3_remote_orifice_line_port_2 = ( self.components.p4_port3_remote_orifice_line.properties_2() ) p4_port3_remote_resistance_node_line_port_1 = ( self.components.p4_port3_remote_resistance_node_line.properties_1() ) p4_port3_remote_resistance_node_line_port_2 = ( self.components.p4_port3_remote_resistance_node_line.properties_2() ) inlet_node = self.inlet_node.properties(self.components.inlet_line.gas) resistance_boundary = self.resistance_boundary.properties( self.components.node_resistance.gas ) inlet_node_to_line_flow = self.components.inlet_line.resistance_mass_flow( port_1_pressure_pa=p4_port3_remote_orifice_line_port_1.p, port_1_temperature_k=p4_port3_remote_orifice_line_port_1.T, ) outlet_node_to_line_flow = self.components.outlet_line.resistance_mass_flow( port_1_pressure_pa=node_line_port_1.p, port_1_temperature_k=node_line_port_1.T, ) inlet_line_to_chamber_flow = self._line_to_chamber_flow( line=inlet_line, chamber=chamber, orifice=self.components.inlet_orifice, ) outlet_line_to_chamber_flow = self._line_to_chamber_flow( line=outlet_line, chamber=chamber, orifice=self.components.outlet_orifice, ) node_to_resistance_flow = self.components.node_resistance.mass_flow( port_1_pressure_pa=node_line_port_1.p, port_1_temperature_k=node_line_port_1.T, port_2_pressure_pa=p4_port1_remote_orifice_line_port_1.p, port_2_temperature_k=p4_port1_remote_orifice_line_port_1.T, ) node_balance = self.components.node.balance( port_2_temperature_k=node_line_port_1.T, port_2_pressure_pa=node_line_port_1.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=node_to_resistance_flow, node_h=node_line_port_1.h, connected_h=p4_port1_remote_orifice_line_port_1.h, ), port_1_mass_flow_g_s=node_to_resistance_flow * 1.0e3, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=outlet_node_to_line_flow, node_h=node_line_port_1.h, connected_h=outlet_line.h, ), port_3_mass_flow_g_s=outlet_node_to_line_flow * 1.0e3, ) node_to_pnl0003_flow = -node_balance.port_2_mass_flow_g_s * 1.0e-3 pnl0003_center_flow = self.components.node_line.resistance_mass_flow() pnl0003_to_p4_flow = self._line_to_p4_flow( line=node_line_port_2, p4_boundary=p4_primary_line, orifice=self.components.node_orifice, ) p4_primary_chamber_to_line_flow = ( self.components.p4_primary_line.resistance_mass_flow( port_1_pressure_pa=p4_primary_chamber.p, port_1_temperature_k=p4_primary_chamber.T, ) ) p4_to_port1_line_flow = self.components.p4_port1_line.port_mass_flow( port_pressure_pa=p4_primary_line.p, port_temperature_k=p4_primary_line.T, ) p4_port1_remote_node_to_line_flow = ( self.components.p4_port1_line.port_mass_flow( port_pressure_pa=p4_port1_remote_primary_line.p, port_temperature_k=p4_port1_remote_primary_line.T, ) ) p4_port1_remote_chamber_to_line_flow = ( self.components.p4_port1_remote_primary_line.resistance_mass_flow( port_1_pressure_pa=p4_port1_remote_primary_chamber.p, port_1_temperature_k=p4_port1_remote_primary_chamber.T, ) ) p4_port1_remote_to_port1_line_flow = ( self.components.p4_port1_remote_port1_line.port_mass_flow( port_pressure_pa=p4_port1_remote_primary_line.p, port_temperature_k=p4_port1_remote_primary_line.T, ) ) p4_port1_far_node_to_line_flow = ( self.components.p4_port1_remote_port1_line.port_mass_flow( port_pressure_pa=p4_port1_far_primary_line.p, port_temperature_k=p4_port1_far_primary_line.T, ) ) p4_port1_far_chamber_to_line_flow = ( self.components.p4_port1_far_primary_line.resistance_mass_flow( port_1_pressure_pa=p4_port1_far_primary_chamber.p, port_1_temperature_k=p4_port1_far_primary_chamber.T, ) ) p4_port1_far_to_next_line_flow = ( self.components.p4_port1_far_port1_line.port_mass_flow( port_pressure_pa=p4_port1_far_primary_line.p, port_temperature_k=p4_port1_far_primary_line.T, ) ) p4_port1_next_node_to_line_flow = ( self.components.p4_port1_far_port1_line.port_mass_flow( port_pressure_pa=p4_port1_next_primary_line.p, port_temperature_k=p4_port1_next_primary_line.T, ) ) p4_port1_next_chamber_to_line_flow = ( self.components.p4_port1_next_primary_line.resistance_mass_flow( port_1_pressure_pa=p4_port1_next_primary_chamber.p, port_1_temperature_k=p4_port1_next_primary_chamber.T, ) ) p4_port1_remote_node_to_orifice_line_flow = -self.components.p4_port1_remote_orifice_node.balance( port_2_temperature_k=p4_port1_remote_orifice_line_port_1.T, port_2_pressure_pa=p4_port1_remote_orifice_line_port_1.p, port_1_enthalpy_flow_w=0.0, port_1_mass_flow_g_s=0.0, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=-node_to_resistance_flow, node_h=p4_port1_remote_orifice_line_port_1.h, connected_h=node_line_port_1.h, ), port_3_mass_flow_g_s=-node_to_resistance_flow * 1.0e3, ).port_2_mass_flow_g_s * 1.0e-3 p4_port1_remote_orifice_line_center_flow = ( self.components.p4_port1_remote_orifice_line.resistance_mass_flow() ) p4_port1_remote_orifice_to_node_flow = self._line_to_p4_flow( line=p4_port1_remote_orifice_line_port_2, p4_boundary=p4_port1_remote_primary_line, orifice=self.components.p4_port1_remote_orifice, ) p4_to_port3_line_flow = self.components.p4_port3_line.port_mass_flow( port_pressure_pa=p4_primary_line.p, port_temperature_k=p4_primary_line.T, ) p4_port3_remote_node_to_line_flow = ( self.components.p4_port3_line.port_mass_flow( port_pressure_pa=p4_port3_remote_primary_line.p, port_temperature_k=p4_port3_remote_primary_line.T, ) ) p4_port3_remote_chamber_to_line_flow = ( self.components.p4_port3_remote_primary_line.resistance_mass_flow( port_1_pressure_pa=p4_port3_remote_primary_chamber.p, port_1_temperature_k=p4_port3_remote_primary_chamber.T, ) ) p4_port3_remote_to_port3_line_flow = ( self.components.p4_port3_remote_port3_line.port_mass_flow( port_pressure_pa=p4_port3_remote_primary_line.p, port_temperature_k=p4_port3_remote_primary_line.T, ) ) p4_port3_far_node_to_line_flow = ( self.components.p4_port3_remote_port3_line.port_mass_flow( port_pressure_pa=p4_port3_far_primary_line.p, port_temperature_k=p4_port3_far_primary_line.T, ) ) p4_port3_far_chamber_to_line_flow = ( self.components.p4_port3_far_primary_line.resistance_mass_flow( port_1_pressure_pa=p4_port3_far_primary_chamber.p, port_1_temperature_k=p4_port3_far_primary_chamber.T, ) ) p4_port3_far_to_next_line_flow = ( self.components.p4_port3_far_port3_line.port_mass_flow( port_pressure_pa=p4_port3_far_primary_line.p, port_temperature_k=p4_port3_far_primary_line.T, ) ) p4_port3_next_node_to_line_flow = ( self.components.p4_port3_far_port3_line.port_mass_flow( port_pressure_pa=p4_port3_next_primary_line.p, port_temperature_k=p4_port3_next_primary_line.T, ) ) p4_port3_next_chamber_to_line_flow = ( self.components.p4_port3_next_primary_line.resistance_mass_flow( port_1_pressure_pa=p4_port3_next_primary_chamber.p, port_1_temperature_k=p4_port3_next_primary_chamber.T, ) ) p4_port3_remote_node_to_resistance_flow = ( self.components.p4_port3_remote_orifice_resistance.mass_flow( port_1_pressure_pa=p4_port3_remote_orifice_line_port_1.p, port_1_temperature_k=p4_port3_remote_orifice_line_port_1.T, port_2_pressure_pa=p4_port3_remote_resistance_node_line_port_1.p, port_2_temperature_k=p4_port3_remote_resistance_node_line_port_1.T, ) ) p4_port3_remote_orifice_node_balance = ( self.components.p4_port3_remote_orifice_node.balance( port_2_temperature_k=p4_port3_remote_orifice_line_port_1.T, port_2_pressure_pa=p4_port3_remote_orifice_line_port_1.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=inlet_node_to_line_flow, node_h=p4_port3_remote_orifice_line_port_1.h, connected_h=inlet_line.h, ), port_1_mass_flow_g_s=inlet_node_to_line_flow * 1.0e3, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port3_remote_node_to_resistance_flow, node_h=p4_port3_remote_orifice_line_port_1.h, connected_h=p4_port3_remote_resistance_node_line_port_1.h, ), port_3_mass_flow_g_s=p4_port3_remote_node_to_resistance_flow * 1.0e3, ) ) p4_port3_remote_node_to_orifice_line_flow = ( -p4_port3_remote_orifice_node_balance.port_2_mass_flow_g_s * 1.0e-3 ) p4_port3_remote_resistance_node_balance = ( self.components.p4_port3_remote_resistance_node.balance( port_2_temperature_k=p4_port3_remote_resistance_node_line_port_1.T, port_2_pressure_pa=p4_port3_remote_resistance_node_line_port_1.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=-p4_port3_remote_node_to_resistance_flow, node_h=p4_port3_remote_resistance_node_line_port_1.h, connected_h=p4_port3_remote_orifice_line_port_1.h, ), port_1_mass_flow_g_s=-p4_port3_remote_node_to_resistance_flow * 1.0e3, port_3_enthalpy_flow_w=0.0, port_3_mass_flow_g_s=0.0, ) ) p4_port3_remote_resistance_node_to_line_flow = ( -p4_port3_remote_resistance_node_balance.port_2_mass_flow_g_s * 1.0e-3 ) p4_port3_remote_resistance_line_center_flow = ( self.components.p4_port3_remote_resistance_node_line.resistance_mass_flow() ) p4_port3_remote_resistance_to_p4_flow = self._line_to_p4_flow( line=p4_port3_remote_resistance_node_line_port_2, p4_boundary=p4_port3_far_primary_line, orifice=self.components.p4_port3_remote_resistance_orifice, ) p4_port3_remote_orifice_line_center_flow = ( self.components.p4_port3_remote_orifice_line.resistance_mass_flow() ) p4_port3_remote_orifice_to_node_flow = self._line_to_p4_flow( line=p4_port3_remote_orifice_line_port_2, p4_boundary=p4_port3_remote_primary_line, orifice=self.components.p4_port3_remote_orifice, ) p4_balance = self.components.p4_node.balance( port_2_temperature_k=p4_primary_line.T, port_2_pressure_pa=p4_primary_line.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_to_port1_line_flow, node_h=p4_primary_line.h, connected_h=p4_port1_line.h, ), port_1_mass_flow_g_s=-p4_to_port1_line_flow * 1.0e3, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_to_port3_line_flow, node_h=p4_primary_line.h, connected_h=p4_port3_line.h, ), port_3_mass_flow_g_s=-p4_to_port3_line_flow * 1.0e3, port_4_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=pnl0003_to_p4_flow, node_h=node_line_port_2.h, connected_h=p4_primary_line.h, ), port_4_mass_flow_g_s=pnl0003_to_p4_flow * 1.0e3, ) p4_node_to_primary_line_flow = p4_balance.port_2_mass_flow_g_s * 1.0e-3 p4_port1_remote_balance = self.components.p4_port1_remote_node.balance( port_2_temperature_k=p4_port1_remote_primary_line.T, port_2_pressure_pa=p4_port1_remote_primary_line.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port1_remote_to_port1_line_flow, node_h=p4_port1_remote_primary_line.h, connected_h=p4_port1_remote_port1_line.h, ), port_1_mass_flow_g_s=-p4_port1_remote_to_port1_line_flow * 1.0e3, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port1_remote_node_to_line_flow, node_h=p4_port1_remote_primary_line.h, connected_h=p4_port1_line.h, ), port_3_mass_flow_g_s=-p4_port1_remote_node_to_line_flow * 1.0e3, port_4_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port1_remote_orifice_to_node_flow, node_h=p4_port1_remote_orifice_line_port_2.h, connected_h=p4_port1_remote_primary_line.h, ), port_4_mass_flow_g_s=p4_port1_remote_orifice_to_node_flow * 1.0e3, ) p4_port1_remote_node_to_primary_line_flow = ( p4_port1_remote_balance.port_2_mass_flow_g_s * 1.0e-3 ) p4_port1_remote_orifice_node_balance = ( self.components.p4_port1_remote_orifice_node.balance( port_2_temperature_k=p4_port1_remote_orifice_line_port_1.T, port_2_pressure_pa=p4_port1_remote_orifice_line_port_1.p, port_1_enthalpy_flow_w=0.0, port_1_mass_flow_g_s=0.0, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=-node_to_resistance_flow, node_h=p4_port1_remote_orifice_line_port_1.h, connected_h=node_line_port_1.h, ), port_3_mass_flow_g_s=-node_to_resistance_flow * 1.0e3, ) ) p4_port1_far_balance = self.components.p4_port1_far_node.balance( port_2_temperature_k=p4_port1_far_primary_line.T, port_2_pressure_pa=p4_port1_far_primary_line.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port1_far_to_next_line_flow, node_h=p4_port1_far_primary_line.h, connected_h=p4_port1_far_port1_line.h, ), port_1_mass_flow_g_s=-p4_port1_far_to_next_line_flow * 1.0e3, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port1_far_node_to_line_flow, node_h=p4_port1_far_primary_line.h, connected_h=p4_port1_remote_port1_line.h, ), port_3_mass_flow_g_s=-p4_port1_far_node_to_line_flow * 1.0e3, port_4_enthalpy_flow_w=0.0, port_4_mass_flow_g_s=0.0, ) p4_port1_far_node_to_primary_line_flow = ( p4_port1_far_balance.port_2_mass_flow_g_s * 1.0e-3 ) p4_port1_next_balance = self.components.p4_port1_next_node.balance( port_2_temperature_k=p4_port1_next_primary_line.T, port_2_pressure_pa=p4_port1_next_primary_line.p, port_1_enthalpy_flow_w=0.0, port_1_mass_flow_g_s=0.0, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port1_next_node_to_line_flow, node_h=p4_port1_next_primary_line.h, connected_h=p4_port1_far_port1_line.h, ), port_3_mass_flow_g_s=-p4_port1_next_node_to_line_flow * 1.0e3, port_4_enthalpy_flow_w=0.0, port_4_mass_flow_g_s=0.0, ) p4_port1_next_node_to_primary_line_flow = ( p4_port1_next_balance.port_2_mass_flow_g_s * 1.0e-3 ) p4_port3_remote_balance = self.components.p4_port3_remote_node.balance( port_2_temperature_k=p4_port3_remote_primary_line.T, port_2_pressure_pa=p4_port3_remote_primary_line.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port3_remote_node_to_line_flow, node_h=p4_port3_remote_primary_line.h, connected_h=p4_port3_line.h, ), port_1_mass_flow_g_s=-p4_port3_remote_node_to_line_flow * 1.0e3, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port3_remote_to_port3_line_flow, node_h=p4_port3_remote_primary_line.h, connected_h=p4_port3_remote_port3_line.h, ), port_3_mass_flow_g_s=-p4_port3_remote_to_port3_line_flow * 1.0e3, port_4_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port3_remote_orifice_to_node_flow, node_h=p4_port3_remote_orifice_line_port_2.h, connected_h=p4_port3_remote_primary_line.h, ), port_4_mass_flow_g_s=p4_port3_remote_orifice_to_node_flow * 1.0e3, ) p4_port3_remote_node_to_primary_line_flow = ( p4_port3_remote_balance.port_2_mass_flow_g_s * 1.0e-3 ) p4_port3_far_balance = self.components.p4_port3_far_node.balance( port_2_temperature_k=p4_port3_far_primary_line.T, port_2_pressure_pa=p4_port3_far_primary_line.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port3_far_node_to_line_flow, node_h=p4_port3_far_primary_line.h, connected_h=p4_port3_remote_port3_line.h, ), port_1_mass_flow_g_s=-p4_port3_far_node_to_line_flow * 1.0e3, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port3_far_to_next_line_flow, node_h=p4_port3_far_primary_line.h, connected_h=p4_port3_far_port3_line.h, ), port_3_mass_flow_g_s=-p4_port3_far_to_next_line_flow * 1.0e3, port_4_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port3_remote_resistance_to_p4_flow, node_h=p4_port3_remote_resistance_node_line_port_2.h, connected_h=p4_port3_far_primary_line.h, ), port_4_mass_flow_g_s=p4_port3_remote_resistance_to_p4_flow * 1.0e3, ) p4_port3_far_node_to_primary_line_flow = ( p4_port3_far_balance.port_2_mass_flow_g_s * 1.0e-3 ) p4_port3_next_balance = self.components.p4_port3_next_node.balance( port_2_temperature_k=p4_port3_next_primary_line.T, port_2_pressure_pa=p4_port3_next_primary_line.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=p4_port3_next_node_to_line_flow, node_h=p4_port3_next_primary_line.h, connected_h=p4_port3_far_port3_line.h, ), port_1_mass_flow_g_s=-p4_port3_next_node_to_line_flow * 1.0e3, port_3_enthalpy_flow_w=0.0, port_3_mass_flow_g_s=0.0, port_4_enthalpy_flow_w=0.0, port_4_mass_flow_g_s=0.0, ) p4_port3_next_node_to_primary_line_flow = ( p4_port3_next_balance.port_2_mass_flow_g_s * 1.0e-3 ) snapshot = TestMqlPn3P4NodeChamberSegmentSnapshot( inlet_line=inlet_line, chamber=chamber, outlet_line=outlet_line, node_line_port_1=node_line_port_1, node_line_port_2=node_line_port_2, p4_primary_line=p4_primary_line, p4_boundary=p4_primary_line, p4_primary_chamber=p4_primary_chamber, p4_port1_line=p4_port1_line, p4_port1_remote_primary_line=p4_port1_remote_primary_line, p4_port1_remote_primary_chamber=p4_port1_remote_primary_chamber, p4_port1_remote_port1_line=p4_port1_remote_port1_line, p4_port1_far_primary_line=p4_port1_far_primary_line, p4_port1_far_primary_chamber=p4_port1_far_primary_chamber, p4_port1_far_port1_line=p4_port1_far_port1_line, p4_port1_next_primary_line=p4_port1_next_primary_line, p4_port1_next_primary_chamber=p4_port1_next_primary_chamber, p4_port1_remote_orifice_line_port_1=p4_port1_remote_orifice_line_port_1, p4_port1_remote_orifice_line_port_2=p4_port1_remote_orifice_line_port_2, p4_port3_line=p4_port3_line, p4_port3_remote_primary_line=p4_port3_remote_primary_line, p4_port3_remote_primary_chamber=p4_port3_remote_primary_chamber, p4_port3_remote_port3_line=p4_port3_remote_port3_line, p4_port3_far_primary_line=p4_port3_far_primary_line, p4_port3_far_primary_chamber=p4_port3_far_primary_chamber, p4_port3_far_port3_line=p4_port3_far_port3_line, p4_port3_next_primary_line=p4_port3_next_primary_line, p4_port3_next_primary_chamber=p4_port3_next_primary_chamber, p4_port3_remote_orifice_line_port_1=p4_port3_remote_orifice_line_port_1, p4_port3_remote_orifice_line_port_2=p4_port3_remote_orifice_line_port_2, p4_port3_remote_resistance_node_line_port_1=( p4_port3_remote_resistance_node_line_port_1 ), p4_port3_remote_resistance_node_line_port_2=( p4_port3_remote_resistance_node_line_port_2 ), inlet_node=inlet_node, resistance_boundary=resistance_boundary, node_balance=node_balance, p4_balance=p4_balance, p4_port1_remote_balance=p4_port1_remote_balance, p4_port1_far_balance=p4_port1_far_balance, p4_port1_next_balance=p4_port1_next_balance, p4_port1_remote_orifice_node_balance=p4_port1_remote_orifice_node_balance, p4_port3_remote_balance=p4_port3_remote_balance, p4_port3_far_balance=p4_port3_far_balance, p4_port3_next_balance=p4_port3_next_balance, p4_port3_remote_orifice_node_balance=p4_port3_remote_orifice_node_balance, p4_port3_remote_resistance_node_balance=( p4_port3_remote_resistance_node_balance ), inlet_node_to_line_flow=inlet_node_to_line_flow, inlet_line_to_chamber_flow=inlet_line_to_chamber_flow, outlet_node_to_line_flow=outlet_node_to_line_flow, outlet_line_to_chamber_flow=outlet_line_to_chamber_flow, node_to_resistance_flow=node_to_resistance_flow, node_to_pnl0003_flow=node_to_pnl0003_flow, pnl0003_center_flow=pnl0003_center_flow, pnl0003_to_p4_flow=pnl0003_to_p4_flow, p4_primary_chamber_to_line_flow=p4_primary_chamber_to_line_flow, p4_node_to_primary_line_flow=p4_node_to_primary_line_flow, p4_to_port1_line_flow=p4_to_port1_line_flow, p4_port1_remote_node_to_line_flow=p4_port1_remote_node_to_line_flow, p4_port1_remote_chamber_to_line_flow=p4_port1_remote_chamber_to_line_flow, p4_port1_remote_node_to_primary_line_flow=( p4_port1_remote_node_to_primary_line_flow ), p4_port1_remote_to_port1_line_flow=p4_port1_remote_to_port1_line_flow, p4_port1_far_node_to_line_flow=p4_port1_far_node_to_line_flow, p4_port1_far_chamber_to_line_flow=p4_port1_far_chamber_to_line_flow, p4_port1_far_node_to_primary_line_flow=( p4_port1_far_node_to_primary_line_flow ), p4_port1_far_to_next_line_flow=p4_port1_far_to_next_line_flow, p4_port1_next_node_to_line_flow=p4_port1_next_node_to_line_flow, p4_port1_next_chamber_to_line_flow=p4_port1_next_chamber_to_line_flow, p4_port1_next_node_to_primary_line_flow=( p4_port1_next_node_to_primary_line_flow ), p4_port1_remote_node_to_orifice_line_flow=( p4_port1_remote_node_to_orifice_line_flow ), p4_port1_remote_orifice_line_center_flow=( p4_port1_remote_orifice_line_center_flow ), p4_port1_remote_orifice_to_node_flow=p4_port1_remote_orifice_to_node_flow, p4_to_port3_line_flow=p4_to_port3_line_flow, p4_port3_remote_node_to_line_flow=p4_port3_remote_node_to_line_flow, p4_port3_remote_chamber_to_line_flow=p4_port3_remote_chamber_to_line_flow, p4_port3_remote_node_to_primary_line_flow=( p4_port3_remote_node_to_primary_line_flow ), p4_port3_remote_to_port3_line_flow=p4_port3_remote_to_port3_line_flow, p4_port3_far_node_to_line_flow=p4_port3_far_node_to_line_flow, p4_port3_far_chamber_to_line_flow=p4_port3_far_chamber_to_line_flow, p4_port3_far_node_to_primary_line_flow=( p4_port3_far_node_to_primary_line_flow ), p4_port3_far_to_next_line_flow=p4_port3_far_to_next_line_flow, p4_port3_next_node_to_line_flow=p4_port3_next_node_to_line_flow, p4_port3_next_chamber_to_line_flow=p4_port3_next_chamber_to_line_flow, p4_port3_next_node_to_primary_line_flow=( p4_port3_next_node_to_primary_line_flow ), p4_port3_remote_node_to_orifice_line_flow=( p4_port3_remote_node_to_orifice_line_flow ), p4_port3_remote_node_to_resistance_flow=( p4_port3_remote_node_to_resistance_flow ), p4_port3_remote_resistance_node_to_line_flow=( p4_port3_remote_resistance_node_to_line_flow ), p4_port3_remote_resistance_line_center_flow=( p4_port3_remote_resistance_line_center_flow ), p4_port3_remote_resistance_to_p4_flow=( p4_port3_remote_resistance_to_p4_flow ), p4_port3_remote_orifice_line_center_flow=( p4_port3_remote_orifice_line_center_flow ), p4_port3_remote_orifice_to_node_flow=p4_port3_remote_orifice_to_node_flow, ) self._write_port_states(snapshot) return snapshot @staticmethod def _line_to_chamber_flow( *, line: ThermodynamicProperties, chamber: ThermodynamicProperties, orifice: AmesimPneumaticOrifice, ) -> float: return TestMqlPn3NodeChamberSegmentClosure._line_to_chamber_flow( line=line, chamber=chamber, orifice=orifice, ) @staticmethod def _line_to_p4_flow( *, line: ThermodynamicProperties, p4_boundary: ThermodynamicProperties, orifice: AmesimPneumaticOrifice, ) -> float: return TestMqlPn3NodeChamberSegmentClosure._line_to_p4_flow( line=line, p4_boundary=p4_boundary, orifice=orifice, ) @staticmethod def _boundary_to_p4_flow( *, boundary: ThermodynamicProperties, p4_boundary: ThermodynamicProperties, orifice: AmesimPneumaticOrifice, ) -> float: upstream_temperature = boundary.T if boundary.p >= p4_boundary.p else p4_boundary.T return orifice.mass_flow(boundary.p, p4_boundary.p, upstream_temperature) @staticmethod def _port( component: AmesimPneumaticVolume | AmesimPneumaticOrifice, port_name: str, ) -> PortState: return TestMqlPn3NodeChamberSegmentClosure._port(component, port_name) @staticmethod def _enthalpy_flow_from_node( *, flow_kg_s: float, node_h: float, connected_h: float, ) -> float: return TestMqlPn3NodeChamberSegmentClosure._enthalpy_flow_from_node( flow_kg_s=flow_kg_s, node_h=node_h, connected_h=connected_h, ) def _write_port_states( self, snapshot: TestMqlPn3P4NodeChamberSegmentSnapshot, ) -> None: spec = self.components.spec chamber = self.components.volume chamber_inlet_port = self._port(chamber, spec.volume_inlet_port) chamber_outlet_port = self._port(chamber, spec.volume_outlet_port) TestMqlPnl0001PairChamberSegmentClosure._write_line_side( self, line=self.components.inlet_line, line_properties=snapshot.inlet_line, node_properties=snapshot.p4_port3_remote_orifice_line_port_1, node_to_line_flow=snapshot.inlet_node_to_line_flow, line_to_chamber_flow=snapshot.inlet_line_to_chamber_flow, orifice=self.components.inlet_orifice, orifice_boundary_port=spec.inlet_orifice_boundary_port, orifice_volume_port=spec.inlet_orifice_volume_port, chamber_port=chamber_inlet_port, chamber_properties=snapshot.chamber, ) TestMqlPnl0001PairChamberSegmentClosure._write_line_side( self, line=self.components.outlet_line, line_properties=snapshot.outlet_line, node_properties=snapshot.node_line_port_1, node_to_line_flow=snapshot.outlet_node_to_line_flow, line_to_chamber_flow=snapshot.outlet_line_to_chamber_flow, orifice=self.components.outlet_orifice, orifice_boundary_port=spec.outlet_orifice_boundary_port, orifice_volume_port=spec.outlet_orifice_volume_port, chamber_port=chamber_outlet_port, chamber_properties=snapshot.chamber, ) node_line = self.components.node_line node_line.port_1.p = snapshot.node_line_port_1.p node_line.port_1.m_flow = snapshot.node_to_pnl0003_flow node_line.port_1.h_outflow = snapshot.node_line_port_1.h node_line.port_2.p = snapshot.node_line_port_2.p node_line.port_2.m_flow = -snapshot.pnl0003_to_p4_flow node_line.port_2.h_outflow = snapshot.node_line_port_2.h node_orifice = self.components.node_orifice node_orifice.port_a.p = snapshot.node_line_port_2.p node_orifice.port_a.m_flow = snapshot.pnl0003_to_p4_flow node_orifice.port_a.h_outflow = snapshot.node_line_port_2.h node_orifice.port_b.p = snapshot.p4_primary_line.p node_orifice.port_b.m_flow = -snapshot.pnl0003_to_p4_flow node_orifice.port_b.h_outflow = snapshot.p4_primary_line.h resistance = self.components.node_resistance resistance.port_1.p = snapshot.node_line_port_1.p resistance.port_1.m_flow = snapshot.node_to_resistance_flow resistance.port_1.h_outflow = snapshot.node_line_port_1.h resistance.port_2.p = snapshot.p4_port1_remote_orifice_line_port_1.p resistance.port_2.m_flow = -snapshot.node_to_resistance_flow resistance.port_2.h_outflow = snapshot.p4_port1_remote_orifice_line_port_1.h p4_primary_line = self.components.p4_primary_line p4_primary_line.port_1.p = snapshot.p4_primary_chamber.p p4_primary_line.port_1.m_flow = snapshot.p4_primary_chamber_to_line_flow p4_primary_line.port_1.h_outflow = snapshot.p4_primary_line.h p4_primary_line.port_2.p = snapshot.p4_primary_line.p p4_primary_line.port_2.m_flow = snapshot.p4_node_to_primary_line_flow p4_primary_line.port_2.h_outflow = snapshot.p4_primary_line.h p4_primary_chamber = self.components.p4_primary_chamber p4_primary_chamber.port_a.p = snapshot.p4_primary_chamber.p p4_primary_chamber.port_a.m_flow = -snapshot.p4_primary_chamber_to_line_flow p4_primary_chamber.port_a.h_outflow = snapshot.p4_primary_chamber.h p4_port1_line = self.components.p4_port1_line p4_port1_line.port_1.p = snapshot.p4_primary_line.p p4_port1_line.port_1.m_flow = snapshot.p4_to_port1_line_flow p4_port1_line.port_1.h_outflow = snapshot.p4_port1_line.h p4_port1_line.port_2.p = snapshot.p4_port1_remote_primary_line.p p4_port1_line.port_2.m_flow = snapshot.p4_port1_remote_node_to_line_flow p4_port1_line.port_2.h_outflow = snapshot.p4_port1_line.h p4_port1_remote_primary_line = self.components.p4_port1_remote_primary_line p4_port1_remote_primary_line.port_1.p = snapshot.p4_port1_remote_primary_chamber.p p4_port1_remote_primary_line.port_1.m_flow = ( snapshot.p4_port1_remote_chamber_to_line_flow ) p4_port1_remote_primary_line.port_1.h_outflow = ( snapshot.p4_port1_remote_primary_line.h ) p4_port1_remote_primary_line.port_2.p = snapshot.p4_port1_remote_primary_line.p p4_port1_remote_primary_line.port_2.m_flow = ( snapshot.p4_port1_remote_node_to_primary_line_flow ) p4_port1_remote_primary_line.port_2.h_outflow = ( snapshot.p4_port1_remote_primary_line.h ) p4_port1_remote_primary_chamber = self.components.p4_port1_remote_primary_chamber p4_port1_remote_primary_chamber.port_a.p = snapshot.p4_port1_remote_primary_chamber.p p4_port1_remote_primary_chamber.port_a.m_flow = ( -snapshot.p4_port1_remote_chamber_to_line_flow ) p4_port1_remote_primary_chamber.port_a.h_outflow = ( snapshot.p4_port1_remote_primary_chamber.h ) p4_port1_remote_port1_line = self.components.p4_port1_remote_port1_line p4_port1_remote_port1_line.port_1.p = snapshot.p4_port1_remote_primary_line.p p4_port1_remote_port1_line.port_1.m_flow = ( snapshot.p4_port1_remote_to_port1_line_flow ) p4_port1_remote_port1_line.port_1.h_outflow = ( snapshot.p4_port1_remote_port1_line.h ) p4_port1_remote_port1_line.port_2.p = snapshot.p4_port1_far_primary_line.p p4_port1_remote_port1_line.port_2.m_flow = snapshot.p4_port1_far_node_to_line_flow p4_port1_remote_port1_line.port_2.h_outflow = ( snapshot.p4_port1_remote_port1_line.h ) p4_port1_far_primary_line = self.components.p4_port1_far_primary_line p4_port1_far_primary_line.port_1.p = snapshot.p4_port1_far_primary_chamber.p p4_port1_far_primary_line.port_1.m_flow = snapshot.p4_port1_far_chamber_to_line_flow p4_port1_far_primary_line.port_1.h_outflow = snapshot.p4_port1_far_primary_line.h p4_port1_far_primary_line.port_2.p = snapshot.p4_port1_far_primary_line.p p4_port1_far_primary_line.port_2.m_flow = snapshot.p4_port1_far_node_to_primary_line_flow p4_port1_far_primary_line.port_2.h_outflow = snapshot.p4_port1_far_primary_line.h p4_port1_far_primary_chamber = self.components.p4_port1_far_primary_chamber p4_port1_far_primary_chamber.port_a.p = snapshot.p4_port1_far_primary_chamber.p p4_port1_far_primary_chamber.port_a.m_flow = -snapshot.p4_port1_far_chamber_to_line_flow p4_port1_far_primary_chamber.port_a.h_outflow = snapshot.p4_port1_far_primary_chamber.h p4_port1_far_port1_line = self.components.p4_port1_far_port1_line p4_port1_far_port1_line.port_1.p = snapshot.p4_port1_far_primary_line.p p4_port1_far_port1_line.port_1.m_flow = snapshot.p4_port1_far_to_next_line_flow p4_port1_far_port1_line.port_1.h_outflow = snapshot.p4_port1_far_port1_line.h p4_port1_far_port1_line.port_2.p = snapshot.p4_port1_next_primary_line.p p4_port1_far_port1_line.port_2.m_flow = snapshot.p4_port1_next_node_to_line_flow p4_port1_far_port1_line.port_2.h_outflow = snapshot.p4_port1_far_port1_line.h p4_port1_next_primary_line = self.components.p4_port1_next_primary_line p4_port1_next_primary_line.port_1.p = snapshot.p4_port1_next_primary_chamber.p p4_port1_next_primary_line.port_1.m_flow = snapshot.p4_port1_next_chamber_to_line_flow p4_port1_next_primary_line.port_1.h_outflow = snapshot.p4_port1_next_primary_line.h p4_port1_next_primary_line.port_2.p = snapshot.p4_port1_next_primary_line.p p4_port1_next_primary_line.port_2.m_flow = snapshot.p4_port1_next_node_to_primary_line_flow p4_port1_next_primary_line.port_2.h_outflow = snapshot.p4_port1_next_primary_line.h p4_port1_next_primary_chamber = self.components.p4_port1_next_primary_chamber p4_port1_next_primary_chamber.port_a.p = snapshot.p4_port1_next_primary_chamber.p p4_port1_next_primary_chamber.port_a.m_flow = -snapshot.p4_port1_next_chamber_to_line_flow p4_port1_next_primary_chamber.port_a.h_outflow = snapshot.p4_port1_next_primary_chamber.h p4_port1_remote_orifice_line = self.components.p4_port1_remote_orifice_line p4_port1_remote_orifice_line.port_1.p = snapshot.p4_port1_remote_orifice_line_port_1.p p4_port1_remote_orifice_line.port_1.m_flow = snapshot.p4_port1_remote_node_to_orifice_line_flow p4_port1_remote_orifice_line.port_1.h_outflow = snapshot.p4_port1_remote_orifice_line_port_1.h p4_port1_remote_orifice_line.port_2.p = snapshot.p4_port1_remote_orifice_line_port_2.p p4_port1_remote_orifice_line.port_2.m_flow = -snapshot.p4_port1_remote_orifice_to_node_flow p4_port1_remote_orifice_line.port_2.h_outflow = snapshot.p4_port1_remote_orifice_line_port_2.h p4_port1_remote_orifice = self.components.p4_port1_remote_orifice p4_port1_remote_orifice.port_a.p = snapshot.p4_port1_remote_orifice_line_port_2.p p4_port1_remote_orifice.port_a.m_flow = snapshot.p4_port1_remote_orifice_to_node_flow p4_port1_remote_orifice.port_a.h_outflow = snapshot.p4_port1_remote_orifice_line_port_2.h p4_port1_remote_orifice.port_b.p = snapshot.p4_port1_remote_primary_line.p p4_port1_remote_orifice.port_b.m_flow = -snapshot.p4_port1_remote_orifice_to_node_flow p4_port1_remote_orifice.port_b.h_outflow = snapshot.p4_port1_remote_primary_line.h p4_port3_line = self.components.p4_port3_line p4_port3_line.port_1.p = snapshot.p4_port3_remote_primary_line.p p4_port3_line.port_1.m_flow = snapshot.p4_port3_remote_node_to_line_flow p4_port3_line.port_1.h_outflow = snapshot.p4_port3_line.h p4_port3_line.port_2.p = snapshot.p4_primary_line.p p4_port3_line.port_2.m_flow = snapshot.p4_to_port3_line_flow p4_port3_line.port_2.h_outflow = snapshot.p4_port3_line.h p4_port3_remote_primary_line = self.components.p4_port3_remote_primary_line p4_port3_remote_primary_line.port_1.p = snapshot.p4_port3_remote_primary_chamber.p p4_port3_remote_primary_line.port_1.m_flow = ( snapshot.p4_port3_remote_chamber_to_line_flow ) p4_port3_remote_primary_line.port_1.h_outflow = ( snapshot.p4_port3_remote_primary_line.h ) p4_port3_remote_primary_line.port_2.p = snapshot.p4_port3_remote_primary_line.p p4_port3_remote_primary_line.port_2.m_flow = ( snapshot.p4_port3_remote_node_to_primary_line_flow ) p4_port3_remote_primary_line.port_2.h_outflow = ( snapshot.p4_port3_remote_primary_line.h ) p4_port3_remote_primary_chamber = self.components.p4_port3_remote_primary_chamber p4_port3_remote_primary_chamber.port_a.p = snapshot.p4_port3_remote_primary_chamber.p p4_port3_remote_primary_chamber.port_a.m_flow = ( -snapshot.p4_port3_remote_chamber_to_line_flow ) p4_port3_remote_primary_chamber.port_a.h_outflow = ( snapshot.p4_port3_remote_primary_chamber.h ) p4_port3_remote_port3_line = self.components.p4_port3_remote_port3_line p4_port3_remote_port3_line.port_1.p = snapshot.p4_port3_far_primary_line.p p4_port3_remote_port3_line.port_1.m_flow = snapshot.p4_port3_far_node_to_line_flow p4_port3_remote_port3_line.port_1.h_outflow = ( snapshot.p4_port3_remote_port3_line.h ) p4_port3_remote_port3_line.port_2.p = snapshot.p4_port3_remote_primary_line.p p4_port3_remote_port3_line.port_2.m_flow = ( snapshot.p4_port3_remote_to_port3_line_flow ) p4_port3_remote_port3_line.port_2.h_outflow = ( snapshot.p4_port3_remote_port3_line.h ) p4_port3_far_primary_line = self.components.p4_port3_far_primary_line p4_port3_far_primary_line.port_1.p = snapshot.p4_port3_far_primary_chamber.p p4_port3_far_primary_line.port_1.m_flow = snapshot.p4_port3_far_chamber_to_line_flow p4_port3_far_primary_line.port_1.h_outflow = snapshot.p4_port3_far_primary_line.h p4_port3_far_primary_line.port_2.p = snapshot.p4_port3_far_primary_line.p p4_port3_far_primary_line.port_2.m_flow = snapshot.p4_port3_far_node_to_primary_line_flow p4_port3_far_primary_line.port_2.h_outflow = snapshot.p4_port3_far_primary_line.h p4_port3_far_primary_chamber = self.components.p4_port3_far_primary_chamber p4_port3_far_primary_chamber.port_a.p = snapshot.p4_port3_far_primary_chamber.p p4_port3_far_primary_chamber.port_a.m_flow = -snapshot.p4_port3_far_chamber_to_line_flow p4_port3_far_primary_chamber.port_a.h_outflow = snapshot.p4_port3_far_primary_chamber.h p4_port3_far_port3_line = self.components.p4_port3_far_port3_line p4_port3_far_port3_line.port_1.p = snapshot.p4_port3_next_primary_line.p p4_port3_far_port3_line.port_1.m_flow = snapshot.p4_port3_next_node_to_line_flow p4_port3_far_port3_line.port_1.h_outflow = snapshot.p4_port3_far_port3_line.h p4_port3_far_port3_line.port_2.p = snapshot.p4_port3_far_primary_line.p p4_port3_far_port3_line.port_2.m_flow = snapshot.p4_port3_far_to_next_line_flow p4_port3_far_port3_line.port_2.h_outflow = snapshot.p4_port3_far_port3_line.h p4_port3_next_primary_line = self.components.p4_port3_next_primary_line p4_port3_next_primary_line.port_1.p = snapshot.p4_port3_next_primary_chamber.p p4_port3_next_primary_line.port_1.m_flow = snapshot.p4_port3_next_chamber_to_line_flow p4_port3_next_primary_line.port_1.h_outflow = snapshot.p4_port3_next_primary_line.h p4_port3_next_primary_line.port_2.p = snapshot.p4_port3_next_primary_line.p p4_port3_next_primary_line.port_2.m_flow = snapshot.p4_port3_next_node_to_primary_line_flow p4_port3_next_primary_line.port_2.h_outflow = snapshot.p4_port3_next_primary_line.h p4_port3_next_primary_chamber = self.components.p4_port3_next_primary_chamber p4_port3_next_primary_chamber.port_a.p = snapshot.p4_port3_next_primary_chamber.p p4_port3_next_primary_chamber.port_a.m_flow = -snapshot.p4_port3_next_chamber_to_line_flow p4_port3_next_primary_chamber.port_a.h_outflow = snapshot.p4_port3_next_primary_chamber.h p4_port3_remote_orifice_line = self.components.p4_port3_remote_orifice_line p4_port3_remote_orifice_line.port_1.p = snapshot.p4_port3_remote_orifice_line_port_1.p p4_port3_remote_orifice_line.port_1.m_flow = snapshot.p4_port3_remote_node_to_orifice_line_flow p4_port3_remote_orifice_line.port_1.h_outflow = snapshot.p4_port3_remote_orifice_line_port_1.h p4_port3_remote_orifice_line.port_2.p = snapshot.p4_port3_remote_orifice_line_port_2.p p4_port3_remote_orifice_line.port_2.m_flow = -snapshot.p4_port3_remote_orifice_to_node_flow p4_port3_remote_orifice_line.port_2.h_outflow = snapshot.p4_port3_remote_orifice_line_port_2.h p4_port3_remote_orifice_resistance = self.components.p4_port3_remote_orifice_resistance p4_port3_remote_orifice_resistance.port_1.p = snapshot.p4_port3_remote_orifice_line_port_1.p p4_port3_remote_orifice_resistance.port_1.m_flow = snapshot.p4_port3_remote_node_to_resistance_flow p4_port3_remote_orifice_resistance.port_1.h_outflow = snapshot.p4_port3_remote_orifice_line_port_1.h p4_port3_remote_orifice_resistance.port_2.p = snapshot.p4_port3_remote_resistance_node_line_port_1.p p4_port3_remote_orifice_resistance.port_2.m_flow = -snapshot.p4_port3_remote_node_to_resistance_flow p4_port3_remote_orifice_resistance.port_2.h_outflow = snapshot.p4_port3_remote_resistance_node_line_port_1.h p4_port3_remote_resistance_node_line = self.components.p4_port3_remote_resistance_node_line p4_port3_remote_resistance_node_line.port_1.p = snapshot.p4_port3_remote_resistance_node_line_port_1.p p4_port3_remote_resistance_node_line.port_1.m_flow = snapshot.p4_port3_remote_resistance_node_to_line_flow p4_port3_remote_resistance_node_line.port_1.h_outflow = snapshot.p4_port3_remote_resistance_node_line_port_1.h p4_port3_remote_resistance_node_line.port_2.p = snapshot.p4_port3_remote_resistance_node_line_port_2.p p4_port3_remote_resistance_node_line.port_2.m_flow = -snapshot.p4_port3_remote_resistance_to_p4_flow p4_port3_remote_resistance_node_line.port_2.h_outflow = snapshot.p4_port3_remote_resistance_node_line_port_2.h p4_port3_remote_resistance_orifice = self.components.p4_port3_remote_resistance_orifice p4_port3_remote_resistance_orifice.port_a.p = snapshot.p4_port3_remote_resistance_node_line_port_2.p p4_port3_remote_resistance_orifice.port_a.m_flow = snapshot.p4_port3_remote_resistance_to_p4_flow p4_port3_remote_resistance_orifice.port_a.h_outflow = snapshot.p4_port3_remote_resistance_node_line_port_2.h p4_port3_remote_resistance_orifice.port_b.p = snapshot.p4_port3_far_primary_line.p p4_port3_remote_resistance_orifice.port_b.m_flow = -snapshot.p4_port3_remote_resistance_to_p4_flow p4_port3_remote_resistance_orifice.port_b.h_outflow = snapshot.p4_port3_far_primary_line.h p4_port3_remote_orifice = self.components.p4_port3_remote_orifice p4_port3_remote_orifice.port_a.p = snapshot.p4_port3_remote_orifice_line_port_2.p p4_port3_remote_orifice.port_a.m_flow = snapshot.p4_port3_remote_orifice_to_node_flow p4_port3_remote_orifice.port_a.h_outflow = snapshot.p4_port3_remote_orifice_line_port_2.h p4_port3_remote_orifice.port_b.p = snapshot.p4_port3_remote_primary_line.p p4_port3_remote_orifice.port_b.m_flow = -snapshot.p4_port3_remote_orifice_to_node_flow p4_port3_remote_orifice.port_b.h_outflow = snapshot.p4_port3_remote_primary_line.h def rhs(self, state_vector: list[float]) -> list[float]: snapshot = self.snapshot(state_vector) inlet_derivative = self.components.inlet_line.derivatives_from_connections( port_1_m_flow=snapshot.inlet_node_to_line_flow, connected_h_1=snapshot.p4_port3_remote_orifice_line_port_1.h, port_2_m_flow=-snapshot.inlet_line_to_chamber_flow, connected_h_2=snapshot.chamber.h, ) outlet_derivative = self.components.outlet_line.derivatives_from_connections( port_1_m_flow=snapshot.outlet_node_to_line_flow, connected_h_1=snapshot.node_line_port_1.h, port_2_m_flow=-snapshot.outlet_line_to_chamber_flow, connected_h_2=snapshot.chamber.h, ) chamber = self.components.volume spec = self.components.spec chamber_derivative = chamber.derivatives_from_two_connections( port_a_m_flow=self._port(chamber, "port_1").m_flow, connected_h_a=( snapshot.inlet_line.h if spec.volume_inlet_port == "port_1" else snapshot.outlet_line.h ), port_b_m_flow=self._port(chamber, "port_2").m_flow, connected_h_b=( snapshot.inlet_line.h if spec.volume_inlet_port == "port_2" else snapshot.outlet_line.h ), internal_h=snapshot.chamber.h, ) node_line_derivative_1, node_line_derivative_2 = ( self.components.node_line.derivatives_from_connections( port_1_m_flow=snapshot.node_to_pnl0003_flow, connected_h_1=snapshot.node_line_port_1.h, port_2_m_flow=-snapshot.pnl0003_to_p4_flow, connected_h_2=snapshot.p4_primary_line.h, ) ) p4_primary_derivative = ( self.components.p4_primary_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_primary_chamber_to_line_flow, connected_h_1=snapshot.p4_primary_chamber.h, port_2_m_flow=snapshot.p4_node_to_primary_line_flow, connected_h_2=snapshot.p4_primary_line.h, ) ) p4_primary_chamber_derivative = ( self.components.p4_primary_chamber.derivatives_from_two_connections( port_a_m_flow=-snapshot.p4_primary_chamber_to_line_flow, connected_h_a=snapshot.p4_primary_line.h, port_b_m_flow=0.0, connected_h_b=snapshot.p4_primary_chamber.h, internal_h=snapshot.p4_primary_chamber.h, ) ) p4_port1_derivative = self.components.p4_port1_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_to_port1_line_flow, connected_h_1=snapshot.p4_primary_line.h, port_2_m_flow=snapshot.p4_port1_remote_node_to_line_flow, connected_h_2=snapshot.p4_port1_remote_primary_line.h, ) p4_port1_remote_primary_derivative = ( self.components.p4_port1_remote_primary_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port1_remote_chamber_to_line_flow, connected_h_1=snapshot.p4_port1_remote_primary_chamber.h, port_2_m_flow=snapshot.p4_port1_remote_node_to_primary_line_flow, connected_h_2=snapshot.p4_port1_remote_primary_line.h, ) ) p4_port1_remote_chamber_derivative = ( self.components.p4_port1_remote_primary_chamber.derivatives_from_two_connections( port_a_m_flow=-snapshot.p4_port1_remote_chamber_to_line_flow, connected_h_a=snapshot.p4_port1_remote_primary_line.h, port_b_m_flow=0.0, connected_h_b=snapshot.p4_port1_remote_primary_chamber.h, internal_h=snapshot.p4_port1_remote_primary_chamber.h, ) ) p4_port1_remote_port1_derivative = ( self.components.p4_port1_remote_port1_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port1_remote_to_port1_line_flow, connected_h_1=snapshot.p4_port1_remote_primary_line.h, port_2_m_flow=snapshot.p4_port1_far_node_to_line_flow, connected_h_2=snapshot.p4_port1_far_primary_line.h, ) ) p4_port1_far_primary_derivative = ( self.components.p4_port1_far_primary_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port1_far_chamber_to_line_flow, connected_h_1=snapshot.p4_port1_far_primary_chamber.h, port_2_m_flow=snapshot.p4_port1_far_node_to_primary_line_flow, connected_h_2=snapshot.p4_port1_far_primary_line.h, ) ) p4_port1_far_chamber_derivative = ( self.components.p4_port1_far_primary_chamber.derivatives_from_two_connections( port_a_m_flow=-snapshot.p4_port1_far_chamber_to_line_flow, connected_h_a=snapshot.p4_port1_far_primary_line.h, port_b_m_flow=0.0, connected_h_b=snapshot.p4_port1_far_primary_chamber.h, internal_h=snapshot.p4_port1_far_primary_chamber.h, ) ) p4_port1_far_port1_derivative = ( self.components.p4_port1_far_port1_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port1_far_to_next_line_flow, connected_h_1=snapshot.p4_port1_far_primary_line.h, port_2_m_flow=snapshot.p4_port1_next_node_to_line_flow, connected_h_2=snapshot.p4_port1_next_primary_line.h, ) ) p4_port1_next_primary_derivative = ( self.components.p4_port1_next_primary_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port1_next_chamber_to_line_flow, connected_h_1=snapshot.p4_port1_next_primary_chamber.h, port_2_m_flow=snapshot.p4_port1_next_node_to_primary_line_flow, connected_h_2=snapshot.p4_port1_next_primary_line.h, ) ) p4_port1_next_chamber_derivative = ( self.components.p4_port1_next_primary_chamber.derivatives_from_two_connections( port_a_m_flow=-snapshot.p4_port1_next_chamber_to_line_flow, connected_h_a=snapshot.p4_port1_next_primary_line.h, port_b_m_flow=0.0, connected_h_b=snapshot.p4_port1_next_primary_chamber.h, internal_h=snapshot.p4_port1_next_primary_chamber.h, ) ) p4_port1_remote_orifice_derivative_1, p4_port1_remote_orifice_derivative_2 = ( self.components.p4_port1_remote_orifice_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port1_remote_node_to_orifice_line_flow, connected_h_1=snapshot.p4_port1_remote_orifice_line_port_1.h, port_2_m_flow=-snapshot.p4_port1_remote_orifice_to_node_flow, connected_h_2=snapshot.p4_port1_remote_primary_line.h, ) ) p4_port3_derivative = self.components.p4_port3_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port3_remote_node_to_line_flow, connected_h_1=snapshot.p4_port3_remote_primary_line.h, port_2_m_flow=snapshot.p4_to_port3_line_flow, connected_h_2=snapshot.p4_primary_line.h, ) p4_port3_remote_primary_derivative = ( self.components.p4_port3_remote_primary_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port3_remote_chamber_to_line_flow, connected_h_1=snapshot.p4_port3_remote_primary_chamber.h, port_2_m_flow=snapshot.p4_port3_remote_node_to_primary_line_flow, connected_h_2=snapshot.p4_port3_remote_primary_line.h, ) ) p4_port3_remote_chamber_derivative = ( self.components.p4_port3_remote_primary_chamber.derivatives_from_two_connections( port_a_m_flow=-snapshot.p4_port3_remote_chamber_to_line_flow, connected_h_a=snapshot.p4_port3_remote_primary_line.h, port_b_m_flow=0.0, connected_h_b=snapshot.p4_port3_remote_primary_chamber.h, internal_h=snapshot.p4_port3_remote_primary_chamber.h, ) ) p4_port3_remote_port3_derivative = ( self.components.p4_port3_remote_port3_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port3_far_node_to_line_flow, connected_h_1=snapshot.p4_port3_far_primary_line.h, port_2_m_flow=snapshot.p4_port3_remote_to_port3_line_flow, connected_h_2=snapshot.p4_port3_remote_primary_line.h, ) ) p4_port3_far_primary_derivative = ( self.components.p4_port3_far_primary_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port3_far_chamber_to_line_flow, connected_h_1=snapshot.p4_port3_far_primary_chamber.h, port_2_m_flow=snapshot.p4_port3_far_node_to_primary_line_flow, connected_h_2=snapshot.p4_port3_far_primary_line.h, ) ) p4_port3_far_chamber_derivative = ( self.components.p4_port3_far_primary_chamber.derivatives_from_two_connections( port_a_m_flow=-snapshot.p4_port3_far_chamber_to_line_flow, connected_h_a=snapshot.p4_port3_far_primary_line.h, port_b_m_flow=0.0, connected_h_b=snapshot.p4_port3_far_primary_chamber.h, internal_h=snapshot.p4_port3_far_primary_chamber.h, ) ) p4_port3_far_port3_derivative = ( self.components.p4_port3_far_port3_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port3_next_node_to_line_flow, connected_h_1=snapshot.p4_port3_next_primary_line.h, port_2_m_flow=snapshot.p4_port3_far_to_next_line_flow, connected_h_2=snapshot.p4_port3_far_primary_line.h, ) ) p4_port3_next_primary_derivative = ( self.components.p4_port3_next_primary_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port3_next_chamber_to_line_flow, connected_h_1=snapshot.p4_port3_next_primary_chamber.h, port_2_m_flow=snapshot.p4_port3_next_node_to_primary_line_flow, connected_h_2=snapshot.p4_port3_next_primary_line.h, ) ) p4_port3_next_chamber_derivative = ( self.components.p4_port3_next_primary_chamber.derivatives_from_two_connections( port_a_m_flow=-snapshot.p4_port3_next_chamber_to_line_flow, connected_h_a=snapshot.p4_port3_next_primary_line.h, port_b_m_flow=0.0, connected_h_b=snapshot.p4_port3_next_primary_chamber.h, internal_h=snapshot.p4_port3_next_primary_chamber.h, ) ) ( p4_port3_remote_resistance_derivative_1, p4_port3_remote_resistance_derivative_2, ) = self.components.p4_port3_remote_resistance_node_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port3_remote_resistance_node_to_line_flow, connected_h_1=snapshot.p4_port3_remote_resistance_node_line_port_1.h, port_2_m_flow=-snapshot.p4_port3_remote_resistance_to_p4_flow, connected_h_2=snapshot.p4_port3_far_primary_line.h, ) p4_port3_remote_orifice_derivative_1, p4_port3_remote_orifice_derivative_2 = ( self.components.p4_port3_remote_orifice_line.derivatives_from_connections( port_1_m_flow=snapshot.p4_port3_remote_node_to_orifice_line_flow, connected_h_1=snapshot.p4_port3_remote_orifice_line_port_1.h, port_2_m_flow=-snapshot.p4_port3_remote_orifice_to_node_flow, connected_h_2=snapshot.p4_port3_remote_primary_line.h, ) ) return [ *inlet_derivative.as_vector(), *chamber_derivative.as_vector(), *outlet_derivative.as_vector(), *node_line_derivative_1.as_vector(), *node_line_derivative_2.as_vector(), *p4_primary_derivative.as_vector(), *p4_primary_chamber_derivative.as_vector(), *p4_port1_derivative.as_vector(), *p4_port1_remote_primary_derivative.as_vector(), *p4_port1_remote_chamber_derivative.as_vector(), *p4_port1_remote_port1_derivative.as_vector(), *p4_port1_far_primary_derivative.as_vector(), *p4_port1_far_chamber_derivative.as_vector(), *p4_port1_far_port1_derivative.as_vector(), *p4_port1_next_primary_derivative.as_vector(), *p4_port1_next_chamber_derivative.as_vector(), *p4_port1_remote_orifice_derivative_1.as_vector(), *p4_port1_remote_orifice_derivative_2.as_vector(), *p4_port3_derivative.as_vector(), *p4_port3_remote_primary_derivative.as_vector(), *p4_port3_remote_chamber_derivative.as_vector(), *p4_port3_remote_port3_derivative.as_vector(), *p4_port3_far_primary_derivative.as_vector(), *p4_port3_far_chamber_derivative.as_vector(), *p4_port3_far_port3_derivative.as_vector(), *p4_port3_next_primary_derivative.as_vector(), *p4_port3_next_chamber_derivative.as_vector(), *p4_port3_remote_resistance_derivative_1.as_vector(), *p4_port3_remote_resistance_derivative_2.as_vector(), *p4_port3_remote_orifice_derivative_1.as_vector(), *p4_port3_remote_orifice_derivative_2.as_vector(), ] @dataclass(frozen=True) class TestMqlPneumaticBranchComponents: name: str upstream_volume: AmesimPneumaticVolume orifice: AmesimPneumaticOrifice downstream_volume: AmesimPneumaticVolume spec: TestMqlPneumaticBranchSpec | None = None @dataclass(frozen=True) class TestMqlPneumaticBranchState: name: str upstream: ThermodynamicProperties downstream: ThermodynamicProperties flow: float upstream_inlet_h: float downstream_inlet_h: float @dataclass(frozen=True) class TestMqlPneumaticSnapshot: branch: TestMqlPneumaticBranchState @property def flow(self) -> float: return self.branch.flow @property def upstream(self) -> ThermodynamicProperties: return self.branch.upstream @property def downstream(self) -> ThermodynamicProperties: return self.branch.downstream class TestMqlPneumaticClosure: """Minimal test_mql pneumatic closure following the existing Testmodel pattern. The canonical branch flow is positive from ``upstream_volume`` through the orifice port_a/port_b into ``downstream_volume``. Port ``m_flow`` values are written with Modelica-style signs: positive means flow into that component. """ def __init__( self, *, components: TestMqlPneumaticBranchComponents, initial_state_vector: Callable[[], list[float]], apply_state_vector: Callable[[list[float]], None], ) -> None: self.components = components self._initial_state_vector = initial_state_vector self._apply_state_vector = apply_state_vector def initial_state_vector(self) -> list[float]: return self._initial_state_vector() def apply_state_vector(self, values: list[float]) -> None: self._apply_state_vector(values) def snapshot( self, state_vector: list[float] | None = None, ) -> TestMqlPneumaticSnapshot: if state_vector is not None: self._apply_state_vector(state_vector) upstream = self.components.upstream_volume.properties() downstream = self.components.downstream_volume.properties() flow = self._solve_branch_flow(upstream, downstream) upstream_inlet_h = self.components.upstream_volume.connection_inlet_enthalpy( port_m_flow=-flow, connected_h=downstream.h, internal_h=upstream.h, ) downstream_inlet_h = self.components.downstream_volume.connection_inlet_enthalpy( port_m_flow=flow, connected_h=upstream.h, internal_h=downstream.h, ) branch = TestMqlPneumaticBranchState( name=self.components.name, upstream=upstream, downstream=downstream, flow=flow, upstream_inlet_h=upstream_inlet_h, downstream_inlet_h=downstream_inlet_h, ) self._write_port_states(branch) return TestMqlPneumaticSnapshot(branch=branch) def _solve_branch_flow( self, upstream: ThermodynamicProperties, downstream: ThermodynamicProperties, ) -> float: upstream_temperature = upstream.T if upstream.p >= downstream.p else downstream.T return self.components.orifice.mass_flow( upstream.p, downstream.p, upstream_temperature, ) def _write_port_states(self, branch: TestMqlPneumaticBranchState) -> None: upstream_volume = self.components.upstream_volume downstream_volume = self.components.downstream_volume orifice = self.components.orifice upstream_volume.port_a.p = branch.upstream.p upstream_volume.port_a.m_flow = -branch.flow upstream_volume.port_a.h_outflow = branch.upstream.h orifice.port_a.p = branch.upstream.p orifice.port_a.m_flow = branch.flow orifice.port_a.h_outflow = branch.upstream.h orifice.port_b.p = branch.downstream.p orifice.port_b.m_flow = -branch.flow orifice.port_b.h_outflow = branch.downstream.h downstream_volume.port_a.p = branch.downstream.p downstream_volume.port_a.m_flow = branch.flow downstream_volume.port_a.h_outflow = branch.downstream.h def branch_derivatives( self, snapshot: TestMqlPneumaticSnapshot, ) -> tuple[VolumeState, VolumeState]: flow = snapshot.flow upstream_derivative = self.components.upstream_volume.derivatives( inlet_h=snapshot.branch.upstream_inlet_h, m_flow=-flow, ) downstream_derivative = self.components.downstream_volume.derivatives( inlet_h=snapshot.branch.downstream_inlet_h, m_flow=flow, ) return upstream_derivative, downstream_derivative def rhs(self, state_vector: list[float]) -> list[float]: snapshot = self.snapshot(state_vector) upstream_derivative, downstream_derivative = self.branch_derivatives(snapshot) return [ *upstream_derivative.as_vector(), *downstream_derivative.as_vector(), ] class TestMqlPneumaticChamberSegmentClosure: """Boundary-reduced fixed chamber segment discovered from AMESim topology. The two PNL0001 lines remain prescribed boundary interfaces in this first closure. Their aliases are retained in the spec so line dynamics can be inserted later without rediscovering the component path. """ def __init__( self, *, components: TestMqlPneumaticChamberSegmentComponents, inlet_boundary: TestMqlPneumaticBoundaryCondition, outlet_boundary: TestMqlPneumaticBoundaryCondition, ) -> None: self.components = components self.inlet_boundary = inlet_boundary self.outlet_boundary = outlet_boundary def initial_state_vector(self) -> list[float]: return self.components.volume.get_state_vector() def apply_state_vector(self, values: list[float]) -> None: if len(values) != 2: raise ValueError("single-chamber segment state vector requires two values") self.components.volume.set_state_vector(values) def snapshot( self, state_vector: list[float] | None = None, ) -> TestMqlPneumaticChamberSegmentSnapshot: if state_vector is not None: self.apply_state_vector(state_vector) chamber = self.components.volume.properties() inlet_boundary = self.inlet_boundary.properties(self.components.volume.gas) outlet_boundary = self.outlet_boundary.properties(self.components.volume.gas) inlet_temperature = ( inlet_boundary.T if inlet_boundary.p >= chamber.p else chamber.T ) outlet_temperature = ( chamber.T if chamber.p >= outlet_boundary.p else outlet_boundary.T ) inlet_flow = self.components.inlet_orifice.mass_flow( inlet_boundary.p, chamber.p, inlet_temperature, ) outlet_flow = self.components.outlet_orifice.mass_flow( chamber.p, outlet_boundary.p, outlet_temperature, ) snapshot = TestMqlPneumaticChamberSegmentSnapshot( chamber=chamber, inlet_boundary=inlet_boundary, outlet_boundary=outlet_boundary, inlet_flow=inlet_flow, outlet_flow=outlet_flow, ) self._write_port_states(snapshot) return snapshot @staticmethod def _port( component: AmesimPneumaticVolume | AmesimPneumaticOrifice, port_name: str, ) -> PortState: if port_name == "port_1": return component.port_a if port_name == "port_2": return component.port_b raise ValueError(f"unsupported pneumatic port: {port_name}") def _write_port_states( self, snapshot: TestMqlPneumaticChamberSegmentSnapshot, ) -> None: spec = self.components.spec chamber = self.components.volume inlet_orifice = self.components.inlet_orifice outlet_orifice = self.components.outlet_orifice inlet_boundary_port = self._port( inlet_orifice, spec.inlet_orifice_boundary_port, ) inlet_volume_port = self._port(inlet_orifice, spec.inlet_orifice_volume_port) inlet_boundary_port.p = snapshot.inlet_boundary.p inlet_boundary_port.m_flow = snapshot.inlet_flow inlet_boundary_port.h_outflow = snapshot.inlet_boundary.h inlet_volume_port.p = snapshot.chamber.p inlet_volume_port.m_flow = -snapshot.inlet_flow inlet_volume_port.h_outflow = snapshot.chamber.h chamber_inlet_port = self._port(chamber, spec.volume_inlet_port) chamber_outlet_port = self._port(chamber, spec.volume_outlet_port) chamber_inlet_port.m_flow = snapshot.inlet_flow chamber_outlet_port.m_flow = -snapshot.outlet_flow outlet_volume_port = self._port( outlet_orifice, spec.outlet_orifice_volume_port, ) outlet_boundary_port = self._port( outlet_orifice, spec.outlet_orifice_boundary_port, ) outlet_volume_port.p = snapshot.chamber.p outlet_volume_port.m_flow = snapshot.outlet_flow outlet_volume_port.h_outflow = snapshot.chamber.h outlet_boundary_port.p = snapshot.outlet_boundary.p outlet_boundary_port.m_flow = -snapshot.outlet_flow outlet_boundary_port.h_outflow = snapshot.outlet_boundary.h def rhs(self, state_vector: list[float]) -> list[float]: snapshot = self.snapshot(state_vector) spec = self.components.spec chamber = self.components.volume derivative = chamber.derivatives_from_two_connections( port_a_m_flow=self._port(chamber, "port_1").m_flow, connected_h_a=( snapshot.inlet_boundary.h if spec.volume_inlet_port == "port_1" else snapshot.outlet_boundary.h ), port_b_m_flow=self._port(chamber, "port_2").m_flow, connected_h_b=( snapshot.inlet_boundary.h if spec.volume_inlet_port == "port_2" else snapshot.outlet_boundary.h ), internal_h=snapshot.chamber.h, ) return derivative.as_vector() class TestMqlPnl0001ChamberSegmentClosure: """Fixed chamber segment with the topology-derived inlet PNL0001 state. The inlet line has a closed causal boundary here: port-1 pressure and temperature come from the PN3 node boundary, while port-2 flow comes from the fixed orifice. The outlet line remains a boundary until its three-line PN3 node balance is assembled. """ def __init__( self, *, components: TestMqlPnl0001ChamberSegmentComponents, inlet_node: TestMqlPneumaticBoundaryCondition, outlet_boundary: TestMqlPneumaticBoundaryCondition, ) -> None: self.components = components self.inlet_node = inlet_node self.outlet_boundary = outlet_boundary def initial_state_vector(self) -> list[float]: return [ *self.components.inlet_line.get_state_vector(), *self.components.volume.get_state_vector(), ] def apply_state_vector(self, values: list[float]) -> None: if len(values) != 4: raise ValueError("PNL0001/chamber segment state vector requires four values") self.components.inlet_line.set_state_vector(values[:2]) self.components.volume.set_state_vector(values[2:]) def snapshot( self, state_vector: list[float] | None = None, ) -> TestMqlPnl0001ChamberSegmentSnapshot: if state_vector is not None: self.apply_state_vector(state_vector) line = self.components.inlet_line.properties() chamber = self.components.volume.properties() inlet_node = self.inlet_node.properties(self.components.inlet_line.gas) outlet_boundary = self.outlet_boundary.properties(self.components.volume.gas) node_to_line_flow = self.components.inlet_line.resistance_mass_flow( port_1_pressure_pa=inlet_node.p, port_1_temperature_k=inlet_node.T, ) inlet_temperature = line.T if line.p >= chamber.p else chamber.T line_to_chamber_flow = self.components.inlet_orifice.mass_flow( line.p, chamber.p, inlet_temperature, ) outlet_temperature = ( chamber.T if chamber.p >= outlet_boundary.p else outlet_boundary.T ) outlet_flow = self.components.outlet_orifice.mass_flow( chamber.p, outlet_boundary.p, outlet_temperature, ) snapshot = TestMqlPnl0001ChamberSegmentSnapshot( inlet_line=line, chamber=chamber, inlet_node=inlet_node, outlet_boundary=outlet_boundary, node_to_line_flow=node_to_line_flow, line_to_chamber_flow=line_to_chamber_flow, outlet_flow=outlet_flow, ) self._write_port_states(snapshot) return snapshot @staticmethod def _line_to_p4_flow( *, line: ThermodynamicProperties, p4_boundary: ThermodynamicProperties, orifice: AmesimPneumaticOrifice, ) -> float: upstream_temperature = line.T if line.p >= p4_boundary.p else p4_boundary.T return orifice.mass_flow(line.p, p4_boundary.p, upstream_temperature) @staticmethod def _port( component: AmesimPneumaticVolume | AmesimPneumaticOrifice, port_name: str, ) -> PortState: return TestMqlPneumaticChamberSegmentClosure._port(component, port_name) def _write_port_states( self, snapshot: TestMqlPnl0001ChamberSegmentSnapshot, ) -> None: spec = self.components.spec line = self.components.inlet_line chamber = self.components.volume inlet_orifice = self.components.inlet_orifice outlet_orifice = self.components.outlet_orifice line.port_1.p = snapshot.inlet_node.p line.port_1.m_flow = snapshot.node_to_line_flow line.port_1.h_outflow = snapshot.inlet_line.h line.port_2.p = snapshot.inlet_line.p line.port_2.m_flow = -snapshot.line_to_chamber_flow inlet_boundary_port = self._port( inlet_orifice, spec.inlet_orifice_boundary_port, ) inlet_volume_port = self._port(inlet_orifice, spec.inlet_orifice_volume_port) inlet_boundary_port.p = snapshot.inlet_line.p inlet_boundary_port.m_flow = snapshot.line_to_chamber_flow inlet_boundary_port.h_outflow = snapshot.inlet_line.h inlet_volume_port.p = snapshot.chamber.p inlet_volume_port.m_flow = -snapshot.line_to_chamber_flow inlet_volume_port.h_outflow = snapshot.chamber.h chamber_inlet_port = self._port(chamber, spec.volume_inlet_port) chamber_outlet_port = self._port(chamber, spec.volume_outlet_port) chamber_inlet_port.m_flow = snapshot.line_to_chamber_flow chamber_outlet_port.m_flow = -snapshot.outlet_flow outlet_volume_port = self._port( outlet_orifice, spec.outlet_orifice_volume_port, ) outlet_boundary_port = self._port( outlet_orifice, spec.outlet_orifice_boundary_port, ) outlet_volume_port.p = snapshot.chamber.p outlet_volume_port.m_flow = snapshot.outlet_flow outlet_volume_port.h_outflow = snapshot.chamber.h outlet_boundary_port.p = snapshot.outlet_boundary.p outlet_boundary_port.m_flow = -snapshot.outlet_flow outlet_boundary_port.h_outflow = snapshot.outlet_boundary.h def rhs(self, state_vector: list[float]) -> list[float]: snapshot = self.snapshot(state_vector) line_derivative = self.components.inlet_line.derivatives_from_connections( port_1_m_flow=snapshot.node_to_line_flow, connected_h_1=snapshot.inlet_node.h, port_2_m_flow=-snapshot.line_to_chamber_flow, connected_h_2=snapshot.chamber.h, ) chamber = self.components.volume spec = self.components.spec chamber_derivative = chamber.derivatives_from_two_connections( port_a_m_flow=self._port(chamber, "port_1").m_flow, connected_h_a=( snapshot.inlet_line.h if spec.volume_inlet_port == "port_1" else snapshot.outlet_boundary.h ), port_b_m_flow=self._port(chamber, "port_2").m_flow, connected_h_b=( snapshot.inlet_line.h if spec.volume_inlet_port == "port_2" else snapshot.outlet_boundary.h ), internal_h=snapshot.chamber.h, ) return [*line_derivative.as_vector(), *chamber_derivative.as_vector()] class TestMqlPnl0001PairChamberSegmentClosure: """Six-state fixed chamber segment with both PNL0001 compliance states. Generated C shows that both line instances receive ``t1/p1`` from their PN3 nodes and send their explicit ``t2/p2`` states to the fixed orifices. The reduced closure therefore prescribes node pressure/temperature at both resistive port-1 boundaries while keeping both line storage states native. """ def __init__( self, *, components: TestMqlPnl0001PairChamberSegmentComponents, inlet_node: TestMqlPneumaticBoundaryCondition, outlet_node: TestMqlPneumaticBoundaryCondition, ) -> None: self.components = components self.inlet_node = inlet_node self.outlet_node = outlet_node def initial_state_vector(self) -> list[float]: return [ *self.components.inlet_line.get_state_vector(), *self.components.volume.get_state_vector(), *self.components.outlet_line.get_state_vector(), ] def apply_state_vector(self, values: list[float]) -> None: if len(values) != 6: raise ValueError("PNL0001 pair/chamber state vector requires six values") self.components.inlet_line.set_state_vector(values[:2]) self.components.volume.set_state_vector(values[2:4]) self.components.outlet_line.set_state_vector(values[4:]) def snapshot( self, state_vector: list[float] | None = None, ) -> TestMqlPnl0001PairChamberSegmentSnapshot: if state_vector is not None: self.apply_state_vector(state_vector) inlet_line = self.components.inlet_line.properties() chamber = self.components.volume.properties() outlet_line = self.components.outlet_line.properties() inlet_node = self.inlet_node.properties(self.components.inlet_line.gas) outlet_node = self.outlet_node.properties(self.components.outlet_line.gas) inlet_node_to_line_flow = self.components.inlet_line.resistance_mass_flow( port_1_pressure_pa=inlet_node.p, port_1_temperature_k=inlet_node.T, ) outlet_node_to_line_flow = self.components.outlet_line.resistance_mass_flow( port_1_pressure_pa=outlet_node.p, port_1_temperature_k=outlet_node.T, ) inlet_line_to_chamber_flow = self._line_to_chamber_flow( line=inlet_line, chamber=chamber, orifice=self.components.inlet_orifice, ) outlet_line_to_chamber_flow = self._line_to_chamber_flow( line=outlet_line, chamber=chamber, orifice=self.components.outlet_orifice, ) snapshot = TestMqlPnl0001PairChamberSegmentSnapshot( inlet_line=inlet_line, chamber=chamber, outlet_line=outlet_line, inlet_node=inlet_node, outlet_node=outlet_node, inlet_node_to_line_flow=inlet_node_to_line_flow, inlet_line_to_chamber_flow=inlet_line_to_chamber_flow, outlet_node_to_line_flow=outlet_node_to_line_flow, outlet_line_to_chamber_flow=outlet_line_to_chamber_flow, ) self._write_port_states(snapshot) return snapshot @staticmethod def _line_to_chamber_flow( *, line: ThermodynamicProperties, chamber: ThermodynamicProperties, orifice: AmesimPneumaticOrifice, ) -> float: upstream_temperature = line.T if line.p >= chamber.p else chamber.T return orifice.mass_flow(line.p, chamber.p, upstream_temperature) @staticmethod def _line_to_p4_flow( *, line: ThermodynamicProperties, p4_boundary: ThermodynamicProperties, orifice: AmesimPneumaticOrifice, ) -> float: upstream_temperature = line.T if line.p >= p4_boundary.p else p4_boundary.T return orifice.mass_flow(line.p, p4_boundary.p, upstream_temperature) @staticmethod def _port( component: AmesimPneumaticVolume | AmesimPneumaticOrifice, port_name: str, ) -> PortState: return TestMqlPneumaticChamberSegmentClosure._port(component, port_name) def _write_port_states( self, snapshot: TestMqlPnl0001PairChamberSegmentSnapshot, ) -> None: spec = self.components.spec chamber = self.components.volume chamber_inlet_port = self._port(chamber, spec.volume_inlet_port) chamber_outlet_port = self._port(chamber, spec.volume_outlet_port) self._write_line_side( line=self.components.inlet_line, line_properties=snapshot.inlet_line, node_properties=snapshot.inlet_node, node_to_line_flow=snapshot.inlet_node_to_line_flow, line_to_chamber_flow=snapshot.inlet_line_to_chamber_flow, orifice=self.components.inlet_orifice, orifice_boundary_port=spec.inlet_orifice_boundary_port, orifice_volume_port=spec.inlet_orifice_volume_port, chamber_port=chamber_inlet_port, chamber_properties=snapshot.chamber, ) self._write_line_side( line=self.components.outlet_line, line_properties=snapshot.outlet_line, node_properties=snapshot.outlet_node, node_to_line_flow=snapshot.outlet_node_to_line_flow, line_to_chamber_flow=snapshot.outlet_line_to_chamber_flow, orifice=self.components.outlet_orifice, orifice_boundary_port=spec.outlet_orifice_boundary_port, orifice_volume_port=spec.outlet_orifice_volume_port, chamber_port=chamber_outlet_port, chamber_properties=snapshot.chamber, ) def _write_line_side( self, *, line: AmesimPnl0001Pipe, line_properties: ThermodynamicProperties, node_properties: ThermodynamicProperties, node_to_line_flow: float, line_to_chamber_flow: float, orifice: AmesimPneumaticOrifice, orifice_boundary_port: str, orifice_volume_port: str, chamber_port: PortState, chamber_properties: ThermodynamicProperties, ) -> None: line.port_1.p = node_properties.p line.port_1.m_flow = node_to_line_flow line.port_1.h_outflow = line_properties.h line.port_2.p = line_properties.p line.port_2.m_flow = -line_to_chamber_flow boundary_port = self._port(orifice, orifice_boundary_port) volume_port = self._port(orifice, orifice_volume_port) boundary_port.p = line_properties.p boundary_port.m_flow = line_to_chamber_flow boundary_port.h_outflow = line_properties.h volume_port.p = chamber_properties.p volume_port.m_flow = -line_to_chamber_flow volume_port.h_outflow = chamber_properties.h chamber_port.m_flow = line_to_chamber_flow def rhs(self, state_vector: list[float]) -> list[float]: snapshot = self.snapshot(state_vector) inlet_derivative = self.components.inlet_line.derivatives_from_connections( port_1_m_flow=snapshot.inlet_node_to_line_flow, connected_h_1=snapshot.inlet_node.h, port_2_m_flow=-snapshot.inlet_line_to_chamber_flow, connected_h_2=snapshot.chamber.h, ) outlet_derivative = self.components.outlet_line.derivatives_from_connections( port_1_m_flow=snapshot.outlet_node_to_line_flow, connected_h_1=snapshot.outlet_node.h, port_2_m_flow=-snapshot.outlet_line_to_chamber_flow, connected_h_2=snapshot.chamber.h, ) chamber = self.components.volume spec = self.components.spec chamber_derivative = chamber.derivatives_from_two_connections( port_a_m_flow=self._port(chamber, "port_1").m_flow, connected_h_a=( snapshot.inlet_line.h if spec.volume_inlet_port == "port_1" else snapshot.outlet_line.h ), port_b_m_flow=self._port(chamber, "port_2").m_flow, connected_h_b=( snapshot.inlet_line.h if spec.volume_inlet_port == "port_2" else snapshot.outlet_line.h ), internal_h=snapshot.chamber.h, ) return [ *inlet_derivative.as_vector(), *chamber_derivative.as_vector(), *outlet_derivative.as_vector(), ] class TestMqlPn3NodeChamberSegmentClosure: """Boundary-reduced chamber segment closed by one real PN3 node. ``pneumatic_88`` supplies the PN3 primary pressure/temperature from its port-1 compliance. The node has no storage, so the sum of the port-1 PNL00R flow and port-3 PNL0001 flow is written as the opposite port-1 flow into the PNL0003 state. """ def __init__( self, *, components: TestMqlPn3NodeChamberSegmentComponents, inlet_node: TestMqlPneumaticBoundaryCondition, resistance_boundary: TestMqlPneumaticBoundaryCondition, p4_boundary: TestMqlPneumaticBoundaryCondition, ) -> None: self.components = components self.inlet_node = inlet_node self.resistance_boundary = resistance_boundary self.p4_boundary = p4_boundary def initial_state_vector(self) -> list[float]: return [ *self.components.inlet_line.get_state_vector(), *self.components.volume.get_state_vector(), *self.components.outlet_line.get_state_vector(), *self.components.node_line.get_state_vector(), ] def apply_state_vector(self, values: list[float]) -> None: if len(values) != 10: raise ValueError("PN3 node/chamber segment state vector requires ten values") self.components.inlet_line.set_state_vector(values[:2]) self.components.volume.set_state_vector(values[2:4]) self.components.outlet_line.set_state_vector(values[4:6]) self.components.node_line.set_state_vector(values[6:]) def snapshot( self, state_vector: list[float] | None = None, ) -> TestMqlPn3NodeChamberSegmentSnapshot: if state_vector is not None: self.apply_state_vector(state_vector) inlet_line = self.components.inlet_line.properties() chamber = self.components.volume.properties() outlet_line = self.components.outlet_line.properties() node_line_port_1 = self.components.node_line.properties_1() node_line_port_2 = self.components.node_line.properties_2() inlet_node = self.inlet_node.properties(self.components.inlet_line.gas) resistance_boundary = self.resistance_boundary.properties( self.components.node_resistance.gas ) p4_boundary = self.p4_boundary.properties(self.components.node_line.gas) inlet_node_to_line_flow = self.components.inlet_line.resistance_mass_flow( port_1_pressure_pa=inlet_node.p, port_1_temperature_k=inlet_node.T, ) outlet_node_to_line_flow = self.components.outlet_line.resistance_mass_flow( port_1_pressure_pa=node_line_port_1.p, port_1_temperature_k=node_line_port_1.T, ) inlet_line_to_chamber_flow = self._line_to_chamber_flow( line=inlet_line, chamber=chamber, orifice=self.components.inlet_orifice, ) outlet_line_to_chamber_flow = self._line_to_chamber_flow( line=outlet_line, chamber=chamber, orifice=self.components.outlet_orifice, ) node_to_resistance_flow = self.components.node_resistance.mass_flow( port_1_pressure_pa=node_line_port_1.p, port_1_temperature_k=node_line_port_1.T, port_2_pressure_pa=resistance_boundary.p, port_2_temperature_k=resistance_boundary.T, ) node_balance = self.components.node.balance( port_2_temperature_k=node_line_port_1.T, port_2_pressure_pa=node_line_port_1.p, port_1_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=node_to_resistance_flow, node_h=node_line_port_1.h, connected_h=resistance_boundary.h, ), port_1_mass_flow_g_s=node_to_resistance_flow * 1.0e3, port_3_enthalpy_flow_w=self._enthalpy_flow_from_node( flow_kg_s=outlet_node_to_line_flow, node_h=node_line_port_1.h, connected_h=outlet_line.h, ), port_3_mass_flow_g_s=outlet_node_to_line_flow * 1.0e3, ) node_to_pnl0003_flow = -node_balance.port_2_mass_flow_g_s * 1.0e-3 pnl0003_center_flow = self.components.node_line.resistance_mass_flow() pnl0003_to_p4_flow = self._line_to_p4_flow( line=node_line_port_2, p4_boundary=p4_boundary, orifice=self.components.node_orifice, ) snapshot = TestMqlPn3NodeChamberSegmentSnapshot( inlet_line=inlet_line, chamber=chamber, outlet_line=outlet_line, node_line_port_1=node_line_port_1, node_line_port_2=node_line_port_2, inlet_node=inlet_node, resistance_boundary=resistance_boundary, p4_boundary=p4_boundary, node_balance=node_balance, inlet_node_to_line_flow=inlet_node_to_line_flow, inlet_line_to_chamber_flow=inlet_line_to_chamber_flow, outlet_node_to_line_flow=outlet_node_to_line_flow, outlet_line_to_chamber_flow=outlet_line_to_chamber_flow, node_to_resistance_flow=node_to_resistance_flow, node_to_pnl0003_flow=node_to_pnl0003_flow, pnl0003_center_flow=pnl0003_center_flow, pnl0003_to_p4_flow=pnl0003_to_p4_flow, ) self._write_port_states(snapshot) return snapshot @staticmethod def _line_to_chamber_flow( *, line: ThermodynamicProperties, chamber: ThermodynamicProperties, orifice: AmesimPneumaticOrifice, ) -> float: return TestMqlPnl0001PairChamberSegmentClosure._line_to_chamber_flow( line=line, chamber=chamber, orifice=orifice, ) @staticmethod def _line_to_p4_flow( *, line: ThermodynamicProperties, p4_boundary: ThermodynamicProperties, orifice: AmesimPneumaticOrifice, ) -> float: upstream_temperature = line.T if line.p >= p4_boundary.p else p4_boundary.T return orifice.mass_flow(line.p, p4_boundary.p, upstream_temperature) @staticmethod def _port( component: AmesimPneumaticVolume | AmesimPneumaticOrifice, port_name: str, ) -> PortState: return TestMqlPneumaticChamberSegmentClosure._port(component, port_name) @staticmethod def _enthalpy_flow_from_node( *, flow_kg_s: float, node_h: float, connected_h: float, ) -> float: return flow_kg_s * (node_h if flow_kg_s >= 0.0 else connected_h) def _write_port_states( self, snapshot: TestMqlPn3NodeChamberSegmentSnapshot, ) -> None: spec = self.components.spec chamber = self.components.volume chamber_inlet_port = self._port(chamber, spec.volume_inlet_port) chamber_outlet_port = self._port(chamber, spec.volume_outlet_port) TestMqlPnl0001PairChamberSegmentClosure._write_line_side( self, line=self.components.inlet_line, line_properties=snapshot.inlet_line, node_properties=snapshot.inlet_node, node_to_line_flow=snapshot.inlet_node_to_line_flow, line_to_chamber_flow=snapshot.inlet_line_to_chamber_flow, orifice=self.components.inlet_orifice, orifice_boundary_port=spec.inlet_orifice_boundary_port, orifice_volume_port=spec.inlet_orifice_volume_port, chamber_port=chamber_inlet_port, chamber_properties=snapshot.chamber, ) TestMqlPnl0001PairChamberSegmentClosure._write_line_side( self, line=self.components.outlet_line, line_properties=snapshot.outlet_line, node_properties=snapshot.node_line_port_1, node_to_line_flow=snapshot.outlet_node_to_line_flow, line_to_chamber_flow=snapshot.outlet_line_to_chamber_flow, orifice=self.components.outlet_orifice, orifice_boundary_port=spec.outlet_orifice_boundary_port, orifice_volume_port=spec.outlet_orifice_volume_port, chamber_port=chamber_outlet_port, chamber_properties=snapshot.chamber, ) node_line = self.components.node_line node_line.port_1.p = snapshot.node_line_port_1.p node_line.port_1.m_flow = snapshot.node_to_pnl0003_flow node_line.port_1.h_outflow = snapshot.node_line_port_1.h node_line.port_2.p = snapshot.node_line_port_2.p node_line.port_2.m_flow = -snapshot.pnl0003_to_p4_flow node_line.port_2.h_outflow = snapshot.node_line_port_2.h node_orifice = self.components.node_orifice node_orifice.port_a.p = snapshot.node_line_port_2.p node_orifice.port_a.m_flow = snapshot.pnl0003_to_p4_flow node_orifice.port_a.h_outflow = snapshot.node_line_port_2.h node_orifice.port_b.p = snapshot.p4_boundary.p node_orifice.port_b.m_flow = -snapshot.pnl0003_to_p4_flow node_orifice.port_b.h_outflow = snapshot.p4_boundary.h resistance = self.components.node_resistance resistance.port_1.p = snapshot.node_line_port_1.p resistance.port_1.m_flow = snapshot.node_to_resistance_flow resistance.port_1.h_outflow = snapshot.node_line_port_1.h resistance.port_2.p = snapshot.resistance_boundary.p resistance.port_2.m_flow = -snapshot.node_to_resistance_flow resistance.port_2.h_outflow = snapshot.resistance_boundary.h def rhs(self, state_vector: list[float]) -> list[float]: snapshot = self.snapshot(state_vector) inlet_derivative = self.components.inlet_line.derivatives_from_connections( port_1_m_flow=snapshot.inlet_node_to_line_flow, connected_h_1=snapshot.inlet_node.h, port_2_m_flow=-snapshot.inlet_line_to_chamber_flow, connected_h_2=snapshot.chamber.h, ) outlet_derivative = self.components.outlet_line.derivatives_from_connections( port_1_m_flow=snapshot.outlet_node_to_line_flow, connected_h_1=snapshot.node_line_port_1.h, port_2_m_flow=-snapshot.outlet_line_to_chamber_flow, connected_h_2=snapshot.chamber.h, ) chamber = self.components.volume spec = self.components.spec chamber_derivative = chamber.derivatives_from_two_connections( port_a_m_flow=self._port(chamber, "port_1").m_flow, connected_h_a=( snapshot.inlet_line.h if spec.volume_inlet_port == "port_1" else snapshot.outlet_line.h ), port_b_m_flow=self._port(chamber, "port_2").m_flow, connected_h_b=( snapshot.inlet_line.h if spec.volume_inlet_port == "port_2" else snapshot.outlet_line.h ), internal_h=snapshot.chamber.h, ) node_line_derivative_1, node_line_derivative_2 = ( self.components.node_line.derivatives_from_connections( port_1_m_flow=snapshot.node_to_pnl0003_flow, connected_h_1=snapshot.node_line_port_1.h, port_2_m_flow=-snapshot.pnl0003_to_p4_flow, connected_h_2=snapshot.p4_boundary.h, ) ) return [ *inlet_derivative.as_vector(), *chamber_derivative.as_vector(), *outlet_derivative.as_vector(), *node_line_derivative_1.as_vector(), *node_line_derivative_2.as_vector(), ]