"""Backend-neutral simulation result and preparation error contracts.""" from __future__ import annotations from dataclasses import dataclass from typing import TYPE_CHECKING, Literal if TYPE_CHECKING: from app.simulation.native_codegen.transport import NativeSeriesJson from app.simulation.core.metadata import ResultVariableMetadata SimulationRunStatus = Literal["completed", "cancelled", "failed"] @dataclass(frozen=True) class SimulationPreparationIssue: code: str message: str def as_dict(self) -> dict[str, str]: return {"code": self.code, "message": self.message} class SimulationPreparationError(ValueError): def __init__(self, issues: tuple[SimulationPreparationIssue, ...]) -> None: super().__init__("The compiled model is not ready for simulation.") self.issues = issues @dataclass(frozen=True) class GenericSimulationResult: success: bool status: SimulationRunStatus message: str simulated_until: float requested_stop_time: float variables: tuple[ResultVariableMetadata, ...] series: dict[str, list[float]] | NativeSeriesJson final: dict[str, float] diagnostics: dict[str, object] def as_dict(self, *, raw_series: bool = False) -> dict[str, object]: from app.simulation.native_codegen.transport import NativeSeriesJson series = self.series if isinstance(series, NativeSeriesJson) and not raw_series: series = series.materialize() return { "success": self.success, "status": self.status, "partial": self.status != "completed", "message": self.message, "simulatedUntil": self.simulated_until, "requestedStopTime": self.requested_stop_time, "variables": [variable.as_dict() for variable in self.variables], "series": series, "final": self.final, "diagnostics": self.diagnostics, }