Fixed signal tree and added progress bar in besim
This commit is contained in:
@@ -15,6 +15,14 @@ from bedit_gui.views.simulation_window import SimulationWindow
|
|||||||
logger = get_logger(__name__)
|
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):
|
class SimulationPlotController(QObject):
|
||||||
def __init__(self, window: SimulationWindow, files: SimulationFileController) -> None:
|
def __init__(self, window: SimulationWindow, files: SimulationFileController) -> None:
|
||||||
super().__init__(window)
|
super().__init__(window)
|
||||||
@@ -129,7 +137,7 @@ class SimulationPlotController(QObject):
|
|||||||
nodes: dict[tuple[str, ...], QTreeWidgetItem] = {}
|
nodes: dict[tuple[str, ...], QTreeWidgetItem] = {}
|
||||||
for signal in signals:
|
for signal in signals:
|
||||||
parent = tree.invisibleRootItem()
|
parent = tree.invisibleRootItem()
|
||||||
parts = signal.split(".")
|
parts = _signal_tree_parts(signal)
|
||||||
for depth, part in enumerate(parts, start=1):
|
for depth, part in enumerate(parts, start=1):
|
||||||
path = tuple(parts[:depth])
|
path = tuple(parts[:depth])
|
||||||
item = nodes.get(path)
|
item = nodes.get(path)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class SimulationRunController(QObject):
|
|||||||
run_completed = Signal(object)
|
run_completed = Signal(object)
|
||||||
run_cancelled = Signal()
|
run_cancelled = Signal()
|
||||||
run_failed = Signal(object)
|
run_failed = Signal(object)
|
||||||
|
run_progress = Signal(int)
|
||||||
simulation_state_changed = Signal()
|
simulation_state_changed = Signal()
|
||||||
|
|
||||||
def __init__(self, window: SimulationWindow, files: SimulationFileController, session_factory: SessionFactory = _create_session) -> None:
|
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.session: SimulationSession | None = None
|
||||||
self._running = False
|
self._running = False
|
||||||
self._reset_pending = False
|
self._reset_pending = False
|
||||||
|
self.window.ui.progressBar.setValue(0)
|
||||||
|
|
||||||
window.ui.actionRun_Simulation.triggered.connect(self.start)
|
window.ui.actionRun_Simulation.triggered.connect(self.start)
|
||||||
window.ui.actionStop_Simulation.triggered.connect(self.stop)
|
window.ui.actionStop_Simulation.triggered.connect(self.stop)
|
||||||
@@ -42,6 +44,7 @@ class SimulationRunController(QObject):
|
|||||||
self.run_completed.connect(self._completed)
|
self.run_completed.connect(self._completed)
|
||||||
self.run_cancelled.connect(self._cancelled)
|
self.run_cancelled.connect(self._cancelled)
|
||||||
self.run_failed.connect(self._failed)
|
self.run_failed.connect(self._failed)
|
||||||
|
self.run_progress.connect(self.window.ui.progressBar.setValue)
|
||||||
self._load_session()
|
self._load_session()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -54,6 +57,7 @@ class SimulationRunController(QObject):
|
|||||||
start_time = self.session.settings.start_time
|
start_time = self.session.settings.start_time
|
||||||
stop_time = self.session.current_end_time + self.session.settings.duration
|
stop_time = self.session.current_end_time + self.session.settings.duration
|
||||||
self._running = True
|
self._running = True
|
||||||
|
self.window.ui.progressBar.setValue(0)
|
||||||
self._update_actions()
|
self._update_actions()
|
||||||
logger.info("Starting simulation from %s to %s", start_time, stop_time)
|
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()
|
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:
|
if self.session is None:
|
||||||
return
|
return
|
||||||
self.session.reset()
|
self.session.reset()
|
||||||
|
self.window.ui.progressBar.setValue(0)
|
||||||
self._store_session_state()
|
self._store_session_state()
|
||||||
logger.info("Reset simulation to start time %s", self.session.current_end_time)
|
logger.info("Reset simulation to start time %s", self.session.current_end_time)
|
||||||
self._update_actions()
|
self._update_actions()
|
||||||
|
|
||||||
def _run_worker(self, session: SimulationSession) -> None:
|
def _run_worker(self, session: SimulationSession) -> None:
|
||||||
try:
|
try:
|
||||||
result = asyncio.run(session.run_next())
|
result = asyncio.run(self._run_with_progress(session))
|
||||||
except SimulationCancelledError:
|
except SimulationCancelledError:
|
||||||
self.run_cancelled.emit()
|
self.run_cancelled.emit()
|
||||||
except (OSError, RuntimeError, TypeError, ValueError) as exc:
|
except (OSError, RuntimeError, TypeError, ValueError) as exc:
|
||||||
@@ -92,9 +97,21 @@ class SimulationRunController(QObject):
|
|||||||
else:
|
else:
|
||||||
self.run_completed.emit(result)
|
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:
|
def _completed(self, result: SimulationResult) -> None:
|
||||||
self._running = False
|
self._running = False
|
||||||
self._store_session_state()
|
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")
|
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():
|
if result.process_output.strip():
|
||||||
logger.info("Simulation output:\n%s", 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
|
root = self.files.root
|
||||||
compiled = self.files.compiled_model
|
compiled = self.files.compiled_model
|
||||||
self._reset_pending = False
|
self._reset_pending = False
|
||||||
|
self.window.ui.progressBar.setValue(0)
|
||||||
if root is None or compiled is None:
|
if root is None or compiled is None:
|
||||||
self.session = None
|
self.session = None
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -27,6 +27,13 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progressBar">
|
||||||
|
<property name="value">
|
||||||
|
<number>24</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenuBar" name="menubar">
|
<widget class="QMenuBar" name="menubar">
|
||||||
@@ -35,7 +42,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>800</width>
|
||||||
<height>22</height>
|
<height>19</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ class SimulationSession:
|
|||||||
def is_running(self) -> bool:
|
def is_running(self) -> bool:
|
||||||
return self._simulation.is_running
|
return self._simulation.is_running
|
||||||
|
|
||||||
|
def get_progress(self) -> int:
|
||||||
|
return self._simulation.get_progress()
|
||||||
|
|
||||||
async def run_next(self) -> SimulationResult:
|
async def run_next(self) -> SimulationResult:
|
||||||
start_time = self.settings.start_time
|
start_time = self.settings.start_time
|
||||||
stop_time = self.current_end_time + self.settings.duration
|
stop_time = self.current_end_time + self.settings.duration
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"file_format_version": 1,
|
"file_format_version": 1,
|
||||||
"root_type": "simulation_root",
|
"root_type": "simulation_root",
|
||||||
"format_version": 1,
|
"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",
|
"source_document_id": "3b6780c7-488b-471e-a784-392db7632090",
|
||||||
"component": "50e6ef97-f686-4400-bc01-e5a352e8cc22",
|
"component": "50e6ef97-f686-4400-bc01-e5a352e8cc22",
|
||||||
"component_path": "some_bondgraph",
|
"component_path": "some_bondgraph",
|
||||||
|
|||||||
Reference in New Issue
Block a user