source: sasview/sansview/perspectives/fitting/fitting.py @ 00353b4

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

modified context menu

  • Property mode set to 100644
File size: 23.5 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 fitpage
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(fitpage.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                    name = item.group_id # item in Data1D
150                except:
151                    name = 'Fit'
152                try:
153                    page = self.fit_panel.add_fit_page(name)
154                    # add data associated to the page created
155                    if item.__class__.__name__=='MetaData1D' or item.__class__.__name__=='Data1D' :
156                        new_item=FitData1D(item)
157                    else:
158                        new_item=FitData2D(item)
159                    if page !=None:   
160                        page.set_data_name(new_item)
161                        #create a fitproblem storing all link to data,model,page creation
162                        self.page_finder[page]= FitProblem()
163                        #data_for_park= Data(sans_data=item)
164                        #datap = PlottableData(data=data_for_park,data1d=item)
165                        #self.page_finder[page].add_data(datap)
166                        self.page_finder[page].add_data(new_item)
167                except:
168                    raise
169                    wx.PostEvent(self.parent, StatusEvent(status="Creating Fit page: %s"\
170                    %sys.exc_value))
171    def schedule_for_fit(self,value=0,fitproblem =None): 
172        """
173       
174        """   
175        if fitproblem !=None:
176            fitproblem.schedule_tofit(value)
177        else:
178            current_pg=self.fit_panel.get_current_page() 
179            for page, val in self.page_finder.iteritems():
180                if page ==current_pg :
181                    val.schedule_tofit(value)
182                    break
183                     
184                   
185    def get_page_finder(self):
186        """ @return self.page_finder used also by simfitpage.py""" 
187        return self.page_finder
188   
189   
190    def set_page_finder(self,modelname,names,values):
191        """
192             Used by simfitpage.py to reset a parameter given the string constrainst.
193             @param modelname: the name ot the model for with the parameter has to reset
194             @param value: can be a string in this case.
195             @param names: the paramter name
196             @note: expecting park used for fit.
197        """ 
198        sim_page=self.fit_panel.get_page(0)
199        for page, value in self.page_finder.iteritems():
200            if page != sim_page:
201                list=value.get_model()
202                model=list[0]
203                print "fitting",model.name,modelname
204                if model.name== modelname:
205                    value.set_model_param(names,values)
206                    break
207
208   
209                           
210    def split_string(self,item): 
211        """
212            receive a word containing dot and split it. used to split parameterset
213            name into model name and parameter name example:
214            paramaterset (item) = M1.A
215            @return model_name =M1 , parameter name =A
216        """
217        if string.find(item,".")!=-1:
218            param_names= re.split("\.",item)
219            model_name=param_names[0]
220            param_name=param_names[1] 
221            return model_name,param_name
222       
223       
224    def _single_fit_completed(self,result,pars,cpage,qmin,qmax):
225        """
226            Display fit result on one page of the notebook.
227            @param result: result of fit
228            @param pars: list of names of parameters fitted
229            @param current_pg: the page where information will be displayed
230            @param qmin: the minimum value of x to replot the model
231            @param qmax: the maximum value of x to replot model
232         
233        """
234        try:
235            for page, value in self.page_finder.iteritems():
236                if page==cpage :
237                    #fitdata = value.get_data()
238                    list = value.get_model()
239                    model= list[0]
240                    break
241            i = 0
242#            print "fitting: single fit pars ", pars
243            for name in pars:
244                if result.pvec.__class__==numpy.float64:
245                    model.setParam(name,result.pvec)
246                else:
247                    model.setParam(name,result.pvec[i])
248#                    print "fitting: single fit", name, result.pvec[i]
249                    i += 1
250#            print "fitting result : chisqr",result.fitness
251#            print "fitting result : pvec",result.pvec
252#            print "fitting result : stderr",result.stderr
253           
254            cpage.onsetValues(result.fitness, result.pvec,result.stderr)
255            self.plot_helper(currpage=cpage,qmin=qmin,qmax=qmax)
256        except:
257            raise
258            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
259           
260       
261    def _simul_fit_completed(self,result,qmin,qmax):
262        """
263            Parameter estimation completed,
264            display the results to the user
265            @param alpha: estimated best alpha
266            @param elapsed: computation time
267        """
268        try:
269            for page, value in self.page_finder.iteritems():
270                if value.get_scheduled()==1:
271                    #fitdata = value.get_data()
272                    list = value.get_model()
273                    model= list[0]
274                   
275                    small_out = []
276                    small_cov = []
277                    i = 0
278                    #Separate result in to data corresponding to each page
279                    for p in result.parameters:
280                        model_name,param_name = self.split_string(p.name) 
281                        if model.name == model_name:
282                            small_out.append(p.value )
283                            small_cov.append(p.stderr)
284                            model.setParam(param_name,p.value) 
285                    # Display result on each page
286                    page.onsetValues(result.fitness, small_out,small_cov)
287                    #Replot model
288                    self.plot_helper(currpage= page,qmin= qmin,qmax= qmax) 
289        except:
290             wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
291           
292   
293    def _on_single_fit(self,id=None,qmin=None,qmax=None):
294        """
295            perform fit for the  current page  and return chisqr,out and cov
296            @param engineName: type of fit to be performed
297            @param id: unique id corresponding to a fit problem(model, set of data)
298            @param model: model to fit
299           
300        """
301        #print "in single fitting"
302        #set an engine to perform fit
303        from sans.fit.Fitting import Fit
304        self.fitter= Fit(self._fit_engine)
305        #Setting an id to store model and data in fit engine
306        if id==None:
307            id=0
308        self.id = id
309        page_fitted=None
310        fit_problem=None
311        #Get information (model , data) related to the page on
312        #with the fit will be perform
313        #current_pg=self.fit_panel.get_current_page()
314        #simul_pg=self.fit_panel.get_page(0)
315           
316        for page, value in self.page_finder.iteritems():
317            if  value.get_scheduled() ==1 :
318                fitdata = value.get_data()
319                list=value.get_model()
320                model=list[0]
321                #Create list of parameters for fitting used
322                pars=[]
323                templist=[]
324                try:
325                    #templist=current_pg.get_param_list()
326                    templist=page.get_param_list()
327                    for element in templist:
328                        pars.append(str(element[0].GetLabelText()))
329                    pars.sort()
330                    #Do the single fit
331                    self.fitter.set_model(Model(model), self.id, pars) 
332                    self.fitter.set_data(fitdata,self.id,qmin,qmax)
333                    self.fitter.select_problem_for_fit(Uid=self.id,value=value.get_scheduled())
334                    page_fitted=page
335                    self.id+=1
336                    self.schedule_for_fit( 0,value) 
337                except:
338                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
339                    return
340                # make sure to keep an alphabetic order
341                #of parameter names in the list     
342        try:
343            result=self.fitter.fit()
344            #self._single_fit_completed(result,pars,current_pg,qmin,qmax)
345            print "single_fit: result",result.fitness,result.pvec,result.stderr
346            #self._single_fit_completed(result,pars,page,qmin,qmax)
347            self._single_fit_completed(result,pars,page_fitted,qmin,qmax)
348        except:
349            raise
350            wx.PostEvent(self.parent, StatusEvent(status="Single Fit error: %s" % sys.exc_value))
351            return
352         
353    def _on_simul_fit(self, id=None,qmin=None,qmax=None):
354        """
355            perform fit for all the pages selected on simpage and return chisqr,out and cov
356            @param engineName: type of fit to be performed
357            @param id: unique id corresponding to a fit problem(model, set of data)
358             in park_integration
359            @param model: model to fit
360           
361        """
362        #set an engine to perform fit
363        from sans.fit.Fitting import Fit
364        self.fitter= Fit(self._fit_engine)
365       
366        #Setting an id to store model and data
367        if id==None:
368             id = 0
369        self.id = id
370       
371        for page, value in self.page_finder.iteritems():
372            try:
373                if value.get_scheduled()==1:
374                    fitdata = value.get_data()
375                    list = value.get_model()
376                    model= list[0]
377                    #Create dictionary of parameters for fitting used
378                    pars = []
379                    templist = []
380                    templist = page.get_param_list()
381                    for element in templist:
382                        try:
383                            name = str(element[0].GetLabelText())
384                            pars.append(name)
385                        except:
386                            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
387                            return
388                    new_model=Model(model)
389                    param=value.get_model_param()
390                   
391                    if len(param)>0:
392                        for item in param:
393                            param_value = item[1]
394                            param_name = item[0]
395                            #print "fitting ", param,param_name, param_value
396                           
397                            #new_model.set( model.getParam(param_name[0])= param_value)
398                            #new_model.set( exec"%s=%s"%(param_name[0], param_value))
399                            #new_model.set( exec "%s"%(param_nam) = param_value)
400                            new_model.parameterset[ param_name].set( param_value )
401                           
402                    self.fitter.set_model(new_model, self.id, pars) 
403                    self.fitter.set_data(fitdata,self.id,qmin,qmax)
404                    self.fitter.select_problem_for_fit(Uid=self.id,value=value.get_scheduled())
405                    self.id += 1 
406            except:
407                wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
408                return 
409        #Do the simultaneous fit
410        try:
411            result=self.fitter.fit()
412            self._simul_fit_completed(result,qmin,qmax)
413        except:
414            wx.PostEvent(self.parent, StatusEvent(status="Simultaneous Fitting error: %s" % sys.exc_value))
415            return
416       
417       
418    def _onset_engine(self,event):
419        """ set engine to scipy"""
420        if self._fit_engine== 'park':
421            self._on_change_engine('scipy')
422        else:
423            self._on_change_engine('park')
424        wx.PostEvent(self.parent, StatusEvent(status="Engine set to: %s" % self._fit_engine))
425 
426   
427    def _on_change_engine(self, engine='park'):
428        """
429            Allow to select the type of engine to perform fit
430            @param engine: the key work of the engine
431        """
432        self._fit_engine = engine
433   
434   
435    def _on_model_panel(self, evt):
436        """
437            react to model selection on any combo box or model menu.plot the model 
438        """
439        model = evt.model
440        name = evt.name
441        sim_page=self.fit_panel.get_page(0)
442        current_pg = self.fit_panel.get_current_page() 
443        if current_pg != sim_page:
444            current_pg.set_model_name(name)
445            current_pg.set_panel(model)
446            try:
447                fitdata=self.page_finder[current_pg].get_data()
448                M_name="M"+str(self.index_model)+"= "+name+"("+fitdata.data.group_id+")"
449            except:
450                raise 
451                M_name="M"+str(self.index_model)+"= "+name
452            model.name="M"+str(self.index_model)
453            self.index_model += 1 
454           
455            self.page_finder[current_pg].set_model(model,M_name)
456            self.plot_helper(currpage= current_pg,qmin= None,qmax= None)
457            sim_page.add_model(self.page_finder)
458       
459           
460    def redraw_model(self,qmin= None,qmax= None):
461        """
462            Draw a theory according to model changes or data range.
463            @param qmin: the minimum value plotted for theory
464            @param qmax: the maximum value plotted for theory
465        """
466        current_pg=self.fit_panel.get_current_page()
467        for page, value in self.page_finder.iteritems():
468            if page ==current_pg :
469                break 
470        self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
471       
472    def plot_helper(self,currpage,qmin=None,qmax=None):
473        """
474            Plot a theory given a model and data
475            @param model: the model from where the theory is derived
476            @param currpage: page in a dictionary referring to some data
477        """
478        if self.fit_panel.get_page_count() >1:
479            for page in self.page_finder.iterkeys():
480                if  page==currpage : 
481                    break 
482            fitdata=self.page_finder[page].get_data()
483            list=self.page_finder[page].get_model()
484            model=list[0]
485            data=fitdata.data
486           
487            if data!=None and data.__class__.__name__ != 'MetaData2D':
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                    except:
517                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
518                        skipping point x %g %s" %(data.x[i], sys.exc_value)))   
519                try:
520                    tempx = qmax
521                    tempy = model.run(qmax)
522                    theory.x.append(tempx)
523                    theory.y.append(tempy)
524                   
525                except:
526                    wx.PostEvent(self.parent, StatusEvent(status="fitting \
527                        skipping point x %g %s" %(qmax, sys.exc_value)))
528            else:
529                theory=Data2D(data.image, data.err_image)
530                theory.x_bins= data.x_bins
531                theory.y_bins= data.y_bins
532                tempy=[]
533                for i in range(len(data.x_bins)):
534                    theory.image= model.runXY([data.x_bins[i],data.y_bins[i]])
535                    #print "fitting : plot_helper:", theory.image
536                #print data.image
537                #theory.image=model.runXY(data.image)
538                theory.image=model.run(data.image)
539                print "fitting : plot_helper:",theory.image
540                theory.zmin= data.zmin
541                theory.zmax= data.zmax
542                theory.xmin= data.xmin
543                theory.xmax= data.xmax
544                theory.ymin= data.ymin
545                theory.ymax= data.ymax
546               
547        wx.PostEvent(self.parent, NewPlotEvent(plot=theory, title="Analytical model"))
548       
549       
550    def _on_model_menu(self, evt):
551        """
552            Plot a theory from a model selected from the menu
553        """
554        name="Model View"
555        model=evt.modelinfo.model()
556        description=evt.modelinfo.description
557        self.fit_panel.add_model_page(model,description,name)       
558        self.draw_model(model)
559       
560    def draw_model(self,model):
561        """
562             draw model with default data value
563        """
564        x = pylab.arange(0.001, 0.1, 0.001)
565        xlen = len(x)
566        dy = numpy.zeros(xlen)
567        y = numpy.zeros(xlen)
568       
569        for i in range(xlen):
570            y[i] = model.run(x[i])
571            dy[i] = math.sqrt(math.fabs(y[i]))
572        try:
573           
574            new_plot = Theory1D(x, y)
575            new_plot.name = "Model"
576            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
577            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
578            new_plot.group_id ="Fitness"
579            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
580        except:
581            wx.PostEvent(self.parent, StatusEvent(status="fitting \
582                        skipping point x %g %s" %(qmax, sys.exc_value)))
583
584if __name__ == "__main__":
585    i = Plugin()
586   
587   
588   
589   
Note: See TracBrowser for help on using the repository browser.