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

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

model 2D changed

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