Пример #1
0
    def __init__(self,
                 system,
                 database,
                 min1=None,
                 min2=None,
                 parent=None,
                 app=None):
        QtGui.QMainWindow.__init__(self, parent=parent)
        self.ui = UI()
        self.ui.setupUi(self)
        self.ui.centralwidget.hide()

        self.app = app
        self.system = system
        self.database = database

        self.ogl = self.ui.ogl
        self.ogl.setSystem(system)

        self.textEdit = self.ui.textEdit
        self.textEdit.setReadOnly(True)
        self.textEdit_writer = OutLog(self.textEdit)
        self.view_log = self.ui.view_Log
        self.ui.actionLog.setChecked(True)

        if min1 is not None and min2 is not None:
            self.decrunner = DECRunner(system,
                                       database,
                                       min1,
                                       min2,
                                       outstream=self.textEdit_writer)
            self.decrunner.on_finished.connect(self.on_finished)

        self.view_3D = self.ui.view_ogl
        self.ui.action3D.setChecked(True)

        self.wgt_energies = ConnectEnergyWidget(parent=self)
        self.view_energies = self.new_view("Energies", self.wgt_energies,
                                           QtCore.Qt.TopDockWidgetArea)
        self.ui.actionEnergy.setChecked(True)

        self.wgt_graphview = GraphViewWidget(database=self.database,
                                             parent=self,
                                             app=app)
        self.view_graphview = self.new_view("Graph View", self.wgt_graphview,
                                            QtCore.Qt.TopDockWidgetArea)
        self.view_graphview.hide()
        self.ui.actionGraph.setChecked(False)

        self.ui.actionPause.setVisible(False)
        self.ui.actionD_Graph.setVisible(False)
        self.ui.actionSummary.setVisible(False)
        self.ui.actionSummary.setChecked(False)
        self.ui.actionRandom_connect.setChecked(False)
        self.ui.actionRandom_connect.setVisible(False)

        self.smoothed_path = None
Пример #2
0
 def do_one_connection(self, min1, min2):
     self.textEdit.insertPlainText("\n\n")
     self.textEdit_summary.insertPlainText(
         "\nNow connecting minima %d %d\n" % (self.min1._id, self.min2._id))
     self.decrunner = DECRunner(self.system,
                                self.database,
                                min1,
                                min2,
                                outstream=self.textEdit_writer,
                                return_smoothed_path=True)
     self.decrunner.on_finished.connect(self.on_finished)
     self.tstart = time.clock()
     self.decrunner.start()
Пример #3
0
 def do_one_connection(self, min1, min2):
     self.textEdit.insertPlainText("\n\n")
     self.textEdit_summary.insertPlainText("\nNow connecting minima %d %d\n" % (self.min1._id, self.min2._id))
     self.decrunner = DECRunner(self.system, self.database, min1, min2, outstream=self.textEdit_writer,
                                return_smoothed_path=True)
     self.decrunner.on_finished.connect(self.on_finished)
     self.tstart = time.clock()
     self.decrunner.start()
Пример #4
0
    def __init__(self, system, database, min1=None, min2=None, parent=None, app=None):
        QtGui.QMainWindow.__init__(self, parent=parent)    
        self.ui = UI()
        self.ui.setupUi(self)
        self.ui.centralwidget.hide()
        
        self.app = app
        self.system = system
        self.database = database
        
        self.ogl = self.ui.ogl
        self.ogl.setSystem(system)

        
        self.textEdit = self.ui.textEdit      
        self.textEdit.setReadOnly(True)
        self.textEdit_writer = OutLog(self.textEdit)
        self.view_log = self.ui.view_Log
        self.ui.actionLog.setChecked(True)
        
        if min1 is not None and min2 is not None:
            self.decrunner = DECRunner(system, database, min1, min2, outstream=self.textEdit_writer)
            self.decrunner.on_finished.connect(self.on_finished)

        self.view_3D = self.ui.view_ogl
        self.ui.action3D.setChecked(True)
        
        self.wgt_energies = ConnectEnergyWidget(parent=self)
        self.view_energies = self.new_view("Energies", self.wgt_energies, QtCore.Qt.TopDockWidgetArea)
        self.ui.actionEnergy.setChecked(True)

        self.wgt_graphview = GraphViewWidget(database=self.database, parent=self, app=app)
        self.view_graphview = self.new_view("Graph View", self.wgt_graphview, QtCore.Qt.TopDockWidgetArea)
        self.view_graphview.hide()
        self.ui.actionGraph.setChecked(False)
        
        self.ui.actionPause.setVisible(False)
        self.ui.actionD_Graph.setVisible(False)
        self.ui.actionSummary.setVisible(False)
        self.ui.actionSummary.setChecked(False)
        self.ui.actionRandom_connect.setChecked(False)
        self.ui.actionRandom_connect.setVisible(False)
        
        self.smoothed_path = None
Пример #5
0
class ConnectAllDialog(ConnectViewer):
    def __init__(self, system, database, parent=None, app=None):
        super(ConnectAllDialog, self).__init__(system,
                                               database,
                                               app=app,
                                               parent=parent)

        self.wgt_dgraph = DGraphWidget(database=self.database, parent=self)
        self.view_dgraph = self.new_view("Disconnectivity Graph",
                                         self.wgt_dgraph,
                                         QtCore.Qt.TopDockWidgetArea)
        self.view_dgraph.hide()
        self.ui.actionD_Graph.setVisible(True)
        self.ui.actionD_Graph.setChecked(False)

        self.textEdit_summary = QtGui.QTextEdit(parent=self)
        self.textEdit_summary.setReadOnly(True)
        self.view_summary = self.new_view("Summary",
                                          self.textEdit_summary,
                                          pos=QtCore.Qt.TopDockWidgetArea)
        self.connect_summary = ConnectAllSummary()
        self.ui.actionSummary.setVisible(True)
        self.view_summary.hide()
        self.ui.actionSummary.setChecked(False)
        self.ui.actionRandom_connect.setVisible(True)
        self.ui.actionRandom_connect.setChecked(False)

        self.ui.action3D.setChecked(False)
        self.view_3D.hide()

        self.ui.actionEnergy.setChecked(False)
        self.view_energies.hide()

        self.ui.actionPause.setVisible(True)

        self.is_running = False

        self.failed_pairs = set()

    def do_one_connection(self, min1, min2):
        self.textEdit.insertPlainText("\n\n")
        self.textEdit_summary.insertPlainText(
            "\nNow connecting minima %d %d\n" % (self.min1._id, self.min2._id))
        self.decrunner = DECRunner(self.system,
                                   self.database,
                                   min1,
                                   min2,
                                   outstream=self.textEdit_writer,
                                   return_smoothed_path=True)
        self.decrunner.on_finished.connect(self.on_finished)
        self.tstart = time.clock()
        self.decrunner.start()

    def get_next_pair_gmin(self):
        minima = self.database.minima()
        min1 = minima[0]
        graph = TSGraph(self.database)
        all_connected = True
        for m2 in minima[1:]:
            if not graph.areConnected(min1, m2):
                if (min1, m2) in self.failed_pairs or (
                        m2, min1) in self.failed_pairs:
                    continue
                all_connected = False
                break
        if all_connected:
            print "minima are all connected, ending"
            self.textEdit_summary.insertPlainText(
                "minima are all connected, ending\n")
            return None, None
        return min1, m2

    def get_next_pair_random(self):
        ''' get a new connect job '''
        query = self.database.session.query(Minimum)
        #        if self.Emax is not None:
        #            query.filter(Minimum.energy < self.Emax)

        while True:
            min1 = query.order_by(sqlalchemy.func.random()).first()
            min2 = query.order_by(sqlalchemy.func.random()).first()
            if (min1, min2) not in self.failed_pairs and (
                    min2, min1) not in self.failed_pairs:
                return min1, min2

    def do_next_connect(self):
        self.is_running = True
        if self.ui.actionRandom_connect.isChecked():
            self.min1, self.min2 = self.get_next_pair_random()
        else:
            self.min1, self.min2 = self.get_next_pair_gmin()

        if self.min1 is None or self.min2 is None:
            self.is_running = False
            return
        self.do_one_connection(self.min1, self.min2)

    def start(self):
        self.do_next_connect()

    def update_energy_view(self):
        # plot the energies
        if self.view_energies.isVisible():
            self.wgt_energies.update_gui(self.S, self.energies)

    def update_graph_view(self):
        # show the graph view
        if self.view_graphview.isVisible():
            self.wgt_graphview.make_graph()
            self.wgt_graphview.show_graph()

    def update_3D_view(self):
        # show the smoothed path in the ogl viewer
        if self.view_3D.isVisible():
            self.ogl.setCoordsPath(self.smoothed_path)

    def update_dgraph_view(self):
        if self.view_dgraph.isVisible():
            self.wgt_dgraph.rebuild_disconnectivity_graph()

    def update_summary_view(self):
        self.textEdit_summary.clear()
        summary = self.connect_summary.get_summary()
        self.textEdit_summary.insertPlainText(summary)

    def on_finished(self):
        print "finished connecting", self.min1._id, "and", self.min2._id
        tend = time.clock()
        elapsed_time = tend - self.tstart
        #        print "\n"
        # add this run to the summary
        self.connect_summary.add(self.min1,
                                 self.min2,
                                 self.decrunner.success,
                                 self.decrunner.newminima,
                                 self.decrunner.newtransition_states,
                                 elapsed_time=elapsed_time)

        if not self.isVisible():
            self.is_running = False
            return
        if self.decrunner.success:
            # get the path data
            self.smoothed_path = np.array(self.decrunner.smoothed_path)
            self.S = np.array(self.decrunner.S)
            self.energies = np.array(self.decrunner.energies)
            #            print self.smoothed_path.shape

            self.update_3D_view()
            self.update_energy_view()
            self.update_graph_view()
            self.update_dgraph_view()
        else:
            print "connection run failed"
            #            summary "connection run failed"
            if not self.decrunner.killed_early:
                self.failed_pairs.add((self.min1, self.min2))

        self.update_summary_view()
        if self.ui.actionPause.isChecked():
            self.is_running = False
            return
        self.do_next_connect()

    def on_actionEnergy_toggled(self, checked):
        self.toggle_view(self.view_energies, checked)
        self.update_energy_view()

    def on_actionGraph_toggled(self, checked):
        self.toggle_view(self.view_graphview, checked)
        self.update_graph_view()

    def on_action3D_toggled(self, checked):
        self.toggle_view(self.view_3D, checked)
        self.update_3D_view()

    def on_actionD_Graph_toggled(self, checked):
        self.toggle_view(self.view_dgraph, checked)
        self.update_dgraph_view()

    def on_actionSummary_toggled(self, checked):
        self.toggle_view(self.view_summary, checked)

    def on_actionPause_toggled(self, checked):
        if checked is None: return
        if not checked:
            if not self.is_running:
                self.start()

    def on_actionKill_triggered(self, checked=None):
        if checked is None: return
        self.ui.actionPause.setChecked(True)
        self.is_running = False
        self.decrunner.terminate_early()
