Changeset 4ea8020 in sasview for src/sas/qtgui/Perspectives


Ignore:
Timestamp:
Sep 7, 2018 7:40:56 AM (6 years ago)
Author:
GitHub <noreply@…>
Branches:
ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
c0de493
Parents:
0109f2a (diff), dcabba7 (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.
git-author:
Torin Cooper-Bennun <40573959+tcbennun@…> (09/07/18 07:40:56)
git-committer:
GitHub <noreply@…> (09/07/18 07:40:56)
Message:

Merge branch 'ESS_GUI' into ESS_GUI_iss966

Location:
src/sas/qtgui/Perspectives/Fitting
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • 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

    r70f4458 r4ea8020  
    474474 
    475475    theory_name = str(current_data.name.split()[0]) 
    476     residuals.name = "Residuals for " + str(theory_name) + "[" + \ 
    477                     str(reference_data.filename) + "]" 
     476    res_name = reference_data.filename if reference_data.filename else reference_data.name 
     477    residuals.name = "Residuals for " + str(theory_name) + "[" + res_name + "]" 
    478478    residuals.title = residuals.name 
    479479    residuals.ytransform = 'y' 
     
    501501    """ 
    502502    weight = None 
     503    if data is None: 
     504        return [] 
    503505    if is2d: 
     506        if not hasattr(data, 'err_data'): 
     507            return [] 
    504508        dy_data = data.err_data 
    505509        data = data.data 
    506510    else: 
     511        if not hasattr(data, 'dy'): 
     512            return [] 
    507513        dy_data = data.dy 
    508514        data = data.y 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    r0109f2a r4ea8020  
    4949 
    5050 
    51  
    5251TAB_MAGNETISM = 4 
    5352TAB_POLY = 3 
     
    6160 
    6261logger = logging.getLogger(__name__) 
    63  
    6462 
    6563class ToolTippedItemModel(QtGui.QStandardItemModel): 
     
    9391    fittingFinishedSignal = QtCore.pyqtSignal(tuple) 
    9492    batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 
    95     Calc1DFinishedSignal = QtCore.pyqtSignal(tuple) 
    96     Calc2DFinishedSignal = QtCore.pyqtSignal(tuple) 
     93    Calc1DFinishedSignal = QtCore.pyqtSignal(dict) 
     94    Calc2DFinishedSignal = QtCore.pyqtSignal(dict) 
    9795 
    9896    def __init__(self, parent=None, data=None, tab_id=1): 
     
    251249        self.kernel_module_copy = None 
    252250 
     251        # dictionaries of current params 
     252        self.poly_params = {} 
     253        self.magnet_params = {} 
     254 
    253255        # Page id for fitting 
    254256        # To keep with previous SasView values, use 200 as the start offset 
     
    267269        self.has_poly_error_column = False 
    268270        self.has_magnet_error_column = False 
     271 
     272        # If the widget generated theory item, save it 
     273        self.theory_item = None 
    269274 
    270275        # signal communicator 
     
    390395        # Tag along functionality 
    391396        self.label.setText("Data loaded from: ") 
    392         self.lblFilename.setText(self.logic.data.filename) 
     397        if self.logic.data.filename: 
     398            self.lblFilename.setText(self.logic.data.filename) 
     399        else: 
     400            self.lblFilename.setText(self.logic.data.name) 
    393401        self.updateQRange() 
    394402        # Switch off Data2D control 
     
    522530 
    523531        # Signals from separate tabs asking for replot 
    524         self.options_widget.plot_signal.connect(self.onOptionsUpdate) 
    525532        self.options_widget.plot_signal.connect(self.onOptionsUpdate) 
    526533 
     
    964971        model = self.cbModel.currentText() 
    965972 
    966         # empty combobox forced to be read 
     973        # Assure the control is active 
     974        if not self.cbModel.isEnabled(): 
     975            return 
     976        # Empty combobox forced to be read 
    967977        if not model: 
    968978            return 
    969         # Reset structure factor 
    970         self.cbStructureFactor.setCurrentIndex(0) 
    971979 
    972980        # Reset parameters to fit 
     
    975983        self.has_poly_error_column = False 
    976984 
    977         self.respondToModelStructure(model=model, structure_factor=None) 
     985        structure = None 
     986        if self.cbStructureFactor.isEnabled(): 
     987            structure = str(self.cbStructureFactor.currentText()) 
     988        self.respondToModelStructure(model=model, structure_factor=structure) 
    978989 
    979990    def onSelectBatchFilename(self, data_index): 
     
    11181129            self.disableModelCombo() 
    11191130            self.enableStructureCombo() 
     1131            # set the index to 0 
     1132            self.cbStructureFactor.setCurrentIndex(0) 
     1133            self.model_parameters = None 
    11201134            self._model_model.clear() 
    11211135            return 
     
    11421156        model_row = item.row() 
    11431157        name_index = self._poly_model.index(model_row, 0) 
    1144         parameter_name = str(name_index.data()).lower() # "distribution of sld" etc. 
    1145         if "distribution of" in parameter_name: 
     1158        parameter_name = str(name_index.data()) # "distribution of sld" etc. 
     1159        if "istribution of" in parameter_name: 
    11461160            # just the last word 
    11471161            parameter_name = parameter_name.rsplit()[-1] 
     
    11881202            # Update the sasmodel 
    11891203            # PD[ratio] -> width, npts -> npts, nsigs -> nsigmas 
    1190             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 
    11911207 
    11921208            # Update plot 
     
    11971213            row = self.getRowFromName(parameter_name) 
    11981214            param_item = self._model_model.item(row) 
     1215            self._model_model.blockSignals(True) 
    11991216            param_item.child(0).child(0, model_column).setText(item.text()) 
     1217            self._model_model.blockSignals(False) 
    12001218 
    12011219    def onMagnetModelChange(self, item): 
     
    12261244            # Unparsable field 
    12271245            return 
    1228  
    1229         property_index = self._magnet_model.headerData(1, model_column)-1 # Value, min, max, etc. 
    1230  
    1231         # Update the parameter value - note: this supports +/-inf as well 
    1232         self.kernel_module.params[parameter_name] = value 
    1233  
    1234         # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 
    1235         self.kernel_module.details[parameter_name][property_index] = value 
    1236  
    1237         # Force the chart update when actual parameters changed 
    1238         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 
    12391263            self.recalculatePlotData() 
    12401264 
     
    14971521        # Data going in 
    14981522        data = self.logic.data 
    1499         model = self.kernel_module 
     1523        model = copy.deepcopy(self.kernel_module) 
    15001524        qmin = self.q_range_min 
    15011525        qmax = self.q_range_max 
     1526        # add polydisperse/magnet parameters if asked 
     1527        self.updateKernelModelWithExtraParams(model) 
    15021528 
    15031529        params_to_fit = self.main_params_to_fit 
     
    15091535            raise ValueError('Fitting requires at least one parameter to optimize.') 
    15101536 
    1511         # Potential smearing added 
    1512         # Remember that smearing_min/max can be None -> 
    1513         # deal with it until Python gets discriminated unions 
    1514         self.addWeightingToData(data) 
    1515  
    15161537        # Get the constraints. 
    15171538        constraints = self.getComplexConstraintsForModel() 
     
    15301551            data = GuiUtils.dataFromItem(fit_index) 
    15311552            # Potential weights added directly to data 
    1532             self.addWeightingToData(data) 
     1553            weighted_data = self.addWeightingToData(data) 
    15331554            try: 
    1534                 fitter_single.set_model(model, fit_id, params_to_fit, data=data, 
     1555                fitter_single.set_model(model, fit_id, params_to_fit, data=weighted_data, 
    15351556                             constraints=constraints) 
    15361557            except ValueError as ex: 
    15371558                raise ValueError("Setting model parameters failed with: %s" % ex) 
    15381559 
    1539             qmin, qmax, _ = self.logic.computeRangeFromData(data) 
    1540             fitter_single.set_data(data=data, id=fit_id, smearer=smearer, qmin=qmin, 
     1560            qmin, qmax, _ = self.logic.computeRangeFromData(weighted_data) 
     1561            fitter_single.set_data(data=weighted_data, id=fit_id, smearer=smearer, qmin=qmin, 
    15411562                            qmax=qmax) 
    15421563            fitter_single.select_problem_for_fit(id=fit_id, value=1) 
     
    19291950        Adds weighting contribution to fitting data 
    19301951        """ 
     1952        new_data = copy.deepcopy(data) 
    19311953        # Send original data for weighting 
    19321954        weight = FittingUtilities.getWeight(data=data, is2d=self.is2D, flag=self.weighting) 
    19331955        if self.is2D: 
    1934             data.err_data = weight 
     1956            new_data.err_data = weight 
    19351957        else: 
    1936             data.dy = weight 
    1937         pass 
     1958            new_data.dy = weight 
     1959 
     1960        return new_data 
    19381961 
    19391962    def updateQRange(self): 
     
    19701993            self.addExtraShells() 
    19711994 
    1972             if structure_factor not in (None, "None"): 
    1973                 # add S(Q) 
     1995            # Allow the SF combobox visibility for the given sasmodel 
     1996            self.enableStructureFactorControl(structure_factor) 
     1997         
     1998            # Add S(Q) 
     1999            if self.cbStructureFactor.isEnabled(): 
     2000                structure_factor = self.cbStructureFactor.currentText() 
    19742001                self.fromStructureFactorToQModel(structure_factor) 
    1975             else: 
    1976                 # enable selection of S(Q) 
    1977                 self.enableStructureFactorControl(structure_factor) 
    19782002 
    19792003            # Add polydispersity to the model 
     2004            self.poly_params = {} 
    19802005            self.setPolyModel() 
    19812006            # Add magnetic parameters to the model 
     2007            self.magnet_params = {} 
    19822008            self.setMagneticModel() 
    19832009 
     
    20052031        """ 
    20062032        name = model_name 
     2033        kernel_module = None 
    20072034        if self.cbCategory.currentText() == CATEGORY_CUSTOM: 
    20082035            # custom kernel load requires full path 
     
    20102037        try: 
    20112038            kernel_module = generate.load_kernel_module(name) 
    2012         except ModuleNotFoundError: 
    2013             # maybe it's a recategorised custom model? 
    2014             name = os.path.join(ModelUtilities.find_plugins_dir(), model_name+".py") 
    2015             # If this rises, it's a valid problem. 
    2016             kernel_module = generate.load_kernel_module(name) 
     2039        except ModuleNotFoundError as ex: 
     2040            pass 
     2041 
     2042        if kernel_module is None: 
     2043            # mismatch between "name" attribute and actual filename. 
     2044            curr_model = self.models[model_name] 
     2045            name, _ = os.path.splitext(os.path.basename(curr_model.filename)) 
     2046            try: 
     2047                kernel_module = generate.load_kernel_module(name) 
     2048            except ModuleNotFoundError as ex: 
     2049                logging.error("Can't find the model "+ str(ex)) 
     2050                return 
    20172051 
    20182052        if hasattr(kernel_module, 'parameters'): 
     
    20592093        Setting model parameters into QStandardItemModel based on selected _structure factor_ 
    20602094        """ 
     2095        if structure_factor is None or structure_factor=="None": 
     2096            return 
     2097 
    20612098        s_kernel = self.models[structure_factor]() 
    20622099        p_kernel = self.kernel_module 
     
    22572294        name = self.nameFromData(fitted_data) 
    22582295        # Notify the GUI manager so it can create the theory model in DataExplorer 
    2259         new_item = GuiUtils.createModelItemWithPlot(fitted_data, name=name) 
    2260         self.communicate.updateTheoryFromPerspectiveSignal.emit(new_item) 
     2296        self.theory_item = GuiUtils.createModelItemWithPlot(fitted_data, name=name) 
     2297        self.communicate.updateTheoryFromPerspectiveSignal.emit(self.theory_item) 
    22612298 
    22622299    def nameFromData(self, fitted_data): 
     
    22812318        return self.completed1D if isinstance(self.data, Data1D) else self.completed2D 
    22822319 
     2320    def updateKernelModelWithExtraParams(self, model=None): 
     2321        """ 
     2322        Updates kernel model 'model' with extra parameters from 
     2323        the polydisp and magnetism tab, if the tabs are enabled 
     2324        """ 
     2325        if model is None: return 
     2326        if not hasattr(model, 'setParam'): return 
     2327 
     2328        # add polydisperse parameters if asked 
     2329        if self.chkPolydispersity.isChecked(): 
     2330            for key, value in self.poly_params.items(): 
     2331                model.setParam(key, value) 
     2332        # add magnetic params if asked 
     2333        if self.chkMagnetism.isChecked(): 
     2334            for key, value in self.magnet_params.items(): 
     2335                model.setParam(key, value) 
     2336 
    22832337    def calculateQGridForModelExt(self, data=None, model=None, completefn=None, use_threads=True): 
    22842338        """ 
     
    22882342            data = self.data 
    22892343        if model is None: 
    2290             model = self.kernel_module 
     2344            model = copy.deepcopy(self.kernel_module) 
     2345            self.updateKernelModelWithExtraParams(model) 
     2346 
    22912347        if completefn is None: 
    22922348            completefn = self.methodCompleteForData() 
    22932349        smearer = self.smearing_widget.smearer() 
     2350        weight = FittingUtilities.getWeight(data=data, is2d=self.is2D, flag=self.weighting) 
     2351 
    22942352        # Awful API to a backend method. 
    22952353        calc_thread = self.methodCalculateForData()(data=data, 
     
    23002358                                               smearer=smearer, 
    23012359                                               state=None, 
    2302                                                weight=None, 
     2360                                               weight=weight, 
    23032361                                               fid=None, 
    23042362                                               toggle_mode_on=False, 
     
    23482406        residuals = self.calculateResiduals(fitted_data) 
    23492407        self.model_data = fitted_data 
    2350  
    2351         new_plots = [fitted_data, residuals] 
     2408        new_plots = [fitted_data] 
     2409        if residuals is not None: 
     2410            new_plots.append(residuals) 
     2411 
     2412        if self.data_is_loaded: 
     2413            GuiUtils.deleteRedundantPlots(self.all_data[self.data_index], new_plots) 
     2414        else: 
     2415            # delete theory items for the model, in order to get rid of any redundant items, e.g. beta(Q), S_eff(Q) 
     2416            self.communicate.deleteIntermediateTheoryPlotsSignal.emit(self.kernel_module.id) 
    23522417 
    23532418        # Create plots for intermediate product data 
     
    23642429            new_plots.append(sq_data) 
    23652430 
    2366         if self.data_is_loaded: 
    2367             GuiUtils.deleteRedundantPlots(self.all_data[self.data_index], new_plots) 
    2368  
    2369         # TODO: merge rest of beta approx implementation in 
    2370         # TODO: refactor 
    2371         # deal with constrained radius_effective 
    2372         # for row in range(self._model_model.rowCount()): 
    2373         #     if self._model_model.item(row, 0).text() == "radius_effective_mode": 
    2374         #         if GuiUtils.toDouble(self._model_model.item(row, 1).text()) == 0: 
    2375         #             return 
    2376         # radius_effective = intermediate_ER() 
    2377         # if radius_effective: 
    2378         #     for row in range(self._model_model.rowCount()): 
    2379         #         if self._model_model.item(row, 0).text() == "radius_effective": 
    2380         #             self._model_model.item(row, 1).setText(str(radius_effective)) 
    2381         #             break 
    2382  
    23832431        for plot in new_plots: 
    2384             if hasattr(plot, "id") and "esidual" in plot.id: 
    2385                 # TODO: fix updates to residuals plot 
    2386                 pass 
    2387             elif plot is not None: 
    2388                 self.communicate.plotUpdateSignal.emit([plot]) 
     2432            self.communicate.plotUpdateSignal.emit([plot]) 
    23892433 
    23902434    def complete2D(self, return_data): 
     
    23932437        """ 
    23942438        fitted_data = self.logic.new2DPlot(return_data) 
    2395         self.calculateResiduals(fitted_data) 
     2439        residuals = self.calculateResiduals(fitted_data) 
    23962440        self.model_data = fitted_data 
     2441        new_plots = [fitted_data] 
     2442        if residuals is not None: 
     2443            new_plots.append(residuals) 
     2444 
     2445        # Update/generate plots 
     2446        for plot in new_plots: 
     2447            self.communicate.plotUpdateSignal.emit([plot]) 
    23972448 
    23982449    def calculateResiduals(self, fitted_data): 
     
    24042455 
    24052456        # Modify fitted_data with weighting 
    2406         self.addWeightingToData(fitted_data) 
    2407  
    2408         self.createNewIndex(fitted_data) 
     2457        weighted_data = self.addWeightingToData(fitted_data) 
     2458 
     2459        self.createNewIndex(weighted_data) 
    24092460        # Calculate difference between return_data and logic.data 
    2410         self.chi2 = FittingUtilities.calculateChi2(fitted_data, self.logic.data) 
     2461        self.chi2 = FittingUtilities.calculateChi2(weighted_data, self.logic.data) 
    24112462        # Update the control 
    24122463        chi2_repr = "---" if self.chi2 is None else GuiUtils.formatNumber(self.chi2, high=True) 
    24132464        self.lblChi2Value.setText(chi2_repr) 
    24142465 
    2415         # self.communicate.plotUpdateSignal.emit([fitted_data]) 
    2416  
    24172466        # Plot residuals if actual data 
    24182467        if not self.data_is_loaded: 
    24192468            return 
    24202469 
    2421         residuals_plot = FittingUtilities.plotResiduals(self.data, fitted_data) 
     2470        residuals_plot = FittingUtilities.plotResiduals(self.data, weighted_data) 
    24222471        residuals_plot.id = "Residual " + residuals_plot.id 
    24232472        self.createNewIndex(residuals_plot) 
     
    24882537        self._poly_model.clear() 
    24892538 
     2539        parameters = self.model_parameters.form_volume_parameters 
     2540        if self.is2D: 
     2541            parameters += self.model_parameters.orientation_parameters 
     2542 
    24902543        [self.setPolyModelParameters(i, param) for i, param in \ 
    2491             enumerate(self.model_parameters.form_volume_parameters) if param.polydisperse] 
     2544            enumerate(parameters) if param.polydisperse] 
     2545 
    24922546        FittingUtilities.addPolyHeadersToModel(self._poly_model) 
    24932547 
     
    25222576        _, min, max = self.kernel_module.details[param_name] 
    25232577 
     2578        # Update local param dict 
     2579        self.poly_params[param_name + '.width'] = width 
     2580        self.poly_params[param_name + '.npts'] = npts 
     2581        self.poly_params[param_name + '.nsigmas'] = nsigs 
     2582 
    25242583        # Construct a row with polydisp. related variable. 
    25252584        # This will get added to the polydisp. model 
     
    25712630            if not self.isCheckable(row): 
    25722631                return 
     2632            self._model_model.blockSignals(True) 
    25732633            param_name = str(self._model_model.item(row, 0).text()) 
     2634            self._model_model.blockSignals(False) 
    25742635            if param_name !=  param.name: 
    25752636                return 
    25762637            # Modify the param value 
     2638            self._model_model.blockSignals(True) 
    25772639            if self.has_error_column: 
    25782640                # err column changes the indexing 
     
    25802642            else: 
    25812643                self._model_model.item(row, 0).child(0).child(0,4).setText(combo_string) 
     2644            self._model_model.blockSignals(False) 
    25822645 
    25832646        if combo_string == 'array': 
     
    26982761                        param.units] 
    26992762 
     2763        self.magnet_params[param.name] = param.default 
     2764 
    27002765        FittingUtilities.addCheckedListToModel(model, checked_list) 
    27012766 
     
    28762941        # TODO: add polidyspersity and magnetism 
    28772942 
    2878  
    28792943    def updateUndo(self): 
    28802944        """ 
     
    29132977        if self.all_data: 
    29142978            index = self.all_data[self.data_index] 
     2979        else: 
     2980            index = self.theory_item 
    29152981        report_logic = ReportPageLogic(self, 
    29162982                                       kernel_module=self.kernel_module, 
     
    30363102        # first - regular params 
    30373103        param_list = [] 
     3104 
     3105        param_list.append(['model_name', str(self.cbModel.currentText())]) 
    30383106        def gatherParams(row): 
    30393107            """ 
     
    31223190        if lines[0] != 'sasview_parameter_values': 
    31233191            return False 
    3124         for line in lines[1:-1]: 
     3192 
     3193        model = lines[1].split(',') 
     3194 
     3195        if model[0] != 'model_name': 
     3196            return False 
     3197 
     3198        context['model_name'] = [model[1]] 
     3199        for line in lines[2:-1]: 
    31253200            if len(line) != 0: 
    31263201                item = line.split(',') 
     
    31483223                    except IndexError: 
    31493224                        pass 
     3225 
     3226        if str(self.cbModel.currentText()) != str(context['model_name'][0]): 
     3227            msg = QtWidgets.QMessageBox() 
     3228            msg.setIcon(QtWidgets.QMessageBox.Information) 
     3229            msg.setText("The model in the clipboard is not the same as the currently loaded model. \ 
     3230                         Not all parameters saved may paste correctly.") 
     3231            msg.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) 
     3232            result = msg.exec_() 
     3233            if result == QtWidgets.QMessageBox.Ok: 
     3234                pass 
     3235            else: 
     3236                return 
    31503237 
    31513238        self.updateFullModel(context) 
     
    31863273            param_repr = GuiUtils.formatNumber(param_dict[param_name][3+ioffset], high=True) 
    31873274            self._model_model.item(row, 3+ioffset).setText(param_repr) 
     3275            self.setFocus() 
     3276 
    31883277 
    31893278        # block signals temporarily, so we don't end up 
     
    31923281        self.iterateOverModel(updateFittedValues) 
    31933282        self._model_model.blockSignals(False) 
     3283 
    31943284 
    31953285    def updateFullPolyModel(self, param_dict): 
     
    32363326            param_repr = GuiUtils.formatNumber(param_dict[param_name][5+ioffset], high=True) 
    32373327            self._poly_model.item(row, 5+ioffset).setText(param_repr) 
     3328            self.setFocus() 
    32383329 
    32393330        # block signals temporarily, so we don't end up 
     
    32433334        self._poly_model.blockSignals(False) 
    32443335 
    3245  
  • src/sas/qtgui/Perspectives/Fitting/ModelThread.py

    r3ae9179 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.complete(image=output, 
    120                            data=self.data, 
    121                            page_id=self.page_id, 
    122                            model=self.model, 
    123                            state=self.state, 
    124                            toggle_mode_on=self.toggle_mode_on, 
    125                            elapsed=elapsed, 
    126                            index=index_model, 
    127                            fid=self.fid, 
    128                            qmin=self.qmin, 
    129                            qmax=self.qmax, 
    130                            weight=self.weight, 
    131                            #qstep=self.qstep, 
    132                            update_chisqr=self.update_chisqr, 
    133                            source=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.complete(x=self.data.x[index], y=output[index], 
    253                           page_id=self.page_id, 
    254                           state=self.state, 
    255                           weight=self.weight, 
    256                           fid=self.fid, 
    257                           toggle_mode_on=self.toggle_mode_on, 
    258                           elapsed=elapsed, index=index, model=self.model, 
    259                           data=self.data, 
    260                           update_chisqr=self.update_chisqr, 
    261                           source=self.source, 
    262                           unsmeared_model=unsmeared_output, 
    263                           unsmeared_data=unsmeared_data, 
    264                           unsmeared_error=unsmeared_error, 
    265                           pq_model=pq_values, 
    266                           sq_model=sq_values) 
     228            return res 
     229        else: 
     230            self.completefn(res) 
    267231 
    268232    def results(self): 
  • src/sas/qtgui/Perspectives/Fitting/OptionsWidget.py

    rc0a3b22e rb764ae5  
    7979        self.weightingGroup.buttonClicked.connect(self.onWeightingChoice) 
    8080 
     81        self.qmin = QMIN_DEFAULT 
     82        self.qmax = QMAX_DEFAULT 
     83        self.npts = NPTS_DEFAULT 
     84        if self.logic.data_is_loaded: 
     85            self.qmin, self.qmax, self.npts = self.logic.computeDataRange() 
    8186        self.initModel() 
    8287        self.initMapper() 
    8388        self.model.blockSignals(True) 
    84         self.updateQRange(QMIN_DEFAULT, QMAX_DEFAULT, NPTS_DEFAULT) 
    85         self.txtMaxRange.setText(str(QMAX_DEFAULT)) 
    86         self.txtMinRange.setText(str(QMIN_DEFAULT)) 
    87         self.txtNpts.setText(str(NPTS_DEFAULT)) 
    88         self.txtNptsFit.setText(str(NPTS_DEFAULT)) 
     89        self.updateQRange(self.qmin, self.qmax, self.npts) 
     90        self.txtMaxRange.setText(str(self.qmax)) 
     91        self.txtMinRange.setText(str(self.qmin)) 
     92        self.txtNpts.setText(str(self.npts)) 
     93        self.txtNptsFit.setText(str(self.npts)) 
    8994        self.model.blockSignals(False) 
    9095 
     
    134139        Callback for resetting qmin/qmax 
    135140        """ 
    136         self.updateQRange(QMIN_DEFAULT, QMAX_DEFAULT, NPTS_DEFAULT) 
     141        self.updateQRange(self.qmin, self.qmax, self.npts) 
    137142 
    138143    def onWeightingChoice(self, button): 
     
    179184        self.model.item(MODEL.index('MAX_RANGE')).setText(str(q_range_max)) 
    180185        self.model.item(MODEL.index('NPTS')).setText(str(npts)) 
     186        self.qmin, self.qmax, self.npts = q_range_min, q_range_max, npts 
    181187 
    182188    def state(self): 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py

    r3fbd77b r4ea8020  
    1818from sas.qtgui.Perspectives.Fitting.FittingWidget import * 
    1919from sas.qtgui.Perspectives.Fitting.Constraint import Constraint 
    20  
     20import sas.qtgui.Utilities.LocalConfig 
    2121from sas.qtgui.UnitTesting.TestUtils import QtSignalSpy 
     22from sas.qtgui.Perspectives.Fitting.ModelThread import Calc1D 
     23from sas.qtgui.Perspectives.Fitting.ModelThread import Calc2D 
    2224 
    2325from sas.qtgui.Plotting.PlotterData import Data1D 
     
    260262        self.widget.cbModel.setCurrentIndex(0) 
    261263 
    262         # Observe factor reset to None 
    263         self.assertEqual(self.widget.cbStructureFactor.currentText(), STRUCTURE_DEFAULT) 
     264        # Observe factor doesn't reset to None 
     265        self.assertEqual(self.widget.cbStructureFactor.currentText(), 'squarewell') 
    264266 
    265267        # Switch category to structure factor 
     
    319321        Check that the fitting 1D data object is ready 
    320322        """ 
    321         # Mock the thread creation 
    322         threads.deferToThread = MagicMock() 
    323         # Model for theory 
    324         self.widget.SASModelToQModel("cylinder") 
    325         # Call the tested method 
    326         self.widget.calculateQGridForModel() 
    327         time.sleep(1) 
    328         # Test the mock 
    329         self.assertTrue(threads.deferToThread.called) 
    330         self.assertEqual(threads.deferToThread.call_args_list[0][0][0].__name__, "compute") 
     323 
     324        if LocalConfig.USING_TWISTED: 
     325            # Mock the thread creation 
     326            threads.deferToThread = MagicMock() 
     327            # Model for theory 
     328            self.widget.SASModelToQModel("cylinder") 
     329            # Call the tested method 
     330            self.widget.calculateQGridForModel() 
     331            time.sleep(1) 
     332            # Test the mock 
     333            self.assertTrue(threads.deferToThread.called) 
     334            self.assertEqual(threads.deferToThread.call_args_list[0][0][0].__name__, "compute") 
     335        else: 
     336            Calc2D.queue = MagicMock() 
     337            # Model for theory 
     338            self.widget.SASModelToQModel("cylinder") 
     339            # Call the tested method 
     340            self.widget.calculateQGridForModel() 
     341            time.sleep(1) 
     342            # Test the mock 
     343            self.assertTrue(Calc2D.queue.called) 
    331344 
    332345    def testCalculateResiduals(self): 
     
    417430        index = self.widget._poly_model.index(0,0) 
    418431 
    419         #self.widget.show() 
    420         #QtWidgets.QApplication(sys.argv).exec_() 
    421  
    422432        # Set the checbox 
    423433        self.widget._poly_model.item(0,0).setCheckState(2) 
     
    435445        self.assertEqual(self.widget.kernel_module.details['radius_bell'][1], 1.0) 
    436446 
     447        #self.widget.show() 
     448        #QtWidgets.QApplication.exec_() 
     449 
    437450        # Change the number of points 
    438         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 
     451        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 35) 
    439452        self.widget._poly_model.item(0,4).setText("22") 
    440         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 
     453        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 22) 
    441454        # try something stupid 
    442455        self.widget._poly_model.item(0,4).setText("butt") 
    443456        # see that this didn't annoy the control at all 
    444         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 22) 
     457        self.assertEqual(self.widget.poly_params['radius_bell.npts'], 22) 
    445458 
    446459        # Change the number of sigmas 
    447         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 3) 
     460        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 3) 
    448461        self.widget._poly_model.item(0,5).setText("222") 
    449         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 
     462        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 222) 
    450463        # try something stupid again 
    451464        self.widget._poly_model.item(0,4).setText("beer") 
    452465        # no efect 
    453         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.nsigmas'), 222) 
     466        self.assertEqual(self.widget.poly_params['radius_bell.nsigmas'], 222) 
    454467 
    455468    def testOnPolyComboIndexChange(self): 
     
    472485        self.widget.onPolyComboIndexChange('rectangle', 0) 
    473486        # check values 
    474         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 35) 
    475         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) 
    476489        # Change the index 
    477490        self.widget.onPolyComboIndexChange('lognormal', 0) 
    478491        # check values 
    479         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 
    480         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) 
    481494        # Change the index 
    482495        self.widget.onPolyComboIndexChange('schulz', 0) 
    483496        # check values 
    484         self.assertEqual(self.widget.kernel_module.getParam('radius_bell.npts'), 80) 
    485         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) 
    486499 
    487500        # mock up file load 
     
    651664        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot') 
    652665 
    653         self.widget.show() 
    654  
    655666        # Set data 
    656667        test_data = Data1D(x=[1,2], y=[1,2]) 
    657  
     668        item = QtGui.QStandardItem() 
     669        updateModelItem(item, test_data, "test") 
    658670        # Force same data into logic 
    659         self.widget.logic.data = test_data 
    660         self.widget.data_is_loaded = True 
     671        self.widget.data = item 
    661672 
    662673        # Change the category index so we have a model available 
     
    704715        self.widget.close() 
    705716 
     717    def testOnEmptyFit2(self): 
    706718        test_data = Data2D(image=[1.0, 2.0, 3.0], 
    707719                           err_image=[0.01, 0.02, 0.03], 
     
    714726        item = QtGui.QStandardItem() 
    715727        updateModelItem(item, test_data, "test") 
     728 
    716729        # Force same data into logic 
    717730        self.widget.data = item 
     
    731744        self.widget.close() 
    732745 
    733  
    734     def testOnFit1D(self): 
     746    def notestOnFit1D(self): 
    735747        """ 
    736748        Test the threaded fitting call 
     
    770782        self.widget.close() 
    771783 
    772     def testOnFit2D(self): 
     784    def notestOnFit2D(self): 
    773785        """ 
    774786        Test the threaded fitting call 
     
    865877        # Set data 
    866878        test_data = Data1D(x=[1,2], y=[1,2]) 
    867  
     879        item = QtGui.QStandardItem() 
     880        updateModelItem(item, test_data, "test") 
    868881        # Force same data into logic 
    869         self.widget.logic.data = test_data 
    870         self.widget.data_is_loaded = True 
     882        self.widget.data = item 
     883 
     884        # Force same data into logic 
    871885        category_index = self.widget.cbCategory.findText('Sphere') 
     886 
    872887        self.widget.cbCategory.setCurrentIndex(category_index) 
    873888        self.widget.main_params_to_fit = ['scale'] 
     
    951966        # Set data 
    952967        test_data = Data1D(x=[1,2], y=[1,2]) 
    953  
     968        item = QtGui.QStandardItem() 
     969        updateModelItem(item, test_data, "test") 
    954970        # Force same data into logic 
    955         self.widget.logic.data = test_data 
    956         self.widget.data_is_loaded = True 
     971        self.widget.data = item 
    957972        category_index = self.widget.cbCategory.findText("Sphere") 
    958973        self.widget.cbCategory.setCurrentIndex(category_index) 
     
    976991        # Set data 
    977992        test_data = Data1D(x=[1,2], y=[1,2]) 
    978  
     993        item = QtGui.QStandardItem() 
     994        updateModelItem(item, test_data, "test") 
    979995        # Force same data into logic 
    980         self.widget.logic.data = test_data 
    981         self.widget.data_is_loaded = True 
     996        self.widget.data = item 
    982997        category_index = self.widget.cbCategory.findText("Sphere") 
    983998 
Note: See TracChangeset for help on using the changeset viewer.