706 lines
29 KiB
Python
706 lines
29 KiB
Python
from __future__ import annotations
|
||
|
||
import json
|
||
from pathlib import Path
|
||
import unittest
|
||
|
||
from app.main import get_component_catalog
|
||
from app.simulation.registry import (
|
||
COMPONENT_MODEL_REGISTRY,
|
||
validate_component_registries,
|
||
)
|
||
from app.simulation.core.metadata import ParameterDefinition
|
||
|
||
|
||
class ComponentCatalogTests(unittest.TestCase):
|
||
def setUp(self) -> None:
|
||
self.catalog = get_component_catalog()
|
||
self.libraries = {
|
||
library["id"]: library for library in self.catalog["libraries"]
|
||
}
|
||
self.library = self.libraries["experimental"]
|
||
self.components = {
|
||
component["modelType"]: component
|
||
for library in self.catalog["libraries"]
|
||
for component in library["components"]
|
||
}
|
||
|
||
def test_experimental_library_is_exposed_as_temporary(self) -> None:
|
||
self.assertEqual(self.catalog["schemaVersion"], 1)
|
||
self.assertEqual(self.library["id"], "experimental")
|
||
self.assertEqual(self.library["label"], "临时测试组件库")
|
||
self.assertEqual(self.library["version"], "0.1.0")
|
||
self.assertTrue(self.library["temporary"])
|
||
self.assertEqual(
|
||
self.library["sourcePackage"],
|
||
"app.simulation.components.experimental",
|
||
)
|
||
self.assertEqual(
|
||
[category["id"] for category in self.library["categories"]],
|
||
["storage", "flow", "junctions"],
|
||
)
|
||
|
||
|
||
def test_amesim_library_exposes_pneumatic_models(self) -> None:
|
||
library = self.libraries["amesim"]
|
||
components = {
|
||
component["modelType"]: component for component in library["components"]
|
||
}
|
||
|
||
self.assertEqual(library["label"], "AMESim 组件库")
|
||
self.assertEqual([category["id"] for category in library["categories"]], ["media", "storage", "flow", "junctions", "boundary", "signals", "mechanical"])
|
||
self.assertEqual(set(components), {"amesim_ideal_air_medium", "amesim_helium_medium", "amesim_pnpl01", "amesim_step0", "amesim_ud00", "amesim_f000", "amesim_forc", "amesim_mecmas21", "amesim_lstp00a", "amesim_lmechn1", "amesim_pnrp17", "amesim_pnch023", "amesim_pnch012", "amesim_pnor001", "amesim_pnvo001_fixed", "amesim_pnvo001", "amesim_pnl00r", "amesim_pnl0001", "amesim_pnl0002", "amesim_pnl0003", "amesim_pn3node2", "amesim_p4node2"})
|
||
for model_type, component in components.items():
|
||
with self.subTest(model_type=model_type):
|
||
self.assertEqual(component["symbol"], model_type)
|
||
self.assertEqual(
|
||
components["amesim_ideal_air_medium"]["role"],
|
||
"amesimGasMediumDefinition",
|
||
)
|
||
self.assertEqual(
|
||
components["amesim_ideal_air_medium"]["category"]["id"],
|
||
"media",
|
||
)
|
||
self.assertEqual(
|
||
components["amesim_ideal_air_medium"]["label"],
|
||
"空气介质定义",
|
||
)
|
||
self.assertEqual(
|
||
components["amesim_ideal_air_medium"]["modelVersion"],
|
||
"0.2.0",
|
||
)
|
||
medium_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in components["amesim_ideal_air_medium"]["parameters"]
|
||
}
|
||
self.assertEqual(
|
||
list(medium_parameters),
|
||
["gi", "property_model"],
|
||
)
|
||
self.assertEqual(
|
||
medium_parameters["property_model"]["editor"],
|
||
"amesimGasPropertyModel",
|
||
)
|
||
self.assertEqual(
|
||
medium_parameters["property_model"]["options"],
|
||
[{"value": 0, "label": "理想气体"}],
|
||
)
|
||
helium_medium = components["amesim_helium_medium"]
|
||
self.assertEqual(helium_medium["role"], "amesimGasMediumDefinition")
|
||
self.assertEqual(helium_medium["category"]["id"], "media")
|
||
self.assertEqual(helium_medium["label"], "氦气介质定义")
|
||
self.assertEqual(helium_medium["modelVersion"], "0.1.0")
|
||
helium_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in helium_medium["parameters"]
|
||
}
|
||
self.assertEqual(list(helium_parameters), ["gi", "property_model"])
|
||
self.assertEqual(
|
||
helium_parameters["property_model"]["editor"],
|
||
"amesimGasPropertyModel",
|
||
)
|
||
self.assertEqual(
|
||
helium_parameters["property_model"]["options"],
|
||
[{"value": 0, "label": "Peng–Robinson"}],
|
||
)
|
||
self.assertEqual(
|
||
[port["name"] for port in components["amesim_p4node2"]["ports"]],
|
||
["port_1", "port_2", "port_3", "port_4"],
|
||
)
|
||
self.assertEqual(components["amesim_pnpl01"]["category"]["id"], "boundary")
|
||
self.assertEqual([port["name"] for port in components["amesim_pnpl01"]["ports"]], ["port_1"])
|
||
|
||
pnch_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in components["amesim_pnch023"]["parameters"]
|
||
}
|
||
self.assertEqual(components["amesim_pnch023"]["category"]["id"], "storage")
|
||
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"]
|
||
}
|
||
self.assertEqual(components["amesim_pnor001"]["category"]["id"], "flow")
|
||
self.assertEqual(pnor_parameters["area"]["quantity"], "area")
|
||
self.assertEqual(pnor_parameters["area"]["unit"], "m2")
|
||
pnvo_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in components["amesim_pnvo001_fixed"]["parameters"]
|
||
}
|
||
self.assertEqual(components["amesim_pnvo001_fixed"]["category"]["id"], "flow")
|
||
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_2", "port_1"])
|
||
self.assertEqual(components["amesim_mecmas21"]["modelVersion"], "0.2.0")
|
||
self.assertEqual(
|
||
components["amesim_mecmas21"]["parameterGroups"],
|
||
[
|
||
{
|
||
"id": "friction",
|
||
"label": "摩擦",
|
||
"parameters": [
|
||
"frictionType",
|
||
"strib",
|
||
"astrib",
|
||
"fstick",
|
||
"fcoul",
|
||
"rvisc",
|
||
"wind",
|
||
"dvel",
|
||
],
|
||
"order": 10,
|
||
"defaultExpanded": False,
|
||
},
|
||
{
|
||
"id": "endstops",
|
||
"label": "限位",
|
||
"parameters": [
|
||
"discContactOption",
|
||
"xmax",
|
||
"Kbmax",
|
||
"Dbmax",
|
||
"Pdmax",
|
||
"xmin",
|
||
"Kbmin",
|
||
"Dbmin",
|
||
"Pdmin",
|
||
"restcoeff",
|
||
"restdvel",
|
||
],
|
||
"order": 20,
|
||
"defaultExpanded": False,
|
||
},
|
||
],
|
||
)
|
||
self.assertNotIn("parameterGroups", components["amesim_f000"])
|
||
self.assertEqual(mecmas_parameters["mass"]["unit"], "kg")
|
||
self.assertEqual(mecmas_parameters["Kbmin"]["unit"], "N/m")
|
||
self.assertEqual(mecmas_parameters["theta"]["label"], "倾角(度)")
|
||
self.assertIn("+90°", mecmas_parameters["theta"]["description"])
|
||
self.assertIn("-90°", mecmas_parameters["theta"]["description"])
|
||
self.assertEqual(
|
||
{
|
||
name: (
|
||
mecmas_parameters[name]["editor"],
|
||
[
|
||
(option["value"], option["label"])
|
||
for option in mecmas_parameters[name]["options"]
|
||
],
|
||
)
|
||
for name in (
|
||
"useFriction",
|
||
"stoptype",
|
||
"discContactOption",
|
||
"strib",
|
||
"frictionType",
|
||
)
|
||
},
|
||
{
|
||
"useFriction": ("choice", [(1.0, "否"), (2.0, "是")]),
|
||
"stoptype": (
|
||
"choice",
|
||
[
|
||
(1.0, "理想限位"),
|
||
(2.0, "弹性限位"),
|
||
(3.0, "恢复碰撞"),
|
||
(4.0, "无限位"),
|
||
],
|
||
),
|
||
"discContactOption": (
|
||
"choice",
|
||
[
|
||
(1.0, "允许负接触力"),
|
||
(2.0, "不允许负接触力"),
|
||
],
|
||
),
|
||
"strib": ("choice", [(1.0, "否"), (2.0, "是")]),
|
||
"frictionType": (
|
||
"choice",
|
||
[(1.0, "简单"), (2.0, "高级")],
|
||
),
|
||
},
|
||
)
|
||
self.assertEqual(
|
||
{
|
||
name: mecmas_parameters[name]["visibleWhen"]
|
||
for name in (
|
||
"fstick",
|
||
"fcoul",
|
||
"rvisc",
|
||
"wind",
|
||
"dvel",
|
||
"restdvel",
|
||
"restcoeff",
|
||
"astrib",
|
||
"xmin",
|
||
"Kbmin",
|
||
"Dbmin",
|
||
"Pdmin",
|
||
"xmax",
|
||
"Kbmax",
|
||
"Dbmax",
|
||
"Pdmax",
|
||
"discContactOption",
|
||
"strib",
|
||
"frictionType",
|
||
)
|
||
},
|
||
{
|
||
"fstick": [
|
||
{"parameter": "stoptype", "values": [1.0, 2.0, 4.0]},
|
||
{"parameter": "useFriction", "values": [2.0]},
|
||
],
|
||
"fcoul": [
|
||
{"parameter": "stoptype", "values": [1.0, 2.0, 4.0]},
|
||
{"parameter": "useFriction", "values": [2.0]},
|
||
],
|
||
"rvisc": [
|
||
{"parameter": "useFriction", "values": [2.0]},
|
||
],
|
||
"wind": [
|
||
{"parameter": "useFriction", "values": [2.0]},
|
||
],
|
||
"dvel": [
|
||
{"parameter": "stoptype", "values": [1.0, 2.0, 4.0]},
|
||
{"parameter": "useFriction", "values": [2.0]},
|
||
{"parameter": "frictionType", "values": [2.0]},
|
||
],
|
||
"restdvel": [
|
||
{"parameter": "stoptype", "values": [3.0]},
|
||
],
|
||
"restcoeff": [
|
||
{"parameter": "stoptype", "values": [3.0]},
|
||
],
|
||
"astrib": [
|
||
{"parameter": "stoptype", "values": [1.0, 2.0, 4.0]},
|
||
{"parameter": "useFriction", "values": [2.0]},
|
||
{"parameter": "frictionType", "values": [2.0]},
|
||
{"parameter": "strib", "values": [2.0]},
|
||
],
|
||
"xmin": [
|
||
{"parameter": "stoptype", "values": [1.0, 2.0, 3.0]},
|
||
],
|
||
"Kbmin": [
|
||
{"parameter": "stoptype", "values": [2.0]},
|
||
],
|
||
"Dbmin": [
|
||
{"parameter": "stoptype", "values": [2.0]},
|
||
],
|
||
"Pdmin": [
|
||
{"parameter": "stoptype", "values": [2.0]},
|
||
],
|
||
"xmax": [
|
||
{"parameter": "stoptype", "values": [1.0, 2.0, 3.0]},
|
||
],
|
||
"Kbmax": [
|
||
{"parameter": "stoptype", "values": [2.0]},
|
||
],
|
||
"Dbmax": [
|
||
{"parameter": "stoptype", "values": [2.0]},
|
||
],
|
||
"Pdmax": [
|
||
{"parameter": "stoptype", "values": [2.0]},
|
||
],
|
||
"discContactOption": [
|
||
{"parameter": "stoptype", "values": [2.0]},
|
||
],
|
||
"strib": [
|
||
{"parameter": "stoptype", "values": [1.0, 2.0, 4.0]},
|
||
{"parameter": "useFriction", "values": [2.0]},
|
||
{"parameter": "frictionType", "values": [2.0]},
|
||
],
|
||
"frictionType": [
|
||
{"parameter": "stoptype", "values": [1.0, 2.0, 4.0]},
|
||
{"parameter": "useFriction", "values": [2.0]},
|
||
],
|
||
},
|
||
)
|
||
for name in ("mass", "theta", "useFriction", "stoptype", "v0", "x0"):
|
||
with self.subTest(always_visible=name):
|
||
self.assertNotIn("visibleWhen", mecmas_parameters[name])
|
||
lstp_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in components["amesim_lstp00a"]["parameters"]
|
||
}
|
||
self.assertEqual(components["amesim_lstp00a"]["category"]["id"], "mechanical")
|
||
self.assertEqual([port["name"] for port in components["amesim_lstp00a"]["ports"]], ["port_1", "port_2"])
|
||
self.assertEqual(lstp_parameters["gap0"]["unit"], "m")
|
||
self.assertEqual(lstp_parameters["kcont"]["unit"], "N/m")
|
||
lmechn_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in components["amesim_lmechn1"]["parameters"]
|
||
}
|
||
self.assertEqual(components["amesim_lmechn1"]["category"]["id"], "mechanical")
|
||
self.assertEqual([port["name"] for port in components["amesim_lmechn1"]["ports"]], [f"port_{index}" for index in range(1, 10)])
|
||
pnrp_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in components["amesim_pnrp17"]["parameters"]
|
||
}
|
||
self.assertEqual(components["amesim_pnrp17"]["category"]["id"], "mechanical")
|
||
self.assertEqual([port["name"] for port in components["amesim_pnrp17"]["ports"]], ["port_1", "port_3", "port_2", "port_4", "port_5"])
|
||
self.assertEqual(pnrp_parameters["dp"]["unit"], "m")
|
||
self.assertEqual(lmechn_parameters["v1"]["maximum"], 8.0)
|
||
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"]
|
||
}
|
||
self.assertEqual(components["amesim_pnl00r"]["category"]["id"], "flow")
|
||
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_amesim_configurable_parameters_expose_choices_and_groups(self) -> None:
|
||
def parameters(model_type: str) -> dict[str, dict[str, object]]:
|
||
return {
|
||
parameter["name"]: parameter
|
||
for parameter in self.components[model_type]["parameters"]
|
||
}
|
||
|
||
flow_options = [
|
||
{"value": 1.0, "label": "Cq"},
|
||
{"value": 2.0, "label": "Cv"},
|
||
{"value": 3.0, "label": "Kv"},
|
||
]
|
||
for model_type, area_name in (
|
||
("amesim_pnor001", "area"),
|
||
("amesim_pnvo001_fixed", "area0"),
|
||
("amesim_pnvo001", "area0"),
|
||
):
|
||
with self.subTest(model_type=model_type):
|
||
component = self.components[model_type]
|
||
model_parameters = parameters(model_type)
|
||
self.assertEqual(
|
||
component["modelVersion"],
|
||
"0.3.0" if model_type == "amesim_pnor001" else "0.2.0",
|
||
)
|
||
self.assertEqual(model_parameters["flowset"]["editor"], "choice")
|
||
self.assertEqual(model_parameters["flowset"]["options"], flow_options)
|
||
self.assertEqual(
|
||
model_parameters["cq"]["visibleWhen"],
|
||
[{"parameter": "flowset", "values": [1.0]}],
|
||
)
|
||
self.assertEqual(
|
||
model_parameters[area_name]["visibleWhen"],
|
||
[{"parameter": "flowset", "values": [1.0]}],
|
||
)
|
||
self.assertEqual(
|
||
model_parameters["Cv"]["visibleWhen"],
|
||
[{"parameter": "flowset", "values": [2.0]}],
|
||
)
|
||
self.assertEqual(
|
||
model_parameters["Kv"]["visibleWhen"],
|
||
[{"parameter": "flowset", "values": [3.0]}],
|
||
)
|
||
self.assertEqual(
|
||
component["parameterGroups"],
|
||
[
|
||
{
|
||
"id": "flow_coefficient",
|
||
"label": "流量系数",
|
||
"parameters": ["cq", area_name, "Cv", "Kv"],
|
||
"order": 10,
|
||
"defaultExpanded": False,
|
||
}
|
||
],
|
||
)
|
||
|
||
thermal_options = [
|
||
{"value": 1.0, "label": "多方过程"},
|
||
{"value": 2.0, "label": "带换热"},
|
||
]
|
||
for model_type in ("amesim_pnl0001", "amesim_pnl0002", "amesim_pnl0003"):
|
||
with self.subTest(model_type=model_type):
|
||
component = self.components[model_type]
|
||
model_parameters = parameters(model_type)
|
||
expected_version = (
|
||
"0.3.0" if model_type == "amesim_pnl0002" else "0.2.0"
|
||
)
|
||
self.assertEqual(component["modelVersion"], expected_version)
|
||
self.assertEqual(model_parameters["mode"]["editor"], "choice")
|
||
self.assertEqual(model_parameters["mode"]["options"], thermal_options)
|
||
self.assertEqual(
|
||
model_parameters["k"]["visibleWhen"],
|
||
[{"parameter": "mode", "values": [1.0]}],
|
||
)
|
||
for name in ("kth", "extemp"):
|
||
self.assertEqual(
|
||
model_parameters[name]["visibleWhen"],
|
||
[{"parameter": "mode", "values": [2.0]}],
|
||
)
|
||
self.assertEqual(
|
||
component["parameterGroups"],
|
||
[
|
||
{
|
||
"id": "thermodynamics",
|
||
"label": "热力学",
|
||
"parameters": ["k", "kth", "extemp"],
|
||
"order": 10,
|
||
"defaultExpanded": False,
|
||
}
|
||
],
|
||
)
|
||
|
||
ud00 = self.components["amesim_ud00"]
|
||
ud00_parameters = parameters("amesim_ud00")
|
||
self.assertEqual(ud00["modelVersion"], "0.2.0")
|
||
self.assertEqual(ud00_parameters["nstages"]["editor"], "choice")
|
||
self.assertEqual(
|
||
ud00_parameters["nstages"]["options"],
|
||
[
|
||
{"value": float(stage_count), "label": str(stage_count)}
|
||
for stage_count in range(1, 9)
|
||
],
|
||
)
|
||
self.assertEqual(
|
||
ud00_parameters["iscyclic"]["options"],
|
||
[{"value": 0.0, "label": "否"}, {"value": 1.0, "label": "是"}],
|
||
)
|
||
self.assertNotIn("visibleWhen", ud00_parameters["start1"])
|
||
self.assertEqual(
|
||
ud00_parameters["start2"]["visibleWhen"],
|
||
[{"parameter": "nstages", "values": [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]}],
|
||
)
|
||
self.assertEqual(
|
||
ud00_parameters["t8"]["visibleWhen"],
|
||
[{"parameter": "nstages", "values": [8.0]}],
|
||
)
|
||
self.assertEqual(
|
||
ud00["parameterGroups"][0]["parameters"],
|
||
[
|
||
name
|
||
for stage_index in range(1, 9)
|
||
for name in (
|
||
f"start{stage_index}",
|
||
f"end{stage_index}",
|
||
f"t{stage_index}",
|
||
)
|
||
],
|
||
)
|
||
|
||
lstp = self.components["amesim_lstp00a"]
|
||
lstp_parameters = parameters("amesim_lstp00a")
|
||
self.assertEqual(lstp["modelVersion"], "0.2.0")
|
||
self.assertEqual(
|
||
lstp_parameters["stiffmode"]["options"],
|
||
[
|
||
{"value": 1.0, "label": "数值刚度"},
|
||
{"value": 2.0, "label": "几何参数"},
|
||
],
|
||
)
|
||
self.assertEqual(
|
||
lstp_parameters["discContactOption"]["options"],
|
||
[
|
||
{"value": 1.0, "label": "允许负接触力"},
|
||
{"value": 2.0, "label": "不允许负接触力"},
|
||
],
|
||
)
|
||
self.assertEqual(
|
||
lstp_parameters["kcont"]["visibleWhen"],
|
||
[{"parameter": "stiffmode", "values": [1.0]}],
|
||
)
|
||
for name in ("na", "G", "sdiam", "wdiam"):
|
||
self.assertEqual(
|
||
lstp_parameters[name]["visibleWhen"],
|
||
[{"parameter": "stiffmode", "values": [2.0]}],
|
||
)
|
||
self.assertEqual(
|
||
lstp["parameterGroups"],
|
||
[
|
||
{
|
||
"id": "stiffness",
|
||
"label": "刚度",
|
||
"parameters": ["kcont", "G", "sdiam", "wdiam", "na"],
|
||
"order": 10,
|
||
"defaultExpanded": False,
|
||
},
|
||
{
|
||
"id": "contact",
|
||
"label": "接触",
|
||
"parameters": ["gap0", "rcont", "Pdis"],
|
||
"order": 20,
|
||
"defaultExpanded": False,
|
||
},
|
||
],
|
||
)
|
||
|
||
def test_every_registered_component_is_in_the_catalog(self) -> None:
|
||
self.assertEqual(
|
||
set(self.components),
|
||
set(COMPONENT_MODEL_REGISTRY),
|
||
)
|
||
|
||
def test_catalog_reuses_model_parameter_contracts(self) -> None:
|
||
cylinder = self.components["cylinder"]
|
||
parameters = {
|
||
parameter["name"]: parameter for parameter in cylinder["parameters"]
|
||
}
|
||
|
||
self.assertEqual(cylinder["label"], "气瓶")
|
||
self.assertEqual(cylinder["modelVersion"], "1.0.0")
|
||
self.assertEqual(parameters["volume"]["default"], 0.01)
|
||
self.assertEqual(parameters["volume"]["quantity"], "volume")
|
||
self.assertEqual(parameters["p0"]["unit"], "Pa")
|
||
self.assertTrue(parameters["p0"]["minimumExclusive"])
|
||
|
||
def test_parameter_description_is_optional_interface_metadata(self) -> None:
|
||
described = ParameterDefinition(
|
||
"diam",
|
||
0.01,
|
||
label="管径",
|
||
quantity="length",
|
||
unit="m",
|
||
minimum=0.0,
|
||
minimum_exclusive=True,
|
||
description="用于计算流通面积。",
|
||
).as_interface_dict()
|
||
undescribed = ParameterDefinition(
|
||
"gain",
|
||
1.0,
|
||
label="增益",
|
||
).as_interface_dict()
|
||
|
||
self.assertEqual(described["description"], "用于计算流通面积。")
|
||
self.assertEqual(described["default"], 0.01)
|
||
self.assertEqual(described["unit"], "m")
|
||
self.assertEqual(described["minimum"], 0.0)
|
||
self.assertTrue(described["minimumExclusive"])
|
||
self.assertNotIn("description", undescribed)
|
||
|
||
def test_catalog_exposes_descriptions_for_core_amesim_pneumatic_parameters(
|
||
self,
|
||
) -> None:
|
||
medium_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in self.components["amesim_helium_medium"]["parameters"]
|
||
}
|
||
chamber_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in self.components["amesim_pnch023"]["parameters"]
|
||
}
|
||
pipe_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in self.components["amesim_pnl00r"]["parameters"]
|
||
}
|
||
orifice_parameters = {
|
||
parameter["name"]: parameter
|
||
for parameter in self.components["amesim_pnor001"]["parameters"]
|
||
}
|
||
|
||
self.assertIn("自动分配", medium_parameters["gi"]["description"])
|
||
self.assertIn(
|
||
"Peng–Robinson",
|
||
medium_parameters["property_model"]["description"],
|
||
)
|
||
self.assertIn("固定有效容积", chamber_parameters["cvol"]["description"])
|
||
self.assertIn("Darcy", pipe_parameters["rr"]["description"])
|
||
self.assertIn("有效孔口面积", orifice_parameters["area"]["description"])
|
||
self.assertEqual(chamber_parameters["cvol"]["default"], 0.057)
|
||
self.assertEqual(pipe_parameters["diam"]["unit"], "m")
|
||
|
||
def test_catalog_adds_port_layout_without_changing_physical_contract(self) -> None:
|
||
tee_ports = {
|
||
port["name"]: port for port in self.components["tee"]["ports"]
|
||
}
|
||
|
||
self.assertEqual(tee_ports["port_in"]["side"], "left")
|
||
self.assertEqual(tee_ports["port_out1"]["side"], "right")
|
||
self.assertEqual(tee_ports["port_out2"]["side"], "right")
|
||
self.assertEqual(tee_ports["port_in"]["kind"], "physical")
|
||
self.assertEqual(tee_ports["port_in"]["domain"], "pneumatic")
|
||
self.assertEqual(tee_ports["port_in"]["nominalRole"], "bidirectional")
|
||
|
||
def test_registry_can_repeat_discovery_and_validation(self) -> None:
|
||
validate_component_registries()
|
||
|
||
def test_catalog_schema_is_committed_and_targets_version_one(self) -> None:
|
||
schema_path = (
|
||
Path(__file__).resolve().parent.parent
|
||
/ "schemas"
|
||
/ "component-catalog-v1.schema.json"
|
||
)
|
||
schema = json.loads(schema_path.read_text(encoding="utf-8"))
|
||
|
||
self.assertEqual(schema["properties"]["schemaVersion"]["const"], 1)
|
||
self.assertIn("modelVersion", schema["$defs"]["component"]["required"])
|
||
self.assertIn("version", schema["$defs"]["library"]["required"])
|
||
parameter_schema = schema["$defs"]["parameter"]
|
||
parameter_group_schema = schema["$defs"]["parameterGroup"]
|
||
self.assertEqual(
|
||
parameter_schema["properties"]["description"],
|
||
{"type": "string", "minLength": 1},
|
||
)
|
||
self.assertNotIn("description", parameter_schema["required"])
|
||
self.assertFalse(parameter_schema["additionalProperties"])
|
||
self.assertNotIn("unknownField", parameter_schema["properties"])
|
||
self.assertEqual(
|
||
parameter_group_schema["required"],
|
||
["id", "label", "parameters", "order", "defaultExpanded"],
|
||
)
|
||
self.assertTrue(
|
||
parameter_group_schema["properties"]["parameters"]["uniqueItems"]
|
||
)
|
||
self.assertIn(
|
||
"parameterGroups",
|
||
schema["$defs"]["component"]["properties"],
|
||
)
|
||
self.assertNotIn(
|
||
"parameterGroups",
|
||
schema["$defs"]["component"]["required"],
|
||
)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|