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

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

need to fix data2 d plot

  • Property mode set to 100644
File size: 22.9 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
7
8from sans.guiframe.data_loader import MetaData1D, MetaTheory1D, MetaData2D
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 fitpage1D
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(fitpage1D.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 "MetaData2D":
87                return [["Fit Data2D", "Dialog with fitting parameters ", self._onSelect]] 
88            else:
89                if item.name==graph.selected_plottable and (item.__class__.__name__ is  "MetaData1D"or \
90                                        item.__class__.__name__ is  "Data1D" ):
91                    return [["Fit Data1D", "Dialog with fitting parameters ", self._onSelect]] 
92        return []   
93
94
95    def get_panels(self, parent):
96        """
97            Create and return a list of panel objects
98        """
99        self.parent = parent
100        # Creation of the fit panel
101        self.fit_panel = FitPanel(self.parent, -1)
102        #Set the manager forthe main panel
103        self.fit_panel.set_manager(self)
104        # List of windows used for the perspective
105        self.perspective = []
106        self.perspective.append(self.fit_panel.window_name)
107        # take care of saving  data, model and page associated with each other
108        self.page_finder = {}
109        #index number to create random model name
110        self.index_model = 0
111        #create the fitting panel
112        return [self.fit_panel]
113   
114     
115    def get_perspective(self):
116        """
117            Get the list of panel names for this perspective
118        """
119        return self.perspective
120   
121   
122    def on_perspective(self, event):
123        """
124            Call back function for the perspective menu item.
125            We notify the parent window that the perspective
126            has changed.
127        """
128        self.parent.set_perspective(self.perspective)
129   
130   
131    def post_init(self):
132        """
133            Post initialization call back to close the loose ends
134            [Somehow openGL needs this call]
135        """
136        self.parent.set_perspective(self.perspective)
137       
138       
139    def _onSelect(self,event):
140        """
141            when Select data to fit a new page is created .Its reference is
142            added to self.page_finder
143        """
144        self.panel = event.GetEventObject()
145        for item in self.panel.graph.plottables:
146            if item.name == self.panel.graph.selected_plottable or item.__class__.__name__ is "MetaData2D":
147                #find a name for the page created for notebook
148                try:
149                    page = self.fit_panel.add_fit_page(item)
150                    # add data associated to the page created
151                   
152                    if page !=None:   
153                       
154                        #create a fitproblem storing all link to data,model,page creation
155                        self.page_finder[page]= FitProblem()
156                        self.page_finder[page].add_data(item)
157                except:
158                    wx.PostEvent(self.parent, StatusEvent(status="Creating Fit page: %s"\
159                    %sys.exc_value))
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                    #fitdata = 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                    #fitdata = 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                fitdata = 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(fitdata,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            raise
339            wx.PostEvent(self.parent, StatusEvent(status="Single Fit error: %s" % sys.exc_value))
340            return
341         
342    def _on_simul_fit(self, id=None,qmin=None,qmax=None):
343        """
344            perform fit for all the pages selected on simpage and return chisqr,out and cov
345            @param engineName: type of fit to be performed
346            @param id: unique id corresponding to a fit problem(model, set of data)
347             in park_integration
348            @param model: model to fit
349           
350        """
351        #set an engine to perform fit
352        from sans.fit.Fitting import Fit
353        self.fitter= Fit(self._fit_engine)
354       
355        #Setting an id to store model and data
356        if id==None:
357             id = 0
358        self.id = id
359       
360        for page, value in self.page_finder.iteritems():
361            try:
362                if value.get_scheduled()==1:
363                    fitdata = value.get_data()
364                    list = value.get_model()
365                    model= list[0]
366                    #Create dictionary of parameters for fitting used
367                    pars = []
368                    templist = []
369                    templist = page.get_param_list()
370                    for element in templist:
371                        try:
372                            name = str(element[0].GetLabelText())
373                            pars.append(name)
374                        except:
375                            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
376                            return
377                    new_model=Model(model)
378                    param=value.get_model_param()
379                   
380                    if len(param)>0:
381                        for item in param:
382                            param_value = item[1]
383                            param_name = item[0]
384                            #print "fitting ", param,param_name, param_value
385                           
386                            #new_model.set( model.getParam(param_name[0])= param_value)
387                            #new_model.set( exec"%s=%s"%(param_name[0], param_value))
388                            #new_model.set( exec "%s"%(param_nam) = param_value)
389                            new_model.parameterset[ param_name].set( param_value )
390                           
391                    self.fitter.set_model(new_model, self.id, pars) 
392                    self.fitter.set_data(fitdata,self.id,qmin,qmax)
393                    self.fitter.select_problem_for_fit(Uid=self.id,value=value.get_scheduled())
394                    self.id += 1 
395            except:
396                wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
397                return 
398        #Do the simultaneous fit
399        try:
400            result=self.fitter.fit()
401            self._simul_fit_completed(result,qmin,qmax)
402        except:
403            wx.PostEvent(self.parent, StatusEvent(status="Simultaneous Fitting error: %s" % sys.exc_value))
404            return
405       
406       
407    def _onset_engine(self,event):
408        """ set engine to scipy"""
409        if self._fit_engine== 'park':
410            self._on_change_engine('scipy')
411        else:
412            self._on_change_engine('park')
413        wx.PostEvent(self.parent, StatusEvent(status="Engine set to: %s" % self._fit_engine))
414 
415   
416    def _on_change_engine(self, engine='park'):
417        """
418            Allow to select the type of engine to perform fit
419            @param engine: the key work of the engine
420        """
421        self._fit_engine = engine
422   
423   
424    def _on_model_panel(self, evt):
425        """
426            react to model selection on any combo box or model menu.plot the model 
427        """
428       
429        model = evt.model
430        name = evt.name
431        sim_page=self.fit_panel.get_page(0)
432        current_pg = self.fit_panel.get_current_page() 
433        if current_pg != sim_page:
434            current_pg.set_model_name(name)
435            current_pg.set_panel(model)
436           
437            try:
438                metadata=self.page_finder[current_pg].get_data()
439                M_name="M"+str(self.index_model)+"= "+name+"("+metadata.group_id+")"
440            except:
441                M_name="M"+str(self.index_model)+"= "+name
442            model.name="M"+str(self.index_model)
443            self.index_model += 1 
444           
445            self.page_finder[current_pg].set_model(model,M_name)
446            self.plot_helper(currpage= current_pg,qmin= None,qmax= None)
447            sim_page.add_model(self.page_finder)
448       
449           
450    def redraw_model(self,qmin= None,qmax= None):
451        """
452            Draw a theory according to model changes or data range.
453            @param qmin: the minimum value plotted for theory
454            @param qmax: the maximum value plotted for theory
455        """
456        current_pg=self.fit_panel.get_current_page()
457        for page, value in self.page_finder.iteritems():
458            if page ==current_pg :
459                break 
460        self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
461       
462    def plot_helper(self,currpage,qmin=None,qmax=None):
463        """
464            Plot a theory given a model and data
465            @param model: the model from where the theory is derived
466            @param currpage: page in a dictionary referring to some data
467        """
468        if self.fit_panel.get_page_count() >1:
469            for page in self.page_finder.iterkeys():
470                if  page==currpage : 
471                    data=self.page_finder[page].get_data()
472                    list=self.page_finder[page].get_model()
473                    model=list[0]
474                    break 
475           
476            if data!=None and data.__class__.__name__ != 'MetaData2D':
477                theory = Theory1D(x=[], y=[])
478                theory.name = "Model"
479                theory.group_id = data.group_id
480             
481                x_name, x_units = data.get_xaxis() 
482                y_name, y_units = data.get_yaxis() 
483                theory.xaxis(x_name, x_units)
484                theory.yaxis(y_name, y_units)
485                if qmin == None :
486                   qmin = min(data.x)
487                if qmax == None :
488                    qmax = max(data.x)
489                try:
490                    tempx = qmin
491                    tempy = model.run(qmin)
492                    theory.x.append(tempx)
493                    theory.y.append(tempy)
494                except :
495                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
496                        skipping point x %g %s" %(qmin, sys.exc_value)))
497                           
498                for i in range(len(data.x)):
499                    try:
500                        if data.x[i]> qmin and data.x[i]< qmax:
501                            tempx = data.x[i]
502                            tempy = model.run(tempx)
503                            theory.x.append(tempx) 
504                            theory.y.append(tempy)
505                    except:
506                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
507                        skipping point x %g %s" %(data.x[i], sys.exc_value)))   
508                try:
509                    tempx = qmax
510                    tempy = model.run(qmax)
511                    theory.x.append(tempx)
512                    theory.y.append(tempy)
513                   
514                except:
515                    wx.PostEvent(self.parent, StatusEvent(status="fitting \
516                        skipping point x %g %s" %(qmax, sys.exc_value)))
517            else:
518                theory=Data2D(data.image, data.err_image)
519                theory.x_bins= data.x_bins
520                theory.y_bins= data.y_bins
521                tempy=[]
522                for i in range(len(data.x_bins)):
523                    theory.image= model.runXY([data.x_bins[i],data.y_bins[i]])
524                    #print "fitting : plot_helper:", theory.image
525                #print data.image
526                #theory.image=model.runXY(data.image)
527                theory.image=model.run(data.image)
528                print "fitting : plot_helper:",theory.image
529                theory.zmin= data.zmin
530                theory.zmax= data.zmax
531                theory.xmin= data.xmin
532                theory.xmax= data.xmax
533                theory.ymin= data.ymin
534                theory.ymax= data.ymax
535               
536        wx.PostEvent(self.parent, NewPlotEvent(plot=theory, title="Analytical model"))
537       
538       
539    def _on_model_menu(self, evt):
540        """
541            Plot a theory from a model selected from the menu
542        """
543        name="Model View"
544        model=evt.modelinfo.model()
545        description=evt.modelinfo.description
546        self.fit_panel.add_model_page(model,description,name)       
547        self.draw_model(model)
548       
549    def draw_model(self,model):
550        """
551             draw model with default data value
552        """
553        x = pylab.arange(0.001, 0.1, 0.001)
554        xlen = len(x)
555        dy = numpy.zeros(xlen)
556        y = numpy.zeros(xlen)
557       
558        for i in range(xlen):
559            y[i] = model.run(x[i])
560            dy[i] = math.sqrt(math.fabs(y[i]))
561        try:
562           
563            new_plot = Theory1D(x, y)
564            new_plot.name = "Model"
565            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
566            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
567            new_plot.group_id ="Fitness"
568            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
569        except:
570            wx.PostEvent(self.parent, StatusEvent(status="fitting \
571                        skipping point x %g %s" %(qmax, sys.exc_value)))
572
573if __name__ == "__main__":
574    i = Plugin()
575   
576   
577   
578   
Note: See TracBrowser for help on using the repository browser.