对齐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

+113 -1
View File
@@ -5,6 +5,13 @@ from collections.abc import Callable
from dataclasses import dataclass
from math import expm1, isfinite, log, sqrt
from app.simulation.components.amesim.boundary.sources import AmesimPnpl01
from app.simulation.components.amesim.flow.orifices import AmesimPnor001
from app.simulation.components.amesim.flow.pipes import (
AmesimPnl00r,
AmesimPnl0001,
AmesimPnl0002,
)
from app.simulation.core.ports import PortState, VariableRole
from app.simulation.systems.network import SimulationNetwork
@@ -716,7 +723,7 @@ class PressureFlowSolver:
"""Execute the precompiled explicit flow/force causalization plan."""
for unknown in self.unknowns:
if unknown.variable == "f":
if unknown.variable in {"f", "m_flow"}:
unknown.write(0.0)
seeded_ids: set[str] = set()
@@ -728,6 +735,109 @@ class PressureFlowSolver:
seeded_ids.add(assignment.unknown.id)
return seeded_ids
def _seed_closed_resistance_pressures(self) -> None:
"""Seed a sealed resistance end at its zero-flow pressure.
A PNPL01 fixes flow, not pressure. Starting a dead-ended Darcy branch
with the plug-side pressure at the medium reference can otherwise put
the nonlinear solver on the singular square-root part of the inverse
flow law. At zero flow, these AMESim pipe resistances have exactly zero
pressure drop, which gives a deterministic and physically exact seed.
"""
connected: dict[tuple[str, str], tuple[str, str]] = {}
for connection in self.network.connections:
if connection.kind != "physical" or connection.domain != "pneumatic":
continue
first, second = connection.endpoints
connected[first.key] = second.key
connected[second.key] = first.key
for component in self.network.components.values():
if not isinstance(component, (AmesimPnl00r, AmesimPnl0001)):
continue
for port_name in component.ports:
neighbor_key = connected.get((component.name, port_name))
if neighbor_key is None:
continue
neighbor = self.network.components[neighbor_key[0]]
if not isinstance(neighbor, AmesimPnpl01):
continue
if isinstance(component, AmesimPnl0002):
pressure = component.properties().p
elif isinstance(component, AmesimPnl0001):
if port_name != "port_1":
continue
pressure = component.properties().p
else:
other_port_name = "port_2" if port_name == "port_1" else "port_1"
pressure = component.get_port(other_port_name).p
component.get_port(port_name).p = pressure
neighbor.get_port(neighbor_key[1]).p = pressure
def _seed_pnor_pnl0001_series_pressures(self) -> None:
"""Causalize the pressure between a PNOR001 and PNL0001 R port."""
for connection in self.network.connections:
first_endpoint, second_endpoint = connection.endpoints
first = self.network.components[first_endpoint.component]
second = self.network.components[second_endpoint.component]
if isinstance(first, AmesimPnor001) and isinstance(second, AmesimPnl0001):
orifice, orifice_port = first, first_endpoint.port
pipe, pipe_port = second, second_endpoint.port
elif isinstance(second, AmesimPnor001) and isinstance(first, AmesimPnl0001):
orifice, orifice_port = second, second_endpoint.port
pipe, pipe_port = first, first_endpoint.port
else:
continue
if isinstance(pipe, AmesimPnl0002) or pipe_port != "port_1":
continue
orifice_other = "port_2" if orifice_port == "port_1" else "port_1"
pressure_a = orifice.get_port(orifice_other).p
pressure_b = pipe.properties().p
lower = min(pressure_a, pressure_b)
upper = max(pressure_a, pressure_b)
def mismatch(intermediate_pressure: float) -> float:
if orifice_port == "port_2":
orifice_flow_into_connection = -orifice.mass_flow(
pressure_a,
intermediate_pressure,
)
else:
orifice_flow_into_connection = orifice.mass_flow(
intermediate_pressure,
pressure_a,
)
pipe_flow_into_connection = pipe.mass_flow(
intermediate_pressure,
pressure_b,
pipe.properties().T,
)
return orifice_flow_into_connection + pipe_flow_into_connection
lower_value = mismatch(lower)
upper_value = mismatch(upper)
if lower_value == 0.0:
pressure = lower
elif upper_value == 0.0:
pressure = upper
elif (lower_value < 0.0) == (upper_value < 0.0):
continue
else:
for _iteration in range(64):
middle = 0.5 * (lower + upper)
middle_value = mismatch(middle)
if (middle_value < 0.0) == (lower_value < 0.0):
lower = middle
lower_value = middle_value
else:
upper = middle
pressure = 0.5 * (lower + upper)
orifice.get_port(orifice_port).p = pressure
pipe.get_port(pipe_port).p = pressure
def _scales(self) -> dict[str, float]:
pressure_scale = max(
[
@@ -783,6 +893,8 @@ class PressureFlowSolver:
clear_causal_contact()
self._seed_equal_efforts()
self._seed_closed_resistance_pressures()
self._seed_pnor_pnl0001_series_pressures()
self._solve_explicit_flow_unknowns()
contact_bindings = self._seed_unilateral_contacts()
if contact_bindings: