diff --git a/scripts/Muon/maxent_model.py b/scripts/Muon/maxent_model.py index 94755bcb856a00931b54ac2ef3f7fca7f0111a4e..98f4b20ebfbabc726276c0f80689de827126a865 100644 --- a/scripts/Muon/maxent_model.py +++ b/scripts/Muon/maxent_model.py @@ -1,70 +1,116 @@ from __future__ import (absolute_import, division, print_function) + from six import iteritems + import mantid.simpleapi as mantid -class MaxEntModel(object): - # A simple class to hold the MaxEnt algorithm +class MaxEntWrapper(object): - def __init__(self): - self.alg=mantid.AlgorithmManager.create("MuonMaxent") - self.alg.initialize() - self.alg.setChild(True) + """ + A class to wrap the different parts + of the MaxEnt and its preprocessing. + This keeps the main MaxEnt class simple. + """ + + def __init__(self, maxent): + self.name = "MaxEnt" + self.model = maxent - def setInputs(self,inputs,runName): - self.inputs=inputs - for name,value in iteritems(self.inputs): - self.alg.setProperty(name,value) - self.run=runName + def loadData(self, inputs): + """ + store the data in the wrapper for later + """ + self.phaseTable = inputs.get("phaseTable",None) + self.maxent = inputs.get("maxent",None) + self.model.setRun(inputs["Run"]) def execute(self): - self.alg.execute() + """ + runs the relevant parts of the MaxEnt and the preprocessing + """ + if self.phaseTable is not None: + self.model.makePhaseTable(self.phaseTable) + + if self.maxent is not None: + self.model.MaxEntAlg(self.maxent) def cancel(self): - self.alg.cancel() + self.model.cancel() def output(self): - self.addOutput("OutputWorkspace") - self.addOutput("OutputPhaseTable") - self.addOutput("OutputDeadTimeTable") - self.addOutput("ReconstructedSpectra") - self.addOutput("PhaseConvergenceTable") - - def addOutput(self,name): - if name in self.inputs: - mantid.AnalysisDataService.addOrReplace( self.inputs[name],self.alg.getProperty(name).value) - else: - return - if mantid.AnalysisDataService.doesExist(self.run): - group=mantid.AnalysisDataService.retrieve(self.run) - else: - mantid.GroupWorkspaces(OutputWorkspace=self.run) + return - group.add(self.inputs[name]) +class MaxEntModel(object): -class PhaseModel(object): - # A simple class to hold the CalcMuonDetectorPhases algorithm + """ + A simple class which executes + the relevant algorithms for + the analysis. + """ def __init__(self): - self.calcAlg=mantid.AlgorithmManager.create("CalMuonDetectorPhases") - self.calcAlg.initialize() - self.calcAlg.setChild(True) + self.name = "MaxEnt" + self.alg = None - def loadData(self,inputs_phases): - self.inputs_phases = inputs_phases - if self.inputs_phases is not None: - for name,value in iteritems(self.inputs_phases): - self.calcAlg.setProperty(name,value) + def setRun(self, run): + self.run = run - def execute(self): - if self.inputs_phases is not None: - self.calcAlg.execute() - name="DetectorTable" - mantid.AnalysisDataService.addOrReplace( self.inputs_phases[name],self.calcAlg.getProperty(name).value) + def MaxEntAlg(self, inputs): + """ + Use the MaxEnt alg + """ + self.alg = mantid.AlgorithmManager.create("MuonMaxent") + self.alg.initialize() + self.alg.setAlwaysStoreInADS(False) + for name, value in iteritems(inputs): + self.alg.setProperty(name, value) + self.alg.execute() + self.addOutput(inputs, self.alg, "OutputWorkspace") + self.addOutput(inputs, self.alg, "OutputPhaseTable") + self.addOutput(inputs, self.alg, "OutputDeadTimeTable") + self.addOutput(inputs, self.alg, "ReconstructedSpectra") + self.addOutput(inputs, self.alg, "PhaseConvergenceTable") + self.alg = None + + def makePhaseTable(self, inputs): + """ + generates a phase table from CalMuonDetectorPhases + """ + self.alg = mantid.AlgorithmManager.create("CalMuonDetectorPhases") + self.alg.initialize() + self.alg.setAlwaysStoreInADS(False) + + for name, value in iteritems(inputs): + self.alg.setProperty(name, value) + if inputs["InputWorkspace"] != "MuonAnalysis": + raise ValueError( + "Cannot currently generate phase table from this data using CalMuonDetectorPhases") + self.alg.execute() + name = "DetectorTable" + mantid.AnalysisDataService.addOrReplace( + inputs[name], + self.alg.getProperty(name).value) + self.alg = None + + def addOutput(self, inputs, alg, name): + if name in inputs: + mantid.AnalysisDataService.addOrReplace( + inputs[name], + alg.getProperty(name).value) + else: + return + if mantid.AnalysisDataService.doesExist(self.run): + group = mantid.AnalysisDataService.retrieve(self.run) + else: + mantid.GroupWorkspaces(OutputWorkspace=self.run) + + group.add(inputs[name]) def cancel(self): - self.calcAlg.cancel() + if self.alg is not None: + self.alg.cancel() - def output(self): - return + def getName(self): + return self.name diff --git a/scripts/Muon/maxent_presenter.py b/scripts/Muon/maxent_presenter.py index 8dd617003f4759e8436d4dd5bad18988ad57ba99..6b598a1ef9b9c836b2df04210509195e28823a13 100644 --- a/scripts/Muon/maxent_presenter.py +++ b/scripts/Muon/maxent_presenter.py @@ -1,112 +1,104 @@ from __future__ import (absolute_import, division, print_function) -from Muon import thread_model -from Muon import maxent_model -import mantid.simpleapi as mantid import math +from Muon import thread_model class MaxEntPresenter(object): + """ - This is the presenter for the maximum entropy widget. - It connects the view and model together and deals with - logic. + This class links the MaxEnt model to the GUI """ - def __init__(self,view,alg,load): - self.view=view - self.alg=alg - self.calcAlg = maxent_model.PhaseModel() - self.load=load - self.thread =None + + def __init__(self, view, alg, load): + self.view = view + self.alg = alg + self.load = load + self.thread = None # set data self.getWorkspaceNames() - #connect + # connect self.view.maxEntButtonSignal.connect(self.handleMaxEntButton) self.view.cancelSignal.connect(self.cancel) self.view.phaseSignal.connect(self.handlePhase) - #functions + # functions def getWorkspaceNames(self): - final_options=self.load.getGroupedWorkspaceNames() + final_options = self.load.getGroupedWorkspaceNames() run = self.load.getRunName() self.view.setRun(run) final_options.append(run) self.view.addItems(final_options) - start = int(math.ceil(math.log(self.load.getNPoints())/math.log(2.0))) - values = [str(2**k) for k in range(start,21)] + start = int( + math.ceil(math.log(self.load.getNPoints()) / math.log(2.0))) + values = [str(2**k) for k in range(start, 21)] self.view.addNPoints(values) + def cancel(self): + if self.thread is not None: + self.thread.cancel() + + # turn on button + def activate(self): + self.view.activateCalculateButton() + + # turn off button + def deactivate(self): + self.view.deactivateCalculateButton() + + def handlePhase(self, row, col): + if col == 1 and row == 4: + self.view.changedPhaseBox() + def createThread(self): return thread_model.ThreadModel(self.alg) - def createPhaseThread(self): - return thread_model.ThreadModel(self.calcAlg) - + # constructs the inputs for the MaxEnt algorithms + # then executes them (see maxent_model to see the order + # of execution def handleMaxEntButton(self): - do_maxent = self.load.hasDataChanged() - if do_maxent: + if self.load.hasDataChanged(): self.getWorkspaceNames() - else: - if self.view.calcPhases() and self.view.usePhases(): - self.DoPhase() - else: - self.DoMaxEnt() - - def DoMaxEnt(self): - self.thread=self.createThread() - self.thread.started.connect(self.deactivate) - self.thread.finished.connect(self.handleFinished) - - inputs = self.getMaxEntInput() + return + # put this on its own thread so not to freeze Mantid + self.thread = self.createThread() + self.thread.threadWrapperSetUp(self.deactivate, self.handleFinished) + + # make some inputs + inputs = {} + inputs["Run"] = self.load.getRunName() + maxentInputs = self.getMaxEntInput() + if self.view.usePhases(): - self.view.addPhaseTable(inputs) + phaseTable = {} + if self.view.calcPhases(): + phaseTable["FirstGoodData"] = self.view.getFirstGoodData() + phaseTable["LastGoodData"] = self.view.getLastGoodData() + phaseTable["InputWorkspace"] = self.view.getInputWS() - runName=self.load.getRunName() - self.thread.setInputs(inputs,runName) - self.thread.start() + if "MuonAnalysisGrouped" not in phaseTable["InputWorkspace"]: + phaseTable["InputWorkspace"] = "MuonAnalysis" - def DoPhase(self): - - if self.view.usePhases() and self.view.calcPhases(): - inputs_phase = self.getCalPhasesInput() - if inputs_phase["InputWorkspace"] != "MuonAnalysis": - mantid.logger.error("Cannot currently generate phase table from this data using CalMuonDetecotrPhases") - return - self.calcThread=self.createPhaseThread() - self.calcThread.started.connect(self.deactivate) - self.calcThread.finished.connect(self.handleFinishedCalc) - self.calcThread.loadData(inputs_phase) - self.calcThread.start() - - def handlePhase(self,row,col): - if col==1 and row == 4: - self.view.changedPhaseBox() + phaseTable["DetectorTable"] = "PhaseTable" + phaseTable["DataFitted"] = "fits" - def cancel(self): - if self.thread is not None: - self.thread.cancel() + inputs["phaseTable"] = phaseTable + self.view.addPhaseTable(maxentInputs) + + inputs["maxent"] = maxentInputs + self.thread.loadData(inputs) + self.thread.start() + # kills the thread at end of execution def handleFinished(self): self.activate() + self.thread.threadWrapperTearDown(self.deactivate, self.handleFinished) self.thread.deleteLater() - self.thread=None - - def deactivate(self): - self.view.deactivateCalculateButton() - - def handleFinishedCalc(self): - self.activate() - self.calcThread.deleteLater() - self.calcThread=None - # ensures maxent is done after calcMuonDetectorPhases - self.DoMaxEnt() - - def activate(self): - self.view.activateCalculateButton() + self.thread = None def getMaxEntInput(self): - inputs=self.view.initMaxEntInput() + inputs = self.view.initMaxEntInput() if "MuonAnalysisGrouped" not in inputs["InputWorkspace"]: inputs["InputWorkspace"] = "MuonAnalysis" if self.view.outputPhases(): @@ -121,12 +113,3 @@ class MaxEntPresenter(object): if self.view.outputTime(): self.view.addOutputTime(inputs) return inputs - - def getCalPhasesInput(self): - inputs_phase = None - if self.view.calcPhases(): - inputs_phase =self.view.calcPhasesInit() - if "MuonAnalysisGrouped" not in inputs_phase["InputWorkspace"]: - inputs_phase["InputWorkspace"] = "MuonAnalysis" - - return inputs_phase diff --git a/scripts/Muon/maxent_view.py b/scripts/Muon/maxent_view.py index 82af799bca30c8073d9cf94bb094b9a171eaff49..1a5b238206b38a4373394d2ec6ada6f68413cc3a 100644 --- a/scripts/Muon/maxent_view.py +++ b/scripts/Muon/maxent_view.py @@ -6,6 +6,7 @@ from Muon import table_utils class MaxEntView(QtGui.QWidget): + """ The view for the MaxEnt widget. This creates the look of the widget @@ -13,122 +14,140 @@ class MaxEntView(QtGui.QWidget): # signals maxEntButtonSignal = QtCore.pyqtSignal() cancelSignal = QtCore.pyqtSignal() - phaseSignal = QtCore.pyqtSignal(object,object) + phaseSignal = QtCore.pyqtSignal(object, object) def __init__(self, parent=None): super(MaxEntView, self).__init__(parent) self.grid = QtGui.QVBoxLayout(self) self.run = None - #make table + # make table self.table = QtGui.QTableWidget(self) self.table.resize(800, 800) self.table.setRowCount(11) self.table.setColumnCount(2) - self.table.setColumnWidth(0,300) - self.table.setColumnWidth(1,300) + self.table.setColumnWidth(0, 300) + self.table.setColumnWidth(1, 300) self.table.verticalHeader().setVisible(False) self.table.horizontalHeader().setStretchLastSection(True) - self.table.setHorizontalHeaderLabels(("MaxEnt Property;Value").split(";")) + self.table.setHorizontalHeaderLabels( + ("MaxEnt Property;Value").split(";")) table_utils.setTableHeaders(self.table) # populate table options = ['test'] - table_utils.setRowName(self.table,0,"Workspace") - self.ws = table_utils.addComboToTable(self.table,0,options) + table_utils.setRowName(self.table, 0, "Workspace") + self.ws = table_utils.addComboToTable(self.table, 0, options) - table_utils.setRowName(self.table,1,"First good time") - self.first_good= table_utils.addDoubleToTable(self.table,0.1,1) + table_utils.setRowName(self.table, 1, "First good time") + self.first_good = table_utils.addDoubleToTable(self.table, 0.1, 1) - table_utils.setRowName(self.table,2,"Last good time") - self.last_good= table_utils.addDoubleToTable(self.table,15.0,2) + table_utils.setRowName(self.table, 2, "Last good time") + self.last_good = table_utils.addDoubleToTable(self.table, 15.0, 2) - table_utils.setRowName(self.table, 3,"Fit dead times") - self.dead_box= table_utils.addCheckBoxToTable(self.table,True,3) + table_utils.setRowName(self.table, 3, "Fit dead times") + self.dead_box = table_utils.addCheckBoxToTable(self.table, True, 3) - table_utils.setRowName(self.table,4,"Use Phase Table") - self.use_phaseTable_box = table_utils.addCheckBoxToTable(self.table,False,4) + table_utils.setRowName(self.table, 4, "Use Phase Table") + self.use_phaseTable_box = table_utils.addCheckBoxToTable( + self.table, False, 4) - table_utils.setRowName(self.table,5,"Construct Phase Table") - self.phaseTable_box = table_utils.addCheckBoxToTable(self.table,True,5) + table_utils.setRowName(self.table, 5, "Construct Phase Table") + self.phaseTable_box = table_utils.addCheckBoxToTable( + self.table, True, 5) - table_utils.setRowName(self.table, 6,"Fix phases") - self.fix_phase_box= table_utils.addCheckBoxToTable(self.table,False,6) + table_utils.setRowName(self.table, 6, "Fix phases") + self.fix_phase_box = table_utils.addCheckBoxToTable( + self.table, False, 6) self.table.hideRow(5) self.table.hideRow(6) - table_utils.setRowName(self.table, 7,"Output phase table") - self.output_phase_box= table_utils.addCheckBoxToTable(self.table,False,7) + table_utils.setRowName(self.table, 7, "Output phase table") + self.output_phase_box = table_utils.addCheckBoxToTable( + self.table, False, 7) - table_utils.setRowName(self.table, 8,"Output deadtimes") - self.output_dead_box= table_utils.addCheckBoxToTable(self.table,False,8) + table_utils.setRowName(self.table, 8, "Output deadtimes") + self.output_dead_box = table_utils.addCheckBoxToTable( + self.table, False, 8) - table_utils.setRowName(self.table, 9,"Output reconstructed data") - self.output_data_box= table_utils.addCheckBoxToTable(self.table,False,9) + table_utils.setRowName(self.table, 9, "Output reconstructed data") + self.output_data_box = table_utils.addCheckBoxToTable( + self.table, False, 9) - table_utils.setRowName(self.table, 10,"Output phase convergence") - self.output_phase_evo_box= table_utils.addCheckBoxToTable(self.table,False,10) + table_utils.setRowName(self.table, 10, "Output phase convergence") + self.output_phase_evo_box = table_utils.addCheckBoxToTable( + self.table, False, 10) self.table.resizeRowsToContents() # advanced options table - self.advancedLabel=QtGui.QLabel("\n Advanced Options") - #make table + self.advancedLabel = QtGui.QLabel("\n Advanced Options") + # make table self.tableA = QtGui.QTableWidget(self) self.tableA.resize(800, 800) self.tableA.setRowCount(7) self.tableA.setColumnCount(2) - self.tableA.setColumnWidth(0,300) - self.tableA.setColumnWidth(1,300) + self.tableA.setColumnWidth(0, 300) + self.tableA.setColumnWidth(1, 300) self.tableA.verticalHeader().setVisible(False) self.tableA.horizontalHeader().setStretchLastSection(True) - self.tableA.setHorizontalHeaderLabels(("Advanced Property;Value").split(";")) + self.tableA.setHorizontalHeaderLabels( + ("Advanced Property;Value").split(";")) table_utils.setTableHeaders(self.tableA) - table_utils.setRowName(self.tableA,0,"Maximum entropy constant (A)") - self.AConst= table_utils.addDoubleToTable(self.tableA,0.1,0) + table_utils.setRowName(self.tableA, 0, "Maximum entropy constant (A)") + self.AConst = table_utils.addDoubleToTable(self.tableA, 0.1, 0) - table_utils.setRowName(self.tableA,1,"Lagrange multiplier for chi^2") - self.factor= table_utils.addDoubleToTable(self.tableA,1.04,1) + table_utils.setRowName(self.tableA, 1, "Lagrange multiplier for chi^2") + self.factor = table_utils.addDoubleToTable(self.tableA, 1.04, 1) - table_utils.setRowName(self.tableA,2,"Inner Iterations") - self.inner_loop= table_utils.addSpinBoxToTable(self.tableA,10,2) + table_utils.setRowName(self.tableA, 2, "Inner Iterations") + self.inner_loop = table_utils.addSpinBoxToTable(self.tableA, 10, 2) - table_utils.setRowName(self.tableA,3,"Outer Iterations") - self.outer_loop= table_utils.addSpinBoxToTable(self.tableA,10,3) + table_utils.setRowName(self.tableA, 3, "Outer Iterations") + self.outer_loop = table_utils.addSpinBoxToTable(self.tableA, 10, 3) - table_utils.setRowName(self.tableA, 4,"Double pulse data") - self.double_pulse_box= table_utils.addCheckBoxToTable(self.tableA,False,4) + table_utils.setRowName(self.tableA, 4, "Double pulse data") + self.double_pulse_box = table_utils.addCheckBoxToTable( + self.tableA, False, 4) - table_utils.setRowName(self.tableA,5,"Number of data points") - self.N_points = table_utils.addComboToTable(self.tableA,5,options) + table_utils.setRowName(self.tableA, 5, "Number of data points") + self.N_points = table_utils.addComboToTable(self.tableA, 5, options) - table_utils.setRowName(self.tableA,6,"Maximum Field ") - self.max_field= table_utils.addDoubleToTable(self.tableA,1000.0,6) + table_utils.setRowName(self.tableA, 6, "Maximum Field ") + self.max_field = table_utils.addDoubleToTable(self.tableA, 1000.0, 6) - #layout + # layout # this is if complex data is unhidden - self.table.setMinimumSize(40,203) - self.tableA.setMinimumSize(40,207) - self.horizontalSpacer1 = QtGui.QSpacerItem(20, 30, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) - self.horizontalSpacer2 = QtGui.QSpacerItem(20, 70, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) - #make buttons + self.table.setMinimumSize(40, 203) + self.tableA.setMinimumSize(40, 207) + self.horizontalSpacer1 = QtGui.QSpacerItem( + 20, + 30, + QtGui.QSizePolicy.Expanding, + QtGui.QSizePolicy.Expanding) + self.horizontalSpacer2 = QtGui.QSpacerItem( + 20, + 70, + QtGui.QSizePolicy.Expanding, + QtGui.QSizePolicy.Expanding) + # make buttons self.button = QtGui.QPushButton('Calculate MaxEnt', self) self.button.setStyleSheet("background-color:lightgrey") self.cancel = QtGui.QPushButton('Cancel', self) self.cancel.setStyleSheet("background-color:lightgrey") self.cancel.setEnabled(False) - #connects + # connects self.button.clicked.connect(self.MaxEntButtonClick) self.cancel.clicked.connect(self.cancelClick) self.table.cellClicked.connect(self.phaseBoxClick) # button layout - self.buttonLayout=QtGui.QHBoxLayout() + self.buttonLayout = QtGui.QHBoxLayout() self.buttonLayout.addWidget(self.button) self.buttonLayout.addWidget(self.cancel) # add to layout @@ -140,20 +159,26 @@ class MaxEntView(QtGui.QWidget): self.grid.addLayout(self.buttonLayout) # add data to view - def addItems(self,options): + def addItems(self, options): self.ws.clear() self.ws.addItems(options) - def addNPoints(self,options): + def addNPoints(self, options): self.N_points.clear() self.N_points.addItems(options) - def setRun(self,run): - self.run=run + def setRun(self, run): + self.run = run def changedPhaseBox(self): - self.table.setRowHidden(5,self.use_phaseTable_box.checkState() != QtCore.Qt.Checked) - self.table.setRowHidden(6,self.use_phaseTable_box.checkState() != QtCore.Qt.Checked) + self.table.setRowHidden( + 5, + self.use_phaseTable_box.checkState( + ) != QtCore.Qt.Checked) + self.table.setRowHidden( + 6, + self.use_phaseTable_box.checkState( + ) != QtCore.Qt.Checked) # send signal def MaxEntButtonClick(self): @@ -162,60 +187,65 @@ class MaxEntView(QtGui.QWidget): def cancelClick(self): self.cancelSignal.emit() - def phaseBoxClick(self,row,col): - self.phaseSignal.emit(row,col) + def phaseBoxClick(self, row, col): + self.phaseSignal.emit(row, col) # get some inputs for model def initMaxEntInput(self): - inputs={} + inputs = {} # this will be removed once maxEnt does a simultaneous fit - inputs['InputWorkspace']=str( self.ws.currentText()) + inputs['InputWorkspace'] = str(self.ws.currentText()) # will use this instead of the above - inputs["FirstGoodTime"]= float( self.first_good.text()) - inputs['LastGoodTime']=float(self.last_good.text()) + inputs["FirstGoodTime"] = float(self.first_good.text()) + inputs['LastGoodTime'] = float(self.last_good.text()) - inputs["Npts"]=int(self.N_points.currentText()) + inputs["Npts"] = int(self.N_points.currentText()) inputs["MaxField"] = float(self.max_field.text()) - inputs["FixPhases"]=self.fix_phase_box.checkState() - inputs["FitDeadTime"]=self.dead_box.checkState() - inputs["DoublePulse"]=self.double_pulse_box.checkState() - inputs["OuterIterations"]=int(self.inner_loop.text()) - inputs["InnerIterations"]=int(self.outer_loop.text()) - inputs["DefaultLevel"]=float(self.AConst.text()) - inputs["Factor"]=float(self.factor.text()) + inputs["FixPhases"] = self.fix_phase_box.checkState() + inputs["FitDeadTime"] = self.dead_box.checkState() + inputs["DoublePulse"] = self.double_pulse_box.checkState() + inputs["OuterIterations"] = int(self.inner_loop.text()) + inputs["InnerIterations"] = int(self.outer_loop.text()) + inputs["DefaultLevel"] = float(self.AConst.text()) + inputs["Factor"] = float(self.factor.text()) # will remove this when sim maxent Works - out=self.run.replace(";","; ") - inputs['OutputWorkspace']=out+";"+ str( self.ws.currentText()) +";FrequencyDomain;MaxEnt" + out = self.run.replace(";", "; ") + inputs['OutputWorkspace'] = out + ";" + \ + str(self.ws.currentText()) + ";FrequencyDomain;MaxEnt" return inputs - def addPhaseTable(self,inputs): - inputs['InputPhaseTable']= "PhaseTable" + def addPhaseTable(self, inputs): + inputs['InputPhaseTable'] = "PhaseTable" def outputPhases(self): return self.output_phase_box.checkState() == QtCore.Qt.Checked - def addOutputPhases(self,inputs): - inputs['OutputPhaseTable']=self.run+";"+ str( self.ws.currentText()) +";PhaseTable;MaxEnt" + def addOutputPhases(self, inputs): + inputs['OutputPhaseTable'] = self.run + ";" + \ + str(self.ws.currentText()) + ";PhaseTable;MaxEnt" def outputDeadTime(self): return self.output_dead_box.checkState() == QtCore.Qt.Checked - def addOutputDeadTime(self,inputs): - inputs['OutputDeadTimeTable']=self.run+";"+ str( self.ws.currentText()) +";DeadTimeTable;MaxEnt" + def addOutputDeadTime(self, inputs): + inputs['OutputDeadTimeTable'] = self.run + ";" + \ + str(self.ws.currentText()) + ";DeadTimeTable;MaxEnt" def outputPhaseEvo(self): return self.output_phase_evo_box.checkState() == QtCore.Qt.Checked - def addOutputPhaseEvo(self,inputs): - inputs['PhaseConvergenceTable']=self.run+";"+ str( self.ws.currentText()) +";PhaseConvergenceTable;MaxEnt" + def addOutputPhaseEvo(self, inputs): + inputs['PhaseConvergenceTable'] = self.run + ";" + \ + str(self.ws.currentText()) + ";PhaseConvergenceTable;MaxEnt" def outputTime(self): return self.output_data_box.checkState() == QtCore.Qt.Checked - def addOutputTime(self,inputs): - inputs['ReconstructedSpectra']=self.run+";"+ str( self.ws.currentText()) +";TimeDomain;MaxEnt" + def addOutputTime(self, inputs): + inputs['ReconstructedSpectra'] = self.run + ";" + \ + str(self.ws.currentText()) + ";TimeDomain;MaxEnt" def calcPhases(self): return self.phaseTable_box.checkState() == QtCore.Qt.Checked @@ -223,20 +253,28 @@ class MaxEntView(QtGui.QWidget): def usePhases(self): return self.use_phaseTable_box.checkState() == QtCore.Qt.Checked - def calcPhasesInit(self): - inputs={} - - # this will be removed once maxEnt does a simultaneous fit - inputs['InputWorkspace']=str( self.ws.currentText()) - # will use this instead of the above - inputs["FirstGoodData"]= float( self.first_good.text()) - inputs['LastGoodData']=float(self.last_good.text()) - inputs["DetectorTable"] = "PhaseTable" - inputs["DataFitted"] = "fits" - - return inputs - + def getInputWS(self): + return str(self.ws.currentText()) + +# def calcPhasesInit(self): +# inputs={} +# +# this will be removed once maxEnt does a simultaneous fit +# inputs['InputWorkspace']=str( self.ws.currentText()) +# will use this instead of the above +# inputs["FirstGoodData"]= float( self.first_good.text()) +# inputs['LastGoodData']=float(self.last_good.text()) +# inputs["DetectorTable"] = "PhaseTable" +# inputs["DataFitted"] = "fits" +# +# return inputs + def getFirstGoodData(self): + return float(self.first_good.text()) + + def getLastGoodData(self): + return float(self.last_good.text()) # turn button on and off + def activateCalculateButton(self): self.button.setEnabled(True) self.cancel.setEnabled(False) diff --git a/scripts/Muon/message_box.py b/scripts/Muon/message_box.py new file mode 100644 index 0000000000000000000000000000000000000000..ecea1a6479924f0097b30b33441e776b526a93b5 --- /dev/null +++ b/scripts/Muon/message_box.py @@ -0,0 +1,7 @@ +import PyQt4.QtGui as QtGui + + +def warning(error): + + ex = QtGui.QWidget() + QtGui.QMessageBox.warning(ex, "Frequency Domain Analysis", str(error)) diff --git a/scripts/Muon/model_constructor.py b/scripts/Muon/model_constructor.py index 5146eaf29a09eebd4060e55fa3ac2ecdc78f107f..91392d7a38867aecd4911d0590a6d106f23ac51e 100644 --- a/scripts/Muon/model_constructor.py +++ b/scripts/Muon/model_constructor.py @@ -18,10 +18,11 @@ class ModelConstructor(object): self.transformModels={} # generate the models MaxEnt =maxent_model.MaxEntModel() + MaxEntWrapper =maxent_model.MaxEntWrapper(MaxEnt) FFT =fft_model.FFTModel() FFTWrapper=fft_model.FFTWrapper(FFT) # adds the models to the transformation tab - self.transformModels["MaxEnt"]=MaxEnt + self.transformModels[MaxEnt.getName()]=MaxEntWrapper self.transformModels[FFT.getName()]=FFTWrapper # gets the model diff --git a/scripts/Muon/thread_model.py b/scripts/Muon/thread_model.py index 50f9140b7f2d6d479a906481912f4dbe60e8091d..4008d79a9f5d8bfac51d28ce9cd25f602ad6a6b6 100644 --- a/scripts/Muon/thread_model.py +++ b/scripts/Muon/thread_model.py @@ -1,6 +1,8 @@ from __future__ import (absolute_import, division, print_function) from PyQt4.QtCore import QThread +from PyQt4 import QtCore +from Muon import message_box class ThreadModel(QThread): @@ -9,27 +11,54 @@ class ThreadModel(QThread): A wrapper to allow threading with the MaxEnt models. """ - def __init__(self,model): + exceptionSignal = QtCore.pyqtSignal(object) + + def __init__(self, model): QThread.__init__(self) - self.model=model + self.model = model def __del__(self): self.wait() def run(self): + self.user_cancel = False try: self.model.execute() self.model.output() except KeyboardInterrupt: pass + except Exception as error: + if self.user_cancel: + print("User ended job") + else: + self.sendSignal(error) + pass + + def sendSignal(self, error): + self.exceptionSignal.emit(error) + + def join(self): + if self.exception is not None: + raise self.exception def cancel(self): + self.user_cancel = True self.model.cancel() # if there is one set of inputs (1 alg) - def setInputs(self,inputs,runName): - self.model.setInputs(inputs,runName) + def setInputs(self, inputs, runName): + self.model.setInputs(inputs, runName) # if there are multiple inputs (alg>1) - def loadData(self,inputs): + def loadData(self, inputs): self.model.loadData(inputs) + + def threadWrapperSetUp(self, startSlot, endSlot): + self.started.connect(startSlot) + self.finished.connect(endSlot) + self.exceptionSignal.connect(message_box.warning) + + def threadWrapperTearDown(self, startSlot, endSlot): + self.started.disconnect(startSlot) + self.finished.disconnect(endSlot) + self.exceptionSignal.disconnect(message_box.warning) diff --git a/scripts/test/Muon/CMakeLists.txt b/scripts/test/Muon/CMakeLists.txt index f4984ab9448762e4ad2ab1fb5eb2f7a8e6784b98..5eb15b0b9eac3ad3ec99c39a1d61584062c62fe4 100644 --- a/scripts/test/Muon/CMakeLists.txt +++ b/scripts/test/Muon/CMakeLists.txt @@ -6,6 +6,7 @@ set ( TEST_PY_FILES FFTPresenter_test.py FFTModel_test.py MaxEntPresenter_test.py + MaxEntModel_test.py transformPresenter_test.py ) diff --git a/scripts/test/Muon/MaxEntModel_test.py b/scripts/test/Muon/MaxEntModel_test.py new file mode 100644 index 0000000000000000000000000000000000000000..ebb0884d359efc70fd88461d78b37eb62d811cdd --- /dev/null +++ b/scripts/test/Muon/MaxEntModel_test.py @@ -0,0 +1,50 @@ +import sys + +from Muon import maxent_model + +import unittest + +if sys.version_info.major == 3: + from unittest import mock +else: + import mock + + +class MaxEntModelTest(unittest.TestCase): + + def setUp(self): + self.model = mock.create_autospec( + maxent_model.MaxEntModel, + spec_set=True) + self.model.setRun = mock.Mock() + self.model.MaxEntAlg = mock.Mock() + self.model.makePhaseTable = mock.Mock() + + # set presenter + self.wrapper = maxent_model.MaxEntWrapper(self.model) + + def test_execute(self): + empty = {} + inputs = {} + inputs["Run"] = empty + inputs["maxent"] = empty + self.wrapper.loadData(inputs) + self.wrapper.execute() + assert(self.model.setRun.call_count == 1) + assert(self.model.MaxEntAlg.call_count == 1) + assert(self.model.makePhaseTable.call_count == 0) + + def testAll_execute(self): + empty = {} + inputs = {} + inputs["Run"] = empty + inputs["maxent"] = empty + inputs["phaseTable"] = empty + self.wrapper.loadData(inputs) + self.wrapper.execute() + assert(self.model.setRun.call_count == 1) + assert(self.model.MaxEntAlg.call_count == 1) + assert(self.model.makePhaseTable.call_count == 1) + +if __name__ == '__main__': + unittest.main() diff --git a/scripts/test/Muon/MaxEntPresenter_test.py b/scripts/test/Muon/MaxEntPresenter_test.py index 0b47e03f31bde9d9848b44802793548bad764a65..73156d0ddb10409d486854c657b72216e2445e45 100644 --- a/scripts/test/Muon/MaxEntPresenter_test.py +++ b/scripts/test/Muon/MaxEntPresenter_test.py @@ -46,6 +46,8 @@ class MaxEntPresenterTest(unittest.TestCase): self.thread.finished=mock.Mock() self.thread.setInputs=mock.Mock() self.thread.loadData=mock.Mock() + self.thread.threadWrapperSetup = mock.Mock() + self.thread.threadWrapperTearDown = mock.Mock() self.presenter.createThread=mock.Mock(return_value=self.thread) self.presenter.createPhaseThread=mock.Mock(return_value=self.thread)