From d16371d4c8a03ac680152d3c7043461a3218f092 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson <oscar.gustafsson@gmail.com> Date: Fri, 7 Apr 2023 17:14:32 +0200 Subject: [PATCH] Do simulation in separate thread --- b_asic/GUI/main_window.py | 42 ++++++++++++++++----------------- b_asic/GUI/simulation_worker.py | 21 +++++++++++++++++ b_asic/gui_utils/plot_window.py | 7 +++--- test/test_gui.py | 4 ++-- 4 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 b_asic/GUI/simulation_worker.py diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py index 698dc612..f4a39e06 100644 --- a/b_asic/GUI/main_window.py +++ b/b_asic/GUI/main_window.py @@ -12,7 +12,7 @@ from collections import deque from pprint import pprint from typing import Dict, List, Optional, Tuple, cast -from qtpy.QtCore import QCoreApplication, QFileInfo, QSettings, QSize, Qt +from qtpy.QtCore import QCoreApplication, QFileInfo, QSettings, QSize, Qt, QThread from qtpy.QtGui import QCursor, QIcon, QKeySequence, QPainter from qtpy.QtWidgets import ( QAction, @@ -39,9 +39,8 @@ from b_asic.GUI.gui_interface import Ui_main_window from b_asic.GUI.port_button import PortButton from b_asic.GUI.select_sfg_window import SelectSFGWindow from b_asic.GUI.show_pc_window import ShowPCWindow - -# from b_asic.GUI.simulate_sfg_window import Plot, SimulateSFGWindow from b_asic.GUI.simulate_sfg_window import SimulateSFGWindow +from b_asic.GUI.simulation_worker import SimulationWorker from b_asic.GUI.util_dialogs import FaqWindow, KeybindingsWindow from b_asic.gui_utils.about_window import AboutWindow from b_asic.gui_utils.decorators import decorate_class, handle_error @@ -51,9 +50,7 @@ from b_asic.port import InputPort, OutputPort from b_asic.save_load_structure import python_to_sfg, sfg_to_python from b_asic.signal import Signal from b_asic.signal_flow_graph import SFG - -# from b_asic import FastSimulation -from b_asic.simulation import Simulation as FastSimulation +from b_asic.simulation import Simulation from b_asic.special_operations import Input, Output logging.basicConfig(level=logging.INFO) @@ -89,6 +86,7 @@ class MainWindow(QMainWindow): self.sfg_dict = {} self._window = self self.logger = logging.getLogger(__name__) + self._plot: Dict[Simulation, PlotWindow] = dict() # Create Graphics View self.graphic_view = QGraphicsView(self.scene, self) @@ -237,7 +235,6 @@ class MainWindow(QMainWindow): module, accepted = QFileDialog().getOpenFileName() if not accepted: return - self.addRecentFile(module) self._load_from_file(module) def _load_from_file(self, module) -> None: @@ -250,6 +247,8 @@ class MainWindow(QMainWindow): ) return + self.addRecentFile(module) + while sfg.name in self.sfg_dict: self.logger.warning( f"Duplicate SFG with name: {sfg.name} detected. " @@ -741,22 +740,23 @@ class MainWindow(QMainWindow): self.pressed_operations = selected def _simulate_sfg(self) -> None: + self._thread = dict() + self._sim_worker = dict() for sfg, properties in self._simulation_dialog.properties.items(): self.logger.info("Simulating SFG with name: %s" % str(sfg.name)) - simulation = FastSimulation(sfg, input_providers=properties["input_values"]) - l_result = simulation.run_for( - properties["iteration_count"], - save_results=properties["all_results"], - ) - - print(f"{'=' * 10} {sfg.name} {'=' * 10}") - pprint(simulation.results if properties["all_results"] else l_result) - print(f"{'=' * 10} /{sfg.name} {'=' * 10}") - - if properties["show_plot"]: - self.logger.info("Opening plot for SFG with name: " + str(sfg.name)) - self._plot = PlotWindow(simulation.results, sfg_name=sfg.name) - self._plot.show() + self._sim_worker[sfg] = SimulationWorker(sfg, properties) + self._thread[sfg] = QThread() + self._sim_worker[sfg].moveToThread(self._thread[sfg]) + self._thread[sfg].started.connect(self._sim_worker[sfg].start_simulation) + self._sim_worker[sfg].finished.connect(self._thread[sfg].quit) + self._sim_worker[sfg].finished.connect(self._show_plot_window) + self._sim_worker[sfg].finished.connect(self._sim_worker[sfg].deleteLater) + self._thread[sfg].finished.connect(self._thread[sfg].deleteLater) + self._thread[sfg].start() + + def _show_plot_window(self, sim: Simulation): + self._plot[sim] = PlotWindow(sim.results, sfg_name=sim._sfg.name) + self._plot[sim].show() def simulate_sfg(self, event=None) -> None: self._simulation_dialog = SimulateSFGWindow(self) diff --git a/b_asic/GUI/simulation_worker.py b/b_asic/GUI/simulation_worker.py new file mode 100644 index 00000000..6411a791 --- /dev/null +++ b/b_asic/GUI/simulation_worker.py @@ -0,0 +1,21 @@ +from qtpy.QtCore import QObject, Signal + +from b_asic.signal_flow_graph import SFG +from b_asic.simulation import Simulation + + +class SimulationWorker(QObject): + finished = Signal(Simulation) + + def __init__(self, sfg: SFG, properties): + super().__init__() + self._sfg = sfg + self._props = properties + + def start_simulation(self): + simulation = Simulation(self._sfg, input_providers=self._props["input_values"]) + simulation.run_for( + self._props["iteration_count"], + save_results=self._props["all_results"], + ) + self.finished.emit(simulation) diff --git a/b_asic/gui_utils/plot_window.py b/b_asic/gui_utils/plot_window.py index 7aec9c35..e2d5dcf1 100644 --- a/b_asic/gui_utils/plot_window.py +++ b/b_asic/gui_utils/plot_window.py @@ -12,20 +12,20 @@ from qtpy.QtCore import Qt from qtpy.QtWidgets import ( # QFrame,; QScrollArea,; QLineEdit,; QSizePolicy,; QLabel,; QFileDialog,; QShortcut, QApplication, QCheckBox, - QDialog, QHBoxLayout, QListWidget, QListWidgetItem, QPushButton, QSizePolicy, QVBoxLayout, + QWidget, ) from b_asic.operation import ResultKey from b_asic.types import Num -class PlotWindow(QDialog): +class PlotWindow(QWidget): """ Dialog for plotting the result of a simulation. @@ -43,9 +43,8 @@ class PlotWindow(QDialog): self, sim_result: Mapping[ResultKey, Sequence[Num]], sfg_name: Optional[str] = None, - parent=None, ): - super().__init__(parent=parent) + super().__init__() self.setWindowFlags( Qt.WindowTitleHint | Qt.WindowCloseButtonHint diff --git a/test/test_gui.py b/test/test_gui.py index 1feca3c6..0e1af8bb 100644 --- a/test/test_gui.py +++ b/test/test_gui.py @@ -157,8 +157,8 @@ def test_simulate(qtbot, datadir): assert 'twotapfir' in widget.sfg_dict widget.simulate_sfg() qtbot.wait(100) - # widget.dialog.save_properties() - # qtbot.wait(100) + widget._simulation_dialog.save_properties() + qtbot.wait(100) widget._simulation_dialog.close() widget.exit_app() -- GitLab