Пример #6
0
class ConnectViewer(QtGui.QMainWindow):
    """
    external viewer for connect runs
    
    This viewer will use DECRunner to run a connect job in parallel.
    The log messages from that run will be redirected into a GUI text viewer.
    When the run is finished, the completed path will be shown in an OGL viewer
    
    Parameters
    ----------
    system : 
    database :
    min1, min2 : Minimum objects
        the minima to try to connect
    parent : 
        the parent window
    app : 
        the application
    
    See Also
    --------
    DECRunner
    
    """
    def __init__(self,
                 system,
                 database,
                 min1=None,
                 min2=None,
                 parent=None,
                 app=None):
        QtGui.QMainWindow.__init__(self, parent=parent)
        self.ui = UI()
        self.ui.setupUi(self)
        self.ui.centralwidget.hide()

        self.app = app
        self.system = system
        self.database = database

        self.ogl = self.ui.ogl
        self.ogl.setSystem(system)

        self.textEdit = self.ui.textEdit
        self.textEdit.setReadOnly(True)
        self.textEdit_writer = OutLog(self.textEdit)
        self.view_log = self.ui.view_Log
        self.ui.actionLog.setChecked(True)

        if min1 is not None and min2 is not None:
            self.decrunner = DECRunner(system,
                                       database,
                                       min1,
                                       min2,
                                       outstream=self.textEdit_writer)
            self.decrunner.on_finished.connect(self.on_finished)

        self.view_3D = self.ui.view_ogl
        self.ui.action3D.setChecked(True)

        self.wgt_energies = ConnectEnergyWidget(parent=self)
        self.view_energies = self.new_view("Energies", self.wgt_energies,
                                           QtCore.Qt.TopDockWidgetArea)
        self.ui.actionEnergy.setChecked(True)

        self.wgt_graphview = GraphViewWidget(database=self.database,
                                             parent=self,
                                             app=app)
        self.view_graphview = self.new_view("Graph View", self.wgt_graphview,
                                            QtCore.Qt.TopDockWidgetArea)
        self.view_graphview.hide()
        self.ui.actionGraph.setChecked(False)

        self.ui.actionPause.setVisible(False)
        self.ui.actionD_Graph.setVisible(False)
        self.ui.actionSummary.setVisible(False)
        self.ui.actionSummary.setChecked(False)
        self.ui.actionRandom_connect.setChecked(False)
        self.ui.actionRandom_connect.setVisible(False)

        self.smoothed_path = None

    def start(self):
        self.decrunner.start()

    def on_finished(self):
        print "success", self.decrunner.success
        #        print "success", self.decrunner.smoothed_path
        if self.decrunner.success:
            # get the path data
            self.smoothed_path = np.array(self.decrunner.smoothed_path)
            self.S = np.array(self.decrunner.S)
            self.energies = np.array(self.decrunner.energies)
            #            print self.smoothed_path.shape

            # show the smoothed path in the ogl viewer
            self.show_path()

            # plot the energies
            self.make_energy_plot()

            # plot the graph of minima
            self.make_graph()

    def make_energy_plot(self):
        if self.wgt_energies.isVisible() and self.decrunner.success:
            self.wgt_energies.update_gui(self.S, self.energies)

    def show_path(self):
        if self.ogl.isVisible() and self.smoothed_path is not None:
            self.ogl.setCoordsPath(self.smoothed_path)

    def make_graph(self):
        if self.wgt_graphview.isVisible() and self.decrunner.success:
            self.wgt_graphview.make_graph(database=self.decrunner.database,
                                          minima=self.decrunner.newminima)
            self.wgt_graphview.show_graph()

    def new_view(self, title, widget, pos=QtCore.Qt.RightDockWidgetArea):
        child = QtGui.QDockWidget(title, self)
        child.setWidget(widget)
        self.addDockWidget(pos, child)
        return child

    def toggle_view(self, view, show):
        if show:
            view.show()
        else:
            view.hide()

    def on_actionEnergy_toggled(self, checked):
        self.toggle_view(self.view_energies, checked)
        self.make_energy_plot()

    def on_actionGraph_toggled(self, checked):
        self.toggle_view(self.view_graphview, checked)
        self.make_graph()

    def on_action3D_toggled(self, checked):
        self.toggle_view(self.view_3D, checked)
        self.show_path()

    def on_actionLog_toggled(self, checked):
        self.toggle_view(self.view_log, checked)

    def on_actionKill_triggered(self, checked=None):
        sys.stderr.write("kill toggled, terminating early\n")
        if checked is None: return
        self.decrunner.terminate_early()

    def closeEvent(self, event):
        self.on_actionKill_triggered(True)
        super(ConnectViewer, self).closeEvent(event)
