254 lines
7.5 KiB
Python
254 lines
7.5 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping
|
|
|
|
from PythonModels.core.base import ThermodynamicVolumeComponent
|
|
from PythonModels.core.equations import EquationResidual
|
|
from PythonModels.core.metadata import (
|
|
ParameterDefinition,
|
|
THERMODYNAMIC_VOLUME_RESULT_VARIABLES,
|
|
)
|
|
from PythonModels.core.medium import IdealGasMedium, ThermodynamicProperties
|
|
from PythonModels.core.ports import PortDefinition
|
|
from PythonModels.core.state import VolumeState
|
|
|
|
|
|
class Pipe(ThermodynamicVolumeComponent):
|
|
"""Python port of ModelicaModels.Mypipe."""
|
|
|
|
MODEL_TYPE = "pipe"
|
|
PORTS = (
|
|
PortDefinition.pneumatic("port_a", nominal_role="inlet"),
|
|
PortDefinition.pneumatic("port_b", nominal_role="outlet"),
|
|
)
|
|
PARAMETERS = (
|
|
ParameterDefinition(
|
|
"length",
|
|
5.0,
|
|
label="长度",
|
|
quantity="length",
|
|
unit="m",
|
|
minimum=0.0,
|
|
minimum_exclusive=True,
|
|
),
|
|
ParameterDefinition(
|
|
"diameter",
|
|
0.02,
|
|
label="直径",
|
|
quantity="length",
|
|
unit="m",
|
|
minimum=0.0,
|
|
minimum_exclusive=True,
|
|
),
|
|
ParameterDefinition(
|
|
"lambda_darcy",
|
|
0.02,
|
|
label="摩阻系数",
|
|
minimum=0.0,
|
|
),
|
|
ParameterDefinition(
|
|
"p0",
|
|
1e5,
|
|
label="初始压力",
|
|
quantity="pressure",
|
|
unit="Pa",
|
|
minimum=0.0,
|
|
minimum_exclusive=True,
|
|
),
|
|
ParameterDefinition(
|
|
"T0",
|
|
300.0,
|
|
label="初始温度",
|
|
quantity="temperature",
|
|
unit="K",
|
|
minimum=0.0,
|
|
minimum_exclusive=True,
|
|
),
|
|
)
|
|
RESULT_VARIABLES = THERMODYNAMIC_VOLUME_RESULT_VARIABLES
|
|
|
|
def __init__(
|
|
self,
|
|
name: str,
|
|
medium: IdealGasMedium,
|
|
L: float = 5.0,
|
|
D: float = 0.02,
|
|
lambda_darcy: float = 0.02,
|
|
p0: float = 1e5,
|
|
T0: float = 300.0,
|
|
) -> None:
|
|
super().__init__(name=name)
|
|
self.set_parameter_values(
|
|
{
|
|
"length": L,
|
|
"diameter": D,
|
|
"lambda_darcy": lambda_darcy,
|
|
"p0": p0,
|
|
"T0": T0,
|
|
}
|
|
)
|
|
self.medium = medium
|
|
self.L = L
|
|
self.D = D
|
|
self.lambda_darcy = lambda_darcy
|
|
self.area = 3.141592653589793 * D * D / 4.0
|
|
self.V = self.area * L
|
|
m0 = p0 * self.V / (medium.R_gas * T0)
|
|
U0 = m0 * medium.specific_internal_energy(T0)
|
|
self.state = VolumeState(m=m0, U=U0)
|
|
self.port_a = self.register_declared_port("port_a")
|
|
self.port_b = self.register_declared_port("port_b")
|
|
|
|
def get_state_vector(self) -> list[float]:
|
|
return self.state.as_vector()
|
|
|
|
def set_state_vector(self, values: list[float]) -> None:
|
|
self.state = VolumeState.from_vector(values)
|
|
|
|
def properties(self) -> ThermodynamicProperties:
|
|
props = self.medium.properties_from_mU(self.state.m, self.state.U, self.V)
|
|
self.port_b.p = props.p
|
|
self.port_a.h_outflow = props.h
|
|
self.port_b.h_outflow = props.h
|
|
return props
|
|
|
|
def refresh_thermodynamic_ports(self) -> ThermodynamicProperties:
|
|
return self.properties()
|
|
|
|
def state_derivative_from_ports(
|
|
self,
|
|
connected_h: Mapping[str, float],
|
|
) -> list[float]:
|
|
properties = self.properties()
|
|
derivative = self.derivatives_from_connections(
|
|
port_a_m_flow=self.port_a.m_flow,
|
|
connected_h_a=connected_h["port_a"],
|
|
port_b_m_flow=self.port_b.m_flow,
|
|
connected_h_b=connected_h["port_b"],
|
|
internal_h=properties.h,
|
|
)
|
|
return derivative.as_vector()
|
|
|
|
def inlet_pressure(self, m_flow_a: float, rho: float, core_pressure: float) -> float:
|
|
resistance = self.lambda_darcy * (self.L / self.D)
|
|
dynamic_term = m_flow_a * abs(m_flow_a) / (2.0 * rho * self.area * self.area)
|
|
return core_pressure + resistance * dynamic_term
|
|
|
|
def pressure_flow_equation_residuals(self) -> tuple[EquationResidual, ...]:
|
|
properties = self.medium.properties_from_mU(
|
|
self.state.m,
|
|
self.state.U,
|
|
self.V,
|
|
)
|
|
expected_inlet_pressure = self.inlet_pressure(
|
|
self.port_a.m_flow,
|
|
max(properties.rho, 1e-12),
|
|
properties.p,
|
|
)
|
|
return (
|
|
EquationResidual(
|
|
id=f"{self.name}:darcy_pressure_loss",
|
|
owner="component",
|
|
owner_id=self.name,
|
|
relation="constitutive",
|
|
variables=(
|
|
f"{self.name}.port_a.p",
|
|
f"{self.name}.port_a.m_flow",
|
|
f"{self.name}.state",
|
|
),
|
|
role="effort",
|
|
value=self.port_a.p - expected_inlet_pressure,
|
|
),
|
|
EquationResidual(
|
|
id=f"{self.name}:port_b_pressure_state",
|
|
owner="component",
|
|
owner_id=self.name,
|
|
relation="state",
|
|
variables=(f"{self.name}.port_b.p", f"{self.name}.state"),
|
|
role="effort",
|
|
value=self.port_b.p - properties.p,
|
|
),
|
|
)
|
|
|
|
def port_a_inlet_enthalpy(
|
|
self,
|
|
*,
|
|
port_a_m_flow: float,
|
|
connected_h: float,
|
|
internal_h: float,
|
|
) -> float:
|
|
return self.connection_inlet_enthalpy(
|
|
port_m_flow=port_a_m_flow,
|
|
connected_h=connected_h,
|
|
internal_h=internal_h,
|
|
)
|
|
|
|
def port_b_inlet_enthalpy(
|
|
self,
|
|
*,
|
|
port_b_m_flow: float,
|
|
connected_h: float,
|
|
internal_h: float,
|
|
) -> float:
|
|
return self.connection_inlet_enthalpy(
|
|
port_m_flow=port_b_m_flow,
|
|
connected_h=connected_h,
|
|
internal_h=internal_h,
|
|
)
|
|
|
|
def connection_inlet_enthalpies(
|
|
self,
|
|
*,
|
|
port_a_m_flow: float,
|
|
connected_h_a: float,
|
|
port_b_m_flow: float,
|
|
connected_h_b: float,
|
|
internal_h: float,
|
|
) -> tuple[float, float]:
|
|
return (
|
|
self.port_a_inlet_enthalpy(
|
|
port_a_m_flow=port_a_m_flow,
|
|
connected_h=connected_h_a,
|
|
internal_h=internal_h,
|
|
),
|
|
self.port_b_inlet_enthalpy(
|
|
port_b_m_flow=port_b_m_flow,
|
|
connected_h=connected_h_b,
|
|
internal_h=internal_h,
|
|
),
|
|
)
|
|
|
|
def derivatives_from_connections(
|
|
self,
|
|
*,
|
|
port_a_m_flow: float,
|
|
connected_h_a: float,
|
|
port_b_m_flow: float,
|
|
connected_h_b: float,
|
|
internal_h: float,
|
|
) -> VolumeState:
|
|
inlet_h_a, inlet_h_b = self.connection_inlet_enthalpies(
|
|
port_a_m_flow=port_a_m_flow,
|
|
connected_h_a=connected_h_a,
|
|
port_b_m_flow=port_b_m_flow,
|
|
connected_h_b=connected_h_b,
|
|
internal_h=internal_h,
|
|
)
|
|
return self.derivatives(
|
|
inlet_h_a=inlet_h_a,
|
|
inlet_h_b=inlet_h_b,
|
|
m_flow_a=port_a_m_flow,
|
|
m_flow_b=port_b_m_flow,
|
|
)
|
|
|
|
def derivatives(
|
|
self,
|
|
inlet_h_a: float,
|
|
inlet_h_b: float,
|
|
m_flow_a: float,
|
|
m_flow_b: float,
|
|
) -> VolumeState:
|
|
dm_dt = m_flow_a + m_flow_b
|
|
dU_dt = m_flow_a * inlet_h_a + m_flow_b * inlet_h_b
|
|
return VolumeState(m=dm_dt, U=dU_dt)
|