From a8a68f6dd4e4eb3b540bd723507e5c280ec2b0d7 Mon Sep 17 00:00:00 2001 From: huojiarong Date: Wed, 29 Jul 2026 08:38:37 +0000 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0test=5Fmql=20pneumatic=5F96?= =?UTF-8?q?=E5=B1=80=E9=83=A8=E5=8F=82=E8=80=83RHS=E5=80=99=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../run_test_mql_full_state_comparison.py | 52 ++++++++++++++- PythonModels/systems/test_mql.py | 8 +++ PythonModels/systems/test_mql_closure.py | 64 +++++++++++++++++++ ...test_run_test_mql_full_state_comparison.py | 6 ++ tests/test_test_mql_pnl0001_segment.py | 34 ++++++++++ 5 files changed, 162 insertions(+), 2 deletions(-) diff --git a/PythonModels/scripts/run_test_mql_full_state_comparison.py b/PythonModels/scripts/run_test_mql_full_state_comparison.py index 22905b1..e918afc 100644 --- a/PythonModels/scripts/run_test_mql_full_state_comparison.py +++ b/PythonModels/scripts/run_test_mql_full_state_comparison.py @@ -658,6 +658,10 @@ class TestMqlPneumatic96InletLineDiagnostic: python_reference_amesim_storage_pressure_derivative_temperature_component_pa_s: float python_reference_amesim_storage_pressure_derivative_eos_sum_pa_s: float python_reference_amesim_storage_pressure_derivative_eos_error_pa_s: float + python_active_temperature_derivative_k_s: float + python_active_temperature_derivative_error_k_s: float + python_active_pressure_derivative_eos_sum_pa_s: float + python_active_pressure_derivative_eos_error_pa_s: float python_chamber_pressure_error_pa: float python_chamber_temperature_error_k: float @@ -755,6 +759,7 @@ class TestMqlFullStateComparisonExecutionConfig: resistance_boundary_pressure_pa: float = 15.29e6 inlet_node_temperature_k: float = 293.15 resistance_boundary_temperature_k: float = 293.15 + use_pneumatic_96_reference_rhs: bool = False @dataclass(frozen=True) @@ -795,6 +800,9 @@ def run_test_mql_full_state_comparison( resistance_boundary_temperature_k=( config.execution.resistance_boundary_temperature_k ), + use_pneumatic_96_reference_rhs=( + config.execution.use_pneumatic_96_reference_rhs + ), config=config.execution.solver, t_eval=list(config.execution.t_eval) if config.execution.t_eval is not None else None, data_paths=selected_paths, @@ -809,6 +817,9 @@ def run_test_mql_full_state_comparison( resistance_boundary_temperature_k=( config.execution.resistance_boundary_temperature_k ), + use_pneumatic_96_reference_rhs=( + config.execution.use_pneumatic_96_reference_rhs + ), ) series_by_data_path = { data_path: result.series[data_path] @@ -885,6 +896,9 @@ def run_test_mql_pnvo_event_boundary_diagnostic( "resistance_boundary_temperature_k": ( config.execution.resistance_boundary_temperature_k ), + "use_pneumatic_96_reference_rhs": ( + config.execution.use_pneumatic_96_reference_rhs + ), } solution = system.simulate_full_state_from_spec( spec, @@ -2846,6 +2860,12 @@ def _pneumatic_96_inlet_line_diagnostic( + python_reference_amesim_storage_mass_offset_dtemp + python_heat_dtemp ) + use_reference_rhs = bool( + getattr(closure.pneumatic_closure, "use_inlet_line_reference_rhs", False) + ) + python_active_dtemp = ( + python_reference_dtemp if use_reference_rhs else python_current_dtemp + ) ( python_reference_amesim_storage_pressure_mass_component, python_reference_amesim_storage_pressure_temperature_component, @@ -3029,6 +3049,19 @@ def _pneumatic_96_inlet_line_diagnostic( python_reference_amesim_storage_pressure_derivative_eos_error_pa_s=( python_reference_amesim_storage_pressure_eos_sum - amesim_line_pressure_fd ), + python_active_temperature_derivative_k_s=python_active_dtemp, + python_active_temperature_derivative_error_k_s=( + python_active_dtemp - amesim_line_temperature_fd + ), + python_active_pressure_derivative_eos_sum_pa_s=( + python_reference_pressure_eos_sum + if use_reference_rhs + else python_pressure_eos_sum + ), + python_active_pressure_derivative_eos_error_pa_s=( + (python_reference_pressure_eos_sum if use_reference_rhs else python_pressure_eos_sum) + - amesim_line_pressure_fd + ), python_chamber_pressure_error_pa=( snapshot.chamber.p - amesim_chamber_pressure ), @@ -3228,6 +3261,9 @@ def run_test_mql_pnvo_event_window_diagnostic( "resistance_boundary_temperature_k": ( config.execution.resistance_boundary_temperature_k ), + "use_pneumatic_96_reference_rhs": ( + config.execution.use_pneumatic_96_reference_rhs + ), } closure = system.full_state_closure_from_spec(spec, **closure_kwargs) state_vector = closure.initial_state_vector() @@ -3750,6 +3786,10 @@ def format_test_mql_pnvo_event_window_summary( f"python_ref_amesim_storage_dP_T={inlet_line.python_reference_amesim_storage_pressure_derivative_temperature_component_pa_s}, " f"python_ref_amesim_storage_dP_sum={inlet_line.python_reference_amesim_storage_pressure_derivative_eos_sum_pa_s}, " f"python_ref_amesim_storage_dP_error={inlet_line.python_reference_amesim_storage_pressure_derivative_eos_error_pa_s}, " + f"python_active_dT={inlet_line.python_active_temperature_derivative_k_s}, " + f"python_active_dT_error={inlet_line.python_active_temperature_derivative_error_k_s}, " + f"python_active_dP_sum={inlet_line.python_active_pressure_derivative_eos_sum_pa_s}, " + f"python_active_dP_error={inlet_line.python_active_pressure_derivative_eos_error_pa_s}, " f"python_chamber_p_error={inlet_line.python_chamber_pressure_error_pa}, " f"python_chamber_t_error={inlet_line.python_chamber_temperature_error_k}" ) @@ -4216,13 +4256,21 @@ def main() -> None: type=Path, help="read AMESim observations from a separate .ame results package", ) + parser.add_argument( + "--pneumatic-96-reference-rhs", + action="store_true", + help="enable the local reference/mass-offset RHS candidate for pneumatic_96", + ) args = parser.parse_args() config = None - if args.amesim_results_archive is not None: + if args.amesim_results_archive is not None or args.pneumatic_96_reference_rhs: config = TestMqlFullStateComparisonScriptConfig( paths=TestMqlFullStateComparisonPathConfig( amesim_results_archive_path=args.amesim_results_archive, - ) + ), + execution=TestMqlFullStateComparisonExecutionConfig( + use_pneumatic_96_reference_rhs=args.pneumatic_96_reference_rhs, + ), ) if args.pnvo_event_boundary: diagnostic = run_test_mql_pnvo_event_boundary_diagnostic(config) diff --git a/PythonModels/systems/test_mql.py b/PythonModels/systems/test_mql.py index 258d4e7..506fc4c 100644 --- a/PythonModels/systems/test_mql.py +++ b/PythonModels/systems/test_mql.py @@ -4802,6 +4802,7 @@ class TestMqlSystem: resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, + use_pneumatic_96_reference_rhs: bool = False, ) -> TestMqlFullStateClosure: return TestMqlFullStateClosure( pneumatic_closure=self.pn3_p4_node_chamber_segment_closure_from_spec( @@ -4810,6 +4811,7 @@ 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, + use_inlet_line_reference_rhs=use_pneumatic_96_reference_rhs, ), mechanical_closure=self.mechanical_mass_closure(), pneumatic_assembly=self.pneumatic_assembly, @@ -4823,6 +4825,7 @@ class TestMqlSystem: resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, + use_pneumatic_96_reference_rhs: bool = False, config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, ): @@ -4832,6 +4835,7 @@ 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, + use_pneumatic_96_reference_rhs=use_pneumatic_96_reference_rhs, ) return integrate_ode( rhs=lambda t, state: closure.rhs_at(t, state), @@ -4851,6 +4855,7 @@ class TestMqlSystem: config: SolveIVPConfig | None = None, t_eval: list[float] | None = None, data_paths: tuple[str, ...] | list[str] | None = None, + use_pneumatic_96_reference_rhs: bool = False, ) -> TestMqlSimulationResult: closure = self.full_state_closure_from_spec( spec, @@ -4858,6 +4863,7 @@ 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, + use_pneumatic_96_reference_rhs=use_pneumatic_96_reference_rhs, ) solution = integrate_ode( rhs=lambda t, state: closure.rhs_at(t, state), @@ -5329,6 +5335,7 @@ class TestMqlSystem: resistance_boundary_pressure_pa: float, inlet_node_temperature_k: float = 293.15, resistance_boundary_temperature_k: float = 293.15, + use_inlet_line_reference_rhs: bool = False, ): """Close a PN3 chamber segment through the adjacent real P4 node. @@ -6074,6 +6081,7 @@ class TestMqlSystem: pressure_pa=resistance_boundary_pressure_pa, temperature_k=resistance_boundary_temperature_k, ), + use_inlet_line_reference_rhs=use_inlet_line_reference_rhs, ) def simulate_pn3_p4_node_chamber_segment_from_spec( diff --git a/PythonModels/systems/test_mql_closure.py b/PythonModels/systems/test_mql_closure.py index 6581a64..9a5cdca 100644 --- a/PythonModels/systems/test_mql_closure.py +++ b/PythonModels/systems/test_mql_closure.py @@ -490,10 +490,12 @@ class TestMqlPn3P4NodeChamberSegmentClosure: components: TestMqlPn3P4NodeChamberSegmentComponents, inlet_node: TestMqlPneumaticBoundaryCondition, resistance_boundary: TestMqlPneumaticBoundaryCondition, + use_inlet_line_reference_rhs: bool = False, ) -> None: self.components = components self.inlet_node = inlet_node self.resistance_boundary = resistance_boundary + self.use_inlet_line_reference_rhs = use_inlet_line_reference_rhs def initial_state_vector(self) -> list[float]: return [ @@ -2086,6 +2088,59 @@ class TestMqlPn3P4NodeChamberSegmentClosure: chamber.port_a.m_flow = -chamber_to_line_flow chamber.port_a.h_outflow = chamber_properties.h + @staticmethod + def _pnl0001_reference_enthalpy_derivative( + *, + line: AmesimPnl0001Pipe, + line_properties: ThermodynamicProperties, + port_1_properties: ThermodynamicProperties, + port_1_flow: float, + port_2_properties: ThermodynamicProperties, + port_2_flow: float, + reference_temperature_k: float = 298.15, + ) -> VolumeState: + def reference_enthalpy_flow( + *, + port_flow: float, + connected: ThermodynamicProperties, + ) -> float: + if port_flow > 0.0: + pressure = connected.p + temperature = connected.T + else: + pressure = line_properties.p + temperature = line_properties.T + return port_flow * line.gas.pressure_reference_enthalpy( + pressure, + temperature, + reference_temperature=reference_temperature_k, + ) + + mass_derivative = port_1_flow + port_2_flow + heat_flow = ( + line.heat_transfer_coefficient + * line.heat_transfer_area + * (line.external_temperature - line_properties.T) + ) + enthalpy_flow = reference_enthalpy_flow( + port_flow=port_1_flow, + connected=port_1_properties, + ) + reference_enthalpy_flow( + port_flow=port_2_flow, + connected=port_2_properties, + ) + reference_offset_flow = ( + line.gas.cp * reference_temperature_k - line.gas.cv * line_properties.T + ) * mass_derivative + temperature_derivative = ( + enthalpy_flow + reference_offset_flow + heat_flow + ) / (line.state.m * line.gas.cv) + return VolumeState( + m=mass_derivative, + U=line.gas.cv + * (line.state.m * temperature_derivative + line_properties.T * mass_derivative), + ) + @staticmethod def _primary_chamber_line_derivatives( *, @@ -2706,6 +2761,15 @@ class TestMqlPn3P4NodeChamberSegmentClosure: outlet_node_to_line_flow=snapshot.outlet_node_to_line_flow, outlet_line_to_chamber_flow=snapshot.outlet_line_to_chamber_flow, ) + if self.use_inlet_line_reference_rhs: + inlet_derivative = self._pnl0001_reference_enthalpy_derivative( + line=self.components.inlet_line, + line_properties=snapshot.inlet_line, + port_1_properties=snapshot.p4_port3_remote_orifice_line_port_1, + port_1_flow=snapshot.inlet_node_to_line_flow, + port_2_properties=snapshot.chamber, + port_2_flow=-snapshot.inlet_line_to_chamber_flow, + ) ( node_line_derivative_1, node_line_derivative_2, diff --git a/tests/test_run_test_mql_full_state_comparison.py b/tests/test_run_test_mql_full_state_comparison.py index 885c889..2b41dc8 100644 --- a/tests/test_run_test_mql_full_state_comparison.py +++ b/tests/test_run_test_mql_full_state_comparison.py @@ -599,6 +599,10 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase): python_reference_amesim_storage_pressure_derivative_eos_error_pa_s=( -27999648.2 ), + python_active_temperature_derivative_k_s=261.9, + python_active_temperature_derivative_error_k_s=112.4, + python_active_pressure_derivative_eos_sum_pa_s=-17267169.5, + python_active_pressure_derivative_eos_error_pa_s=568762.8, python_chamber_pressure_error_pa=11.9, python_chamber_temperature_error_k=0.1, ), @@ -786,6 +790,8 @@ class RunTestMqlFullStateComparisonScriptTests(unittest.TestCase): self.assertIn("python_ref_dP_error=-21955100.0", summary) self.assertIn("python_ref_amesim_storage_dT=-416.3", summary) self.assertIn("python_ref_amesim_storage_dP_error=-27999648.2", summary) + self.assertIn("python_active_dT=261.9", summary) + self.assertIn("python_active_dP_error=568762.8", summary) self.assertIn("pnl0003_energy@pneumatic_87", summary) self.assertIn("amesim_sdm1=-462.7", summary) self.assertIn("amesim_sdh2=3028.0", summary) diff --git a/tests/test_test_mql_pnl0001_segment.py b/tests/test_test_mql_pnl0001_segment.py index a1603ca..75ff8cd 100644 --- a/tests/test_test_mql_pnl0001_segment.py +++ b/tests/test_test_mql_pnl0001_segment.py @@ -744,6 +744,40 @@ class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase): + diagnostic.thermal_energy_flow_w, ) + def test_full_state_closure_can_enable_pneumatic_96_reference_rhs_candidate( + self, + ) -> None: + default_closure = self.system.full_state_closure_from_spec( + self.spec, + inlet_node_pressure_pa=15.31e6, + resistance_boundary_pressure_pa=15.29e6, + ) + candidate_closure = self.system.full_state_closure_from_spec( + self.spec, + inlet_node_pressure_pa=15.31e6, + resistance_boundary_pressure_pa=15.29e6, + use_pneumatic_96_reference_rhs=True, + ) + state = default_closure.initial_state_vector() + + default_rhs = default_closure.rhs_at(0.04, state) + candidate_rhs = candidate_closure.rhs_at(0.04, state) + snapshot = candidate_closure.snapshot_at(0.04, state).pneumatic + line = candidate_closure.pneumatic_closure.components.inlet_line + expected = candidate_closure.pneumatic_closure._pnl0001_reference_enthalpy_derivative( + line=line, + line_properties=snapshot.inlet_line, + port_1_properties=snapshot.p4_port3_remote_orifice_line_port_1, + port_1_flow=snapshot.inlet_node_to_line_flow, + port_2_properties=snapshot.chamber, + port_2_flow=-snapshot.inlet_line_to_chamber_flow, + ) + + self.assertAlmostEqual(candidate_rhs[0], default_rhs[0]) + self.assertAlmostEqual(candidate_rhs[0], expected.m) + self.assertAlmostEqual(candidate_rhs[1], expected.U) + self.assertNotAlmostEqual(candidate_rhs[1], default_rhs[1]) + def test_full_state_closure_applies_step_controls_to_variable_orifices(self) -> None: closure = self.system.full_state_closure_from_spec( self.spec,