优化仿真求解性能并修复流量闭合问题(初版)

This commit is contained in:
ljz committed 2026-08-16 17:46:05 +08:00
1 parent 57b459bc72
commit 5332a788f3
55 files changed
+8973 -549

No files matched your search

+74 -45
View File
@@ -2,9 +2,10 @@ from __future__ import annotations
from dataclasses import dataclass
from app.simulation.core.base import DynamicComponent
from app.simulation.core.base import Component, DynamicComponent
from app.simulation.core.ports import PortState
from app.simulation.performance import profile_phase
from app.simulation.systems.network import Endpoint, SimulationNetwork
from app.simulation.systems.network import SimulationNetwork
class StreamSolveError(RuntimeError):
@@ -27,6 +28,14 @@ class StreamSolveDiagnostics:
}
@dataclass(frozen=True)
class _StreamConnectionBinding:
component_name: str
port_name: str
connected_component: Component
connected_port: PortState
class StreamResolver:
"""Resolve outflow enthalpy propagation after pressure and flow are known."""
@@ -40,28 +49,59 @@ class StreamResolver:
self.network = network
self.relative_tolerance = relative_tolerance
self.max_iterations = max_iterations
self._connected_endpoint = self._build_connection_map()
self._components = tuple(network.components.values())
self._dynamic_components = tuple(
component
for component in self._components
if isinstance(component, DynamicComponent)
)
self._non_dynamic_components = tuple(
component
for component in self._components
if not isinstance(component, DynamicComponent)
)
self._ports = tuple(
(component.name, port_name, port)
for component in self._components
for port_name, port in component.ports.items()
)
self._connection_bindings = self._build_connection_bindings()
self.last_diagnostics: StreamSolveDiagnostics | None = None
def _build_connection_map(self) -> dict[Endpoint, Endpoint]:
result: dict[Endpoint, Endpoint] = {}
def _build_connection_bindings(self) -> tuple[_StreamConnectionBinding, ...]:
result: list[_StreamConnectionBinding] = []
for connection in self.network.connections:
if connection.kind != "physical":
continue
first, second = connection.endpoints
result[first] = second
result[second] = first
return result
first_component = self.network.components[first.component]
second_component = self.network.components[second.component]
result.append(
_StreamConnectionBinding(
component_name=first.component,
port_name=first.port,
connected_component=second_component,
connected_port=second_component.get_port(second.port),
)
)
result.append(
_StreamConnectionBinding(
component_name=second.component,
port_name=second.port,
connected_component=first_component,
connected_port=first_component.get_port(first.port),
)
)
return tuple(result)
def connected_enthalpies(self) -> dict[str, dict[str, float]]:
values: dict[str, dict[str, float]] = {
component.name: {} for component in self.network.components.values()
component.name: {} for component in self._components
}
for endpoint, connected in self._connected_endpoint.items():
connected_port = self.network.components[connected.component].get_port(
connected.port
for binding in self._connection_bindings:
values[binding.component_name][binding.port_name] = (
binding.connected_port.h_outflow
)
values[endpoint.component][endpoint.port] = connected_port.h_outflow
return values
def connected_temperature_reference_enthalpies(
@@ -70,26 +110,21 @@ class StreamResolver:
"""Return connector references used for upstream temperature only."""
values: dict[str, dict[str, float]] = {
component.name: {} for component in self.network.components.values()
component.name: {} for component in self._components
}
for endpoint, connected in self._connected_endpoint.items():
connected_component = self.network.components[connected.component]
connected_port = connected_component.get_port(connected.port)
values[endpoint.component][endpoint.port] = float(
for binding in self._connection_bindings:
values[binding.component_name][binding.port_name] = float(
getattr(
connected_component,
binding.connected_component,
"temperature_reference_h",
connected_port.h_outflow,
binding.connected_port.h_outflow,
)
)
return values
@profile_phase("simulation.refresh", minimum_mode="audit")
def _refresh_dynamic_components(
self,
components: list[DynamicComponent],
) -> None:
for component in components:
def _refresh_dynamic_components(self) -> None:
for component in self._dynamic_components:
component.refresh_thermodynamic_ports()
@profile_phase("simulation.refresh", minimum_mode="audit")
@@ -97,40 +132,34 @@ class StreamResolver:
self,
connected: dict[str, dict[str, float]],
) -> None:
for component in self.network.components.values():
if isinstance(component, DynamicComponent):
component.refresh_thermodynamic_ports()
else:
component.update_stream_outflows(connected[component.name])
for component in self._non_dynamic_components:
component.update_stream_outflows(connected[component.name])
@profile_phase("simulation.stream", minimum_mode="audit")
def solve(self) -> tuple[StreamSolveDiagnostics, dict[str, dict[str, float]]]:
dynamic_components = [
component
for component in self.network.components.values()
if isinstance(component, DynamicComponent)
]
self._refresh_dynamic_components(dynamic_components)
def solve(
self,
*,
dynamic_ports_are_current: bool = False,
) -> tuple[StreamSolveDiagnostics, dict[str, dict[str, float]]]:
if not dynamic_ports_are_current:
self._refresh_dynamic_components()
max_delta = 0.0
for iteration in range(1, self.max_iterations + 1):
previous = {
(component.name, port_name): port.h_outflow
for component in self.network.components.values()
for port_name, port in component.ports.items()
(component_name, port_name): port.h_outflow
for component_name, port_name, port in self._ports
}
connected = self.connected_enthalpies()
self._refresh_stream_components(connected)
deltas = [
abs(port.h_outflow - previous[(component.name, port_name)])
for component in self.network.components.values()
for port_name, port in component.ports.items()
abs(port.h_outflow - previous[(component_name, port_name)])
for component_name, port_name, port in self._ports
]
magnitudes = [
abs(port.h_outflow)
for component in self.network.components.values()
for port in component.ports.values()
for _component_name, _port_name, port in self._ports
]
max_delta = max(deltas, default=0.0)
scale = max(magnitudes + [1.0])