校准第二支路热流体能量与管路摩擦
This commit is contained in:
1 parent
0f73d5b568
commit
caca32a513
12 files changed
+336
-42
No files matched your search
@@ -47,7 +47,7 @@ class AmesimPnl00r(AlgebraicComponent):
|
||||
"""
|
||||
|
||||
MODEL_TYPE = "amesim_pnl00r"
|
||||
MODEL_VERSION = "0.1.0"
|
||||
MODEL_VERSION = "0.2.0"
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
@@ -203,13 +203,34 @@ class AmesimPnl00r(AlgebraicComponent):
|
||||
laminar = 64.0 / reynolds_number
|
||||
if reynolds_number <= 2300.0:
|
||||
return laminar
|
||||
turbulent = 1.0 / (
|
||||
-1.8 * log10((self.rr / 3.7) ** 1.11 + 6.9 / reynolds_number)
|
||||
|
||||
# pn2pipefr does not apply the fully rough correction at every
|
||||
# turbulent Reynolds number. Its saved ff curves first follow the
|
||||
# hydraulically smooth law and approach the rough asymptote as Re*rr
|
||||
# grows. Keeping those two limits separate reproduces the AMESim
|
||||
# curves for both 14 mm and 20 mm test_mql pipes; putting both terms
|
||||
# directly inside one Haaland logarithm over-predicts PNL0002 friction
|
||||
# by about 23 percent near Re=57,000.
|
||||
smooth_turbulent = 1.0 / (
|
||||
-1.8 * log10(6.9 / reynolds_number)
|
||||
) ** 2
|
||||
if self.rr <= 0.0:
|
||||
turbulent = smooth_turbulent
|
||||
else:
|
||||
fully_rough = 1.0 / (
|
||||
-1.8 * log10((self.rr / 3.7) ** 1.11)
|
||||
) ** 2
|
||||
roughness_reynolds = reynolds_number * self.rr
|
||||
roughness_weight = roughness_reynolds * roughness_reynolds / (
|
||||
roughness_reynolds * roughness_reynolds + 180.0 * 180.0
|
||||
)
|
||||
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 * (turbulent - laminar)
|
||||
return laminar + fraction**0.58 * (turbulent - laminar)
|
||||
|
||||
def darcy_pressure_drop(
|
||||
self,
|
||||
@@ -279,7 +300,11 @@ class AmesimPnl00r(AlgebraicComponent):
|
||||
density = max(self.medium.density(upstream_pressure, upstream_temperature), 1.0e-12)
|
||||
reynolds = self.reynolds_number(m_flow, upstream_temperature)
|
||||
velocity = m_flow / (density * self.area)
|
||||
cm = abs(m_flow) / max(self.area * upstream_pressure, 1.0e-18)
|
||||
cm = (
|
||||
abs(m_flow)
|
||||
* sqrt(upstream_temperature)
|
||||
/ max(self.area * upstream_pressure, 1.0e-18)
|
||||
)
|
||||
return {
|
||||
"re": reynolds,
|
||||
"cm": cm,
|
||||
@@ -326,7 +351,7 @@ class AmesimPnl0001(ThermodynamicVolumeComponent):
|
||||
"""AMESim PNL0001 C-R pneumatic pipe with compressibility and friction."""
|
||||
|
||||
MODEL_TYPE = "amesim_pnl0001"
|
||||
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"),
|
||||
@@ -798,7 +823,11 @@ class AmesimPnl0001(ThermodynamicVolumeComponent):
|
||||
"u": props.u,
|
||||
"h": props.h,
|
||||
"re": reynolds,
|
||||
"cm": abs(flow) / max(self.area * upstream_pressure, 1.0e-18),
|
||||
"cm": (
|
||||
abs(flow)
|
||||
* sqrt(props.T)
|
||||
/ max(self.area * upstream_pressure, 1.0e-18)
|
||||
),
|
||||
"v": flow / (density * self.area),
|
||||
"ff": self.friction_factor(reynolds),
|
||||
}
|
||||
@@ -861,7 +890,7 @@ class AmesimPnl0002(AmesimPnl0001):
|
||||
"""AMESim PNL0002 R-C-R pneumatic pipe with one center compliance."""
|
||||
|
||||
MODEL_TYPE = "amesim_pnl0002"
|
||||
MODEL_VERSION = "0.3.0"
|
||||
MODEL_VERSION = "0.5.0"
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
@@ -964,6 +993,20 @@ class AmesimPnl0002(AmesimPnl0001):
|
||||
def update_stream_outflows(self, connected_h: Mapping[str, float]) -> None:
|
||||
self._connected_h = dict(connected_h)
|
||||
|
||||
def update_flow_temperature_references(
|
||||
self,
|
||||
connected_h: Mapping[str, float],
|
||||
) -> None:
|
||||
self._connected_h = dict(connected_h)
|
||||
|
||||
def state_derivative_from_ports(
|
||||
self,
|
||||
connected_h: Mapping[str, float],
|
||||
) -> list[float]:
|
||||
# Junctions allocate their energy-balanced outlet enthalpy per port.
|
||||
# The separate cache is only the temperature input to pn2pipefr.
|
||||
return super().state_derivative_from_ports(connected_h)
|
||||
|
||||
def component_result_values(self) -> Mapping[str, float]:
|
||||
props = self.properties()
|
||||
flow_1 = self.port_mass_flow(
|
||||
@@ -978,10 +1021,45 @@ class AmesimPnl0002(AmesimPnl0001):
|
||||
props.T,
|
||||
port_name="port_2",
|
||||
)
|
||||
diagnostic_flow = flow_1 if abs(flow_1) >= abs(flow_2) else flow_2
|
||||
upstream_pressure = max(self.port_1.p, self.port_2.p, props.p, 1.0)
|
||||
density = max(self.medium.density(upstream_pressure, props.T), 1.0e-12)
|
||||
reynolds = self.reynolds_number(diagnostic_flow, props.T)
|
||||
resistance_diagnostics: list[tuple[float, float, float, float]] = []
|
||||
for port_name, port, flow in (
|
||||
("port_1", self.port_1, flow_1),
|
||||
("port_2", self.port_2, flow_2),
|
||||
):
|
||||
if flow >= 0.0:
|
||||
upstream_pressure = max(port.p, 1.0)
|
||||
upstream_h = self._connected_h.get(port_name, props.h)
|
||||
upstream_temperature = max(
|
||||
self.medium.temperature_from_pressure_enthalpy(
|
||||
upstream_pressure,
|
||||
upstream_h,
|
||||
),
|
||||
1.0,
|
||||
)
|
||||
else:
|
||||
upstream_pressure = max(props.p, 1.0)
|
||||
upstream_temperature = props.T
|
||||
density = max(
|
||||
self.medium.density(upstream_pressure, upstream_temperature),
|
||||
1.0e-12,
|
||||
)
|
||||
reynolds = self.reynolds_number(flow, upstream_temperature)
|
||||
resistance_diagnostics.append(
|
||||
(
|
||||
reynolds,
|
||||
(
|
||||
abs(flow)
|
||||
* sqrt(upstream_temperature)
|
||||
/ max(self.area * upstream_pressure, 1.0e-18)
|
||||
),
|
||||
abs(flow) / (density * self.area),
|
||||
self.friction_factor(reynolds),
|
||||
)
|
||||
)
|
||||
reynolds, cm, velocity, friction = (
|
||||
sum(values) / len(resistance_diagnostics)
|
||||
for values in zip(*resistance_diagnostics)
|
||||
)
|
||||
return {
|
||||
"m": self.state.m,
|
||||
"U": self.state.U,
|
||||
@@ -991,9 +1069,9 @@ class AmesimPnl0002(AmesimPnl0001):
|
||||
"u": props.u,
|
||||
"h": props.h,
|
||||
"re": reynolds,
|
||||
"cm": abs(diagnostic_flow) / max(self.area * upstream_pressure, 1.0e-18),
|
||||
"v": diagnostic_flow / (density * self.area),
|
||||
"ff": self.friction_factor(reynolds),
|
||||
"cm": cm,
|
||||
"v": velocity,
|
||||
"ff": friction,
|
||||
}
|
||||
|
||||
def pressure_flow_equation_residuals(self) -> tuple[EquationResidual, ...]:
|
||||
@@ -1045,7 +1123,7 @@ class AmesimPnl0003(DynamicComponent):
|
||||
|
||||
state_size = 4
|
||||
MODEL_TYPE = "amesim_pnl0003"
|
||||
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"),
|
||||
@@ -1318,7 +1396,11 @@ class AmesimPnl0003(DynamicComponent):
|
||||
"h2": port_2.h,
|
||||
"dmctr": center_flow,
|
||||
"re": reynolds,
|
||||
"cm": abs(center_flow) / max(self.area * max(port_1.p, port_2.p, 1.0), 1.0e-18),
|
||||
"cm": (
|
||||
abs(center_flow)
|
||||
* sqrt(upstream.T)
|
||||
/ max(self.area * max(port_1.p, port_2.p, 1.0), 1.0e-18)
|
||||
),
|
||||
"v": center_flow / (max(upstream.rho, 1.0e-12) * self.area),
|
||||
"ff": self.friction_factor(reynolds),
|
||||
}
|
||||
|
||||
@@ -10,13 +10,20 @@ from app.simulation.core.ports import PortDefinition, PortState
|
||||
|
||||
|
||||
class _AmesimPneumaticNode(AlgebraicComponent):
|
||||
"""Shared implementation for AMESim pneumatic junction submodels."""
|
||||
"""Shared implementation for AMESim pneumatic junction submodels.
|
||||
|
||||
PN3NODE2/P4NODE2 use port 2 as their pressure and temperature reference.
|
||||
Non-reference outlet ports use that reference temperature. When port 2 is
|
||||
an outlet, its enthalpy is the residual that closes the junction energy
|
||||
balance, matching the AMESim dh2 causality.
|
||||
"""
|
||||
|
||||
REFERENCE_PORT = "port_2"
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
super().__init__(name=name)
|
||||
self.set_parameter_values({})
|
||||
self.temperature_reference_h = 0.0
|
||||
for definition in self.PORTS:
|
||||
setattr(self, definition.name, self.register_declared_port(definition.name))
|
||||
|
||||
@@ -58,6 +65,10 @@ class _AmesimPneumaticNode(AlgebraicComponent):
|
||||
return tuple(residuals)
|
||||
|
||||
def update_stream_outflows(self, connected_h: Mapping[str, float]) -> None:
|
||||
self.temperature_reference_h = connected_h.get(
|
||||
self.REFERENCE_PORT,
|
||||
sum(connected_h.values()) / len(connected_h) if connected_h else 0.0,
|
||||
)
|
||||
incoming = [
|
||||
(port.m_flow, connected_h[name])
|
||||
for name, port in self.ports.items()
|
||||
@@ -67,19 +78,37 @@ class _AmesimPneumaticNode(AlgebraicComponent):
|
||||
if total_flow > 1e-12:
|
||||
mixed_h = sum(m_flow * h for m_flow, h in incoming) / total_flow
|
||||
else:
|
||||
mixed_h = connected_h.get(
|
||||
self.REFERENCE_PORT,
|
||||
sum(connected_h.values()) / len(connected_h) if connected_h else 0.0,
|
||||
mixed_h = self.temperature_reference_h
|
||||
|
||||
reference_port = self.get_port(self.REFERENCE_PORT)
|
||||
for name, port in self.ports.items():
|
||||
port.h_outflow = (
|
||||
mixed_h
|
||||
if name == self.REFERENCE_PORT
|
||||
else self.temperature_reference_h
|
||||
)
|
||||
|
||||
if reference_port.m_flow < -1e-12:
|
||||
energy_without_reference = sum(
|
||||
port.m_flow
|
||||
* (
|
||||
connected_h[name]
|
||||
if port.m_flow > 1e-12
|
||||
else self.temperature_reference_h
|
||||
)
|
||||
for name, port in self.ports.items()
|
||||
if name != self.REFERENCE_PORT
|
||||
)
|
||||
reference_port.h_outflow = (
|
||||
-energy_without_reference / reference_port.m_flow
|
||||
)
|
||||
for port in self.ports.values():
|
||||
port.h_outflow = mixed_h
|
||||
|
||||
|
||||
class AmesimPn3Node2(_AmesimPneumaticNode):
|
||||
"""AMESim PN3NODE2 pneumatic three-port junction."""
|
||||
|
||||
MODEL_TYPE = "amesim_pn3node2"
|
||||
MODEL_VERSION = "0.1.0"
|
||||
MODEL_VERSION = "0.3.0"
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
@@ -115,7 +144,7 @@ class AmesimP4Node2(_AmesimPneumaticNode):
|
||||
"""AMESim P4NODE2 pneumatic four-port junction."""
|
||||
|
||||
MODEL_TYPE = "amesim_p4node2"
|
||||
MODEL_VERSION = "0.1.0"
|
||||
MODEL_VERSION = "0.3.0"
|
||||
PORTS = (
|
||||
PortDefinition.pneumatic("port_1", nominal_role="bidirectional"),
|
||||
PortDefinition.pneumatic("port_2", nominal_role="bidirectional"),
|
||||
|
||||
Reference in new issue
Block a user