diff --git a/PythonModels/systems/test_mql.py b/PythonModels/systems/test_mql.py index e9b216d..0d76f1b 100644 --- a/PythonModels/systems/test_mql.py +++ b/PythonModels/systems/test_mql.py @@ -4564,17 +4564,14 @@ class TestMqlSystem: resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, - p4_port1_remote_orifice_boundary_pressure_pa: float = 15.3e6, - p4_port1_remote_orifice_boundary_temperature_k: float = 293.15, - p4_port3_remote_orifice_boundary_pressure_pa: float = 15.3e6, - p4_port3_remote_orifice_boundary_temperature_k: float = 293.15, ): """Close a PN3 chamber segment through the adjacent real P4 node. The P4 primary pressure/temperature is supplied by the PNL0001 line on P4 port 2. Ports 1 and 3 use the adjacent PNL0002 center compliances. - The next P4 nodes contribute their primary PNL0001/chamber states; - PNVO upstream endpoints remain prescribed boundaries in this local closure. + The next P4 nodes contribute their primary PNL0001/chamber states, and + PNVO upstream endpoints are closed through their adjacent PN3/PNL0003 + subnets. """ from PythonModels.components.amesim_pneumatic import ( AmesimPneumaticOrifice, @@ -4586,6 +4583,28 @@ class TestMqlSystem: TestMqlPn3P4NodeChamberSegmentComponents, ) + def pnl0003_line_and_node_for_orifice(orifice_alias: str): + for line_spec in self.pnl0003_assembly.specs: + if ( + line_spec.target_component == orifice_alias + and line_spec.target_port == "port_3" + and line_spec.source_component in self.node3_assembly + ): + return ( + self.pnl0003_assembly.lines[line_spec.alias], + self.node3_assembly[line_spec.source_component], + ) + if ( + line_spec.source_component == orifice_alias + and line_spec.source_port == "port_3" + and line_spec.target_component in self.node3_assembly + ): + return ( + self.pnl0003_assembly.lines[line_spec.alias], + self.node3_assembly[line_spec.target_component], + ) + raise KeyError(f"No PN3/PNL0003 line attached to {orifice_alias}.port_3") + inlet_line = self.pnl0001_assembly.lines[spec.inlet_line_alias] outlet_line = self.pnl0001_assembly.lines[spec.outlet_line_alias] node_line_spec = self._pnl0003_spec_for_node_port( @@ -4658,6 +4677,12 @@ class TestMqlSystem: p4_port1_remote_orifice = self.pneumatic_assembly.variable_orifices[ p4_port1_remote_neighborhood.port_4.orifice_alias ] + ( + p4_port1_remote_orifice_line, + p4_port1_remote_orifice_node, + ) = pnl0003_line_and_node_for_orifice( + p4_port1_remote_neighborhood.port_4.orifice_alias + ) p4_port3_remote_neighborhood = self.p4_node_neighborhood( p4_neighborhood.port_3.remote_node_alias ) @@ -4691,6 +4716,16 @@ class TestMqlSystem: p4_port3_remote_orifice = self.pneumatic_assembly.variable_orifices[ p4_port3_remote_neighborhood.port_4.orifice_alias ] + ( + p4_port3_remote_orifice_line, + p4_port3_remote_orifice_node, + ) = pnl0003_line_and_node_for_orifice( + p4_port3_remote_neighborhood.port_4.orifice_alias + ) + p4_port3_remote_orifice_resistance = self._pnl00r_line_for_node_port( + p4_port3_remote_orifice_node.alias, + "port_3", + ) volume = self.network.components[spec.volume_alias] inlet_orifice = self.network.components[spec.inlet_orifice_alias] outlet_orifice = self.network.components[spec.outlet_orifice_alias] @@ -4744,6 +4779,8 @@ class TestMqlSystem: p4_port1_far_primary_line=p4_port1_far_primary_line, p4_port1_far_primary_chamber=p4_port1_far_primary_chamber, p4_port1_remote_orifice=p4_port1_remote_orifice, + p4_port1_remote_orifice_line=p4_port1_remote_orifice_line, + p4_port1_remote_orifice_node=p4_port1_remote_orifice_node, p4_port3_line=p4_port3_line, p4_port3_remote_node=p4_port3_remote_node, p4_port3_remote_primary_line=p4_port3_remote_primary_line, @@ -4753,6 +4790,9 @@ class TestMqlSystem: p4_port3_far_primary_line=p4_port3_far_primary_line, p4_port3_far_primary_chamber=p4_port3_far_primary_chamber, p4_port3_remote_orifice=p4_port3_remote_orifice, + p4_port3_remote_orifice_line=p4_port3_remote_orifice_line, + p4_port3_remote_orifice_node=p4_port3_remote_orifice_node, + p4_port3_remote_orifice_resistance=p4_port3_remote_orifice_resistance, volume=volume, inlet_orifice=inlet_orifice, outlet_orifice=outlet_orifice, @@ -4766,14 +4806,6 @@ class TestMqlSystem: pressure_pa=resistance_boundary_pressure_pa, temperature_k=resistance_boundary_temperature_k, ), - p4_port1_remote_orifice_boundary=TestMqlPneumaticBoundaryCondition( - pressure_pa=p4_port1_remote_orifice_boundary_pressure_pa, - temperature_k=p4_port1_remote_orifice_boundary_temperature_k, - ), - p4_port3_remote_orifice_boundary=TestMqlPneumaticBoundaryCondition( - pressure_pa=p4_port3_remote_orifice_boundary_pressure_pa, - temperature_k=p4_port3_remote_orifice_boundary_temperature_k, - ), ) def simulate_pn3_p4_node_chamber_segment_from_spec( @@ -4784,10 +4816,6 @@ class TestMqlSystem: resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, - p4_port1_remote_orifice_boundary_pressure_pa: float = 15.3e6, - p4_port1_remote_orifice_boundary_temperature_k: float = 293.15, - p4_port3_remote_orifice_boundary_pressure_pa: float = 15.3e6, - p4_port3_remote_orifice_boundary_temperature_k: float = 293.15, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): @@ -4797,18 +4825,6 @@ class TestMqlSystem: resistance_boundary_pressure_pa=resistance_boundary_pressure_pa, inlet_node_temperature_k=inlet_node_temperature_k, resistance_boundary_temperature_k=resistance_boundary_temperature_k, - p4_port1_remote_orifice_boundary_pressure_pa=( - p4_port1_remote_orifice_boundary_pressure_pa - ), - p4_port1_remote_orifice_boundary_temperature_k=( - p4_port1_remote_orifice_boundary_temperature_k - ), - p4_port3_remote_orifice_boundary_pressure_pa=( - p4_port3_remote_orifice_boundary_pressure_pa - ), - p4_port3_remote_orifice_boundary_temperature_k=( - p4_port3_remote_orifice_boundary_temperature_k - ), ) run_config = config or SolveIVPConfig(t_stop=1.0e-4, max_step=1.0e-5) return integrate_ode( diff --git a/PythonModels/systems/test_mql_closure.py b/PythonModels/systems/test_mql_closure.py index 74f4956..1bd9345 100644 --- a/PythonModels/systems/test_mql_closure.py +++ b/PythonModels/systems/test_mql_closure.py @@ -208,6 +208,8 @@ class TestMqlPn3P4NodeChamberSegmentComponents: p4_port1_far_primary_line: AmesimPnl0001Pipe p4_port1_far_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 @@ -217,6 +219,9 @@ class TestMqlPn3P4NodeChamberSegmentComponents: p4_port3_far_primary_line: AmesimPnl0001Pipe p4_port3_far_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 volume: AmesimPneumaticVolume inlet_orifice: AmesimPneumaticOrifice outlet_orifice: AmesimPneumaticOrifice @@ -239,22 +244,26 @@ class TestMqlPn3P4NodeChamberSegmentSnapshot: p4_port1_remote_port1_line: ThermodynamicProperties p4_port1_far_primary_line: ThermodynamicProperties p4_port1_far_primary_chamber: ThermodynamicProperties - p4_port1_remote_orifice_boundary: 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_remote_orifice_boundary: ThermodynamicProperties + p4_port3_remote_orifice_line_port_1: ThermodynamicProperties + p4_port3_remote_orifice_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_remote_orifice_node_balance: TestMqlPneumaticNode3Balance p4_port3_remote_balance: TestMqlPneumaticNode4Balance p4_port3_far_balance: TestMqlPneumaticNode4Balance + p4_port3_remote_orifice_node_balance: TestMqlPneumaticNode3Balance inlet_node_to_line_flow: float inlet_line_to_chamber_flow: float outlet_node_to_line_flow: float @@ -273,6 +282,8 @@ class TestMqlPn3P4NodeChamberSegmentSnapshot: 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_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 @@ -282,6 +293,9 @@ class TestMqlPn3P4NodeChamberSegmentSnapshot: 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_remote_node_to_orifice_line_flow: float + p4_port3_remote_node_to_resistance_flow: float + p4_port3_remote_orifice_line_center_flow: float p4_port3_remote_orifice_to_node_flow: float @@ -299,14 +313,10 @@ class TestMqlPn3P4NodeChamberSegmentClosure: components: TestMqlPn3P4NodeChamberSegmentComponents, inlet_node: TestMqlPneumaticBoundaryCondition, resistance_boundary: TestMqlPneumaticBoundaryCondition, - p4_port1_remote_orifice_boundary: TestMqlPneumaticBoundaryCondition, - p4_port3_remote_orifice_boundary: TestMqlPneumaticBoundaryCondition, ) -> None: self.components = components self.inlet_node = inlet_node self.resistance_boundary = resistance_boundary - self.p4_port1_remote_orifice_boundary = p4_port1_remote_orifice_boundary - self.p4_port3_remote_orifice_boundary = p4_port3_remote_orifice_boundary def initial_state_vector(self) -> list[float]: return [ @@ -322,17 +332,19 @@ class TestMqlPn3P4NodeChamberSegmentClosure: *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_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_remote_orifice_line.get_state_vector(), ] def apply_state_vector(self, values: list[float]) -> None: - if len(values) != 38: - raise ValueError("PN3/P4 node chamber segment state vector requires thirty-eight values") + if len(values) != 46: + raise ValueError("PN3/P4 node chamber segment state vector requires forty-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:6]) @@ -345,12 +357,14 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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_port3_line.set_state_vector(values[26:28]) - self.components.p4_port3_remote_primary_line.set_state_vector(values[28:30]) - self.components.p4_port3_remote_primary_chamber.set_state_vector(values[30:32]) - self.components.p4_port3_remote_port3_line.set_state_vector(values[32:34]) - self.components.p4_port3_far_primary_line.set_state_vector(values[34:36]) - self.components.p4_port3_far_primary_chamber.set_state_vector(values[36:]) + self.components.p4_port1_remote_orifice_line.set_state_vector(values[26:30]) + self.components.p4_port3_line.set_state_vector(values[30:32]) + self.components.p4_port3_remote_primary_line.set_state_vector(values[32:34]) + self.components.p4_port3_remote_primary_chamber.set_state_vector(values[34:36]) + self.components.p4_port3_remote_port3_line.set_state_vector(values[36:38]) + self.components.p4_port3_far_primary_line.set_state_vector(values[38:40]) + self.components.p4_port3_far_primary_chamber.set_state_vector(values[40:42]) + self.components.p4_port3_remote_orifice_line.set_state_vector(values[42:]) def snapshot( self, @@ -379,6 +393,12 @@ class TestMqlPn3P4NodeChamberSegmentClosure: p4_port1_far_primary_chamber = ( self.components.p4_port1_far_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() @@ -393,23 +413,19 @@ class TestMqlPn3P4NodeChamberSegmentClosure: p4_port3_far_primary_chamber = ( self.components.p4_port3_far_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() + ) inlet_node = self.inlet_node.properties(self.components.inlet_line.gas) resistance_boundary = self.resistance_boundary.properties( self.components.node_resistance.gas ) - p4_port1_remote_orifice_boundary = ( - self.p4_port1_remote_orifice_boundary.properties( - self.components.p4_port1_remote_orifice.gas - ) - ) - p4_port3_remote_orifice_boundary = ( - self.p4_port3_remote_orifice_boundary.properties( - self.components.p4_port3_remote_orifice.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, + 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, @@ -428,8 +444,8 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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, + 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, @@ -437,7 +453,7 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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, + 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( @@ -495,8 +511,23 @@ class TestMqlPn3P4NodeChamberSegmentClosure: port_1_temperature_k=p4_port1_far_primary_chamber.T, ) ) - p4_port1_remote_orifice_to_node_flow = self._boundary_to_p4_flow( - boundary=p4_port1_remote_orifice_boundary, + 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, ) @@ -534,8 +565,40 @@ class TestMqlPn3P4NodeChamberSegmentClosure: port_1_temperature_k=p4_port3_far_primary_chamber.T, ) ) - p4_port3_remote_orifice_to_node_flow = self._boundary_to_p4_flow( - boundary=p4_port3_remote_orifice_boundary, + 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=inlet_node.p, + port_2_temperature_k=inlet_node.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=inlet_node.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_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, ) @@ -579,7 +642,7 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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_boundary.h, + 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, @@ -587,6 +650,20 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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, @@ -621,7 +698,7 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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_boundary.h, + 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, @@ -662,22 +739,26 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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_remote_orifice_boundary=p4_port1_remote_orifice_boundary, + 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_remote_orifice_boundary=p4_port3_remote_orifice_boundary, + 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, 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_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_remote_orifice_node_balance=p4_port3_remote_orifice_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, @@ -700,6 +781,12 @@ class TestMqlPn3P4NodeChamberSegmentClosure: p4_port1_far_node_to_primary_line_flow=( p4_port1_far_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, @@ -713,6 +800,15 @@ class TestMqlPn3P4NodeChamberSegmentClosure: p4_port3_far_node_to_primary_line_flow=( p4_port3_far_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_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) @@ -778,7 +874,61 @@ class TestMqlPn3P4NodeChamberSegmentClosure: self, snapshot: TestMqlPn3P4NodeChamberSegmentSnapshot, ) -> None: - TestMqlPn3NodeChamberSegmentClosure._write_port_states(self, snapshot) + 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 @@ -853,10 +1003,18 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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_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_boundary.p + 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_boundary.h + 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 @@ -921,17 +1079,69 @@ class TestMqlPn3P4NodeChamberSegmentClosure: 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_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.inlet_node.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.inlet_node.h + p4_port3_remote_orifice = self.components.p4_port3_remote_orifice - p4_port3_remote_orifice.port_a.p = snapshot.p4_port3_remote_orifice_boundary.p + 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_boundary.h + 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) - base_rhs = TestMqlPn3NodeChamberSegmentClosure.rhs(self, state_vector)[:10] + 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, @@ -955,12 +1165,6 @@ class TestMqlPn3P4NodeChamberSegmentClosure: port_2_m_flow=snapshot.p4_port1_remote_node_to_line_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_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, @@ -1003,6 +1207,20 @@ class TestMqlPn3P4NodeChamberSegmentClosure: internal_h=snapshot.p4_port1_far_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, @@ -1045,8 +1263,20 @@ class TestMqlPn3P4NodeChamberSegmentClosure: internal_h=snapshot.p4_port3_far_primary_chamber.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 [ - *base_rhs, + *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(), @@ -1055,12 +1285,16 @@ class TestMqlPn3P4NodeChamberSegmentClosure: *p4_port1_remote_port1_derivative.as_vector(), *p4_port1_far_primary_derivative.as_vector(), *p4_port1_far_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_remote_orifice_derivative_1.as_vector(), + *p4_port3_remote_orifice_derivative_2.as_vector(), ] diff --git a/tests/test_test_mql_pnl0001_segment.py b/tests/test_test_mql_pnl0001_segment.py index b9c5fb8..7d0c240 100644 --- a/tests/test_test_mql_pnl0001_segment.py +++ b/tests/test_test_mql_pnl0001_segment.py @@ -292,6 +292,14 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase): closure.components.p4_port1_remote_orifice.name, "pn_morifice_10", ) + self.assertEqual( + closure.components.p4_port1_remote_orifice_line.name, + "pneumatic_75", + ) + self.assertEqual( + closure.components.p4_port1_remote_orifice_node.alias, + "pn_node3_10", + ) self.assertEqual(closure.components.p4_port3_line.name, "pneumatic_83") self.assertEqual(closure.components.p4_port3_remote_node.alias, "pnnode4_16") self.assertEqual( @@ -319,8 +327,20 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase): closure.components.p4_port3_remote_orifice.name, "pn_morifice_1", ) - self.assertEqual(len(closure.initial_state_vector()), 38) - self.assertEqual(len(rhs), 38) + self.assertEqual( + closure.components.p4_port3_remote_orifice_line.name, + "pneumatic_87", + ) + self.assertEqual( + closure.components.p4_port3_remote_orifice_node.alias, + "pn_node3_8", + ) + self.assertEqual( + closure.components.p4_port3_remote_orifice_resistance.name, + "pneumatic_105", + ) + self.assertEqual(len(closure.initial_state_vector()), 46) + self.assertEqual(len(rhs), 46) self.assertAlmostEqual( snapshot.p4_balance.pressure_pa, snapshot.p4_primary_line.p, @@ -375,6 +395,14 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase): closure.components.p4_port1_remote_orifice.name, port1_remote_neighborhood.port_4.orifice_alias, ) + self.assertEqual( + closure.components.p4_port1_remote_orifice_line.name, + self.system._pnl0003_line_for_node_port("pn_node3_10", "port_2").name, + ) + self.assertEqual( + closure.components.p4_port1_remote_orifice_node.alias, + "pn_node3_10", + ) self.assertEqual( closure.components.p4_port3_line.name, neighborhood.port_3.line_alias, @@ -404,6 +432,18 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase): closure.components.p4_port3_remote_orifice.name, port3_remote_neighborhood.port_4.orifice_alias, ) + self.assertEqual( + closure.components.p4_port3_remote_orifice_line.name, + self.system._pnl0003_line_for_node_port("pn_node3_8", "port_2").name, + ) + self.assertEqual( + closure.components.p4_port3_remote_orifice_node.alias, + "pn_node3_8", + ) + self.assertEqual( + closure.components.p4_port3_remote_orifice_resistance.name, + self.system._pnl00r_line_for_node_port("pn_node3_8", "port_3").name, + ) self.assertEqual( closure.components.node_orifice.name, neighborhood.port_4.orifice_alias, @@ -455,6 +495,18 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase): 0.0, delta=1.0e-12, ) + self.assertAlmostEqual( + snapshot.p4_port1_remote_node_to_orifice_line_flow, + snapshot.node_to_resistance_flow, + delta=1.0e-12, + ) + self.assertAlmostEqual( + snapshot.p4_port3_remote_node_to_orifice_line_flow + + snapshot.inlet_node_to_line_flow + + snapshot.p4_port3_remote_node_to_resistance_flow, + 0.0, + delta=1.0e-12, + ) self.assertAlmostEqual( snapshot.p4_port3_remote_node_to_primary_line_flow + snapshot.p4_port3_remote_node_to_line_flow @@ -469,19 +521,14 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase): 0.0, delta=1.0e-12, ) - mass_derivative_sum = sum(rhs[index] for index in range(0, 38, 2)) + mass_derivative_sum = sum(rhs[index] for index in range(0, 46, 2)) self.assertAlmostEqual( mass_derivative_sum, - ( - snapshot.inlet_node_to_line_flow - - snapshot.node_to_resistance_flow - + snapshot.p4_port1_remote_orifice_to_node_flow - + snapshot.p4_port3_remote_orifice_to_node_flow - ), + -snapshot.p4_port3_remote_node_to_resistance_flow, delta=1.0e-12, ) - def test_simulates_thirty_eight_state_pn3_p4_node_chamber_segment(self) -> None: + def test_simulates_forty_six_state_pn3_p4_node_chamber_segment(self) -> None: solution = self.system.simulate_pn3_p4_node_chamber_segment_from_spec( self.spec, inlet_node_pressure_pa=15.31e6, @@ -496,8 +543,8 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase): self.assertTrue(solution.success) self.assertEqual(len(solution.t), 3) - self.assertEqual(len(solution.y), 38) - self.assertEqual([len(row) for row in solution.y], [3] * 38) + self.assertEqual(len(solution.y), 46) + self.assertEqual([len(row) for row in solution.y], [3] * 46) if __name__ == "__main__":