from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass from typing import ClassVar from app.simulation.core.medium import GasMedium, IdealGasMedium from app.simulation.core.peng_robinson import HELIUM_PR, PengRobinsonFluid @dataclass(frozen=True) class AmesimIdealAirMedium(IdealGasMedium): """AMESim air properties evaluated with the ideal-gas method. Substance identity and property method are part of the concrete Python type. A future air correlation or helium Peng-Robinson implementation can therefore coexist as a sibling type without turning ``gi`` into a fluid enumeration. """ SUBSTANCE_ID: ClassVar[str] = "air" PROPERTY_METHOD_ID: ClassVar[str] = "ideal_gas" name: str = "AMESimAirIdealGas" R_gas: float = 287.0 cp_ref: float = 1005.0 T_ref: float = 300.0 cp_slope: float = 0.0 viscosity_ref: float = 1.82e-5 viscosity_T_ref: float = 293.15 sutherland_constant: float = 110.4 @dataclass(frozen=True) class AmesimHeliumPengRobinsonMedium(IdealGasMedium): """AMESim helium with a Peng-Robinson mechanical equation of state. The pressure-density-temperature relation is evaluated by the shared ``HELIUM_PR`` fluid. The first public AMESim port keeps the committed constant-heat-capacity caloric model so it can be consumed through the same :class:`GasMedium` contract as ideal-gas air. """ SUBSTANCE_ID: ClassVar[str] = "helium" PROPERTY_METHOD_ID: ClassVar[str] = "peng_robinson" fluid: ClassVar[PengRobinsonFluid] = HELIUM_PR name: str = "AMESimHeliumPengRobinson" R_gas: float = HELIUM_PR.specific_gas_constant cp_ref: float = 5193.0 T_ref: float = 293.15 cp_slope: float = 0.0 viscosity_ref: float = 1.96e-5 viscosity_T_ref: float = 293.15 sutherland_constant: float = 79.4 @property def cv(self) -> float: return 3116.0 def cv_at_temperature(self, T: float) -> float: del T return self.cv def density(self, p: float, T: float) -> float: return self.fluid.density(p, T) def pressure(self, m: float, T: float, V: float) -> float: if V <= 0.0: raise ValueError("Volume must stay positive.") return self.fluid.pressure_from_density(T, m / V) @dataclass(frozen=True) class AmesimGasPropertyModelSpec: """A selectable calculation method for one AMESim gas substance.""" value: int label: str method_id: str factory: Callable[[], GasMedium] eos_type: int def build_medium(self) -> GasMedium: return self.factory() AMESIM_AIR_IDEAL_GAS_PROPERTY_MODEL = 0 AMESIM_AIR_PROPERTY_MODELS = ( AmesimGasPropertyModelSpec( value=AMESIM_AIR_IDEAL_GAS_PROPERTY_MODEL, label="理想气体", method_id=AmesimIdealAirMedium.PROPERTY_METHOD_ID, factory=AmesimIdealAirMedium, eos_type=1, ), ) AMESIM_HELIUM_PENG_ROBINSON_PROPERTY_MODEL = 0 AMESIM_HELIUM_PROPERTY_MODELS = ( AmesimGasPropertyModelSpec( value=AMESIM_HELIUM_PENG_ROBINSON_PROPERTY_MODEL, label="Peng–Robinson", method_id=AmesimHeliumPengRobinsonMedium.PROPERTY_METHOD_ID, factory=AmesimHeliumPengRobinsonMedium, eos_type=6, ), )