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

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

working on data2D panel

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