source: sasview/sansview/perspectives/fitting/fitting.py @ 6f73a08

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 6f73a08 was 6f73a08, checked in by Gervaise Alina <gervyh@…>, 16 years ago

working on fitting data 2 D

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