Пример #7
0
class ConnectViewer(QtGui.QMainWindow):
    """
    external viewer for connect runs
    
    This viewer will use DECRunner to run a connect job in parallel.
    The log messages from that run will be redirected into a GUI text viewer.
    When the run is finished, the completed path will be shown in an OGL viewer
    
    Parameters
    ----------
    system : 
    database :
    min1, min2 : Minimum objects
        the minima to try to connect
    parent : 
        the parent window
    app : 
        the application
    
    See Also
    --------
    DECRunner
    
    """
    def __init__(self, system, database, min1=None, min2=None, parent=None, app=None):
        QtGui.QMainWindow.__init__(self, parent=parent)    
        self.ui = UI()
        self.ui.setupUi(self)
        self.ui.centralwidget.hide()
        
        self.app = app
        self.system = system
        self.database = database
        
        self.ogl = self.ui.ogl
        self.ogl.setSystem(system)

        
        self.textEdit = self.ui.textEdit      
        self.textEdit.setReadOnly(True)
        self.textEdit_writer = OutLog(self.textEdit)
        self.view_log = self.ui.view_Log
        self.ui.actionLog.setChecked(True)
        
        if min1 is not None and min2 is not None:
            self.decrunner = DECRunner(system, database, min1, min2, outstream=self.textEdit_writer)
            self.decrunner.on_finished.connect(self.on_finished)

        self.view_3D = self.ui.view_ogl
        self.ui.action3D.setChecked(True)
        
        self.wgt_energies = ConnectEnergyWidget(parent=self)
        self.view_energies = self.new_view("Energies", self.wgt_energies, QtCore.Qt.TopDockWidgetArea)
        self.ui.actionEnergy.setChecked(True)

        self.wgt_graphview = GraphViewWidget(database=self.database, parent=self, app=app)
        self.view_graphview = self.new_view("Graph View", self.wgt_graphview, QtCore.Qt.TopDockWidgetArea)
        self.view_graphview.hide()
        self.ui.actionGraph.setChecked(False)
        
        self.ui.actionPause.setVisible(False)
        self.ui.actionD_Graph.setVisible(False)
        self.ui.actionSummary.setVisible(False)
        self.ui.actionSummary.setChecked(False)
        self.ui.actionRandom_connect.setChecked(False)
        self.ui.actionRandom_connect.setVisible(False)
        
        self.smoothed_path = None


    def start(self):
        self.decrunner.start()

    def on_finished(self):
        print "success", self.decrunner.success
