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

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

Default datasets for fitting SASVIEW-498

  • Property mode set to 100755
File size: 28.3 KB
Line 
1import sys
2import json
3import  os
4import numpy
5from collections import defaultdict
6
7import logging
8import traceback
9
10
11from PyQt4 import QtGui
12from PyQt4 import QtCore
13
14from sasmodels import generate
15from sasmodels import modelinfo
16from sasmodels.sasview_model import load_standard_models
17
18from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
19from sas.sasgui.guiframe.dataFitting import Data1D
20from sas.sasgui.guiframe.dataFitting import Data2D
21import sas.qtgui.GuiUtils as GuiUtils
22from sas.sascalc.dataloader.data_info import Detector
23from sas.sascalc.dataloader.data_info import Source
24from sas.sasgui.perspectives.fitting.model_thread import Calc1D
25
26from UI.FittingWidgetUI import Ui_FittingWidgetUI
27
28TAB_MAGNETISM = 4
29TAB_POLY = 3
30CATEGORY_DEFAULT="Choose category..."
31
32class FittingWidget(QtGui.QWidget, Ui_FittingWidgetUI):
33    """
34    Main widget for selecting form and structure factor models
35    """
36    signalTheory =  QtCore.pyqtSignal(QtGui.QStandardItem)
37
38    def __init__(self, manager=None, parent=None, data=None, id=1):
39        """
40
41        :param manager:
42        :param parent:
43        :return:
44        """
45        super(FittingWidget, self).__init__()
46
47        # Necessary globals
48        self.model_is_loaded = False
49        self.data_is_loaded = False
50        self.kernel_module = None
51        self.is2D = False
52        self.model_has_shells = False
53        self._previous_category_index = 0
54        self._last_model_row = 0
55        self._current_parameter_name = None
56        self.models = {}
57
58        # Which tab is this widget displayed in?
59        self.tab_id = id
60
61        # Parameters
62        self.q_range_min = 0.0005
63        self.q_range_max = 0.5
64        self.npts = 20
65        self._data = None
66
67        # Main GUI setup up
68        self.setupUi(self)
69        self.setWindowTitle("Fitting")
70        self.communicate = GuiUtils.Communicate()
71
72        # Set the main models
73        self._model_model = QtGui.QStandardItemModel()
74        self._poly_model = QtGui.QStandardItemModel()
75        self._magnet_model = QtGui.QStandardItemModel()
76        # Proxy model for custom views on the main _model_model
77        self.proxyModel = QtGui.QSortFilterProxyModel()
78
79        # Param model displayed in param list
80        self.lstParams.setModel(self._model_model)
81        self.readCategoryInfo()
82        self.model_parameters = None
83        self.lstParams.setAlternatingRowColors(True)
84
85        # Poly model displayed in poly list
86        self.lstPoly.setModel(self._poly_model)
87        self.setPolyModel()
88        self.setTableProperties(self.lstPoly)
89
90        # Magnetism model displayed in magnetism list
91        self.lstMagnetic.setModel(self._magnet_model)
92        self.setMagneticModel()
93        self.setTableProperties(self.lstMagnetic)
94
95        # Defaults for the structure factors
96        self.setDefaultStructureCombo()
97
98        # Make structure factor and model CBs disabled
99        self.disableModelCombo()
100        self.disableStructureCombo()
101
102        # Generate the category list for display
103        category_list = sorted(self.master_category_dict.keys())
104        self.cbCategory.addItem(CATEGORY_DEFAULT)
105        self.cbCategory.addItems(category_list)
106        self.cbCategory.addItem("Structure Factor")
107        self.cbCategory.setCurrentIndex(0)
108
109        self._index = data
110        if data is not None:
111            self.data = data
112
113        # Connect signals to controls
114        self.initializeSignals()
115
116        # Initial control state
117        self.initializeControls()
118
119    @property
120    def data(self):
121        return self._data
122
123    @data.setter
124    def data(self, value):
125        """ data setter """
126        self._index = value
127        self._data = GuiUtils.dataFromItem(value[0])
128        self.data_is_loaded = True
129        self.updateQRange()
130        self.cmdFit.setEnabled(True)
131
132    def acceptsData(self):
133        """ Tells the caller this widget can accept new dataset """
134        return not self.data_is_loaded
135
136    def disableModelCombo(self):
137        self.cbModel.setEnabled(False)
138        self.label_3.setEnabled(False)
139
140    def enableModelCombo(self):
141        self.cbModel.setEnabled(True)
142        self.label_3.setEnabled(True)
143
144    def disableStructureCombo(self):
145        self.cbStructureFactor.setEnabled(False)
146        self.label_4.setEnabled(False)
147
148    def enableStructureCombo(self):
149        self.cbStructureFactor.setEnabled(True)
150        self.label_4.setEnabled(True)
151
152    def updateQRange(self):
153        """
154        Updates Q Range display
155        """
156        if self.data_is_loaded:
157            self.q_range_min, self.q_range_max, self.npts = self.computeDataRange(self.data)
158        # set Q range labels
159        self.lblMinRangeDef.setText(str(self.q_range_min))
160        self.lblMaxRangeDef.setText(str(self.q_range_max))
161
162        self.txtMaxRange.setText(str(self.q_range_max))
163        self.txtMinRange.setText(str(self.q_range_min))
164        self.txtNpts.setText(str(self.npts))
165
166    def initializeControls(self):
167        """
168        Set initial control enablement
169        """
170        self.cmdFit.setEnabled(False)
171        self.cmdPlot.setEnabled(True)
172        self.chkPolydispersity.setEnabled(True)
173        self.chkPolydispersity.setCheckState(False)
174        self.chk2DView.setEnabled(True)
175        self.chk2DView.setCheckState(False)
176        self.chkMagnetism.setEnabled(False)
177        self.chkMagnetism.setCheckState(False)
178        # tabs
179        self.tabFitting.setTabEnabled(TAB_POLY, False)
180        self.tabFitting.setTabEnabled(TAB_MAGNETISM, False)
181        self.lblChi2Value.setText("---")
182   
183        # Update Q Ranges
184        self.updateQRange()
185
186    def initializeSignals(self):
187        """
188        Connect GUI element signals
189        """
190        self.cbStructureFactor.currentIndexChanged.connect(self.selectStructureFactor)
191        self.cbCategory.currentIndexChanged.connect(self.selectCategory)
192        self.cbModel.currentIndexChanged.connect(self.selectModel)
193        self.chk2DView.toggled.connect(self.toggle2D)
194        self.chkPolydispersity.toggled.connect(self.togglePoly)
195        self.chkMagnetism.toggled.connect(self.toggleMagnetism)
196        self.cmdFit.clicked.connect(self.onFit)
197
198    def setDefaultStructureCombo(self):
199        # Fill in the structure factors combo box with defaults
200        structure_factor_list = self.master_category_dict.pop('Structure Factor')
201        structure_factors = []
202        self.cbStructureFactor.clear()
203        for (structure_factor, _) in structure_factor_list:
204            structure_factors.append(structure_factor)
205        self.cbStructureFactor.addItems(sorted(structure_factors))
206
207    def selectCategory(self):
208        """
209        Select Category from list
210        :return:
211        """
212        category = self.cbCategory.currentText()
213        # Check if the user chose "Choose category entry"
214        if str(category) == CATEGORY_DEFAULT:
215            # if the previous category was not the default, keep it.
216            # Otherwise, just return
217            if self._previous_category_index != 0:
218                self.cbCategory.setCurrentIndex(self._previous_category_index)
219            return
220
221        if category == "Structure Factor":
222            self.disableModelCombo()
223            self.enableStructureCombo()
224            return
225
226        self.cbModel.blockSignals(True)
227        self.cbModel.clear()
228        self.cbModel.blockSignals(False)
229        self.enableModelCombo()
230        self.disableStructureCombo()
231
232        self._previous_category_index = self.cbCategory.currentIndex()
233        model_list = self.master_category_dict[str(category)]
234        models = []
235        for (model, _) in model_list:
236            models.append(model)
237        self.cbModel.addItems(sorted(models))
238
239    def selectModel(self):
240        """
241        Respond to select Model from list event
242        """
243        model = self.cbModel.currentText()
244        self._current_parameter_name = model
245
246        # SasModel -> QModel
247        self.setModelModel(model)
248
249        if self._index is None:
250            if self.is2D:
251                self.createDefault2dData()
252            else:
253                self.createDefault1dData()
254            self.createTheoryIndex()
255        else:
256            # TODO: 2D case
257            # TODO: attach the chart to index
258            self.calculate1DForModel()
259
260    def selectStructureFactor(self):
261        """
262        Select Structure Factor from list
263        :param:
264        :return:
265        """
266        model = self.cbStructureFactor.currentText()
267        self.setModelModel(model)
268
269    def readCategoryInfo(self):
270        """
271        Reads the categories in from file
272        """
273        self.master_category_dict = defaultdict(list)
274        self.by_model_dict = defaultdict(list)
275        self.model_enabled_dict = defaultdict(bool)
276
277        try:
278            categorization_file = CategoryInstaller.get_user_file()
279            if not os.path.isfile(categorization_file):
280                categorization_file = CategoryInstaller.get_default_file()
281            cat_file = open(categorization_file, 'rb')
282            self.master_category_dict = json.load(cat_file)
283            self.regenerateModelDict()
284            cat_file.close()
285        except IOError:
286            raise
287            print 'Problem reading in category file.'
288            print 'We even looked for it, made sure it was there.'
289            print 'An existential crisis if there ever was one.'
290
291        # Load the model dict
292        models = load_standard_models()
293        for model in models:
294            self.models[model.name] = model
295
296    def regenerateModelDict(self):
297        """
298        regenerates self.by_model_dict which has each model name as the
299        key and the list of categories belonging to that model
300        along with the enabled mapping
301        """
302        self.by_model_dict = defaultdict(list)
303        for category in self.master_category_dict:
304            for (model, enabled) in self.master_category_dict[category]:
305                self.by_model_dict[model].append(category)
306                self.model_enabled_dict[model] = enabled
307
308    def getIterParams(self, model):
309        """
310        Returns a list of all multi-shell parameters in 'model'
311        """
312        iter_params = list(filter(lambda par: "[" in par.name, model.iq_parameters))
313
314        return iter_params
315
316    def getMultiplicity(self, model):
317        """
318        Finds out if 'model' has multishell parameters.
319        If so, returns the name of the counter parameter and the number of shells
320        """
321        iter_param = ""
322        iter_length = 0
323
324        iter_params = self.getIterParams(model)
325        # pull out the iterator parameter name and length
326        if iter_params:
327            iter_length = iter_params[0].length
328            iter_param = iter_params[0].length_control
329        return (iter_param, iter_length)
330
331    def addBackgroundToModel(self, model):
332        """
333        Adds background parameter with default values to the model
334        """
335        assert(isinstance(model, QtGui.QStandardItemModel))
336
337        checked_list = ['background', '0.001', '-inf', 'inf', '1/cm']
338        self.addCheckedListToModel(model, checked_list)
339
340    def addScaleToModel(self, model):
341        """
342        Adds scale parameter with default values to the model
343        """
344        assert(isinstance(model, QtGui.QStandardItemModel))
345
346        checked_list = ['scale', '1.0', '0.0', 'inf', '']
347        self.addCheckedListToModel(model, checked_list)
348
349    def addCheckedListToModel(self, model, param_list):
350        assert(isinstance(model, QtGui.QStandardItemModel))
351        item_list = [QtGui.QStandardItem(item) for item in param_list]
352        item_list[0].setCheckable(True)
353        model.appendRow(item_list)
354
355    def addHeadersToModel(self, model):
356        """
357        Adds predefined headers to the model
358        """
359        model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Parameter"))
360        model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("Value"))
361        model.setHeaderData(2, QtCore.Qt.Horizontal, QtCore.QVariant("Min"))
362        model.setHeaderData(3, QtCore.Qt.Horizontal, QtCore.QVariant("Max"))
363        model.setHeaderData(4, QtCore.Qt.Horizontal, QtCore.QVariant("[Units]"))
364
365    def addPolyHeadersToModel(self, model):
366        """
367        Adds predefined headers to the model
368        """
369        model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Parameter"))
370        model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("PD[ratio]"))
371        model.setHeaderData(2, QtCore.Qt.Horizontal, QtCore.QVariant("Min"))
372        model.setHeaderData(3, QtCore.Qt.Horizontal, QtCore.QVariant("Max"))
373        model.setHeaderData(4, QtCore.Qt.Horizontal, QtCore.QVariant("Npts"))
374        model.setHeaderData(5, QtCore.Qt.Horizontal, QtCore.QVariant("Nsigs"))
375        model.setHeaderData(6, QtCore.Qt.Horizontal, QtCore.QVariant("Function"))
376
377    def setModelModel(self, model_name):
378        """
379        Setting model parameters into table based on selected
380        :param model_name:
381        """
382        # Crete/overwrite model items
383        self._model_model.clear()
384        model_name = str(model_name)
385
386        kernel_module = generate.load_kernel_module(model_name)
387        #model_info = modelinfo.make_model_info(kernel_module)
388        #self.kernel_module = _make_model_from_info(model_info)
389        self.model_parameters = modelinfo.make_parameter_table(getattr(kernel_module, 'parameters', []))
390
391        # Instantiate the current model
392        self.kernel_module = self.models[model_name]()
393
394        # Explicitly add scale and background with default values
395        self.addScaleToModel(self._model_model)
396        self.addBackgroundToModel(self._model_model)
397
398        # Update the QModel
399        self.addParametersToModel(self.model_parameters, self._model_model)
400        self.addHeadersToModel(self._model_model)
401        # Multishell models need additional treatment
402        self.addExtraShells()
403
404        # Add polydispersity to the model
405        self.setPolyModel()
406        # Add magnetic parameters to the model
407        self.setMagneticModel()
408
409        # Now we claim the model has been loaded
410        self.model_is_loaded = True
411
412        # Update Q Ranges
413        self.updateQRange()
414
415    def computeDataRange(self, data):
416        """
417        compute the minimum and the maximum range of the data
418        return the npts contains in data
419        """
420        assert(data is not None)
421        assert((isinstance(data, Data1D) or isinstance(data, Data2D)))
422        qmin, qmax, npts = None, None, None
423        if isinstance(data, Data1D):
424            try:
425                qmin = min(data.x)
426                qmax = max(data.x)
427                npts = len(data.x)
428            except:
429                msg = "Unable to find min/max/length of \n data named %s" % \
430                            data.filename
431                raise ValueError, msg
432
433        else:
434            qmin = 0
435            try:
436                x = max(numpy.fabs(data.xmin), numpy.fabs(data.xmax))
437                y = max(numpy.fabs(data.ymin), numpy.fabs(data.ymax))
438            except:
439                msg = "Unable to find min/max of \n data named %s" % \
440                            data.filename
441                raise ValueError, msg
442            qmax = math.sqrt(x * x + y * y)
443            npts = len(data.data)
444        return qmin, qmax, npts
445
446    def addParametersToModel(self, parameters, model):
447        """
448        Update local ModelModel with sasmodel parameters
449        """
450        multishell_parameters = self.getIterParams(parameters)
451        multishell_param_name, _ = self.getMultiplicity(parameters)
452
453        #TODO: iq_parameters are used here. If orientation paramateres or magnetic are needed
454        # kernel_paramters should be used instead
455        for param in parameters.iq_parameters:
456            # don't include shell parameters
457            if param.name == multishell_param_name:
458                continue
459            # Modify parameter name from <param>[n] to <param>1
460            item_name = param.name
461            if param in multishell_parameters:
462                item_name = self.replaceShellName(param.name, 1)
463
464            item1 = QtGui.QStandardItem(item_name)
465            item1.setCheckable(True)
466            # check for polydisp params
467            if param.polydisperse:
468                poly_item = QtGui.QStandardItem("Polydispersity")
469                item1_1 = QtGui.QStandardItem("Distribution")
470                # Find param in volume_params
471                for p in parameters.form_volume_parameters:
472                    if p.name == param.name:
473                        item1_2 = QtGui.QStandardItem(str(p.default))
474                        item1_3 = QtGui.QStandardItem(str(p.limits[0]))
475                        item1_4 = QtGui.QStandardItem(str(p.limits[1]))
476                        item1_5 = QtGui.QStandardItem(p.units)
477                        poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5])
478                        break
479
480                item1.appendRow([poly_item])
481
482            item2 = QtGui.QStandardItem(str(param.default))
483            item3 = QtGui.QStandardItem(str(param.limits[0]))
484            item4 = QtGui.QStandardItem(str(param.limits[1]))
485            item5 = QtGui.QStandardItem(param.units)
486            model.appendRow([item1, item2, item3, item4, item5])
487
488        self._last_model_row = self._model_model.rowCount()
489
490    def createDefault1dData(self):
491        """
492        Create default data for fitting perspective
493        Only when the page is on theory mode.
494        """
495        x = numpy.linspace(start=self.q_range_min, stop=self.q_range_max,
496                           num=self.npts, endpoint=True)
497        self._data = Data1D(x=x)
498        self._data.xaxis('\\rm{Q}', "A^{-1}")
499        self._data.yaxis('\\rm{Intensity}', "cm^{-1}")
500        self._data.is_data = False
501        self._data.id = str(self.tab_id) + " data"
502        self._data.group_id = str(self.tab_id) + " Model1D"
503
504    def createDefault2dData(self):
505        """
506        Create 2D data by default
507        Only when the page is on theory mode.
508        """
509        self._data = Data2D()
510        qmax = self.q_range_max / numpy.sqrt(2)
511        self._data.xaxis('\\rm{Q_{x}}', 'A^{-1}')
512        self._data.yaxis('\\rm{Q_{y}}', 'A^{-1}')
513        self._data.is_data = False
514        self._data.id = str(self.tab_id) + " data"
515        self._data.group_id = str(self.tab_id) + " Model2D"
516
517        # Default detector
518        self._data.detector.append(Detector())
519        index = len(self._data.detector) - 1
520        self._data.detector[index].distance = 8000   # mm
521        self._data.source.wavelength = 6             # A
522        self._data.detector[index].pixel_size.x = 5  # mm
523        self._data.detector[index].pixel_size.y = 5  # mm
524        self._data.detector[index].beam_center.x = qmax
525        self._data.detector[index].beam_center.y = qmax
526        # theory default: assume the beam
527        #center is located at the center of sqr detector
528        xmax = qmax
529        xmin = -qmax
530        ymax = qmax
531        ymin = -qmax
532        qstep = self.npts
533
534        x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
535        y = numpy.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
536        # Use data info instead
537        new_x = numpy.tile(x, (len(y), 1))
538        new_y = numpy.tile(y, (len(x), 1))
539        new_y = new_y.swapaxes(0, 1)
540
541        # all data required in 1d array
542        qx_data = new_x.flatten()
543        qy_data = new_y.flatten()
544        q_data = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
545
546        # set all True (standing for unmasked) as default
547        mask = numpy.ones(len(qx_data), dtype=bool)
548        # calculate the range of qx and qy: this way,
549        # it is a little more independent
550        # store x and y bin centers in q space
551        x_bins = x
552        y_bins = y
553
554        self._data.source = Source()
555        self._data.data = numpy.ones(len(mask))
556        self._data.err_data = numpy.ones(len(mask))
557        self._data.qx_data = qx_data
558        self._data.qy_data = qy_data
559        self._data.q_data = q_data
560        self._data.mask = mask
561        self._data.x_bins = x_bins
562        self._data.y_bins = y_bins
563        # max and min taking account of the bin sizes
564        self._data.xmin = xmin
565        self._data.xmax = xmax
566        self._data.ymin = ymin
567        self._data.ymax = ymax
568
569    def createTheoryIndex(self):
570        """
571        Create a QStandardModelIndex containing default model data
572        """
573        name = self._current_parameter_name
574        if self.is2D:
575            name += "2d"
576        name = "M%i [%s]" % (self.tab_id, name)
577        new_item = GuiUtils.createModelItemWithPlot(QtCore.QVariant(self.data), name=name)
578        self.signalTheory.emit(new_item)
579
580    def onFit(self):
581        """
582        Perform fitting on the current data
583        """
584        # TEST FOR DISPLAY.
585        self.calculate1DForModel()
586
587    def calculate1DForModel(self):
588        """
589        Prepare the fitting data object, based on current ModelModel
590        """
591        data = self.data
592        model = self.kernel_module
593        page_id = 0
594        qmin = self.q_range_min
595        qmax = self.q_range_max
596        smearer = None
597        state = None
598        weight = None
599        fid = None
600        toggle_mode_on = False
601        update_chisqr = False
602        source = None
603
604        self.calc_1D = Calc1D(data=data,
605                              model=model,
606                              page_id=page_id,
607                              qmin=qmin,
608                              qmax=qmax,
609                              smearer=smearer,
610                              state=state,
611                              weight=weight,
612                              fid=fid,
613                              toggle_mode_on=toggle_mode_on,
614                              completefn=self.complete1D,
615                              update_chisqr=update_chisqr,
616                              exception_handler=self.calcException,
617                              source=source)
618        self.calc_1D.queue()
619
620    def complete1D(self, x, y, page_id, elapsed, index, model,
621                   weight=None, fid=None,
622                   toggle_mode_on=False, state=None,
623                   data=None, update_chisqr=True,
624                   source='model', plot_result=True):
625        """
626        Plot the current data
627        Should be a rewrite of fitting.py/_complete1D
628        """
629        print "THREAD FINISHED"
630
631    def calcException(self, etype, value, tb):
632        """
633        """
634        print "THREAD EXCEPTION"
635        logging.error("".join(traceback.format_exception(etype, value, tb)))
636        msg = traceback.format_exception(etype, value, tb, limit=1)
637
638    def replaceShellName(self, param_name, value):
639        """
640        Updates parameter name from <param_name>[n_shell] to <param_name>value
641        """
642        assert('[' in param_name)
643        return param_name[:param_name.index('[')]+str(value)
644
645    def setTableProperties(self, table):
646        """
647        Setting table properties
648        :param table:
649        :return:
650        """
651        # Table properties
652        table.verticalHeader().setVisible(False)
653        table.setAlternatingRowColors(True)
654        table.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)
655        table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
656        table.resizeColumnsToContents()
657
658        # Header
659        header = table.horizontalHeader()
660        header.setResizeMode(QtGui.QHeaderView.ResizeToContents)
661
662        header.ResizeMode(QtGui.QHeaderView.Interactive)
663        header.setResizeMode(0, QtGui.QHeaderView.ResizeToContents)
664        header.setResizeMode(6, QtGui.QHeaderView.ResizeToContents)
665
666    def setPolyModel(self):
667        """
668        Set polydispersity values
669        """
670        ### TODO: apply proper proxy model filtering from the main _model_model
671
672        if not self.model_parameters:
673            return
674        self._poly_model.clear()
675        for row, param in enumerate(self.model_parameters.form_volume_parameters):
676            # Counters should not be included
677            if not param.polydisperse:
678                continue
679
680            # Potential multishell params
681            #length_control = param.length_control
682            #if length_control in param.name:
683
684            checked_list = ["Distribution of "+param.name, str(param.default),
685                            str(param.limits[0]),str(param.limits[1]),
686                            "35", "3", ""]
687            self.addCheckedListToModel(self._poly_model, checked_list)
688
689            #TODO: Need to find cleaner way to input functions
690            func = QtGui.QComboBox()
691            func.addItems(['rectangle','array','lognormal','gaussian','schulz',])
692            func_index = self.lstPoly.model().index(row,6)
693            self.lstPoly.setIndexWidget(func_index,func)
694
695        self.addPolyHeadersToModel(self._poly_model)
696
697    def setMagneticModel(self):
698        """
699        Set magnetism values on model
700        """
701        if not self.model_parameters:
702            return
703        self._magnet_model.clear()
704        for param in self.model_parameters.call_parameters:
705            if param.type != "magnetic":
706                continue
707            checked_list = [param.name,
708                            str(param.default),
709                            str(param.limits[0]),
710                            str(param.limits[1]),
711                            param.units]
712            self.addCheckedListToModel(self._magnet_model, checked_list)
713
714        self.addHeadersToModel(self._magnet_model)
715
716    def addExtraShells(self):
717        """
718        Add a combobox for multiple shell display
719        """
720        param_name, param_length = self.getMultiplicity(self.model_parameters)
721
722        if param_length == 0:
723            return
724
725        # cell 1: variable name
726        item1 = QtGui.QStandardItem(param_name)
727
728        func = QtGui.QComboBox()
729        func.addItems([str(i+1) for i in xrange(param_length)])
730        func.currentIndexChanged.connect(self.modifyShellsInList)
731
732        # cell 2: combobox
733        item2 = QtGui.QStandardItem()
734        self._model_model.appendRow([item1, item2])
735
736        # Beautify the row:  span columns 2-4
737        shell_row = self._model_model.rowCount()
738        shell_index = self._model_model.index(shell_row-1, 1)
739        self.lstParams.setIndexWidget(shell_index, func)
740
741        self._last_model_row = self._model_model.rowCount()
742
743
744    def modifyShellsInList(self, index):
745        """
746        Add/remove additional multishell parameters
747        """
748        # Find row location of the combobox
749        last_row = self._last_model_row
750        remove_rows = self._model_model.rowCount() - last_row
751
752        if remove_rows > 1:
753            self._model_model.removeRows(last_row, remove_rows)
754
755        multishell_parameters = self.getIterParams(self.model_parameters)
756
757        for i in xrange(index):
758            for par in multishell_parameters:
759                param_name = self.replaceShellName(par.name, i+2)
760                #param_name = str(p.name) + str(i+2)
761                item1 = QtGui.QStandardItem(param_name)
762                item1.setCheckable(True)
763                # check for polydisp params
764                if par.polydisperse:
765                    poly_item = QtGui.QStandardItem("Polydispersity")
766                    item1_1 = QtGui.QStandardItem("Distribution")
767                    # Find param in volume_params
768                    for p in self.model_parameters.form_volume_parameters:
769                        if p.name == par.name:
770                            item1_2 = QtGui.QStandardItem(str(p.default))
771                            item1_3 = QtGui.QStandardItem(str(p.limits[0]))
772                            item1_4 = QtGui.QStandardItem(str(p.limits[1]))
773                            item1_5 = QtGui.QStandardItem(p.units)
774                            poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5])
775                            break
776                    item1.appendRow([poly_item])
777
778                item2 = QtGui.QStandardItem(str(par.default))
779                item3 = QtGui.QStandardItem(str(par.limits[0]))
780                item4 = QtGui.QStandardItem(str(par.limits[1]))
781                item5 = QtGui.QStandardItem(par.units)
782                self._model_model.appendRow([item1, item2, item3, item4, item5])
783
784    def togglePoly(self, isChecked):
785        """
786        Enable/disable the polydispersity tab
787        """
788        self.tabFitting.setTabEnabled(TAB_POLY, isChecked)
789
790    def toggleMagnetism(self, isChecked):
791        """
792        Enable/disable the magnetism tab
793        """
794        self.tabFitting.setTabEnabled(TAB_MAGNETISM, isChecked)
795
796    def toggle2D(self, isChecked):
797        """
798        Enable/disable the controls dependent on 1D/2D data instance
799        """
800        self.chkMagnetism.setEnabled(isChecked)
801        self.is2D = isChecked
802
Note: See TracBrowser for help on using the repository browser.