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

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

creating a panel for model display

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