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

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 d89f09b was d89f09b, checked in by Gervaise Alina <gervyh@…>, 16 years ago
  • Property mode set to 100644
File size: 21.8 KB
Line 
1import os,os.path, re
2import sys, wx, logging
3import string, numpy, pylab, math
4
5from sans.guitools.plottables import Data1D, Theory1D
6from sans.guitools.PlotPanel import PlotPanel
7from sans.guicomm.events import NewPlotEvent, StatusEvent 
8from copy import deepcopy
9from sans.fit.AbstractFitEngine import Model
10from sans.fit.AbstractFitEngine import Data
11from fitproblem import FitProblem
12from fitpanel import FitPanel
13
14import models
15import fitpage
16class PlottableData(Data,Data1D):
17    """ class plottable data"""
18    def __init__(self,data,data1d):
19        self.x = data1d.x
20        self.y = data1d.y
21        self.dx= data1d.dx
22        self.dy= data1d.dy
23       
24        self.group_id= data1d.group_id
25        x_name, x_units = data1d.get_xaxis() 
26        y_name, y_units = data1d.get_yaxis() 
27        self.xaxis( x_name, x_units)
28        self.yaxis( y_name, y_units )
29        self.qmin=data.qmin
30        self.qmax=data.qmax
31class Plugin:
32    """
33    """
34   
35    def __init__(self):
36        ## Plug-in name
37        self.sub_menu = "Fitting"
38       
39        ## Reference to the parent window
40        self.parent = None
41        self.menu_mng = models.ModelManager()
42        ## List of panels for the simulation perspective (names)
43        self.perspective = []
44        # Start with a good default
45        self.elapsed = 0.022
46        self.fitter  = None
47       
48        #Flag to let the plug-in know that it is running standalone
49        self.standalone=True
50        ## Fit engine
51        self._fit_engine = 'park'
52        # Log startup
53        logging.info("Fitting plug-in started")   
54
55    def populate_menu(self, id, owner):
56        """
57            Create a menu for the Fitting plug-in
58            @param id: id to create a menu
59            @param owner: owner of menu
60            @ return : list of information to populate the main menu
61        """
62        #Menu for fitting
63        self.menu1 = wx.Menu()
64        id1 = wx.NewId()
65        self.menu1.Append(id1, '&Show fit panel')
66        wx.EVT_MENU(owner, id1, self.on_perspective)
67       
68        #menu for model
69        menu2 = wx.Menu()
70        self.menu_mng.populate_menu(menu2, owner)
71        id2 = wx.NewId()
72        owner.Bind(models.EVT_MODEL,self._on_model_menu)
73        self.fit_panel.set_owner(owner)
74        self.fit_panel.set_model_list(self.menu_mng.get_model_list())
75        owner.Bind(fitpage.EVT_MODEL_BOX,self._on_model_panel)
76     
77        return [(id, self.menu1, "Fitting"),(id2, menu2, "Model")]
78   
79   
80    def help(self, evt):
81        """
82            Show a general help dialog.
83            TODO: replace the text with a nice image
84        """
85        pass
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       
94        self.graph=graph
95        for item in graph.plottables:
96            if item.name==graph.selected_plottable and item.__class__.__name__ is not "Theory1D":
97                return [["Select Data", "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        self.index_model=0
116        return [self.fit_panel]
117   
118     
119    def get_perspective(self):
120        """
121            Get the list of panel names for this perspective
122        """
123        return self.perspective
124   
125   
126    def on_perspective(self, event):
127        """
128            Call back function for the perspective menu item.
129            We notify the parent window that the perspective
130            has changed.
131        """
132        self.parent.set_perspective(self.perspective)
133   
134   
135    def post_init(self):
136        """
137            Post initialization call back to close the loose ends
138            [Somehow openGL needs this call]
139        """
140        self.parent.set_perspective(self.perspective)
141       
142       
143    def _onSelect(self,event):
144        """
145            when Select data to fit a new page is created .Its reference is
146            added to self.page_finder
147        """
148        self.panel = event.GetEventObject()
149        for item in self.panel.graph.plottables:
150            if item.name == self.panel.graph.selected_plottable:
151                try:
152                    name = item.group_id # item in Data1D
153                except:
154                    name = 'Fit'
155                try:
156                    page = self.fit_panel.add_page(name)
157                    page.set_data_name(item)
158                    self.page_finder[page]= FitProblem()
159                    #creating Data type
160                    data1= Data(sans_data=item)
161                    datas=PlottableData(data=data1,data1d=item)
162                    self.page_finder[page].add_data(datas)
163                except:
164                    raise 
165                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: \
166                    data already Selected "))
167                   
168                   
169    def get_page_finder(self):
170        """ @return self.page_finder used also by simfitpage.py""" 
171        return self.page_finder
172   
173   
174    def set_page_finder(self,modelname,param,values):
175        """
176             Used by simfitpage.py to reset a parameter given the string constrainst.
177             @param modelname: the name ot the model for with the parameter has to reset
178             @param value: can be a string in this case.
179             @note: expecting park used for fit.
180        """ 
181        sim_page=self.fit_panel.get_page(0)
182        for page, value in self.page_finder.iteritems():
183            if page != sim_page:
184                list=value.get_model()
185                model=list[0]
186                if model.name== modelname:
187                    value.set_model_param(param,values)
188                    break
189
190   
191                           
192    def split_string(self,item): 
193        """
194            recieve a word containing ""
195        """
196        #print "fitting: split :went here"
197       
198        if string.find(item,".")!=-1:
199            param_names= re.split("\.",item)
200            model_name=param_names[0]
201            param_name=param_names[1] 
202            return model_name,param_name
203       
204       
205    def _single_fit_completed(self,result,pars,current_pg,qmin,qmax):
206        """
207         
208        """
209       
210        try:
211            for page, value in self.page_finder.iteritems():
212                if page== current_pg:
213                    data = value.get_data()
214                    list = value.get_model()
215                    model= list[0]
216                    break
217            #print "fitting : result",result,result.pvec,result.cov,result.fitness
218            i = 0
219            for name in pars:
220                if result.pvec.__class__==numpy.float64:
221                    model.model.setParam(name,result.pvec)
222                else:
223                    model.model.setParam(name,result.pvec[i])
224                    #print "fitting: i name out[i]", i,name,float(result.pvec[i])
225                    i += 1
226            new_cov=[]
227            if result.cov !=None:
228                 for j in range(len(result.cov)):
229                     new_cov.append(result.cov[j][j]) 
230            else:
231                new_cov=None
232            current_pg.onsetValues(result.fitness, result.pvec,new_cov)
233            self.plot_helper(currpage=current_pg,qmin=qmin,qmax=qmax)
234        except:
235             wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
236           
237       
238    def _simul_fit_completed(self,result,qmin,qmax):
239        """
240            Parameter estimation completed,
241            display the results to the user
242            @param alpha: estimated best alpha
243            @param elapsed: computation time
244        """
245        try:
246            for page, value in self.page_finder.iteritems():
247                data = value.get_data()
248                list = value.get_model()
249                model= list[0]
250               
251                small_out = []
252                small_cov = []
253                i = 0
254                for p in result.parameters:
255                    print "fitting: fit in park fitting", p.name, p.value,p.stderr
256                    model_name,param_name = self.split_string(p.name) 
257                    print "fitting: simultfit",model.model.name,model_name,param_name ,p.name,param_name,p.value
258                    if model.model.name == model_name:
259                        print "fitting: hello",p.name,param_name,p.value
260                        small_out.append(p.value )
261                        small_cov.append(p.stderr)
262                        model.model.setParam(param_name,p.value)   
263                #print "fitting: out of each page",page,small_out,small_cov,data.group_id
264                page.onsetValues(result.fitness, small_out,small_cov)
265                self.plot_helper(currpage= page,qmin= qmin,qmax= qmax) 
266        except:
267             wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
268           
269     
270    def _completed(self,result,pars,current_pg, elapsed):
271        """
272            Method called with the results when the inversion
273            is done
274           
275            @param out: output coefficient for the base functions
276            @param cov: covariance matrix
277            @param pr: Invertor instance
278            @param elapsed: time spent computing
279        """
280       
281        # Save useful info
282        self.elapsed = elapsed
283        # Keep a copy of the last result
284        self._last_out = result.pvec
285        self._last_cov = result.cov
286        self._last_chisqr=result.fitness
287        #print "fitting: initial parameter ",pars
288        #result=self.fitter.fit(qmin,qmax)
289       
290        #print "fitting : result",result,result.pvec,result.cov,result.fitness
291        i = 0
292        for name in pars:
293            if result.pvec.__class__==numpy.float64:
294                model.model.setParam(name,result.pvec)
295            else:
296                model.model.setParam(name,result.pvec[i])
297                #print "fitting: i name out[i]", i,name,float(result.pvec[i])
298                i += 1
299        new_cov=[]
300        if result.cov !=None:
301             for j in range(len(result.cov)):
302                 new_cov.append(result.cov[j][j]) 
303        else:
304            new_cov=None
305        current_pg.onsetValues(result.fitness, result.pvec,new_cov)
306        self.plot_helper(currpage=current_pg,qmin=qmin,qmax=qmax)
307 
308       
309    def _on_single_fit(self,id=None,qmin=None,qmax=None):
310        """
311            perform fit for the  current page  and return chisqr,out and cov
312            @param engineName: type of fit to be performed
313            @param id: unique id corresponding to a fit problem(model, set of data)
314            @param model: model to fit
315           
316        """
317        #set an engine to perform fit
318        from sans.fit.Fitting import Fit
319        self.fitter= Fit(self._fit_engine)
320        #Setting an id to store model and data
321        if id==None:
322            id=0
323        self.id=id
324        current_pg=self.fit_panel.get_current_page() 
325        for page, value in self.page_finder.iteritems():
326            if page ==current_pg :
327                #print "fitting: self.page_finder",self.page_finder
328                data = value.get_data()
329                list=value.get_model()
330                model=list[0]
331               
332                #Create dictionary of parameters for fitting used
333                pars=[]
334                templist=[]
335                try:
336                    templist=current_pg.get_param_list()
337                except:
338                    raise
339                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
340                    return
341                #for element in templist:
342                #    print "fitting: templist",str(element[0].GetLabelText())
343                #print "fitting: model list",model.getParamList()
344                for element in templist:
345                    try:
346                       pars.append(str(element[0].GetLabelText()))
347                    except:
348                        raise
349                        wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
350                        return
351                #print "fitting: pars",pars
352                pars.sort()
353               
354                self.fitter.set_model(model,model.name, self.id, pars) 
355                self.fitter.set_data(data,self.id,qmin,qmax)
356                #Do the fit SCIPY
357                try:
358                    result=self.fitter.fit()
359                    self._single_fit_completed(result,pars,current_pg,qmin,qmax)
360                   
361                except:
362                    wx.PostEvent(self.parent, StatusEvent(status="Single Fit error: %s" % sys.exc_value))
363                    return
364         
365    def _on_simul_fit(self, id=None,qmin=None,qmax=None):
366        """
367            perform fit for all the pages selected on simpage and return chisqr,out and cov
368            @param engineName: type of fit to be performed
369            @param id: unique id corresponding to a fit problem(model, set of data)
370             in park_integration
371            @param model: model to fit
372           
373        """
374        #print "fitting: probabily breaking on fit call"
375        #set an engine to perform fit
376        from sans.fit.Fitting import Fit
377        self.fitter= Fit(self._fit_engine)
378        #Setting an id to store model and data
379        if id==None:
380             id = 0
381        self.id = id
382        for page, value in self.page_finder.iteritems():
383            try:
384                #print "fitting: self.page_finder",value
385                data = value.get_data()
386                #print "fitting: data",data
387                list = value.get_model()
388                model= list[0]
389                if data != None :
390                    #Create dictionary of parameters for fitting used
391                    pars = []
392                    templist = []
393                    try:
394                        templist = page.get_param_list()
395                    except:
396                        wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
397                        return
398                   
399                    for element in templist:
400                        try:
401                            name = str(element[0].GetLabelText())
402                            pars.append(name)
403                        except:
404                            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
405                            return
406               
407                    print "fitting: pars",pars,model.name
408                    #print "fitter",self.fitter
409                    #print "fitting: model name",model.name
410                    self.fitter.set_model(model,model.model.name, self.id, pars) 
411                    self.fitter.set_data(data,self.id,qmin,qmax)
412                else:
413                    raise ValueError," Fitting: cannot set model with empty parameter"
414                self.id += 1 
415            except:
416                    raise
417                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
418                    return 
419        #Do the fit SCIPY
420        try:
421            result=self.fitter.fit()
422            self._simul_fit_completed(result,qmin,qmax)
423        except:
424            raise
425            wx.PostEvent(self.parent, StatusEvent(status="Simultaneous Fitting error: %s" % sys.exc_value))
426            return
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        model = evt.model
441        name = evt.name
442        sim_page=self.fit_panel.get_page(0)
443        current_pg = self.fit_panel.get_current_page() 
444        if current_pg != sim_page:
445            current_pg.set_model_name(name)
446            current_pg.set_panel(model)
447            try:
448                data=self.page_finder[current_pg].get_data()
449                M_name="M"+str(self.index_model)+"= "+name+"("+data.group_id+")"
450            except:
451                raise 
452                M_name="M"+str(self.index_model)+"= "+name
453            model.name="M"+str(self.index_model)
454            self.index_model += 1 
455            self.page_finder[current_pg].set_theory("Fitness")
456            #print "on model",model.name
457            self.page_finder[current_pg].set_model(Model(model),M_name)
458            self.plot_helper(currpage= current_pg,qmin= None,qmax= None)
459            sim_page.add_model(self.page_finder)
460       
461           
462    def redraw_model(self,qmin= None,qmax= None):
463        """
464            Draw a theory according to model changes or data range.
465            @param qmin: the minimum value plotted for theory
466            @param qmax: the maximum value plotted for theory
467        """
468        current_pg=self.fit_panel.get_current_page()
469        for page, value in self.page_finder.iteritems():
470            if page ==current_pg :
471                break 
472        self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
473       
474    def plot_helper(self,currpage,qmin=None,qmax=None):
475        """
476            Plot a theory given a model and data
477            @param model: the model from where the theory is derived
478            @param currpage: page in a dictionary referring to some data
479        """
480        #print "fitting: plot helper"
481        if self.fit_panel.get_page_count() >1:
482            for page in self.page_finder.iterkeys():
483                if  page==currpage : 
484                    break 
485           
486            data=self.page_finder[page].get_data()
487            list=self.page_finder[page].get_model()
488            model=list[0]
489            if data!=None:
490                theory = Theory1D(x=[], y=[])
491                theory.name = self.page_finder[page].get_theory()
492                theory.group_id = data.group_id
493             
494                x_name, x_units = data.get_xaxis() 
495                y_name, y_units = data.get_yaxis() 
496                theory.xaxis(x_name, x_units)
497                theory.yaxis(y_name, y_units)
498             
499                if qmin == None :
500                   qmin = min(data.x)
501                if qmax == None :
502                    qmax = max(data.x)
503                try:
504                    tempx = qmin
505                    tempy = model.eval(qmin)
506                    theory.x.append(tempx)
507                    theory.y.append(tempy)
508                except :
509                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
510                        skipping point x %g %s" %(qmin, sys.exc_value)))
511                           
512                for i in range(len(data.x)):
513                    try:
514                        if data.x[i]> qmin and data.x[i]< qmax:
515                            tempx = data.x[i]
516                            tempy = model.eval(tempx)
517                           
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" %(data.x[i], sys.exc_value)))   
523                try:
524                    tempx = qmax
525                    tempy = model.eval(qmax)
526                    theory.x.append(tempx)
527                    theory.y.append(tempy)
528                except:
529                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
530                        skipping point x %g %s" %(qmax, sys.exc_value)))
531                try:
532                    from sans.guicomm.events import NewPlotEvent
533                    #print"fitting: theory",theory
534                    wx.PostEvent(self.parent, NewPlotEvent(plot=theory, title="Analytical model"))
535                except:
536                    raise
537                    print "SimView.complete1D: could not import sans.guicomm.events"
538           
539           
540    def _on_model_menu(self, evt):
541        """
542            Plot a theory from a model selected from the menu
543        """
544        x = pylab.arange(0.001, 0.1, 0.001)
545        xlen = len(x)
546        dy = numpy.zeros(xlen)
547        y = numpy.zeros(xlen)
548       
549        for i in range(xlen):
550            y[i] = evt.model.run(x[i])
551            dy[i] = math.sqrt(math.fabs(y[i]))
552        try:
553           
554            new_plot = Theory1D(x, y)
555            #new_plot.name = evt.model.__class__.__name__
556            new_plot.name ="Fitness"
557            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
558            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
559         
560            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
561        except:
562            print "SimView.complete1D: could not import sans.guicomm.events"
563
564
565if __name__ == "__main__":
566    i = Plugin()
567   
568   
569   
570   
Note: See TracBrowser for help on using the repository browser.