- Timestamp:
- Sep 7, 2018 10:56:02 AM (6 years ago)
- Branches:
- ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
- Children:
- 34cf92c
- Parents:
- d9410c5 (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
- Files:
-
- 1 added
- 9 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 rb69b549 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): 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 model.appendRow(row) 219 if cbox: 220 view.setIndexWidget(item2.index(), cbox) 221 rows.append(row) 222 223 return rows 150 224 151 225 def markParameterDisabled(model, row): … … 182 256 model.appendRow(item_list) 183 257 258 def addHeadingRowToModel(model, name): 259 """adds a non-interactive top-level row to the model""" 260 header_row = [QtGui.QStandardItem() for i in range(5)] 261 header_row[0].setText(name) 262 263 font = header_row[0].font() 264 font.setBold(True) 265 header_row[0].setFont(font) 266 267 for item in header_row: 268 item.setEditable(False) 269 item.setCheckable(False) 270 item.setSelectable(False) 271 272 model.appendRow(header_row) 273 184 274 def addHeadersToModel(model): 185 275 """ … … 227 317 model.header_tooltips = copy.copy(poly_header_error_tooltips) 228 318 229 def addShellsToModel(parameters, model, index): 230 """ 231 Find out multishell parameters and update the model with the requested number of them 319 def addShellsToModel(parameters, model, index, row_num=None, view=None): 320 """ 321 Find out multishell parameters and update the model with the requested number of them. 322 Inserts them after the row at row_num, if not None; otherwise, appends to end. 323 If view param is not None, supports fixed-choice params. 324 Returns a list of lists of QStandardItem objects. 232 325 """ 233 326 multishell_parameters = getIterParams(parameters) 234 327 328 rows = [] 235 329 for i in range(index): 236 330 for par in multishell_parameters: … … 250 344 item1_3 = QtGui.QStandardItem(str(p.limits[0])) 251 345 item1_4 = QtGui.QStandardItem(str(p.limits[1])) 252 item1_5 = QtGui.QStandardItem( p.units)346 item1_5 = QtGui.QStandardItem(str(p.units)) 253 347 poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 254 348 break … … 258 352 item3 = QtGui.QStandardItem(str(par.limits[0])) 259 353 item4 = QtGui.QStandardItem(str(par.limits[1])) 260 item5 = QtGui.QStandardItem(par.units) 261 model.appendRow([item1, item2, item3, item4, item5]) 354 item5 = QtGui.QStandardItem(str(par.units)) 355 item5.setEditable(False) 356 357 # Check if fixed-choice (returns combobox, if so, also makes some items uneditable) 358 row = [item1, item2, item3, item4, item5] 359 cbox = createFixedChoiceComboBox(par, row) 360 361 # Always add to the model 362 if row_num is None: 363 model.appendRow(row) 364 else: 365 model.insertRow(row_num, row) 366 row_num += 1 367 368 # Apply combobox if required 369 if None not in (view, cbox): 370 view.setIndexWidget(item2.index(), cbox) 371 372 rows.append(row) 373 374 return rows 262 375 263 376 def calculateChi2(reference_data, current_data): -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r66d4370 rf0365a2e 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 … … 1197 1209 self.updateData() 1198 1210 1211 # update in param model 1212 if model_column in [delegate.poly_pd, delegate.poly_error, delegate.poly_min, delegate.poly_max]: 1213 row = self.getRowFromName(parameter_name) 1214 param_item = self._model_model.item(row) 1215 self._model_model.blockSignals(True) 1216 param_item.child(0).child(0, model_column).setText(item.text()) 1217 self._model_model.blockSignals(False) 1218 1199 1219 def onMagnetModelChange(self, item): 1200 1220 """ … … 1487 1507 # update charts 1488 1508 self.onPlot() 1509 #self.recalculatePlotData() 1510 1489 1511 1490 1512 # Read only value - we can get away by just printing it here … … 1569 1591 # internal so can use closure for param_dict 1570 1592 param_name = str(self._model_model.item(row, 0).text()) 1571 if param_name not in list(param_dict.keys()):1593 if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 1572 1594 return 1573 1595 # modify the param value 1574 1596 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1575 1597 self._model_model.item(row, 1).setText(param_repr) 1598 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1576 1599 if self.has_error_column: 1577 1600 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) … … 1581 1604 # Utility function for updateof polydispersity part of the main model 1582 1605 param_name = str(self._model_model.item(row, 0).text())+'.width' 1583 if param_name not in list(param_dict.keys()):1606 if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 1584 1607 return 1585 1608 # modify the param value … … 1615 1638 poly_item.insertColumn(2, [QtGui.QStandardItem("")]) 1616 1639 1617 # block signals temporarily, so we don't end up1618 # updating charts with every single model change on the end of fitting1619 self._model_model.blockSignals(True)1620 1621 1640 if not self.has_error_column: 1622 1641 # create top-level error column … … 1625 1644 self.iterateOverModel(createErrorColumn) 1626 1645 1627 # we need to enable signals for this, otherwise the final column mysteriously disappears (don't ask, I don't1628 # know)1629 self._model_model.blockSignals(False)1630 1646 self._model_model.insertColumn(2, error_column) 1631 self._model_model.blockSignals(True)1632 1647 1633 1648 FittingUtilities.addErrorHeadersToModel(self._model_model) … … 1638 1653 self.has_error_column = True 1639 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() 1640 1658 self.iterateOverModel(updateFittedValues) 1641 1659 self.iterateOverModel(updatePolyValues) 1642 1643 self._model_model.blockSignals(False) 1660 self._model_model.itemChanged.connect(self.onMainParamsChange) 1644 1661 1645 1662 # Adjust the table cells width. … … 1676 1693 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1677 1694 self._poly_model.item(row_i, 1).setText(param_repr) 1695 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1678 1696 if self.has_poly_error_column: 1679 1697 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 1680 1698 self._poly_model.item(row_i, 2).setText(error_repr) 1681 1682 1699 1683 1700 def createErrorColumn(row_i): … … 1700 1717 # block signals temporarily, so we don't end up 1701 1718 # updating charts with every single model change on the end of fitting 1702 self._poly_model. blockSignals(True)1719 self._poly_model.itemChanged.disconnect() 1703 1720 self.iterateOverPolyModel(updateFittedValues) 1704 self._poly_model. blockSignals(False)1721 self._poly_model.itemChanged.connect(self.onPolyModelChange) 1705 1722 1706 1723 if self.has_poly_error_column: … … 1712 1729 1713 1730 # switch off reponse to model change 1714 self._poly_model.blockSignals(True)1715 1731 self._poly_model.insertColumn(2, error_column) 1716 self._poly_model.blockSignals(False)1717 1732 FittingUtilities.addErrorPolyHeadersToModel(self._poly_model) 1718 1733 … … 1747 1762 param_repr = GuiUtils.formatNumber(param_dict[param_name][0], high=True) 1748 1763 self._magnet_model.item(row, 1).setText(param_repr) 1764 self.kernel_module.setParam(param_name, param_dict[param_name][0]) 1749 1765 if self.has_magnet_error_column: 1750 1766 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) … … 1766 1782 # block signals temporarily, so we don't end up 1767 1783 # updating charts with every single model change on the end of fitting 1768 self._magnet_model. blockSignals(True)1784 self._magnet_model.itemChanged.disconnect() 1769 1785 self.iterateOverMagnetModel(updateFittedValues) 1770 self._magnet_model. blockSignals(False)1786 self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 1771 1787 1772 1788 if self.has_magnet_error_column: … … 1778 1794 1779 1795 # switch off reponse to model change 1780 self._magnet_model.blockSignals(True)1781 1796 self._magnet_model.insertColumn(2, error_column) 1782 self._magnet_model.blockSignals(False)1783 1797 FittingUtilities.addErrorHeadersToModel(self._magnet_model) 1784 1798 … … 1792 1806 self.cmdPlot.setText("Show Plot") 1793 1807 # Force data recalculation so existing charts are updated 1808 self.showPlot() 1794 1809 self.recalculatePlotData() 1795 self.showPlot()1796 1810 1797 1811 def onSmearingOptionsUpdate(self): … … 1958 1972 # Crete/overwrite model items 1959 1973 self._model_model.clear() 1960 1961 # First, add parameters from the main model 1962 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: 1963 1986 self.fromModelToQModel(model_name) 1964 1965 # Then, add structure factor derived parameters 1966 if structure_factor is not None and structure_factor != "None": 1967 if model_name is None: 1968 # Instantiate the current sasmodel for SF-only models 1969 self.kernel_module = self.models[structure_factor]() 1970 self.fromStructureFactorToQModel(structure_factor) 1971 else: 1987 self.addExtraShells() 1988 1972 1989 # Allow the SF combobox visibility for the given sasmodel 1973 1990 self.enableStructureFactorControl(structure_factor) 1991 1992 # Add S(Q) 1974 1993 if self.cbStructureFactor.isEnabled(): 1975 1994 structure_factor = self.cbStructureFactor.currentText() 1976 1995 self.fromStructureFactorToQModel(structure_factor) 1977 1996 1978 # Then, add multishells 1979 if model_name is not None: 1980 # Multishell models need additional treatment 1981 self.addExtraShells() 1982 1983 # Add polydispersity to the model 1984 self.poly_params = {} 1985 self.setPolyModel() 1986 # Add magnetic parameters to the model 1987 self.magnet_params = {} 1988 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() 1989 2003 1990 2004 # Adjust the table cells width … … 2059 2073 self.shell_names = self.shellNamesList() 2060 2074 2075 # Add heading row 2076 FittingUtilities.addHeadingRowToModel(self._model_model, model_name) 2077 2061 2078 # Update the QModel 2062 new_rows = FittingUtilities.addParametersToModel(self.model_parameters, self.kernel_module, self.is2D)2063 2064 for row in new_rows:2065 self._model_model.appendRow(row)2066 # Update the counter used for multishell display2067 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) 2068 2085 2069 2086 def fromStructureFactorToQModel(self, structure_factor): … … 2073 2090 if structure_factor is None or structure_factor=="None": 2074 2091 return 2075 structure_module = generate.load_kernel_module(structure_factor) 2076 structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', [])) 2077 2078 structure_kernel = self.models[structure_factor]() 2079 form_kernel = self.kernel_module 2080 2081 self.kernel_module = MultiplicationModel(form_kernel, structure_kernel) 2082 2083 new_rows = FittingUtilities.addSimpleParametersToModel(structure_parameters, self.is2D) 2084 for row in new_rows: 2085 self._model_model.appendRow(row) 2086 # disable fitting of parameters not listed in self.kernel_module (probably radius_effective) 2087 if row[0].text() not in self.kernel_module.params.keys(): 2088 row_num = self._model_model.rowCount() - 1 2089 FittingUtilities.markParameterDisabled(self._model_model, row_num) 2090 2091 # Update the counter used for multishell display 2092 self._last_model_row = self._model_model.rowCount() 2092 2093 if self.kernel_module is None: 2094 # Structure factor is the only selected model; build it and show all its params 2095 self.kernel_module = self.models[structure_factor]() 2096 s_params = self.kernel_module._model_info.parameters 2097 s_params_orig = s_params 2098 2099 else: 2100 s_kernel = self.models[structure_factor]() 2101 p_kernel = self.kernel_module 2102 2103 p_pars_len = len(p_kernel._model_info.parameters.kernel_parameters) 2104 s_pars_len = len(s_kernel._model_info.parameters.kernel_parameters) 2105 2106 self.kernel_module = MultiplicationModel(p_kernel, s_kernel) 2107 all_params = self.kernel_module._model_info.parameters.kernel_parameters 2108 all_param_names = [param.name for param in all_params] 2109 2110 # S(Q) params from the product model are not necessarily the same as those from the S(Q) model; any 2111 # conflicting names with P(Q) params will cause a rename 2112 2113 if "radius_effective_mode" in all_param_names: 2114 # Show all parameters 2115 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len]) 2116 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters) 2117 else: 2118 # Ensure radius_effective is not displayed 2119 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters[1:]) 2120 if "radius_effective" in all_param_names: 2121 s_params = modelinfo.ParameterTable(all_params[p_pars_len+1:p_pars_len+s_pars_len]) 2122 else: 2123 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len-1]) 2124 2125 # Add heading row 2126 FittingUtilities.addHeadingRowToModel(self._model_model, structure_factor) 2127 2128 # Get new rows for QModel 2129 # Any renamed parameters are stored as data in the relevant item, for later handling 2130 FittingUtilities.addSimpleParametersToModel( 2131 s_params, 2132 self.is2D, 2133 s_params_orig, 2134 self._model_model, 2135 self.lstParams) 2093 2136 2094 2137 def haveParamsToFit(self): … … 2116 2159 model_row = item.row() 2117 2160 name_index = self._model_model.index(model_row, 0) 2161 name_item = self._model_model.itemFromIndex(name_index) 2118 2162 2119 2163 # Extract changed value. … … 2124 2168 return 2125 2169 2126 parameter_name = str(self._model_model.data(name_index)) # sld, background etc. 2170 # if the item has user data, this is the actual parameter name (e.g. to handle duplicate names) 2171 if name_item.data(QtCore.Qt.UserRole): 2172 parameter_name = str(name_item.data(QtCore.Qt.UserRole)) 2173 else: 2174 parameter_name = str(self._model_model.data(name_index)) 2127 2175 2128 2176 # Update the parameter value - note: this supports +/-inf as well … … 2358 2406 new_plots.append(sq_data) 2359 2407 2360 # Update/generate plots2361 2408 for plot in new_plots: 2362 2409 self.communicate.plotUpdateSignal.emit([plot]) … … 2558 2605 def updateFunctionCaption(row): 2559 2606 # Utility function for update of polydispersity function name in the main model 2607 if not self.isCheckable(row): 2608 return 2609 self._model_model.blockSignals(True) 2560 2610 param_name = str(self._model_model.item(row, 0).text()) 2611 self._model_model.blockSignals(False) 2561 2612 if param_name != param.name: 2562 2613 return 2563 2614 # Modify the param value 2615 self._model_model.blockSignals(True) 2564 2616 if self.has_error_column: 2565 2617 # err column changes the indexing … … 2567 2619 else: 2568 2620 self._model_model.item(row, 0).child(0).child(0,4).setText(combo_string) 2621 self._model_model.blockSignals(False) 2569 2622 2570 2623 if combo_string == 'array': … … 2726 2779 2727 2780 self.lstParams.setIndexWidget(shell_index, func) 2728 self._ last_model_row = self._model_model.rowCount()2781 self._n_shells_row = shell_row - 1 2729 2782 2730 2783 # Set the index to the state-kept value … … 2737 2790 """ 2738 2791 # Find row location of the combobox 2739 last_row = self._last_model_row2740 remove_rows = self._ model_model.rowCount() - last_row2792 first_row = self._n_shells_row + 1 2793 remove_rows = self._num_shell_params 2741 2794 2742 2795 if remove_rows > 1: 2743 self._model_model.removeRows(last_row, remove_rows) 2744 2745 FittingUtilities.addShellsToModel(self.model_parameters, self._model_model, index) 2796 self._model_model.removeRows(first_row, remove_rows) 2797 2798 new_rows = FittingUtilities.addShellsToModel( 2799 self.model_parameters, 2800 self._model_model, 2801 index, 2802 first_row, 2803 self.lstParams) 2804 2805 self._num_shell_params = len(new_rows) 2746 2806 self.current_shell_displayed = index 2747 2807 -
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 -
src/sas/qtgui/Perspectives/Inversion/InversionPerspective.py
r3c6ecd9 rb1f6063 309 309 and not self.isCalculating) 310 310 self.removeButton.setEnabled(self.logic.data_is_loaded) 311 self.explorerButton.setEnabled(self.logic.data_is_loaded 312 and np.all(self.logic.data.dy != 0)) 311 self.explorerButton.setEnabled(self.logic.data_is_loaded) 313 312 self.stopButton.setVisible(self.isCalculating) 314 313 self.regConstantSuggestionButton.setEnabled( … … 641 640 self.calcThread.ready(2.5) 642 641 642 #Perform estimate should be done on value enter this should solve delay problem 643 self.performEstimate() 644 643 645 def stopCalcThread(self): 644 646 """ Stops a thread if it exists and is running """ -
src/sas/sascalc/pr/invertor.py
rb8080e1 r6701a0b 71 71 A[j][i] = (Fourier transformed base function for point j) 72 72 73 We the mchoose a number of r-points, n_r, to evaluate the second73 We then choose a number of r-points, n_r, to evaluate the second 74 74 derivative of P(r) at. This is used as our regularization term. 75 75 For a vector r of length n_r, the following n_r rows are set to :: … … 144 144 x, y, err, d_max, q_min, q_max and alpha 145 145 """ 146 if 146 if name == 'x': 147 147 if 0.0 in value: 148 148 msg = "Invertor: one of your q-values is zero. " … … 227 227 return None 228 228 229 def add_errors(self, yvalues): 230 """ 231 Adds errors to data set is they are not avaialble 232 :return: 233 """ 234 stats_errors = np.zeros(len(yvalues)) 235 for i in range(len(yvalues)): 236 # Scale the error so that we can fit over several decades of Q 237 scale = 0.05 * np.sqrt(yvalues[i]) 238 min_err = 0.01 * yvalues[i] 239 stats_errors[i] = scale * np.sqrt(np.fabs(yvalues[i])) + min_err 240 logger.warning("Simulated errors have been added to the data set\n") 241 return stats_errors 242 229 243 def clone(self): 230 244 """ … … 244 258 invertor.x = self.x 245 259 invertor.y = self.y 246 invertor.err = self.err 260 if np.size(self.err) == 0 or np.all(self.err) == 0: 261 invertor.err = self.add_errors(self.y) 262 else: 263 invertor.err = self.err 247 264 invertor.est_bck = self.est_bck 248 265 invertor.background = self.background … … 268 285 A[i][j] = (Fourier transformed base function for point j) 269 286 270 We the mchoose a number of r-points, n_r, to evaluate the second287 We then choose a number of r-points, n_r, to evaluate the second 271 288 derivative of P(r) at. This is used as our regularization term. 272 289 For a vector r of length n_r, the following n_r rows are set to ::
Note: See TracChangeset
for help on using the changeset viewer.