From 961a173a17f58e756defc195241051a1aca5ba2f Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Sun, 2 Aug 2026 18:51:33 +0200 Subject: [PATCH] Fixed signal tree and added progress bar in besim --- .../controllers/simulation_plot_controller.py | 10 +++++++++- .../controllers/simulation_run_controller.py | 20 ++++++++++++++++++- src/bedit_gui/ui/forms/simulation_window.ui | 9 ++++++++- src/bedit_simulation/runtime.py | 3 +++ untitled.besim.json | 2 +- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/bedit_gui/controllers/simulation_plot_controller.py b/src/bedit_gui/controllers/simulation_plot_controller.py index 6c7b458..f39103c 100644 --- a/src/bedit_gui/controllers/simulation_plot_controller.py +++ b/src/bedit_gui/controllers/simulation_plot_controller.py @@ -15,6 +15,14 @@ from bedit_gui.views.simulation_window import SimulationWindow logger = get_logger(__name__) +def _signal_tree_parts(signal: str) -> list[str]: + if signal.startswith("der(") and signal.endswith(")"): + parts = signal[4:-1].split(".") + if len(parts) > 1: + return [*parts[:-1], f"der({parts[-1]})"] + return signal.split(".") + + class SimulationPlotController(QObject): def __init__(self, window: SimulationWindow, files: SimulationFileController) -> None: super().__init__(window) @@ -129,7 +137,7 @@ class SimulationPlotController(QObject): nodes: dict[tuple[str, ...], QTreeWidgetItem] = {} for signal in signals: parent = tree.invisibleRootItem() - parts = signal.split(".") + parts = _signal_tree_parts(signal) for depth, part in enumerate(parts, start=1): path = tuple(parts[:depth]) item = nodes.get(path) diff --git a/src/bedit_gui/controllers/simulation_run_controller.py b/src/bedit_gui/controllers/simulation_run_controller.py index f1d4bac..27e5f47 100644 --- a/src/bedit_gui/controllers/simulation_run_controller.py +++ b/src/bedit_gui/controllers/simulation_run_controller.py @@ -24,6 +24,7 @@ class SimulationRunController(QObject): run_completed = Signal(object) run_cancelled = Signal() run_failed = Signal(object) + run_progress = Signal(int) simulation_state_changed = Signal() def __init__(self, window: SimulationWindow, files: SimulationFileController, session_factory: SessionFactory = _create_session) -> None: @@ -34,6 +35,7 @@ class SimulationRunController(QObject): self.session: SimulationSession | None = None self._running = False self._reset_pending = False + self.window.ui.progressBar.setValue(0) window.ui.actionRun_Simulation.triggered.connect(self.start) window.ui.actionStop_Simulation.triggered.connect(self.stop) @@ -42,6 +44,7 @@ class SimulationRunController(QObject): self.run_completed.connect(self._completed) self.run_cancelled.connect(self._cancelled) self.run_failed.connect(self._failed) + self.run_progress.connect(self.window.ui.progressBar.setValue) self._load_session() @property @@ -54,6 +57,7 @@ class SimulationRunController(QObject): start_time = self.session.settings.start_time stop_time = self.session.current_end_time + self.session.settings.duration self._running = True + self.window.ui.progressBar.setValue(0) self._update_actions() logger.info("Starting simulation from %s to %s", start_time, stop_time) Thread(target=self._run_worker, args=(self.session,), name="besim-run", daemon=True).start() @@ -78,13 +82,14 @@ class SimulationRunController(QObject): if self.session is None: return self.session.reset() + self.window.ui.progressBar.setValue(0) self._store_session_state() logger.info("Reset simulation to start time %s", self.session.current_end_time) self._update_actions() def _run_worker(self, session: SimulationSession) -> None: try: - result = asyncio.run(session.run_next()) + result = asyncio.run(self._run_with_progress(session)) except SimulationCancelledError: self.run_cancelled.emit() except (OSError, RuntimeError, TypeError, ValueError) as exc: @@ -92,9 +97,21 @@ class SimulationRunController(QObject): else: self.run_completed.emit(result) + async def _run_with_progress(self, session: SimulationSession) -> SimulationResult: + task = asyncio.create_task(session.run_next()) + last_progress = -1 + while not task.done(): + progress = min(session.get_progress(), 99) + if progress != last_progress: + self.run_progress.emit(progress) + last_progress = progress + await asyncio.sleep(0.1) + return await task + def _completed(self, result: SimulationResult) -> None: self._running = False self._store_session_state() + self.window.ui.progressBar.setValue(100) logger.info("Simulation completed at time %s", self.session.current_end_time if self.session is not None else "unknown") if result.process_output.strip(): logger.info("Simulation output:\n%s", result.process_output.strip()) @@ -122,6 +139,7 @@ class SimulationRunController(QObject): root = self.files.root compiled = self.files.compiled_model self._reset_pending = False + self.window.ui.progressBar.setValue(0) if root is None or compiled is None: self.session = None else: diff --git a/src/bedit_gui/ui/forms/simulation_window.ui b/src/bedit_gui/ui/forms/simulation_window.ui index c3d0eed..1f9aed3 100644 --- a/src/bedit_gui/ui/forms/simulation_window.ui +++ b/src/bedit_gui/ui/forms/simulation_window.ui @@ -27,6 +27,13 @@ + + + + 24 + + + @@ -35,7 +42,7 @@ 0 0 800 - 22 + 19 diff --git a/src/bedit_simulation/runtime.py b/src/bedit_simulation/runtime.py index 7633828..22addf4 100644 --- a/src/bedit_simulation/runtime.py +++ b/src/bedit_simulation/runtime.py @@ -45,6 +45,9 @@ class SimulationSession: def is_running(self) -> bool: return self._simulation.is_running + def get_progress(self) -> int: + return self._simulation.get_progress() + async def run_next(self) -> SimulationResult: start_time = self.settings.start_time stop_time = self.current_end_time + self.settings.duration diff --git a/untitled.besim.json b/untitled.besim.json index 6e17c94..d364d2f 100644 --- a/untitled.besim.json +++ b/untitled.besim.json @@ -2,7 +2,7 @@ "file_format_version": 1, "root_type": "simulation_root", "format_version": 1, - "source_document": "/home/joppe/Projects/BEdit/untitled.bedit.json", + "source_document": "untitled.bedit.json", "source_document_id": "3b6780c7-488b-471e-a784-392db7632090", "component": "50e6ef97-f686-4400-bc01-e5a352e8cc22", "component_path": "some_bondgraph",