feat: integrate AMESim media models and editor UI

This commit is contained in:
ljz committed 2026-07-31 23:36:58 +08:00
1 parent 3e4f466114
commit e7177ab03e
181 files changed
+7042 -25270

No files matched your search

+88 -3
View File
@@ -17,9 +17,10 @@ from app.simulation.core.catalog import (
from app.simulation.core.metadata import (
SI_UNIT_BY_QUANTITY,
ParameterDefinition,
ParameterOption,
ResultVariableDefinition,
)
from app.simulation.core.medium import IdealGasMedium
from app.simulation.core.medium import GasMedium, IdealGasMedium
from app.simulation.core.ports import PortDefinition, PortVariableDefinition
@@ -81,7 +82,7 @@ class ComponentModelSpec:
ports.append(payload)
ports.sort(key=lambda item: (int(item["order"]), str(item["name"])))
return {
payload: dict[str, object] = {
"type": self.model_type,
"modelType": self.model_type,
"modelVersion": self.model_version,
@@ -94,11 +95,14 @@ class ComponentModelSpec:
parameter.as_interface_dict() for parameter in self.parameters
],
}
if self.display.role is not None:
payload["role"] = self.display.role
return payload
def create(
self,
name: str,
medium: IdealGasMedium,
medium: GasMedium,
values: Mapping[str, float],
) -> Component:
unknown = sorted(set(values) - set(self.parameter_by_name))
@@ -410,6 +414,14 @@ def _validate_parameter(
raise ValueError(f"{field} declarations must use ParameterDefinition.")
_validate_member_id(parameter.name, field=f"{field} name")
_validate_label(parameter.label, field=f"{field} '{parameter.name}' label")
if not isinstance(parameter.description, str):
raise ValueError(
f"{field} '{parameter.name}' description must be a string."
)
if parameter.description and not parameter.description.strip():
raise ValueError(
f"{field} '{parameter.name}' description must not be blank."
)
_validate_quantity_unit(
parameter.quantity,
parameter.unit,
@@ -433,6 +445,74 @@ def _validate_parameter(
raise ValueError(
f"{field} '{parameter.name}' minimum_exclusive must be a boolean."
)
if parameter.editor not in {
None,
"amesimGasReference",
"amesimGasPropertyModel",
}:
raise ValueError(
f"{field} '{parameter.name}' uses unsupported editor "
f"'{parameter.editor}'."
)
if not isinstance(parameter.options, tuple):
raise ValueError(
f"{field} '{parameter.name}' options must use a tuple."
)
if parameter.editor == "amesimGasPropertyModel" and not parameter.options:
raise ValueError(
f"{field} '{parameter.name}' property-model editor must declare options."
)
if parameter.options and parameter.editor != "amesimGasPropertyModel":
raise ValueError(
f"{field} '{parameter.name}' options require the "
"'amesimGasPropertyModel' editor."
)
option_values: list[float] = []
for option in parameter.options:
if not isinstance(option, ParameterOption):
raise ValueError(
f"{field} '{parameter.name}' options must use ParameterOption."
)
if (
isinstance(option.value, bool)
or not isinstance(option.value, (int, float))
or not isfinite(option.value)
):
raise ValueError(
f"{field} '{parameter.name}' option values must be finite numbers."
)
_validate_label(
option.label,
field=(
f"{field} '{parameter.name}' option "
f"'{option.value:g}' label"
),
)
numeric_option = float(option.value)
if (
parameter.editor == "amesimGasPropertyModel"
and not numeric_option.is_integer()
):
raise ValueError(
f"{field} '{parameter.name}' property-model option values "
"must be integers."
)
option_message = parameter.validation_message(numeric_option)
if option_message is not None:
raise ValueError(
f"{field} '{parameter.name}' option {numeric_option:g} "
f"{option_message}."
)
option_values.append(numeric_option)
duplicate_option_values = sorted(
{value for value in option_values if option_values.count(value) > 1}
)
if duplicate_option_values:
duplicates = ", ".join(f"{value:g}" for value in duplicate_option_values)
raise ValueError(
f"{field} '{parameter.name}' contains duplicate option values: "
f"{duplicates}."
)
if (
parameter.minimum is not None
and parameter.maximum is not None
@@ -532,6 +612,11 @@ def validate_component_model_class(
field=f"Component '{model_type}' display symbol",
)
_validate_order(display.order, field=f"Component '{model_type}' display order")
if display.role not in {None, "amesimGasMediumDefinition"}:
raise ValueError(
f"Component '{model_type}' DISPLAY uses unsupported role "
f"'{display.role}'."
)
if not isinstance(display.ports, tuple):
raise ValueError(f"Component '{model_type}' DISPLAY ports must be a tuple.")
if display.library_id != library.id: