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

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 ef16f59 was ef16f59, checked in by Jae Cho <jhjcho@…>, 14 years ago

Now it saves and opens all states of fitv taps.

  • Property mode set to 100644
File size: 54.1 KB
Line 
1
2
3################################################################################
4#This software was developed by the University of Tennessee as part of the
5#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
6#project funded by the US National Science Foundation.
7#
8#See the license text in license.txt
9#
10#copyright 2009, University of Tennessee
11################################################################################
12
13
14import  re
15import sys
16import wx
17import logging
18import numpy
19import math
20import string
21import time
22import thread
23from copy import deepcopy
24
25import models
26import fitpage
27
28from DataLoader.loader import Loader
29
30from sans.guiframe.dataFitting import Data2D
31from sans.guiframe.dataFitting import Data1D
32from sans.guiframe.dataFitting import Theory1D
33
34from sans.guicomm.events import NewPlotEvent, StatusEvent 
35from sans.guicomm.events import EVT_SLICER_PANEL,ERR_DATA,EVT_REMOVE_DATA
36from sans.guicomm.events import EVT_SLICER_PARS_UPDATE
37
38from sans.fit.AbstractFitEngine import Model
39from sans.fit.AbstractFitEngine import FitAbort
40from console import ConsoleUpdate
41
42from fitproblem import FitProblem
43from fitpanel import FitPanel
44from fit_thread import FitThread
45from pagestate import Reader
46
47DEFAULT_BEAM = 0.005
48DEFAULT_QMIN = 0.001
49DEFAULT_QMAX = 0.13
50DEFAULT_NPTS = 50
51
52(PageInfoEvent, EVT_PAGE_INFO)   = wx.lib.newevent.NewEvent()
53(FitStateUpdateEvent, EVT_STATE_UPDATE)   = wx.lib.newevent.NewEvent()
54from fitpage import Chi2UpdateEvent
55
56
57class PlotInfo:
58    """
59    store some plotting field
60    """
61    _xunit = 'A^{-1}'
62    _xaxis= "\\rm{Q}"
63    _yunit = "cm^{-1}"
64    _yaxis= "\\rm{Intensity} "
65    id = "Model"
66    group_id = "Model"
67    title= None
68    info= None
69   
70   
71class Plugin:
72    """
73    Fitting plugin is used to perform fit
74    """
75    def __init__(self):
76        """
77        """
78        ## Plug-in name
79        self.sub_menu = "Fitting"
80       
81        ## Reference to the parent window
82        self.parent = None
83        #Provide list of models existing in the application
84        self.menu_mng = models.ModelManager()
85        ## List of panels for the simulation perspective (names)
86        self.perspective = []
87        #list of panel to send to guiframe
88        self.mypanels = []
89        # reference to the current running thread
90        self.calc_2D = None
91        self.calc_1D = None
92        self.calc_fit = None
93       
94        # Start with a good default
95        self.elapsed = 0.022
96        # the type of optimizer selected, park or scipy
97        self.fitter  = None
98        #let fit ready
99        self.fitproblem_count = None
100        #Flag to let the plug-in know that it is running stand alone
101        self.standalone = True
102        ## dictionary of page closed and id
103        self.closed_page_dict = {}
104        ## Fit engine
105        self._fit_engine = 'scipy'
106        #List of selected data
107        self.selected_data_list = []
108        ## list of slicer panel created to display slicer parameters and results
109        self.slicer_panels = []
110        # model 2D view
111        self.model2D_id = None
112        #keep reference of the simultaneous fit page
113        self.sim_page = None
114        #dictionary containing data name and error on dy of that data
115        self.err_dy = {}
116        self.theory_data = None 
117        #Create a reader for fit page's state
118        self.state_reader = None 
119        self.temp_state = []
120        self.state_index = 0
121        # Log startup
122        logging.info("Fitting plug-in started") 
123       
124    def populate_menu(self, id, owner):
125        """
126        Create a menu for the Fitting plug-in
127       
128        :param id: id to create a menu
129        :param owner: owner of menu
130       
131        :return: list of information to populate the main menu
132       
133        """
134        #Menu for fitting
135        self.menu1 = wx.Menu()
136       
137        #Set park engine
138        id3 = wx.NewId()
139        scipy_help= "Scipy Engine: Perform Simple fit. More in Help window...."
140        self.menu1.AppendCheckItem(id3, "Simple Fit  [Scipy]",scipy_help) 
141        wx.EVT_MENU(owner, id3,  self._onset_engine_scipy)
142       
143        id3 = wx.NewId()
144        park_help = "Park Engine: Perform Complex fit. More in Help window...."
145        self.menu1.AppendCheckItem(id3, "Complex Fit  [Park]",park_help) 
146        wx.EVT_MENU(owner, id3,  self._onset_engine_park)
147       
148        self.menu1.FindItemByPosition(0).Check(True)
149        self.menu1.FindItemByPosition(1).Check(False)
150           
151        self.menu1.AppendSeparator()
152        id1 = wx.NewId()
153        simul_help = "Allow to edit fit engine with multiple model and data"
154        self.menu1.Append(id1, '&Simultaneous Page',simul_help)
155        wx.EVT_MENU(owner, id1, self.on_add_sim_page)
156       
157        #menu for model
158        menu2 = wx.Menu()
159        self.menu_mng.populate_menu(menu2, owner)
160        id2 = wx.NewId()
161        owner.Bind(models.EVT_MODEL,self._on_model_menu)
162     
163        self.fit_panel.set_owner(owner)
164        self.fit_panel.set_model_list(self.menu_mng.get_model_list())
165   
166        #create  menubar items
167        return [(id, self.menu1, "Fitting")]
168               
169    def on_add_sim_page(self, event):
170        """
171        Create a page to access simultaneous fit option
172        """
173        Plugin.on_perspective(self,event=event)
174        if self.sim_page !=None:
175            msg= "Simultaneous Fit page already opened"
176            wx.PostEvent(self.parent, StatusEvent(status= msg))
177            return 
178       
179        self.sim_page= self.fit_panel.add_sim_page()
180       
181    def help(self, evt):
182        """
183        Show a general help dialog.
184        """
185       
186        from help_panel import  HelpWindow
187        frame = HelpWindow(None, -1, 'HelpWindow')   
188        frame.Show(True)
189       
190    def get_context_menu(self, graph=None):
191        """
192        Get the context menu items available for P(r).them allow fitting option
193        for Data2D and Data1D only.
194       
195        :param graph: the Graph object to which we attach the context menu
196       
197        :return: a list of menu items with call-back function
198       
199        :note: if Data1D was generated from Theory1D 
200                the fitting option is not allowed
201               
202        """
203        self.graph = graph
204        fit_option = "Select data for fitting"
205        fit_hint =  "Dialog with fitting parameters "
206       
207        for item in graph.plottables:
208            if item.__class__.__name__ is "Data2D":
209               
210                if hasattr(item,"is_data"):
211                    if item.is_data:
212                        return [[fit_option, fit_hint, self._onSelect]]
213                    else:
214                        return [] 
215                return [[fit_option, fit_hint, self._onSelect]]
216            else:
217                if item.name == graph.selected_plottable :
218                    if item.name in ["$I_{obs}(q)$","$I_{fit}(q)$","$P_{fit}(r)$"]:
219                        return [] 
220                    if hasattr(item, "group_id"):
221                        # if is_data is true , this in an actual data loaded
222                        #else it is a data created from a theory model
223                        if hasattr(item,"is_data"):
224                            if item.is_data:
225                                return [[fit_option, fit_hint,
226                                          self._onSelect]]
227                            else:
228                                return [] 
229                        else:
230                           return [[fit_option, fit_hint, self._onSelect]]
231        return []   
232
233
234    def get_panels(self, parent):
235        """
236        Create and return a list of panel objects
237        """
238        self.parent = parent
239        self.parent.Bind(EVT_STATE_UPDATE, self.on_set_state_helper)
240        # Creation of the fit panel
241        self.fit_panel = FitPanel(self.parent, -1)
242        #Set the manager for the main panel
243        self.fit_panel.set_manager(self)
244        # List of windows used for the perspective
245        self.perspective = []
246        self.perspective.append(self.fit_panel.window_name)
247        # take care of saving  data, model and page associated with each other
248        self.page_finder = {}
249        #index number to create random model name
250        self.index_model = 0
251        self.index_theory= 0
252        self.parent.Bind(EVT_SLICER_PANEL, self._on_slicer_event)
253        self.parent.Bind(ERR_DATA, self._on_data_error)
254        self.parent.Bind(EVT_REMOVE_DATA, self._closed_fitpage)
255        self.parent.Bind(EVT_SLICER_PARS_UPDATE, self._onEVT_SLICER_PANEL)
256        self.parent._mgr.Bind(wx.aui.EVT_AUI_PANE_CLOSE,self._onclearslicer)   
257        #Create reader when fitting panel are created
258        self.state_reader = Reader(self.set_state)   
259        #append that reader to list of available reader
260        loader = Loader()
261        loader.associate_file_reader(".fitv", self.state_reader)
262        loader.associate_file_reader(".svs", self.state_reader)
263        #Send the fitting panel to guiframe
264        self.mypanels.append(self.fit_panel)
265        return self.mypanels
266   
267    def get_perspective(self):
268        """
269        Get the list of panel names for this perspective
270        """
271        return self.perspective
272   
273    def on_perspective(self, event):
274        """
275        Call back function for the perspective menu item.
276        We notify the parent window that the perspective
277        has changed.
278        """
279        self.parent.set_perspective(self.perspective)
280   
281    def set_default_perspective(self):
282        """
283        Call back method that True to notify the parent that the current plug-in
284        can be set as default  perspective.
285        when returning False, the plug-in is not candidate for an automatic
286        default perspective setting
287        """
288        return True
289   
290    def post_init(self):
291        """
292        Post initialization call back to close the loose ends
293        """
294        pass
295   
296    def set_state(self, state, datainfo=None):
297        """
298        Call-back method for the fit page state reader.
299        This method is called when a .fitv file is loaded.
300       
301        :param state: PageState object
302       
303        """
304        # store fitting state in temp_state
305        self.temp_state.append(state) 
306        # index to start with for a new set_state
307        self.state_index = 0
308
309    def  on_set_state_helper(self,event=None):
310        """
311        Set_state_helper. This acutally sets state after plotting data from state file.
312       
313        : event: FitStateUpdateEvent called by plot_data from guiframe, data_loader
314        """
315        if self.temp_state == None or len(self.temp_state) == 0:
316            return
317        try:
318            # Load fitting state
319            state = self.temp_state[self.state_index]
320            #set state
321            page = self.fit_panel.set_state(state) 
322            # get ready for the next set state
323            self.state_index += 1
324           
325            #reset state variables to default when all set_state is finished.
326            if len(self.temp_state) == self.state_index:
327                self.temp_state = []
328                # Make sure the user sees the fitting panel after loading
329                self.parent.set_perspective(self.perspective) 
330        except:
331            self.temp_state = [] 
332            raise
333                 
334    def save_fit_state(self, filepath, fitstate): 
335        """
336        save fit page state into file
337        """
338        self.state_reader.write(filename=filepath, fitstate=fitstate)
339       
340    def copy_data(self, item, dy=None):
341        """
342        receive a data 1D and the list of errors on dy
343        and create a new data1D data
344   
345        """
346        id = None
347        if hasattr(item,"id"):
348            id = item.id
349
350        data= Data1D(x=item.x, y=item.y,dx=None, dy=None)
351        data.copy_from_datainfo(item)
352        item.clone_without_data(clone=data)   
353        data.dy = deepcopy(dy)
354        data.name = item.name
355        ## allow to highlight data when plotted
356        data.interactive = deepcopy(item.interactive)
357        ## when 2 data have the same id override the 1 st plotted
358        data.id = id
359        data.group_id = item.group_id
360        return data
361   
362    def set_fit_range(self, page, qmin, qmax):
363        """
364        Set the fitting range of a given page
365        """
366        if page in self.page_finder.iterkeys():
367            fitproblem= self.page_finder[page]
368            fitproblem.set_range(qmin= qmin, qmax= qmax)
369                   
370    def schedule_for_fit(self,value=0,page=None,fitproblem =None): 
371        """
372        Set the fit problem field to 0 or 1 to schedule that problem to fit.
373        Schedule the specified fitproblem or get the fit problem related to
374        the current page and set value.
375       
376        :param value: integer 0 or 1
377        :param fitproblem: fitproblem to schedule or not to fit
378       
379        """   
380        if fitproblem !=None:
381            fitproblem.schedule_tofit(value)
382        else:
383            if page in self.page_finder.iterkeys():
384                fitproblem= self.page_finder[page]
385                fitproblem.schedule_tofit(value)
386         
387    def get_page_finder(self):
388        """
389        return self.page_finder used also by simfitpage.py
390        """ 
391        return self.page_finder
392   
393    def set_page_finder(self,modelname,names,values):
394        """
395        Used by simfitpage.py to reset a parameter given the string constrainst.
396         
397        :param modelname: the name ot the model for with the parameter has to reset
398        :param value: can be a string in this case.
399        :param names: the paramter name
400         
401        :note: expecting park used for fit.
402         
403        """ 
404        sim_page= self.sim_page
405        for page, value in self.page_finder.iteritems():
406            if page != sim_page:
407                list=value.get_model()
408                model = list[0]
409                if model.name== modelname:
410                    value.set_model_param(names,values)
411                    break
412         
413    def split_string(self,item): 
414        """
415        receive a word containing dot and split it. used to split parameterset
416        name into model name and parameter name example: ::
417       
418            paramaterset (item) = M1.A
419            Will return model_name = M1 , parameter name = A
420           
421        """
422        if string.find(item,".")!=-1:
423            param_names= re.split("\.",item)
424            model_name=param_names[0]           
425            ##Assume max len is 3; eg., M0.radius.width
426            if len(param_names) == 3:
427                param_name=param_names[1]+"."+param_names[2]
428            else:
429                param_name=param_names[1]                   
430            return model_name,param_name
431       
432    def stop_fit(self):
433        """
434        Stop the fit engine
435        """
436        if self.calc_fit!= None and self.calc_fit.isrunning():
437            self.calc_fit.stop()
438            wx.PostEvent(self.parent, StatusEvent(status="Fitting  \
439                is cancelled" , type="stop"))
440           
441    def set_smearer_nodraw(self,smearer, qmin=None, qmax=None):
442        """
443        Get a smear object and store it to a fit problem
444       
445        :param smearer: smear object to allow smearing data
446       
447        """ 
448        self.current_pg=self.fit_panel.get_current_page()
449        self.page_finder[self.current_pg].set_smearer(smearer)
450        ## draw model 1D with smeared data
451        data =  self.page_finder[self.current_pg].get_fit_data()
452        model = self.page_finder[self.current_pg].get_model()
453        ## if user has already selected a model to plot
454        ## redraw the model with data smeared
455        smear =self.page_finder[self.current_pg].get_smearer()   
456           
457    def set_smearer(self,smearer, qmin=None, qmax=None):
458        """
459        Get a smear object and store it to a fit problem
460       
461        :param smearer: smear object to allow smearing data
462       
463        """   
464        self.current_pg=self.fit_panel.get_current_page()
465        self.page_finder[self.current_pg].set_smearer(smearer)
466        ## draw model 1D with smeared data
467        data =  self.page_finder[self.current_pg].get_fit_data()
468        model = self.page_finder[self.current_pg].get_model()
469        ## if user has already selected a model to plot
470        ## redraw the model with data smeared
471
472        smear =self.page_finder[self.current_pg].get_smearer()
473        if model!= None:
474            self.draw_model( model=model, data= data, smearer= smear,
475                qmin= qmin, qmax= qmax)
476
477    def draw_model(self, model, data= None,smearer= None,
478                   enable1D= True, enable2D= False,
479                   qmin= DEFAULT_QMIN, qmax= DEFAULT_QMAX, qstep= DEFAULT_NPTS):
480        """
481        Draw model.
482       
483        :param model: the model to draw
484        :param name: the name of the model to draw
485        :param data: the data on which the model is based to be drawn
486        :param description: model's description
487        :param enable1D: if true enable drawing model 1D
488        :param enable2D: if true enable drawing model 2D
489        :param qmin:  Range's minimum value to draw model
490        :param qmax:  Range's maximum value to draw model
491        :param qstep: number of step to divide the x and y-axis
492             
493        """
494        if data.__class__.__name__ !="Data2D":   
495            ## draw model 1D with no loaded data
496            self._draw_model1D( model= model, data= data,
497                                                    enable1D=enable1D, 
498                                                    smearer= smearer,
499                                                    qmin= qmin, qmax= qmax, qstep= qstep )
500        else:     
501            ## draw model 2D with no initial data
502             self._draw_model2D(model=model,
503                                      data = data,
504                                      enable2D= enable2D,
505                                      smearer= smearer,
506                                      qmin=qmin,
507                                      qmax=qmax,
508                                      qstep=qstep)
509           
510    def onFit(self):
511        """
512        perform fit
513        """
514        ##  count the number of fitproblem schedule to fit
515        fitproblem_count= 0
516        for value in self.page_finder.itervalues():
517            if value.get_scheduled()==1:
518                fitproblem_count += 1
519               
520        ## if simultaneous fit change automatically the engine to park
521        if fitproblem_count >1:
522            self._on_change_engine(engine='park')
523           
524        self.fitproblem_count = fitproblem_count 
525         
526        from sans.fit.Fitting import Fit
527        self.fitter= Fit(self._fit_engine)
528       
529        if self._fit_engine=="park":
530            engineType="Simultaneous Fit"
531        else:
532            engineType="Single Fit"
533           
534        fproblemId = 0
535        self.current_pg=None
536        for page, value in self.page_finder.iteritems():
537            try:
538                if value.get_scheduled()==1:
539                    #Get list of parameters name to fit
540                    pars = []
541                    templist = []
542                    templist = page.get_param_list()
543                    for element in templist:
544                        name = str(element[1])
545                        pars.append(name)
546                    #Set Engine  (model , data) related to the page on
547                    self._fit_helper( value=value,pars=pars,
548                                      id=fproblemId, title= engineType ) 
549                    fproblemId += 1 
550                    self.current_pg= page
551            except:
552                msg= "%s error: %s" % (engineType,sys.exc_value)
553                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
554                                                      type="stop"))
555                return 
556        ## If a thread is already started, stop it
557        #if self.calc_fit!= None and self.calc_fit.isrunning():
558        #    self.calc_fit.stop()
559         #Handler used for park engine displayed message
560        handler = ConsoleUpdate(parent=self.parent,improvement_delta=0.1)
561        ## perform single fit
562        if fitproblem_count == 1:
563            calc_fit=FitThread(parent =self.parent,
564                                    handler = handler,
565                                    fn= self.fitter,
566                                   cpage=self.current_pg,
567                                   pars= pars,
568                                   updatefn=handler.update_fit,
569                                   completefn= self._single_fit_completed)
570        else:
571            ## Perform more than 1 fit at the time
572            calc_fit=FitThread(parent=self.parent,
573                                handler=handler,
574                                    fn= self.fitter,
575                                   completefn= self._simul_fit_completed,
576                                  updatefn=handler.update_fit)
577       
578        calc_fit.queue()
579        self.ready_fit(calc_fit=calc_fit)
580     
581    def ready_fit(self, calc_fit):
582        """
583        Ready for another fit
584        """
585        if self.fitproblem_count != None and self.fitproblem_count > 1:
586            calc_fit.ready(2.5)
587           
588        else:
589            time.sleep(0.4)
590           
591    def remove_plot(self, page, theory=False):
592        """
593        remove model plot when a fit page is closed
594        """
595        fitproblem = self.page_finder[page]
596        data = fitproblem.get_fit_data()
597        model = fitproblem.get_model()
598        if model is not None:
599            name = model.name
600            new_plot = Theory1D(x=[], y=[], dy=None)
601            new_plot.name = name
602            new_plot.xaxis(data._xaxis, data._xunit)
603            new_plot.yaxis(data._yaxis, data._yunit)
604            new_plot.group_id = data.group_id
605            new_plot.id = data.id + name
606            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=data.name))
607        if theory:
608            new_plot_data = Data1D(x=[], y=[], dx=None, dy=None)
609            new_plot_data.name = data.name
610            new_plot_data.xaxis(data._xaxis, data._xunit)
611            new_plot_data.yaxis(data._yaxis, data._yunit)
612            new_plot_data.group_id = data.group_id
613            new_plot_data.id = data.id
614            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot_data,
615                                                    title=data.name))
616    def create_fittable_data2D(self, data):
617        """
618        check if the current data is a data 2d and add dy to that data
619       
620        :return: Data2D
621       
622        """
623        if data.__class__.__name__ != "Data2D":
624            raise ValueError, " create_fittable_data2D expects a Data2D"
625        ## Data2D case
626        new_data = deepcopy(data)
627        if not hasattr(data, "is_data"):
628            new_data.group_id += "data2D"
629            new_data.id +="data2D"
630            new_data.is_data = False
631            title = new_data.name
632            title += " Fit"
633            wx.PostEvent(self.parent, NewPlotEvent(plot=new_data,
634                                                    title=str(title)))
635        else:
636            new_data.is_data = True
637        return new_data
638       
639    def create_fittable_data1D(self, data):
640        """
641        check if the current data is a theory 1d and add dy to that data
642       
643        :return: Data1D
644       
645        """
646        class_name = data.__class__.__name__
647        if not class_name in ["Data1D", "Theory1D"]:
648            raise ValueError, "create_fittable_data1D expects Data1D"
649     
650        #get the appropriate dy
651        dy = deepcopy(data.dy)
652        if len(self.err_dy) > 0:
653            if data.name in  self.err_dy.iterkeys():
654                dy = self.err_dy[data.name]   
655        if data.__class__.__name__ == "Theory1D":
656            new_data = self.copy_data(data, dy)
657            new_data.group_id = str(new_data.group_id)+"data1D"
658            new_data.id = str(new_data.id)+"data1D"
659            new_data.is_data = False
660            title = new_data.name
661            title = 'Data created from Theory'
662            wx.PostEvent(self.parent, NewPlotEvent(plot=new_data,
663                                                    title=str(title),
664                                                   reset=True))
665        else:
666            new_data = self.copy_data(data, dy) 
667            new_data.id = data.id
668            new_data.is_data = True
669        return new_data
670           
671    def store_page(self, page, data):
672        """
673        Helper to save page reference into the plug-in
674       
675        :param page: page to store
676       
677        """
678        page.set_data(data) 
679        #create a fitproblem storing all link to data,model,page creation
680        if not page in self.page_finder.keys():
681            self.page_finder[page] = FitProblem()
682        self.page_finder[page].add_fit_data(data)
683       
684    def add_fit_page(self, data):
685        """
686        given a data, ask to the fitting panel to create a new fitting page,
687        get this page and store it into the page_finder of this plug-in
688        """
689        try:
690            page = self.fit_panel.add_fit_page(data)
691           
692            # add data associated to the page created
693            if page != None: 
694                self.store_page(page=page, data=data)
695                wx.PostEvent(self.parent, StatusEvent(status="Page Created",
696                                               info="info"))
697            else:
698                msg = "Page was already Created"
699                wx.PostEvent(self.parent, StatusEvent(status=msg, info="warning"))
700        except:
701            msg = "Creating Fit page: %s"%sys.exc_value
702            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
703       
704    def _onEVT_SLICER_PANEL(self, event):
705        """
706        receive and event telling to update a panel with a name starting with
707        event.panel_name. this method update slicer panel for a given interactor.
708       
709        :param event: contains type of slicer , paramaters for updating the panel
710            and panel_name to find the slicer 's panel concerned.
711        """
712        for item in self.parent.panels:
713            if self.parent.panels[item].window_caption.startswith(event.panel_name):
714                self.parent.panels[item].set_slicer(event.type, event.params)
715               
716        self.parent._mgr.Update()
717   
718    def _closed_fitpage(self, event):   
719        """
720        request fitpanel to close a given page when its unique data is removed
721        from the plot. close fitpage only when the a loaded data is removed
722        """   
723        if event is None or event.data is None:
724            return
725       
726        if hasattr(event.data,"is_data"):
727            if not event.data.is_data or event.data.__class__.__name__=="Data1D":
728                self.fit_panel.close_page_with_data(event.data) 
729       
730    def _add_page_onmenu(self, name,fitproblem=None):
731        """
732        Add name of a closed page of fitpanel in a menu
733        """
734        list = self.menu1.GetMenuItems()
735        for item in list:
736            if name == item.GetItemLabel():
737                self.closed_page_dict[name][1] = fitproblem
738               
739        if not name in self.closed_page_dict.keys():   
740            # Post paramters
741            event_id = wx.NewId()
742            self.menu1.Append(event_id, name, "Show %s fit panel" % name)
743            self.closed_page_dict[name]= [event_id, fitproblem]
744            wx.EVT_MENU(self.parent,event_id,  self._open_closed_page)
745       
746    def _open_closed_page(self, event):   
747        """
748        reopen a closed page
749        """
750        for name, value in self.closed_page_dict.iteritems():
751            if event.GetId() in value:
752                id,fitproblem = value
753                if name !="Model":
754                    data= fitproblem.get_fit_data()
755                    page = self.fit_panel.add_fit_page(data= data,reset=True)
756                    if fitproblem != None:
757                        self.page_finder[page]=fitproblem
758                        if self.sim_page != None:
759                            self.sim_page.draw_page()
760                           
761                else:
762                    model = fitproblem
763                    self.fit_panel.add_model_page(model=model, topmenu=True,
764                                                  reset= True)
765                    break
766   
767    def _reset_schedule_problem(self, value=0):
768        """
769        unschedule or schedule all fitproblem to be fit
770        """
771        for page, fitproblem in self.page_finder.iteritems():
772            fitproblem.schedule_tofit(value)
773           
774    def _fit_helper(self,pars,value, id, title="Single Fit " ):
775        """
776        helper for fitting
777        """
778        metadata = value.get_fit_data()
779        model = value.get_model()
780        smearer = value.get_smearer()
781        qmin , qmax = value.get_range()
782        self.fit_id =id
783        #Create list of parameters for fitting used
784        templist=[]
785       
786        try:
787            #Extra list of parameters and their constraints
788            listOfConstraint= []
789           
790            param = value.get_model_param()
791            if len(param)>0:
792                for item in param:
793                    ## check if constraint
794                    if item[0] !=None and item[1] != None:
795                        listOfConstraint.append((item[0],item[1]))
796                   
797            #Do the single fit
798            self.fitter.set_model(model, self.fit_id,
799                                   pars,constraints = listOfConstraint)
800           
801            self.fitter.set_data(data=metadata,Uid=self.fit_id,
802                                 smearer=smearer,qmin= qmin,qmax=qmax )
803           
804            self.fitter.select_problem_for_fit(Uid= self.fit_id,
805                                               value= value.get_scheduled())
806            value.clear_model_param()
807        except:
808            msg= title +" error: %s" % sys.exc_value
809            wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop"))
810            return
811       
812    def _onSelect(self,event):
813        """
814        when Select data to fit a new page is created .Its reference is
815        added to self.page_finder
816        """
817        self.panel = event.GetEventObject()
818        Plugin.on_perspective(self,event=event)
819        for plottable in self.panel.graph.plottables:
820            if plottable.__class__.__name__ in ["Data1D", "Theory1D"]:
821                if plottable.name == self.panel.graph.selected_plottable:
822                    data = self.create_fittable_data1D(data=plottable)
823                    self.add_fit_page(data=data)
824                    return
825            else:
826                data = self.create_fittable_data2D(data=plottable)
827                self.add_fit_page(data=data)
828           
829    def _single_fit_completed(self,result,pars,cpage, elapsed=None):
830        """
831        Display fit result on one page of the notebook.
832       
833        :param result: result of fit
834        :param pars: list of names of parameters fitted
835        :param current_pg: the page where information will be displayed
836        :param qmin: the minimum value of x to replot the model
837        :param qmax: the maximum value of x to replot model
838         
839        """     
840        try:
841            if result ==None:
842                msg= "Simple Fitting Stop !!!"
843                wx.PostEvent(self.parent, StatusEvent(status=msg,info="warning",
844                                                      type="stop"))
845                return
846            if not numpy.isfinite(result.fitness) or numpy.any(result.pvec ==None )or not numpy.all(numpy.isfinite(result.pvec) ):
847                msg= "Single Fitting did not converge!!!"
848                wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
849                return
850            for page, value in self.page_finder.iteritems():
851                if page==cpage :
852                    model= value.get_model()
853                    break
854            param_name = []
855            i = 0
856            for name in pars:
857                param_name.append(name)
858
859            cpage.onsetValues(result.fitness,param_name, result.pvec,result.stderr)
860           
861        except:
862            msg= "Single Fit completed but Following error occurred:%s"% sys.exc_value
863            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
864                                                  type="stop"))
865            return
866       
867    def _simul_fit_completed(self,result,pars=None,cpage=None, elapsed=None):
868        """
869        Parameter estimation completed,
870        display the results to the user
871       
872        :param alpha: estimated best alpha
873        :param elapsed: computation time
874       
875        """
876        ## fit more than 1 model at the same time
877        try:
878            msg = "" 
879            if result ==None:
880                msg= "Complex Fitting Stop !!!"
881                wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
882                return
883            if not numpy.isfinite(result.fitness) or numpy.any(result.pvec ==None )or not numpy.all(numpy.isfinite(result.pvec) ):
884                msg= "Single Fitting did not converge!!!"
885                wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
886                return
887             
888            for page, value in self.page_finder.iteritems():   
889                if value.get_scheduled()==1:
890                    model = value.get_model()
891                    data =  value.get_fit_data()
892                    small_param_name = []
893                    small_out = []
894                    small_cov = []
895                    i = 0
896                    #Separate result in to data corresponding to each page
897                    for p in result.parameters:
898                        model_name,param_name = self.split_string(p.name) 
899                        if model.name == model_name:
900                            p_name= model.name+"."+param_name
901                            if p.name == p_name:     
902                                if p.value != None and numpy.isfinite(p.value):
903                                    small_out.append(p.value )
904                                    small_param_name.append(param_name)
905                                    small_cov.append(p.stderr)
906
907                    # Display result on each page
908                    page.onsetValues(result.fitness, small_param_name,small_out,small_cov)
909        except:
910             msg= "Simultaneous Fit completed"
911             msg +=" but Following error occurred:%s"%sys.exc_value
912             wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
913             return 
914             
915    def _on_show_panel(self, event):
916        """
917        """
918        #print "_on_show_panel: fitting"
919        pass
920       
921    def _onset_engine_park(self,event):
922        """
923        set engine to park
924        """
925        Plugin.on_perspective(self,event=event)
926        self._on_change_engine('park')
927       
928    def _onset_engine_scipy(self,event):
929        """
930        set engine to scipy
931        """
932        self._on_change_engine('scipy')
933       
934    def _on_slicer_event(self, event):
935        """
936        Receive a panel as event and send it to guiframe
937       
938        :param event: event containing a panel
939       
940        """
941        if event.panel is not None:
942            new_panel = event.panel
943            self.slicer_panels.append(event.panel)
944            # Set group ID if available
945            event_id = self.parent.popup_panel(new_panel)
946            #self.menu3.Append(event_id, new_panel.window_caption,
947            #                 "Show %s plot panel" % new_panel.window_caption)
948            # Set UID to allow us to reference the panel later
949         
950            new_panel.uid = event_id
951            self.mypanels.append(new_panel) 
952       
953    def _onclearslicer(self, event):
954        """
955        Clear the boxslicer when close the panel associate with this slicer
956        """
957        name =event.GetPane().caption
958   
959        for panel in self.slicer_panels:
960            if panel.window_caption==name:
961               
962                for item in self.parent.panels:
963                    if hasattr(self.parent.panels[item],"uid"):
964                        if self.parent.panels[item].uid ==panel.base.uid:
965                            self.parent.panels[item].onClearSlicer(event)
966                            self.parent._mgr.Update()
967                            break 
968                break
969   
970    def _return_engine_type(self):
971        """
972        return the current type of engine
973        """
974        return self._fit_engine
975     
976     
977    def _on_change_engine(self, engine='park'):
978        """
979        Allow to select the type of engine to perform fit
980       
981        :param engine: the key work of the engine
982       
983        """
984        ## saving fit engine name
985        self._fit_engine = engine
986        ## change menu item state
987        if engine=="park":
988            self.menu1.FindItemByPosition(0).Check(False)
989            self.menu1.FindItemByPosition(1).Check(True)
990        else:
991            self.menu1.FindItemByPosition(0).Check(True)
992            self.menu1.FindItemByPosition(1).Check(False)
993           
994        ## post a message to status bar
995        wx.PostEvent(self.parent, StatusEvent(status="Engine set to: %s" % self._fit_engine))
996   
997        ## Bind every open fit page with a newevent to know the current fitting engine
998        import fitpage
999        event= fitpage.FitterTypeEvent()
1000        event.type = self._fit_engine
1001        for key in self.page_finder.keys():
1002            wx.PostEvent(key, event)
1003       
1004    def _on_model_panel(self, evt):
1005        """
1006        react to model selection on any combo box or model menu.plot the model 
1007       
1008        :param evt: wx.combobox event
1009       
1010        """
1011        model = evt.model
1012        if model == None:
1013            return
1014        smearer = None
1015        qmin = None
1016        qmax = None
1017        if hasattr(evt, "qmin"):
1018            qmin = evt.qmin
1019        if hasattr(evt, "qmax"):
1020            qmax = evt.qmax
1021        if hasattr(evt, "smearer"):
1022            smearer = evt.smearer
1023        model.origin_name = model.name
1024        self.current_pg = self.fit_panel.get_current_page() 
1025        ## make sure nothing is done on self.sim_page
1026        ## example trying to call set_panel on self.sim_page
1027        if self.current_pg != self.sim_page :
1028            if self.page_finder[self.current_pg].get_model()== None:
1029               
1030                model.name = "M"+str(self.index_model)
1031                self.index_model += 1 
1032            else:
1033                model.name= self.page_finder[self.current_pg].get_model().name
1034           
1035            data = self.page_finder[self.current_pg].get_fit_data()
1036           
1037            # save the name containing the data name with the appropriate model
1038            self.page_finder[self.current_pg].set_model(model)
1039            qmin, qmax= self.current_pg.get_range()
1040            self.page_finder[self.current_pg].set_range(qmin=qmin, qmax=qmax)
1041           
1042            if self.sim_page!=None:
1043                self.sim_page.draw_page()
1044       
1045    def _on_model_menu(self, evt):
1046        """
1047        Plot a theory from a model selected from the menu
1048       
1049        :param evt: wx.menu event
1050       
1051        """
1052        model = evt.model
1053        Plugin.on_perspective(self,event=evt)
1054        # Create a model page. If a new page is created, the model
1055        # will be plotted automatically. If a page already exists,
1056        # the content will be updated and the plot refreshed
1057        self.fit_panel.add_model_page(model,topmenu=True)
1058
1059    def _update1D(self,x, output):
1060        """
1061        Update the output of plotting model 1D
1062        """
1063        wx.PostEvent(self.parent, StatusEvent(status="Plot \
1064        #updating ... ",type="update"))
1065        self.ready_fit()
1066        #self.calc_thread.ready(0.01)
1067   
1068    def _fill_default_model2D(self, theory, qmax,qstep, qmin=None):
1069        """
1070        fill Data2D with default value
1071       
1072        :param theory: Data2D to fill
1073       
1074        """
1075        from DataLoader.data_info import Detector, Source
1076       
1077        detector = Detector()
1078        theory.detector.append(detector)         
1079        theory.source= Source()
1080       
1081        ## Default values   
1082        theory.detector[0].distance= 8000   # mm       
1083        theory.source.wavelength= 6         # A     
1084        theory.detector[0].pixel_size.x= 5  # mm
1085        theory.detector[0].pixel_size.y= 5  # mm
1086       
1087        theory.detector[0].beam_center.x= qmax
1088        theory.detector[0].beam_center.y= qmax
1089   
1090        ## create x_bins and y_bins of the model 2D
1091        pixel_width_x = theory.detector[0].pixel_size.x
1092        pixel_width_y = theory.detector[0].pixel_size.y
1093        center_x      = theory.detector[0].beam_center.x/pixel_width_x
1094        center_y      = theory.detector[0].beam_center.y/pixel_width_y
1095
1096        # theory default: assume the beam center is located at the center of sqr detector
1097        xmax = qmax
1098        xmin = -qmax
1099        ymax = qmax
1100        ymin = -qmax
1101       
1102        x=  numpy.linspace(start= -1*qmax,
1103                               stop= qmax,
1104                               num= qstep,
1105                               endpoint=True ) 
1106        y = numpy.linspace(start= -1*qmax,
1107                               stop= qmax,
1108                               num= qstep,
1109                               endpoint=True )
1110         
1111        ## use data info instead
1112        new_x = numpy.tile(x, (len(y),1))
1113        new_y = numpy.tile(y, (len(x),1))
1114        new_y = new_y.swapaxes(0,1)
1115       
1116        # all data reuire now in 1d array
1117        qx_data = new_x.flatten()
1118        qy_data = new_y.flatten()
1119       
1120        q_data = numpy.sqrt(qx_data*qx_data+qy_data*qy_data)
1121        # set all True (standing for unmasked) as default
1122        mask    = numpy.ones(len(qx_data), dtype = bool)
1123       
1124        # calculate the range of qx and qy: this way, it is a little more independent
1125        x_size = xmax- xmin
1126        y_size = ymax -ymin
1127       
1128        # store x and y bin centers in q space
1129        x_bins  = x
1130        y_bins  = y
1131        # bin size: x- & y-directions
1132        xstep = x_size/len(x_bins-1)
1133        ystep = y_size/len(y_bins-1)
1134       
1135        #theory.data = numpy.zeros(len(mask))
1136        theory.err_data = numpy.ones(len(mask))
1137        theory.qx_data = qx_data
1138        theory.qy_data = qy_data 
1139        theory.q_data = q_data
1140        theory.mask = mask           
1141        theory.x_bins = x_bins 
1142        theory.y_bins = y_bins   
1143       
1144        # max and min taking account of the bin sizes
1145        theory.xmin= xmin
1146        theory.xmax= xmax
1147        theory.ymin= ymin
1148        theory.ymax= ymax
1149        theory.group_id = "Model"
1150        theory.id = "Model"
1151       
1152    def _get_plotting_info(self, data=None):
1153        """
1154        get plotting info from data if data !=None else use some default
1155        """
1156        my_info = PlotInfo()
1157        if data !=None:
1158            if hasattr(data,"info"):
1159                x_name, x_units = data.get_xaxis() 
1160                y_name, y_units = data.get_yaxis() 
1161               
1162                my_info._xunit = x_units
1163                my_info._xaxis = x_name
1164                my_info._yunit = y_units
1165                my_info._yaxis = y_name
1166               
1167            my_info.title= data.name
1168            if hasattr(data, "info"):
1169                my_info.info= data.info
1170            if hasattr(data, "group_id"):
1171                my_info.group_id= data.group_id
1172        return my_info
1173               
1174    def _complete1D(self, x,y, elapsed,index,model,data=None):
1175        """
1176        Complete plotting 1D data
1177        """ 
1178        try:
1179            new_plot = Theory1D(x=x, y=y)
1180            my_info = self._get_plotting_info( data)
1181            new_plot.name = model.name
1182            new_plot.id = my_info.id
1183            new_plot.group_id = my_info.group_id
1184           
1185            new_plot.xaxis( my_info._xaxis,  my_info._xunit)
1186            new_plot.yaxis( my_info._yaxis, my_info._yunit)
1187            if data!=None:
1188                if new_plot.id == data.id:
1189                    new_plot.id += "Model"
1190                new_plot.is_data =False 
1191           
1192            title= new_plot.name
1193            # x, y are only in range of index
1194            self.theory_data = new_plot
1195            #new_plot.perspective = self.get_perspective()
1196            # Pass the reset flag to let the plotting event handler
1197            # know that we are replacing the whole plot
1198            if title== None:
1199                title = "Analytical model 1D "
1200            if data ==None:
1201                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1202                             title=str(title), reset=True))
1203            else:
1204                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,title= str(title)))
1205            # Chisqr in fitpage
1206            current_pg=self.fit_panel.get_current_page()
1207            wx.PostEvent(current_pg,Chi2UpdateEvent(output=self._cal_chisqr(data=data,index=index)))
1208            msg = "Plot 1D  complete !"
1209            wx.PostEvent( self.parent, StatusEvent(status=msg , type="stop" ))
1210        except:
1211            msg= " Error occurred when drawing %s Model 1D: "%new_plot.name
1212            msg+= " %s"%sys.exc_value
1213            wx.PostEvent( self.parent, StatusEvent(status= msg, type="stop"))
1214   
1215    def _update2D(self, output,time=None):
1216        """
1217        Update the output of plotting model
1218        """
1219        wx.PostEvent(self.parent, StatusEvent(status="Plot \
1220        #updating ... ",type="update"))
1221        self.ready_fit()
1222        #self.calc_thread.ready(0.01)
1223   
1224    def _complete2D(self, image, data, model, elapsed, index, qmin,
1225                     qmax, qstep=DEFAULT_NPTS):
1226        """
1227        Complete get the result of modelthread and create model 2D
1228        that can be plot.
1229        """
1230        err_image = numpy.zeros(numpy.shape(image))
1231       
1232        theory= Data2D(image= image , err_image= err_image)
1233        theory.name= model.name
1234       
1235        if data ==None:
1236            self._fill_default_model2D(theory=theory, qmax=qmax, qstep=qstep,
1237                                        qmin= qmin)
1238       
1239        else:
1240            theory.id= data.id+"Model"
1241            theory.group_id= data.name+"Model"
1242            theory.x_bins= data.x_bins
1243            theory.y_bins= data.y_bins
1244            theory.detector= data.detector
1245            theory.source= data.source
1246            theory.is_data =False 
1247            theory.qx_data = data.qx_data
1248            theory.qy_data = data.qy_data
1249            theory.q_data = data.q_data
1250            theory.err_data = err_image#numpy.zeros(len(data.err_data))#data.err_data
1251            theory.mask = data.mask
1252            ## plot boundaries
1253            theory.ymin= data.ymin
1254            theory.ymax= data.ymax
1255            theory.xmin= data.xmin
1256            theory.xmax= data.xmax
1257           
1258        self.theory_data = theory
1259        ## plot
1260        wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
1261                         title="Analytical model 2D ", reset=True ))
1262        # Chisqr in fitpage
1263        current_pg = self.fit_panel.get_current_page()
1264        wx.PostEvent(current_pg,
1265            Chi2UpdateEvent(output=self._cal_chisqr(data=data,index=index)))
1266        msg = "Plot 2D complete !"
1267        wx.PostEvent( self.parent, StatusEvent(status=msg, type="stop" ))
1268     
1269    def _on_data_error(self, event):
1270        """
1271        receives and event from plotting plu-gins to store the data name and
1272        their errors of y coordinates for 1Data hide and show error
1273        """
1274        self.err_dy = event.err_dy
1275         
1276    def _draw_model2D(self,model,data=None, smearer= None,description=None, enable2D=False,
1277                      qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, qstep=DEFAULT_NPTS):
1278        """
1279        draw model in 2D
1280       
1281        :param model: instance of the model to draw
1282        :param description: the description of the model
1283        :param enable2D: when True allows to draw model 2D
1284        :param qmin: the minimum value to  draw model 2D
1285        :param qmax: the maximum value to draw model 2D
1286        :param qstep: the number of division of Qx and Qy of the model to draw
1287           
1288        """
1289        x=  numpy.linspace(start= -1*qmax,
1290                               stop= qmax,
1291                               num= qstep,
1292                               endpoint=True ) 
1293        y = numpy.linspace(start= -1*qmax,
1294                               stop= qmax,
1295                               num= qstep,
1296                               endpoint=True )
1297        ## use data info instead
1298        if data !=None:
1299            ## check if data2D to plot
1300            if hasattr(data, "x_bins"):
1301                enable2D = True
1302                x= data.x_bins
1303                y= data.y_bins
1304               
1305        if not enable2D:
1306            return None,None
1307        try:
1308            from model_thread import Calc2D
1309            ## If a thread is already started, stop it
1310            if self.calc_2D != None and self.calc_2D.isrunning():
1311                self.calc_2D.stop()
1312
1313            self.calc_2D = Calc2D(  x= x,
1314                                    y= y,
1315                                    model= model, 
1316                                    data = data,
1317                                    smearer = smearer,
1318                                    qmin= qmin,
1319                                    qmax= qmax,
1320                                    qstep= qstep,
1321                                    completefn= self._complete2D,
1322                                    updatefn= self._update2D )
1323            self.calc_2D.queue()
1324
1325        except:
1326            msg= " Error occurred when drawing %s Model 2D: "%model.name
1327            msg+= " %s"%sys.exc_value
1328            wx.PostEvent( self.parent, StatusEvent(status= msg ))
1329
1330    def _draw_model1D(self, model, data=None, smearer= None,
1331                qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, qstep= DEFAULT_NPTS,enable1D= True):
1332        """
1333        Draw model 1D from loaded data1D
1334       
1335        :param data: loaded data
1336        :param model: the model to plot
1337       
1338        """
1339        x=  numpy.linspace(start= qmin,
1340                           stop= qmax,
1341                           num= qstep,
1342                           endpoint=True
1343                           )
1344        if data!=None:
1345            ## check for data2D
1346            if hasattr(data,"x_bins"):
1347                return
1348            x = data.x
1349            if qmin == DEFAULT_QMIN :
1350                qmin = min(data.x)
1351            if qmax == DEFAULT_QMAX:
1352                qmax = max(data.x) 
1353           
1354       
1355        if not enable1D:
1356            return 
1357   
1358        try:
1359            from model_thread import Calc1D
1360            ## If a thread is already started, stop it
1361            if self.calc_1D!= None and self.calc_1D.isrunning():
1362                self.calc_1D.stop()
1363            self.calc_1D= Calc1D( x= x,
1364                                  data = data,
1365                                  model= model, 
1366                                  qmin = qmin,
1367                                  qmax = qmax,
1368                                  smearer = smearer,
1369                                  completefn = self._complete1D,
1370                                  updatefn = self._update1D  )
1371            self.calc_1D.queue()
1372
1373        except:
1374            msg= " Error occurred when drawing %s Model 1D: "%model.name
1375            msg+= " %s"%sys.exc_value
1376            wx.PostEvent( self.parent, StatusEvent(status= msg ))
1377
1378    def _cal_chisqr(self, data=None, index=None): 
1379        """
1380        Get handy Chisqr using the output from draw1D and 2D,
1381        instead of calling expansive CalcChisqr in guithread
1382        """
1383        # default chisqr
1384        chisqr = None
1385       
1386        # return None if data == None
1387        if data == None: return chisqr
1388       
1389        # Get data: data I, theory I, and data dI in order
1390        if data.__class__.__name__ =="Data2D":
1391            if index == None: index = numpy.ones(len(data.data),ntype=bool)
1392            index = index & (data.err_data !=0 )   # get rid of zero error points
1393            fn = data.data[index] 
1394            gn = self.theory_data.data[index]
1395            en = data.err_data[index]
1396        else:
1397            # 1 d theory from model_thread is only in the range of index
1398            if index == None: index = numpy.ones(len(data.y),ntype=bool)
1399            if data.dy== None or data.dy ==[]:
1400                dy = numpy.ones(len(data.y))
1401            else:
1402                ## Set consitently w/AbstractFitengine: But this should be corrected later.
1403                dy = data.dy
1404                dy[dy==0] = 1 
1405            fn = data.y[index] 
1406            gn = self.theory_data.y
1407            en = dy[index]
1408
1409        # residual
1410        res = (fn - gn)/en
1411        # get chisqr only w/finite
1412        chisqr = numpy.average(res[numpy.isfinite(res)]*res[numpy.isfinite(res)])
1413
1414        return chisqr
1415   
1416   
1417#def profile(fn, *args, **kw):
1418#    import cProfile, pstats, os
1419#    global call_result
1420#    def call():
1421#        global call_result
1422#        call_result = fn(*args, **kw)
1423#    cProfile.runctx('call()', dict(call=call), {}, 'profile.out')
1424#    stats = pstats.Stats('profile.out')
1425#    #stats.sort_stats('time')
1426#    stats.sort_stats('calls')
1427#    stats.print_stats()
1428#    os.unlink('profile.out')
1429#    return call_result
1430if __name__ == "__main__":
1431    i = Plugin()
1432   
1433   
1434   
1435   
Note: See TracBrowser for help on using the repository browser.