对齐AMESim管阻孔口与储气耦合

This commit is contained in:
huojiarong committed 2026-08-10 13:07:03 +00:00
1 parent 7671418582
commit 6abcc220de
14 files changed
+817 -65

No files matched your search

+136 -37
View File
@@ -51,13 +51,12 @@ _PNVO001_FLOW_COEFFICIENT_GROUP = ParameterGroupDisplaySpec(
class AmesimPnor001(AlgebraicComponent):
"""AMESim PNOR001 constant-flow-coefficient pneumatic orifice.
This public component preserves the PNOR001 catalog/XML contract and uses a
finite bidirectional compressible-orifice approximation. The Siemens
`pn2rcqfix_` details remain a later calibration target.
This public component preserves the PNOR001 catalog/XML contract and uses
real-gas pressure-ratio flow with AMESim-style near-equal-pressure smoothing.
"""
MODEL_TYPE = "amesim_pnor001"
MODEL_VERSION = "0.2.0"
MODEL_VERSION = "0.3.0"
PORTS = (
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
@@ -188,6 +187,7 @@ class AmesimPnor001(AlgebraicComponent):
self.port_1.h_outflow = initial_h
self.port_2 = self.register_declared_port("port_2")
self.port_2.h_outflow = initial_h
self._connected_h: dict[str, float] = {}
@staticmethod
def _integer_parameter(name: str, value: float) -> int:
@@ -243,16 +243,113 @@ class AmesimPnor001(AlgebraicComponent):
def _upstream_temperature(self, port_name: str) -> float:
port = self.get_port(port_name)
inlet_h = self._connected_h.get(port_name, port.h_outflow)
return max(
self.medium.temperature_from_pressure_enthalpy(
max(port.p, 1.0),
port.h_outflow,
inlet_h,
),
1.0,
)
@staticmethod
def _subsonic_mass_flow_parameter(
*,
pressure_ratio: float,
gamma_s: float,
density: float,
upstream_temperature: float,
upstream_pressure: float,
) -> float:
expansion = (
pressure_ratio ** (2.0 * gamma_s)
- pressure_ratio ** (1.0 + gamma_s)
)
return sqrt(
max(
2.0
/ (1.0 - gamma_s)
* density
* upstream_temperature
/ upstream_pressure
* expansion,
0.0,
)
)
def _one_way_flow_characteristics(
self,
*,
upstream_pressure: float,
downstream_pressure: float,
upstream_temperature: float,
) -> tuple[float, float]:
p_up = max(upstream_pressure, 1.0)
p_down = max(min(downstream_pressure, p_up), 0.0)
T_up = max(upstream_temperature, 1.0)
gamma_s = self.medium.isentropic_density_pressure_factor(
p_up,
T_up,
p_down,
)
gamma_s = min(max(gamma_s, 1.0e-9), 1.0 - 1.0e-9)
density = max(self.medium.density(p_up, T_up), 1.0e-12)
pressure_ratio = max(p_down / p_up, 0.0)
critical_ratio = (2.0 * gamma_s / (gamma_s + 1.0)) ** (
1.0 / (1.0 - gamma_s)
)
if pressure_ratio <= critical_ratio:
effective_pressure_ratio = critical_ratio
mass_flow_parameter = (
sqrt(2.0 / (1.0 + gamma_s) * density * T_up / p_up)
* (2.0 * gamma_s / (gamma_s + 1.0))
** (gamma_s / (1.0 - gamma_s))
)
gas_velocity = sqrt(2.0 / (1.0 + gamma_s) * p_up / density)
else:
effective_pressure_ratio = pressure_ratio
mass_flow_parameter = self._subsonic_mass_flow_parameter(
pressure_ratio=pressure_ratio,
gamma_s=gamma_s,
density=density,
upstream_temperature=T_up,
upstream_pressure=p_up,
)
gas_velocity = sqrt(
max(
2.0
/ (1.0 - gamma_s)
* p_up
/ density
* (1.0 - pressure_ratio ** (1.0 - gamma_s)),
0.0,
)
)
reference = self._subsonic_mass_flow_parameter(
pressure_ratio=_PN_PRESSURE_RATIO_ACCURACY,
gamma_s=gamma_s,
density=density,
upstream_temperature=T_up,
upstream_pressure=p_up,
)
if mass_flow_parameter > 0.0 and reference > 0.0:
argument = (
_PN_LAMINAR_SMOOTHING_GAIN
* abs(mass_flow_parameter / reference)
* log(effective_pressure_ratio)
/ log(_PN_PRESSURE_RATIO_ACCURACY)
)
smoothing_factor = tanh(max(argument, 0.0))
mass_flow_parameter *= smoothing_factor
gas_velocity *= smoothing_factor
return mass_flow_parameter, gas_velocity
def mass_flow(self, p_1: float, p_2: float) -> float:
if p_1 == p_2 or self.effective_area == 0.0:
if (
isclose(p_1, p_2, rel_tol=0.0, abs_tol=1.0e-8)
or self.effective_area == 0.0
):
return 0.0
if p_1 > p_2:
return self._one_way_mass_flow(
@@ -274,43 +371,41 @@ class AmesimPnor001(AlgebraicComponent):
upstream_temperature: float,
) -> float:
p_up = max(upstream_pressure, 1.0)
p_down = max(min(downstream_pressure, p_up), 0.0)
T_up = max(upstream_temperature, 1.0)
gamma = max(self.medium.gamma, 1.000001)
pressure_ratio = max(p_down / p_up, 0.0)
critical_ratio = (2.0 / (gamma + 1.0)) ** (gamma / (gamma - 1.0))
if pressure_ratio <= critical_ratio:
flow_factor = sqrt(gamma / (self.medium.R_gas * T_up)) * (
2.0 / (gamma + 1.0)
) ** ((gamma + 1.0) / (2.0 * (gamma - 1.0)))
else:
expansion = pressure_ratio ** (2.0 / gamma) - pressure_ratio ** (
(gamma + 1.0) / gamma
)
flow_factor = sqrt(
max(
2.0
* gamma
* expansion
/ (self.medium.R_gas * T_up * (gamma - 1.0)),
0.0,
)
)
return self.effective_cq * self.effective_area * p_up * flow_factor
mass_flow_parameter, _ = self._one_way_flow_characteristics(
upstream_pressure=p_up,
downstream_pressure=downstream_pressure,
upstream_temperature=T_up,
)
return (
self.effective_cq
* self.effective_area
* p_up
* mass_flow_parameter
/ sqrt(T_up)
)
def component_result_values(self) -> Mapping[str, float]:
p_1 = max(self.port_1.p, 1.0)
p_2 = max(self.port_2.p, 1.0)
m_flow = abs(self.mass_flow(self.port_1.p, self.port_2.p))
upstream_pressure = max(p_1, p_2)
upstream_temperature = self._upstream_temperature(
"port_1" if p_1 >= p_2 else "port_2"
if p_1 >= p_2:
upstream_port_name = "port_1"
upstream_pressure = p_1
downstream_pressure = p_2
flow_direction = 1.0
else:
upstream_port_name = "port_2"
upstream_pressure = p_2
downstream_pressure = p_1
flow_direction = -1.0
mass_flow_parameter, gas_velocity = self._one_way_flow_characteristics(
upstream_pressure=upstream_pressure,
downstream_pressure=downstream_pressure,
upstream_temperature=self._upstream_temperature(upstream_port_name),
)
density = max(self.medium.density(upstream_pressure, upstream_temperature), 1.0e-12)
area = max(self.effective_area, 1.0e-18)
return {
"cm": m_flow / (self.effective_cq * area * upstream_pressure),
"gasvel": m_flow / (density * area),
"cm": mass_flow_parameter,
"gasvel": flow_direction * gas_velocity,
}
def pressure_flow_equation_residuals(self) -> tuple[EquationResidual, ...]:
@@ -344,6 +439,7 @@ class AmesimPnor001(AlgebraicComponent):
)
def update_stream_outflows(self, connected_h: Mapping[str, float]) -> None:
self._connected_h = dict(connected_h)
self.port_1.h_outflow = connected_h["port_2"]
self.port_2.h_outflow = connected_h["port_1"]
@@ -593,7 +689,10 @@ class AmesimPnvo001FixedOpening(AlgebraicComponent):
)
def mass_flow(self, p_2: float, p_3: float) -> float:
if p_2 == p_3 or self.effective_area == 0.0:
if (
isclose(p_2, p_3, rel_tol=1.0e-7, abs_tol=1.0e-9)
or self.effective_area == 0.0
):
return 0.0
if p_2 > p_3:
return self._one_way_mass_flow(