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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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 
Note: See TracChangeset for help on using the changeset viewer.