197 lines
6.3 KiB
Python
197 lines
6.3 KiB
Python
from __future__ import annotations
|
||
|
||
from abc import ABC
|
||
from collections.abc import Mapping
|
||
|
||
from app.simulation.components.amesim.gases import (
|
||
AMESIM_GAS_DEFINITION_INDEX_PARAMETER,
|
||
AmesimGasDefinition,
|
||
normalize_amesim_defined_gas_index,
|
||
)
|
||
from app.simulation.components.amesim.media.mediums import (
|
||
AMESIM_AIR_IDEAL_GAS_PROPERTY_MODEL,
|
||
AMESIM_AIR_PROPERTY_MODELS,
|
||
AMESIM_HELIUM_PENG_ROBINSON_PROPERTY_MODEL,
|
||
AMESIM_HELIUM_PROPERTY_MODELS,
|
||
AmesimGasPropertyModelSpec,
|
||
)
|
||
from app.simulation.core.base import AlgebraicComponent
|
||
from app.simulation.core.catalog import ComponentDisplaySpec
|
||
from app.simulation.core.medium import GasMedium
|
||
from app.simulation.core.metadata import ParameterDefinition, ParameterOption
|
||
|
||
|
||
AMESIM_AIR_PROPERTY_MODEL_PARAMETER = ParameterDefinition(
|
||
"property_model",
|
||
float(AMESIM_AIR_IDEAL_GAS_PROPERTY_MODEL),
|
||
label="物性计算模型",
|
||
quantity="dimensionless",
|
||
unit="",
|
||
minimum=float(min(model.value for model in AMESIM_AIR_PROPERTY_MODELS)),
|
||
maximum=float(max(model.value for model in AMESIM_AIR_PROPERTY_MODELS)),
|
||
editor="amesimGasPropertyModel",
|
||
options=tuple(
|
||
ParameterOption(value=model.value, label=model.label)
|
||
for model in AMESIM_AIR_PROPERTY_MODELS
|
||
),
|
||
description="选择空气介质的物性计算方法;当前首版提供理想气体模型。",
|
||
)
|
||
|
||
AMESIM_HELIUM_PROPERTY_MODEL_PARAMETER = ParameterDefinition(
|
||
"property_model",
|
||
float(AMESIM_HELIUM_PENG_ROBINSON_PROPERTY_MODEL),
|
||
label="物性计算模型",
|
||
quantity="dimensionless",
|
||
unit="",
|
||
minimum=float(min(model.value for model in AMESIM_HELIUM_PROPERTY_MODELS)),
|
||
maximum=float(max(model.value for model in AMESIM_HELIUM_PROPERTY_MODELS)),
|
||
editor="amesimGasPropertyModel",
|
||
options=tuple(
|
||
ParameterOption(value=model.value, label=model.label)
|
||
for model in AMESIM_HELIUM_PROPERTY_MODELS
|
||
),
|
||
description=(
|
||
"选择氦气介质的物性计算方法;当前首版提供 "
|
||
"Peng–Robinson 状态方程模型。"
|
||
),
|
||
)
|
||
|
||
|
||
class AmesimGasMediumDefinitionComponent(AlgebraicComponent, ABC):
|
||
"""Compile-time definition of one project-scoped AMESim gas medium.
|
||
|
||
Concrete subclasses declare one substance and its available calculation
|
||
methods; each instance selects a method through ``property_model``. They
|
||
deliberately expose no physical ports or equations: the compiler consumes
|
||
them before it creates the simulation network.
|
||
"""
|
||
|
||
IS_AMESIM_GAS_MEDIUM_DEFINITION = True
|
||
MEDIUM_LABEL = ""
|
||
FLUID_TYPE: int | None = None
|
||
PROPERTY_MODELS: tuple[AmesimGasPropertyModelSpec, ...] = ()
|
||
|
||
def __init__(
|
||
self,
|
||
name: str,
|
||
gi: float,
|
||
property_model: float = float(AMESIM_AIR_IDEAL_GAS_PROPERTY_MODEL),
|
||
) -> None:
|
||
super().__init__(name)
|
||
self.gi = normalize_amesim_defined_gas_index(gi)
|
||
self.property_model = self._resolve_property_model(property_model).value
|
||
self.set_parameter_values(
|
||
{
|
||
"gi": self.gi,
|
||
"property_model": self.property_model,
|
||
}
|
||
)
|
||
|
||
def _resolve_property_model(
|
||
self,
|
||
value: float | int,
|
||
) -> AmesimGasPropertyModelSpec:
|
||
for model in self.PROPERTY_MODELS:
|
||
if float(model.value) == float(value):
|
||
return model
|
||
available = ", ".join(str(model.value) for model in self.PROPERTY_MODELS)
|
||
raise ValueError(
|
||
f"AMESim medium definition '{self.name}' does not support property "
|
||
f"model {value:g}; available models: {available or 'none'}."
|
||
)
|
||
|
||
def build_medium(self) -> GasMedium:
|
||
"""Create the executable property model selected by this instance."""
|
||
|
||
return self._resolve_property_model(self.property_model).build_medium()
|
||
|
||
def gas_definition(self) -> AmesimGasDefinition:
|
||
model = self._resolve_property_model(self.property_model)
|
||
return AmesimGasDefinition(
|
||
gi=self.gi,
|
||
label=f"{self.MEDIUM_LABEL}({model.label})",
|
||
medium=self.build_medium(),
|
||
fluid_type=self.FLUID_TYPE,
|
||
eos_type=model.eos_type,
|
||
)
|
||
|
||
|
||
class AmesimIdealAirMediumDefinition(AmesimGasMediumDefinitionComponent):
|
||
"""Project gas slot using the built-in ideal-gas air property method."""
|
||
|
||
MODEL_TYPE = "amesim_ideal_air_medium"
|
||
MODEL_VERSION = "0.2.0"
|
||
PORTS = ()
|
||
PARAMETERS = (
|
||
AMESIM_GAS_DEFINITION_INDEX_PARAMETER,
|
||
AMESIM_AIR_PROPERTY_MODEL_PARAMETER,
|
||
)
|
||
RESULT_VARIABLES = ()
|
||
DISPLAY = ComponentDisplaySpec(
|
||
label="空气介质定义",
|
||
library_id="amesim",
|
||
category_id="media",
|
||
symbol="amesim_ideal_air_medium",
|
||
ports=(),
|
||
order=10,
|
||
role="amesimGasMediumDefinition",
|
||
)
|
||
MEDIUM_LABEL = "空气"
|
||
FLUID_TYPE = 2
|
||
PROPERTY_MODELS = AMESIM_AIR_PROPERTY_MODELS
|
||
|
||
@classmethod
|
||
def create(
|
||
cls,
|
||
*,
|
||
name: str,
|
||
medium: GasMedium,
|
||
parameters: Mapping[str, float],
|
||
) -> AmesimIdealAirMediumDefinition:
|
||
del medium
|
||
return cls(
|
||
name=name,
|
||
gi=parameters["gi"],
|
||
property_model=parameters["property_model"],
|
||
)
|
||
|
||
|
||
class AmesimHeliumMediumDefinition(AmesimGasMediumDefinitionComponent):
|
||
"""Project gas slot using the AMESim helium Peng-Robinson method."""
|
||
|
||
MODEL_TYPE = "amesim_helium_medium"
|
||
MODEL_VERSION = "0.1.0"
|
||
PORTS = ()
|
||
PARAMETERS = (
|
||
AMESIM_GAS_DEFINITION_INDEX_PARAMETER,
|
||
AMESIM_HELIUM_PROPERTY_MODEL_PARAMETER,
|
||
)
|
||
RESULT_VARIABLES = ()
|
||
DISPLAY = ComponentDisplaySpec(
|
||
label="氦气介质定义",
|
||
library_id="amesim",
|
||
category_id="media",
|
||
symbol="amesim_helium_medium",
|
||
ports=(),
|
||
order=20,
|
||
role="amesimGasMediumDefinition",
|
||
)
|
||
MEDIUM_LABEL = "氦气"
|
||
FLUID_TYPE = 12
|
||
PROPERTY_MODELS = AMESIM_HELIUM_PROPERTY_MODELS
|
||
|
||
@classmethod
|
||
def create(
|
||
cls,
|
||
*,
|
||
name: str,
|
||
medium: GasMedium,
|
||
parameters: Mapping[str, float],
|
||
) -> AmesimHeliumMediumDefinition:
|
||
del medium
|
||
return cls(
|
||
name=name,
|
||
gi=parameters["gi"],
|
||
property_model=parameters["property_model"],
|
||
)
|