Changeset 5c1c486 in sasview for src/sas/sasgui/perspectives/fitting


Ignore:
Timestamp:
Sep 13, 2017 8:27:29 AM (7 years ago)
Author:
lewis
Branches:
master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
Children:
fca1f50
Parents:
b76e65a (diff), 7b3f154 (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 'master' into 4.2.0-fixes

Location:
src/sas/sasgui/perspectives/fitting
Files:
3 added
7 edited

Legend:

Unmodified
Added
Removed
  • src/sas/sasgui/perspectives/fitting/fitting.py

    r0900627 r5c1c486  
    17481748            @param unsmeared_error: data error, rescaled to unsmeared model 
    17491749        """ 
    1750  
    17511750        number_finite = np.count_nonzero(np.isfinite(y)) 
    17521751        np.nan_to_num(y) 
     
    17541753                                         data_description=model.name, 
    17551754                                         data_id=str(page_id) + " " + data.name) 
     1755        plots_to_update = [] # List of plottables that have changed since last calculation 
     1756        # Create the new theories 
    17561757        if unsmeared_model is not None: 
    1757             self.create_theory_1D(x, unsmeared_model, page_id, model, data, state, 
     1758            unsmeared_model_plot = self.create_theory_1D(x, unsmeared_model,  
     1759                                  page_id, model, data, state, 
    17581760                                  data_description=model.name + " unsmeared", 
    17591761                                  data_id=str(page_id) + " " + data.name + " unsmeared") 
     1762            plots_to_update.append(unsmeared_model_plot) 
    17601763 
    17611764            if unsmeared_data is not None and unsmeared_error is not None: 
    1762                 self.create_theory_1D(x, unsmeared_data, page_id, model, data, state, 
     1765                unsmeared_data_plot = self.create_theory_1D(x, unsmeared_data,  
     1766                                      page_id, model, data, state, 
    17631767                                      data_description="Data unsmeared", 
    17641768                                      data_id="Data  " + data.name + " unsmeared", 
    17651769                                      dy=unsmeared_error) 
    1766         # Comment this out until we can get P*S models with correctly populated parameters 
    1767         #if sq_model is not None and pq_model is not None: 
    1768         #    self.create_theory_1D(x, sq_model, page_id, model, data, state, 
    1769         #                          data_description=model.name + " S(q)", 
    1770         #                          data_id=str(page_id) + " " + data.name + " S(q)") 
    1771         #    self.create_theory_1D(x, pq_model, page_id, model, data, state, 
    1772         #                          data_description=model.name + " P(q)", 
    1773         #                          data_id=str(page_id) + " " + data.name + " P(q)") 
     1770                plots_to_update.append(unsmeared_data_plot) 
     1771        if sq_model is not None and pq_model is not None: 
     1772            sq_id = str(page_id) + " " + data.name + " S(q)" 
     1773            sq_plot = self.create_theory_1D(x, sq_model, page_id, model, data, state, 
     1774                                  data_description=model.name + " S(q)", 
     1775                                  data_id=sq_id) 
     1776            plots_to_update.append(sq_plot) 
     1777            pq_id = str(page_id) + " " + data.name + " P(q)" 
     1778            pq_plot = self.create_theory_1D(x, pq_model, page_id, model, data, state, 
     1779                                  data_description=model.name + " P(q)", 
     1780                                  data_id=pq_id) 
     1781            plots_to_update.append(pq_plot) 
     1782        # Update the P(Q), S(Q) and unsmeared theory plots if they exist 
     1783        wx.PostEvent(self.parent, NewPlotEvent(plots=plots_to_update,  
     1784                                              action='update')) 
    17741785 
    17751786        current_pg = self.fit_panel.get_page_by_id(page_id) 
  • src/sas/sasgui/perspectives/fitting/media/fitting_help.rst

    r5295cf5 r05b0bf6  
    484484.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    485485 
     486.. _Batch_Fit_Mode: 
     487 
    486488Batch Fit Mode 
    487489-------------- 
     
    636638 
    637639     Example: radius [2 : 5] , radius [10 : 25] 
    638  
    639 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    640  
    641 .. note::  This help document was last changed by Steve King, 10Oct2016 
     640      
     641.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     642 
     643Combined Batch Fit Mode 
     644----------------------- 
     645 
     646The purpose of the Combined Batch Fit is to allow running two or more batch 
     647fits in sequence without overwriting the output table of results.  This may be 
     648of interest for example if one is fitting a series of data sets where there is 
     649a shape change occurring in the series that requires changing the model part 
     650way through the series; for example a sphere to rod transition.  Indeed the 
     651regular batch mode does not allow for multiple models and requires all the 
     652files in the series to be fit with single model and set of parameters.  While 
     653it is of course possible to just run part of the series as a batch fit using 
     654model one followed by running another batch fit on the rest of the series with 
     655model two (and/or model three etc), doing so will overwrite the table of 
     656outputs from the previous batch fit(s).  This may not be desirable if one is 
     657interested in comparing the parameters: for example the sphere radius of set 
     658one and the cylinder radius of set two. 
     659 
     660Method 
     661^^^^^^ 
     662 
     663In order to use the *Combined Batch Fit*, first load all the data needed as 
     664described in :ref:`Loading_data`. Next start up two or more *BatchPage* fits 
     665following the instructions in :ref:`Batch_Fit_Mode` but **DO NOT PRESS FIT**. 
     666At this point the *Combine Batch Fit* menu item under the *Fitting menu* should 
     667be active (if there is one or no *BatchPage* the menu item will be greyed out 
     668and inactive).  Clicking on *Combine Batch Fit* will bring up a new panel, 
     669similar to the *Const & Simult Fit* panel. In this case there will be a 
     670checkbox for each *BatchPage* instead of each *FitPage* that should be included 
     671in the fit.  Once all are selected, click the Fit button on 
     672the *BatchPage* to run each batch fit in *sequence* 
     673 
     674.. image:: combine_batch_page.png 
     675 
     676The batch table will then pop up at the end as for the case of the simple Batch 
     677Fitting with the following caveats: 
     678 
     679.. note:: 
     680   The order matters.  The parameters in the table will be taken from the model 
     681   used in the first *BatchPage* of the list.  Any parameters from the 
     682   second and later *BatchPage* s that have the same name as a parameter in the 
     683   first will show up allowing for plotting of that parameter across the 
     684   models. The other parameters will not be available in the grid. 
     685.. note:: 
     686   a corralary of the above is that currently models created as a sum|multiply 
     687   model will not work as desired because the generated model parameters have a 
     688   p#_ appended to the beginning and thus radius and p1_radius will not be 
     689   recognized as the same parameter. 
     690    
     691.. image:: combine_batch_grid.png 
     692 
     693In the example shown above the data is a time series with a shifting peak. 
     694The first part of the series was fitted using the *broad_peak* model, while 
     695the rest of the data were fit using the *gaussian_peak* model. Unfortunately the 
     696time is not listed in the file but the file name contains the information. As 
     697described in :ref:`Grid_Window`, a column can be added manually, in this case 
     698called time, and the peak position plotted against time.  
     699 
     700.. image:: combine_batch_plot.png 
     701 
     702Note the discontinuity in the peak position.  This reflects the fact that the 
     703Gaussian fit is a rather poor model for the data and is not actually 
     704finding the peak. 
     705 
     706.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
     707 
     708.. note::  This help document was last changed by Paul Butler, 10 September 
     709   2017 
  • src/sas/sasgui/perspectives/fitting/model_thread.py

    r7432acb r0f9ea1c  
    7171                    (self.data.qy_data * self.data.qy_data)) 
    7272 
    73         # For theory, qmax is based on 1d qmax  
     73        # For theory, qmax is based on 1d qmax 
    7474        # so that must be mulitified by sqrt(2) to get actual max for 2d 
    7575        index_model = (self.qmin <= radius) & (radius <= self.qmax) 
     
    9191                self.data.qy_data[index_model] 
    9292            ]) 
    93         output = np.zeros(len(self.data.qx_data)) 
     93        # Initialize output to NaN so masked elements do not get plotted. 
     94        output = np.empty_like(self.data.qx_data) 
    9495        # output default is None 
    9596        # This method is to distinguish between masked 
    9697        #point(nan) and data point = 0. 
    97         output = output / output 
     98        output[:] = np.NaN 
    9899        # set value for self.mask==True, else still None to Plottools 
    99100        output[index_model] = value 
     
    198199            output[index] = self.model.evalDistribution(self.data.x[index]) 
    199200 
     201        x=self.data.x[index] 
     202        y=output[index] 
    200203        sq_values = None 
    201204        pq_values = None 
    202         s_model = None 
    203         p_model = None 
    204205        if isinstance(self.model, MultiplicationModel): 
    205206            s_model = self.model.s_model 
    206207            p_model = self.model.p_model 
    207         elif hasattr(self.model, "get_composition_models"): 
    208             p_model, s_model = self.model.get_composition_models() 
    209  
    210         if p_model is not None and s_model is not None: 
    211             sq_values = np.zeros((len(self.data.x))) 
    212             pq_values = np.zeros((len(self.data.x))) 
    213             sq_values[index] = s_model.evalDistribution(self.data.x[index]) 
    214             pq_values[index] = p_model.evalDistribution(self.data.x[index]) 
     208            sq_values = s_model.evalDistribution(x) 
     209            pq_values = p_model.evalDistribution(x) 
     210        elif hasattr(self.model, "calc_composition_models"): 
     211            results = self.model.calc_composition_models(x) 
     212            if results is not None: 
     213                pq_values, sq_values = results 
     214 
    215215 
    216216        elapsed = time.time() - self.starttime 
    217217 
    218         self.complete(x=self.data.x[index], y=output[index], 
     218        self.complete(x=x, y=y, 
    219219                      page_id=self.page_id, 
    220220                      state=self.state, 
  • src/sas/sasgui/perspectives/fitting/simfitpage.py

    r959eb01 ra9f9ca4  
    11""" 
    2     Simultaneous fit page 
     2    Simultaneous or Batch fit page 
    33""" 
     4# Note that this is used for both Simultaneous/Constrained fit AND for  
     5# combined batch fit.  This is done through setting of the batch_on parameter. 
     6# There are the a half dozen or so places where an if statement is used as in  
     7# if not batch_on: 
     8#     xxxx 
     9# else: 
     10#     xxxx 
     11# This is just wrong but dont have time to fix this go. Proper approach would be 
     12# to strip all parts of the code that depend on batch_on and create the top 
     13# level class from which a contrained/simultaneous fit page and a combined  
     14# batch page inherit. 
     15# 
     16#            04/09/2017   --PDB 
     17 
    418import sys 
    519from collections import namedtuple 
     
    400414        # General Help button 
    401415        self.btHelp = wx.Button(self, wx.ID_HELP, 'HELP') 
    402         self.btHelp.SetToolTipString("Simultaneous/Constrained Fitting help.") 
     416        if self.batch_on: 
     417            self.btHelp.SetToolTipString("Combined Batch Fitting help.") 
     418        else: 
     419            self.btHelp.SetToolTipString("Simultaneous/Constrained Fitting help.") 
    403420        self.btHelp.Bind(wx.EVT_BUTTON, self._on_help) 
    404421 
     
    527544    """ 
    528545        _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html" 
    529         _PageAnchor = "#simultaneous-fit-mode" 
    530         _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation, 
     546        if not self.batch_on: 
     547            _PageAnchor = "#simultaneous-fit-mode" 
     548            _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation, 
    531549                                          _PageAnchor, 
    532550                                          "Simultaneous/Constrained Fitting Help") 
     551        else: 
     552            _PageAnchor = "#combined-batch-fit-mode" 
     553            _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation, 
     554                                          _PageAnchor, 
     555                                          "Combined Batch Fit Help") 
    533556 
    534557    def set_manager(self, manager): 
  • src/sas/sasgui/perspectives/fitting/basepage.py

    r914c49d5 rb76e65a  
    29292929            return False 
    29302930 
     2931 
     2932    def _get_copy_params_details(self): 
     2933        """ 
     2934        Combines polydisperse parameters with self.parameters so that they can 
     2935        be written to the clipboard (for Excel or LaTeX). Also returns a list of 
     2936        the names of parameters that have been fitted 
     2937 
     2938        :returns: all_params - A list of all parameters, in the format of  
     2939        self.parameters 
     2940        :returns: fitted_par_names - A list of the names of parameters that have 
     2941        been fitted 
     2942        """ 
     2943        # Names of params that are being fitted 
     2944        fitted_par_names = [param[1] for param in self.param_toFit] 
     2945        # Names of params with associated polydispersity 
     2946        disp_params = [param[1].split('.')[0] for param in self.fittable_param] 
     2947 
     2948        # Create array of all parameters 
     2949        all_params = copy.copy(self.parameters) 
     2950        for param in self.parameters: 
     2951            if param[1] in disp_params: 
     2952                # Polydisperse params aren't in self.parameters, so need adding 
     2953                # to all_params 
     2954                name = param[1] + ".width" 
     2955                index = all_params.index(param) + 1 
     2956                to_insert = [] 
     2957                if name in fitted_par_names: 
     2958                    # Param is fitted, so already has a param list in self.param_toFit 
     2959                    to_insert = self.param_toFit[fitted_par_names.index(name)] 
     2960                else: 
     2961                    # Param isn't fitted, so mockup a param list 
     2962                    to_insert = [None, name, self.model.getParam(name), None, None] 
     2963                all_params.insert(index, to_insert) 
     2964        return all_params, fitted_par_names 
     2965 
    29312966    def get_copy_excel(self): 
    29322967        """ 
     
    29422977        Get the string copies of the param names and values in the tap 
    29432978        """ 
     2979        if not self.parameters: 
     2980            # Do nothing if parameters doesn't exist 
     2981            return False 
     2982 
    29442983        content = '' 
    2945  
    29462984        crlf = chr(13) + chr(10) 
    29472985        tab = chr(9) 
    29482986 
    2949         # Do it if params exist 
    2950         if self.parameters: 
    2951  
    2952             for param in self.parameters: 
    2953                 content += param[1]  # parameter name 
     2987        all_params, fitted_param_names = self._get_copy_params_details() 
     2988 
     2989        # Construct row of parameter names 
     2990        for param in all_params: 
     2991            name = param[1] # Parameter name 
     2992            content += name 
     2993            content += tab 
     2994            if name in fitted_param_names: 
     2995                # Only print errors for fitted parameters 
     2996                content += name + "_err" 
    29542997                content += tab 
    2955                 content += param[1] + "_err" 
    2956                 content += tab 
    2957  
    2958             content += crlf 
    2959  
    2960             # row of values and errors... 
    2961             for param in self.parameters: 
    2962                 content += param[2].GetValue()  # value 
    2963                 content += tab 
    2964                 content += param[4].GetValue()  # error 
    2965                 content += tab 
    2966  
    2967             return content 
    2968         else: 
    2969             return False 
     2998 
     2999        content += crlf 
     3000 
     3001        # Construct row of parameter values and errors 
     3002        for param in all_params: 
     3003            value = param[2] 
     3004            if hasattr(value, 'GetValue'): 
     3005                # param[2] is a text box 
     3006                value = value.GetValue() 
     3007            else: 
     3008                # param[2] is a float (from our self._get_copy_params_details) 
     3009                value = str(value) 
     3010            content += value 
     3011            content += tab 
     3012            if param[1] in fitted_param_names: 
     3013                # Only print errors for fitted parameters 
     3014                content += param[4].GetValue() 
     3015                content += tab  
     3016 
     3017        return content 
    29703018 
    29713019    def get_copy_latex(self): 
     
    29823030        Get the string copies of the param names and values in the tap 
    29833031        """ 
     3032        if not self.parameters: 
     3033            # Do nothing if self.parameters doesn't exist 
     3034            return False 
     3035         
    29843036        content = '\\begin{table}' 
    29853037        content += '\\begin{tabular}[h]' 
     
    29883040        tab = chr(9) 
    29893041 
    2990         # Do it if params exist 
    2991         if self.parameters: 
    2992  
    2993             content += '{|' 
    2994             for param in self.parameters: 
    2995                 content += 'l|l|' 
    2996             content += '}\hline' 
    2997             content += crlf 
    2998  
    2999             for index, param in enumerate(self.parameters): 
    3000                 content += param[1].replace('_', '\_')  # parameter name 
     3042        all_params, fitted_param_names = self._get_copy_params_details() 
     3043 
     3044        content += '{|' 
     3045        for param in all_params: 
     3046            content += 'l|l|' 
     3047        content += '}\hline' 
     3048        content += crlf 
     3049 
     3050        # Construct row of parameter names 
     3051        for index, param in enumerate(all_params): 
     3052            name = param[1] # Parameter name 
     3053            content += name.replace('_', '\_')  # Escape underscores 
     3054            if name in fitted_param_names: 
     3055                # Only print errors for fitted parameters 
    30013056                content += ' & ' 
    3002                 content += param[1].replace('_', '\_') + "\_err" 
    3003                 if index < len(self.parameters) - 1: 
    3004                     content += ' & ' 
    3005             content += '\\\\ \\hline' 
    3006             content += crlf 
    3007  
    3008             # row of values and errors... 
    3009             for index, param in enumerate(self.parameters): 
    3010                 content += param[2].GetValue()  # parameter value 
     3057                content += name.replace('_', '\_') + "\_err" 
     3058            if index < len(all_params) - 1: 
    30113059                content += ' & ' 
    3012                 content += param[4].GetValue()  # parameter error 
    3013                 if index < len(self.parameters) - 1: 
    3014                     content += ' & ' 
    3015             content += '\\\\ \\hline' 
    3016             content += crlf 
    3017  
    3018             content += '\\end{tabular}' 
    3019             content += '\\end{table}' 
    3020             return content 
    3021         else: 
    3022             return False 
     3060 
     3061        content += '\\\\ \\hline' 
     3062        content += crlf 
     3063 
     3064        # Construct row of values and errors 
     3065        for index, param in enumerate(all_params): 
     3066            value = param[2] 
     3067            if hasattr(value, "GetValue"): 
     3068                # value is a text box 
     3069                value = value.GetValue() 
     3070            else: 
     3071                # value is a float (from self._get_copy_params_details) 
     3072                value = str(value) 
     3073            content += value 
     3074            if param[1] in fitted_param_names: 
     3075                # Only print errors for fitted params 
     3076                content += ' & ' 
     3077                content += param[4].GetValue() 
     3078            if index < len(all_params) - 1: 
     3079                content += ' & ' 
     3080         
     3081        content += '\\\\ \\hline' 
     3082        content += crlf 
     3083        content += '\\end{tabular}' 
     3084        content += '\\end{table}' 
     3085 
     3086        return content 
    30233087 
    30243088    def set_clipboard(self, content=None): 
  • src/sas/sasgui/perspectives/fitting/fitpage.py

    red2276f r0b6f83c  
    289289        self.btFitHelp.SetToolTipString("General fitting help.") 
    290290        self.btFitHelp.Bind(wx.EVT_BUTTON, self._onFitHelp) 
    291          
     291 
    292292        # Resolution Smearing Help button (for now use same technique as 
    293293        # used for dI help to get tiniest possible button that works 
     
    303303        self.btSmearHelp.SetToolTipString("Resolution smearing help.") 
    304304        self.btSmearHelp.Bind(wx.EVT_BUTTON, self._onSmearHelp) 
    305          
     305 
    306306        # textcntrl for custom resolution 
    307307        self.smear_pinhole_percent = ModelTextCtrl(self, wx.ID_ANY, 
     
    564564        sizer.Add(self.draw_button, 0, 0) 
    565565        sizer.Add((-1, 5)) 
    566          
     566 
    567567        sizer.Add(self.tcChi, 0, 0) 
    568568        sizer.Add(self.Npts_fit, 0, 0) 
     
    570570        sizer.Add(self.btFit, 0, 0) 
    571571        sizer.Add(self.btFitHelp, 0, 0) 
    572          
     572 
    573573        boxsizer_range.Add(sizer_chi2) 
    574574        boxsizer_range.Add(sizer) 
     
    21812181        self.save_current_state() 
    21822182 
     2183        if not self.is_mac: 
     2184            self.Layout() 
     2185            self.Refresh() 
    21832186        # plot model ( when drawing, do not update chisqr value again) 
    21842187        self._draw_model(update_chisqr=False, source='fit') 
     
    27752778            else: 
    27762779                return cmp(a.lower(), b.lower()) 
    2777          
     2780 
    27782781        # keys obtained now from ordered dict, so commenting alphabetical 
    27792782        # ordering keys.sort(custom_compare) 
  • src/sas/sasgui/perspectives/fitting/fitpanel.py

    r67b0a99 r6f9abd3  
    501501            if data is None: 
    502502                return None 
     503        focused_page = self.GetPage(self.GetSelection()) 
    503504        for page in self.opened_pages.values(): 
    504505            # check if the selected data existing in the fitpanel 
    505506            pos = self.GetPageIndex(page) 
    506507            if not check_data_validity(page.get_data()) and not page.batch_on: 
     508                if page.model is not None and page != focused_page: 
     509                    # Page has an active theory and is in background - don't 
     510                    # send data here. 
     511                    continue 
    507512                # make sure data get placed in 1D empty tab if data is 1D 
    508513                # else data get place on 2D tab empty tab 
Note: See TracChangeset for help on using the changeset viewer.