公开更多 AMESim 组件并接入信号机械闭环

This commit is contained in:
huojiarong committed 2026-07-30 10:11:08 +00:00
1 parent db4bdb4b70
commit 3f51a124d6
28 files changed
+3397 -58

No files matched your search

@@ -21,14 +21,9 @@ class AmesimComponentMigrationMatrixTests(unittest.TestCase):
def test_unsupported_domains_are_not_marked_as_public_candidates(self) -> None:
text = MATRIX_PATH.read_text(encoding="utf-8")
unsupported = {
"F000",
"FORC",
"LMECHN1",
"LSTP00A",
"MECMAS21",
"PNRP17",
"STEP0",
"UD00",
}
for family in unsupported:
@@ -0,0 +1,69 @@
from __future__ import annotations
import unittest
from app.simulation.components.amesim.mechanical.translational import (
AmesimF000,
AmesimForc,
AmesimMecmas21,
)
from app.simulation.core.medium import IdealGasMedium
from app.simulation.registry import COMPONENT_MODEL_REGISTRY
class AmesimMechanicalPublicComponentTests(unittest.TestCase):
def setUp(self) -> None:
self.medium = IdealGasMedium()
def test_f000_constrains_mechanical_port_force_to_zero(self) -> None:
source = AmesimF000("zero_1")
source.port_1.f = 12.5
residuals = source.pressure_flow_equation_residuals()
self.assertEqual(len(residuals), 1)
self.assertEqual(residuals[0].variables, ("zero_1.port_1.f",))
self.assertAlmostEqual(residuals[0].value, 12.5)
def test_forc_converts_signal_to_opposing_source_port_force(self) -> None:
converter = AmesimForc("force_1")
converter.res.signal = 20.0
converter.port_2.f = -20.0
residuals = converter.pressure_flow_equation_residuals()
self.assertAlmostEqual(converter.output_force, 20.0)
self.assertAlmostEqual(residuals[0].value, 0.0)
self.assertEqual(converter.component_result_values(), {"force": 20.0})
def test_mecmas21_acceleration_uses_connected_port_forces(self) -> None:
mass = AmesimMecmas21(
"mass_1",
self.medium,
mass=2.0,
fcoul=0.0,
rvisc=0.0,
wind=0.0,
x0=0.1,
v0=0.2,
)
mass.port_1.f = 10.0
mass.port_2.f = -2.0
self.assertEqual(mass.get_state_vector(), [0.2, 0.1])
self.assertAlmostEqual(mass.acceleration(), 4.0)
self.assertEqual(mass.state_derivative_from_ports({}), [4.0, 0.2])
self.assertAlmostEqual(mass.port_1.x, 0.1)
self.assertAlmostEqual(mass.port_2.v, 0.2)
def test_mecmas21_registry_rejects_fractional_integer_options(self) -> None:
with self.assertRaisesRegex(ValueError, "useFriction must be an integer"):
COMPONENT_MODEL_REGISTRY["amesim_mecmas21"].create(
"mass_1",
self.medium,
{"useFriction": 0.5},
)
if __name__ == "__main__":
unittest.main()
+166
View File
@@ -0,0 +1,166 @@
from __future__ import annotations
import unittest
from app.main import (
ReactFlowProjectPayload,
build_reactflow_system_xml,
compile_reactflow_network,
run_system_xml_simulation,
)
from app.system_xml import validate_system_xml_document
from tests.test_amesim_pnvo001_signal_xml import signal_edge, signal_port
from tests.test_generic_system_xml_simulation import component_node, physical_edge
from tests.test_system_xml_protocol import physical_port
MECMAS21_DEFAULTS = {
"mass": 2.0,
"fstick": 0.0,
"fcoul": 0.0,
"rvisc": 0.0,
"wind": 0.0,
"dvel": 1.0e-6,
"restdvel": 1.0e-6,
"restcoeff": 0.65,
"astrib": 1.0e-3,
"xmin": -1.0,
"Kbmin": 1.0e9,
"Dbmin": 1.0e4,
"Pdmin": 1.0e-4,
"xmax": 1.0,
"Kbmax": 1.0e9,
"Dbmax": 1.0e4,
"Pdmax": 1.0e-4,
"theta": 0.0,
"useFriction": 1.0,
"stoptype": 4.0,
"discContactOption": 1.0,
"strib": 1.0,
"frictionType": 1.0,
"v0": 0.0,
"x0": 0.0,
}
def mechanical_port(name: str, side: str) -> dict[str, str]:
return physical_port(name, "bidirectional", side, domain="mechanical")
def zero_force_mass_project() -> ReactFlowProjectPayload:
return ReactFlowProjectPayload(
name="amesim-mechanical-zero-force-smoke",
nodes=[
component_node("zero_left", "amesim_f000", [mechanical_port("port_1", "right")]),
component_node(
"mass_1",
"amesim_mecmas21",
[mechanical_port("port_1", "left"), mechanical_port("port_2", "right")],
MECMAS21_DEFAULTS,
),
component_node("zero_right", "amesim_f000", [mechanical_port("port_1", "left")]),
],
edges=[
physical_edge("edge-1", "zero_left", "port_1", "mass_1", "port_1"),
physical_edge("edge-2", "mass_1", "port_2", "zero_right", "port_1"),
],
simulation={"t_start": 0.0, "t_stop": 0.02, "step": 0.01, "max_step": 0.01, "method": "BDF"},
)
def signal_force_mass_project() -> ReactFlowProjectPayload:
parameters = dict(MECMAS21_DEFAULTS)
parameters["mass"] = 2.0
return ReactFlowProjectPayload(
name="amesim-mechanical-signal-force-smoke",
nodes=[
component_node(
"force_signal",
"amesim_ud00",
[signal_port("out", "output", "right")],
{
"tstart": 0.0,
"start1": 10.0,
"end1": 10.0,
"t1": 1.0,
"start2": 10.0,
"end2": 10.0,
"t2": 0.0,
"start3": 10.0,
"end3": 10.0,
"t3": 0.0,
"start4": 10.0,
"end4": 10.0,
"t4": 0.0,
"start5": 10.0,
"end5": 10.0,
"t5": 0.0,
"start6": 10.0,
"end6": 10.0,
"t6": 0.0,
"start7": 10.0,
"end7": 10.0,
"t7": 0.0,
"start8": 10.0,
"end8": 10.0,
"t8": 0.0,
"nstages": 1.0,
"iscyclic": 0.0,
},
),
component_node(
"force_1",
"amesim_forc",
[signal_port("res", "input", "left"), mechanical_port("port_2", "right")],
),
component_node(
"mass_1",
"amesim_mecmas21",
[mechanical_port("port_1", "left"), mechanical_port("port_2", "right")],
parameters,
),
component_node("zero_right", "amesim_f000", [mechanical_port("port_1", "left")]),
],
edges=[
signal_edge("signal-1", "force_signal", "out", "force_1", "res"),
physical_edge("edge-1", "force_1", "port_2", "mass_1", "port_1"),
physical_edge("edge-2", "mass_1", "port_2", "zero_right", "port_1"),
],
simulation={"t_start": 0.0, "t_stop": 0.02, "step": 0.01, "max_step": 0.005, "method": "BDF"},
)
class AmesimMechanicalXmlTests(unittest.TestCase):
def test_zero_force_mechanical_project_compiles_and_simulates(self) -> None:
xml = build_reactflow_system_xml(zero_force_mass_project())
report = validate_system_xml_document(xml)
self.assertTrue(report.valid, report.as_dict())
network = compile_reactflow_network(zero_force_mass_project())
self.assertTrue(network.pressure_flow_structure_dict()["isSquare"])
result = run_system_xml_simulation(xml)
self.assertTrue(result["success"], result["message"])
self.assertEqual(result["series"]["time"], [0.0, 0.01, 0.02])
self.assertEqual(result["series"]["mass_1.v"], [0.0, 0.0, 0.0])
self.assertEqual(result["series"]["mass_1.x"], [0.0, 0.0, 0.0])
def test_signal_force_mechanical_project_compiles_and_simulates(self) -> None:
xml = build_reactflow_system_xml(signal_force_mass_project())
report = validate_system_xml_document(xml)
self.assertTrue(report.valid, report.as_dict())
network = compile_reactflow_network(signal_force_mass_project())
self.assertTrue(network.pressure_flow_structure_dict()["isSquare"])
result = run_system_xml_simulation(xml)
self.assertTrue(result["success"], result["message"])
self.assertEqual(result["series"]["force_signal.out.signal"], [10.0, 10.0, 10.0])
self.assertEqual(result["series"]["force_1.res.signal"], [10.0, 10.0, 10.0])
self.assertAlmostEqual(result["series"]["mass_1.a"][0], 5.0)
self.assertGreater(result["series"]["mass_1.v"][-1], 0.0)
self.assertGreater(result["series"]["mass_1.x"][-1], 0.0)
if __name__ == "__main__":
unittest.main()
+120
View File
@@ -0,0 +1,120 @@
from __future__ import annotations
import unittest
from app.simulation.components.amesim.storage.chambers import AmesimPnch012
from app.simulation.core.medium import IdealGasMedium
from app.simulation.registry import COMPONENT_MODEL_REGISTRY
class AmesimPnch012ComponentTests(unittest.TestCase):
def setUp(self) -> None:
self.medium = IdealGasMedium()
def test_default_create_preserves_parameterized_volume_contract(self) -> None:
chamber = COMPONENT_MODEL_REGISTRY["amesim_pnch012"].create(
"chamber_1",
self.medium,
{},
)
self.assertIsInstance(chamber, AmesimPnch012)
self.assertEqual(set(chamber.ports), {"port_1", "port_2", "port_3", "port_4"})
self.assertEqual(len(chamber.get_state_vector()), 2)
self.assertEqual(chamber.parameter_values["cvol0"], 0.015)
self.assertAlmostEqual(chamber.total_volume(), 0.015)
def test_total_volume_adds_four_external_volume_parameters(self) -> None:
chamber = AmesimPnch012(
"chamber_1",
self.medium,
cvol0=0.015,
vol1=0.001,
vol2=0.002,
vol3=0.003,
vol4=0.004,
dvol1=1.0e-6,
dvol2=2.0e-6,
dvol3=-1.0e-6,
dvol4=0.0,
)
self.assertAlmostEqual(chamber.total_volume(), 0.025)
self.assertAlmostEqual(chamber.total_volume_rate(), 2.0e-6)
def test_initial_state_uses_total_volume_pressure_and_temperature(self) -> None:
chamber = AmesimPnch012(
"chamber_1",
self.medium,
cvol0=0.015,
vol1=0.010,
p0=200000.0,
T0=300.0,
)
props = chamber.properties()
self.assertAlmostEqual(props.p, 200000.0, delta=1.0e-8)
self.assertAlmostEqual(props.T, 300.0)
self.assertAlmostEqual(chamber.port_1.p, props.p)
self.assertAlmostEqual(chamber.port_4.p, props.p)
def test_pressure_flow_residuals_bind_all_ports_to_chamber_state(self) -> None:
chamber = AmesimPnch012("chamber_1", self.medium)
chamber.properties()
residuals = {
residual.id.rsplit(":", 1)[1]: residual
for residual in chamber.pressure_flow_equation_residuals()
}
self.assertEqual(
set(residuals),
{
"port_1_pressure_state",
"port_2_pressure_state",
"port_3_pressure_state",
"port_4_pressure_state",
},
)
self.assertTrue(all(abs(residual.value) < 1.0e-9 for residual in residuals.values()))
def test_derivative_sums_four_mass_flows_and_boundary_work(self) -> None:
chamber = AmesimPnch012(
"chamber_1",
self.medium,
dvol1=1.0e-6,
kth=2.0,
sth=0.5,
extemp=310.0,
)
props = chamber.properties()
chamber.port_1.m_flow = 0.2
chamber.port_2.m_flow = -0.1
chamber.port_3.m_flow = 0.05
chamber.port_4.m_flow = 0.0
derivative = chamber.state_derivative_from_ports(
{
"port_1": props.h + 1000.0,
"port_2": props.h - 1000.0,
"port_3": props.h + 500.0,
"port_4": props.h,
}
)
self.assertAlmostEqual(derivative[0], 0.15)
self.assertLess(derivative[1], 0.2 * (props.h + 1000.0) + 0.05 * (props.h + 500.0))
def test_results_include_total_volume_and_volume_rate(self) -> None:
chamber = AmesimPnch012("chamber_1", self.medium, vol1=0.001, dvol1=1.0e-6)
values = chamber.component_result_values()
self.assertIn("vol", values)
self.assertIn("dvol", values)
self.assertAlmostEqual(values["vol"], 0.016)
self.assertAlmostEqual(values["dvol"], 1.0e-6)
if __name__ == "__main__":
unittest.main()
+93
View File
@@ -0,0 +1,93 @@
from __future__ import annotations
import unittest
from app.main import (
ReactFlowProjectPayload,
build_reactflow_system_xml,
compile_reactflow_network,
run_system_xml_simulation,
)
from app.system_xml import validate_system_xml_document
from tests.test_generic_system_xml_simulation import component_node, physical_edge
from tests.test_system_xml_protocol import physical_port
def _pnpl_node(index: int) -> object:
return component_node(
f"boundary_{index}",
"amesim_pnpl01",
[physical_port("port_1", "bidirectional", "left")],
{},
)
def amesim_pnch012_project() -> ReactFlowProjectPayload:
return ReactFlowProjectPayload(
name="amesim-pnch012-smoke",
nodes=[
component_node(
"chamber_1",
"amesim_pnch012",
[
physical_port("port_1", "bidirectional", "left"),
physical_port("port_2", "bidirectional", "right"),
physical_port("port_3", "bidirectional", "left"),
physical_port("port_4", "bidirectional", "right"),
],
{
"cvol0": 0.015,
"kth": 0.0,
"sth": 0.7,
"extemp": 300.0,
"gi": 1.0,
"p0": 200000.0,
"T0": 300.0,
"vol1": 0.001,
"vol2": 0.0,
"vol3": 0.0,
"vol4": 0.0,
"dvol1": 0.0,
"dvol2": 0.0,
"dvol3": 0.0,
"dvol4": 0.0,
},
),
_pnpl_node(1),
_pnpl_node(2),
_pnpl_node(3),
_pnpl_node(4),
],
edges=[
physical_edge("edge-1", "chamber_1", "port_1", "boundary_1", "port_1"),
physical_edge("edge-2", "chamber_1", "port_2", "boundary_2", "port_1"),
physical_edge("edge-3", "chamber_1", "port_3", "boundary_3", "port_1"),
physical_edge("edge-4", "chamber_1", "port_4", "boundary_4", "port_1"),
],
simulation={"t_start": 0.0, "t_stop": 0.002, "step": 0.001, "max_step": 0.001, "method": "BDF"},
)
class AmesimPnch012XmlTests(unittest.TestCase):
def test_pnch012_reactflow_project_compiles(self) -> None:
network = compile_reactflow_network(amesim_pnch012_project())
self.assertIn("chamber_1", network.components)
self.assertEqual(network.components["chamber_1"].model_type, "amesim_pnch012")
self.assertTrue(network.pressure_flow_structure_dict()["isSquare"])
def test_pnch012_system_xml_validates_and_simulates(self) -> None:
xml = build_reactflow_system_xml(amesim_pnch012_project())
report = validate_system_xml_document(xml)
self.assertTrue(report.valid, report.as_dict())
result = run_system_xml_simulation(xml)
self.assertTrue(result["success"], result["message"])
self.assertEqual(result["series"]["time"], [0.0, 0.001, 0.002])
self.assertIn("chamber_1.port_1.m_flow", result["series"])
self.assertIn("chamber_1.vol", result["series"])
if __name__ == "__main__":
unittest.main()
+139
View File
@@ -0,0 +1,139 @@
from __future__ import annotations
import unittest
from app.simulation.components.amesim.flow.pipes import AmesimPnl0001
from app.simulation.core.medium import IdealGasMedium
from app.simulation.registry import COMPONENT_MODEL_REGISTRY
class AmesimPnl0001ComponentTests(unittest.TestCase):
def setUp(self) -> None:
self.medium = IdealGasMedium()
def test_default_create_preserves_amesim_parameter_contract(self) -> None:
pipe = COMPONENT_MODEL_REGISTRY["amesim_pnl0001"].create(
"pnl_1",
self.medium,
{},
)
self.assertIsInstance(pipe, AmesimPnl0001)
self.assertEqual(set(pipe.ports), {"port_1", "port_2"})
self.assertEqual(
set(pipe.parameter_values),
{
"diam",
"le",
"rr",
"k",
"kth",
"extemp",
"gi",
"mode",
"p0",
"T0",
},
)
self.assertEqual(len(pipe.get_state_vector()), 2)
self.assertAlmostEqual(pipe.volume, 7.853981633974483e-5)
def test_rejects_fractional_integer_parameters(self) -> None:
with self.assertRaisesRegex(ValueError, "gi must be an integer"):
COMPONENT_MODEL_REGISTRY["amesim_pnl0001"].create(
"pnl_1",
self.medium,
{"gi": 1.5},
)
with self.assertRaisesRegex(ValueError, "mode must be an integer"):
COMPONENT_MODEL_REGISTRY["amesim_pnl0001"].create(
"pnl_1",
self.medium,
{"mode": 1.5},
)
def test_initial_state_uses_pipe_volume_pressure_and_temperature(self) -> None:
pipe = AmesimPnl0001(
"pnl_1",
self.medium,
diam=0.014,
le=1.0,
rr=0.045 / 14.0,
p0=15.3e6,
T0=293.15,
)
props = pipe.properties()
self.assertAlmostEqual(pipe.volume, 1.539380400258999e-4)
self.assertAlmostEqual(props.p, 15.3e6, delta=1.0e-5)
self.assertAlmostEqual(props.T, 293.15)
self.assertAlmostEqual(pipe.port_2.p, props.p)
def test_resistance_flow_follows_pressure_gradient(self) -> None:
pipe = AmesimPnl0001(
"pnl_1",
self.medium,
diam=0.014,
le=1.0,
rr=0.045 / 14.0,
p0=15.3e6,
T0=293.15,
)
props = pipe.properties()
forward = pipe.mass_flow(15.31e6, props.p, props.T)
reverse = pipe.mass_flow(15.29e6, props.p, props.T)
self.assertGreater(forward, 0.0)
self.assertLess(reverse, 0.0)
self.assertAlmostEqual(abs(forward), abs(reverse), delta=abs(forward) * 0.02)
def test_pressure_flow_residuals_do_not_force_storage_mass_balance(self) -> None:
pipe = AmesimPnl0001("pnl_1", self.medium)
pipe.port_1.p = 101000.0
pipe.port_2.m_flow = -1.0e-4
props = pipe.properties()
pipe.port_1.m_flow = pipe.mass_flow(pipe.port_1.p, pipe.port_2.p, props.T)
residuals = {
residual.id.rsplit(":", 1)[1]: residual
for residual in pipe.pressure_flow_equation_residuals()
}
self.assertEqual(
set(residuals),
{"port_2_pressure_state", "port_1_pressure_flow_relation"},
)
self.assertAlmostEqual(residuals["port_2_pressure_state"].value, 0.0)
self.assertAlmostEqual(residuals["port_1_pressure_flow_relation"].value, 0.0)
def test_connection_derivative_preserves_two_port_accumulation(self) -> None:
pipe = AmesimPnl0001("pnl_1", self.medium, kth=2.0, extemp=310.0)
props = pipe.properties()
pipe.port_1.m_flow = 0.2
pipe.port_2.m_flow = -0.1
derivative = pipe.state_derivative_from_ports(
{
"port_1": props.h + 1000.0,
"port_2": props.h - 1000.0,
}
)
self.assertAlmostEqual(derivative[0], 0.1)
self.assertGreater(derivative[1], 0.0)
def test_results_include_thermodynamic_and_pipe_diagnostics(self) -> None:
pipe = AmesimPnl0001("pnl_1", self.medium)
pipe.port_1.p = 101000.0
values = pipe.component_result_values()
self.assertEqual(
set(values),
{"m", "U", "p", "T", "rho", "u", "h", "re", "cm", "v", "ff"},
)
if __name__ == "__main__":
unittest.main()
+101
View File
@@ -0,0 +1,101 @@
from __future__ import annotations
import unittest
from app.main import (
ReactFlowProjectPayload,
build_reactflow_system_xml,
compile_reactflow_network,
run_system_xml_simulation,
)
from app.system_xml import validate_system_xml_document
from tests.test_generic_system_xml_simulation import component_node, physical_edge
from tests.test_system_xml_protocol import physical_port
def amesim_pnl0001_project() -> ReactFlowProjectPayload:
return ReactFlowProjectPayload(
name="amesim-pnl0001-smoke",
nodes=[
component_node(
"cylinder_1",
"cylinder",
[physical_port("port_b", "outlet", "right")],
{"volume": 0.01, "p0": 500000.0, "T0": 300.0},
),
component_node(
"pnl_1",
"amesim_pnl0001",
[
physical_port("port_1", "bidirectional", "left"),
physical_port("port_2", "bidirectional", "right"),
],
{
"diam": 0.01,
"le": 1.0,
"rr": 1.0e-5,
"k": 1.35,
"kth": 0.0,
"extemp": 300.0,
"gi": 1.0,
"mode": 2.0,
"p0": 300000.0,
"T0": 300.0,
},
),
component_node(
"resistance_1",
"amesim_pnl00r",
[
physical_port("port_1", "bidirectional", "left"),
physical_port("port_2", "bidirectional", "right"),
],
{"diam": 0.01, "le": 0.5, "rr": 1.0e-5, "gi": 1.0},
),
component_node(
"tank_1",
"tank",
[physical_port("port_a", "inlet", "left")],
{"volume": 0.1, "p0": 100000.0, "T0": 300.0},
),
],
edges=[
physical_edge("edge-1", "cylinder_1", "port_b", "pnl_1", "port_1"),
physical_edge("edge-2", "pnl_1", "port_2", "resistance_1", "port_1"),
physical_edge("edge-3", "resistance_1", "port_2", "tank_1", "port_a"),
],
simulation={
"t_start": 0.0,
"t_stop": 0.002,
"step": 0.001,
"max_step": 0.001,
"method": "BDF",
},
)
class AmesimPnl0001XmlTests(unittest.TestCase):
def test_pnl0001_reactflow_project_compiles(self) -> None:
network = compile_reactflow_network(amesim_pnl0001_project())
self.assertIn("pnl_1", network.components)
self.assertEqual(network.components["pnl_1"].model_type, "amesim_pnl0001")
self.assertTrue(network.pressure_flow_structure_dict()["isSquare"])
def test_pnl0001_system_xml_validates_and_simulates(self) -> None:
xml = build_reactflow_system_xml(amesim_pnl0001_project())
report = validate_system_xml_document(xml)
self.assertTrue(report.valid, report.as_dict())
result = run_system_xml_simulation(xml)
self.assertTrue(result["success"], result["message"])
self.assertEqual(result["series"]["time"], [0.0, 0.001, 0.002])
self.assertIn("pnl_1.port_1.m_flow", result["series"])
self.assertIn("pnl_1.re", result["series"])
self.assertIn("pnl_1.m", result["series"])
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,160 @@
from __future__ import annotations
import unittest
from app.simulation.components.amesim.flow.pipes import AmesimPnl0002, AmesimPnl0003
from app.simulation.core.medium import IdealGasMedium
from app.simulation.registry import COMPONENT_MODEL_REGISTRY
class AmesimPnl0002ComponentTests(unittest.TestCase):
def setUp(self) -> None:
self.medium = IdealGasMedium()
def test_default_create_preserves_contract(self) -> None:
pipe = COMPONENT_MODEL_REGISTRY["amesim_pnl0002"].create("pnl_2", self.medium, {})
self.assertIsInstance(pipe, AmesimPnl0002)
self.assertEqual(set(pipe.ports), {"port_1", "port_2"})
self.assertEqual(len(pipe.get_state_vector()), 2)
self.assertAlmostEqual(pipe.resistance_length, pipe.le / 2.0)
def test_center_compliance_initial_state(self) -> None:
pipe = AmesimPnl0002(
"pnl_2",
self.medium,
diam=0.02,
le=2.0,
rr=0.045 / 20.0,
p0=100000.0,
T0=293.15,
)
props = pipe.properties()
self.assertAlmostEqual(pipe.volume, 6.283185307179586e-4)
self.assertAlmostEqual(props.p, 100000.0, delta=1.0e-6)
self.assertAlmostEqual(props.T, 293.15)
def test_port_flows_enter_center_from_higher_external_pressure(self) -> None:
pipe = AmesimPnl0002("pnl_2", self.medium, p0=100000.0, T0=293.15)
center = pipe.properties()
forward = pipe.port_mass_flow(101000.0, center.p, center.T)
reverse = pipe.port_mass_flow(99000.0, center.p, center.T)
self.assertGreater(forward, 0.0)
self.assertLess(reverse, 0.0)
def test_pressure_flow_residuals_use_two_port_resistances(self) -> None:
pipe = AmesimPnl0002("pnl_2", self.medium, p0=100000.0, T0=293.15)
center = pipe.properties()
pipe.port_1.p = 101000.0
pipe.port_2.p = 99000.0
pipe.port_1.m_flow = pipe.port_mass_flow(pipe.port_1.p, center.p, center.T)
pipe.port_2.m_flow = pipe.port_mass_flow(pipe.port_2.p, center.p, center.T)
residuals = {
residual.id.rsplit(":", 1)[1]: residual
for residual in pipe.pressure_flow_equation_residuals()
}
self.assertEqual(
set(residuals),
{"port_1_pressure_flow_relation", "port_2_pressure_flow_relation"},
)
self.assertAlmostEqual(residuals["port_1_pressure_flow_relation"].value, 0.0)
self.assertAlmostEqual(residuals["port_2_pressure_flow_relation"].value, 0.0)
def test_connection_derivative_accumulates_two_external_flows(self) -> None:
pipe = AmesimPnl0002("pnl_2", self.medium)
props = pipe.properties()
pipe.port_1.m_flow = 0.2
pipe.port_2.m_flow = -0.1
derivative = pipe.state_derivative_from_ports(
{"port_1": props.h + 1000.0, "port_2": props.h - 1000.0}
)
self.assertAlmostEqual(derivative[0], 0.1)
class AmesimPnl0003ComponentTests(unittest.TestCase):
def setUp(self) -> None:
self.medium = IdealGasMedium()
def test_default_create_preserves_contract(self) -> None:
pipe = COMPONENT_MODEL_REGISTRY["amesim_pnl0003"].create("pnl_3", self.medium, {})
self.assertIsInstance(pipe, AmesimPnl0003)
self.assertEqual(set(pipe.ports), {"port_1", "port_2"})
self.assertEqual(len(pipe.get_state_vector()), 4)
def test_initial_state_uses_two_half_volume_compliances(self) -> None:
pipe = AmesimPnl0003(
"pnl_3",
self.medium,
diam=0.02,
le=0.3,
rr=0.045 / 20.0,
p1_0=15.3e6,
T1_0=293.15,
p2_0=15.3e6,
T2_0=293.15,
)
port_1 = pipe.properties_1()
port_2 = pipe.properties_2()
self.assertAlmostEqual(pipe.volume, 9.424777960769381e-5)
self.assertAlmostEqual(pipe.compliance_volume, pipe.volume / 2.0)
self.assertAlmostEqual(port_1.p, 15.3e6, delta=1.0e-5)
self.assertAlmostEqual(port_2.p, 15.3e6, delta=1.0e-5)
def test_center_resistance_flow_follows_end_pressure_gradient(self) -> None:
pipe = AmesimPnl0003("pnl_3", self.medium, p1_0=101000.0, p2_0=100000.0)
forward = pipe.resistance_mass_flow()
pipe = AmesimPnl0003("pnl_3", self.medium, p1_0=100000.0, p2_0=101000.0)
reverse = pipe.resistance_mass_flow()
self.assertGreater(forward, 0.0)
self.assertLess(reverse, 0.0)
def test_pressure_flow_residuals_bind_both_port_pressures_to_states(self) -> None:
pipe = AmesimPnl0003("pnl_3", self.medium)
pipe.properties_1()
pipe.properties_2()
residuals = {
residual.id.rsplit(":", 1)[1]: residual
for residual in pipe.pressure_flow_equation_residuals()
}
self.assertEqual(set(residuals), {"port_1_pressure_state", "port_2_pressure_state"})
self.assertAlmostEqual(residuals["port_1_pressure_state"].value, 0.0)
self.assertAlmostEqual(residuals["port_2_pressure_state"].value, 0.0)
def test_connection_derivative_conserves_external_and_center_flows(self) -> None:
pipe = AmesimPnl0003("pnl_3", self.medium, p1_0=101000.0, p2_0=100000.0)
port_1 = pipe.properties_1()
port_2 = pipe.properties_2()
pipe.port_1.m_flow = 0.2
pipe.port_2.m_flow = -0.1
derivative = pipe.state_derivative_from_ports(
{"port_1": port_1.h + 1000.0, "port_2": port_2.h - 1000.0}
)
self.assertAlmostEqual(derivative[0] + derivative[2], 0.1)
def test_results_include_two_thermodynamic_sides_and_center_flow(self) -> None:
pipe = AmesimPnl0003("pnl_3", self.medium, p1_0=101000.0, p2_0=100000.0)
values = pipe.component_result_values()
self.assertIn("m1", values)
self.assertIn("m2", values)
self.assertIn("dmctr", values)
self.assertIn("re", values)
if __name__ == "__main__":
unittest.main()
+159
View File
@@ -0,0 +1,159 @@
from __future__ import annotations
import unittest
from app.main import (
ReactFlowProjectPayload,
build_reactflow_system_xml,
compile_reactflow_network,
run_system_xml_simulation,
)
from app.system_xml import validate_system_xml_document
from tests.test_generic_system_xml_simulation import component_node, physical_edge
from tests.test_system_xml_protocol import physical_port
def _storage_nodes(*, source_pressure: float = 500000.0, sink_pressure: float = 100000.0) -> list:
return [
component_node(
"cylinder_1",
"cylinder",
[physical_port("port_b", "outlet", "right")],
{"volume": 0.01, "p0": source_pressure, "T0": 300.0},
),
component_node(
"tank_1",
"tank",
[physical_port("port_a", "inlet", "left")],
{"volume": 0.1, "p0": sink_pressure, "T0": 300.0},
),
]
def _dynamic_pipe_params() -> dict[str, float]:
return {
"diam": 0.01,
"le": 1.0,
"rr": 1.0e-5,
"k": 1.35,
"kth": 0.0,
"extemp": 300.0,
"gi": 1.0,
"mode": 2.0,
"p0": 300000.0,
"T0": 300.0,
}
def _resistance_node(name: str) -> object:
return component_node(
name,
"amesim_pnl00r",
[
physical_port("port_1", "bidirectional", "left"),
physical_port("port_2", "bidirectional", "right"),
],
{"diam": 0.01, "le": 0.5, "rr": 1.0e-5, "gi": 1.0},
)
def amesim_pnl0002_project() -> ReactFlowProjectPayload:
return ReactFlowProjectPayload(
name="amesim-pnl0002-smoke",
nodes=[
_storage_nodes()[0],
component_node(
"pnl_2",
"amesim_pnl0002",
[
physical_port("port_1", "bidirectional", "left"),
physical_port("port_2", "bidirectional", "right"),
],
_dynamic_pipe_params(),
),
_storage_nodes()[1],
],
edges=[
physical_edge("edge-1", "cylinder_1", "port_b", "pnl_2", "port_1"),
physical_edge("edge-2", "pnl_2", "port_2", "tank_1", "port_a"),
],
simulation={"t_start": 0.0, "t_stop": 0.002, "step": 0.001, "max_step": 0.001, "method": "BDF"},
)
def amesim_pnl0003_project() -> ReactFlowProjectPayload:
params = {
key: value
for key, value in _dynamic_pipe_params().items()
if key not in {"p0", "T0"}
}
params.update({"p1_0": 300000.0, "T1_0": 300.0, "p2_0": 300000.0, "T2_0": 300.0})
return ReactFlowProjectPayload(
name="amesim-pnl0003-smoke",
nodes=[
_storage_nodes(source_pressure=300000.0, sink_pressure=300000.0)[0],
_resistance_node("resistance_1"),
component_node(
"pnl_3",
"amesim_pnl0003",
[
physical_port("port_1", "bidirectional", "left"),
physical_port("port_2", "bidirectional", "right"),
],
params,
),
_resistance_node("resistance_2"),
_storage_nodes(source_pressure=300000.0, sink_pressure=300000.0)[1],
],
edges=[
physical_edge("edge-1", "cylinder_1", "port_b", "resistance_1", "port_1"),
physical_edge("edge-2", "resistance_1", "port_2", "pnl_3", "port_1"),
physical_edge("edge-3", "pnl_3", "port_2", "resistance_2", "port_1"),
physical_edge("edge-4", "resistance_2", "port_2", "tank_1", "port_a"),
],
simulation={"t_start": 0.0, "t_stop": 0.002, "step": 0.001, "max_step": 0.001, "method": "BDF"},
)
class AmesimPnl0002Pnl0003XmlTests(unittest.TestCase):
def test_pnl0002_reactflow_project_compiles(self) -> None:
network = compile_reactflow_network(amesim_pnl0002_project())
self.assertIn("pnl_2", network.components)
self.assertEqual(network.components["pnl_2"].model_type, "amesim_pnl0002")
self.assertTrue(network.pressure_flow_structure_dict()["isSquare"])
def test_pnl0002_system_xml_validates_and_simulates(self) -> None:
xml = build_reactflow_system_xml(amesim_pnl0002_project())
report = validate_system_xml_document(xml)
self.assertTrue(report.valid, report.as_dict())
result = run_system_xml_simulation(xml)
self.assertTrue(result["success"], result["message"])
self.assertEqual(result["series"]["time"], [0.0, 0.001, 0.002])
self.assertIn("pnl_2.port_1.m_flow", result["series"])
self.assertIn("pnl_2.m", result["series"])
def test_pnl0003_reactflow_project_compiles(self) -> None:
network = compile_reactflow_network(amesim_pnl0003_project())
self.assertIn("pnl_3", network.components)
self.assertEqual(network.components["pnl_3"].model_type, "amesim_pnl0003")
self.assertTrue(network.pressure_flow_structure_dict()["isSquare"])
def test_pnl0003_system_xml_validates_and_simulates(self) -> None:
xml = build_reactflow_system_xml(amesim_pnl0003_project())
report = validate_system_xml_document(xml)
self.assertTrue(report.valid, report.as_dict())
result = run_system_xml_simulation(xml)
self.assertTrue(result["success"], result["message"])
self.assertEqual(result["series"]["time"], [0.0, 0.001, 0.002])
self.assertIn("pnl_3.port_1.m_flow", result["series"])
self.assertIn("pnl_3.dmctr", result["series"])
if __name__ == "__main__":
unittest.main()
+112
View File
@@ -0,0 +1,112 @@
from __future__ import annotations
import unittest
from app.main import (
ReactFlowProjectPayload,
build_reactflow_system_xml,
compile_reactflow_network,
run_system_xml_simulation,
)
from app.system_xml import validate_system_xml_document
from tests.test_generic_system_xml_simulation import component_node, physical_edge
from tests.test_system_xml_protocol import physical_port
def signal_port(name: str, role: str, side: str) -> dict[str, str | None]:
return {
"name": name,
"kind": "signal",
"domain": "signal",
"nominalRole": role,
"positiveFlowDirection": None,
"side": side,
}
def signal_edge(edge_id: str, source: str, source_port: str, target: str, target_port: str) -> dict[str, str]:
return {
"id": edge_id,
"source": source,
"sourceHandle": source_port,
"target": target,
"targetHandle": target_port,
}
def amesim_pnvo001_signal_project() -> ReactFlowProjectPayload:
return ReactFlowProjectPayload(
name="amesim-pnvo001-signal-smoke",
nodes=[
component_node(
"step_1",
"amesim_step0",
[signal_port("out", "output", "right")],
{"initial": 1.0, "final": 1.0, "time": 0.0},
),
component_node(
"cylinder_1",
"cylinder",
[physical_port("port_b", "outlet", "right")],
{"volume": 0.01, "p0": 300000.0, "T0": 300.0},
),
component_node(
"valve_1",
"amesim_pnvo001",
[
signal_port("res", "input", "left"),
physical_port("port_2", "bidirectional", "left"),
physical_port("port_3", "bidirectional", "right"),
],
{
"cq": 0.72,
"area0": 5.0e-6,
"Cv": 0.5,
"Kv": 0.4,
"gi": 1.0,
"flowset": 1.0,
"opening0": 0.0,
},
),
component_node(
"tank_1",
"tank",
[physical_port("port_a", "inlet", "left")],
{"volume": 0.1, "p0": 100000.0, "T0": 300.0},
),
],
edges=[
signal_edge("signal-1", "step_1", "out", "valve_1", "res"),
physical_edge("edge-1", "cylinder_1", "port_b", "valve_1", "port_2"),
physical_edge("edge-2", "valve_1", "port_3", "tank_1", "port_a"),
],
simulation={"t_start": 0.0, "t_stop": 0.002, "step": 0.001, "max_step": 0.001, "method": "BDF"},
)
class AmesimPnvo001SignalXmlTests(unittest.TestCase):
def test_signal_project_compiles_with_signal_connection(self) -> None:
network = compile_reactflow_network(amesim_pnvo001_signal_project())
self.assertIn("step_1", network.components)
self.assertIn("valve_1", network.components)
self.assertEqual(network.components["valve_1"].model_type, "amesim_pnvo001")
self.assertTrue(network.pressure_flow_structure_dict()["isSquare"])
def test_signal_system_xml_validates_and_simulates(self) -> None:
xml = build_reactflow_system_xml(amesim_pnvo001_signal_project())
report = validate_system_xml_document(xml)
self.assertTrue(report.valid, report.as_dict())
result = run_system_xml_simulation(xml)
self.assertTrue(result["success"], result["message"])
self.assertEqual(result["series"]["time"], [0.0, 0.001, 0.002])
self.assertEqual(result["series"]["step_1.out.signal"], [1.0, 1.0, 1.0])
self.assertEqual(result["series"]["valve_1.res.signal"], [1.0, 1.0, 1.0])
self.assertIn("valve_1.xv", result["series"])
self.assertGreater(result["diagnostics"]["signal"]["propagations"], 0)
if __name__ == "__main__":
unittest.main()
+97
View File
@@ -0,0 +1,97 @@
from __future__ import annotations
import unittest
from app.simulation.components.amesim.flow.orifices import AmesimPnvo001SignalOpening
from app.simulation.components.amesim.signals.sources import AmesimStep0, AmesimUd00
from app.simulation.core.medium import IdealGasMedium
from app.simulation.registry import COMPONENT_MODEL_REGISTRY
from app.simulation.solvers.signal import SignalResolver
from app.simulation.systems.network import SimulationNetwork
class AmesimSignalComponentTests(unittest.TestCase):
def setUp(self) -> None:
self.medium = IdealGasMedium()
def test_step0_output_switches_at_step_time(self) -> None:
step = AmesimStep0("step_1", self.medium, initial=0.2, final=0.8, time=0.5)
self.assertEqual(step.output_at(0.49), 0.2)
self.assertEqual(step.output_at(0.5), 0.8)
self.assertEqual(step.signal_output_values(0.5), {"out": 0.8})
def test_ud00_output_interpolates_piecewise_signal(self) -> None:
signal = AmesimUd00(
"piecewise_1",
self.medium,
tstart=0.5,
starts=(0.0, 10.0, 20.0, 0.0, 0.0, 0.0, 0.0, 0.0),
ends=(10.0, 20.0, 30.0, 0.0, 0.0, 0.0, 0.0, 0.0),
durations=(1.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0),
nstages=3,
)
self.assertAlmostEqual(signal.output_at(0.0), 0.0)
self.assertAlmostEqual(signal.output_at(1.0), 5.0)
self.assertAlmostEqual(signal.output_at(2.5), 15.0)
self.assertAlmostEqual(signal.output_at(5.0), 35.0)
self.assertEqual(signal.signal_output_values(2.5), {"out": 15.0})
def test_ud00_can_cycle_active_stages(self) -> None:
signal = AmesimUd00(
"piecewise_1",
self.medium,
starts=(0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
ends=(10.0, 20.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
durations=(1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
nstages=2,
iscyclic=True,
)
self.assertAlmostEqual(signal.output_at(0.25), 2.5)
self.assertAlmostEqual(signal.output_at(1.25), 12.5)
self.assertAlmostEqual(signal.output_at(2.25), 2.5)
def test_ud00_registry_rejects_fractional_stage_controls(self) -> None:
with self.assertRaisesRegex(ValueError, "nstages must be an integer"):
COMPONENT_MODEL_REGISTRY["amesim_ud00"].create(
"piecewise_1",
self.medium,
{"nstages": 1.5},
)
def test_pnvo001_signal_opening_reads_res_port(self) -> None:
valve = COMPONENT_MODEL_REGISTRY["amesim_pnvo001"].create(
"valve_1",
self.medium,
{"opening0": 0.25},
)
self.assertIsInstance(valve, AmesimPnvo001SignalOpening)
self.assertEqual(set(valve.ports), {"res", "port_2", "port_3"})
self.assertAlmostEqual(valve.opening, 0.25)
valve.res.signal = 1.5
self.assertAlmostEqual(valve.opening, 1.0)
valve.res.signal = -0.5
self.assertAlmostEqual(valve.opening, 0.0)
def test_signal_resolver_propagates_step_to_valve_input(self) -> None:
network = SimulationNetwork("signal-smoke")
step = AmesimStep0("step_1", self.medium, initial=0.0, final=0.75, time=0.1)
valve = AmesimPnvo001SignalOpening("valve_1", self.medium, opening0=0.0)
network.add_component(step)
network.add_component(valve)
network.connect("step_1", "out", "valve_1", "res", connection_id="signal-1")
resolver = SignalResolver(network)
resolver.solve(0.2)
self.assertAlmostEqual(step.out.signal, 0.75)
self.assertAlmostEqual(valve.res.signal, 0.75)
self.assertAlmostEqual(valve.opening, 0.75)
if __name__ == "__main__":
unittest.main()
+120
View File
@@ -0,0 +1,120 @@
from __future__ import annotations
import unittest
from app.main import (
ReactFlowProjectPayload,
build_reactflow_system_xml,
compile_reactflow_network,
run_system_xml_simulation,
)
from app.system_xml import validate_system_xml_document
from tests.test_amesim_pnvo001_signal_xml import signal_edge, signal_port
from tests.test_generic_system_xml_simulation import component_node, physical_edge
from tests.test_system_xml_protocol import physical_port
def amesim_ud00_signal_project() -> ReactFlowProjectPayload:
return ReactFlowProjectPayload(
name="amesim-ud00-signal-smoke",
nodes=[
component_node(
"piecewise_1",
"amesim_ud00",
[signal_port("out", "output", "right")],
{
"tstart": 0.0,
"start1": 1.0,
"end1": 1.0,
"t1": 1.0,
"start2": 1.0,
"end2": 1.0,
"t2": 0.0,
"start3": 1.0,
"end3": 1.0,
"t3": 0.0,
"start4": 1.0,
"end4": 1.0,
"t4": 0.0,
"start5": 1.0,
"end5": 1.0,
"t5": 0.0,
"start6": 1.0,
"end6": 1.0,
"t6": 0.0,
"start7": 1.0,
"end7": 1.0,
"t7": 0.0,
"start8": 1.0,
"end8": 1.0,
"t8": 0.0,
"nstages": 1.0,
"iscyclic": 0.0,
},
),
component_node(
"cylinder_1",
"cylinder",
[physical_port("port_b", "outlet", "right")],
{"volume": 0.01, "p0": 300000.0, "T0": 300.0},
),
component_node(
"valve_1",
"amesim_pnvo001",
[
signal_port("res", "input", "left"),
physical_port("port_2", "bidirectional", "left"),
physical_port("port_3", "bidirectional", "right"),
],
{
"cq": 0.72,
"area0": 5.0e-6,
"Cv": 0.5,
"Kv": 0.4,
"gi": 1.0,
"flowset": 1.0,
"opening0": 0.0,
},
),
component_node(
"tank_1",
"tank",
[physical_port("port_a", "inlet", "left")],
{"volume": 0.1, "p0": 100000.0, "T0": 300.0},
),
],
edges=[
signal_edge("signal-1", "piecewise_1", "out", "valve_1", "res"),
physical_edge("edge-1", "cylinder_1", "port_b", "valve_1", "port_2"),
physical_edge("edge-2", "valve_1", "port_3", "tank_1", "port_a"),
],
simulation={"t_start": 0.0, "t_stop": 0.002, "step": 0.001, "max_step": 0.001, "method": "BDF"},
)
class AmesimUd00XmlTests(unittest.TestCase):
def test_signal_project_compiles_with_signal_connection(self) -> None:
network = compile_reactflow_network(amesim_ud00_signal_project())
self.assertIn("piecewise_1", network.components)
self.assertEqual(network.components["piecewise_1"].model_type, "amesim_ud00")
self.assertEqual(network.components["valve_1"].model_type, "amesim_pnvo001")
self.assertTrue(network.pressure_flow_structure_dict()["isSquare"])
def test_signal_system_xml_validates_and_simulates(self) -> None:
xml = build_reactflow_system_xml(amesim_ud00_signal_project())
report = validate_system_xml_document(xml)
self.assertTrue(report.valid, report.as_dict())
result = run_system_xml_simulation(xml)
self.assertTrue(result["success"], result["message"])
self.assertEqual(result["series"]["time"], [0.0, 0.001, 0.002])
self.assertEqual(result["series"]["piecewise_1.out.signal"], [1.0, 1.0, 1.0])
self.assertEqual(result["series"]["valve_1.res.signal"], [1.0, 1.0, 1.0])
self.assertIn("valve_1.xv", result["series"])
self.assertGreater(result["diagnostics"]["signal"]["propagations"], 0)
if __name__ == "__main__":
unittest.main()
+55 -2
View File
@@ -47,8 +47,8 @@ class ComponentCatalogTests(unittest.TestCase):
}
self.assertEqual(library["label"], "AMESim 组件库")
self.assertEqual([category["id"] for category in library["categories"]], ["storage", "flow", "junctions", "boundary"])
self.assertEqual(set(components), {"amesim_pnpl01", "amesim_pnch023", "amesim_pnor001", "amesim_pnvo001_fixed", "amesim_pnl00r", "amesim_pn3node2", "amesim_p4node2"})
self.assertEqual([category["id"] for category in library["categories"]], ["storage", "flow", "junctions", "boundary", "signals", "mechanical"])
self.assertEqual(set(components), {"amesim_pnpl01", "amesim_step0", "amesim_ud00", "amesim_f000", "amesim_forc", "amesim_mecmas21", "amesim_pnch023", "amesim_pnch012", "amesim_pnor001", "amesim_pnvo001_fixed", "amesim_pnvo001", "amesim_pnl00r", "amesim_pnl0001", "amesim_pnl0002", "amesim_pnl0003", "amesim_pn3node2", "amesim_p4node2"})
self.assertEqual(
[port["name"] for port in components["amesim_p4node2"]["ports"]],
["port_1", "port_2", "port_3", "port_4"],
@@ -64,6 +64,15 @@ class ComponentCatalogTests(unittest.TestCase):
self.assertEqual(pnch_parameters["cvol"]["quantity"], "volume")
self.assertEqual(pnch_parameters["kth"]["quantity"], "heat_transfer_coefficient")
pnch012_parameters = {
parameter["name"]: parameter
for parameter in components["amesim_pnch012"]["parameters"]
}
self.assertEqual(components["amesim_pnch012"]["category"]["id"], "storage")
self.assertEqual([port["name"] for port in components["amesim_pnch012"]["ports"]], ["port_1", "port_2", "port_3", "port_4"])
self.assertEqual(pnch012_parameters["cvol0"]["quantity"], "volume")
self.assertEqual(pnch012_parameters["dvol1"]["unit"], "m3/s")
pnor_parameters = {
parameter["name"]: parameter
for parameter in components["amesim_pnor001"]["parameters"]
@@ -79,6 +88,33 @@ class ComponentCatalogTests(unittest.TestCase):
self.assertEqual(pnvo_parameters["opening"]["maximum"], 1.0)
self.assertEqual([port["name"] for port in components["amesim_pnvo001_fixed"]["ports"]], ["port_2", "port_3"])
self.assertEqual(components["amesim_step0"]["category"]["id"], "signals")
self.assertEqual([port["name"] for port in components["amesim_step0"]["ports"]], ["out"])
ud00_parameters = {
parameter["name"]: parameter
for parameter in components["amesim_ud00"]["parameters"]
}
self.assertEqual(components["amesim_ud00"]["category"]["id"], "signals")
self.assertEqual([port["name"] for port in components["amesim_ud00"]["ports"]], ["out"])
self.assertEqual(ud00_parameters["tstart"]["quantity"], "time")
self.assertEqual(ud00_parameters["nstages"]["maximum"], 8.0)
self.assertEqual(components["amesim_f000"]["category"]["id"], "mechanical")
self.assertEqual([port["name"] for port in components["amesim_f000"]["ports"]], ["port_1"])
self.assertEqual(components["amesim_f000"]["ports"][0]["domain"], "mechanical")
self.assertEqual(components["amesim_forc"]["category"]["id"], "mechanical")
self.assertEqual([port["name"] for port in components["amesim_forc"]["ports"]], ["res", "port_2"])
self.assertEqual(components["amesim_forc"]["ports"][1]["domain"], "mechanical")
mecmas_parameters = {
parameter["name"]: parameter
for parameter in components["amesim_mecmas21"]["parameters"]
}
self.assertEqual(components["amesim_mecmas21"]["category"]["id"], "mechanical")
self.assertEqual([port["name"] for port in components["amesim_mecmas21"]["ports"]], ["port_1", "port_2"])
self.assertEqual(mecmas_parameters["mass"]["unit"], "kg")
self.assertEqual(mecmas_parameters["Kbmin"]["unit"], "N/m")
self.assertEqual(components["amesim_pnvo001"]["category"]["id"], "flow")
self.assertEqual([port["name"] for port in components["amesim_pnvo001"]["ports"]], ["res", "port_2", "port_3"])
pnl_parameters = {
parameter["name"]: parameter
for parameter in components["amesim_pnl00r"]["parameters"]
@@ -87,6 +123,23 @@ class ComponentCatalogTests(unittest.TestCase):
self.assertEqual(pnl_parameters["diam"]["quantity"], "length")
self.assertEqual(pnl_parameters["le"]["unit"], "m")
pnl0001_parameters = {
parameter["name"]: parameter
for parameter in components["amesim_pnl0001"]["parameters"]
}
self.assertEqual(components["amesim_pnl0001"]["category"]["id"], "flow")
self.assertEqual(pnl0001_parameters["kth"]["quantity"], "heat_transfer_coefficient")
self.assertEqual(pnl0001_parameters["p0"]["unit"], "Pa")
self.assertEqual(components["amesim_pnl0002"]["category"]["id"], "flow")
self.assertEqual(components["amesim_pnl0003"]["category"]["id"], "flow")
pnl0003_parameters = {
parameter["name"]: parameter
for parameter in components["amesim_pnl0003"]["parameters"]
}
self.assertEqual(pnl0003_parameters["p1_0"]["unit"], "Pa")
self.assertEqual(pnl0003_parameters["T2_0"]["quantity"], "temperature")
def test_every_registered_component_is_in_the_catalog(self) -> None:
self.assertEqual(
set(self.components),
+20
View File
@@ -31,10 +31,20 @@ class ComponentRegistryTests(unittest.TestCase):
"orifice",
"tee",
"amesim_pnpl01",
"amesim_step0",
"amesim_ud00",
"amesim_f000",
"amesim_forc",
"amesim_mecmas21",
"amesim_pnch023",
"amesim_pnch012",
"amesim_pnor001",
"amesim_pnvo001_fixed",
"amesim_pnvo001",
"amesim_pnl00r",
"amesim_pnl0001",
"amesim_pnl0002",
"amesim_pnl0003",
"amesim_pn3node2",
"amesim_p4node2",
),
@@ -51,10 +61,20 @@ class ComponentRegistryTests(unittest.TestCase):
self.assertIn("amesim", libraries)
self.assertEqual(libraries["amesim"], AMESIM_LIBRARY)
self.assertEqual(models["amesim_pnpl01"].library.id, "amesim")
self.assertEqual(models["amesim_step0"].library.id, "amesim")
self.assertEqual(models["amesim_ud00"].library.id, "amesim")
self.assertEqual(models["amesim_f000"].library.id, "amesim")
self.assertEqual(models["amesim_forc"].library.id, "amesim")
self.assertEqual(models["amesim_mecmas21"].library.id, "amesim")
self.assertEqual(models["amesim_pnch023"].library.id, "amesim")
self.assertEqual(models["amesim_pnch012"].library.id, "amesim")
self.assertEqual(models["amesim_pnor001"].library.id, "amesim")
self.assertEqual(models["amesim_pnvo001_fixed"].library.id, "amesim")
self.assertEqual(models["amesim_pnvo001"].library.id, "amesim")
self.assertEqual(models["amesim_pnl00r"].library.id, "amesim")
self.assertEqual(models["amesim_pnl0001"].library.id, "amesim")
self.assertEqual(models["amesim_pnl0002"].library.id, "amesim")
self.assertEqual(models["amesim_pnl0003"].library.id, "amesim")
self.assertEqual(models["amesim_pn3node2"].library.id, "amesim")
self.assertEqual(models["amesim_p4node2"].library.id, "amesim")