source: sasview/src/sas/qtgui/Perspectives/Fitting/FittingWidget.py @ b1e36a3

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since b1e36a3 was b1e36a3, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

FittingWidget? code review SASVIEW-561

  • Property mode set to 100755
File size: 27.3 KB
RevLine 
[60af928]1import sys
2import json
[cd31251]3import os
[5236449]4import numpy
[60af928]5from collections import defaultdict
6
[5236449]7import logging
8import traceback
[cbcdd2c]9from twisted.internet import threads
[5236449]10
[60af928]11from PyQt4 import QtGui
12from PyQt4 import QtCore
13
14from sasmodels import generate
15from sasmodels import modelinfo
[5236449]16from sasmodels.sasview_model import load_standard_models
17
[60af928]18from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
[5236449]19from sas.sasgui.guiframe.dataFitting import Data1D
20from sas.sasgui.guiframe.dataFitting import Data2D
21import sas.qtgui.GuiUtils as GuiUtils
22from sas.sasgui.perspectives.fitting.model_thread import Calc1D
[cbcdd2c]23from sas.sasgui.perspectives.fitting.model_thread import Calc2D
[5236449]24
25from UI.FittingWidgetUI import Ui_FittingWidgetUI
[4d457df]26from sas.qtgui.Perspectives.Fitting.FittingLogic import FittingLogic
27from sas.qtgui.Perspectives.Fitting import FittingUtilities
[60af928]28
29TAB_MAGNETISM = 4
30TAB_POLY = 3
[cbcdd2c]31CATEGORY_DEFAULT = "Choose category..."
[4d457df]32CATEGORY_STRUCTURE = "Structure Factor"
[351b53e]33STRUCTURE_DEFAULT = "None"
[cbcdd2c]34QMIN_DEFAULT = 0.0005
35QMAX_DEFAULT = 0.5
36NPTS_DEFAULT = 50
[60af928]37
38class FittingWidget(QtGui.QWidget, Ui_FittingWidgetUI):
39    """
[f46f6dc]40    Main widget for selecting form and structure factor models
[60af928]41    """
[811bec1]42    def __init__(self, parent=None, data=None, id=1):
[60af928]43
44        super(FittingWidget, self).__init__()
45
[86f88d1]46        # Necessary globals
[cbcdd2c]47        self.parent = parent
48        # SasModel is loaded
[60af928]49        self.model_is_loaded = False
[cbcdd2c]50        # Data[12]D passed and set
[5236449]51        self.data_is_loaded = False
[cbcdd2c]52        # Current SasModel in view
[5236449]53        self.kernel_module = None
[cbcdd2c]54        # Current SasModel view dimension
[60af928]55        self.is2D = False
[cbcdd2c]56        # Current SasModel is multishell
[86f88d1]57        self.model_has_shells = False
[cbcdd2c]58        # Utility variable to enable unselectable option in category combobox
[86f88d1]59        self._previous_category_index = 0
[cbcdd2c]60        # Utility variable for multishell display
[86f88d1]61        self._last_model_row = 0
[cbcdd2c]62        # Dictionary of {model name: model class} for the current category
[5236449]63        self.models = {}
64
65        # Which tab is this widget displayed in?
66        self.tab_id = id
67
[811bec1]68        # Range parameters
[cbcdd2c]69        self.q_range_min = QMIN_DEFAULT
70        self.q_range_max = QMAX_DEFAULT
71        self.npts = NPTS_DEFAULT
[811bec1]72
[cbcdd2c]73        # Main Data[12]D holder
[4d457df]74        self.logic = FittingLogic(data=data)
[60af928]75
[86f88d1]76        # Main GUI setup up
[60af928]77        self.setupUi(self)
78        self.setWindowTitle("Fitting")
[cbcdd2c]79        self.communicate = self.parent.communicate
[60af928]80
[b1e36a3]81        # Define bold font for use in various controls
82        self.boldFont=QtGui.QFont()
83        self.boldFont.setBold(True)
84
85        # Set data label
86        self.label.setFont(self.boldFont)
87        self.label.setText("No data loaded")
88        self.lblFilename.setText("")
89
[86f88d1]90        # Set the main models
[cd31251]91        # We can't use a single model here, due to restrictions on flattening
92        # the model tree with subclassed QAbstractProxyModel...
[60af928]93        self._model_model = QtGui.QStandardItemModel()
94        self._poly_model = QtGui.QStandardItemModel()
95        self._magnet_model = QtGui.QStandardItemModel()
96
97        # Param model displayed in param list
98        self.lstParams.setModel(self._model_model)
[5236449]99        self.readCategoryInfo()
[60af928]100        self.model_parameters = None
[86f88d1]101        self.lstParams.setAlternatingRowColors(True)
[60af928]102
103        # Poly model displayed in poly list
[811bec1]104        self.lstPoly.setModel(self._poly_model)
[60af928]105        self.setPolyModel()
106        self.setTableProperties(self.lstPoly)
107
108        # Magnetism model displayed in magnetism list
109        self.lstMagnetic.setModel(self._magnet_model)
110        self.setMagneticModel()
111        self.setTableProperties(self.lstMagnetic)
112
[5236449]113        # Defaults for the structure factors
[6f7f652]114        self.setDefaultStructureCombo()
115
[5236449]116        # Make structure factor and model CBs disabled
[6f7f652]117        self.disableModelCombo()
118        self.disableStructureCombo()
[60af928]119
[6f7f652]120        # Generate the category list for display
[60af928]121        category_list = sorted(self.master_category_dict.keys())
[86f88d1]122        self.cbCategory.addItem(CATEGORY_DEFAULT)
[60af928]123        self.cbCategory.addItems(category_list)
[4d457df]124        self.cbCategory.addItem(CATEGORY_STRUCTURE)
[6f7f652]125        self.cbCategory.setCurrentIndex(0)
[60af928]126
[b1e36a3]127        self._index = None
[5236449]128        if data is not None:
129            self.data = data
130
[86f88d1]131        # Connect signals to controls
132        self.initializeSignals()
[60af928]133
[86f88d1]134        # Initial control state
135        self.initializeControls()
[60af928]136
137    @property
138    def data(self):
[4d457df]139        return self.logic.data
[60af928]140
141    @data.setter
142    def data(self, value):
143        """ data setter """
[4d457df]144        assert isinstance(value[0], QtGui.QStandardItem)
[cbcdd2c]145        # _index contains the QIndex with data
[5236449]146        self._index = value
[b1e36a3]147
[4d457df]148        # Update logics with data items
149        self.logic.data = GuiUtils.dataFromItem(value[0])
150
[5236449]151        self.data_is_loaded = True
[cbcdd2c]152        # Tag along functionality
[b1e36a3]153        self.label.setText("Data loaded from: ")
154        self.lblFilename.setText(self.logic.data.title)
[5236449]155        self.updateQRange()
156        self.cmdFit.setEnabled(True)
[60af928]157
[f46f6dc]158    def acceptsData(self):
159        """ Tells the caller this widget can accept new dataset """
[5236449]160        return not self.data_is_loaded
[f46f6dc]161
[6f7f652]162    def disableModelCombo(self):
[cbcdd2c]163        """ Disable the combobox """
[6f7f652]164        self.cbModel.setEnabled(False)
[b1e36a3]165        self.lblModel.setEnabled(False)
[6f7f652]166
167    def enableModelCombo(self):
[cbcdd2c]168        """ Enable the combobox """
[6f7f652]169        self.cbModel.setEnabled(True)
[b1e36a3]170        self.lblModel.setEnabled(True)
[6f7f652]171
172    def disableStructureCombo(self):
[cbcdd2c]173        """ Disable the combobox """
[6f7f652]174        self.cbStructureFactor.setEnabled(False)
[b1e36a3]175        self.lblStructure.setEnabled(False)
[6f7f652]176
177    def enableStructureCombo(self):
[cbcdd2c]178        """ Enable the combobox """
[6f7f652]179        self.cbStructureFactor.setEnabled(True)
[b1e36a3]180        self.lblStructure.setEnabled(True)
[6f7f652]181
[5236449]182    def updateQRange(self):
183        """
184        Updates Q Range display
185        """
186        if self.data_is_loaded:
[4d457df]187            self.q_range_min, self.q_range_max, self.npts = self.logic.computeDataRange()
[cbcdd2c]188        # set Q range labels on the main tab
[5236449]189        self.lblMinRangeDef.setText(str(self.q_range_min))
190        self.lblMaxRangeDef.setText(str(self.q_range_max))
[cbcdd2c]191        # set Q range labels on the options tab
[5236449]192        self.txtMaxRange.setText(str(self.q_range_max))
193        self.txtMinRange.setText(str(self.q_range_min))
194        self.txtNpts.setText(str(self.npts))
195
[86f88d1]196    def initializeControls(self):
197        """
198        Set initial control enablement
199        """
200        self.cmdFit.setEnabled(False)
201        self.cmdPlot.setEnabled(True)
202        self.chkPolydispersity.setEnabled(True)
203        self.chkPolydispersity.setCheckState(False)
204        self.chk2DView.setEnabled(True)
205        self.chk2DView.setCheckState(False)
206        self.chkMagnetism.setEnabled(False)
207        self.chkMagnetism.setCheckState(False)
[cbcdd2c]208        # Tabs
[86f88d1]209        self.tabFitting.setTabEnabled(TAB_POLY, False)
210        self.tabFitting.setTabEnabled(TAB_MAGNETISM, False)
211        self.lblChi2Value.setText("---")
[5236449]212        # Update Q Ranges
213        self.updateQRange()
[86f88d1]214
215    def initializeSignals(self):
216        """
217        Connect GUI element signals
218        """
[cbcdd2c]219        # Comboboxes
[cd31251]220        self.cbStructureFactor.currentIndexChanged.connect(self.onSelectStructureFactor)
221        self.cbCategory.currentIndexChanged.connect(self.onSelectCategory)
222        self.cbModel.currentIndexChanged.connect(self.onSelectModel)
[cbcdd2c]223        # Checkboxes
[86f88d1]224        self.chk2DView.toggled.connect(self.toggle2D)
225        self.chkPolydispersity.toggled.connect(self.togglePoly)
226        self.chkMagnetism.toggled.connect(self.toggleMagnetism)
[cbcdd2c]227        # Buttons
[5236449]228        self.cmdFit.clicked.connect(self.onFit)
[cbcdd2c]229        self.cmdPlot.clicked.connect(self.onPlot)
230        # Line edits
231        self.txtNpts.textChanged.connect(self.onNpts)
232        self.txtMinRange.textChanged.connect(self.onMinRange)
233        self.txtMaxRange.textChanged.connect(self.onMaxRange)
234
235        # Respond to change in parameters from the UI
236        self._model_model.itemChanged.connect(self.updateParamsFromModel)
[cd31251]237        self._poly_model.itemChanged.connect(self.onPolyModelChange)
238        # TODO after the poly_model prototype accepted
239        #self._magnet_model.itemChanged.connect(self.onMagneticModelChange)
[86f88d1]240
[6f7f652]241    def setDefaultStructureCombo(self):
[cbcdd2c]242        """
243        Fill in the structure factors combo box with defaults
244        """
[4d457df]245        structure_factor_list = self.master_category_dict.pop(CATEGORY_STRUCTURE)
[351b53e]246        factors = [factor[0] for factor in structure_factor_list]
247        factors.insert(0, STRUCTURE_DEFAULT)
[6f7f652]248        self.cbStructureFactor.clear()
[351b53e]249        self.cbStructureFactor.addItems(sorted(factors))
[6f7f652]250
[cd31251]251    def onSelectCategory(self):
[60af928]252        """
253        Select Category from list
254        """
[4d457df]255        category = str(self.cbCategory.currentText())
[86f88d1]256        # Check if the user chose "Choose category entry"
[4d457df]257        if category == CATEGORY_DEFAULT:
[86f88d1]258            # if the previous category was not the default, keep it.
259            # Otherwise, just return
260            if self._previous_category_index != 0:
[351b53e]261                # We need to block signals, or else state changes on perceived unchanged conditions
262                self.cbCategory.blockSignals(True)
[86f88d1]263                self.cbCategory.setCurrentIndex(self._previous_category_index)
[351b53e]264                self.cbCategory.blockSignals(False)
[86f88d1]265            return
266
[4d457df]267        if category == CATEGORY_STRUCTURE:
[6f7f652]268            self.disableModelCombo()
269            self.enableStructureCombo()
[29eb947]270            self._model_model.clear()
[6f7f652]271            return
272
[cbcdd2c]273        # Safely clear and enable the model combo
[6f7f652]274        self.cbModel.blockSignals(True)
275        self.cbModel.clear()
276        self.cbModel.blockSignals(False)
277        self.enableModelCombo()
278        self.disableStructureCombo()
279
[86f88d1]280        self._previous_category_index = self.cbCategory.currentIndex()
[cbcdd2c]281        # Retrieve the list of models
[4d457df]282        model_list = self.master_category_dict[category]
[6f7f652]283        models = []
[cbcdd2c]284        # Populate the models combobox
[b1e36a3]285        self.cbModel.addItems(sorted([model for (model, _) in model_list]))
[4d457df]286
287    def createDefaultDataset(self):
288        """
289        Generate default Dataset 1D/2D for the given model
290        """
291        # Create default datasets if no data passed
292        if self.is2D:
293            qmax = self.q_range_max/numpy.sqrt(2)
294            qstep = self.npts
295            self.logic.createDefault2dData(qmax, qstep, self.tab_id)
296        else:
297            interval = numpy.linspace(start=self.q_range_min, stop=self.q_range_max,
298                        num=self.npts, endpoint=True)
299            self.logic.createDefault1dData(interval, self.tab_id)
[60af928]300
[cd31251]301    def onSelectModel(self):
[60af928]302        """
[5236449]303        Respond to select Model from list event
[60af928]304        """
[cbcdd2c]305        model = str(self.cbModel.currentText())
[5236449]306
[351b53e]307        # Reset structure factor
308        self.cbStructureFactor.setCurrentIndex(0)
309
[5236449]310        # SasModel -> QModel
[4d457df]311        self.SASModelToQModel(model)
[60af928]312
[5236449]313        if self._index is None:
[cbcdd2c]314            # Create default datasets if no data passed
[4d457df]315            self.createDefaultDataset()
[5236449]316        else:
[b1e36a3]317            self.calculateQGridForModel()
[5236449]318
[cd31251]319    def onSelectStructureFactor(self):
[60af928]320        """
321        Select Structure Factor from list
322        """
[cd31251]323        model = str(self.cbModel.currentText())
[29eb947]324        category = str(self.cbCategory.currentText())
[cd31251]325        structure = str(self.cbStructureFactor.currentText())
[29eb947]326        if category == CATEGORY_STRUCTURE:
327            model = None
[4d457df]328        self.SASModelToQModel(model, structure_factor=structure)
[60af928]329
[5236449]330    def readCategoryInfo(self):
[60af928]331        """
332        Reads the categories in from file
333        """
334        self.master_category_dict = defaultdict(list)
335        self.by_model_dict = defaultdict(list)
336        self.model_enabled_dict = defaultdict(bool)
337
[cbcdd2c]338        categorization_file = CategoryInstaller.get_user_file()
339        if not os.path.isfile(categorization_file):
340            categorization_file = CategoryInstaller.get_default_file()
341        with open(categorization_file, 'rb') as cat_file:
[60af928]342            self.master_category_dict = json.load(cat_file)
[5236449]343            self.regenerateModelDict()
[60af928]344
[5236449]345        # Load the model dict
346        models = load_standard_models()
347        for model in models:
348            self.models[model.name] = model
349
350    def regenerateModelDict(self):
[60af928]351        """
[cbcdd2c]352        Regenerates self.by_model_dict which has each model name as the
[60af928]353        key and the list of categories belonging to that model
354        along with the enabled mapping
355        """
356        self.by_model_dict = defaultdict(list)
357        for category in self.master_category_dict:
358            for (model, enabled) in self.master_category_dict[category]:
359                self.by_model_dict[model].append(category)
360                self.model_enabled_dict[model] = enabled
361
[86f88d1]362    def addBackgroundToModel(self, model):
363        """
364        Adds background parameter with default values to the model
365        """
[cbcdd2c]366        assert isinstance(model, QtGui.QStandardItemModel)
[86f88d1]367        checked_list = ['background', '0.001', '-inf', 'inf', '1/cm']
[4d457df]368        FittingUtilities.addCheckedListToModel(model, checked_list)
[86f88d1]369
370    def addScaleToModel(self, model):
371        """
372        Adds scale parameter with default values to the model
373        """
[cbcdd2c]374        assert isinstance(model, QtGui.QStandardItemModel)
[86f88d1]375        checked_list = ['scale', '1.0', '0.0', 'inf', '']
[4d457df]376        FittingUtilities.addCheckedListToModel(model, checked_list)
[86f88d1]377
[4d457df]378    def SASModelToQModel(self, model_name, structure_factor=None):
[60af928]379        """
[cbcdd2c]380        Setting model parameters into table based on selected category
[60af928]381        """
[351b53e]382        # TODO - modify for structure factor-only choice
383
[60af928]384        # Crete/overwrite model items
385        self._model_model.clear()
[5236449]386
[60af928]387        kernel_module = generate.load_kernel_module(model_name)
388        self.model_parameters = modelinfo.make_parameter_table(getattr(kernel_module, 'parameters', []))
389
[cbcdd2c]390        # Instantiate the current sasmodel
[5236449]391        self.kernel_module = self.models[model_name]()
392
393        # Explicitly add scale and background with default values
[86f88d1]394        self.addScaleToModel(self._model_model)
395        self.addBackgroundToModel(self._model_model)
[60af928]396
[5236449]397        # Update the QModel
[4d457df]398        FittingUtilities.addParametersToModel(self.model_parameters, self._model_model)
399        # Update the counter used for multishell display
400        self._last_model_row = self._model_model.rowCount()
401
402        FittingUtilities.addHeadersToModel(self._model_model)
[cd31251]403
404        # Add structure factor
405        if structure_factor is not None and structure_factor != "None":
406            structure_module = generate.load_kernel_module(structure_factor)
407            structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', []))
[4d457df]408            FittingUtilities.addSimpleParametersToModel(structure_parameters, self._model_model)
409            # Update the counter used for multishell display
410            self._last_model_row = self._model_model.rowCount()
[cd31251]411        else:
412            self.addStructureFactor()
413
[5236449]414        # Multishell models need additional treatment
[86f88d1]415        self.addExtraShells()
416
[5236449]417        # Add polydispersity to the model
[86f88d1]418        self.setPolyModel()
[5236449]419        # Add magnetic parameters to the model
[86f88d1]420        self.setMagneticModel()
[5236449]421
422        # Now we claim the model has been loaded
[86f88d1]423        self.model_is_loaded = True
424
[5236449]425        # Update Q Ranges
426        self.updateQRange()
427
[cd31251]428    def onPolyModelChange(self, item):
[cbcdd2c]429        """
[cd31251]430        Callback method for updating the main model and sasmodel
431        parameters with the GUI values in the polydispersity view
[cbcdd2c]432        """
[cd31251]433        model_column = item.column()
434        model_row = item.row()
435        name_index = self._poly_model.index(model_row, 0)
[cbcdd2c]436        # Extract changed value. Assumes proper validation by QValidator/Delegate
[29eb947]437        # Checkbox in column 0
438        if model_column == 0:
439            value = item.checkState()
440        else:
[b1e36a3]441            try:
442                value = float(item.text())
443            except ValueError:
444                # Can't be converted properly, bring back the old value and exit
445                return
446
[cd31251]447        parameter_name = str(self._poly_model.data(name_index).toPyObject()) # "distribution of sld" etc.
448        if "Distribution of" in parameter_name:
449            parameter_name = parameter_name[16:]
450        property_name = str(self._poly_model.headerData(model_column, 1).toPyObject()) # Value, min, max, etc.
[351b53e]451        # print "%s(%s) => %d" % (parameter_name, property_name, value)
[cd31251]452
453        # Update the sasmodel
454        #self.kernel_module.params[parameter_name] = value
455
456        # Reload the main model - may not be required if no variable is shown in main view
457        #model = str(self.cbModel.currentText())
[4d457df]458        #self.SASModelToQModel(model)
[cd31251]459
460        pass # debug anchor
461
462    def updateParamsFromModel(self, item):
463        """
464        Callback method for updating the sasmodel parameters with the GUI values
465        """
[cbcdd2c]466        model_column = item.column()
467        model_row = item.row()
468        name_index = self._model_model.index(model_row, 0)
[cd31251]469
470        if model_column == 0:
471            # Assure we're dealing with checkboxes
472            if not item.isCheckable():
473                return
474            status = item.checkState()
475            # If multiple rows selected - toggle all of them
476            rows = [s.row() for s in self.lstParams.selectionModel().selectedRows()]
477
478            # Switch off signaling from the model to avoid multiple calls
479            self._model_model.blockSignals(True)
480            # Convert to proper indices and set requested enablement
481            items = [self._model_model.item(row, 0).setCheckState(status) for row in rows]
482            self._model_model.blockSignals(False)
483            return
484
485        # Extract changed value. Assumes proper validation by QValidator/Delegate
486        value = float(item.text())
[cbcdd2c]487        parameter_name = str(self._model_model.data(name_index).toPyObject()) # sld, background etc.
488        property_name = str(self._model_model.headerData(1, model_column).toPyObject()) # Value, min, max, etc.
489
[351b53e]490        # print "%s(%s) => %d" % (parameter_name, property_name, value)
[cbcdd2c]491        self.kernel_module.params[parameter_name] = value
492
493        # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf]
494
495        # magnetic params in self.kernel_module.details['M0:parameter_name'] = value
496        # multishell params in self.kernel_module.details[??] = value
497
[5236449]498
499    def createTheoryIndex(self):
500        """
501        Create a QStandardModelIndex containing default model data
502        """
[cbcdd2c]503        name = self.kernel_module.name
[5236449]504        if self.is2D:
505            name += "2d"
506        name = "M%i [%s]" % (self.tab_id, name)
507        new_item = GuiUtils.createModelItemWithPlot(QtCore.QVariant(self.data), name=name)
[cbcdd2c]508        # Notify the GUI manager so it can update the theory model in DataExplorer
509        self.communicate.updateTheoryFromPerspectiveSignal.emit(new_item)
[5236449]510
511    def onFit(self):
512        """
513        Perform fitting on the current data
514        """
[cbcdd2c]515        #self.calculate1DForModel()
516        pass
517
518    def onPlot(self):
519        """
520        Plot the current set of data
521        """
522        # TODO: reimplement basepage.py/_update_paramv_on_fit
[4d457df]523        if self.data is None or not self.data.is_data:
524            self.createDefaultDataset()
[b1e36a3]525        self.calculateQGridForModel()
[cbcdd2c]526
527    def onNpts(self, text):
528        """
529        Callback for number of points line edit update
530        """
531        # assumes type/value correctness achieved with QValidator
532        try:
533            self.npts = int(text)
[b1e36a3]534        except ValueError:
535            # TODO
536            # This will return the old value to model/view and return
537            # notifying the user about format available.
[cbcdd2c]538            pass
539
540    def onMinRange(self, text):
541        """
542        Callback for minimum range of points line edit update
543        """
544        # assumes type/value correctness achieved with QValidator
545        try:
546            self.q_range_min = float(text)
[b1e36a3]547        except ValueError:
548            # TODO
549            # This will return the old value to model/view and return
550            # notifying the user about format available.
551            return
[cd31251]552        # set Q range labels on the main tab
553        self.lblMinRangeDef.setText(str(self.q_range_min))
[cbcdd2c]554
555    def onMaxRange(self, text):
556        """
557        Callback for maximum range of points line edit update
558        """
559        # assumes type/value correctness achieved with QValidator
560        try:
561            self.q_range_max = float(text)
562        except:
563            pass
[cd31251]564        # set Q range labels on the main tab
565        self.lblMaxRangeDef.setText(str(self.q_range_max))
[5236449]566
[4d457df]567    def methodCalculateForData(self):
568        '''return the method for data calculation'''
569        return Calc1D if isinstance(self.data, Data1D) else Calc2D
570
571    def methodCompleteForData(self):
572        '''return the method for result parsin on calc complete '''
573        return self.complete1D if isinstance(self.data, Data1D) else self.complete2D
574
[b1e36a3]575    def calculateQGridForModel(self):
[86f88d1]576        """
577        Prepare the fitting data object, based on current ModelModel
578        """
[4d457df]579        # Awful API to a backend method.
580        method = self.methodCalculateForData()(data=self.data,
[cbcdd2c]581                              model=self.kernel_module,
582                              page_id=0,
583                              qmin=self.q_range_min,
584                              qmax=self.q_range_max,
585                              smearer=None,
586                              state=None,
587                              weight=None,
588                              fid=None,
589                              toggle_mode_on=False,
[4d457df]590                              completefn=None,
[cbcdd2c]591                              update_chisqr=True,
[5236449]592                              exception_handler=self.calcException,
[cbcdd2c]593                              source=None)
[4d457df]594
595        calc_thread = threads.deferToThread(method.compute)
596        calc_thread.addCallback(self.methodCompleteForData())
[5236449]597
[cbcdd2c]598    def complete1D(self, return_data):
[5236449]599        """
[4d457df]600        Plot the current 1D data
601        """
602        self.logic.new1DPlot(return_data)
[cbcdd2c]603        self.createTheoryIndex()
604
605        #output=self._cal_chisqr(data=data,
606        #                        fid=fid,
607        #                        weight=weight,
608        #                        page_id=page_id,
609        #                        index=index)
610
611    def complete2D(self, return_data):
612        """
[4d457df]613        Plot the current 2D data
614        """
615        self.logic.new2DPlot(return_data)
[cbcdd2c]616        self.createTheoryIndex()
617
618        #output=self._cal_chisqr(data=data,
619        #                        weight=weight,
620        #                        fid=fid,
621        #                        page_id=page_id,
622        #                        index=index)
623        #    self._plot_residuals(page_id=page_id, data=data, fid=fid,
624        #                            index=index, weight=weight)
[5236449]625
626    def calcException(self, etype, value, tb):
627        """
[b1e36a3]628        Something horrible happened in the deferred.
[5236449]629        """
630        logging.error("".join(traceback.format_exception(etype, value, tb)))
[60af928]631
632    def setTableProperties(self, table):
633        """
634        Setting table properties
635        """
636        # Table properties
637        table.verticalHeader().setVisible(False)
638        table.setAlternatingRowColors(True)
639        table.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)
640        table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
[f46f6dc]641        table.resizeColumnsToContents()
642
[60af928]643        # Header
644        header = table.horizontalHeader()
[f46f6dc]645        header.setResizeMode(QtGui.QHeaderView.ResizeToContents)
646
647        header.ResizeMode(QtGui.QHeaderView.Interactive)
[b1e36a3]648        # Resize column 0 and 6 to content
[f46f6dc]649        header.setResizeMode(0, QtGui.QHeaderView.ResizeToContents)
650        header.setResizeMode(6, QtGui.QHeaderView.ResizeToContents)
[60af928]651
652    def setPolyModel(self):
653        """
654        Set polydispersity values
655        """
[86f88d1]656        if not self.model_parameters:
657            return
658        self._poly_model.clear()
659        for row, param in enumerate(self.model_parameters.form_volume_parameters):
660            # Counters should not be included
661            if not param.polydisperse:
662                continue
663
664            # Potential multishell params
665            checked_list = ["Distribution of "+param.name, str(param.default),
[cbcdd2c]666                            str(param.limits[0]), str(param.limits[1]),
[86f88d1]667                            "35", "3", ""]
[4d457df]668            FittingUtilities.addCheckedListToModel(self._poly_model, checked_list)
[86f88d1]669
670            #TODO: Need to find cleaner way to input functions
671            func = QtGui.QComboBox()
[cbcdd2c]672            func.addItems(['rectangle', 'array', 'lognormal', 'gaussian', 'schulz',])
673            func_index = self.lstPoly.model().index(row, 6)
674            self.lstPoly.setIndexWidget(func_index, func)
[86f88d1]675
[4d457df]676        FittingUtilities.addPolyHeadersToModel(self._poly_model)
[60af928]677
678    def setMagneticModel(self):
679        """
680        Set magnetism values on model
681        """
[86f88d1]682        if not self.model_parameters:
683            return
684        self._magnet_model.clear()
685        for param in self.model_parameters.call_parameters:
686            if param.type != "magnetic":
687                continue
688            checked_list = [param.name,
689                            str(param.default),
690                            str(param.limits[0]),
691                            str(param.limits[1]),
692                            param.units]
[4d457df]693            FittingUtilities.addCheckedListToModel(self._magnet_model, checked_list)
[86f88d1]694
[4d457df]695        FittingUtilities.addHeadersToModel(self._magnet_model)
[60af928]696
[cd31251]697    def addStructureFactor(self):
698        """
699        Add structure factors to the list of parameters
700        """
701        if self.kernel_module.is_form_factor:
702            self.enableStructureCombo()
703        else:
704            self.disableStructureCombo()
705
[60af928]706    def addExtraShells(self):
707        """
[f46f6dc]708        Add a combobox for multiple shell display
[60af928]709        """
[4d457df]710        param_name, param_length = FittingUtilities.getMultiplicity(self.model_parameters)
[f46f6dc]711
712        if param_length == 0:
713            return
714
[6f7f652]715        # cell 1: variable name
[f46f6dc]716        item1 = QtGui.QStandardItem(param_name)
717
[60af928]718        func = QtGui.QComboBox()
[b1e36a3]719        # Available range of shells displayed in the combobox
720        func.addItems([str(i) for i in xrange(param_length+1)])
721        # Respond to index change
[86f88d1]722        func.currentIndexChanged.connect(self.modifyShellsInList)
[60af928]723
[6f7f652]724        # cell 2: combobox
[f46f6dc]725        item2 = QtGui.QStandardItem()
726        self._model_model.appendRow([item1, item2])
[60af928]727
[6f7f652]728        # Beautify the row:  span columns 2-4
[60af928]729        shell_row = self._model_model.rowCount()
[f46f6dc]730        shell_index = self._model_model.index(shell_row-1, 1)
[86f88d1]731
[4d457df]732        self.lstParams.setIndexWidget(shell_index, func)
[86f88d1]733        self._last_model_row = self._model_model.rowCount()
734
735    def modifyShellsInList(self, index):
736        """
737        Add/remove additional multishell parameters
738        """
739        # Find row location of the combobox
740        last_row = self._last_model_row
741        remove_rows = self._model_model.rowCount() - last_row
742
743        if remove_rows > 1:
744            self._model_model.removeRows(last_row, remove_rows)
745
[4d457df]746        FittingUtilities.addShellsToModel(self.model_parameters, self._model_model, index)
[60af928]747
748    def togglePoly(self, isChecked):
749        """
[6f7f652]750        Enable/disable the polydispersity tab
[60af928]751        """
752        self.tabFitting.setTabEnabled(TAB_POLY, isChecked)
753
754    def toggleMagnetism(self, isChecked):
755        """
[6f7f652]756        Enable/disable the magnetism tab
[60af928]757        """
758        self.tabFitting.setTabEnabled(TAB_MAGNETISM, isChecked)
759
760    def toggle2D(self, isChecked):
761        """
[6f7f652]762        Enable/disable the controls dependent on 1D/2D data instance
[60af928]763        """
764        self.chkMagnetism.setEnabled(isChecked)
765        self.is2D = isChecked
766
Note: See TracBrowser for help on using the repository browser.