source: sasview/sansview/perspectives/fitting/fitting.py @ 57f3320

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 57f3320 was 57f3320, checked in by Gervaise Alina <gervyh@…>, 16 years ago

trying to reduce the 2 fitting methods

  • Property mode set to 100644
File size: 21.9 KB
Line 
1import os,os.path, re
2import sys, wx, logging
3import string, numpy, pylab, math
4
5from copy import deepcopy
6from sans.guitools.plottables import Data1D, Theory1D
7from sans.guitools.PlotPanel import PlotPanel
8from sans.guicomm.events import NewPlotEvent, StatusEvent 
9from sans.fit.AbstractFitEngine import Model,Data
10from fitproblem import FitProblem
11from fitpanel import FitPanel
12
13import models
14import fitpage
15import park
16
17class Plugin:
18    """
19        Fitting plugin is used to perform fit
20    """
21    def __init__(self):
22        ## Plug-in name
23        self.sub_menu = "Fitting"
24       
25        ## Reference to the parent window
26        self.parent = None
27        self.menu_mng = models.ModelManager()
28        ## List of panels for the simulation perspective (names)
29        self.perspective = []
30        # Start with a good default
31        self.elapsed = 0.022
32        self.fitter  = None
33       
34        #Flag to let the plug-in know that it is running standalone
35        self.standalone=True
36        ## Fit engine
37        self._fit_engine = 'scipy'
38        # Log startup
39        logging.info("Fitting plug-in started")   
40
41    def populate_menu(self, id, owner):
42        """
43            Create a menu for the Fitting plug-in
44            @param id: id to create a menu
45            @param owner: owner of menu
46            @ return : list of information to populate the main menu
47        """
48        #Menu for fitting
49        self.menu1 = wx.Menu()
50        id1 = wx.NewId()
51        self.menu1.Append(id1, '&Show fit panel')
52        wx.EVT_MENU(owner, id1, self.on_perspective)
53        id3 = wx.NewId()
54        self.menu1.AppendCheckItem(id3, "park") 
55        wx.EVT_MENU(owner, id3, self._onset_engine)
56       
57        #menu for model
58        menu2 = wx.Menu()
59        self.menu_mng.populate_menu(menu2, owner)
60        id2 = wx.NewId()
61        owner.Bind(models.EVT_MODEL,self._on_model_menu)
62        self.fit_panel.set_owner(owner)
63        self.fit_panel.set_model_list(self.menu_mng.get_model_list())
64        owner.Bind(fitpage.EVT_MODEL_BOX,self._on_model_panel)
65        #create  menubar items
66        return [(id, self.menu1, "Fitting"),(id2, menu2, "Model")]
67   
68   
69    def help(self, evt):
70        """
71            Show a general help dialog.
72            TODO: replace the text with a nice image
73        """
74        pass
75   
76    def get_context_menu(self, graph=None):
77        """
78            Get the context menu items available for P(r)
79            @param graph: the Graph object to which we attach the context menu
80            @return: a list of menu items with call-back function
81        """
82        self.graph=graph
83        for item in graph.plottables:
84            if item.name==graph.selected_plottable and item.__class__.__name__ is not "Theory1D":
85                return [["Select Data", "Dialog with fitting parameters ", self._onSelect]] 
86        return []   
87
88
89    def get_panels(self, parent):
90        """
91            Create and return a list of panel objects
92        """
93        self.parent = parent
94        # Creation of the fit panel
95        self.fit_panel = FitPanel(self.parent, -1)
96        #Set the manager forthe main panel
97        self.fit_panel.set_manager(self)
98        # List of windows used for the perspective
99        self.perspective = []
100        self.perspective.append(self.fit_panel.window_name)
101        # take care of saving  data, model and page associated with each other
102        self.page_finder = {}
103        #index number to create random model name
104        self.index_model = 0
105        #create the fitting panel
106        return [self.fit_panel]
107   
108     
109    def get_perspective(self):
110        """
111            Get the list of panel names for this perspective
112        """
113        return self.perspective
114   
115   
116    def on_perspective(self, event):
117        """
118            Call back function for the perspective menu item.
119            We notify the parent window that the perspective
120            has changed.
121        """
122        self.parent.set_perspective(self.perspective)
123   
124   
125    def post_init(self):
126        """
127            Post initialization call back to close the loose ends
128            [Somehow openGL needs this call]
129        """
130        self.parent.set_perspective(self.perspective)
131       
132       
133    def _onSelect(self,event):
134        """
135            when Select data to fit a new page is created .Its reference is
136            added to self.page_finder
137        """
138        self.panel = event.GetEventObject()
139        for item in self.panel.graph.plottables:
140            if item.name == self.panel.graph.selected_plottable:
141                #find a name for the page created for notebook
142                try:
143                    name = item.group_id # item in Data1D
144                except:
145                    name = 'Fit'
146                try:
147                    page = self.fit_panel.add_fit_page(name)
148                    # add data associated to the page created
149                    page.set_data_name(item)
150                    #create a fitproblem storing all link to data,model,page creation
151                    self.page_finder[page]= FitProblem()
152                    #data_for_park= Data(sans_data=item)
153                    #datap = PlottableData(data=data_for_park,data1d=item)
154                    #self.page_finder[page].add_data(datap)
155                    self.page_finder[page].add_data(item)
156                except:
157                    #raise
158                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: \
159                    data already Selected "))
160    def schedule_for_fit(self,value=0,fitproblem =None): 
161        """
162       
163        """   
164        if fitproblem !=None:
165            fitproblem.schedule_tofit(value)
166        else:
167            current_pg=self.fit_panel.get_current_page() 
168            for page, val in self.page_finder.iteritems():
169                if page ==current_pg :
170                    val.schedule_tofit(value)
171                    break
172                     
173                   
174    def get_page_finder(self):
175        """ @return self.page_finder used also by simfitpage.py""" 
176        return self.page_finder
177   
178   
179    def set_page_finder(self,modelname,names,values):
180        """
181             Used by simfitpage.py to reset a parameter given the string constrainst.
182             @param modelname: the name ot the model for with the parameter has to reset
183             @param value: can be a string in this case.
184             @param names: the paramter name
185             @note: expecting park used for fit.
186        """ 
187        sim_page=self.fit_panel.get_page(0)
188        for page, value in self.page_finder.iteritems():
189            if page != sim_page:
190                list=value.get_model()
191                model=list[0]
192                print "fitting",model.name,modelname
193                if model.name== modelname:
194                    value.set_model_param(names,values)
195                    break
196
197   
198                           
199    def split_string(self,item): 
200        """
201            receive a word containing dot and split it. used to split parameterset
202            name into model name and parameter name example:
203            paramaterset (item) = M1.A
204            @return model_name =M1 , parameter name =A
205        """
206        if string.find(item,".")!=-1:
207            param_names= re.split("\.",item)
208            model_name=param_names[0]
209            param_name=param_names[1] 
210            return model_name,param_name
211       
212       
213    def _single_fit_completed(self,result,pars,cpage,qmin,qmax):
214        """
215            Display fit result on one page of the notebook.
216            @param result: result of fit
217            @param pars: list of names of parameters fitted
218            @param current_pg: the page where information will be displayed
219            @param qmin: the minimum value of x to replot the model
220            @param qmax: the maximum value of x to replot model
221         
222        """
223        try:
224            for page, value in self.page_finder.iteritems():
225                if page==cpage :
226                    data = value.get_data()
227                    list = value.get_model()
228                    model= list[0]
229                    break
230            i = 0
231#            print "fitting: single fit pars ", pars
232            for name in pars:
233                if result.pvec.__class__==numpy.float64:
234                    model.setParam(name,result.pvec)
235                else:
236                    model.setParam(name,result.pvec[i])
237#                    print "fitting: single fit", name, result.pvec[i]
238                    i += 1
239#            print "fitting result : chisqr",result.fitness
240#            print "fitting result : pvec",result.pvec
241#            print "fitting result : stderr",result.stderr
242           
243            cpage.onsetValues(result.fitness, result.pvec,result.stderr)
244            self.plot_helper(currpage=cpage,qmin=qmin,qmax=qmax)
245        except:
246            raise
247            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
248           
249       
250    def _simul_fit_completed(self,result,qmin,qmax):
251        """
252            Parameter estimation completed,
253            display the results to the user
254            @param alpha: estimated best alpha
255            @param elapsed: computation time
256        """
257        try:
258            for page, value in self.page_finder.iteritems():
259                if value.get_scheduled()==1:
260                    data = value.get_data()
261                    list = value.get_model()
262                    model= list[0]
263                   
264                    small_out = []
265                    small_cov = []
266                    i = 0
267                    #Separate result in to data corresponding to each page
268                    for p in result.parameters:
269                        model_name,param_name = self.split_string(p.name) 
270                        if model.name == model_name:
271                            small_out.append(p.value )
272                            small_cov.append(p.stderr)
273                            model.setParam(param_name,p.value) 
274                    # Display result on each page
275                    page.onsetValues(result.fitness, small_out,small_cov)
276                    #Replot model
277                    self.plot_helper(currpage= page,qmin= qmin,qmax= qmax) 
278        except:
279             wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
280           
281   
282    def _on_single_fit(self,id=None,qmin=None,qmax=None):
283        """
284            perform fit for the  current page  and return chisqr,out and cov
285            @param engineName: type of fit to be performed
286            @param id: unique id corresponding to a fit problem(model, set of data)
287            @param model: model to fit
288           
289        """
290        #print "in single fitting"
291        #set an engine to perform fit
292        from sans.fit.Fitting import Fit
293        self.fitter= Fit(self._fit_engine)
294        #Setting an id to store model and data in fit engine
295        if id==None:
296            id=0
297        self.id = id
298        page_fitted=None
299        fit_problem=None
300        #Get information (model , data) related to the page on
301        #with the fit will be perform
302        #current_pg=self.fit_panel.get_current_page()
303        #simul_pg=self.fit_panel.get_page(0)
304           
305        for page, value in self.page_finder.iteritems():
306            if  value.get_scheduled() ==1 :
307                data = value.get_data()
308                list=value.get_model()
309                model=list[0]
310                #Create list of parameters for fitting used
311                pars=[]
312                templist=[]
313                try:
314                    #templist=current_pg.get_param_list()
315                    templist=page.get_param_list()
316                    for element in templist:
317                        pars.append(str(element[0].GetLabelText()))
318                    pars.sort()
319                    #Do the single fit
320                    self.fitter.set_model(Model(model), self.id, pars) 
321                    self.fitter.set_data(Data(sans_data=data),self.id,qmin,qmax)
322                    self.fitter.select_problem_for_fit(Uid=self.id,value=value.get_scheduled())
323                    page_fitted=page
324                    self.id+=1
325                    self.schedule_for_fit( 0,value) 
326                except:
327                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
328                    return
329                # make sure to keep an alphabetic order
330                #of parameter names in the list     
331        try:
332            result=self.fitter.fit()
333            #self._single_fit_completed(result,pars,current_pg,qmin,qmax)
334            print "single_fit: result",result.fitness,result.pvec,result.stderr
335            #self._single_fit_completed(result,pars,page,qmin,qmax)
336            self._single_fit_completed(result,pars,page_fitted,qmin,qmax)
337        except:
338            wx.PostEvent(self.parent, StatusEvent(status="Single Fit error: %s" % sys.exc_value))
339            return
340         
341    def _on_simul_fit(self, id=None,qmin=None,qmax=None):
342        """
343            perform fit for all the pages selected on simpage and return chisqr,out and cov
344            @param engineName: type of fit to be performed
345            @param id: unique id corresponding to a fit problem(model, set of data)
346             in park_integration
347            @param model: model to fit
348           
349        """
350        #set an engine to perform fit
351        from sans.fit.Fitting import Fit
352        self.fitter= Fit(self._fit_engine)
353       
354        #Setting an id to store model and data
355        if id==None:
356             id = 0
357        self.id = id
358       
359        for page, value in self.page_finder.iteritems():
360            try:
361                if value.get_scheduled()==1:
362                    data = value.get_data()
363                    list = value.get_model()
364                    model= list[0]
365                    #Create dictionary of parameters for fitting used
366                    pars = []
367                    templist = []
368                    templist = page.get_param_list()
369                    for element in templist:
370                        try:
371                            name = str(element[0].GetLabelText())
372                            pars.append(name)
373                        except:
374                            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
375                            return
376                    new_model=Model(model)
377                    param=value.get_model_param()
378                   
379                    if len(param)>0:
380                        for item in param:
381                            param_value = item[1]
382                            param_name = item[0]
383                            #print "fitting ", param,param_name, param_value
384                           
385                            #new_model.set( model.getParam(param_name[0])= param_value)
386                            #new_model.set( exec"%s=%s"%(param_name[0], param_value))
387                            #new_model.set( exec "%s"%(param_nam) = param_value)
388                            new_model.parameterset[ param_name].set( param_value )
389                           
390                    self.fitter.set_model(new_model, self.id, pars) 
391                    self.fitter.set_data(Data(sans_data=data),self.id,qmin,qmax)
392                    self.fitter.select_problem_for_fit(Uid=self.id,value=value.get_scheduled())
393                    self.id += 1 
394            except:
395                wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
396                return 
397        #Do the simultaneous fit
398        try:
399            result=self.fitter.fit()
400            self._simul_fit_completed(result,qmin,qmax)
401        except:
402            wx.PostEvent(self.parent, StatusEvent(status="Simultaneous Fitting error: %s" % sys.exc_value))
403            return
404       
405       
406    def _onset_engine(self,event):
407        """ set engine to scipy"""
408        if self._fit_engine== 'park':
409            self._on_change_engine('scipy')
410        else:
411            self._on_change_engine('park')
412        wx.PostEvent(self.parent, StatusEvent(status="Engine set to: %s" % self._fit_engine))
413 
414   
415    def _on_change_engine(self, engine='park'):
416        """
417            Allow to select the type of engine to perform fit
418            @param engine: the key work of the engine
419        """
420        self._fit_engine = engine
421   
422   
423    def _on_model_panel(self, evt):
424        """
425            react to model selection on any combo box or model menu.plot the model 
426        """
427        model = evt.model
428        name = evt.name
429        sim_page=self.fit_panel.get_page(0)
430        current_pg = self.fit_panel.get_current_page() 
431        if current_pg != sim_page:
432            current_pg.set_model_name(name)
433            current_pg.set_panel(model)
434            try:
435                data=self.page_finder[current_pg].get_data()
436                M_name="M"+str(self.index_model)+"= "+name+"("+data.group_id+")"
437            except:
438                raise 
439                M_name="M"+str(self.index_model)+"= "+name
440            model.name="M"+str(self.index_model)
441            self.index_model += 1 
442           
443            self.page_finder[current_pg].set_model(model,M_name)
444            self.plot_helper(currpage= current_pg,qmin= None,qmax= None)
445            sim_page.add_model(self.page_finder)
446       
447           
448    def redraw_model(self,qmin= None,qmax= None):
449        """
450            Draw a theory according to model changes or data range.
451            @param qmin: the minimum value plotted for theory
452            @param qmax: the maximum value plotted for theory
453        """
454        current_pg=self.fit_panel.get_current_page()
455        for page, value in self.page_finder.iteritems():
456            if page ==current_pg :
457                break 
458        self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
459       
460    def plot_helper(self,currpage,qmin=None,qmax=None):
461        """
462            Plot a theory given a model and data
463            @param model: the model from where the theory is derived
464            @param currpage: page in a dictionary referring to some data
465        """
466        if self.fit_panel.get_page_count() >1:
467            for page in self.page_finder.iterkeys():
468                if  page==currpage : 
469                    break 
470            data=self.page_finder[page].get_data()
471            list=self.page_finder[page].get_model()
472            model=list[0]
473            if data!=None:
474                theory = Theory1D(x=[], y=[])
475                theory.name = "Model"
476                theory.group_id = data.group_id
477             
478                x_name, x_units = data.get_xaxis() 
479                y_name, y_units = data.get_yaxis() 
480                theory.xaxis(x_name, x_units)
481                theory.yaxis(y_name, y_units)
482                if qmin == None :
483                   qmin = min(data.x)
484                if qmax == None :
485                    qmax = max(data.x)
486                try:
487                    tempx = qmin
488                    tempy = model.run(qmin)
489                    theory.x.append(tempx)
490                    theory.y.append(tempy)
491                except :
492                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
493                        skipping point x %g %s" %(qmin, sys.exc_value)))
494                           
495                for i in range(len(data.x)):
496                    try:
497                        if data.x[i]> qmin and data.x[i]< qmax:
498                            tempx = data.x[i]
499                            tempy = model.run(tempx)
500                           
501                            theory.x.append(tempx) 
502                            theory.y.append(tempy)
503                    except:
504                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
505                        skipping point x %g %s" %(data.x[i], sys.exc_value)))   
506                try:
507                    tempx = qmax
508                    tempy = model.run(qmax)
509                    theory.x.append(tempx)
510                    theory.y.append(tempy)
511                    wx.PostEvent(self.parent, NewPlotEvent(plot=theory, title="Analytical model"))
512                except:
513                    wx.PostEvent(self.parent, StatusEvent(status="fitting \
514                        skipping point x %g %s" %(qmax, sys.exc_value)))
515               
516           
517    def _on_model_menu(self, evt):
518        """
519            Plot a theory from a model selected from the menu
520        """
521        name="Model View"
522        model=evt.modelinfo.model()
523        description=evt.modelinfo.description
524        self.fit_panel.add_model_page(model,description,name)       
525        self.draw_model(model)
526       
527    def draw_model(self,model):
528        """
529             draw model with default data value
530        """
531        x = pylab.arange(0.001, 0.1, 0.001)
532        xlen = len(x)
533        dy = numpy.zeros(xlen)
534        y = numpy.zeros(xlen)
535       
536        for i in range(xlen):
537            y[i] = model.run(x[i])
538            dy[i] = math.sqrt(math.fabs(y[i]))
539        try:
540           
541            new_plot = Theory1D(x, y)
542            new_plot.name = "Model"
543            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
544            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
545            new_plot.group_id ="Fitness"
546            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
547        except:
548            wx.PostEvent(self.parent, StatusEvent(status="fitting \
549                        skipping point x %g %s" %(qmax, sys.exc_value)))
550
551if __name__ == "__main__":
552    i = Plugin()
553   
554   
555   
556   
Note: See TracBrowser for help on using the repository browser.