source: sasview/sansview/perspectives/fitting/fitting.py @ 948add7

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

perform single fit when selecting one model on simul_page

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