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

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 a9b568c was a9b568c, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Sprint demo issues addressed.

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