From 314b65872e06394dc265d3bbacc45d2d1a9fb70b Mon Sep 17 00:00:00 2001 From: huojiarong Date: Thu, 16 Jul 2026 09:17:10 +0000 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5test=5Fmql=E7=9C=9F=E5=AE=9E?= =?UTF-8?q?=E6=B0=94=E5=8A=A8=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PythonModels/systems/test_mql.py | 79 ++++++++++++++++++++++++++++++- tests/test_test_mql_structural.py | 71 +++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) diff --git a/PythonModels/systems/test_mql.py b/PythonModels/systems/test_mql.py index d3857a6..5fce3ae 100644 --- a/PythonModels/systems/test_mql.py +++ b/PythonModels/systems/test_mql.py @@ -3858,8 +3858,13 @@ class TestMqlSystem: def __init__(self, archive_path: Path | None = None) -> None: self.archive_path = archive_path or Path(__file__).resolve().parents[2] / AMESIM_ARCHIVE_RELATIVE_PATH self.network = SimulationNetwork(name=MODEL_NAME) + self.pneumatic_assembly = self._build_pneumatic_assembly() + pneumatic_components = self._pneumatic_components_by_alias() for spec in COMPONENT_SPECS: - self.network.add_component(AmesimStructuralComponent(spec)) + alias = str(spec["alias"]) + self.network.add_component( + pneumatic_components.get(alias, AmesimStructuralComponent(spec)) + ) for spec in CONNECTION_SPECS: self.network.connect( str(spec["source_component"]), @@ -3868,6 +3873,78 @@ class TestMqlSystem: str(spec["target_port"]), ) + @staticmethod + def _build_pneumatic_assembly(): + # Local import avoids a module cycle: test_mql_config reads constants from this module. + from PythonModels.systems.test_mql_pneumatic import build_test_mql_pneumatic_assembly + + return build_test_mql_pneumatic_assembly() + + def _pneumatic_components_by_alias(self) -> dict[str, Component]: + return { + **self.pneumatic_assembly.fixed_chambers, + **self.pneumatic_assembly.variable_chambers, + **self.pneumatic_assembly.fixed_orifices, + **self.pneumatic_assembly.variable_orifices, + } + + @property + def typed_pneumatic_component_count(self) -> int: + return len(self._pneumatic_components_by_alias()) + + def pneumatic_state_vector(self) -> list[float]: + return self.network.initial_state_vector() + + def pneumatic_branch_closure( + self, + *, + name: str, + upstream_volume_alias: str, + orifice_alias: str, + downstream_volume_alias: str, + ): + from PythonModels.components.amesim_pneumatic import ( + AmesimPneumaticOrifice, + AmesimPneumaticVolume, + ) + from PythonModels.systems.test_mql_closure import ( + TestMqlPneumaticBranchComponents, + TestMqlPneumaticClosure, + ) + + upstream_volume = self.network.components[upstream_volume_alias] + orifice = self.network.components[orifice_alias] + downstream_volume = self.network.components[downstream_volume_alias] + if not isinstance(upstream_volume, AmesimPneumaticVolume): + raise TypeError(f"{upstream_volume_alias} is not an AMESim pneumatic volume") + if not isinstance(downstream_volume, AmesimPneumaticVolume): + raise TypeError(f"{downstream_volume_alias} is not an AMESim pneumatic volume") + if not isinstance(orifice, AmesimPneumaticOrifice): + raise TypeError(f"{orifice_alias} is not an AMESim pneumatic orifice") + + def initial_state_vector() -> list[float]: + return [ + *upstream_volume.get_state_vector(), + *downstream_volume.get_state_vector(), + ] + + def apply_state_vector(values: list[float]) -> None: + if len(values) != 4: + raise ValueError("two-volume pneumatic branch state vector requires four values") + upstream_volume.set_state_vector(values[:2]) + downstream_volume.set_state_vector(values[2:]) + + return TestMqlPneumaticClosure( + components=TestMqlPneumaticBranchComponents( + name=name, + upstream_volume=upstream_volume, + orifice=orifice, + downstream_volume=downstream_volume, + ), + initial_state_vector=initial_state_vector, + apply_state_vector=apply_state_vector, + ) + def snapshot(self) -> TestMqlSnapshot: return TestMqlSnapshot( model_name=MODEL_NAME, diff --git a/tests/test_test_mql_structural.py b/tests/test_test_mql_structural.py index dd76bf4..f85a504 100644 --- a/tests/test_test_mql_structural.py +++ b/tests/test_test_mql_structural.py @@ -2,6 +2,11 @@ from __future__ import annotations import unittest +from PythonModels.components.amesim_pneumatic import ( + AmesimPneumaticOrifice, + AmesimPneumaticVolume, + AmesimVariablePneumaticVolume, +) from PythonModels.systems.test_mql import GLOBAL_PARAMETERS, SUBMODEL_COUNTS, TestMqlSystem @@ -25,6 +30,72 @@ class TestMqlStructuralTest(unittest.TestCase): self.assertIn("pn_brp2_8", system.network.components) self.assertIn("pn_gas_data", system.network.components) + def test_network_uses_typed_pneumatic_components_where_available(self) -> None: + system = TestMqlSystem() + + self.assertEqual(system.typed_pneumatic_component_count, 28) + self.assertIsInstance( + system.network.components["pn_general_chamber"], + AmesimPneumaticVolume, + ) + self.assertIsInstance( + system.network.components["pn_c1_8"], + AmesimVariablePneumaticVolume, + ) + self.assertIsInstance( + system.network.components["pn_orifice_18"], + AmesimPneumaticOrifice, + ) + self.assertIsInstance( + system.network.components["pn_morifice_11"], + AmesimPneumaticOrifice, + ) + self.assertEqual(len(system.pneumatic_state_vector()), 24) + + def test_can_build_pneumatic_branch_closure_from_typed_components(self) -> None: + system = TestMqlSystem() + + closure = system.pneumatic_branch_closure( + name="typed_branch", + upstream_volume_alias="pn_general_chamber", + orifice_alias="pn_orifice_18", + downstream_volume_alias="pn_c1_8", + ) + snapshot = closure.snapshot() + + self.assertGreater(snapshot.flow, 0.0) + self.assertIs( + closure.components.upstream_volume, + system.network.components["pn_general_chamber"], + ) + self.assertIs( + closure.components.orifice, + system.network.components["pn_orifice_18"], + ) + self.assertIs( + closure.components.downstream_volume, + system.network.components["pn_c1_8"], + ) + self.assertAlmostEqual( + closure.components.upstream_volume.port_a.m_flow, + -snapshot.flow, + ) + self.assertAlmostEqual( + closure.components.downstream_volume.port_a.m_flow, + snapshot.flow, + ) + + def test_pneumatic_branch_closure_rejects_structural_components(self) -> None: + system = TestMqlSystem() + + with self.assertRaises(TypeError): + system.pneumatic_branch_closure( + name="invalid_branch", + upstream_volume_alias="pn_brp2_8", + orifice_alias="pn_orifice_18", + downstream_volume_alias="pn_c1_8", + ) + def test_submodel_counts_keep_key_amesim_families(self) -> None: self.assertEqual(SUBMODEL_COUNTS["PNRP17"], 8) self.assertEqual(SUBMODEL_COUNTS["PNCH012"], 8)