source: sasview/sansview/perspectives/fitting/fitting.py @ 1c66bc5

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

model view added

  • Property mode set to 100644
File size: 22.2 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       
199        if string.find(item,".")!=-1:
200            param_names= re.split("\.",item)
201            model_name=param_names[0]
202            param_name=param_names[1] 
203            return model_name,param_name
204       
205       
206    def _single_fit_completed(self,result,pars,current_pg,qmin,qmax):
207        """
208         
209        """
210       
211        try:
212            for page, value in self.page_finder.iteritems():
213                if page== current_pg:
214                    data = value.get_data()
215                    list = value.get_model()
216                    model= list[0]
217                    break
218            #print "fitting : result",result,result.pvec,result.cov,result.fitness
219            i = 0
220            for name in pars:
221                if result.pvec.__class__==numpy.float64:
222                    model.setParam(name,result.pvec)
223                else:
224                    model.setParam(name,result.pvec[i])
225                    #print "fitting: i name out[i]", i,name,float(result.pvec[i])
226                    i += 1
227            new_cov=[]
228            if result.cov !=None:
229                 for j in range(len(result.cov)):
230                     new_cov.append(result.cov[j][j]) 
231            else:
232                new_cov=None
233            current_pg.onsetValues(result.fitness, result.pvec,new_cov)
234            self.plot_helper(currpage=current_pg,qmin=qmin,qmax=qmax)
235        except:
236            raise
237            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
238           
239       
240    def _simul_fit_completed(self,result,qmin,qmax):
241        """
242            Parameter estimation completed,
243            display the results to the user
244            @param alpha: estimated best alpha
245            @param elapsed: computation time
246        """
247        try:
248            for page, value in self.page_finder.iteritems():
249                data = value.get_data()
250                list = value.get_model()
251                model= list[0]
252               
253                small_out = []
254                small_cov = []
255                i = 0
256                for p in result.parameters:
257                    print "fitting: fit in park fitting", p.name, p.value,p.stderr
258                    model_name,param_name = self.split_string(p.name) 
259                    print "fitting: simultfit",model.name,model_name,param_name ,p.name,param_name,p.value
260                    if model.name == model_name:
261                        print "fitting: hello",p.name,param_name,p.value
262                        small_out.append(p.value )
263                        small_cov.append(p.stderr)
264                        model.setParam(param_name,p.value)   
265                #print "fitting: out of each page",page,small_out,small_cov,data.group_id
266                page.onsetValues(result.fitness, small_out,small_cov)
267                self.plot_helper(currpage= page,qmin= qmin,qmax= qmax) 
268        except:
269             wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
270           
271     
272    def _completed(self,result,pars,current_pg, elapsed):
273        """
274            Method called with the results when the inversion
275            is done
276           
277            @param out: output coefficient for the base functions
278            @param cov: covariance matrix
279            @param pr: Invertor instance
280            @param elapsed: time spent computing
281        """
282       
283        # Save useful info
284        self.elapsed = elapsed
285        # Keep a copy of the last result
286        self._last_out = result.pvec
287        self._last_cov = result.cov
288        self._last_chisqr=result.fitness
289        #print "fitting: initial parameter ",pars
290        #result=self.fitter.fit(qmin,qmax)
291       
292        #print "fitting : result",result,result.pvec,result.cov,result.fitness
293        i = 0
294        for name in pars:
295            if result.pvec.__class__==numpy.float64:
296                model.model.setParam(name,result.pvec)
297            else:
298                model.model.setParam(name,result.pvec[i])
299                #print "fitting: i name out[i]", i,name,float(result.pvec[i])
300                i += 1
301        new_cov=[]
302        if result.cov !=None:
303             for j in range(len(result.cov)):
304                 new_cov.append(result.cov[j][j]) 
305        else:
306            new_cov=None
307        current_pg.onsetValues(result.fitness, result.pvec,new_cov)
308        self.plot_helper(currpage=current_pg,qmin=qmin,qmax=qmax)
309 
310       
311    def _on_single_fit(self,id=None,qmin=None,qmax=None):
312        """
313            perform fit for the  current page  and return chisqr,out and cov
314            @param engineName: type of fit to be performed
315            @param id: unique id corresponding to a fit problem(model, set of data)
316            @param model: model to fit
317           
318        """
319        #set an engine to perform fit
320        from sans.fit.Fitting import Fit
321        self.fitter= Fit(self._fit_engine)
322        #Setting an id to store model and data
323        if id==None:
324            id=0
325        self.id=id
326        current_pg=self.fit_panel.get_current_page() 
327        for page, value in self.page_finder.iteritems():
328            if page ==current_pg :
329                #print "fitting: self.page_finder",self.page_finder
330                data = value.get_data()
331                list=value.get_model()
332                model=list[0]
333               
334                #Create dictionary of parameters for fitting used
335                pars=[]
336                templist=[]
337                try:
338                    templist=current_pg.get_param_list()
339                except:
340                    raise
341                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
342                    return
343                #for element in templist:
344                #    print "fitting: templist",str(element[0].GetLabelText())
345                #print "fitting: model list",model.getParamList()
346                for element in templist:
347                    try:
348                       pars.append(str(element[0].GetLabelText()))
349                    except:
350                        raise
351                        wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
352                        return
353                #print "fitting: pars",pars
354                pars.sort()
355                print "fitting: model ",model.__class__.__name__
356                self.fitter.set_model(Model(model),model.name, self.id, pars) 
357                self.fitter.set_data(data,self.id,qmin,qmax)
358                #Do the fit SCIPY
359                try:
360                    result=self.fitter.fit()
361                    self._single_fit_completed(result,pars,current_pg,qmin,qmax)
362                   
363                except:
364                    wx.PostEvent(self.parent, StatusEvent(status="Single Fit error: %s" % sys.exc_value))
365                    return
366         
367    def _on_simul_fit(self, id=None,qmin=None,qmax=None):
368        """
369            perform fit for all the pages selected on simpage and return chisqr,out and cov
370            @param engineName: type of fit to be performed
371            @param id: unique id corresponding to a fit problem(model, set of data)
372             in park_integration
373            @param model: model to fit
374           
375        """
376        #print "fitting: probabily breaking on fit call"
377        #set an engine to perform fit
378        from sans.fit.Fitting import Fit
379        self.fitter= Fit(self._fit_engine)
380        #Setting an id to store model and data
381        if id==None:
382             id = 0
383        self.id = id
384        for page, value in self.page_finder.iteritems():
385            try:
386                #print "fitting: self.page_finder",value
387                data = value.get_data()
388                #print "fitting: data",data
389                list = value.get_model()
390                model= list[0]
391                if data != None :
392                    #Create dictionary of parameters for fitting used
393                    pars = []
394                    templist = []
395                    try:
396                        templist = page.get_param_list()
397                    except:
398                        wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
399                        return
400                   
401                    for element in templist:
402                        try:
403                            name = str(element[0].GetLabelText())
404                            pars.append(name)
405                        except:
406                            wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
407                            return
408               
409                    print "fitting: pars",pars,model.name
410                    #print "fitter",self.fitter
411                    #print "fitting: model name",model.name
412                    self.fitter.set_model(Model(model),model.name, self.id, pars) 
413                    self.fitter.set_data(data,self.id,qmin,qmax)
414                else:
415                    raise ValueError," Fitting: cannot set model with empty parameter"
416                self.id += 1 
417            except:
418                    raise
419                    wx.PostEvent(self.parent, StatusEvent(status="Fitting error: %s" % sys.exc_value))
420                    return 
421        #Do the fit SCIPY
422        try:
423            result=self.fitter.fit()
424            self._simul_fit_completed(result,qmin,qmax)
425        except:
426            raise
427            wx.PostEvent(self.parent, StatusEvent(status="Simultaneous Fitting error: %s" % sys.exc_value))
428            return
429   
430    def _on_change_engine(self, engine='park'):
431        """
432            Allow to select the type of engine to perform fit
433            @param engine: the key work of the engine
434        """
435        self._fit_engine = engine
436   
437   
438    def _on_model_panel(self, evt):
439        """
440            react to model selection on any combo box or model menu.plot the model 
441        """
442        model = evt.model
443        name = evt.name
444        sim_page=self.fit_panel.get_page(0)
445        current_pg = self.fit_panel.get_current_page() 
446        if current_pg != sim_page:
447            current_pg.set_model_name(name)
448            current_pg.set_panel(model)
449            try:
450                data=self.page_finder[current_pg].get_data()
451                M_name="M"+str(self.index_model)+"= "+name+"("+data.group_id+")"
452            except:
453                raise 
454                M_name="M"+str(self.index_model)+"= "+name
455            model.name="M"+str(self.index_model)
456            self.index_model += 1 
457            self.page_finder[current_pg].set_theory("Fitness")
458            #print "on model",model.name
459            self.page_finder[current_pg].set_model(model,M_name)
460            self.plot_helper(currpage= current_pg,qmin= None,qmax= None)
461            sim_page.add_model(self.page_finder)
462       
463           
464    def redraw_model(self,qmin= None,qmax= None):
465        """
466            Draw a theory according to model changes or data range.
467            @param qmin: the minimum value plotted for theory
468            @param qmax: the maximum value plotted for theory
469        """
470        current_pg=self.fit_panel.get_current_page()
471        for page, value in self.page_finder.iteritems():
472            if page ==current_pg :
473                break 
474        self.plot_helper(currpage=page,qmin= qmin,qmax= qmax)
475       
476    def plot_helper(self,currpage,qmin=None,qmax=None):
477        """
478            Plot a theory given a model and data
479            @param model: the model from where the theory is derived
480            @param currpage: page in a dictionary referring to some data
481        """
482        #print "fitting: plot helper"
483        if self.fit_panel.get_page_count() >1:
484            for page in self.page_finder.iterkeys():
485                if  page==currpage : 
486                    break 
487           
488            data=self.page_finder[page].get_data()
489            list=self.page_finder[page].get_model()
490            model=list[0]
491            if data!=None:
492                theory = Theory1D(x=[], y=[])
493                theory.name = self.page_finder[page].get_theory()
494                theory.group_id = data.group_id
495             
496                x_name, x_units = data.get_xaxis() 
497                y_name, y_units = data.get_yaxis() 
498                theory.xaxis(x_name, x_units)
499                theory.yaxis(y_name, y_units)
500             
501                if qmin == None :
502                   qmin = min(data.x)
503                if qmax == None :
504                    qmax = max(data.x)
505                try:
506                    tempx = qmin
507                    tempy = model.run(qmin)
508                    theory.x.append(tempx)
509                    theory.y.append(tempy)
510                except :
511                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
512                        skipping point x %g %s" %(qmin, sys.exc_value)))
513                           
514                for i in range(len(data.x)):
515                    try:
516                        if data.x[i]> qmin and data.x[i]< qmax:
517                            tempx = data.x[i]
518                            tempy = model.run(tempx)
519                           
520                            theory.x.append(tempx) 
521                            theory.y.append(tempy)
522                    except:
523                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
524                        skipping point x %g %s" %(data.x[i], sys.exc_value)))   
525                try:
526                    tempx = qmax
527                    tempy = model.run(qmax)
528                    theory.x.append(tempx)
529                    theory.y.append(tempy)
530                except:
531                        wx.PostEvent(self.parent, StatusEvent(status="fitting \
532                        skipping point x %g %s" %(qmax, sys.exc_value)))
533                try:
534                    from sans.guicomm.events import NewPlotEvent
535                    #print"fitting: theory",theory
536                    wx.PostEvent(self.parent, NewPlotEvent(plot=theory, title="Analytical model"))
537                except:
538                    raise
539                    print "SimView.complete1D: could not import sans.guicomm.events"
540           
541           
542    def _on_model_menu(self, evt):
543        """
544            Plot a theory from a model selected from the menu
545        """
546        print "_on_model_menu done"
547        #name = evt.model.__class__.__name__
548        name="Model View"
549        self.fit_panel.add_model_page(evt.model,name)       
550        self.draw_model(evt.model)
551       
552    def draw_model(self,model):
553        x = pylab.arange(0.001, 0.1, 0.001)
554        xlen = len(x)
555        dy = numpy.zeros(xlen)
556        y = numpy.zeros(xlen)
557       
558        for i in range(xlen):
559            y[i] = model.run(x[i])
560            dy[i] = math.sqrt(math.fabs(y[i]))
561        try:
562           
563            new_plot = Theory1D(x, y)
564            #new_plot.name = evt.model.__class__.__name__
565            new_plot.name ="Fitness"
566            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
567            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
568         
569            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Analytical model"))
570        except:
571            print "SimView.complete1D: could not import sans.guicomm.events"
572
573if __name__ == "__main__":
574    i = Plugin()
575   
576   
577   
578   
Note: See TracBrowser for help on using the repository browser.