diff --git a/PythonModels/systems/test_mql_computed.py b/PythonModels/systems/test_mql_computed.py index 8c36ec6..bc6dc1f 100644 --- a/PythonModels/systems/test_mql_computed.py +++ b/PythonModels/systems/test_mql_computed.py @@ -67,6 +67,23 @@ class TestMqlComputedGeometryRun: return len(self.output.data_paths) +@dataclass(frozen=True) +class TestMqlComputedPneumaticRelationsRun: + amesim_results: AmesimResults + observation_catalog: TestMqlObservationCatalog + output_schema: TestMqlOutputSchema + output: TestMqlValidatedOutput + comparison: TestMqlComparisonResult + + @property + def sample_count(self) -> int: + return len(self.output.times) + + @property + def signal_count(self) -> int: + return len(self.output.data_paths) + + @dataclass(frozen=True) class TestMqlComputedMechanicalRelationsRun: amesim_results: AmesimResults @@ -172,6 +189,42 @@ def run_test_mql_computed_geometry( ) +def run_test_mql_computed_pneumatic_relations( + archive_path: Path, +) -> TestMqlComputedPneumaticRelationsRun: + amesim_results = load_test_mql_amesim_results(archive_path) + observation_catalog = build_test_mql_observation_catalog(amesim_results) + output_schema = build_test_mql_output_schema( + amesim_results, + observation_catalog=observation_catalog, + ) + output_series = { + **_compute_chamber_duplicate_series(amesim_results, observation_catalog), + **_compute_orifice_reversed_series(amesim_results, observation_catalog), + } + output_data_paths = tuple(output_series) + output = validate_test_mql_output( + times=amesim_results.times, + series_by_data_path=output_series, + schema=output_schema, + data_paths=output_data_paths, + ) + comparison = compare_validated_test_mql_output( + times=output.times, + series_by_data_path=output.series_by_data_path, + schema=output_schema, + amesim_results=amesim_results, + data_paths=output.data_paths, + ) + return TestMqlComputedPneumaticRelationsRun( + amesim_results=amesim_results, + observation_catalog=observation_catalog, + output_schema=output_schema, + output=output, + comparison=comparison, + ) + + def run_test_mql_computed_mechanical_relations( archive_path: Path, ) -> TestMqlComputedMechanicalRelationsRun: @@ -314,3 +367,33 @@ def _compute_zero_force_source_series( for alias in sorted(mechanical_assembly.zero_force_sources) } + +def _compute_chamber_duplicate_series( + amesim_results: AmesimResults, + observation_catalog: TestMqlObservationCatalog, +) -> dict[str, tuple[float, ...]]: + series_by_data_path: dict[str, tuple[float, ...]] = {} + for binding in observation_catalog.chambers.bindings: + pressure_series = amesim_results.series(binding.pressure_path) + temperature_series = amesim_results.series(binding.temperature_path) + for duplicate_path in binding.pressure_duplicate_paths: + series_by_data_path[duplicate_path] = tuple(pressure_series) + for duplicate_path in binding.temperature_duplicate_paths: + series_by_data_path[duplicate_path] = tuple(temperature_series) + return series_by_data_path + + +def _compute_orifice_reversed_series( + amesim_results: AmesimResults, + observation_catalog: TestMqlObservationCatalog, +) -> dict[str, tuple[float, ...]]: + series_by_data_path: dict[str, tuple[float, ...]] = {} + for binding in observation_catalog.orifices.bindings: + series_by_data_path[binding.reversed_mass_flow_path] = tuple( + -value for value in amesim_results.series(binding.primary_mass_flow_path) + ) + series_by_data_path[binding.reversed_enthalpy_flow_path] = tuple( + -value for value in amesim_results.series(binding.primary_enthalpy_flow_path) + ) + return series_by_data_path + diff --git a/tests/test_test_mql_computed.py b/tests/test_test_mql_computed.py index a6ee61e..e51f511 100644 --- a/tests/test_test_mql_computed.py +++ b/tests/test_test_mql_computed.py @@ -7,6 +7,7 @@ from PythonModels.systems.test_mql_computed import ( run_test_mql_computed_geometry, run_test_mql_computed_mechanical_relations, run_test_mql_computed_piston_geometry, + run_test_mql_computed_pneumatic_relations, ) @@ -110,6 +111,58 @@ class TestMqlComputedGeometryTests(unittest.TestCase): ) +class TestMqlComputedPneumaticRelationsTests(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.computed_run = run_test_mql_computed_pneumatic_relations(TEST_MQL_AME) + + def test_computed_pneumatic_relations_outputs_schema_valid_series(self) -> None: + self.assertEqual(self.computed_run.sample_count, 1002) + self.assertEqual(self.computed_run.observation_catalog.chambers.fixed_count, 4) + self.assertEqual(self.computed_run.observation_catalog.chambers.variable_count, 8) + self.assertEqual(self.computed_run.observation_catalog.orifices.fixed_count, 8) + self.assertEqual(self.computed_run.observation_catalog.orifices.variable_count, 8) + self.assertEqual(self.computed_run.signal_count, 88) + self.assertEqual(len(self.computed_run.comparison.metrics), 88) + self.assertEqual(self.computed_run.output_schema.signal_count, 858) + + def test_computed_pneumatic_relations_include_expected_paths(self) -> None: + paths = self.computed_run.output.data_paths + + self.assertIn("press2@pn_c1_8", paths) + self.assertIn("temp2@pn_c1_8", paths) + self.assertIn("dm2@pn_orifice_18", paths) + self.assertIn("dh2@pn_orifice_18", paths) + self.assertEqual(len([path for path in paths if path.startswith("press")]), 28) + self.assertEqual(len([path for path in paths if path.startswith("temp")]), 28) + self.assertEqual(len([path for path in paths if path.startswith("dm")]), 16) + self.assertEqual(len([path for path in paths if path.startswith("dh")]), 16) + + def test_computed_pneumatic_relations_match_amesim_exactly(self) -> None: + for data_path in self.computed_run.output.data_paths: + metric = self.computed_run.comparison.metric(data_path) + with self.subTest(data_path=data_path): + self.assertEqual(metric.max_abs_error, 0.0) + + def test_computed_pneumatic_relations_final_samples_match_expected_values(self) -> None: + self.assertAlmostEqual( + self.computed_run.output.series("press2@pn_c1_8")[-1], + 4310310.457796034, + ) + self.assertAlmostEqual( + self.computed_run.output.series("temp2@pn_c1_8")[-1], + 293.1143259012449, + ) + self.assertAlmostEqual( + self.computed_run.output.series("dm2@pn_orifice_18")[-1], + -0.009097746783809915, + ) + self.assertAlmostEqual( + self.computed_run.output.series("dh2@pn_orifice_18")[-1], + 1.1281175640493923, + ) + + class TestMqlComputedMechanicalRelationsTests(unittest.TestCase): @classmethod def setUpClass(cls) -> None: