source: sasview/sansview/perspectives/fitting/fitting.py @ 4fc6dbf

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

some mofif added

  • Property mode set to 100644
File size: 20.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        #owner.Bind(modelpage.EVT_MODEL_DRAW,self.draw_model)
77     
78        return [(id, self.menu1, "Fitting"),(id2, menu2, "Model")]
79   
80   
81    def help(self, evt):
82        """
83            Show a general help dialog.
84            TODO: replace the text with a nice image
85        """
86        pass
87   
88    def get_context_menu(self, graph=None):
89        """
90            Get the context menu items available for P(r)
91            @param graph: the Graph object to which we attach the context menu
92            @return: a list of menu items with call-back function
93        """
94       
95        self.graph=graph
96        for item in graph.plottables:
97            if item.name==graph.selected_plottable and item.__class__.__name__ is not "Theory1D":
98                return [["Select Data", "Dialog with fitting parameters ", self._onSelect]] 
99        return []   
100
101
102    def get_panels(self, parent):
103        """
104            Create and return a list of panel objects
105        """
106        self.parent = parent
107        # Creation of the fit panel
108        self.fit_panel = FitPanel(self.parent, -1)
109        #Set the manager forthe main panel
110        self.fit_panel.set_manager(self)
111        # List of windows used for the perspective
112        self.perspective = []
113        self.perspective.append(self.fit_panel.window_name)
114        # take care of saving  data, model and page associated with each other
115        self.page_finder={}
116        self.index_model=0
117        return [self.fit_panel]
118   
119     
120    def get_perspective(self):
121        """
122            Get the list of panel names for this perspective
123        """
124        return self.perspective
125   
126   
127    def on_perspective(self, event):
128        """
129            Call back function for the perspective menu item.
130            We notify the parent window that the perspective
131            has changed.
132        """
133        self.parent.set_perspective(self.perspective)
134   
135   
136    def post_init(self):
137        """
138            Post initialization call back to close the loose ends
139            [Somehow openGL needs this call]
140        """
141        self.parent.set_perspective(self.perspective)
142       
143       
144    def _onSelect(self,event):
145        """
146            when Select data to fit a new page is created .Its reference is
147            added to self.page_finder
148        """
149        self.panel = event.GetEventObject()
150        for item in self.panel.graph.plottables:
151            if item.name == self.panel.graph.selected_plottable:
152                try:
153                    name = item.group_id # item in Data1D
154                except:
155                    name = 'Fit'
156                try:
157                    page = self.fit_panel.add_fit_page(name)
158                    page.set_data_name(item)
159                    self.page_finder[page]= FitProblem()
160                    #creating Data type
161                    data1= Data(sans_data=item)
162                    datas=PlottableData(data=data1,data1d=item)
163                    self.page_finder[page].add_data(datas)
164                except:
165                    raise 
166                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: \
167                    data already Selected "))
168                   
169                   
170    def get_page_finder(self):
171        """ @return self.page_finder used also by simfitpage.py""" 
172        return self.page_finder
173   
174   
175    def set_page_finder(self,modelname,param,values):
176        """
177             Used by simfitpage.py to reset a parameter given the string constrainst.
178             @param modelname: the name ot the model for with the parameter has to reset
179             @param value: can be a string in this case.
180             @note: expecting park used for fit.
181        """ 
182        sim_page=self.fit_panel.get_page(0)
183        for page, value in self.page_finder.iteritems():
184            if page != sim_page:
185                list=value.get_model()
186                model=list[0]
187                if model.name== modelname:
188                    value.set_model_param(param,values)
189                    break
190
191   
192                           
193    def split_string(self,item): 
194        """
195            recieve a word containing ""
196        """
197        #print "fitting: split :went here"
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        try:
210            for page, value in self.page_finder.iteritems():
211                if page== current_pg:
212                    data = value.get_data()
213                    list = value.get_model()
214                    model= list[0]
215                    break
216            #print "fitting : result",result,result.pvec,result.cov,result.fitness
217            i = 0
218            for name in pars:
219                if result.pvec.__class__==numpy.float64:
220                    model.setParam(name,result.pvec)
221                else:
222                    model.setParam(name,result.pvec[i])
223                    #print "fitting: i name out[i]", i,name,float(result.pvec[i])
224                    i += 1
225            new_cov=[]
226            if result.cov !=None:
227                 for j in range(len(result.cov)):
228                     new_cov.append(result.cov[j][j]) 
229            else:
230                new_cov=None
231            current_pg.onsetValues(result.fitness, result.pvec,new_cov)
232            self.plot_helper(currpage=current_pg,qmin=qmin,qmax=qmax)
233        except:
234            raise
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.name,model_name,param_name ,p.name,param_name,p.value
258                    if 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.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 _on_single_fit(self,id=None,qmin=None,qmax=None):
271        """
272            perform fit for the  current page  and return chisqr,out and cov
273            @param engineName: type of fit to be performed
274            @param id: unique id corresponding to a fit problem(model, set of data)
275            @param model: model to fit
276           
277        """
278        #set an engine to perform fit
279        from sans.fit.Fitting import Fit
280        self.fitter= Fit(self._fit_engine)
281        #Setting an id to store model and data
282        if id==None:
283            id=0
284        self.id=id
285        current_pg=self.fit_panel.get_current_page() 
286        for page, value in self.page_finder.iteritems():
287            if page ==current_pg :
288                #print "fitting: self.page_finder",self.page_finder
289                data = value.get_data()
290                list=value.get_model()
291                model=list[0]
292               
293                #Create dictionary of parameters for fitting used
294                pars=[]
295                templist=[]
296                try:
297                    templist=current_pg.get_param_list()
298                except:
299                    raise
300                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
301                    return
302                #for element in templist:
303                #    print "fitting: templist",str(element[0].GetLabelText())
304                #print "fitting: model list",model.getParamList()
305                for element in templist:
306                    try:
307                       pars.append(str(element[0].GetLabelText()))
308                    except:
309                        raise
310                        wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
311                        return
312                #print "fitting: pars",pars
313                pars.sort()
314                print "fitting: model ",model.__class__.__name__
315                self.fitter.set_model(Model(model),model.name, self.id, pars) 
316                self.fitter.set_data(data,self.id,qmin,qmax)
317                #Do the fit SCIPY
318                try:
319                    result=self.fitter.fit()
320                    self._single_fit_completed(result,pars,current_pg,qmin,qmax)
321                   
322                except:
323                    wx.PostEvent(self.parent, StatusEvent(status="Single Fit error: %s" % sys.exc_value))
324                    return
325         
326    def _on_simul_fit(self, id=None,qmin=None,qmax=None):
327        """
328            perform fit for all the pages selected on simpage and return chisqr,out and cov
329            @param engineName: type of fit to be performed
330            @param id: unique id corresponding to a fit problem(model, set of data)
331             in park_integration
332            @param model: model to fit
333           
334        """
335        #print "fitting: probabily breaking on fit call"
336        #set an engine to perform fit
337        from sans.fit.Fitting import Fit
338        self.fitter= Fit(self._fit_engine)
339        #Setting an id to store model and data
340        if id==None:
341             id = 0
342        self.id = id
343        for page, value in self.page_finder.iteritems():
344            try:
345                #print "fitting: self.page_finder",value
346                data = value.get_data()
347                #print "fitting: data",data
348                list = value.get_model()
349                model= list[0]
350                if data != None :
351                    #Create dictionary of parameters for fitting used
352                    pars = []
353                    templist = []
354                    try:
355                        templist = page.get_param_list()
356                    except:
357                        wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
358                        return
359                   
360                    for element in templist:
361                        try:
362                            name = str(element[0].GetLabelText())
363                            pars.append(name)
364                        except:
365                            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
366                            return
367               
368                    print "fitting: pars",pars,model.name
369                    #print "fitter",self.fitter
370                    #print "fitting: model name",model.name
371                    self.fitter.set_model(Model(model),model.name, self.id, pars) 
372                    self.fitter.set_data(data,self.id,qmin,qmax)
373                else:
374                    raise ValueError," Fitting: cannot set model with empty parameter"
375                self.id += 1 
376            except:
377                    raise
378                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
379                    return 
380        #Do the fit SCIPY
381        try:
382            result=self.fitter.fit()
383            self._simul_fit_completed(result,qmin,qmax)
384        except:
385            raise
386            wx.PostEvent(self.parent, StatusEvent(status="Simultaneous Fitting error: %s" % sys.exc_value))
387            return
388   
389    def _on_change_engine(self, engine='park'):
390        """
391            Allow to select the type of engine to perform fit
392            @param engine: the key work of the engine
393        """
394        self._fit_engine = engine
395   
396   
397    def _on_model_panel(self, evt):
398        """
399            react to model selection on any combo box or model menu.plot the model 
400        """
401        model = evt.model
402        name = evt.name
403        sim_page=self.fit_panel.get_page(0)
404        current_pg = self.fit_panel.get_current_page() 
405        if current_pg != sim_page:
406            current_pg.set_model_name(name)
407            current_pg.set_panel(model)
408            try:
409                data=self.page_finder[current_pg].get_data()
410                M_name="M"+str(self.index_model)+"= "+name+"("+data.group_id+")"
411            except:
412                raise 
413                M_name="M"+str(self.index_model)+"= "+name
414            model.name="M"+str(self.index_model)
415            self.index_model += 1 
416            self.page_finder[current_pg].set_theory("Fitness")
417            #print "on model",model.name
418            self.page_finder[current_pg].set_model(model,M_name)
419            self.plot_helper(currpage= current_pg,qmin= None,qmax= None)
420            sim_page.add_model(self.page_finder)
421       
422           
423    def redraw_model(self,qmin= None,qmax= None):
424        """
425            Draw a theory according to model changes or data range.
426            @param qmin: the minimum value plotted for theory
427            @param qmax: the maximum value plotted for theory
428        """
429        current_pg=self.fit_panel.get_current_page()
430        for page, value in self.page_finder.iteritems():
431            if page ==current_pg :
432                break 
433        self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
434       
435    def plot_helper(self,currpage,qmin=None,qmax=None):
436        """
437            Plot a theory given a model and data
438            @param model: the model from where the theory is derived
439            @param currpage: page in a dictionary referring to some data
440        """
441        #print "fitting: plot helper"
442        if self.fit_panel.get_page_count() >1:
443            for page in self.page_finder.iterkeys():
444                if  page==currpage : 
445                    break 
446           
447            data=self.page_finder[page].get_data()
448            list=self.page_finder[page].get_model()
449            model=list[0]
450            if data!=None:
451                theory = Theory1D(x=[], y=[])
452                theory.name = self.page_finder[page].get_theory()
453                theory.group_id = data.group_id
454             
455                x_name, x_units = data.get_xaxis() 
456                y_name, y_units = data.get_yaxis() 
457                theory.xaxis(x_name, x_units)
458                theory.yaxis(y_name, y_units)
459             
460                if qmin == None :
461                   qmin = min(data.x)
462                if qmax == None :
463                    qmax = max(data.x)
464                try:
465                    tempx = qmin
466                    tempy = model.run(qmin)
467                    theory.x.append(tempx)
468                    theory.y.append(tempy)
469                except :
470                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
471                        skipping point x %g %s" %(qmin, sys.exc_value)))
472                           
473                for i in range(len(data.x)):
474                    try:
475                        if data.x[i]> qmin and data.x[i]< qmax:
476                            tempx = data.x[i]
477                            tempy = model.run(tempx)
478                           
479                            theory.x.append(tempx) 
480                            theory.y.append(tempy)
481                    except:
482                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
483                        skipping point x %g %s" %(data.x[i], sys.exc_value)))   
484                try:
485                    tempx = qmax
486                    tempy = model.run(qmax)
487                    theory.x.append(tempx)
488                    theory.y.append(tempy)
489                except:
490                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
491                        skipping point x %g %s" %(qmax, sys.exc_value)))
492                try:
493                    from sans.guicomm.events import NewPlotEvent
494                    #print"fitting: theory",theory
495                    wx.PostEvent(self.parent, NewPlotEvent(plot=theory, title="Analytical model"))
496                except:
497                    raise
498                    print "SimView.complete1D: could not import sans.guicomm.events"
499           
500           
501    def _on_model_menu(self, evt):
502        """
503            Plot a theory from a model selected from the menu
504        """
505        print "_on_model_menu done"
506        #name = evt.model.__class__.__name__
507        name="Model View"
508        model=evt.modelinfo.model()
509        description=evt.modelinfo.description
510        self.fit_panel.add_model_page(model,description,name)       
511        self.draw_model(model)
512       
513    def draw_model(self,model):
514        x = pylab.arange(0.001, 0.1, 0.001)
515        xlen = len(x)
516        dy = numpy.zeros(xlen)
517        y = numpy.zeros(xlen)
518       
519        for i in range(xlen):
520            y[i] = model.run(x[i])
521            dy[i] = math.sqrt(math.fabs(y[i]))
522        try:
523           
524            new_plot = Theory1D(x, y)
525            #new_plot.name = evt.model.__class__.__name__
526            new_plot.name ="Fitness"
527            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
528            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
529         
530            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
531        except:
532            print "SimView.complete1D: could not import sans.guicomm.events"
533
534if __name__ == "__main__":
535    i = Plugin()
536   
537   
538   
539   
Note: See TracBrowser for help on using the repository browser.