131 lines
5.4 KiB
Python
131 lines
5.4 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from app.simulation.examples.test_mql.solver import SolveIVPConfig
|
|
from app.simulation.examples.test_mql.system import TestMqlSystem
|
|
|
|
|
|
class TestMqlPneumaticBranchSimulationTests(unittest.TestCase):
|
|
def test_simulate_pneumatic_branch_returns_ode_solution(self) -> None:
|
|
system = TestMqlSystem()
|
|
|
|
solution = system.simulate_pneumatic_branch(
|
|
name="sample_branch",
|
|
upstream_volume_alias="pn_general_chamber",
|
|
orifice_alias="pn_orifice_18",
|
|
downstream_volume_alias="pn_c1_8",
|
|
config=SolveIVPConfig(t_start=0.0, t_stop=1.0e-5, max_step=1.0e-6),
|
|
t_eval=[0.0, 5.0e-6, 1.0e-5],
|
|
)
|
|
|
|
self.assertTrue(solution.success)
|
|
self.assertEqual(len(solution.t), 3)
|
|
self.assertEqual(len(solution.y), 4)
|
|
self.assertEqual([len(row) for row in solution.y], [3, 3, 3, 3])
|
|
|
|
def test_evaluate_pneumatic_branch_solution_reports_branch_series(self) -> None:
|
|
system = TestMqlSystem()
|
|
solution = system.simulate_pneumatic_branch(
|
|
name="sample_branch",
|
|
upstream_volume_alias="pn_general_chamber",
|
|
orifice_alias="pn_orifice_18",
|
|
downstream_volume_alias="pn_c1_8",
|
|
config=SolveIVPConfig(t_start=0.0, t_stop=1.0e-5, max_step=1.0e-6),
|
|
t_eval=[0.0, 5.0e-6, 1.0e-5],
|
|
)
|
|
|
|
series = system.evaluate_pneumatic_branch_solution(
|
|
solution,
|
|
name="sample_branch",
|
|
upstream_volume_alias="pn_general_chamber",
|
|
orifice_alias="pn_orifice_18",
|
|
downstream_volume_alias="pn_c1_8",
|
|
)
|
|
|
|
self.assertEqual(series["time"], [0.0, 5.0e-6, 1.0e-5])
|
|
self.assertIn("sample_branch.flow", series)
|
|
self.assertIn("pn_general_chamber.p", series)
|
|
self.assertIn("pn_c1_8.p", series)
|
|
self.assertEqual(len(series["sample_branch.flow"]), 3)
|
|
self.assertGreater(series["sample_branch.flow"][0], 0.0)
|
|
self.assertGreater(series["pn_general_chamber.p"][0], series["pn_general_chamber.p"][-1])
|
|
self.assertLess(series["pn_c1_8.p"][0], series["pn_c1_8.p"][-1])
|
|
self.assertAlmostEqual(
|
|
series["pn_general_chamber.m_flow"][0],
|
|
-series["sample_branch.flow"][0],
|
|
)
|
|
self.assertAlmostEqual(
|
|
series["pn_c1_8.m_flow"][0],
|
|
series["sample_branch.flow"][0],
|
|
)
|
|
|
|
def test_pneumatic_branch_spec_drives_closure_and_simulation(self) -> None:
|
|
system = TestMqlSystem()
|
|
spec = system.pneumatic_branch_spec(
|
|
name="sample_branch",
|
|
upstream_volume_alias="pn_general_chamber",
|
|
orifice_alias="pn_orifice_18",
|
|
downstream_volume_alias="pn_c1_8",
|
|
source="manual-test",
|
|
)
|
|
|
|
closure = system.pneumatic_branch_closure_from_spec(spec)
|
|
solution = system.simulate_pneumatic_branch_from_spec(
|
|
spec,
|
|
config=SolveIVPConfig(t_start=0.0, t_stop=1.0e-5, max_step=1.0e-6),
|
|
t_eval=[0.0, 1.0e-5],
|
|
)
|
|
series = system.evaluate_pneumatic_branch_solution_from_spec(solution, spec)
|
|
|
|
self.assertIs(closure.components.spec, spec)
|
|
self.assertEqual(spec.source, "manual-test")
|
|
self.assertEqual(len(solution.t), 2)
|
|
self.assertIn("sample_branch.flow", series)
|
|
self.assertGreater(series["sample_branch.flow"][0], 0.0)
|
|
self.assertGreater(series["pn_general_chamber.p"][0], series["pn_general_chamber.p"][-1])
|
|
self.assertLess(series["pn_c1_8.p"][0], series["pn_c1_8.p"][-1])
|
|
|
|
def test_discover_pneumatic_branch_topology_reports_blocked_candidates(self) -> None:
|
|
system = TestMqlSystem()
|
|
|
|
discovery = system.discover_pneumatic_branch_topology()
|
|
|
|
self.assertEqual(discovery.branch_specs, ())
|
|
self.assertEqual(len(discovery.blocked_candidates), 48)
|
|
candidates = {
|
|
candidate.connection_alias: candidate
|
|
for candidate in discovery.blocked_candidates
|
|
}
|
|
chamber_candidate = candidates["pneumatic_69"]
|
|
self.assertEqual(chamber_candidate.line_submodel, "PNL0001")
|
|
self.assertEqual(chamber_candidate.source_component, "pnnode4_16")
|
|
self.assertEqual(chamber_candidate.target_component, "pn_c1_8")
|
|
self.assertFalse(chamber_candidate.source_is_typed_pneumatic)
|
|
self.assertTrue(chamber_candidate.target_is_typed_pneumatic)
|
|
self.assertIn("node/line", chamber_candidate.reason)
|
|
|
|
orifice_candidate = candidates["pneumatic_96"]
|
|
self.assertEqual(orifice_candidate.line_submodel, "PNL0001")
|
|
self.assertEqual(orifice_candidate.source_component, "pn_node3_8")
|
|
self.assertEqual(orifice_candidate.target_component, "pn_orifice_18")
|
|
self.assertFalse(orifice_candidate.source_is_typed_pneumatic)
|
|
self.assertTrue(orifice_candidate.target_is_typed_pneumatic)
|
|
self.assertIn("node/line", orifice_candidate.reason)
|
|
|
|
def test_simulate_pneumatic_branch_rejects_invalid_component_aliases(self) -> None:
|
|
system = TestMqlSystem()
|
|
|
|
with self.assertRaises(TypeError):
|
|
system.simulate_pneumatic_branch(
|
|
name="invalid_branch",
|
|
upstream_volume_alias="pn_brp2_8",
|
|
orifice_alias="pn_orifice_18",
|
|
downstream_volume_alias="pn_c1_8",
|
|
config=SolveIVPConfig(t_start=0.0, t_stop=0.0),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|