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

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 b70caa1 was 3658abed, checked in by Gervaise Alina <gervyh@…>, 14 years ago

make fitting plugin_inheriting from pluginbase

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