完善 PNL00R 摩擦模型与八路回归

This commit is contained in:
huojiarong committed 2026-08-18 09:30:29 +00:00
1 parent 684d28752a
commit f725f038b6
10 files changed
+498 -98

No files matched your search

+56 -17
View File
@@ -54,6 +54,22 @@ class Pnl0001DerivativeLinearization:
_MAX_REPORTED_FRICTION_FACTOR = 64_000_000.0
# ``pn2pipefr`` blends the laminar and turbulent friction branches over a
# much wider Reynolds range than the former hard 2300..4000 interpolation.
# These constants are a uniform-Re least-squares fit to the unchanged
# Simcenter Amesim 2404 test_mql result for PNL00R/PNL0001/PNL0003 at both
# rr=0.045/14 and rr=0.045/20. The shifted Hill exponent is greater than 2,
# so its zero-valued join to the laminar branch is C2 continuous.
_PN2PIPEFR_TRANSITION_START_REYNOLDS = 89.96829989
_PN2PIPEFR_TRANSITION_SCALE_REYNOLDS = 2741.96700831
_PN2PIPEFR_TRANSITION_SHARPNESS = 8.37293695
# PNL00R keeps the exact closed-form laminar solve where the fitted
# transition contribution is below four parts per million. Extending this
# shortcut to Re=2300 bypassed the real AMESim transition and introduced a
# solver-visible branch point.
_PN2PIPEFR_ANALYTIC_LAMINAR_MAX_REYNOLDS = 1000.0
def _reported_friction_factor(value: float) -> float:
return min(float(value), _MAX_REPORTED_FRICTION_FACTOR)
@@ -75,8 +91,8 @@ class AmesimPnl00r(AlgebraicComponent):
"""AMESim PNL00R pneumatic pipe friction resistance.
The public model exposes the AMESim PNL00R catalog/XML contract and uses
an auditable Darcy-Weisbach resistance with Reynolds/roughness-dependent
friction. Exact `pn2pipefr_` parity is left for the later model tuning pass.
the `pn2pipefr` compressible gas relation with a Reynolds/roughness-
dependent equivalent flow coefficient.
"""
MODEL_TYPE = "amesim_pnl00r"
@@ -244,7 +260,7 @@ class AmesimPnl00r(AlgebraicComponent):
if reynolds_number <= 0.0:
return 64_000_000.0
laminar = 64.0 / reynolds_number
if reynolds_number <= 2300.0:
if reynolds_number <= _PN2PIPEFR_TRANSITION_START_REYNOLDS:
return laminar
# pn2pipefr does not apply the fully rough correction at every
@@ -274,10 +290,13 @@ class AmesimPnl00r(AlgebraicComponent):
turbulent = smooth_turbulent + roughness_weight * (
fully_rough - smooth_turbulent
)
if reynolds_number >= 4000.0:
return turbulent
fraction = (reynolds_number - 2300.0) / 1700.0
return laminar + fraction**0.58 * (turbulent - laminar)
transition_coordinate = (
(reynolds_number - _PN2PIPEFR_TRANSITION_START_REYNOLDS)
/ _PN2PIPEFR_TRANSITION_SCALE_REYNOLDS
)
transition_power = transition_coordinate**_PN2PIPEFR_TRANSITION_SHARPNESS
transition_weight = transition_power / (1.0 + transition_power)
return laminar + transition_weight * (turbulent - laminar)
def darcy_pressure_drop(
self,
@@ -329,13 +348,17 @@ class AmesimPnl00r(AlgebraicComponent):
if isclose(p_1, p_2, rel_tol=0.0, abs_tol=1.0e-8):
return 0.0
pressure_difference = p_1 - p_2
upstream_pressure = max(p_1, p_2, 1.0)
upstream_temperature = self._port_temperature("port_1" if pressure_difference > 0.0 else "port_2")
density = max(self.medium.density(upstream_pressure, upstream_temperature), 1.0e-12)
magnitude = self._mass_flow_for_pressure_drop(
abs(pressure_difference),
density=density,
temperature=upstream_temperature,
upstream_temperature = self._port_temperature(
"port_1" if pressure_difference > 0.0 else "port_2"
)
magnitude = AmesimPnl0001._one_way_pn2pipefr_mass_flow(
self,
upstream_pressure=max(p_1, p_2),
downstream_pressure=min(p_1, p_2),
upstream_temperature=upstream_temperature,
resistance_length=self.le,
max_iterations=64,
analytic_laminar=True,
)
return magnitude if pressure_difference > 0.0 else -magnitude
@@ -347,17 +370,19 @@ class AmesimPnl00r(AlgebraicComponent):
)
density = max(self.medium.density(upstream_pressure, upstream_temperature), 1.0e-12)
reynolds = self.reynolds_number(m_flow, upstream_temperature)
friction = self.friction_factor(reynolds)
flow_coefficient = sqrt(self.diam / (self.le * friction))
velocity = m_flow / (density * self.area)
cm = (
abs(m_flow)
* sqrt(upstream_temperature)
/ max(self.area * upstream_pressure, 1.0e-18)
/ max(flow_coefficient * self.area * upstream_pressure, 1.0e-18)
)
return {
"re": reynolds,
"cm": cm,
"v": velocity,
"ff": _reported_friction_factor(self.friction_factor(reynolds)),
"ff": _reported_friction_factor(friction),
}
def pressure_flow_equation_values(self) -> tuple[float, ...]:
@@ -754,6 +779,8 @@ class AmesimPnl0001(ThermodynamicVolumeComponent):
downstream_pressure: float,
upstream_temperature: float,
resistance_length: float,
max_iterations: int = 16,
analytic_laminar: bool = False,
) -> float:
"""AMESim pn2pipefr-style compressible friction flow."""
@@ -824,6 +851,18 @@ class AmesimPnl0001(ThermodynamicVolumeComponent):
value *= tanh(max(smoothing_argument, 0.0))
return value
if analytic_laminar:
flow_parameter = mass_flow_parameter(pressure_ratio)
viscosity = self._dynamic_viscosity(T_up)
laminar_mass_flow = (
self.area * p_up * flow_parameter
) ** 2 / (16.0 * pi * viscosity * resistance_length * T_up)
if (
self.reynolds_number(laminar_mass_flow, T_up)
<= _PN2PIPEFR_ANALYTIC_LAMINAR_MAX_REYNOLDS
):
return laminar_mass_flow
def target_flow(mass_flow: float) -> float:
reynolds = self.reynolds_number(mass_flow, T_up)
friction = self.friction_factor(reynolds)
@@ -846,7 +885,7 @@ class AmesimPnl0001(ThermodynamicVolumeComponent):
* mass_flow_parameter(pressure_ratio)
/ sqrt(T_up)
)
for _iteration in range(16):
for _iteration in range(max_iterations):
next_magnitude = target_flow(magnitude)
if abs(next_magnitude - magnitude) <= max(
1.0e-12,