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)