Files
SystemSimulationApp/tests/test_test_mql_pnl0001_segment.py

1565 lines
61 KiB
Python

from __future__ import annotations
import unittest
from pathlib import Path
from app.simulation.examples.test_mql.solver import SolveIVPConfig
from app.simulation.reporting.amesim_results import load_test_mql_amesim_results
from app.simulation.reporting.test_mql_output_schema import build_test_mql_output_schema
from app.simulation.reporting.test_mql_output_validation import compare_validated_test_mql_output
from app.simulation.examples.test_mql.system import TestMqlSystem
REPO_ROOT = Path(__file__).resolve().parents[1]
TEST_MQL_AME = REPO_ROOT / "AmesimModels" / "test_mql.ame"
class TestMqlPnl0001ChamberSegmentTests(unittest.TestCase):
def setUp(self) -> None:
self.system = TestMqlSystem()
self.spec = self.system.discover_pneumatic_branch_topology().chamber_segment_specs[0]
def test_system_assembles_all_twenty_physical_pnl0001_lines(self) -> None:
self.assertEqual(self.system.typed_pnl0001_line_count, 20)
self.assertIn("pneumatic_96", self.system.pnl0001_assembly.lines)
def test_closure_inserts_topology_derived_inlet_line(self) -> None:
closure = self.system.pnl0001_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=16.0e6,
outlet_pressure_pa=15.3e6,
)
snapshot = closure.snapshot()
rhs = closure.rhs(closure.initial_state_vector())
self.assertEqual(closure.components.inlet_line.name, "pneumatic_96")
self.assertEqual(len(closure.initial_state_vector()), 4)
self.assertEqual(len(rhs), 4)
self.assertGreater(snapshot.node_to_line_flow, 0.0)
self.assertAlmostEqual(snapshot.line_to_chamber_flow, 0.0, delta=1.0e-7)
self.assertAlmostEqual(snapshot.outlet_flow, 0.0, delta=1.0e-7)
self.assertAlmostEqual(rhs[0] + rhs[2], snapshot.node_to_line_flow)
def test_internal_line_orifice_flow_cancels_from_total_mass_balance(self) -> None:
closure = self.system.pnl0001_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.3e6,
outlet_pressure_pa=14.0e6,
)
state = closure.initial_state_vector()
state[0] *= 1.01
state[1] *= 1.01
snapshot = closure.snapshot(state)
rhs = closure.rhs(state)
self.assertGreater(snapshot.line_to_chamber_flow, 0.0)
self.assertAlmostEqual(
rhs[0] + rhs[2],
snapshot.node_to_line_flow - snapshot.outlet_flow,
delta=1.0e-12,
)
self.assertAlmostEqual(
closure.components.inlet_line.port_2.m_flow,
-snapshot.line_to_chamber_flow,
)
def test_simulates_four_state_line_chamber_segment(self) -> None:
solution = self.system.simulate_pnl0001_chamber_segment_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
outlet_pressure_pa=15.29e6,
config=SolveIVPConfig(
t_start=0.0,
t_stop=1.0e-7,
max_step=1.0e-8,
),
t_eval=[0.0, 5.0e-8, 1.0e-7],
)
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])
class TestMqlPnl0001PairChamberSegmentTests(unittest.TestCase):
def setUp(self) -> None:
self.system = TestMqlSystem()
self.spec = self.system.discover_pneumatic_branch_topology().chamber_segment_specs[0]
def test_pair_closure_uses_both_topology_derived_lines(self) -> None:
closure = self.system.pnl0001_pair_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=16.0e6,
outlet_node_pressure_pa=14.0e6,
)
snapshot = closure.snapshot()
rhs = closure.rhs(closure.initial_state_vector())
self.assertEqual(closure.components.inlet_line.name, "pneumatic_96")
self.assertEqual(closure.components.outlet_line.name, "pneumatic_97")
self.assertEqual(len(closure.initial_state_vector()), 6)
self.assertEqual(len(rhs), 6)
self.assertGreater(snapshot.inlet_node_to_line_flow, 0.0)
self.assertLess(snapshot.outlet_node_to_line_flow, 0.0)
self.assertAlmostEqual(
rhs[0] + rhs[2] + rhs[4],
snapshot.inlet_node_to_line_flow + snapshot.outlet_node_to_line_flow,
delta=1.0e-12,
)
def test_both_internal_orifice_flows_cancel_from_total_mass(self) -> None:
closure = self.system.pnl0001_pair_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.3e6,
outlet_node_pressure_pa=15.3e6,
)
state = closure.initial_state_vector()
state[0] *= 1.01
state[1] *= 1.01
state[4] *= 0.99
state[5] *= 0.99
snapshot = closure.snapshot(state)
rhs = closure.rhs(state)
self.assertGreater(snapshot.inlet_line_to_chamber_flow, 0.0)
self.assertLess(snapshot.outlet_line_to_chamber_flow, 0.0)
self.assertAlmostEqual(
rhs[0] + rhs[2] + rhs[4],
snapshot.inlet_node_to_line_flow + snapshot.outlet_node_to_line_flow,
delta=1.0e-12,
)
self.assertAlmostEqual(
closure.components.outlet_line.port_2.m_flow,
-snapshot.outlet_line_to_chamber_flow,
)
def test_simulates_six_state_pair_line_chamber_segment(self) -> None:
solution = self.system.simulate_pnl0001_pair_chamber_segment_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
outlet_node_pressure_pa=15.29e6,
config=SolveIVPConfig(
t_start=0.0,
t_stop=1.0e-7,
max_step=1.0e-8,
),
t_eval=[0.0, 5.0e-8, 1.0e-7],
)
self.assertTrue(solution.success)
self.assertEqual(len(solution.t), 3)
self.assertEqual(len(solution.y), 6)
self.assertEqual([len(row) for row in solution.y], [3, 3, 3, 3, 3, 3])
class TestMqlPn3NodeChamberSegmentTests(unittest.TestCase):
def setUp(self) -> None:
self.system = TestMqlSystem()
self.spec = self.system.discover_pneumatic_branch_topology().chamber_segment_specs[0]
def test_closure_replaces_outlet_boundary_with_real_pn3_node(self) -> None:
closure = self.system.pn3_node_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
snapshot = closure.snapshot()
rhs = closure.rhs(closure.initial_state_vector())
self.assertEqual(closure.components.inlet_line.name, "pneumatic_96")
self.assertEqual(closure.components.outlet_line.name, "pneumatic_97")
self.assertEqual(closure.components.node_line.name, "pneumatic_88")
self.assertEqual(closure.components.node_resistance.name, "pneumatic_100")
self.assertEqual(closure.components.node_orifice.name, "pn_morifice_9")
self.assertEqual(closure.components.node.alias, "pn_node3_9")
self.assertEqual(len(closure.initial_state_vector()), 10)
self.assertEqual(len(rhs), 10)
self.assertAlmostEqual(
snapshot.node_balance.pressure_pa,
snapshot.node_line_port_1.p,
)
self.assertAlmostEqual(
snapshot.node_balance.temperature_k,
snapshot.node_line_port_1.T,
)
def test_pn3_node_flow_cancels_between_adjacent_lines(self) -> None:
closure = self.system.pn3_node_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.3e6,
resistance_boundary_pressure_pa=15.0e6,
p4_boundary_pressure_pa=15.0e6,
)
state = closure.initial_state_vector()
state[4] *= 0.99
state[5] *= 0.99
self.assertAlmostEqual(closure.components.node_orifice.opening, 0.0)
closure.components.node_orifice.opening = 1.0
snapshot = closure.snapshot(state)
rhs = closure.rhs(state)
self.assertGreater(snapshot.outlet_node_to_line_flow, 0.0)
self.assertGreater(snapshot.node_to_resistance_flow, 0.0)
self.assertAlmostEqual(
snapshot.node_balance.port_2_mass_flow_g_s,
(snapshot.outlet_node_to_line_flow + snapshot.node_to_resistance_flow)
* 1.0e3,
)
self.assertAlmostEqual(
snapshot.node_to_pnl0003_flow,
-(snapshot.outlet_node_to_line_flow + snapshot.node_to_resistance_flow),
)
self.assertGreater(snapshot.pnl0003_to_p4_flow, 0.0)
self.assertAlmostEqual(
closure.components.node_line.port_1.m_flow,
snapshot.node_to_pnl0003_flow,
)
self.assertAlmostEqual(
closure.components.node_line.port_2.m_flow,
-snapshot.pnl0003_to_p4_flow,
)
mass_derivative_sum = rhs[0] + rhs[2] + rhs[4] + rhs[6] + rhs[8]
self.assertAlmostEqual(
mass_derivative_sum,
(
snapshot.inlet_node_to_line_flow
- snapshot.pnl0003_to_p4_flow
- snapshot.node_to_resistance_flow
),
delta=1.0e-12,
)
def test_simulates_ten_state_pn3_node_chamber_segment(self) -> None:
solution = self.system.simulate_pn3_node_chamber_segment_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
p4_boundary_pressure_pa=15.29e6,
config=SolveIVPConfig(
t_start=0.0,
t_stop=1.0e-8,
max_step=1.0e-9,
),
t_eval=[0.0, 5.0e-9, 1.0e-8],
)
self.assertTrue(solution.success)
self.assertEqual(len(solution.t), 3)
self.assertEqual(len(solution.y), 10)
self.assertEqual([len(row) for row in solution.y], [3] * 10)
class TestMqlPn3P4NodeChamberSegmentTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.amesim_results = load_test_mql_amesim_results(TEST_MQL_AME)
cls.output_schema = build_test_mql_output_schema(cls.amesim_results)
def setUp(self) -> None:
self.system = TestMqlSystem()
self.spec = self.system.discover_pneumatic_branch_topology().chamber_segment_specs[0]
def test_closure_replaces_p4_pressure_boundary_with_real_node_and_lines(self) -> None:
closure = self.system.pn3_p4_node_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
snapshot = closure.snapshot()
rhs = closure.rhs(closure.initial_state_vector())
self.assertEqual(closure.components.inlet_line.name, "pneumatic_96")
self.assertEqual(closure.components.volume.name, "pn_general_chamber")
self.assertEqual(closure.components.outlet_line.name, "pneumatic_97")
self.assertEqual(closure.components.inlet_orifice.name, "pn_orifice_18")
self.assertEqual(closure.components.outlet_orifice.name, "pn_orifice_19")
self.assertEqual(closure.components.node_orifice.name, "pn_morifice_9")
self.assertEqual(closure.components.node_resistance.name, "pneumatic_100")
self.assertEqual(closure.components.node.alias, "pn_node3_9")
self.assertEqual(closure.components.p4_node.alias, "pnnode4_17")
self.assertEqual(closure.components.p4_primary_line.name, "pneumatic_68")
self.assertEqual(closure.components.p4_primary_chamber.name, "pn_c1_9")
self.assertEqual(closure.components.p4_port1_line.name, "pneumatic_86")
self.assertEqual(closure.components.p4_port1_remote_node.alias, "pnnode4_18")
self.assertEqual(
closure.components.p4_port1_remote_primary_line.name,
"pneumatic_66",
)
self.assertEqual(
closure.components.p4_port1_remote_primary_chamber.name,
"pn_c1_10",
)
self.assertEqual(
closure.components.p4_port1_remote_port1_line.name,
"pneumatic_80",
)
self.assertEqual(closure.components.p4_port1_far_node.alias, "pnnode4_19")
self.assertEqual(
closure.components.p4_port1_far_primary_line.name,
"pneumatic_65",
)
self.assertEqual(
closure.components.p4_port1_far_primary_chamber.name,
"pn_c1_11",
)
self.assertEqual(closure.components.p4_port1_far_port1_line.name, "pneumatic_85")
self.assertEqual(closure.components.p4_port1_next_node.alias, "pnnode4_23")
self.assertEqual(
closure.components.p4_port1_next_primary_line.name,
"pneumatic_71",
)
self.assertEqual(
closure.components.p4_port1_next_primary_chamber.name,
"pn_c1_12",
)
self.assertEqual(closure.components.p4_port1_next_port1_line.name, "pneumatic_81")
self.assertEqual(closure.components.p4_bridge_node.alias, "pnnode4_20")
self.assertEqual(closure.components.p4_bridge_primary_line.name, "pneumatic_72")
self.assertEqual(closure.components.p4_bridge_primary_chamber.name, "pn_c1_13")
self.assertEqual(
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(
closure.components.p4_port3_remote_primary_line.name,
"pneumatic_69",
)
self.assertEqual(
closure.components.p4_port3_remote_primary_chamber.name,
"pn_c1_8",
)
self.assertEqual(
closure.components.p4_port3_remote_port3_line.name,
"pneumatic_95",
)
self.assertEqual(closure.components.p4_port3_far_node.alias, "pnnode4_22")
self.assertEqual(
closure.components.p4_port3_far_primary_line.name,
"pneumatic_74",
)
self.assertEqual(
closure.components.p4_port3_far_primary_chamber.name,
"pn_c1_15",
)
self.assertEqual(closure.components.p4_port3_far_port3_line.name, "pneumatic_82")
self.assertEqual(closure.components.p4_port3_next_node.alias, "pnnode4_21")
self.assertEqual(
closure.components.p4_port3_next_primary_line.name,
"pneumatic_73",
)
self.assertEqual(
closure.components.p4_port3_next_primary_chamber.name,
"pn_c1_14",
)
self.assertEqual(closure.components.p4_port3_next_port3_line.name, "pneumatic_84")
self.assertEqual(
closure.components.p4_port3_next_orifice.name,
"pn_morifice_13",
)
self.assertEqual(
closure.components.p4_port3_next_orifice_line.name,
"pneumatic_91",
)
self.assertEqual(
closure.components.p4_port3_next_orifice_node.alias,
"pn_node3_14",
)
self.assertEqual(
closure.components.p4_port3_next_orifice_output_line.name,
"pneumatic_93",
)
self.assertEqual(
closure.components.p4_port3_next_chamber_inlet_line.name,
"pneumatic_103",
)
self.assertEqual(
closure.components.p4_port3_next_chamber.name,
"pn_general_chamber_5",
)
self.assertEqual(
closure.components.p4_port3_next_chamber_outlet_line.name,
"pneumatic_104",
)
self.assertEqual(
closure.components.p4_port3_next_chamber_inlet_orifice.name,
"pn_orifice_24",
)
self.assertEqual(
closure.components.p4_port3_next_chamber_outlet_orifice.name,
"pn_orifice_25",
)
self.assertEqual(
closure.components.p4_port3_remote_orifice.name,
"pn_morifice_1",
)
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(
closure.components.p4_port3_remote_resistance_node.alias,
"pn_node3_15",
)
self.assertEqual(
closure.components.p4_port3_remote_resistance_node_line.name,
"pneumatic_92",
)
self.assertEqual(
closure.components.p4_port3_remote_resistance_orifice.name,
"pn_morifice_14",
)
self.assertEqual(
closure.components.p4_port3_remote_resistance_output_line.name,
"pneumatic_94",
)
self.assertEqual(
closure.components.p4_port3_next_orifice_resistance.name,
"pneumatic_106",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_node.alias,
"pn_node3_13",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_node_line.name,
"pneumatic_78",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_orifice.name,
"pn_morifice_12",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_output_line.name,
"pneumatic_70",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_inlet_line.name,
"pneumatic_101",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber.name,
"pn_general_chamber_4",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_outlet_line.name,
"pneumatic_102",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_inlet_orifice.name,
"pn_orifice_22",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_outlet_orifice.name,
"pn_orifice_23",
)
self.assertEqual(
closure.components.p4_port1_next_orifice.name,
"pn_morifice_11",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_line.name,
"pneumatic_77",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_node.alias,
"pn_node3_12",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_output_line.name,
"pneumatic_79",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance.name,
"pneumatic_107",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_node.alias,
"pn_node3_11",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_line.name,
"pneumatic_76",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_orifice.name,
"pn_morifice_15",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_inlet_line.name,
"pneumatic_98",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber.name,
"pn_general_chamber_2",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_outlet_line.name,
"pneumatic_99",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_inlet_orifice.name,
"pn_orifice_20",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_outlet_orifice.name,
"pn_orifice_21",
)
self.assertEqual(len(closure.initial_state_vector()), 112)
self.assertEqual(len(rhs), 112)
self.assertAlmostEqual(
snapshot.p4_balance.pressure_pa,
snapshot.p4_primary_line.p,
)
self.assertAlmostEqual(
snapshot.p4_balance.temperature_k,
snapshot.p4_primary_line.T,
)
def test_full_state_closure_combines_pneumatic_and_mechanical_states(self) -> None:
closure = self.system.full_state_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
state = closure.initial_state_vector()
snapshot = closure.snapshot(state)
rhs = closure.rhs(state)
self.assertEqual(closure.pneumatic_state_count, 112)
self.assertEqual(closure.mechanical_state_count, 20)
self.assertEqual(closure.state_count, 132)
self.assertEqual(len(state), 132)
self.assertEqual(snapshot.state_count, 132)
self.assertEqual(snapshot.mechanical.state_count, 20)
self.assertEqual(len(rhs), 132)
self.assertAlmostEqual(
snapshot.pneumatic.p4_balance.pressure_pa,
snapshot.pneumatic.p4_primary_line.p,
)
self.assertEqual(
snapshot.mechanical.states[0].alias,
"mass_friction_endstops_10",
)
self.assertAlmostEqual(
snapshot.mechanical_node_total_force_by_alias[
"dynamic_mechanical_node_alternative_2"
],
0.0,
)
self.assertAlmostEqual(
snapshot.mechanical_node_total_force_by_alias[
"dynamic_mechanical_node_alternative_3"
],
-326.7174678324367,
)
self.assertAlmostEqual(rhs[112], -0.8167936695810917)
def test_full_state_closure_feeds_piston_kinematics_to_variable_chambers(self) -> None:
closure = self.system.full_state_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
state = closure.initial_state_vector()
state[113] = 0.05
snapshot = closure.snapshot(state)
chamber = closure.pneumatic_closure.components.p4_port3_remote_primary_chamber
piston = closure.mechanical_closure.assembly.pistons["pn_brp2_8"]
expected_external_volume = piston.geometry().chamber_volume_m3(0.0, 0.05)
self.assertAlmostEqual(
chamber.volume,
chamber.dead_volume + expected_external_volume,
)
self.assertLess(
snapshot.pneumatic.p4_port3_remote_primary_chamber.p,
self.system.pneumatic_assembly.variable_initial_absolute_pressure_pa,
)
base_rhs = closure.rhs(closure.initial_state_vector())
moving_state = closure.initial_state_vector()
moving_state[112] = 0.1
moving_snapshot = closure.snapshot(moving_state)
rhs = closure.rhs(moving_state)
expected_volume_rate = piston.geometry().chamber_volume_rate_m3_s(0.0, 0.1)
self.assertAlmostEqual(chamber.volume_rate_m3_s(), expected_volume_rate)
self.assertAlmostEqual(
rhs[47] - base_rhs[47],
-moving_snapshot.pneumatic.p4_port3_remote_primary_chamber.p
* expected_volume_rate,
)
def test_full_state_closure_applies_elastic_endstop_force_to_small_masses(self) -> None:
closure = self.system.full_state_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
state = closure.initial_state_vector()
state[113] = 1.0e-3
snapshot = closure.snapshot(state)
rhs = closure.rhs(state)
endstop = closure.mechanical_closure.assembly.elastic_endstops[
"elasticendstop_8"
].endstop()
expected_contact_force = endstop.contact_force(-1.0, 0.0)
mass = closure.mechanical_closure.assembly.masses[
"mass_friction_endstops_10"
].mass_kg
expected_piston_force = closure._piston_force_by_mass_alias(
snapshot.pneumatic
)["mass_friction_endstops_10"]
self.assertAlmostEqual(
rhs[112],
(expected_piston_force - expected_contact_force) / mass,
)
self.assertAlmostEqual(
snapshot.mechanical_node_total_force_by_alias[
"dynamic_mechanical_node_alternative_2"
],
expected_contact_force,
)
def test_full_state_closure_constrains_large_masses_at_active_limits(self) -> None:
closure = self.system.full_state_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
rhs = closure.rhs(closure.initial_state_vector())
self.assertAlmostEqual(rhs[128], 0.0)
self.assertAlmostEqual(rhs[129], 0.0)
self.assertAlmostEqual(rhs[130], 0.0)
self.assertAlmostEqual(rhs[131], 0.0)
def test_full_state_closure_releases_large_mass_when_node_force_points_inward(self) -> None:
closure = self.system.full_state_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
state = closure.initial_state_vector()
state[113] = 1.0e-3
rhs = closure.rhs_at(0.8000000000000009, state)
endstop = closure.mechanical_closure.assembly.elastic_endstops[
"elasticendstop_8"
].endstop()
expected_contact_force = endstop.contact_force(-1.0, 0.0)
support_mass = closure.mechanical_closure.assembly.masses[
"mass_friction_endstops_18"
].mass_kg
self.assertAlmostEqual(rhs[128], expected_contact_force / support_mass)
self.assertAlmostEqual(rhs[129], 0.0)
def test_full_state_closure_diagnoses_variable_chamber_rhs_terms(self) -> None:
closure = self.system.full_state_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
state = closure.initial_state_vector()
diagnostic = closure.variable_chamber_rhs_diagnostic(
chamber_alias="pn_c1_8",
state_vector=state,
)
rhs = closure.rhs(state)
self.assertEqual(diagnostic.piston_alias, "pn_brp2_8")
self.assertAlmostEqual(diagnostic.chamber_volume_m3, 0.015)
self.assertAlmostEqual(diagnostic.chamber_volume_rate_m3_s, 0.0)
self.assertAlmostEqual(diagnostic.mass_derivative_kg_s, rhs[46])
self.assertAlmostEqual(diagnostic.energy_derivative_w, rhs[47])
self.assertAlmostEqual(
diagnostic.energy_derivative_w,
diagnostic.port_a_energy_flow_w
+ diagnostic.port_b_energy_flow_w
+ diagnostic.boundary_work_w
+ diagnostic.thermal_energy_flow_w,
)
def test_full_state_closure_diagnoses_pnl0001_line_rhs_terms(self) -> None:
closure = self.system.full_state_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
state = closure.initial_state_vector()
diagnostic = closure.pnl0001_line_rhs_diagnostic(
line_alias="pneumatic_69",
state_vector=state,
time_s=0.04,
)
rhs = closure.rhs_at(0.04, state)
self.assertEqual(diagnostic.chamber_alias, "pn_c1_8")
self.assertGreater(diagnostic.node_to_line_flow_kg_s, 0.0)
self.assertAlmostEqual(
diagnostic.mass_derivative_kg_s,
diagnostic.chamber_to_line_flow_kg_s
+ diagnostic.node_to_line_flow_kg_s,
)
self.assertAlmostEqual(diagnostic.mass_derivative_kg_s, rhs[44])
self.assertAlmostEqual(diagnostic.energy_derivative_w, rhs[45])
self.assertAlmostEqual(
diagnostic.energy_derivative_w,
diagnostic.port_1_energy_flow_w
+ diagnostic.port_2_energy_flow_w
+ 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_can_enable_pneumatic_69_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_69_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.p4_port3_remote_primary_line
expected = candidate_closure.pneumatic_closure._pnl0001_reference_enthalpy_derivative(
line=line,
line_properties=snapshot.p4_port3_remote_primary_line,
port_1_properties=snapshot.p4_port3_remote_primary_chamber,
port_1_flow=snapshot.p4_port3_remote_chamber_to_line_flow,
port_2_properties=snapshot.p4_port3_remote_primary_line,
port_2_flow=snapshot.p4_port3_remote_node_to_primary_line_flow,
port_2_connected_reference_h=(
candidate_closure.pneumatic_closure._p4_port3_remote_port_2_reference_h(
snapshot=snapshot
)
),
)
self.assertAlmostEqual(candidate_rhs[0], default_rhs[0])
self.assertAlmostEqual(candidate_rhs[1], default_rhs[1])
self.assertAlmostEqual(candidate_rhs[44], default_rhs[44])
self.assertAlmostEqual(candidate_rhs[44], expected.m)
self.assertAlmostEqual(candidate_rhs[45], expected.U)
self.assertNotAlmostEqual(candidate_rhs[45], default_rhs[45])
def test_full_state_closure_applies_step_controls_to_variable_orifices(self) -> None:
closure = self.system.full_state_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
state = closure.initial_state_vector()
closed_snapshot = closure.snapshot_at(0.0, state).pneumatic
open_snapshot = closure.snapshot_at(0.04, state).pneumatic
self.assertAlmostEqual(
closed_snapshot.p4_port3_remote_node_to_primary_line_flow,
0.0,
)
self.assertGreater(
open_snapshot.p4_port3_remote_node_to_primary_line_flow,
0.0,
)
node_inlet_h = (
open_snapshot.p4_port3_remote_balance.port_2_enthalpy_flow_w
/ open_snapshot.p4_port3_remote_node_to_primary_line_flow
)
self.assertAlmostEqual(
node_inlet_h,
open_snapshot.p4_port3_remote_orifice_line_port_2.h,
)
rhs = closure.rhs_at(0.04, state)
line = closure.pneumatic_closure.components.p4_port3_remote_primary_line
expected_line_derivative = (
line.derivatives_from_transport_enthalpy_connections(
port_1_m_flow=(
open_snapshot.p4_port3_remote_chamber_to_line_flow
),
connected_h_1=open_snapshot.p4_port3_remote_primary_chamber.h,
port_2_m_flow=(
open_snapshot.p4_port3_remote_node_to_primary_line_flow
),
connected_h_2=node_inlet_h,
)
)
self.assertAlmostEqual(rhs[45], expected_line_derivative.U)
self.assertAlmostEqual(
self.system.pneumatic_assembly.variable_orifices[
"pn_morifice_1"
].opening,
1.0,
)
remote_orifice_line = (
closure.pneumatic_closure.components.p4_port3_remote_orifice_line
)
custom_port_1_h = open_snapshot.p4_port3_remote_orifice_line_port_1.h + 1234.0
custom_d1, _ = closure.pneumatic_closure._two_state_connection_line_derivatives(
line=remote_orifice_line,
port_1_properties=open_snapshot.p4_port3_remote_orifice_line_port_1,
port_1_flow=0.01,
port_2_connected_properties=open_snapshot.p4_port3_remote_primary_line,
port_2_flow=-open_snapshot.p4_port3_remote_orifice_to_node_flow,
port_1_connected_h=custom_port_1_h,
)
expected_custom_d1, _ = remote_orifice_line.derivatives_from_connections(
port_1_m_flow=0.01,
connected_h_1=custom_port_1_h,
port_2_m_flow=-open_snapshot.p4_port3_remote_orifice_to_node_flow,
connected_h_2=open_snapshot.p4_port3_remote_primary_line.h,
)
default_d1, _ = closure.pneumatic_closure._two_state_connection_line_derivatives(
line=remote_orifice_line,
port_1_properties=open_snapshot.p4_port3_remote_orifice_line_port_1,
port_1_flow=0.01,
port_2_connected_properties=open_snapshot.p4_port3_remote_primary_line,
port_2_flow=-open_snapshot.p4_port3_remote_orifice_to_node_flow,
)
self.assertAlmostEqual(custom_d1.U, expected_custom_d1.U)
self.assertNotAlmostEqual(custom_d1.U, default_d1.U)
closure.snapshot_at(0.0, state)
self.assertAlmostEqual(
self.system.pneumatic_assembly.variable_orifices[
"pn_morifice_1"
].opening,
0.0,
)
def test_simulates_full_state_key_data_paths_for_amesim_comparison(self) -> None:
data_paths = (
"press@pn_c1_8",
"vol@pn_c1_8",
"mgas1@pn_c1_8",
"vol1@pn_brp2_8",
"vvol1@pn_brp2_8",
"x1@mass_friction_endstops_10",
"v1@mass_friction_endstops_10",
"acc1@mass_friction_endstops_10",
"x1@mass_friction_endstops_18",
"v1@mass_friction_endstops_18",
"acc1@mass_friction_endstops_18",
"p2@pneumatic_69",
"t2@pneumatic_69",
"mgas@pneumatic_69",
"re@pneumatic_69",
"v@pneumatic_69",
"ff@pneumatic_69",
"dm1@pneumatic_69",
"xv@pn_morifice_1",
"dm2@pn_morifice_1",
)
result = self.system.simulate_full_state_series_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
config=SolveIVPConfig(t_start=0.0, t_stop=0.0),
data_paths=data_paths,
)
comparison = compare_validated_test_mql_output(
times=result.t,
series_by_data_path={data_path: result.series[data_path] for data_path in data_paths},
schema=self.output_schema,
amesim_results=self.amesim_results,
data_paths=data_paths,
)
self.assertEqual(result.series["time"], [0.0])
self.assertEqual(len(result.y), 132)
self.assertEqual(len(comparison.metrics), len(data_paths))
self.assertAlmostEqual(result.series["press@pn_c1_8"][0], -1300.0)
self.assertAlmostEqual(result.series["vol@pn_c1_8"][0], 15000.0)
self.assertAlmostEqual(
result.series["mgas1@pn_c1_8"][0],
self.amesim_results.series("mgas1@pn_c1_8")[0],
delta=1.0e-4,
)
self.assertAlmostEqual(result.series["vol1@pn_brp2_8"][0], 0.0)
self.assertAlmostEqual(result.series["vvol1@pn_brp2_8"][0], 0.0)
self.assertAlmostEqual(result.series["x1@mass_friction_endstops_10"][0], 0.0)
self.assertAlmostEqual(result.series["v1@mass_friction_endstops_10"][0], 0.0)
self.assertAlmostEqual(
result.series["acc1@mass_friction_endstops_10"][0],
-0.8167936695810917,
)
self.assertAlmostEqual(result.series["acc1@mass_friction_endstops_18"][0], 0.0)
self.assertAlmostEqual(result.series["p2@pneumatic_69"][0], -1300.0)
self.assertAlmostEqual(result.series["t2@pneumatic_69"][0], 293.15)
self.assertAlmostEqual(
result.series["mgas@pneumatic_69"][0],
self.amesim_results.series("mgas@pneumatic_69")[0],
delta=1.0e-5,
)
self.assertAlmostEqual(result.series["re@pneumatic_69"][0], 0.0)
self.assertAlmostEqual(result.series["v@pneumatic_69"][0], 0.0)
self.assertGreater(result.series["ff@pneumatic_69"][0], 0.0)
self.assertAlmostEqual(result.series["dm1@pneumatic_69"][0], 0.0)
self.assertAlmostEqual(result.series["xv@pn_morifice_1"][0], 0.0)
self.assertAlmostEqual(result.series["dm2@pn_morifice_1"][0], 0.0)
def test_simulates_full_132_state_closure(self) -> None:
solution = self.system.simulate_full_state_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
config=SolveIVPConfig(t_start=0.0, t_stop=1.0e-5, max_step=1.0e-6),
t_eval=[0.0, 1.0e-5],
)
self.assertTrue(solution.success)
self.assertEqual(len(solution.t), 2)
self.assertEqual(len(solution.y), 132)
self.assertEqual([len(row) for row in solution.y], [2] * 132)
def test_p4_closure_uses_structured_neighborhood(self) -> None:
closure = self.system.pn3_p4_node_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
neighborhood = self.system.p4_node_neighborhood(closure.components.p4_node.alias)
self.assertEqual(
closure.components.p4_primary_line.name,
neighborhood.primary.line_alias,
)
self.assertEqual(
closure.components.p4_primary_chamber.name,
neighborhood.primary.chamber_alias,
)
self.assertEqual(
closure.components.p4_port1_line.name,
neighborhood.port_1.line_alias,
)
self.assertEqual(
closure.components.p4_port1_remote_node.alias,
neighborhood.port_1.remote_node_alias,
)
port1_remote_neighborhood = self.system.p4_node_neighborhood(
neighborhood.port_1.remote_node_alias
)
self.assertEqual(
closure.components.p4_port1_remote_port1_line.name,
port1_remote_neighborhood.port_1.line_alias,
)
self.assertEqual(
closure.components.p4_port1_far_node.alias,
port1_remote_neighborhood.port_1.remote_node_alias,
)
self.assertEqual(
closure.components.p4_port1_far_primary_line.name,
self.system._p4_primary_connection_for_node(
port1_remote_neighborhood.port_1.remote_node_alias
).line_alias,
)
port1_far_port1 = self.system._pnl0002_connection_for_node_port(
closure.components.p4_port1_far_node.alias,
"port_1",
)
self.assertEqual(
closure.components.p4_port1_far_port1_line.name,
port1_far_port1.line_alias,
)
self.assertEqual(
closure.components.p4_port1_next_node.alias,
port1_far_port1.remote_node_alias,
)
self.assertEqual(
closure.components.p4_port1_next_primary_line.name,
self.system._p4_primary_connection_for_node(
port1_far_port1.remote_node_alias
).line_alias,
)
port1_next_port1 = self.system._pnl0002_connection_for_node_port(
closure.components.p4_port1_next_node.alias,
"port_1",
)
self.assertEqual(
closure.components.p4_port1_next_port1_line.name,
port1_next_port1.line_alias,
)
self.assertEqual(
closure.components.p4_port1_next_orifice_output_line.name,
self.system._pnl0001_line_for_node_port(
closure.components.p4_port1_next_node.alias,
"port_4",
).name,
)
self.assertEqual(
closure.components.p4_port1_next_orifice_node.alias,
"pn_node3_12",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_line.name,
self.system._pnl0003_line_for_node_port("pn_node3_12", "port_2").name,
)
self.assertEqual(
closure.components.p4_port1_next_orifice.name,
"pn_morifice_11",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance.name,
self.system._pnl00r_line_for_node_port("pn_node3_12", "port_3").name,
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_node.alias,
"pn_node3_11",
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_line.name,
self.system._pnl0003_line_for_node_port("pn_node3_11", "port_2").name,
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_orifice.name,
"pn_morifice_15",
)
resistance_chamber_segment = (
self.system.discover_pneumatic_branch_topology().chamber_segment_specs[1]
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_spec,
resistance_chamber_segment,
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_inlet_line.name,
resistance_chamber_segment.inlet_line_alias,
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_outlet_line.name,
resistance_chamber_segment.outlet_line_alias,
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_inlet_orifice.name,
resistance_chamber_segment.inlet_orifice_alias,
)
self.assertEqual(
closure.components.p4_port1_next_orifice_resistance_chamber_outlet_orifice.name,
resistance_chamber_segment.outlet_orifice_alias,
)
self.assertEqual(
closure.components.p4_bridge_node.alias,
port1_next_port1.remote_node_alias,
)
self.assertEqual(
closure.components.p4_bridge_primary_line.name,
self.system._p4_primary_connection_for_node(
closure.components.p4_bridge_node.alias
).line_alias,
)
self.assertEqual(
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.node_resistance.name,
self.system._pnl00r_line_for_node_port("pn_node3_10", "port_3").name,
)
self.assertEqual(
closure.components.node.alias,
"pn_node3_9",
)
self.assertEqual(
closure.components.p4_port3_line.name,
neighborhood.port_3.line_alias,
)
self.assertEqual(
closure.components.p4_port3_remote_node.alias,
neighborhood.port_3.remote_node_alias,
)
port3_remote_neighborhood = self.system.p4_node_neighborhood(
neighborhood.port_3.remote_node_alias
)
self.assertEqual(
closure.components.p4_port3_remote_port3_line.name,
port3_remote_neighborhood.port_3.line_alias,
)
self.assertEqual(
closure.components.p4_port3_far_node.alias,
port3_remote_neighborhood.port_3.remote_node_alias,
)
self.assertEqual(
closure.components.p4_port3_far_primary_line.name,
self.system._p4_primary_connection_for_node(
port3_remote_neighborhood.port_3.remote_node_alias
).line_alias,
)
port3_far_port3 = self.system._pnl0002_connection_for_node_port(
closure.components.p4_port3_far_node.alias,
"port_3",
)
self.assertEqual(
closure.components.p4_port3_far_port3_line.name,
port3_far_port3.line_alias,
)
self.assertEqual(
closure.components.p4_port3_next_node.alias,
port3_far_port3.remote_node_alias,
)
self.assertEqual(
closure.components.p4_port3_next_primary_line.name,
self.system._p4_primary_connection_for_node(
port3_far_port3.remote_node_alias
).line_alias,
)
port3_next_port3 = self.system._pnl0002_connection_for_node_port(
closure.components.p4_port3_next_node.alias,
"port_3",
)
self.assertEqual(
closure.components.p4_port3_next_port3_line.name,
port3_next_port3.line_alias,
)
self.assertEqual(
closure.components.p4_bridge_node.alias,
port3_next_port3.remote_node_alias,
)
self.assertEqual(
closure.components.p4_port3_next_orifice_output_line.name,
self.system._pnl0001_line_for_node_port(
closure.components.p4_port3_next_node.alias,
"port_4",
).name,
)
self.assertEqual(
closure.components.p4_port3_next_orifice.name,
"pn_morifice_13",
)
self.assertEqual(
closure.components.p4_port3_next_orifice_line.name,
self.system._pnl0003_line_for_node_port("pn_node3_14", "port_2").name,
)
self.assertEqual(
closure.components.p4_port3_next_orifice_node.alias,
"pn_node3_14",
)
chamber_segment = (
self.system.discover_pneumatic_branch_topology().chamber_segment_specs[3]
)
self.assertEqual(
closure.components.p4_port3_next_chamber_spec,
chamber_segment,
)
self.assertEqual(
closure.components.p4_port3_next_chamber_inlet_line.name,
chamber_segment.inlet_line_alias,
)
self.assertEqual(
closure.components.p4_port3_next_chamber_outlet_line.name,
chamber_segment.outlet_line_alias,
)
self.assertEqual(
closure.components.p4_port3_next_orifice_resistance.name,
self.system._pnl00r_line_for_node_port("pn_node3_14", "port_3").name,
)
self.assertEqual(
closure.components.p4_port3_next_resistance_node.alias,
"pn_node3_13",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_node_line.name,
self.system._pnl0003_line_for_node_port("pn_node3_13", "port_2").name,
)
self.assertEqual(
closure.components.p4_port3_next_resistance_orifice.name,
"pn_morifice_12",
)
self.assertEqual(
closure.components.p4_port3_next_resistance_output_line.name,
self.system._pnl0001_line_for_node_port(
closure.components.p4_bridge_node.alias,
"port_4",
).name,
)
resistance_chamber_segment = (
self.system.discover_pneumatic_branch_topology().chamber_segment_specs[2]
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_spec,
resistance_chamber_segment,
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_inlet_line.name,
resistance_chamber_segment.inlet_line_alias,
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_outlet_line.name,
resistance_chamber_segment.outlet_line_alias,
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_inlet_orifice.name,
resistance_chamber_segment.inlet_orifice_alias,
)
self.assertEqual(
closure.components.p4_port3_next_resistance_chamber_outlet_orifice.name,
resistance_chamber_segment.outlet_orifice_alias,
)
self.assertEqual(
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.p4_port3_remote_resistance_node.alias,
"pn_node3_15",
)
self.assertEqual(
closure.components.p4_port3_remote_resistance_node_line.name,
self.system._pnl0003_line_for_node_port("pn_node3_15", "port_2").name,
)
self.assertEqual(
closure.components.p4_port3_remote_resistance_orifice.name,
"pn_morifice_14",
)
self.assertEqual(
closure.components.p4_port3_remote_resistance_output_line.name,
self.system._pnl0001_line_for_node_port(
closure.components.p4_port3_far_node.alias,
"port_4",
).name,
)
self.assertEqual(
closure.components.node_orifice.name,
neighborhood.port_4.orifice_alias,
)
def test_p4_node_flow_cancels_between_pnvo_pnl0002_and_primary_line(self) -> None:
closure = self.system.pn3_p4_node_chamber_segment_closure_from_spec(
self.spec,
inlet_node_pressure_pa=15.31e6,
resistance_boundary_pressure_pa=15.29e6,
)
self.assertAlmostEqual(closure.components.node_orifice.opening, 0.0)
closure.components.node_orifice.opening = 1.0
snapshot = closure.snapshot()
rhs = closure.rhs(closure.initial_state_vector())
self.assertGreater(snapshot.pnl0003_to_p4_flow, 0.0)
self.assertAlmostEqual(
snapshot.p4_balance.port_2_mass_flow_g_s,
(
-snapshot.p4_to_port1_line_flow
- snapshot.p4_to_port3_line_flow
+ snapshot.pnl0003_to_p4_flow
)
* 1.0e3,
)
self.assertAlmostEqual(
snapshot.p4_node_to_primary_line_flow,
snapshot.p4_balance.port_2_mass_flow_g_s * 1.0e-3,
)
self.assertAlmostEqual(
snapshot.p4_node_to_primary_line_flow
+ snapshot.p4_to_port1_line_flow
+ snapshot.p4_to_port3_line_flow
- snapshot.pnl0003_to_p4_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port1_remote_node_to_primary_line_flow
+ snapshot.p4_port1_remote_node_to_line_flow
+ snapshot.p4_port1_remote_to_port1_line_flow
- snapshot.p4_port1_remote_orifice_to_node_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port1_far_node_to_primary_line_flow
+ snapshot.p4_port1_far_node_to_line_flow
+ snapshot.p4_port1_far_to_next_line_flow
- snapshot.p4_port1_next_orifice_resistance_to_p4_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port1_next_node_to_primary_line_flow
+ snapshot.p4_port1_next_node_to_line_flow
+ snapshot.p4_port1_next_to_bridge_line_flow
+ snapshot.p4_port1_next_orifice_p4_to_output_line_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_bridge_node_to_primary_line_flow
+ snapshot.p4_bridge_to_port1_next_line_flow
+ snapshot.p4_bridge_to_port3_next_line_flow
- snapshot.p4_port3_next_resistance_output_to_p4_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port1_remote_node_to_orifice_line_flow
+ snapshot.p4_port1_next_orifice_resistance_chamber_inlet_node_to_line_flow
- snapshot.node_to_resistance_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.node_to_pnl0003_flow
+ snapshot.node_to_resistance_flow
+ snapshot.outlet_node_to_line_flow,
0.0,
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
+ snapshot.p4_port3_remote_to_port3_line_flow
- snapshot.p4_port3_remote_orifice_to_node_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port3_remote_resistance_node_to_line_flow
- snapshot.p4_port3_remote_node_to_resistance_flow
+ snapshot.p4_port3_next_chamber_outlet_node_to_line_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port3_remote_resistance_output_to_p4_flow,
snapshot.p4_port3_remote_resistance_to_output_line_flow,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port3_far_node_to_primary_line_flow
+ snapshot.p4_port3_far_node_to_line_flow
+ snapshot.p4_port3_far_to_next_line_flow
- snapshot.p4_port3_remote_resistance_output_to_p4_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port3_next_node_to_primary_line_flow
+ snapshot.p4_port3_next_node_to_line_flow
+ snapshot.p4_port3_next_to_bridge_line_flow
- snapshot.p4_port3_next_orifice_output_to_p4_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port3_next_orifice_node_to_line_flow
+ snapshot.p4_port3_next_chamber_inlet_node_to_line_flow
- snapshot.p4_port3_next_resistance_node_to_next_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port3_next_orifice_output_to_p4_flow,
snapshot.p4_port3_next_orifice_to_output_line_flow,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port3_next_resistance_node_to_line_flow
+ snapshot.p4_port3_next_resistance_node_to_next_flow
+ snapshot.p4_port3_next_resistance_chamber_outlet_node_to_line_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port3_next_resistance_output_to_p4_flow,
snapshot.p4_port3_next_resistance_to_output_line_flow,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port1_next_orifice_node_to_line_flow
+ snapshot.p4_port3_next_resistance_chamber_inlet_node_to_line_flow
- snapshot.p4_port1_next_orifice_resistance_node_to_next_flow,
0.0,
delta=1.0e-12,
)
self.assertAlmostEqual(
snapshot.p4_port1_next_orifice_resistance_node_to_line_flow
+ snapshot.p4_port1_next_orifice_resistance_node_to_next_flow
+ snapshot.p4_port1_next_orifice_resistance_chamber_outlet_node_to_line_flow,
0.0,
delta=1.0e-12,
)
next_chamber_mass_sum = rhs[78] + rhs[80] + rhs[82]
self.assertAlmostEqual(
next_chamber_mass_sum,
(
snapshot.p4_port3_next_chamber_inlet_node_to_line_flow
+ snapshot.p4_port3_next_chamber_outlet_node_to_line_flow
),
delta=1.0e-12,
)
resistance_chamber_mass_sum = rhs[90] + rhs[92] + rhs[94]
self.assertAlmostEqual(
resistance_chamber_mass_sum,
(
snapshot.p4_port3_next_resistance_chamber_inlet_node_to_line_flow
+ snapshot.p4_port3_next_resistance_chamber_outlet_node_to_line_flow
),
delta=1.0e-12,
)
p4_port1_next_orifice_line_mass_sum = rhs[96] + rhs[98]
self.assertAlmostEqual(
p4_port1_next_orifice_line_mass_sum,
(
snapshot.p4_port1_next_orifice_node_to_line_flow
- snapshot.p4_port1_next_orifice_to_output_line_flow
),
delta=1.0e-12,
)
self.assertAlmostEqual(
rhs[100],
(
snapshot.p4_port1_next_orifice_p4_to_output_line_flow
+ snapshot.p4_port1_next_orifice_to_output_line_flow
),
delta=1.0e-12,
)
p4_port1_next_orifice_resistance_line_mass_sum = rhs[102] + rhs[104]
self.assertAlmostEqual(
p4_port1_next_orifice_resistance_line_mass_sum,
(
snapshot.p4_port1_next_orifice_resistance_node_to_line_flow
- snapshot.p4_port1_next_orifice_resistance_to_p4_flow
),
delta=1.0e-12,
)
p4_port1_next_orifice_resistance_chamber_mass_sum = (
rhs[106] + rhs[108] + rhs[110]
)
self.assertAlmostEqual(
p4_port1_next_orifice_resistance_chamber_mass_sum,
(
snapshot.p4_port1_next_orifice_resistance_chamber_inlet_node_to_line_flow
+ snapshot.p4_port1_next_orifice_resistance_chamber_outlet_node_to_line_flow
),
delta=1.0e-12,
)
mass_derivative_sum = sum(rhs[index] for index in range(0, 112, 2))
self.assertAlmostEqual(
mass_derivative_sum,
0.0,
delta=1.0e-12,
)
def test_simulates_one_hundred_twelve_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,
resistance_boundary_pressure_pa=15.29e6,
config=SolveIVPConfig(
t_start=0.0,
t_stop=1.0e-10,
max_step=1.0e-11,
),
t_eval=[0.0, 5.0e-11, 1.0e-10],
)
self.assertTrue(solution.success)
self.assertEqual(len(solution.t), 3)
self.assertEqual(len(solution.y), 112)
self.assertEqual([len(row) for row in solution.y], [3] * 112)
if __name__ == "__main__":
unittest.main()