#        print "success", self.decrunner.smoothed_path
        if self.decrunner.success:
            # get the path data
            self.smoothed_path = np.array(self.decrunner.smoothed_path)
            self.S = np.array(self.decrunner.S)
            self.energies = np.array(self.decrunner.energies)
#            print self.smoothed_path.shape

            # show the smoothed path in the ogl viewer
            self.show_path()
            
            # plot the energies
            self.make_energy_plot()

            # plot the graph of minima
            self.make_graph()

    def make_energy_plot(self):
        if self.wgt_energies.isVisible() and self.decrunner.success:
            self.wgt_energies.update_gui(self.S, self.energies)

    def show_path(self):
        if self.ogl.isVisible() and self.smoothed_path is not None:
            self.ogl.setCoordsPath(self.smoothed_path)


    def make_graph(self):
        if self.wgt_graphview.isVisible() and self.decrunner.success:
            self.wgt_graphview.make_graph(database=self.decrunner.database, minima=self.decrunner.newminima)
            self.wgt_graphview.show_graph()
        

    def new_view(self, title, widget, pos=QtCore.Qt.RightDockWidgetArea):
        child = QtGui.QDockWidget(title, self)
        child.setWidget(widget)
        self.addDockWidget(pos, child)
        return child

    def toggle_view(self, view, show):
        if show:
            view.show()
        else:
            view.hide()

    def on_actionEnergy_toggled(self, checked):
        self.toggle_view(self.view_energies, checked)
        self.make_energy_plot()
    def on_actionGraph_toggled(self, checked):
        self.toggle_view(self.view_graphview, checked)
        self.make_graph()
    def on_action3D_toggled(self, checked):
        self.toggle_view(self.view_3D, checked)
        self.show_path()
    def on_actionLog_toggled(self, checked):
        self.toggle_view(self.view_log, checked)

    def on_actionKill_triggered(self, checked=None):
        sys.stderr.write( "kill toggled, terminating early\n")
        if checked is None: return
        self.decrunner.terminate_early()
    
    def closeEvent(self, event):
        self.on_actionKill_triggered(True)
        super(ConnectViewer, self).closeEvent(event)
