完善 drawio 建模界面与仿真模型集成
This commit is contained in:
1 parent
d6ef842c59
commit
713b32c1b4
28 files changed
+5966
-103
No files matched your search
@@ -0,0 +1,219 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
|
||||
from PythonModels.reporting import (
|
||||
COMPARISON_KEYS,
|
||||
PRIMARY_KEYS,
|
||||
TestModelArtifacts,
|
||||
export_testmodel_artifacts,
|
||||
format_testmodel_run_report,
|
||||
load_modelica_series,
|
||||
write_testmodel_run_report,
|
||||
)
|
||||
from PythonModels.core.solver import SolveIVPConfig
|
||||
from PythonModels.systems.testmodel import (
|
||||
InitializationDiagnostics,
|
||||
TestModelConfig,
|
||||
TestModelSystem,
|
||||
)
|
||||
from PythonModels.systems.testmodel_closure import TestModelSolveDiagnostics
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TestModelSamplingConfig:
|
||||
step: float = 0.1
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TestModelPathConfig:
|
||||
output_dir: Path | None = None
|
||||
modelica_result_path: Path | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TestModelExecutionConfig:
|
||||
use_modelica_reference_if_available: bool = True
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TestModelRunConfig:
|
||||
model: TestModelConfig = field(default_factory=TestModelConfig)
|
||||
solver: SolveIVPConfig = field(default_factory=SolveIVPConfig)
|
||||
sampling: TestModelSamplingConfig = field(default_factory=TestModelSamplingConfig)
|
||||
paths: TestModelPathConfig = field(default_factory=TestModelPathConfig)
|
||||
execution: TestModelExecutionConfig = field(default_factory=TestModelExecutionConfig)
|
||||
|
||||
@property
|
||||
def sample_step(self) -> float:
|
||||
return self.sampling.step
|
||||
|
||||
def sample_times(self) -> list[float]:
|
||||
return _sample_times(
|
||||
self.solver.t_start,
|
||||
self.solver.t_stop,
|
||||
step=self.sampling.step,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PreparedTestModelRun:
|
||||
run_config: TestModelRunConfig
|
||||
repo_root: Path
|
||||
output_dir: Path
|
||||
modelica_result_path: Path
|
||||
t_eval: tuple[float, ...]
|
||||
use_modelica_reference_if_available: bool
|
||||
modelica_reference_exists: bool
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TestModelRunResult:
|
||||
run_config: TestModelRunConfig
|
||||
prepared_run: PreparedTestModelRun
|
||||
system: TestModelSystem
|
||||
initialization: InitializationDiagnostics
|
||||
raw_initial_state: tuple[float, ...]
|
||||
consistent_initial_state: tuple[float, ...]
|
||||
solution: object
|
||||
series: dict[str, list[float]]
|
||||
solve_diagnostics: TestModelSolveDiagnostics | None
|
||||
artifacts: TestModelArtifacts
|
||||
comparison_summary: dict[str, tuple[float, float]] | None
|
||||
used_modelica_reference: bool
|
||||
|
||||
|
||||
def _sample_times(t_start: float, t_stop: float, step: float) -> list[float]:
|
||||
point_count = int(round((t_stop - t_start) / step))
|
||||
return [t_start + index * step for index in range(point_count + 1)]
|
||||
|
||||
|
||||
def _default_run_output_dir(pythonmodels_root: Path) -> Path:
|
||||
timestamp = datetime.now(UTC).strftime("testmodel_%Y%m%d_%H%M%S_%f")
|
||||
return pythonmodels_root / "runs" / timestamp
|
||||
|
||||
|
||||
def prepare_testmodel_run(
|
||||
*,
|
||||
run_config: TestModelRunConfig | None = None,
|
||||
output_dir: Path | None = None,
|
||||
modelica_result_path: Path | None = None,
|
||||
) -> PreparedTestModelRun:
|
||||
run_config = run_config or TestModelRunConfig()
|
||||
repo_root = Path(__file__).resolve().parents[2]
|
||||
pythonmodels_root = Path(__file__).resolve().parents[1]
|
||||
resolved_output_dir = (
|
||||
output_dir
|
||||
or run_config.paths.output_dir
|
||||
or _default_run_output_dir(pythonmodels_root)
|
||||
)
|
||||
resolved_modelica_result_path = (
|
||||
modelica_result_path
|
||||
or run_config.paths.modelica_result_path
|
||||
or repo_root / "ModelicaModels" / "Simulation" / "Testmodel_res.csv"
|
||||
)
|
||||
t_eval = tuple(run_config.sample_times())
|
||||
return PreparedTestModelRun(
|
||||
run_config=run_config,
|
||||
repo_root=repo_root,
|
||||
output_dir=resolved_output_dir,
|
||||
modelica_result_path=resolved_modelica_result_path,
|
||||
t_eval=t_eval,
|
||||
use_modelica_reference_if_available=run_config.execution.use_modelica_reference_if_available,
|
||||
modelica_reference_exists=resolved_modelica_result_path.exists(),
|
||||
)
|
||||
|
||||
|
||||
def run_prepared_testmodel(prepared_run: PreparedTestModelRun) -> TestModelRunResult:
|
||||
run_config = prepared_run.run_config
|
||||
system = TestModelSystem(config=run_config.model)
|
||||
raw_initial_state = tuple(system.initial_state_vector())
|
||||
initialization = system.initialize_consistent_state()
|
||||
consistent_initial_state = tuple(initialization.state_vector)
|
||||
solution = system.simulate(config=run_config.solver, t_eval=list(prepared_run.t_eval))
|
||||
series = system.evaluate_solution(solution)
|
||||
solve_diagnostics = system.last_solve_diagnostics
|
||||
|
||||
modelica_series = None
|
||||
used_modelica_reference = False
|
||||
if (
|
||||
prepared_run.use_modelica_reference_if_available
|
||||
and prepared_run.modelica_reference_exists
|
||||
):
|
||||
modelica_series = load_modelica_series(
|
||||
prepared_run.modelica_result_path,
|
||||
COMPARISON_KEYS,
|
||||
)
|
||||
used_modelica_reference = True
|
||||
|
||||
artifacts, comparison_summary = export_testmodel_artifacts(
|
||||
output_dir=prepared_run.output_dir,
|
||||
series=series,
|
||||
modelica_series=modelica_series,
|
||||
)
|
||||
report_text = format_testmodel_run_report(
|
||||
network_summary=system.network.summary(),
|
||||
initialization=initialization,
|
||||
raw_initial_state=raw_initial_state,
|
||||
consistent_initial_state=consistent_initial_state,
|
||||
solution=solution,
|
||||
series=series,
|
||||
solve_diagnostics=solve_diagnostics,
|
||||
artifacts=artifacts,
|
||||
comparison_summary=comparison_summary,
|
||||
)
|
||||
write_testmodel_run_report(prepared_run.output_dir, report_text)
|
||||
|
||||
return TestModelRunResult(
|
||||
run_config=run_config,
|
||||
prepared_run=prepared_run,
|
||||
system=system,
|
||||
initialization=initialization,
|
||||
raw_initial_state=raw_initial_state,
|
||||
consistent_initial_state=consistent_initial_state,
|
||||
solution=solution,
|
||||
series=series,
|
||||
solve_diagnostics=solve_diagnostics,
|
||||
artifacts=artifacts,
|
||||
comparison_summary=comparison_summary,
|
||||
used_modelica_reference=used_modelica_reference,
|
||||
)
|
||||
|
||||
|
||||
def run_testmodel(
|
||||
*,
|
||||
run_config: TestModelRunConfig | None = None,
|
||||
output_dir: Path | None = None,
|
||||
modelica_result_path: Path | None = None,
|
||||
) -> TestModelRunResult:
|
||||
prepared_run = prepare_testmodel_run(
|
||||
run_config=run_config,
|
||||
output_dir=output_dir,
|
||||
modelica_result_path=modelica_result_path,
|
||||
)
|
||||
return run_prepared_testmodel(prepared_run)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
run_config = TestModelRunConfig()
|
||||
result = run_testmodel(run_config=run_config)
|
||||
print(
|
||||
format_testmodel_run_report(
|
||||
network_summary=result.system.network.summary(),
|
||||
initialization=result.initialization,
|
||||
raw_initial_state=result.raw_initial_state,
|
||||
consistent_initial_state=result.consistent_initial_state,
|
||||
solution=result.solution,
|
||||
series=result.series,
|
||||
solve_diagnostics=result.solve_diagnostics,
|
||||
artifacts=result.artifacts,
|
||||
comparison_summary=result.comparison_summary,
|
||||
),
|
||||
end="",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user