完善AMESim组件界面与仿真求解稳定性

This commit is contained in:
ljz committed 2026-08-02 00:57:48 +08:00
1 parent e7177ab03e
commit 410ef535e8
34 files changed
+3340 -251

No files matched your search

+47
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
from dataclasses import dataclass
from math import isfinite
from typing import Protocol
from app.simulation.systems.network import Endpoint, SimulationNetwork
@@ -13,6 +14,21 @@ class SignalOutputComponent(Protocol):
...
class SignalEventSource(Protocol):
"""Optional contract for signal sources with known time discontinuities."""
name: str
def signal_event_times(
self,
start_time: float,
stop_time: float,
) -> tuple[float, ...]:
"""Return event times strictly inside ``(start_time, stop_time)``."""
...
@dataclass(frozen=True)
class SignalSolveDiagnostics:
propagated: int
@@ -51,6 +67,37 @@ class SignalResolver:
self.last_diagnostics = diagnostics
return diagnostics
def event_times(self, start_time: float, stop_time: float) -> tuple[float, ...]:
"""Collect optional source events that can be used as integration splits.
Event discovery is deliberately duck typed so existing signal-output
components remain valid without implementing ``signal_event_times``.
"""
start = float(start_time)
stop = float(stop_time)
if not isfinite(start) or not isfinite(stop):
raise ValueError("Signal event interval must be finite.")
if stop < start:
raise ValueError("Signal event interval stop must not precede start.")
if stop == start:
return ()
events: set[float] = set()
for component in self.network.components.values():
source_event_times = getattr(component, "signal_event_times", None)
if source_event_times is None:
continue
for raw_time in source_event_times(start, stop):
event_time = float(raw_time)
if not isfinite(event_time):
raise ValueError(
f"Signal event time from component '{component.name}' must be finite."
)
if start < event_time < stop:
events.add(event_time)
return tuple(sorted(events))
def _source_target(self, endpoints: tuple[Endpoint, Endpoint]) -> tuple[Endpoint, Endpoint]:
first, second = endpoints
first_port = self.network.components[first.component].get_port(first.port)