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

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 a0ac888 was 67e258c, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working pylint fitting

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