Changeset b69b549 in sasview for src


Ignore:
Timestamp:
Sep 7, 2018 10:10:42 AM (6 years ago)
Author:
Torin Cooper-Bennun <torin.cooper-bennun@…>
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:
5fb714b
Parents:
bc7371fd (diff), fb560d2 (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.
Message:

Merge branch 'ESS_GUI' into ESS_GUI_iss1032

Location:
src/sas/qtgui
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/MainWindow/DataExplorer.py

    rfd7ef36 r60d55a7  
    560560        # Now query the model item for available plots 
    561561        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()] 
    564562 
    565563        new_plots = [] 
    566564        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): 
    573566                # 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) 
    575568                # 2nd match group contains the identifier for the intermediate result, if present (e.g. "[P(Q)]") 
    576569                if match and match.groups()[1] != None: 
     
    706699                self.active_plots[plot_set.id] = old_plot 
    707700 
    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 
    713710        assert type(data).__name__ in ['Data1D', 'Data2D'] 
    714711 
     
    719716        if data_id in ids_keys: 
    720717            self.active_plots[data_id].replacePlot(data_id, data) 
     718            return True 
    721719        elif data_id in ids_vals: 
    722720            list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data) 
     721            return True 
     722        return False 
    723723 
    724724    def chooseFiles(self): 
  • src/sas/qtgui/Perspectives/Fitting/FittingLogic.py

    rb4d05bd rdcabba7  
    161161        Create a new 1D data instance based on fitting results 
    162162        """ 
    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']) 
    172166 
    173167    def new2DPlot(self, return_data): 
     
    175169        Create a new 2D data instance based on fitting results 
    176170        """ 
    177         image, data, page_id, model, state, toggle_mode_on,\ 
    178         elapsed, index, fid, qmin, qmax, weight, \ 
    179         update_chisqr, source = return_data 
     171        image = return_data['image'] 
     172        data = return_data['data'] 
     173        model = return_data['model'] 
    180174 
    181175        np.nan_to_num(image) 
     
    183177        new_plot.name = model.name + '2d' 
    184178        new_plot.title = "Analytical model 2D " 
    185         new_plot.id = str(page_id) + " " + data.name 
    186         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" 
    187181        new_plot.detector = data.detector 
    188182        new_plot.source = data.source 
     
    218212        (pq_plot, sq_plot). If either are unavailable, the corresponding plot is None. 
    219213        """ 
    220         # Unpack return data from Calc1D 
    221         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_data 
    227214 
    228215        pq_plot = None 
    229216        sq_plot = None 
    230217 
    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)") 
    235226 
    236227        return pq_plot, sq_plot 
  • src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py

    rbc7371fd rb69b549  
    167167    return rows 
    168168 
    169 def addSimpleParametersToModel(parameters, is2D, model=None, view=None): 
     169def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=None): 
    170170    """ 
    171171    Update local ModelModel with sasmodel parameters (non-dispersed, non-magnetic) 
    172172    Actually appends to model, if model and view params are not None. 
    173173    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) 
    174177    """ 
    175178    if is2D: 
     
    178181        params = parameters.iq_parameters 
    179182 
     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 
    180195    rows = [] 
    181     for param in params: 
     196    for param, param_orig in zip(params, params_orig): 
    182197        # Create the top level, checkable item 
    183         item_name = param.name 
     198        item_name = param_orig.name 
    184199        item1 = QtGui.QStandardItem(item_name) 
     200        item1.setData(param.name, QtCore.Qt.UserRole) 
    185201        item1.setCheckable(True) 
    186202        item1.setEditable(False) 
     
    240256    model.appendRow(item_list) 
    241257 
     258def 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 
    242274def addHeadersToModel(model): 
    243275    """ 
     
    285317    model.header_tooltips = copy.copy(poly_header_error_tooltips) 
    286318 
    287 def addShellsToModel(parameters, model, index, view=None): 
    288     """ 
    289     Find out multishell parameters and update the model with the requested number of them 
    290     Always appends to model. If view param is not None, supports fixed-choice params. 
    291     Returns list of lists of QStandardItems. 
     319def 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. 
    292325    """ 
    293326    multishell_parameters = getIterParams(parameters) 
     
    326359            cbox = createFixedChoiceComboBox(par, row) 
    327360 
    328             # Always append to the model 
    329             model.appendRow(row) 
     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 
    330367 
    331368            # Apply combobox if required 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    ra758043 rb69b549  
    9191    fittingFinishedSignal = QtCore.pyqtSignal(tuple) 
    9292    batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 
    93     Calc1DFinishedSignal = QtCore.pyqtSignal(tuple) 
    94     Calc2DFinishedSignal = QtCore.pyqtSignal(tuple) 
     93    Calc1DFinishedSignal = QtCore.pyqtSignal(dict) 
     94    Calc2DFinishedSignal = QtCore.pyqtSignal(dict) 
    9595 
    9696    def __init__(self, parent=None, data=None, tab_id=1): 
     
    219219        # Utility variable to enable unselectable option in category combobox 
    220220        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 
    223224        # Dictionary of {model name: model class} for the current category 
    224225        self.models = {} 
     
    247248        # copy of current kernel model 
    248249        self.kernel_module_copy = None 
     250 
     251        # dictionaries of current params 
     252        self.poly_params = {} 
     253        self.magnet_params = {} 
    249254 
    250255        # Page id for fitting 
     
    672677        Return list of all parameters for the current model 
    673678        """ 
    674         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)] 
    675682 
    676683    def modifyViewOnRow(self, row, font=None, brush=None): 
     
    700707        assert isinstance(constraint, Constraint) 
    701708        assert 0 <= row <= self._model_model.rowCount() 
     709        assert self.isCheckable(row) 
    702710 
    703711        item = QtGui.QStandardItem() 
     
    720728        max_col = self.lstParams.itemDelegate().param_max 
    721729        for row in self.selectedParameters(): 
     730            assert(self.isCheckable(row)) 
    722731            param = self._model_model.item(row, 0).text() 
    723732            value = self._model_model.item(row, 1).text() 
     
    762771        max_col = self.lstParams.itemDelegate().param_max 
    763772        for row in range(self._model_model.rowCount()): 
     773            if not self.isCheckable(row): 
     774                continue 
    764775            if not self.rowHasConstraint(row): 
    765776                continue 
     
    790801        For the given row, return its constraint, if any 
    791802        """ 
    792         try: 
     803        if self.isCheckable(row): 
    793804            item = self._model_model.item(row, 1) 
    794             return item.child(0).data() 
    795         except AttributeError: 
    796             # return none when no constraints 
    797             return None 
     805            try: 
     806                return item.child(0).data() 
     807            except AttributeError: 
     808                # return none when no constraints 
     809                pass 
     810        return None 
    798811 
    799812    def rowHasConstraint(self, row): 
     
    801814        Finds out if row of the main model has a constraint child 
    802815        """ 
    803         item = self._model_model.item(row, 1) 
    804         if item.hasChildren(): 
    805             c = item.child(0).data() 
    806             if isinstance(c, Constraint): 
    807                 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 
    808822        return False 
    809823 
     
    812826        Finds out if row of the main model has an active constraint child 
    813827        """ 
    814         item = self._model_model.item(row, 1) 
    815         if item.hasChildren(): 
    816             c = item.child(0).data() 
    817             if isinstance(c, Constraint) and c.active: 
    818                 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 
    819834        return False 
    820835 
     
    823838        Finds out if row of the main model has an active, nontrivial constraint child 
    824839        """ 
    825         item = self._model_model.item(row, 1) 
    826         if item.hasChildren(): 
    827             c = item.child(0).data() 
    828             if isinstance(c, Constraint) and c.func and c.active: 
    829                 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 
    830846        return False 
    831847 
     
    11861202            # Update the sasmodel 
    11871203            # PD[ratio] -> width, npts -> npts, nsigs -> nsigmas 
    1188             self.kernel_module.setParam(parameter_name + '.' + delegate.columnDict()[model_column], value) 
     1204            #self.kernel_module.setParam(parameter_name + '.' + delegate.columnDict()[model_column], value) 
     1205            key = parameter_name + '.' + delegate.columnDict()[model_column] 
     1206            self.poly_params[key] = value 
    11891207 
    11901208            # Update plot 
     
    11951213            row = self.getRowFromName(parameter_name) 
    11961214            param_item = self._model_model.item(row) 
     1215            self._model_model.blockSignals(True) 
    11971216            param_item.child(0).child(0, model_column).setText(item.text()) 
     1217            self._model_model.blockSignals(False) 
    11981218 
    11991219    def onMagnetModelChange(self, item): 
     
    12241244            # Unparsable field 
    12251245            return 
    1226  
    1227         property_index = self._magnet_model.headerData(1, model_column)-1 # Value, min, max, etc. 
    1228  
    1229         # Update the parameter value - note: this supports +/-inf as well 
    1230         self.kernel_module.params[parameter_name] = value 
    1231  
    1232         # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 
    1233         self.kernel_module.details[parameter_name][property_index] = value 
    1234  
    1235         # Force the chart update when actual parameters changed 
    1236         if model_column == 1: 
     1246        delegate = self.lstMagnetic.itemDelegate() 
     1247 
     1248        if model_column > 1: 
     1249            if model_column == delegate.mag_min: 
     1250                pos = 1 
     1251            elif model_column == delegate.mag_max: 
     1252                pos = 2 
     1253            elif model_column == delegate.mag_unit: 
     1254                pos = 0 
     1255            else: 
     1256                raise AttributeError("Wrong column in magnetism table.") 
     1257            # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 
     1258            self.kernel_module.details[parameter_name][pos] = value 
     1259        else: 
     1260            self.magnet_params[parameter_name] = value 
     1261            #self.kernel_module.setParam(parameter_name) = value 
     1262            # Force the chart update when actual parameters changed 
    12371263            self.recalculatePlotData() 
    12381264 
     
    14951521        # Data going in 
    14961522        data = self.logic.data 
    1497         model = self.kernel_module 
     1523        model = copy.deepcopy(self.kernel_module) 
    14981524        qmin = self.q_range_min 
    14991525        qmax = self.q_range_max 
     1526        # add polydisperse/magnet parameters if asked 
     1527        self.updateKernelModelWithExtraParams(model) 
    15001528 
    15011529        params_to_fit = self.main_params_to_fit 
     
    15611589            # internal so can use closure for param_dict 
    15621590            param_name = str(self._model_model.item(row, 0).text()) 
    1563             if param_name not in list(param_dict.keys()): 
     1591            if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 
    15641592                return 
    15651593            # modify the param value 
     
    15731601            # Utility function for updateof polydispersity part of the main model 
    15741602            param_name = str(self._model_model.item(row, 0).text())+'.width' 
    1575             if param_name not in list(param_dict.keys()): 
     1603            if not self.isCheckable(row) or param_name not in list(param_dict.keys()): 
    15761604                return 
    15771605            # modify the param value 
     
    19501978        # Crete/overwrite model items 
    19511979        self._model_model.clear() 
    1952  
    1953         # First, add parameters from the main model 
    1954         if model_name is not None: 
     1980        self._poly_model.clear() 
     1981        self._magnet_model.clear() 
     1982 
     1983        if model_name is None: 
     1984            if structure_factor not in (None, "None"): 
     1985                # S(Q) on its own, treat the same as a form factor 
     1986                self.kernel_module = None 
     1987                self.fromStructureFactorToQModel(structure_factor) 
     1988            else: 
     1989                # No models selected 
     1990                return 
     1991        else: 
    19551992            self.fromModelToQModel(model_name) 
    1956  
    1957         # Then, add structure factor derived parameters 
    1958         if structure_factor is not None and structure_factor != "None": 
    1959             if model_name is None: 
    1960                 # Instantiate the current sasmodel for SF-only models 
    1961                 self.kernel_module = self.models[structure_factor]() 
    1962             self.fromStructureFactorToQModel(structure_factor) 
    1963         else: 
     1993            self.addExtraShells() 
     1994 
    19641995            # Allow the SF combobox visibility for the given sasmodel 
    19651996            self.enableStructureFactorControl(structure_factor) 
     1997         
     1998            # Add S(Q) 
    19661999            if self.cbStructureFactor.isEnabled(): 
    19672000                structure_factor = self.cbStructureFactor.currentText() 
    19682001                self.fromStructureFactorToQModel(structure_factor) 
    19692002 
    1970         # Then, add multishells 
    1971         if model_name is not None: 
    1972             # Multishell models need additional treatment 
    1973             self.addExtraShells() 
    1974  
    1975         # Add polydispersity to the model 
    1976         self.setPolyModel() 
    1977         # Add magnetic parameters to the model 
    1978         self.setMagneticModel() 
     2003            # Add polydispersity to the model 
     2004            self.poly_params = {} 
     2005            self.setPolyModel() 
     2006            # Add magnetic parameters to the model 
     2007            self.magnet_params = {} 
     2008            self.setMagneticModel() 
    19792009 
    19802010        # Adjust the table cells width 
     
    20492079        self.shell_names = self.shellNamesList() 
    20502080 
     2081        # Add heading row 
     2082        FittingUtilities.addHeadingRowToModel(self._model_model, model_name) 
     2083 
    20512084        # Update the QModel 
    20522085        FittingUtilities.addParametersToModel( 
     
    20572090                self.lstParams) 
    20582091 
    2059         # Update the counter used for multishell display 
    2060         self._last_model_row = self._model_model.rowCount() 
    2061  
    20622092    def fromStructureFactorToQModel(self, structure_factor): 
    20632093        """ 
     
    20662096        if structure_factor is None or structure_factor=="None": 
    20672097            return 
    2068         structure_module = generate.load_kernel_module(structure_factor) 
    2069         structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', [])) 
    2070  
    2071         structure_kernel = self.models[structure_factor]() 
    2072         form_kernel = self.kernel_module 
    2073  
    2074         self.kernel_module = MultiplicationModel(form_kernel, structure_kernel) 
    2075  
    2076         # Update the QModel 
     2098 
     2099        s_kernel = self.models[structure_factor]() 
     2100        p_kernel = self.kernel_module 
     2101 
     2102        # if p_kernel is None: 
     2103        #     # Not a product model, just S(Q) 
     2104        #     self.kernel_module = s_kernel 
     2105        #     params = modelinfo.ParameterTable(self.kernel_module._model_info.parameters.kernel_parameters) 
     2106        #     FittingUtilities.addSimpleParametersToModel(params, self.is2D) 
     2107        # else: 
     2108        p_pars_len = len(p_kernel._model_info.parameters.kernel_parameters) 
     2109        s_pars_len = len(s_kernel._model_info.parameters.kernel_parameters) 
     2110 
     2111        self.kernel_module = MultiplicationModel(p_kernel, s_kernel) 
     2112        all_params = self.kernel_module._model_info.parameters.kernel_parameters 
     2113        all_param_names = [param.name for param in all_params] 
     2114 
     2115        # S(Q) params from the product model are not necessarily the same as those from the S(Q) model; any 
     2116        # conflicting names with P(Q) params will cause a rename 
     2117 
     2118        if "radius_effective_mode" in all_param_names: 
     2119            # Show all parameters 
     2120            s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len]) 
     2121            s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters) 
     2122        else: 
     2123            # Ensure radius_effective is not displayed 
     2124            s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters[1:]) 
     2125            if "radius_effective" in all_param_names: 
     2126                s_params = modelinfo.ParameterTable(all_params[p_pars_len+1:p_pars_len+s_pars_len]) 
     2127            else: 
     2128                s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len-1]) 
     2129 
     2130        # Add heading row 
     2131        FittingUtilities.addHeadingRowToModel(self._model_model, structure_factor) 
     2132 
     2133        # Get new rows for QModel 
     2134        # Any renamed parameters are stored as data in the relevant item, for later handling 
    20772135        FittingUtilities.addSimpleParametersToModel( 
    2078                 structure_parameters, 
     2136                s_params, 
    20792137                self.is2D, 
     2138                s_params_orig, 
    20802139                self._model_model, 
    20812140                self.lstParams) 
    2082  
    2083         # Any parameters removed from the structure factor when producing the product model, e.g. radius_effective, must 
    2084         # be disabled (greyed out, etc.) 
    2085         for r in range(self._last_model_row, self._model_model.rowCount()): 
    2086             param_name = self._model_model.item(r, 0).text() 
    2087             if param_name not in self.kernel_module.params.keys(): 
    2088                 FittingUtilities.markParameterDisabled(self._model_model, r) 
    2089  
    2090         # Update the counter used for multishell display 
    2091         self._last_model_row = self._model_model.rowCount() 
    20922141 
    20932142    def haveParamsToFit(self): 
     
    21152164        model_row = item.row() 
    21162165        name_index = self._model_model.index(model_row, 0) 
     2166        name_item = self._model_model.itemFromIndex(name_index) 
    21172167 
    21182168        # Extract changed value. 
     
    21232173            return 
    21242174 
    2125         parameter_name = str(self._model_model.data(name_index)) # sld, background etc. 
     2175        # if the item has user data, this is the actual parameter name (e.g. to handle duplicate names) 
     2176        if name_item.data(QtCore.Qt.UserRole): 
     2177            parameter_name = str(name_item.data(QtCore.Qt.UserRole)) 
     2178        else: 
     2179            parameter_name = str(self._model_model.data(name_index)) 
    21262180 
    21272181        # Update the parameter value - note: this supports +/-inf as well 
     
    22462300        return self.completed1D if isinstance(self.data, Data1D) else self.completed2D 
    22472301 
     2302    def updateKernelModelWithExtraParams(self, model=None): 
     2303        """ 
     2304        Updates kernel model 'model' with extra parameters from 
     2305        the polydisp and magnetism tab, if the tabs are enabled 
     2306        """ 
     2307        if model is None: return 
     2308        if not hasattr(model, 'setParam'): return 
     2309 
     2310        # add polydisperse parameters if asked 
     2311        if self.chkPolydispersity.isChecked(): 
     2312            for key, value in self.poly_params.items(): 
     2313                model.setParam(key, value) 
     2314        # add magnetic params if asked 
     2315        if self.chkMagnetism.isChecked(): 
     2316            for key, value in self.magnet_params.items(): 
     2317                model.setParam(key, value) 
     2318 
    22482319    def calculateQGridForModelExt(self, data=None, model=None, completefn=None, use_threads=True): 
    22492320        """ 
     
    22532324            data = self.data 
    22542325        if model is None: 
    2255             model = self.kernel_module 
     2326            model = copy.deepcopy(self.kernel_module) 
     2327            self.updateKernelModelWithExtraParams(model) 
     2328 
    22562329        if completefn is None: 
    22572330            completefn = self.methodCompleteForData() 
     
    23382411            new_plots.append(sq_data) 
    23392412 
     2413        for plot in new_plots: 
     2414            self.communicate.plotUpdateSignal.emit([plot]) 
     2415 
     2416    def complete2D(self, return_data): 
     2417        """ 
     2418        Plot the current 2D data 
     2419        """ 
     2420        fitted_data = self.logic.new2DPlot(return_data) 
     2421        residuals = self.calculateResiduals(fitted_data) 
     2422        self.model_data = fitted_data 
     2423        new_plots = [fitted_data] 
     2424        if residuals is not None: 
     2425            new_plots.append(residuals) 
     2426 
    23402427        # Update/generate plots 
    23412428        for plot in new_plots: 
    23422429            self.communicate.plotUpdateSignal.emit([plot]) 
    2343  
    2344     def complete2D(self, return_data): 
    2345         """ 
    2346         Plot the current 2D data 
    2347         """ 
    2348         fitted_data = self.logic.new2DPlot(return_data) 
    2349         self.calculateResiduals(fitted_data) 
    2350         self.model_data = fitted_data 
    23512430 
    23522431    def calculateResiduals(self, fitted_data): 
     
    24792558        _, min, max = self.kernel_module.details[param_name] 
    24802559 
     2560        # Update local param dict 
     2561        self.poly_params[param_name + '.width'] = width 
     2562        self.poly_params[param_name + '.npts'] = npts 
     2563        self.poly_params[param_name + '.nsigmas'] = nsigs 
     2564 
    24812565        # Construct a row with polydisp. related variable. 
    24822566        # This will get added to the polydisp. model 
     
    25262610        def updateFunctionCaption(row): 
    25272611            # Utility function for update of polydispersity function name in the main model 
     2612            if not self.isCheckable(row): 
     2613                return 
     2614            self._model_model.blockSignals(True) 
    25282615            param_name = str(self._model_model.item(row, 0).text()) 
     2616            self._model_model.blockSignals(False) 
    25292617            if param_name !=  param.name: 
    25302618                return 
    25312619            # Modify the param value 
     2620            self._model_model.blockSignals(True) 
    25322621            if self.has_error_column: 
    25332622                # err column changes the indexing 
     
    25352624            else: 
    25362625                self._model_model.item(row, 0).child(0).child(0,4).setText(combo_string) 
     2626            self._model_model.blockSignals(False) 
    25372627 
    25382628        if combo_string == 'array': 
     
    26532743                        param.units] 
    26542744 
     2745        self.magnet_params[param.name] = param.default 
     2746 
    26552747        FittingUtilities.addCheckedListToModel(model, checked_list) 
    26562748 
     
    26922784 
    26932785        self.lstParams.setIndexWidget(shell_index, func) 
    2694         self._last_model_row = self._model_model.rowCount() 
     2786        self._n_shells_row = shell_row - 1 
    26952787 
    26962788        # Set the index to the state-kept value 
     
    27032795        """ 
    27042796        # Find row location of the combobox 
    2705         last_row = self._last_model_row 
    2706         remove_rows = self._model_model.rowCount() - last_row 
     2797        first_row = self._n_shells_row + 1 
     2798        remove_rows = self._num_shell_params 
    27072799 
    27082800        if remove_rows > 1: 
    2709             self._model_model.removeRows(last_row, remove_rows) 
    2710  
    2711         FittingUtilities.addShellsToModel( 
     2801            self._model_model.removeRows(first_row, remove_rows) 
     2802 
     2803        new_rows = FittingUtilities.addShellsToModel( 
    27122804                self.model_parameters, 
    27132805                self._model_model, 
    27142806                index, 
     2807                first_row, 
    27152808                self.lstParams) 
    27162809 
     2810        self._num_shell_params = len(new_rows) 
    27172811        self.current_shell_displayed = index 
    27182812 
  • src/sas/qtgui/Perspectives/Fitting/ModelThread.py

    r2df558e rdcabba7  
    101101        elapsed = time.time() - self.starttime 
    102102 
     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 
    103111        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) 
    135115 
    136116class Calc1D(CalcThread): 
     
    236216        elapsed = time.time() - self.starttime 
    237217 
     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 
    238227        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) 
    264231 
    265232    def results(self): 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py

    r605d944 r4ea8020  
    256256        self.widget.cbStructureFactor.setCurrentIndex(structure_index) 
    257257 
    258         # We have 4 more rows now 
     258        # We have 3 more param rows now (radius_effective is removed), and a new heading 
    259259        self.assertEqual(self.widget._model_model.rowCount(), rowcount+4) 
    260260 
     
    276276        last_index = self.widget.cbStructureFactor.count() 
    277277        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) 
    280280 
    281281        # Are the command buttons properly enabled? 
     
    445445        self.assertEqual(self.widget.kernel_module.details['radius_bell'][1], 1.0) 
    446446 
     447        #self.widget.show() 
     448        #QtWidgets.QApplication.exec_() 
     449 
    447450        # Change the number of points 
    448         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 
     451        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 35) 
    449452        self.widget._poly_model.item(0,4).setText("22") 
    450         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 
     453        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 22) 
    451454        # try something stupid 
    452455        self.widget._poly_model.item(0,4).setText("butt") 
    453456        # see that this didn't annoy the control at all 
    454         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 
     457        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 22) 
    455458 
    456459        # Change the number of sigmas 
    457         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 3) 
     460        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 3) 
    458461        self.widget._poly_model.item(0,5).setText("222") 
    459         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 
     462        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 222) 
    460463        # try something stupid again 
    461464        self.widget._poly_model.item(0,4).setText("beer") 
    462465        # no efect 
    463         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 
     466        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 222) 
    464467 
    465468    def testOnPolyComboIndexChange(self): 
     
    482485        self.widget.onPolyComboIndexChange('rectangle', 0) 
    483486        # check values 
    484         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 
    485         self.assertAlmostEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 1.73205, 5) 
     487        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 35) 
     488        self.assertAlmostEqual(self.widget.poly_params['radius_bell.nsigmas'], 1.73205, 5) 
    486489        # Change the index 
    487490        self.widget.onPolyComboIndexChange('lognormal', 0) 
    488491        # check values 
    489         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 
    490         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8) 
     492        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 80) 
     493        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 8) 
    491494        # Change the index 
    492495        self.widget.onPolyComboIndexChange('schulz', 0) 
    493496        # check values 
    494         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 
    495         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 8) 
     497        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 80) 
     498        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 8) 
    496499 
    497500        # mock up file load 
     
    506509        Test opening of the load file dialog for 'array' polydisp. function 
    507510        """ 
     511 
     512        # open a non-existent file 
    508513        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) 
    509516        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 
    510517        self.widget.show() 
     
    522529 
    523530        # 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 
    524534        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") 
    525539        QtWidgets.QFileDialog.getOpenFileName = MagicMock(return_value=(filename,'')) 
    526540 
     
    588602 
    589603        # Assure we have the combobox available 
    590         last_row = self.widget._last_model_row 
    591         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) 
    592606        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() 
    593610 
    594611        # Change the combo box index 
     
    10241041 
    10251042         # Check the model 
    1026         self.assertEqual(self.widget._model_model.rowCount(), 6) 
     1043        self.assertEqual(self.widget._model_model.rowCount(), 7) 
    10271044        self.assertEqual(self.widget._model_model.columnCount(), 5) 
    10281045 
     
    11401157        # two rows selected 
    11411158        index1 = self.widget.lstParams.model().index(1, 0, QtCore.QModelIndex()) 
    1142         index2 = self.widget.lstParams.model().index(2, 0, QtCore.QModelIndex()) 
     1159        index2 = self.widget.lstParams.model().index(3, 0, QtCore.QModelIndex()) 
    11431160        selection_model = self.widget.lstParams.selectionModel() 
    11441161        selection_model.select(index1, selection_model.Select | selection_model.Rows) 
     
    11761193        # several random parameters 
    11771194        self.assertEqual(self.widget.getRowFromName('scale'), 0) 
    1178         self.assertEqual(self.widget.getRowFromName('length'), 5) 
     1195        self.assertEqual(self.widget.getRowFromName('length'), 6) 
    11791196 
    11801197    def testGetParamNames(self): 
     
    12131230        # Create a constraint object 
    12141231        const = Constraint(parent=None, value=7.0) 
    1215         row = 2 
     1232        row = 3 
    12161233 
    12171234        spy = QtSignalSpy(self.widget, self.widget.constraintAddedSignal) 
     
    12321249        # assign complex constraint now 
    12331250        const = Constraint(parent=None, param='radius', func='5*sld') 
    1234         row = 4 
     1251        row = 5 
    12351252        # call the method tested 
    12361253        self.widget.addConstraintToRow(constraint=const, row=row) 
     
    12911308        self.widget.cbModel.setCurrentIndex(model_index) 
    12921309 
     1310        row1 = 1 
     1311        row2 = 5 
     1312 
     1313        param1 = "background" 
     1314        param2 = "radius" 
     1315 
     1316        #default_value1 = "0.001" 
     1317        default_value2 = "20" 
     1318 
    12931319        # select two rows 
    1294         row1 = 1 
    1295         row2 = 4 
    12961320        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    12971321        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    13101334 
    13111335        # delete one of the constraints 
    1312         self.widget.deleteConstraintOnParameter(param='background') 
     1336        self.widget.deleteConstraintOnParameter(param=param1) 
    13131337 
    13141338        # see that the other constraint is still present 
    1315         cons = self.widget.getConstraintForRow(4) # 4 = radius 
    1316         self.assertEqual(cons.param, "radius") 
    1317         self.assertEqual(cons.value, "20") 
     1339        cons = self.widget.getConstraintForRow(row2) 
     1340        self.assertEqual(cons.param, param2) 
     1341        self.assertEqual(cons.value, default_value2) 
    13181342 
    13191343        # kill the other constraint 
     
    13211345 
    13221346        # see that the other constraint is still present 
    1323         self.assertEqual(self.widget.getConstraintsForModel(), [('radius', None)]) 
     1347        self.assertEqual(self.widget.getConstraintsForModel(), [(param2, None)]) 
    13241348 
    13251349    def testGetConstraintForRow(self): 
     
    13411365        self.widget.cbModel.setCurrentIndex(model_index) 
    13421366 
     1367        row1 = 1 
     1368        row2 = 5 
     1369 
    13431370        # select two rows 
    1344         row1 = 1 
    1345         row2 = 4 
    13461371        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    13471372        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    13531378        self.widget.addSimpleConstraint() 
    13541379 
    1355         con_list = [False, True, False, False, True, False] 
     1380        con_list = [False, True, False, False, False, True, False] 
    13561381        new_list = [] 
    13571382        for row in range(self.widget._model_model.rowCount()): 
     
    13711396        self.widget.cbModel.setCurrentIndex(model_index) 
    13721397 
     1398        row1 = 1 
     1399        row2 = 5 
     1400 
    13731401        # select two rows 
    1374         row1 = 1 
    1375         row2 = 4 
    13761402        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    13771403        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    13871413        constraint_objects[0].active = False 
    13881414 
    1389         con_list = [False, False, False, False, True, False] 
     1415        con_list = [False, False, False, False, False, True, False] 
    13901416        new_list = [] 
    13911417        for row in range(self.widget._model_model.rowCount()): 
     
    14081434        self.assertEqual(self.widget.getConstraintsForModel(),[]) 
    14091435 
     1436        row1 = 1 
     1437        row2 = 5 
     1438 
     1439        param1 = "background" 
     1440        param2 = "radius" 
     1441 
     1442        default_value1 = "0.001" 
     1443        default_value2 = "20" 
     1444 
    14101445        # select two rows 
    1411         row1 = 1 
    1412         row2 = 4 
    14131446        index1 = self.widget.lstParams.model().index(row1, 0, QtCore.QModelIndex()) 
    14141447        index2 = self.widget.lstParams.model().index(row2, 0, QtCore.QModelIndex()) 
     
    14221455        # simple constraints 
    14231456        # self.assertEqual(self.widget.getConstraintsForModel(), [('background', '0.001'), ('radius', '20')]) 
    1424         cons = self.widget.getConstraintForRow(1) # 1 - background 
    1425         self.assertEqual(cons.param, "background") 
    1426         self.assertEqual(cons.value, "0.001") 
    1427         cons = self.widget.getConstraintForRow(4) # 4 = radius 
    1428         self.assertEqual(cons.param, "radius") 
    1429         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) 
    14301463 
    14311464        objects = self.widget.getConstraintObjectsForModel() 
    14321465        self.assertEqual(len(objects), 2) 
    1433         self.assertEqual(objects[1].value, '20') 
    1434         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" 
    14351472 
    14361473        # add complex constraint 
    1437         const = Constraint(parent=None, param='scale', func='5*sld') 
    1438         row = 0 
     1474        const = Constraint(parent=None, param=param, func=func) 
    14391475        self.widget.addConstraintToRow(constraint=const, row=row) 
    14401476        #self.assertEqual(self.widget.getConstraintsForModel(),[('scale', '5*sld'), ('background', '0.001'), ('radius', None)]) 
    1441         cons = self.widget.getConstraintForRow(4) # 4 = radius 
    1442         self.assertEqual(cons.param, "radius") 
    1443         self.assertEqual(cons.value, "20") 
     1477        cons = self.widget.getConstraintForRow(row2) 
     1478        self.assertEqual(cons.param, param2) 
     1479        self.assertEqual(cons.value, default_value2) 
    14441480 
    14451481        objects = self.widget.getConstraintObjectsForModel() 
    14461482        self.assertEqual(len(objects), 3) 
    1447         self.assertEqual(objects[0].func, '5*sld') 
     1483        self.assertEqual(objects[0].func, func) 
    14481484 
    14491485    def testReplaceConstraintName(self): 
Note: See TracChangeset for help on using the changeset viewer.