source: sasview/sansview/perspectives/fitting/fitting.py @ d611fb93

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

panel 2d changed for dispersion display

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