- Timestamp:
- Sep 7, 2018 10:53:02 AM (6 years ago)
- Branches:
- ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
- Children:
- c0de493
- Parents:
- 8136e09 (diff), f0365a2e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - Location:
- src/sas/qtgui
- Files:
-
- 1 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/MainWindow/DataExplorer.py
rfd7ef36 r60d55a7 560 560 # Now query the model item for available plots 561 561 plots = GuiUtils.plotsFromFilename(filename, model) 562 ids_keys = list(self.active_plots.keys())563 ids_vals = [val.data.id for val in self.active_plots.values()]564 562 565 563 new_plots = [] 566 564 for item, plot in plots.items(): 567 plot_id = plot.id 568 if plot_id in ids_keys: 569 self.active_plots[plot_id].replacePlot(plot_id, plot) 570 elif plot_id in ids_vals: 571 list(self.active_plots.values())[ids_vals.index(plot_id)].replacePlot(plot_id, plot) 572 else: 565 if not self.updatePlot(plot): 573 566 # Don't plot intermediate results, e.g. P(Q), S(Q) 574 match = GuiUtils.theory_plot_ID_pattern.match(plot _id)567 match = GuiUtils.theory_plot_ID_pattern.match(plot.id) 575 568 # 2nd match group contains the identifier for the intermediate result, if present (e.g. "[P(Q)]") 576 569 if match and match.groups()[1] != None: … … 706 699 self.active_plots[plot_set.id] = old_plot 707 700 708 def updatePlot(self, new_data): 709 """ 710 Modify existing plot for immediate response 711 """ 712 data = new_data[0] 701 def updatePlot(self, data): 702 """ 703 Modify existing plot for immediate response and returns True. 704 Returns false, if the plot does not exist already. 705 """ 706 try: # there might be a list or a single value being passed 707 data = data[0] 708 except TypeError: 709 pass 713 710 assert type(data).__name__ in ['Data1D', 'Data2D'] 714 711 … … 719 716 if data_id in ids_keys: 720 717 self.active_plots[data_id].replacePlot(data_id, data) 718 return True 721 719 elif data_id in ids_vals: 722 720 list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data) 721 return True 722 return False 723 723 724 724 def chooseFiles(self): -
src/sas/qtgui/Perspectives/Fitting/FittingLogic.py
rb4d05bd rdcabba7 161 161 Create a new 1D data instance based on fitting results 162 162 """ 163 # Unpack return data from Calc1D 164 x, y, page_id, state, weight,\ 165 fid, toggle_mode_on, \ 166 elapsed, index, model, \ 167 data, update_chisqr, source, \ 168 unsmeared_output, unsmeared_data, unsmeared_error, \ 169 pq_values, sq_values = return_data 170 171 return self._create1DPlot(tab_id, x, y, model, data) 163 164 return self._create1DPlot(tab_id, return_data['x'], return_data['y'], 165 return_data['model'], return_data['data']) 172 166 173 167 def new2DPlot(self, return_data): … … 175 169 Create a new 2D data instance based on fitting results 176 170 """ 177 image , data, page_id, model, state, toggle_mode_on,\178 elapsed, index, fid, qmin, qmax, weight, \179 update_chisqr, source = return_data171 image = return_data['image'] 172 data = return_data['data'] 173 model = return_data['model'] 180 174 181 175 np.nan_to_num(image) … … 183 177 new_plot.name = model.name + '2d' 184 178 new_plot.title = "Analytical model 2D " 185 new_plot.id = str( page_id) + " " + data.name186 new_plot.group_id = str( page_id) + " Model2D"179 new_plot.id = str(return_data['page_id']) + " " + data.name 180 new_plot.group_id = str(return_data['page_id']) + " Model2D" 187 181 new_plot.detector = data.detector 188 182 new_plot.source = data.source … … 218 212 (pq_plot, sq_plot). If either are unavailable, the corresponding plot is None. 219 213 """ 220 # Unpack return data from Calc1D221 x, y, page_id, state, weight, \222 fid, toggle_mode_on, \223 elapsed, index, model, \224 data, update_chisqr, source, \225 unsmeared_output, unsmeared_data, unsmeared_error, \226 pq_values, sq_values = return_data227 214 228 215 pq_plot = None 229 216 sq_plot = None 230 217 231 if pq_values is not None: 232 pq_plot = self._create1DPlot(tab_id, x, pq_values, model, data, component="P(Q)") 233 if sq_values is not None: 234 sq_plot = self._create1DPlot(tab_id, x, sq_values, model, data, component="S(Q)") 218 if return_data.get('pq_values', None) is not None: 219 pq_plot = self._create1DPlot(tab_id, return_data['x'], 220 return_data['pq_values'], return_data['model'], 221 return_data['data'], component="P(Q)") 222 if return_data.get('sq_values', None) is not None: 223 sq_plot = self._create1DPlot(tab_id, return_data['x'], 224 return_data['sq_values'], return_data['model'], 225 return_data['data'], component="S(Q)") 235 226 236 227 return pq_plot, sq_plot -
src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
rb764ae5 r01b4877 8 8 from sas.qtgui.Plotting.PlotterData import Data1D 9 9 from sas.qtgui.Plotting.PlotterData import Data2D 10 11 from sas.qtgui.Perspectives.Fitting.AssociatedComboBox import AssociatedComboBox 10 12 11 13 model_header_captions = ['Parameter', 'Value', 'Min', 'Max', 'Units'] … … 61 63 return (param_name, param_length) 62 64 63 def addParametersToModel(parameters, kernel_module, is2D): 64 """ 65 Update local ModelModel with sasmodel parameters 65 def createFixedChoiceComboBox(param, item_row): 66 """ 67 Determines whether param is a fixed-choice parameter, modifies items in item_row appropriately and returns a combo 68 box containing the fixed choices. Returns None if param is not fixed-choice. 69 70 item_row is a list of QStandardItem objects for insertion into the parameter table. 71 """ 72 73 # Determine whether this is a fixed-choice parameter. There are lots of conditionals, simply because the 74 # implementation is not yet concrete; there are several possible indicators that the parameter is fixed-choice. 75 # TODO: (when the sasmodels implementation is concrete, clean this up) 76 choices = None 77 if isinstance(param.choices, (list, tuple)) and len(param.choices) > 0: 78 # The choices property is concrete in sasmodels, probably will use this 79 choices = param.choices 80 elif isinstance(param.units, (list, tuple)): 81 choices = [str(x) for x in param.units] 82 83 cbox = None 84 if choices is not None: 85 # Use combo box for input, if it is fixed-choice 86 cbox = AssociatedComboBox(item_row[1], idx_as_value=True) 87 cbox.addItems(choices) 88 item_row[2].setEditable(False) 89 item_row[3].setEditable(False) 90 91 return cbox 92 93 def addParametersToModel(parameters, kernel_module, is2D, model=None, view=None): 94 """ 95 Update local ModelModel with sasmodel parameters. 96 Actually appends to model, if model and view params are not None. 97 Always returns list of lists of QStandardItems. 66 98 """ 67 99 multishell_parameters = getIterParams(parameters) … … 72 104 else: 73 105 params = parameters.iq_parameters 74 item = [] 106 107 rows = [] 75 108 for param in params: 76 109 # don't include shell parameters 77 110 if param.name == multishell_param_name: 78 111 continue 112 79 113 # Modify parameter name from <param>[n] to <param>1 80 114 item_name = param.name 81 115 if param in multishell_parameters: 82 116 continue 83 # item_name = replaceShellName(param.name, 1)84 117 85 118 item1 = QtGui.QStandardItem(item_name) 86 119 item1.setCheckable(True) 87 120 item1.setEditable(False) 88 # item_err = QtGui.QStandardItem() 121 89 122 # check for polydisp params 90 123 if param.polydisperse: … … 93 126 item1_1 = QtGui.QStandardItem("Distribution") 94 127 item1_1.setEditable(False) 128 95 129 # Find param in volume_params 96 130 for p in parameters.form_volume_parameters: … … 99 133 width = kernel_module.getParam(p.name+'.width') 100 134 ptype = kernel_module.getParam(p.name+'.type') 101 102 135 item1_2 = QtGui.QStandardItem(str(width)) 103 136 item1_2.setEditable(False) … … 110 143 poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 111 144 break 145 112 146 # Add the polydisp item as a child 113 147 item1.appendRow([poly_item]) 148 114 149 # Param values 115 150 item2 = QtGui.QStandardItem(str(param.default)) 116 # TODO: the error column.117 # Either add a proxy model or a custom view delegate118 #item_err = QtGui.QStandardItem()119 151 item3 = QtGui.QStandardItem(str(param.limits[0])) 120 152 item4 = QtGui.QStandardItem(str(param.limits[1])) 121 item5 = QtGui.QStandardItem( param.units)153 item5 = QtGui.QStandardItem(str(param.units)) 122 154 item5.setEditable(False) 123 item.append([item1, item2, item3, item4, item5]) 124 return item 125 126 def addSimpleParametersToModel(parameters, is2D): 127 """ 128 Update local ModelModel with sasmodel parameters 155 156 # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 157 row = [item1, item2, item3, item4, item5] 158 cbox = createFixedChoiceComboBox(param, row) 159 160 # Append to the model and use the combobox, if required 161 if None not in (model, view): 162 model.appendRow(row) 163 if cbox: 164 view.setIndexWidget(item2.index(), cbox) 165 rows.append(row) 166 167 return rows 168 169 def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=None, row_num=None): 170 """ 171 Update local ModelModel with sasmodel parameters (non-dispersed, non-magnetic) 172 Actually appends to model, if model and view params are not None. 173 Always returns list of lists of QStandardItems. 174 175 parameters_original: list of parameters before any tagging on their IDs, e.g. for product model (so that those are 176 the display names; see below) 129 177 """ 130 178 if is2D: … … 132 180 else: 133 181 params = parameters.iq_parameters 134 item = [] 135 for param in params: 182 183 if parameters_original: 184 # 'parameters_original' contains the parameters as they are to be DISPLAYED, while 'parameters' 185 # contains the parameters as they were renamed; this is for handling name collisions in product model. 186 # The 'real name' of the parameter will be stored in the item's user data. 187 if is2D: 188 params_orig = [p for p in parameters_original.kernel_parameters if p.type != 'magnetic'] 189 else: 190 params_orig = parameters_original.iq_parameters 191 else: 192 # no difference in names anyway 193 params_orig = params 194 195 rows = [] 196 for param, param_orig in zip(params, params_orig): 136 197 # Create the top level, checkable item 137 item_name = param .name198 item_name = param_orig.name 138 199 item1 = QtGui.QStandardItem(item_name) 200 item1.setData(param.name, QtCore.Qt.UserRole) 139 201 item1.setCheckable(True) 140 202 item1.setEditable(False) 203 141 204 # Param values 142 205 # TODO: add delegate for validation of cells 143 206 item2 = QtGui.QStandardItem(str(param.default)) 144 item4 = QtGui.QStandardItem(str(param.limits[0])) 145 item5 = QtGui.QStandardItem(str(param.limits[1])) 146 item6 = QtGui.QStandardItem(param.units) 147 item6.setEditable(False) 148 item.append([item1, item2, item4, item5, item6]) 149 return item 207 item3 = QtGui.QStandardItem(str(param.limits[0])) 208 item4 = QtGui.QStandardItem(str(param.limits[1])) 209 item5 = QtGui.QStandardItem(str(param.units)) 210 item5.setEditable(False) 211 212 # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 213 row = [item1, item2, item3, item4, item5] 214 cbox = createFixedChoiceComboBox(param, row) 215 216 # Append to the model and use the combobox, if required 217 if None not in (model, view): 218 if row_num is None: 219 model.appendRow(row) 220 else: 221 model.insertRow(row_num, row) 222 row_num += 1 223 224 if cbox: 225 view.setIndexWidget(item2.index(), cbox) 226 227 rows.append(row) 228 229 return rows 150 230 151 231 def markParameterDisabled(model, row): … … 182 262 model.appendRow(item_list) 183 263 264 def addHeadingRowToModel(model, name): 265 """adds a non-interactive top-level row to the model""" 266 header_row = [QtGui.QStandardItem() for i in range(5)] 267 header_row[0].setText(name) 268 269 font = header_row[0].font() 270 font.setBold(True) 271 header_row[0].setFont(font) 272 273 for item in header_row: 274 item.setEditable(False) 275 item.setCheckable(False) 276 item.setSelectable(False) 277 278 model.appendRow(header_row) 279 184 280 def addHeadersToModel(model): 185 281 """ … … 227 323 model.header_tooltips = copy.copy(poly_header_error_tooltips) 228 324 229 def addShellsToModel(parameters, model, index): 230 """ 231 Find out multishell parameters and update the model with the requested number of them 325 def addShellsToModel(parameters, model, index, row_num=None, view=None): 326 """ 327 Find out multishell parameters and update the model with the requested number of them. 328 Inserts them after the row at row_num, if not None; otherwise, appends to end. 329 If view param is not None, supports fixed-choice params. 330 Returns a list of lists of QStandardItem objects. 232 331 """ 233 332 multishell_parameters = getIterParams(parameters) 234 333 334 rows = [] 235 335 for i in range(index): 236 336 for par in multishell_parameters: … … 250 350 item1_3 = QtGui.QStandardItem(str(p.limits[0])) 251 351 item1_4 = QtGui.QStandardItem(str(p.limits[1])) 252 item1_5 = QtGui.QStandardItem( p.units)352 item1_5 = QtGui.QStandardItem(str(p.units)) 253 353 poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 254 354 break … … 258 358 item3 = QtGui.QStandardItem(str(par.limits[0])) 259 359 item4 = QtGui.QStandardItem(str(par.limits[1])) 260 item5 = QtGui.QStandardItem(par.units) 261 model.appendRow([item1, item2, item3, item4, item5]) 360 item5 = QtGui.QStandardItem(str(par.units)) 361 item5.setEditable(False) 362 363 # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 364 row = [item1, item2, item3, item4, item5] 365 cbox = createFixedChoiceComboBox(par, row) 366 367 # Always add to the model 368 if row_num is None: 369 model.appendRow(row) 370 else: 371 model.insertRow(row_num, row) 372 row_num += 1 373 374 # Apply combobox if required 375 if None not in (view, cbox): 376 view.setIndexWidget(item2.index(), cbox) 377 378 rows.append(row) 379 380 return rows 262 381 263 382 def calculateChi2(reference_data, current_data): -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r8136e09 r01b4877 91 91 fittingFinishedSignal = QtCore.pyqtSignal(tuple) 92 92 batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 93 Calc1DFinishedSignal = QtCore.pyqtSignal( tuple)94 Calc2DFinishedSignal = QtCore.pyqtSignal( tuple)93 Calc1DFinishedSignal = QtCore.pyqtSignal(dict) 94 Calc2DFinishedSignal = QtCore.pyqtSignal(dict) 95 95 96 96 def __init__(self, parent=None, data=None, tab_id=1): … … 219 219 # Utility variable to enable unselectable option in category combobox 220 220 self._previous_category_index = 0 221 # Utility variable for multishell display 222 self._last_model_row = 0 221 # Utility variables for multishell display 222 self._n_shells_row = 0 223 self._num_shell_params = 0 223 224 # Dictionary of {model name: model class} for the current category 224 225 self.models = {} … … 676 677 Return list of all parameters for the current model 677 678 """ 678 return [self._model_model.item(row).text() for row in range(self._model_model.rowCount())] 679 return [self._model_model.item(row).text() 680 for row in range(self._model_model.rowCount()) 681 if self.isCheckable(row)] 679 682 680 683 def modifyViewOnRow(self, row, font=None, brush=None): … … 704 707 assert isinstance(constraint, Constraint) 705 708 assert 0 <= row <= self._model_model.rowCount() 709 assert self.isCheckable(row) 706 710 707 711 item = QtGui.QStandardItem() … … 724 728 max_col = self.lstParams.itemDelegate().param_max 725 729 for row in self.selectedParameters(): 730 assert(self.isCheckable(row)) 726 731 param = self._model_model.item(row, 0).text() 727 732 value = self._model_model.item(row, 1).text() … … 766 771 max_col = self.lstParams.itemDelegate().param_max 767 772 for row in range(self._model_model.rowCount()): 773 if not self.isCheckable(row): 774 continue 768 775 if not self.rowHasConstraint(row): 769 776 continue … … 794 801 For the given row, return its constraint, if any 795 802 """ 796 try:803 if self.isCheckable(row): 797 804 item = self._model_model.item(row, 1) 798 return item.child(0).data() 799 except AttributeError: 800 # return none when no constraints 801 return None 805 try: 806 return item.child(0).data() 807 except AttributeError: 808 # return none when no constraints 809 pass 810 return None 802 811 803 812 def rowHasConstraint(self, row): … … 805 814 Finds out if row of the main model has a constraint child 806 815 """ 807 item = self._model_model.item(row, 1) 808 if item.hasChildren(): 809 c = item.child(0).data() 810 if isinstance(c, Constraint): 811 return True 816 if self.isCheckable(row): 817 item = self._model_model.item(row, 1) 818 if item.hasChildren(): 819 c = item.child(0).data() 820 if isinstance(c, Constraint): 821 return True 812 822 return False 813 823 … … 816 826 Finds out if row of the main model has an active constraint child 817 827 """ 818 item = self._model_model.item(row, 1) 819 if item.hasChildren(): 820 c = item.child(0).data() 821 if isinstance(c, Constraint) and c.active: 822 return True 828 if self.isCheckable(row): 829 item = self._model_model.item(row, 1) 830 if item.hasChildren(): 831 c = item.child(0).data() 832 if isinstance(c, Constraint) and c.active: 833 return True 823 834 return False 824 835 … … 827 838 Finds out if row of the main model has an active, nontrivial constraint child 828 839 """ 829 item = self._model_model.item(row, 1) 830 if item.hasChildren(): 831 c = item.child(0).data() 832 if isinstance(c, Constraint) and c.func and c.active: 833 return True 840 if self.isCheckable(row): 841 item = self._model_model.item(row, 1) 842 if item.hasChildren(): 843 c = item.child(0).data() 844 if isinstance(c, Constraint) and c.func and c.active: 845 return True 834 846 return False 835 847 … … 1495 1507 # update charts 1496 1508 self.onPlot() 1509 #self.recalculatePlotData() 1510 1497 1511 1498 1512 # Read only value - we can get away by just printing it here … … 1577 1591 # internal so can use closure for param_dict 1578 1592 param_name = str(self._model_model.item(row, 0).text()) 1579 if param_name not in list(param_dict.keys()):1593 if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 1580 1594 return 1581 1595 # modify the param value 1582 1596 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1583 1597 self._model_model.item(row, 1).setText(param_repr) 1598 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1584 1599 if self.has_error_column: 1585 1600 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) … … 1589 1604 # Utility function for updateof polydispersity part of the main model 1590 1605 param_name = str(self._model_model.item(row, 0).text())+'.width' 1591 if param_name not in list(param_dict.keys()):1606 if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 1592 1607 return 1593 1608 # modify the param value … … 1623 1638 poly_item.insertColumn(2, [QtGui.QStandardItem("")]) 1624 1639 1625 # block signals temporarily, so we don't end up1626 # updating charts with every single model change on the end of fitting1627 self._model_model.blockSignals(True)1628 1629 1640 if not self.has_error_column: 1630 1641 # create top-level error column … … 1633 1644 self.iterateOverModel(createErrorColumn) 1634 1645 1635 # we need to enable signals for this, otherwise the final column mysteriously disappears (don't ask, I don't1636 # know)1637 self._model_model.blockSignals(False)1638 1646 self._model_model.insertColumn(2, error_column) 1639 self._model_model.blockSignals(True)1640 1647 1641 1648 FittingUtilities.addErrorHeadersToModel(self._model_model) … … 1646 1653 self.has_error_column = True 1647 1654 1655 # block signals temporarily, so we don't end up 1656 # updating charts with every single model change on the end of fitting 1657 self._model_model.itemChanged.disconnect() 1648 1658 self.iterateOverModel(updateFittedValues) 1649 1659 self.iterateOverModel(updatePolyValues) 1650 1651 self._model_model.blockSignals(False) 1660 self._model_model.itemChanged.connect(self.onMainParamsChange) 1652 1661 1653 1662 # Adjust the table cells width. … … 1684 1693 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1685 1694 self._poly_model.item(row_i, 1).setText(param_repr) 1695 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1686 1696 if self.has_poly_error_column: 1687 1697 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 1688 1698 self._poly_model.item(row_i, 2).setText(error_repr) 1689 1690 1699 1691 1700 def createErrorColumn(row_i): … … 1708 1717 # block signals temporarily, so we don't end up 1709 1718 # updating charts with every single model change on the end of fitting 1710 self._poly_model. blockSignals(True)1719 self._poly_model.itemChanged.disconnect() 1711 1720 self.iterateOverPolyModel(updateFittedValues) 1712 self._poly_model. blockSignals(False)1721 self._poly_model.itemChanged.connect(self.onPolyModelChange) 1713 1722 1714 1723 if self.has_poly_error_column: … … 1720 1729 1721 1730 # switch off reponse to model change 1722 self._poly_model.blockSignals(True)1723 1731 self._poly_model.insertColumn(2, error_column) 1724 self._poly_model.blockSignals(False)1725 1732 FittingUtilities.addErrorPolyHeadersToModel(self._poly_model) 1726 1733 … … 1755 1762 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1756 1763 self._magnet_model.item(row, 1).setText(param_repr) 1764 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1757 1765 if self.has_magnet_error_column: 1758 1766 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) … … 1774 1782 # block signals temporarily, so we don't end up 1775 1783 # updating charts with every single model change on the end of fitting 1776 self._magnet_model. blockSignals(True)1784 self._magnet_model.itemChanged.disconnect() 1777 1785 self.iterateOverMagnetModel(updateFittedValues) 1778 self._magnet_model. blockSignals(False)1786 self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 1779 1787 1780 1788 if self.has_magnet_error_column: … … 1786 1794 1787 1795 # switch off reponse to model change 1788 self._magnet_model.blockSignals(True)1789 1796 self._magnet_model.insertColumn(2, error_column) 1790 self._magnet_model.blockSignals(False)1791 1797 FittingUtilities.addErrorHeadersToModel(self._magnet_model) 1792 1798 … … 1800 1806 self.cmdPlot.setText("Show Plot") 1801 1807 # Force data recalculation so existing charts are updated 1808 self.showPlot() 1802 1809 self.recalculatePlotData() 1803 self.showPlot()1804 1810 1805 1811 def onSmearingOptionsUpdate(self): … … 1966 1972 # Crete/overwrite model items 1967 1973 self._model_model.clear() 1968 1969 # First, add parameters from the main model 1970 if model_name is not None: 1974 self._poly_model.clear() 1975 self._magnet_model.clear() 1976 1977 if model_name is None: 1978 if structure_factor not in (None, "None"): 1979 # S(Q) on its own, treat the same as a form factor 1980 self.kernel_module = None 1981 self.fromStructureFactorToQModel(structure_factor) 1982 else: 1983 # No models selected 1984 return 1985 else: 1971 1986 self.fromModelToQModel(model_name) 1972 1973 # Then, add structure factor derived parameters 1974 if structure_factor is not None and structure_factor != "None": 1975 if model_name is None: 1976 # Instantiate the current sasmodel for SF-only models 1977 self.kernel_module = self.models[structure_factor]() 1978 self.fromStructureFactorToQModel(structure_factor) 1979 else: 1987 self.addExtraShells() 1988 1980 1989 # Allow the SF combobox visibility for the given sasmodel 1981 1990 self.enableStructureFactorControl(structure_factor) 1991 1992 # Add S(Q) 1982 1993 if self.cbStructureFactor.isEnabled(): 1983 1994 structure_factor = self.cbStructureFactor.currentText() 1984 1995 self.fromStructureFactorToQModel(structure_factor) 1985 1996 1986 # Then, add multishells 1987 if model_name is not None: 1988 # Multishell models need additional treatment 1989 self.addExtraShells() 1990 1991 # Add polydispersity to the model 1992 self.poly_params = {} 1993 self.setPolyModel() 1994 # Add magnetic parameters to the model 1995 self.magnet_params = {} 1996 self.setMagneticModel() 1997 # Add polydispersity to the model 1998 self.poly_params = {} 1999 self.setPolyModel() 2000 # Add magnetic parameters to the model 2001 self.magnet_params = {} 2002 self.setMagneticModel() 1997 2003 1998 2004 # Adjust the table cells width … … 2067 2073 self.shell_names = self.shellNamesList() 2068 2074 2075 # Add heading row 2076 FittingUtilities.addHeadingRowToModel(self._model_model, model_name) 2077 2069 2078 # Update the QModel 2070 new_rows = FittingUtilities.addParametersToModel(self.model_parameters, self.kernel_module, self.is2D)2071 2072 for row in new_rows:2073 self._model_model.appendRow(row)2074 # Update the counter used for multishell display2075 self._last_model_row = self._model_model.rowCount()2079 FittingUtilities.addParametersToModel( 2080 self.model_parameters, 2081 self.kernel_module, 2082 self.is2D, 2083 self._model_model, 2084 self.lstParams) 2076 2085 2077 2086 def fromStructureFactorToQModel(self, structure_factor): … … 2081 2090 if structure_factor is None or structure_factor=="None": 2082 2091 return 2083 structure_module = generate.load_kernel_module(structure_factor) 2084 structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', [])) 2085 2086 structure_kernel = self.models[structure_factor]() 2087 form_kernel = self.kernel_module 2088 2089 self.kernel_module = MultiplicationModel(form_kernel, structure_kernel) 2090 2091 new_rows = FittingUtilities.addSimpleParametersToModel(structure_parameters, self.is2D) 2092 for row in new_rows: 2093 self._model_model.appendRow(row) 2094 # disable fitting of parameters not listed in self.kernel_module (probably radius_effective) 2095 if row[0].text() not in self.kernel_module.params.keys(): 2096 row_num = self._model_model.rowCount() - 1 2097 FittingUtilities.markParameterDisabled(self._model_model, row_num) 2098 2099 # grab list of params injected by sasmodels.product 2100 # (only supporting sasmodels master until ESS_GUI merge!!!) 2101 num_p_params = len(form_kernel._model_info.parameters.kernel_parameters) 2102 num_s_params = len(structure_kernel._model_info.parameters.kernel_parameters) 2103 product_params = modelinfo.ParameterTable( 2104 self.kernel_module._model_info.parameters.kernel_parameters[num_p_params+num_s_params-1:]) 2105 product_rows = FittingUtilities.addSimpleParametersToModel(product_params, self.is2D) 2106 2107 # product params should go at the top of the list, below scale & background 2108 row_num = 2 2109 for row in product_rows: 2110 self._model_model.insertRow(row_num, row) 2111 row_num += 1 2112 2113 # Update the counter used for multishell display 2114 self._last_model_row = self._model_model.rowCount() 2092 2093 product_params = None 2094 2095 if self.kernel_module is None: 2096 # Structure factor is the only selected model; build it and show all its params 2097 self.kernel_module = self.models[structure_factor]() 2098 s_params = self.kernel_module._model_info.parameters 2099 s_params_orig = s_params 2100 else: 2101 s_kernel = self.models[structure_factor]() 2102 p_kernel = self.kernel_module 2103 2104 p_pars_len = len(p_kernel._model_info.parameters.kernel_parameters) 2105 s_pars_len = len(s_kernel._model_info.parameters.kernel_parameters) 2106 2107 self.kernel_module = MultiplicationModel(p_kernel, s_kernel) 2108 all_params = self.kernel_module._model_info.parameters.kernel_parameters 2109 all_param_names = [param.name for param in all_params] 2110 2111 # S(Q) params from the product model are not necessarily the same as those from the S(Q) model; any 2112 # conflicting names with P(Q) params will cause a rename 2113 2114 if "radius_effective_mode" in all_param_names: 2115 # Show all parameters 2116 # In this case, radius_effective is NOT pruned by sasmodels.product 2117 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len]) 2118 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters) 2119 product_params = modelinfo.ParameterTable( 2120 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len:]) 2121 else: 2122 # Ensure radius_effective is not displayed 2123 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters[1:]) 2124 if "radius_effective" in all_param_names: 2125 # In this case, radius_effective is NOT pruned by sasmodels.product 2126 s_params = modelinfo.ParameterTable(all_params[p_pars_len+1:p_pars_len+s_pars_len]) 2127 product_params = modelinfo.ParameterTable( 2128 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len:]) 2129 else: 2130 # In this case, radius_effective is pruned by sasmodels.product 2131 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len-1]) 2132 product_params = modelinfo.ParameterTable( 2133 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len-1:]) 2134 2135 # Add heading row 2136 FittingUtilities.addHeadingRowToModel(self._model_model, structure_factor) 2137 2138 # Get new rows for QModel 2139 # Any renamed parameters are stored as data in the relevant item, for later handling 2140 FittingUtilities.addSimpleParametersToModel( 2141 parameters=s_params, 2142 is2D=self.is2D, 2143 parameters_original=s_params_orig, 2144 model=self._model_model, 2145 view=self.lstParams) 2146 2147 # Insert product-only params into QModel 2148 if product_params: 2149 prod_rows = FittingUtilities.addSimpleParametersToModel( 2150 parameters=product_params, 2151 is2D=self.is2D, 2152 parameters_original=None, 2153 model=self._model_model, 2154 view=self.lstParams, 2155 row_num=2) 2156 2157 # Since this all happens after shells are dealt with and we've inserted rows, fix this counter 2158 self._n_shells_row += len(prod_rows) 2115 2159 2116 2160 def haveParamsToFit(self): … … 2138 2182 model_row = item.row() 2139 2183 name_index = self._model_model.index(model_row, 0) 2184 name_item = self._model_model.itemFromIndex(name_index) 2140 2185 2141 2186 # Extract changed value. … … 2146 2191 return 2147 2192 2148 parameter_name = str(self._model_model.data(name_index)) # sld, background etc. 2193 # if the item has user data, this is the actual parameter name (e.g. to handle duplicate names) 2194 if name_item.data(QtCore.Qt.UserRole): 2195 parameter_name = str(name_item.data(QtCore.Qt.UserRole)) 2196 else: 2197 parameter_name = str(self._model_model.data(name_index)) 2149 2198 2150 2199 # Update the parameter value - note: this supports +/-inf as well … … 2380 2429 new_plots.append(sq_data) 2381 2430 2382 # Update/generate plots2383 2431 for plot in new_plots: 2384 2432 self.communicate.plotUpdateSignal.emit([plot]) … … 2580 2628 def updateFunctionCaption(row): 2581 2629 # Utility function for update of polydispersity function name in the main model 2630 if not self.isCheckable(row): 2631 return 2582 2632 self._model_model.blockSignals(True) 2583 2633 param_name = str(self._model_model.item(row, 0).text()) … … 2752 2802 2753 2803 self.lstParams.setIndexWidget(shell_index, func) 2754 self._ last_model_row = self._model_model.rowCount()2804 self._n_shells_row = shell_row - 1 2755 2805 2756 2806 # Set the index to the state-kept value … … 2763 2813 """ 2764 2814 # Find row location of the combobox 2765 last_row = self._last_model_row2766 remove_rows = self._ model_model.rowCount() - last_row2815 first_row = self._n_shells_row + 1 2816 remove_rows = self._num_shell_params 2767 2817 2768 2818 if remove_rows > 1: 2769 self._model_model.removeRows(last_row, remove_rows) 2770 2771 FittingUtilities.addShellsToModel(self.model_parameters, self._model_model, index) 2819 self._model_model.removeRows(first_row, remove_rows) 2820 2821 new_rows = FittingUtilities.addShellsToModel( 2822 self.model_parameters, 2823 self._model_model, 2824 index, 2825 first_row, 2826 self.lstParams) 2827 2828 self._num_shell_params = len(new_rows) 2772 2829 self.current_shell_displayed = index 2773 2830 -
src/sas/qtgui/Perspectives/Fitting/ModelThread.py
r2df558e rdcabba7 101 101 elapsed = time.time() - self.starttime 102 102 103 res = dict(image = output, data = self.data, page_id = self.page_id, 104 model = self.model, state = self.state, 105 toggle_mode_on = self.toggle_mode_on, elapsed = elapsed, 106 index = index_model, fid = self.fid, 107 qmin = self.qmin, qmax = self.qmax, 108 weight = self.weight, update_chisqr = self.update_chisqr, 109 source = self.source) 110 103 111 if LocalConfig.USING_TWISTED: 104 return (output, 105 self.data, 106 self.page_id, 107 self.model, 108 self.state, 109 self.toggle_mode_on, 110 elapsed, 111 index_model, 112 self.fid, 113 self.qmin, 114 self.qmax, 115 self.weight, 116 self.update_chisqr, 117 self.source) 118 else: 119 self.completefn((output, 120 self.data, 121 self.page_id, 122 self.model, 123 self.state, 124 self.toggle_mode_on, 125 elapsed, 126 index_model, 127 self.fid, 128 self.qmin, 129 self.qmax, 130 self.weight, 131 #qstep=self.qstep, 132 self.update_chisqr, 133 self.source)) 134 112 return res 113 else: 114 self.completefn(res) 135 115 136 116 class Calc1D(CalcThread): … … 236 216 elapsed = time.time() - self.starttime 237 217 218 res = dict(x = self.data.x[index], y = output[index], 219 page_id = self.page_id, state = self.state, weight = self.weight, 220 fid = self.fid, toggle_mode_on = self.toggle_mode_on, 221 elapsed = elapsed, index = index, model = self.model, 222 data = self.data, update_chisqr = self.update_chisqr, 223 source = self.source, unsmeared_output = unsmeared_output, 224 unsmeared_data = unsmeared_data, unsmeared_error = unsmeared_error, 225 pq_values = pq_values, sq_values = sq_values) 226 238 227 if LocalConfig.USING_TWISTED: 239 return (self.data.x[index], output[index], 240 self.page_id, 241 self.state, 242 self.weight, 243 self.fid, 244 self.toggle_mode_on, 245 elapsed, index, self.model, 246 self.data, 247 self.update_chisqr, 248 self.source, 249 unsmeared_output, unsmeared_data, unsmeared_error, 250 pq_values, sq_values) 251 else: 252 self.completefn((self.data.x[index], output[index], 253 self.page_id, 254 self.state, 255 self.weight, 256 self.fid, 257 self.toggle_mode_on, 258 elapsed, index, self.model, 259 self.data, 260 self.update_chisqr, 261 self.source, 262 unsmeared_output, unsmeared_data, unsmeared_error, 263 pq_values, sq_values)) 228 return res 229 else: 230 self.completefn(res) 264 231 265 232 def results(self): -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
r66d4370 r4ea8020 256 256 self.widget.cbStructureFactor.setCurrentIndex(structure_index) 257 257 258 # We have 4 more rows now258 # We have 3 more param rows now (radius_effective is removed), and a new heading 259 259 self.assertEqual(self.widget._model_model.rowCount(), rowcount+4) 260 260 … … 276 276 last_index = self.widget.cbStructureFactor.count() 277 277 self.widget.cbStructureFactor.setCurrentIndex(last_index-1) 278 # Do we have all the rows ?279 self.assertEqual(self.widget._model_model.rowCount(), 4)278 # Do we have all the rows (incl. radius_effective & heading row)? 279 self.assertEqual(self.widget._model_model.rowCount(), 5) 280 280 281 281 # Are the command buttons properly enabled? … … 509 509 Test opening of the load file dialog for 'array' polydisp. function 510 510 """ 511 512 # open a non-existent file 511 513 filename = os.path.join("UnitTesting", "testdata_noexist.txt") 514 with self.assertRaises(OSError, msg="testdata_noexist.txt should be a non-existent file"): 515 os.stat(filename) 512 516 QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 513 517 self.widget.show() … … 525 529 526 530 # good file 531 # TODO: this depends on the working directory being src/sas/qtgui, 532 # TODO: which isn't convenient if you want to run this test suite 533 # TODO: individually 527 534 filename = os.path.join("UnitTesting", "testdata.txt") 535 try: 536 os.stat(filename) 537 except OSError: 538 self.assertTrue(False, "testdata.txt does not exist") 528 539 QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 529 540 … … 591 602 592 603 # Assure we have the combobox available 593 last_row = self.widget._last_model_row594 func_index = self.widget._model_model.index( last_row-1, 1)604 cbox_row = self.widget._n_shells_row 605 func_index = self.widget._model_model.index(cbox_row, 1) 595 606 self.assertIsInstance(self.widget.lstParams.indexWidget(func_index), QtWidgets.QComboBox) 607 608 # get number of rows before changing shell count 609 last_row = self.widget._model_model.rowCount() 596 610 597 611 # Change the combo box index … … 1027 1041 1028 1042 # Check the model 1029 self.assertEqual(self.widget._model_model.rowCount(), 6)1043 self.assertEqual(self.widget._model_model.rowCount(), 7) 1030 1044 self.assertEqual(self.widget._model_model.columnCount(), 5) 1031 1045 … … 1143 1157 # two rows selected 1144 1158 index1 = self.widget.lstParams.model().index(1, 0, QtCore.QModelIndex()) 1145 index2 = self.widget.lstParams.model().index( 2, 0, QtCore.QModelIndex())1159 index2 = self.widget.lstParams.model().index(3, 0, QtCore.QModelIndex()) 1146 1160 selection_model = self.widget.lstParams.selectionModel() 1147 1161 selection_model.select(index1, selection_model.Select | selection_model.Rows) … … 1179 1193 # several random parameters 1180 1194 self.assertEqual(self.widget.getRowFromName('scale'), 0) 1181 self.assertEqual(self.widget.getRowFromName('length'), 5)1195 self.assertEqual(self.widget.getRowFromName('length'), 6) 1182 1196 1183 1197 def testGetParamNames(self): … … 1216 1230 # Create a constraint object 1217 1231 const = Constraint(parent=None, value=7.0) 1218 row = 21232 row = 3 1219 1233 1220 1234 spy = QtSignalSpy(self.widget, self.widget.constraintAddedSignal) … … 1235 1249 # assign complex constraint now 1236 1250 const = Constraint(parent=None, param='radius', func='5*sld') 1237 row = 41251 row = 5 1238 1252 # call the method tested 1239 1253 self.widget.addConstraintToRow(constraint=const, row=row) … … 1294 1308 self.widget.cbModel.setCurrentIndex(model_index) 1295 1309 1310 row1 = 1 1311 row2 = 5 1312 1313 param1 = "background" 1314 param2 = "radius" 1315 1316 #default_value1 = "0.001" 1317 default_value2 = "20" 1318 1296 1319 # select two rows 1297 row1 = 11298 row2 = 41299 1320 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1300 1321 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1313 1334 1314 1335 # delete one of the constraints 1315 self.widget.deleteConstraintOnParameter(param= 'background')1336 self.widget.deleteConstraintOnParameter(param=param1) 1316 1337 1317 1338 # see that the other constraint is still present 1318 cons = self.widget.getConstraintForRow( 4) # 4 = radius1319 self.assertEqual(cons.param, "radius")1320 self.assertEqual(cons.value, "20")1339 cons = self.widget.getConstraintForRow(row2) 1340 self.assertEqual(cons.param, param2) 1341 self.assertEqual(cons.value, default_value2) 1321 1342 1322 1343 # kill the other constraint … … 1324 1345 1325 1346 # see that the other constraint is still present 1326 self.assertEqual(self.widget.getConstraintsForModel(), [( 'radius', None)])1347 self.assertEqual(self.widget.getConstraintsForModel(), [(param2, None)]) 1327 1348 1328 1349 def testGetConstraintForRow(self): … … 1344 1365 self.widget.cbModel.setCurrentIndex(model_index) 1345 1366 1367 row1 = 1 1368 row2 = 5 1369 1346 1370 # select two rows 1347 row1 = 11348 row2 = 41349 1371 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1350 1372 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1356 1378 self.widget.addSimpleConstraint() 1357 1379 1358 con_list = [False, True, False, False, True, False]1380 con_list = [False, True, False, False, False, True, False] 1359 1381 new_list = [] 1360 1382 for row in range(self.widget._model_model.rowCount()): … … 1374 1396 self.widget.cbModel.setCurrentIndex(model_index) 1375 1397 1398 row1 = 1 1399 row2 = 5 1400 1376 1401 # select two rows 1377 row1 = 11378 row2 = 41379 1402 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1380 1403 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1390 1413 constraint_objects[0].active = False 1391 1414 1392 con_list = [False, False, False, False, True, False]1415 con_list = [False, False, False, False, False, True, False] 1393 1416 new_list = [] 1394 1417 for row in range(self.widget._model_model.rowCount()): … … 1411 1434 self.assertEqual(self.widget.getConstraintsForModel(),[]) 1412 1435 1436 row1 = 1 1437 row2 = 5 1438 1439 param1 = "background" 1440 param2 = "radius" 1441 1442 default_value1 = "0.001" 1443 default_value2 = "20" 1444 1413 1445 # select two rows 1414 row1 = 11415 row2 = 41416 1446 index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 1417 1447 index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) … … 1425 1455 # simple constraints 1426 1456 # self.assertEqual(self.widget.getConstraintsForModel(), [('background', '0.001'), ('radius', '20')]) 1427 cons = self.widget.getConstraintForRow( 1) # 1 - background1428 self.assertEqual(cons.param, "background")1429 self.assertEqual(cons.value, "0.001")1430 cons = self.widget.getConstraintForRow( 4) # 4 = radius1431 self.assertEqual(cons.param, "radius")1432 self.assertEqual(cons.value, "20")1457 cons = self.widget.getConstraintForRow(row1) 1458 self.assertEqual(cons.param, param1) 1459 self.assertEqual(cons.value, default_value1) 1460 cons = self.widget.getConstraintForRow(row2) 1461 self.assertEqual(cons.param, param2) 1462 self.assertEqual(cons.value, default_value2) 1433 1463 1434 1464 objects = self.widget.getConstraintObjectsForModel() 1435 1465 self.assertEqual(len(objects), 2) 1436 self.assertEqual(objects[1].value, '20') 1437 self.assertEqual(objects[0].param, 'background') 1466 self.assertEqual(objects[1].value, default_value2) 1467 self.assertEqual(objects[0].param, param1) 1468 1469 row = 0 1470 param = "scale" 1471 func = "5*sld" 1438 1472 1439 1473 # add complex constraint 1440 const = Constraint(parent=None, param='scale', func='5*sld') 1441 row = 0 1474 const = Constraint(parent=None, param=param, func=func) 1442 1475 self.widget.addConstraintToRow(constraint=const, row=row) 1443 1476 #self.assertEqual(self.widget.getConstraintsForModel(),[('scale', '5*sld'), ('background', '0.001'), ('radius', None)]) 1444 cons = self.widget.getConstraintForRow( 4) # 4 = radius1445 self.assertEqual(cons.param, "radius")1446 self.assertEqual(cons.value, "20")1477 cons = self.widget.getConstraintForRow(row2) 1478 self.assertEqual(cons.param, param2) 1479 self.assertEqual(cons.value, default_value2) 1447 1480 1448 1481 objects = self.widget.getConstraintObjectsForModel() 1449 1482 self.assertEqual(len(objects), 3) 1450 self.assertEqual(objects[0].func, '5*sld')1483 self.assertEqual(objects[0].func, func) 1451 1484 1452 1485 def testReplaceConstraintName(self): -
src/sas/qtgui/Plotting/Plotter.py
rb764ae5 rc2f3ca2 30 30 # Dictionary of {plot_id:Data1d} 31 31 self.plot_dict = {} 32 32 # Dictionaty of {plot_id:line} 33 34 self.plot_lines = {} 33 35 # Window for text add 34 36 self.addText = AddText(self) … … 182 184 self.plot_dict[self._data.id] = self.data 183 185 186 self.plot_lines[self._data.id] = line 187 184 188 # Now add the legend with some customizations. 185 189 … … 196 200 197 201 # refresh canvas 198 self.canvas.draw _idle()202 self.canvas.draw() 199 203 # This is an important processEvent. 200 204 # This allows charts to be properly updated in order … … 416 420 This effectlvely refreshes the chart with changes to one of its plots 417 421 """ 422 import logging 418 423 self.removePlot(id) 419 424 self.plot(data=new_plot) … … 470 475 """ 471 476 selected_plot = self.plot_dict[id] 472 477 selected_line = self.plot_lines[id] 473 478 # Old style color - single integer for enum color 474 479 # New style color - #hhhhhh
Note: See TracChangeset
for help on using the changeset viewer.