source: sasview/sansview/perspectives/fitting/fitting.py @ 415bc97

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

need to fix help html

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