Files
SystemSimulationApp/PythonModels/systems/test_mql_pneumatic_topology.py
T

129 lines
5.0 KiB
Python

from __future__ import annotations
from PythonModels.systems.test_mql_closure import TestMqlPneumaticChamberSegmentSpec
from PythonModels.systems.test_mql_topology import TestMqlCirTopology
def discover_fixed_chamber_segments(
topology: TestMqlCirTopology,
component_specs: list[dict[str, object]],
connection_specs: list[dict[str, object]],
) -> tuple[TestMqlPneumaticChamberSegmentSpec, ...]:
submodel_by_alias = {
str(component["alias"]): str(component["submodel"])
for component in component_specs
}
segments = []
for component in component_specs:
volume_alias = str(component["alias"])
if component["submodel"] != "PNCH023":
continue
orifice_contacts = []
for contact in topology.contacts_for(volume_alias):
other_alias, other_port = contact.other_endpoint(volume_alias)
if submodel_by_alias.get(other_alias) == "PNOR001":
orifice_contacts.append(
(
other_alias,
other_port,
contact.port_for(volume_alias),
)
)
if len(orifice_contacts) != 2:
raise ValueError(
f"{volume_alias} must contact exactly two PNOR001 orifices; "
f"found {len(orifice_contacts)}"
)
sides = [
_resolve_orifice_boundary(
orifice_alias=orifice_alias,
orifice_volume_port=orifice_volume_port,
volume_port=volume_port,
connection_specs=connection_specs,
submodel_by_alias=submodel_by_alias,
)
for orifice_alias, orifice_volume_port, volume_port in orifice_contacts
]
inlet_sides = [side for side in sides if side["role"] == "inlet"]
outlet_sides = [side for side in sides if side["role"] == "outlet"]
if len(inlet_sides) != 1 or len(outlet_sides) != 1:
raise ValueError(
f"{volume_alias} requires one inlet and one outlet topology side"
)
inlet = inlet_sides[0]
outlet = outlet_sides[0]
segments.append(
TestMqlPneumaticChamberSegmentSpec(
name=f"{volume_alias}_segment",
inlet_node_alias=inlet["node_alias"],
inlet_line_alias=inlet["line_alias"],
inlet_orifice_alias=inlet["orifice_alias"],
inlet_orifice_boundary_port=inlet["orifice_boundary_port"],
inlet_orifice_volume_port=inlet["orifice_volume_port"],
volume_alias=volume_alias,
volume_inlet_port=inlet["volume_port"],
volume_outlet_port=outlet["volume_port"],
outlet_orifice_alias=outlet["orifice_alias"],
outlet_orifice_volume_port=outlet["orifice_volume_port"],
outlet_orifice_boundary_port=outlet["orifice_boundary_port"],
outlet_line_alias=outlet["line_alias"],
outlet_node_alias=outlet["node_alias"],
)
)
return tuple(segments)
def _resolve_orifice_boundary(
*,
orifice_alias: str,
orifice_volume_port: str,
volume_port: str,
connection_specs: list[dict[str, object]],
submodel_by_alias: dict[str, str],
) -> dict[str, str]:
boundary_connections = []
for connection in connection_specs:
if (
connection["source_component"] == orifice_alias
and connection["source_port"] != orifice_volume_port
) or (
connection["target_component"] == orifice_alias
and connection["target_port"] != orifice_volume_port
):
boundary_connections.append(connection)
if len(boundary_connections) != 1:
raise ValueError(
f"{orifice_alias} must have exactly one non-volume boundary connection; "
f"found {len(boundary_connections)}"
)
connection = boundary_connections[0]
if connection["submodel"] != "PNL0001":
raise ValueError(
f"{orifice_alias} boundary must use PNL0001, got {connection['submodel']}"
)
if connection["target_component"] == orifice_alias:
role = "inlet"
node_alias = str(connection["source_component"])
orifice_boundary_port = str(connection["target_port"])
else:
role = "outlet"
node_alias = str(connection["target_component"])
orifice_boundary_port = str(connection["source_port"])
if submodel_by_alias.get(node_alias) != "PN3NODE2":
raise ValueError(
f"{orifice_alias} PNL0001 boundary must terminate at PN3NODE2, "
f"got {node_alias}"
)
return {
"role": role,
"node_alias": node_alias,
"line_alias": str(connection["alias"]),
"orifice_alias": orifice_alias,
"orifice_boundary_port": orifice_boundary_port,
"orifice_volume_port": orifice_volume_port,
"volume_port": volume_port,
}