source: sasview/sansview/perspectives/fitting/fitting.py @ 95986b5

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

redraw model panel

  • 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                           
512                    except:
513                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
514                        skipping point x %g %s" %(data.x[i], sys.exc_value)))   
515                try:
516                    tempx = qmax
517                    tempy = model.run(qmax)
518                    theory.x.append(tempx)
519                    theory.y.append(tempy)
520                except:
521                    wx.PostEvent(self.parent, StatusEvent(status="fitting \
522                        skipping point x %g %s" %(qmax, sys.exc_value)))
523               
524            else:
525                theory=Data2D(data.image, data.err_image)
526                #theory=Theory2D(data.image, data.err_image)
527                theory.x_bins= data.x_bins
528                theory.y_bins= data.y_bins
529                tempy=[]
530                if qmin==None:
531                    qmin=data.xmin
532                if qmax==None:
533                    qmax=data.xmax
534                if ymin==None:
535                    ymin=data.ymin
536                if ymax==None:
537                    ymax=data.ymax
538                   
539                theory.image = numpy.zeros((len(data.y_bins),len(data.x_bins)))
540                for i in range(len(data.y_bins)):
541                    if data.y_bins[i]>= ymin and data.y_bins[i]<= ymax:
542                        for j in range(len(data.x_bins)):
543                            if data.x_bins[i]>= qmin and data.x_bins[i]<= qmax:
544                                theory.image[j][i]=model.runXY([data.x_bins[j],data.y_bins[i]])
545               
546                #print "fitting : plot_helper:", theory.image
547                #print data.image
548                #print "fitting : plot_helper:",theory.image
549                theory.zmin= data.zmin
550                theory.zmax= data.zmax
551                theory.xmin= qmin
552                theory.xmax= qmax
553                theory.ymin= ymin
554                theory.ymax= ymax
555       
556        wx.PostEvent(self.parent, NewPlotEvent(plot=theory, title="Analytical model"))
557       
558       
559    def _on_model_menu(self, evt):
560        """
561            Plot a theory from a model selected from the menu
562        """
563        name="Model View"
564        model=evt.model()
565       
566        description=model.description
567        self.fit_panel.add_model_page(model,description,name)       
568        self.draw_model(model)
569       
570    def draw_model(self,model):
571        """
572             draw model with default data value
573        """
574        x = pylab.arange(0.001, 0.1, 0.001)
575        xlen = len(x)
576        dy = numpy.zeros(xlen)
577        y = numpy.zeros(xlen)
578       
579        for i in range(xlen):
580            y[i] = model.run(x[i])
581            dy[i] = math.sqrt(math.fabs(y[i]))
582        try:
583            new_plot = Theory1D(x, y)
584            new_plot.name = "Model"
585            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
586            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
587            new_plot.group_id ="Fitness"
588            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
589        except:
590            raise
591if __name__ == "__main__":
592    i = Plugin()
593   
594   
595   
596   
Note: See TracBrowser for help on using the repository browser.