Пример #8
0
class ConnectAllDialog(ConnectViewer):
    def __init__(self, system, database, parent=None, app=None):
        super(ConnectAllDialog, self).__init__(system, database, app=app, parent=parent)

        self.wgt_dgraph = DGraphWidget(database=self.database, parent=self)
        self.view_dgraph = self.new_view("Disconnectivity Graph", self.wgt_dgraph, QtCore.Qt.TopDockWidgetArea)
        self.view_dgraph.hide()
        self.ui.actionD_Graph.setVisible(True)
        self.ui.actionD_Graph.setChecked(False)

        self.textEdit_summary = QtGui.QTextEdit(parent=self)
        self.textEdit_summary.setReadOnly(True)
        self.view_summary = self.new_view("Summary", self.textEdit_summary, pos=QtCore.Qt.TopDockWidgetArea)
        self.connect_summary = ConnectAllSummary()
        self.ui.actionSummary.setVisible(True)
        self.view_summary.hide()
        self.ui.actionSummary.setChecked(False)
        

        self.ui.action3D.setChecked(False)
        self.view_3D.hide()
        
        self.ui.actionEnergy.setChecked(False)
        self.view_energies.hide()
        
        self.ui.actionPause.setVisible(True)
        
        self.is_running = False
        
        self.failed_pairs = set()
    


    def do_one_connection(self, min1, min2):
        self.textEdit.insertPlainText("\n\n")
        self.textEdit_summary.insertPlainText("\nNow connecting minima %d %d\n" % (self.min1._id, self.min2._id))
        self.decrunner = DECRunner(self.system, self.database, min1, min2, outstream=self.textEdit_writer,
                                   return_smoothed_path=True)
        self.decrunner.on_finished.connect(self.on_finished)
        self.tstart = time.clock()
        self.decrunner.start()

    def do_next_connect(self):
        self.is_running = True
        minima = self.database.minima()
        self.min1 = minima[0]
        graph = Graph(self.database)
        all_connected = True
        for m2 in minima[1:]:
            if not graph.areConnected(self.min1, m2):
                if (self.min1, m2) in self.failed_pairs or (m2, self.min1) in self.failed_pairs:
                    continue
                all_connected = False
                break
        if all_connected:
            print "minima are all connected, ending"
            self.textEdit_summary.insertPlainText("minima are all connected, ending\n")
            self.is_running = False
            return 
        self.min2 = m2
        self.do_one_connection(self.min1, m2)
        

    def start(self):
        self.do_next_connect()

    def update_energy_view(self):
        # plot the energies
        if self.view_energies.isVisible():
            self.wgt_energies.update_gui(self.S, self.energies)

    def update_graph_view(self):
        # show the graph view
        if self.view_graphview.isVisible():
            self.wgt_graphview.make_graph()
            self.wgt_graphview.show_graph()

    def update_3D_view(self):
        # show the smoothed path in the ogl viewer
        if self.view_3D.isVisible():
            self.ogl.setCoordsPath(self.smoothed_path)

    def update_dgraph_view(self):
        if self.view_dgraph.isVisible():
            self.wgt_dgraph.rebuild_disconnectivity_graph()

    def update_summary_view(self):
        self.textEdit_summary.clear()
        summary = self.connect_summary.get_summary()
        self.textEdit_summary.insertPlainText(summary)

    def on_finished(self):
        print "finished connecting", self.min1._id, "and", self.min2._id 
        tend = time.clock()
        elapsed_time = tend - self.tstart
#        print "\n"
        # add this run to the summary
        self.connect_summary.add(self.min1, self.min2, self.decrunner.success, 
                                 self.decrunner.newminima, self.decrunner.newtransition_states, elapsed_time=elapsed_time)
        
        if not self.isVisible():
            self.is_running = False
            return
        if self.decrunner.success:
            # get the path data
            self.smoothed_path = np.array(self.decrunner.smoothed_path)
            self.S = np.array(self.decrunner.S)
            self.energies = np.array(self.decrunner.energies)
#            print self.smoothed_path.shape


            self.update_3D_view()
            self.update_energy_view()
            self.update_graph_view()
            self.update_dgraph_view()
        else:
            print "connection run failed"
#            summary "connection run failed"
            if not self.decrunner.killed_early:
                self.failed_pairs.add( (self.min1, self.min2) )

        self.update_summary_view()
        if self.ui.actionPause.isChecked():
            self.is_running = False
            return
        self.do_next_connect()

    def on_actionEnergy_toggled(self, checked):
        self.toggle_view(self.view_energies, checked)
        self.update_energy_view()
    def on_actionGraph_toggled(self, checked):
        self.toggle_view(self.view_graphview, checked)
        self.update_graph_view()
    def on_action3D_toggled(self, checked):
        self.toggle_view(self.view_3D, checked)
        self.update_3D_view()
    def on_actionD_Graph_toggled(self, checked):
        self.toggle_view(self.view_dgraph, checked)
        self.update_dgraph_view()
    def on_actionSummary_toggled(self, checked):
        self.toggle_view(self.view_summary, checked)

    def on_actionPause_toggled(self, checked):
        if checked is None: return
        if not checked:
            if not self.is_running:
                self.start()
    
    def on_actionKill_triggered(self, checked=None):
        if checked is None: return
        self.ui.actionPause.setChecked(True)
        self.is_running = False
        self.decrunner.terminate_early()