整合求解器活动监控与步长回归证据
同步远端 PNL0003 诊断和大采样网格能力,语义合并活动感知的 60 秒真停滞判定与旧后端 15 分钟兼容兜底。 纳管热路径优化、15 单元运行证据、浏览器与 API 报告,并补充北京时间更新日志和遗留问题。
This commit is contained in:
1 parent
c19cf77aee
commit
e18399c022
46 files changed
+181589
-170
No files matched your search
@@ -60,6 +60,9 @@ class AmesimPnor001(AlgebraicComponent):
|
||||
MODEL_TYPE = "amesim_pnor001"
|
||||
MODEL_VERSION = "0.3.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = True
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
@@ -465,6 +468,9 @@ class AmesimPnvo001FixedOpening(AlgebraicComponent):
|
||||
MODEL_TYPE = "amesim_pnvo001_fixed"
|
||||
MODEL_VERSION = "0.2.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = True
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_3", nominal_role="bidirectional"),
|
||||
@@ -900,6 +906,10 @@ class AmesimPnvo001SignalOpening(AmesimPnvo001FixedOpening):
|
||||
MODEL_TYPE = "amesim_pnvo001"
|
||||
MODEL_VERSION = "0.2.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = True
|
||||
# Repeat the exact-sum promise on this concrete subclass deliberately.
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.signal("res", nominal_role="input"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping, Sequence
|
||||
from collections.abc import Callable, Mapping, Sequence
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
from math import isclose, isfinite, log, log10, pi, sqrt, tanh
|
||||
@@ -71,6 +71,47 @@ _PN2PIPEFR_TRANSITION_SHARPNESS = 8.37293695
|
||||
_PN2PIPEFR_ANALYTIC_LAMINAR_MAX_REYNOLDS = 1000.0
|
||||
|
||||
|
||||
def _pn2pipefr_friction_factor_with_precomputed_fully_rough(
|
||||
reynolds_number: float,
|
||||
*,
|
||||
relative_roughness: float,
|
||||
fully_rough: float | None,
|
||||
) -> float:
|
||||
"""Evaluate the built-in friction law with its rr-only term supplied."""
|
||||
|
||||
if reynolds_number <= 0.0:
|
||||
return 64_000_000.0
|
||||
laminar = 64.0 / reynolds_number
|
||||
if reynolds_number <= _PN2PIPEFR_TRANSITION_START_REYNOLDS:
|
||||
return laminar
|
||||
|
||||
# Keep this arithmetic in the same order as AmesimPnl00r.friction_factor.
|
||||
# The specialized fixed-point path only moves the rr-only logarithm out of
|
||||
# the iteration; subclasses continue to use the public virtual method.
|
||||
smooth_turbulent = 1.0 / (
|
||||
-1.8 * log10(6.9 / reynolds_number)
|
||||
) ** 2
|
||||
if relative_roughness <= 0.0:
|
||||
turbulent = smooth_turbulent
|
||||
else:
|
||||
assert fully_rough is not None
|
||||
roughness_reynolds = reynolds_number * relative_roughness
|
||||
roughness_reynolds_squared = roughness_reynolds * roughness_reynolds
|
||||
roughness_weight = roughness_reynolds_squared / (
|
||||
roughness_reynolds_squared + 180.0 * 180.0
|
||||
)
|
||||
turbulent = smooth_turbulent + roughness_weight * (
|
||||
fully_rough - smooth_turbulent
|
||||
)
|
||||
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 _reported_friction_factor(value: float) -> float:
|
||||
return min(float(value), _MAX_REPORTED_FRICTION_FACTOR)
|
||||
|
||||
@@ -123,6 +164,9 @@ class AmesimPnl00r(AlgebraicComponent):
|
||||
MODEL_TYPE = "amesim_pnl00r"
|
||||
MODEL_VERSION = "0.3.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = True
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
@@ -876,11 +920,11 @@ class AmesimPnl0001(ThermodynamicVolumeComponent):
|
||||
value *= tanh(max(smoothing_argument, 0.0))
|
||||
return value
|
||||
|
||||
pressure_ratio_flow_parameter = mass_flow_parameter(pressure_ratio)
|
||||
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
|
||||
self.area * p_up * pressure_ratio_flow_parameter
|
||||
) ** 2 / (16.0 * pi * viscosity * resistance_length * T_up)
|
||||
if (
|
||||
self.reynolds_number(laminar_mass_flow, T_up)
|
||||
@@ -888,27 +932,58 @@ class AmesimPnl0001(ThermodynamicVolumeComponent):
|
||||
):
|
||||
return laminar_mass_flow
|
||||
|
||||
sqrt_temperature = sqrt(T_up)
|
||||
compiled_reynolds = (
|
||||
type(self).reynolds_number is AmesimPnl0001.reynolds_number
|
||||
and type(self)._dynamic_viscosity is AmesimPnl0001._dynamic_viscosity
|
||||
)
|
||||
reynolds_denominator = (
|
||||
pi * self.diam * self._dynamic_viscosity(T_up)
|
||||
if max_iterations > 0 and compiled_reynolds
|
||||
else None
|
||||
)
|
||||
compiled_friction_factor = type(self) in (
|
||||
AmesimPnl00r,
|
||||
AmesimPnl0001,
|
||||
AmesimPnl0002,
|
||||
)
|
||||
fully_rough = (
|
||||
1.0 / (-2.0 * log10(self.rr / 3.7)) ** 2
|
||||
if max_iterations > 0
|
||||
and compiled_friction_factor
|
||||
and self.rr > 0.0
|
||||
else None
|
||||
)
|
||||
|
||||
def target_flow(mass_flow: float) -> float:
|
||||
reynolds = self.reynolds_number(mass_flow, T_up)
|
||||
friction = self.friction_factor(reynolds)
|
||||
flow_coefficient = sqrt(
|
||||
self.diam / (resistance_length * friction)
|
||||
reynolds = (
|
||||
4.0 * abs(mass_flow) / reynolds_denominator
|
||||
if reynolds_denominator is not None
|
||||
else self.reynolds_number(mass_flow, T_up)
|
||||
)
|
||||
friction = (
|
||||
_pn2pipefr_friction_factor_with_precomputed_fully_rough(
|
||||
reynolds,
|
||||
relative_roughness=self.rr,
|
||||
fully_rough=fully_rough,
|
||||
)
|
||||
if compiled_friction_factor
|
||||
else self.friction_factor(reynolds)
|
||||
)
|
||||
return (
|
||||
flow_coefficient
|
||||
sqrt(self.diam / (resistance_length * friction))
|
||||
* self.area
|
||||
* p_up
|
||||
* mass_flow_parameter(pressure_ratio)
|
||||
/ sqrt(T_up)
|
||||
* pressure_ratio_flow_parameter
|
||||
/ sqrt_temperature
|
||||
)
|
||||
|
||||
flow_coefficient = sqrt(self.diam / (resistance_length * 0.02))
|
||||
magnitude = (
|
||||
flow_coefficient
|
||||
sqrt(self.diam / (resistance_length * 0.02))
|
||||
* self.area
|
||||
* p_up
|
||||
* mass_flow_parameter(pressure_ratio)
|
||||
/ sqrt(T_up)
|
||||
* pressure_ratio_flow_parameter
|
||||
/ sqrt_temperature
|
||||
)
|
||||
for _iteration in range(max_iterations):
|
||||
next_magnitude = target_flow(magnitude)
|
||||
@@ -1069,6 +1144,23 @@ class AmesimPnl0001(ThermodynamicVolumeComponent):
|
||||
self.port_1.m_flow - self.mass_flow(self.port_1.p, props.p, props.T),
|
||||
)
|
||||
|
||||
def pressure_flow_equation_value_readers(
|
||||
self,
|
||||
) -> Mapping[str, Callable[[], float]]:
|
||||
"""Expose the independently evaluable state-pressure residual."""
|
||||
|
||||
def pressure_state_residual() -> float:
|
||||
props = self.medium.properties_from_mU(
|
||||
self.state.m,
|
||||
self.state.U,
|
||||
self.volume,
|
||||
)
|
||||
return self.port_2.p - props.p
|
||||
|
||||
return {
|
||||
f"{self.name}:port_2_pressure_state": pressure_state_residual,
|
||||
}
|
||||
|
||||
def pressure_flow_equation_residuals(self) -> tuple[EquationResidual, ...]:
|
||||
props = self.medium.properties_from_mU(self.state.m, self.state.U, self.volume)
|
||||
return (
|
||||
|
||||
@@ -163,6 +163,9 @@ class AmesimPn3Node2(_AmesimPneumaticNode):
|
||||
MODEL_TYPE = "amesim_pn3node2"
|
||||
MODEL_VERSION = "0.3.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
@@ -200,6 +203,9 @@ class AmesimP4Node2(_AmesimPneumaticNode):
|
||||
MODEL_TYPE = "amesim_p4node2"
|
||||
MODEL_VERSION = "0.3.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
|
||||
@@ -1386,6 +1386,9 @@ class AmesimLmechn1(AlgebraicComponent):
|
||||
|
||||
MODEL_TYPE = "amesim_lmechn1"
|
||||
MODEL_VERSION = "0.2.0"
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("force_balance",)
|
||||
)
|
||||
PORTS = tuple(
|
||||
PortDefinition.mechanical_translational(f"port_{index}")
|
||||
for index in range(1, 22)
|
||||
|
||||
@@ -17,6 +17,9 @@ class Orifice(AlgebraicComponent):
|
||||
MODEL_TYPE = "orifice"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_a", nominal_role="inlet"),
|
||||
PortDefinition.pneumatic("port_b", nominal_role="outlet"),
|
||||
@@ -116,4 +119,3 @@ class Orifice(AlgebraicComponent):
|
||||
def update_stream_outflows(self, connected_h: Mapping[str, float]) -> None:
|
||||
self.port_a.h_outflow = connected_h["port_b"]
|
||||
self.port_b.h_outflow = connected_h["port_a"]
|
||||
|
||||
@@ -17,6 +17,9 @@ class ResistivePipe(AlgebraicComponent):
|
||||
MODEL_TYPE = "pipe"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_a", nominal_role="inlet"),
|
||||
PortDefinition.pneumatic("port_b", nominal_role="outlet"),
|
||||
|
||||
@@ -15,6 +15,9 @@ class Tee(AlgebraicComponent):
|
||||
MODEL_TYPE = "tee"
|
||||
MODEL_VERSION = "1.0.0"
|
||||
PRESSURE_FLOW_DEPENDS_ON_STREAM = False
|
||||
PRESSURE_FLOW_EXACT_SUM_TO_ZERO_EQUATION_SUFFIXES = frozenset(
|
||||
("mass_flow_balance",)
|
||||
)
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_in", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_out1", nominal_role="bidirectional"),
|
||||
|
||||
Reference in new issue
Block a user