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

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

Multishell parameters support - prototype SASVIEW-346

  • Property mode set to 100755
File size: 14.3 KB
Line 
1import sys
2import json
3import  os
4from collections import defaultdict
5
6from PyQt4 import QtGui
7from PyQt4 import QtCore
8
9from UI.FittingWidgetUI import Ui_FittingWidgetUI
10
11from sasmodels import generate
12from sasmodels import modelinfo
13from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
14
15TAB_MAGNETISM = 4
16TAB_POLY = 3
17
18class FittingWidget(QtGui.QWidget, Ui_FittingWidgetUI):
19    """
20    Main widget for selecting form and structure factor models
21    """
22    def __init__(self, manager=None, parent=None, data=None):
23        """
24
25        :param manager:
26        :param parent:
27        :return:
28        """
29        super(FittingWidget, self).__init__()
30
31        self.model_is_loaded = False
32        self._data = data
33        self.is2D = False
34        self.modelHasShells = False
35        self.data_assigned = False
36
37        self.setupUi(self)
38
39        self.setWindowTitle("Fitting")
40
41        # set the main models
42        self._model_model = QtGui.QStandardItemModel()
43        self._poly_model = QtGui.QStandardItemModel()
44        self._magnet_model = QtGui.QStandardItemModel()
45
46        # Param model displayed in param list
47        self.lstParams.setModel(self._model_model)
48        self._readCategoryInfo()
49        self.model_parameters = None
50
51        # Poly model displayed in poly list
52        self.lstPoly.setModel(self._poly_model)
53        self.setPolyModel()
54        self.setTableProperties(self.lstPoly)
55
56        # Magnetism model displayed in magnetism list
57        self.lstMagnetic.setModel(self._magnet_model)
58        self.setMagneticModel()
59        self.setTableProperties(self.lstMagnetic)
60
61        # Fill in the combo boxes
62        structure_factor_list = self.master_category_dict.pop('Structure Factor')
63        for (structure_factor, enabled) in structure_factor_list:
64            self.cbStructureFactor.addItem(structure_factor)
65
66        category_list = sorted(self.master_category_dict.keys())
67        self.cbCategory.addItems(category_list)
68
69        category = self.cbCategory.currentText()
70        model_list = self.master_category_dict[str(category)]
71        for (model, enabled) in model_list:
72            self.cbModel.addItem(model)
73
74        # Connect GUI element signals
75        self.cbStructureFactor.currentIndexChanged.connect(self.selectStructureFactor)
76        self.cbCategory.currentIndexChanged.connect(self.selectCategory)
77        self.cbModel.currentIndexChanged.connect(self.selectModel)
78        self.chk2DView.toggled.connect(self.toggle2D)
79        self.chkPolydispersity.toggled.connect(self.togglePoly)
80        self.chkMagnetism.toggled.connect(self.toggleMagnetism)
81
82        # Set initial control enablement
83        self.cmdFit.setEnabled(False)
84        self.cmdPlot.setEnabled(True)
85        self.chkPolydispersity.setEnabled(True)
86        self.chkPolydispersity.setCheckState(False)
87        self.chk2DView.setEnabled(True)
88        self.chk2DView.setCheckState(False)
89        self.chkMagnetism.setEnabled(False)
90        self.chkMagnetism.setCheckState(False)
91
92        self.tabFitting.setTabEnabled(TAB_POLY, False)
93        self.tabFitting.setTabEnabled(TAB_MAGNETISM, False)
94
95        # set initial labels
96        self.lblMinRangeDef.setText("---")
97        self.lblMaxRangeDef.setText("---")
98        self.lblChi2Value.setText("---")
99
100    @property
101    def data(self):
102        return self._data
103
104    @data.setter
105    def data(self, value):
106        """ data setter """
107        self._data = value
108        self.data_assigned = True
109        # TODO: update ranges, chi2 etc
110
111    def acceptsData(self):
112        """ Tells the caller this widget can accept new dataset """
113        return not self.data_assigned
114
115    def selectCategory(self):
116        """
117        Select Category from list
118        :return:
119        """
120        self.cbModel.clear()
121        category = self.cbCategory.currentText()
122        model_list = self.master_category_dict[str(category)]
123        for (model, enabled) in model_list:
124            self.cbModel.addItem(model)
125
126    def selectModel(self):
127        """
128        Select Model from list
129        :return:
130        """
131        model = self.cbModel.currentText()
132        self.setModelModel(model)
133
134    def selectStructureFactor(self):
135        """
136        Select Structure Factor from list
137        :param:
138        :return:
139        """
140
141    def _readCategoryInfo(self):
142        """
143        Reads the categories in from file
144        """
145        self.master_category_dict = defaultdict(list)
146        self.by_model_dict = defaultdict(list)
147        self.model_enabled_dict = defaultdict(bool)
148
149        try:
150            categorization_file = CategoryInstaller.get_user_file()
151            if not os.path.isfile(categorization_file):
152                categorization_file = CategoryInstaller.get_default_file()
153            cat_file = open(categorization_file, 'rb')
154            self.master_category_dict = json.load(cat_file)
155            self._regenerate_model_dict()
156            cat_file.close()
157        except IOError:
158            raise
159            print 'Problem reading in category file.'
160            print 'We even looked for it, made sure it was there.'
161            print 'An existential crisis if there ever was one.'
162
163    def _regenerate_model_dict(self):
164        """
165        regenerates self.by_model_dict which has each model name as the
166        key and the list of categories belonging to that model
167        along with the enabled mapping
168        """
169        self.by_model_dict = defaultdict(list)
170        for category in self.master_category_dict:
171            for (model, enabled) in self.master_category_dict[category]:
172                self.by_model_dict[model].append(category)
173                self.model_enabled_dict[model] = enabled
174
175    def checkMultiplicity(self, model):
176        """
177        """
178        iter_param = ""
179        iter_length = 0
180        for param in model.iq_parameters:
181            name = param.name
182            if "[" in name:
183                # pull out the iterator parameter name
184                #iter_param = name[name.index('[')+1:-1]
185                iter_length = param.length
186                iter_param = param.length_control
187        return (iter_param, iter_length)
188       
189    def setModelModel(self, model_name):
190        """
191        Setting model parameters into table based on selected
192        :param model_name:
193        :return:
194        """
195        # Crete/overwrite model items
196        self._model_model.clear()
197        model_name = str(model_name)
198        kernel_module = generate.load_kernel_module(model_name)
199        self.model_parameters = modelinfo.make_parameter_table(getattr(kernel_module, 'parameters', []))
200
201        #TODO: scaale and background are implicit in sasmodels and needs to be added
202        item1 = QtGui.QStandardItem('scale')
203        item1.setCheckable(True)
204        item2 = QtGui.QStandardItem('1.0')
205        item3 = QtGui.QStandardItem('0.0')
206        item4 = QtGui.QStandardItem('inf')
207        item5 = QtGui.QStandardItem('')
208        self._model_model.appendRow([item1, item2, item3, item4, item5])
209
210        item1 = QtGui.QStandardItem('background')
211        item1.setCheckable(True)
212        item2 = QtGui.QStandardItem('0.001')
213        item3 = QtGui.QStandardItem('-inf')
214        item4 = QtGui.QStandardItem('inf')
215        item5 = QtGui.QStandardItem('1/cm')
216        self._model_model.appendRow([item1, item2, item3, item4, item5])
217
218        multishell_param_name, multishell_param_length = self.checkMultiplicity(self.model_parameters)
219        multishell_param_fullname = "[%s]" % multishell_param_name
220        #TODO: iq_parameters are used here. If orientation paramateres or magnetic are needed
221        # kernel_paramters should be used instead
222        #For orientation and magentic parameters param.type needs to be checked
223        for param in self.model_parameters.iq_parameters:
224            # don't include shell parameters
225            if param.name == multishell_param_name:
226                continue
227            # Modify parameter name from <param>[n] to <param>1
228            item_name = param.name
229            if multishell_param_fullname in param.name:
230                item_name = self.replaceShellName(param.name, 1)
231            item1 = QtGui.QStandardItem(item_name)
232            item1.setCheckable(True)
233            item2 = QtGui.QStandardItem(str(param.default))
234            item3 = QtGui.QStandardItem(str(param.limits[0]))
235            item4 = QtGui.QStandardItem(str(param.limits[1]))
236            item5 = QtGui.QStandardItem(param.units)
237            self._model_model.appendRow([item1, item2, item3, item4, item5])
238
239        self._model_model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Parameter"))
240        self._model_model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("Value"))
241        self._model_model.setHeaderData(2, QtCore.Qt.Horizontal, QtCore.QVariant("Min"))
242        self._model_model.setHeaderData(3, QtCore.Qt.Horizontal, QtCore.QVariant("Max"))
243        self._model_model.setHeaderData(4, QtCore.Qt.Horizontal, QtCore.QVariant("[Units]"))
244
245        self.addExtraShells()
246
247        self.setPolyModel()
248        self.setMagneticModel()
249        self.model_is_loaded = True
250
251    def replaceShellName(self, param_name, value):
252        """
253        Updates parameter name from <param_name>[n_shell] to <param_name>value
254        """
255        new_name  = param_name[:param_name.index('[')]+str(value)
256        return new_name
257
258    def setTableProperties(self, table):
259        """
260        Setting table properties
261        :param table:
262        :return:
263        """
264        # Table properties
265        table.verticalHeader().setVisible(False)
266        table.setAlternatingRowColors(True)
267        table.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)
268        table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
269        table.resizeColumnsToContents()
270
271        # Header
272        header = table.horizontalHeader()
273        header.setResizeMode(QtGui.QHeaderView.ResizeToContents)
274
275        header.ResizeMode(QtGui.QHeaderView.Interactive)
276        header.setResizeMode(0, QtGui.QHeaderView.ResizeToContents)
277        header.setResizeMode(6, QtGui.QHeaderView.ResizeToContents)
278
279    def setPolyModel(self):
280        """
281        Set polydispersity values
282        """
283        if self.model_parameters:
284            for row, param in enumerate(self.model_parameters.form_volume_parameters):
285                item1 = QtGui.QStandardItem("Distribution of "+param.name)
286                item1.setCheckable(True)
287                item2 = QtGui.QStandardItem("0")
288                item3 = QtGui.QStandardItem("")
289                item4 = QtGui.QStandardItem("")
290                item5 = QtGui.QStandardItem("35")
291                item6 = QtGui.QStandardItem("3")
292                item7 = QtGui.QStandardItem("")
293
294                self._poly_model.appendRow([item1, item2, item3, item4, item5, item6, item7])
295
296                #TODO: Need to find cleaner way to input functions
297                func = QtGui.QComboBox()
298                func.addItems(['rectangle','array','lognormal','gaussian','schulz',])
299                func_index = self.lstPoly.model().index(row,6)
300                self.lstPoly.setIndexWidget(func_index,func)
301
302        self._poly_model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Parameter"))
303        self._poly_model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("PD[ratio]"))
304        self._poly_model.setHeaderData(2, QtCore.Qt.Horizontal, QtCore.QVariant("Min"))
305        self._poly_model.setHeaderData(3, QtCore.Qt.Horizontal, QtCore.QVariant("Max"))
306        self._poly_model.setHeaderData(4, QtCore.Qt.Horizontal, QtCore.QVariant("Npts"))
307        self._poly_model.setHeaderData(5, QtCore.Qt.Horizontal, QtCore.QVariant("Nsigs"))
308        self._poly_model.setHeaderData(6, QtCore.Qt.Horizontal, QtCore.QVariant("Function"))
309
310    def setMagneticModel(self):
311        """
312        Set magnetism values on model
313        """
314        if self.model_parameters:
315            for row, param in enumerate(self.model_parameters.form_volume_parameters):
316                item1 = QtGui.QStandardItem("Distribution of "+param.name)
317                item1.setCheckable(True)
318                item2 = QtGui.QStandardItem("0")
319                item3 = QtGui.QStandardItem("")
320                item4 = QtGui.QStandardItem("")
321                item5 = QtGui.QStandardItem("35")
322                item6 = QtGui.QStandardItem("3")
323                item7 = QtGui.QStandardItem("")
324
325                self._magnet_model.appendRow([item1, item2, item3, item4, item5, item6, item7])
326
327                #TODO: Need to find cleaner way to input functions
328                func = QtGui.QComboBox()
329                func.addItems(['rectangle','array','lognormal','gaussian','schulz',])
330                func_index = self.lstMagnetic.model().index(row,6)
331                self.lstMagnetic.setIndexWidget(func_index,func)
332
333        self._magnet_model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Parameter"))
334        self._magnet_model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("PD[ratio]"))
335        self._magnet_model.setHeaderData(2, QtCore.Qt.Horizontal, QtCore.QVariant("Min"))
336        self._magnet_model.setHeaderData(3, QtCore.Qt.Horizontal, QtCore.QVariant("Max"))
337        self._magnet_model.setHeaderData(4, QtCore.Qt.Horizontal, QtCore.QVariant("Npts"))
338        self._magnet_model.setHeaderData(5, QtCore.Qt.Horizontal, QtCore.QVariant("Nsigs"))
339        self._magnet_model.setHeaderData(6, QtCore.Qt.Horizontal, QtCore.QVariant("Function"))
340
341    def addExtraShells(self):
342        """
343        Add a combobox for multiple shell display
344        """
345        param_name, param_length = self.checkMultiplicity(self.model_parameters)
346
347        if param_length == 0:
348            return
349
350        item1 = QtGui.QStandardItem(param_name)
351
352        func = QtGui.QComboBox()
353        func.addItems([str(i+1) for i in xrange(param_length)])
354
355        item2 = QtGui.QStandardItem()
356        self._model_model.appendRow([item1, item2])
357
358        shell_row = self._model_model.rowCount()
359        shell_index = self._model_model.index(shell_row-1, 1)
360        self.lstParams.setIndexWidget(shell_index, func)
361        self.lstParams.setSpan(shell_row-1,2,2,4)
362
363    def togglePoly(self, isChecked):
364        """
365        """
366        self.tabFitting.setTabEnabled(TAB_POLY, isChecked)
367
368    def toggleMagnetism(self, isChecked):
369        """
370        """
371        self.tabFitting.setTabEnabled(TAB_MAGNETISM, isChecked)
372
373    def toggle2D(self, isChecked):
374        """
375        """
376        self.chkMagnetism.setEnabled(isChecked)
377        self.is2D = isChecked
378
Note: See TracBrowser for help on using the repository browser.