source: sasview/sansview/perspectives/fitting/fitting.py @ 9ec4406

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

a bit generalized the plotdata

  • Property mode set to 100644
File size: 55.1 KB
Line 
1
2
3################################################################################
4#This software was developed by the University of Tennessee as part of the
5#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
6#project funded by the US National Science Foundation.
7#
8#See the license text in license.txt
9#
10#copyright 2009, University of Tennessee
11################################################################################
12
13
14import  re
15import sys
16import wx
17import logging
18import numpy
19import math
20import string
21import time
22import thread
23from copy import deepcopy
24
25import models
26import fitpage
27
28from DataLoader.loader import Loader
29
30from sans.guiframe.dataFitting import Data2D
31from sans.guiframe.dataFitting import Data1D
32from sans.guiframe.dataFitting import Theory1D
33
34from sans.guicomm.events import NewPlotEvent, StatusEvent 
35from sans.guicomm.events import EVT_SLICER_PANEL,ERR_DATA,EVT_REMOVE_DATA
36from sans.guicomm.events import EVT_SLICER_PARS_UPDATE
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, data= data,
522                                                    enable1D=enable1D, 
523                                                    smearer= smearer,
524                                                    qmin= qmin, qmax= qmax, qstep= qstep )
525        else:     
526            ## draw model 2D with no initial data
527             self._draw_model2D(model=model,
528                                      data = data,
529                                      enable2D= enable2D,
530                                      smearer= smearer,
531                                      qmin=qmin,
532                                      qmax=qmax,
533                                      qstep=qstep)
534           
535    def onFit(self):
536        """
537        perform fit
538        """
539        ##  count the number of fitproblem schedule to fit
540        fitproblem_count= 0
541        for value in self.page_finder.itervalues():
542            if value.get_scheduled()==1:
543                fitproblem_count += 1
544               
545        ## if simultaneous fit change automatically the engine to park
546        if fitproblem_count >1:
547            self._on_change_engine(engine='park')
548           
549        self.fitproblem_count = fitproblem_count 
550         
551        from sans.fit.Fitting import Fit
552        self.fitter= Fit(self._fit_engine)
553       
554        if self._fit_engine=="park":
555            engineType="Simultaneous Fit"
556        else:
557            engineType="Single Fit"
558           
559        fproblemId = 0
560        self.current_pg=None
561        for page, value in self.page_finder.iteritems():
562            try:
563                if value.get_scheduled()==1:
564                    #Get list of parameters name to fit
565                    pars = []
566                    templist = []
567                    templist = page.get_param_list()
568                    for element in templist:
569                        name = str(element[1])
570                        pars.append(name)
571                    #Set Engine  (model , data) related to the page on
572                    self._fit_helper( value=value,pars=pars,
573                                      id=fproblemId, title= engineType ) 
574                    fproblemId += 1 
575                    self.current_pg= page
576            except:
577                msg= "%s error: %s" % (engineType,sys.exc_value)
578                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
579                                                      type="stop"))
580                return 
581        ## If a thread is already started, stop it
582        #if self.calc_fit!= None and self.calc_fit.isrunning():
583        #    self.calc_fit.stop()
584         #Handler used for park engine displayed message
585        handler = ConsoleUpdate(parent=self.parent,improvement_delta=0.1)
586        ## perform single fit
587        if fitproblem_count == 1:
588            calc_fit=FitThread(parent =self.parent,
589                                    handler = handler,
590                                    fn= self.fitter,
591                                   cpage=self.current_pg,
592                                   pars= pars,
593                                   updatefn=handler.update_fit,
594                                   completefn= self._single_fit_completed)
595        else:
596            ## Perform more than 1 fit at the time
597            calc_fit=FitThread(parent=self.parent,
598                                handler=handler,
599                                    fn= self.fitter,
600                                   completefn= self._simul_fit_completed,
601                                  updatefn=handler.update_fit)
602       
603        calc_fit.queue()
604        self.ready_fit(calc_fit=calc_fit)
605     
606    def ready_fit(self, calc_fit):
607        """
608        Ready for another fit
609        """
610        if self.fitproblem_count != None and self.fitproblem_count > 1:
611            calc_fit.ready(2.5)
612           
613        else:
614            time.sleep(0.4)
615           
616    def remove_plot(self, page, theory=False):
617        """
618        remove model plot when a fit page is closed
619        """
620        fitproblem = self.page_finder[page]
621        data = fitproblem.get_fit_data()
622        model = fitproblem.get_model()
623        if model is not None:
624            name = model.name
625            new_plot = Theory1D(x=[], y=[], dy=None)
626            new_plot.name = name
627            new_plot.xaxis(data._xaxis, data._xunit)
628            new_plot.yaxis(data._yaxis, data._yunit)
629            new_plot.group_id = data.group_id
630            new_plot.id = data.id + name
631            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=data.name))
632        if theory:
633            new_plot_data = Data1D(x=[], y=[], dx=None, dy=None)
634            new_plot_data.name = data.name
635            new_plot_data.xaxis(data._xaxis, data._xunit)
636            new_plot_data.yaxis(data._yaxis, data._yunit)
637            new_plot_data.group_id = data.group_id
638            new_plot_data.id = data.id
639            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot_data,
640                                                    title=data.name))
641    def create_fittable_data2D(self, data):
642        """
643        check if the current data is a data 2d and add dy to that data
644       
645        :return: Data2D
646       
647        """
648        if data.__class__.__name__ != "Data2D":
649            raise ValueError, " create_fittable_data2D expects a Data2D"
650        ## Data2D case
651        new_data = deepcopy(data)
652        if not hasattr(data, "is_data"):
653            new_data.group_id += "data2D"
654            new_data.id +="data2D"
655            new_data.is_data = False
656            title = new_data.name
657            title += " Fit"
658            wx.PostEvent(self.parent, NewPlotEvent(plot=new_data,
659                                                    title=str(title)))
660        else:
661            new_data.is_data = True
662        return new_data
663       
664    def create_fittable_data1D(self, data):
665        """
666        check if the current data is a theory 1d and add dy to that data
667       
668        :return: Data1D
669       
670        """
671        class_name = data.__class__.__name__
672        if not class_name in ["Data1D", "Theory1D"]:
673            raise ValueError, "create_fittable_data1D expects Data1D"
674     
675        #get the appropriate dy
676        dy = deepcopy(data.dy)
677        if len(self.err_dy) > 0:
678            if data.name in  self.err_dy.iterkeys():
679                dy = self.err_dy[data.name]   
680        if data.__class__.__name__ == "Theory1D":
681            new_data = self.copy_data(data, dy)
682            new_data.group_id = str(new_data.group_id)+"data1D"
683            new_data.id = str(new_data.id)+"data1D"
684            new_data.is_data = False
685            title = new_data.name
686            title = 'Data created from Theory'
687            wx.PostEvent(self.parent, NewPlotEvent(plot=new_data,
688                                                    title=str(title),
689                                                   reset=True))
690        else:
691            new_data = self.copy_data(data, dy) 
692            new_data.id = data.id
693            new_data.is_data = True
694        return new_data
695           
696    def store_page(self, page, data):
697        """
698        Helper to save page reference into the plug-in
699       
700        :param page: page to store
701       
702        """
703        page.set_data(data) 
704        #create a fitproblem storing all link to data,model,page creation
705        if not page in self.page_finder.keys():
706            self.page_finder[page] = FitProblem()
707        self.page_finder[page].add_fit_data(data)
708       
709    def add_fit_page(self, data):
710        """
711        given a data, ask to the fitting panel to create a new fitting page,
712        get this page and store it into the page_finder of this plug-in
713        """
714        try:
715            page = self.fit_panel.add_fit_page(data)
716           
717            # add data associated to the page created
718            if page != None: 
719                self.store_page(page=page, data=data)
720                wx.PostEvent(self.parent, StatusEvent(status="Page Created",
721                                               info="info"))
722            else:
723                msg = "Page was already Created"
724                wx.PostEvent(self.parent, StatusEvent(status=msg, info="warning"))
725        except:
726            msg = "Creating Fit page: %s"%sys.exc_value
727            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
728       
729    def _onEVT_SLICER_PANEL(self, event):
730        """
731        receive and event telling to update a panel with a name starting with
732        event.panel_name. this method update slicer panel for a given interactor.
733       
734        :param event: contains type of slicer , paramaters for updating the panel
735            and panel_name to find the slicer 's panel concerned.
736        """
737        for item in self.parent.panels:
738            if self.parent.panels[item].window_caption.startswith(event.panel_name):
739                self.parent.panels[item].set_slicer(event.type, event.params)
740               
741        self.parent._mgr.Update()
742   
743    def _closed_fitpage(self, event):   
744        """
745        request fitpanel to close a given page when its unique data is removed
746        from the plot. close fitpage only when the a loaded data is removed
747        """   
748        if event is None or event.data is None:
749            return
750       
751        if hasattr(event.data,"is_data"):
752            if not event.data.is_data or event.data.__class__.__name__=="Data1D":
753                self.fit_panel.close_page_with_data(event.data) 
754       
755    def _add_page_onmenu(self, name,fitproblem=None):
756        """
757        Add name of a closed page of fitpanel in a menu
758        """
759        list = self.menu1.GetMenuItems()
760        for item in list:
761            if name == item.GetItemLabel():
762                self.closed_page_dict[name][1] = fitproblem
763               
764        if not name in self.closed_page_dict.keys():   
765            # Post paramters
766            event_id = wx.NewId()
767            self.menu1.Append(event_id, name, "Show %s fit panel" % name)
768            self.closed_page_dict[name]= [event_id, fitproblem]
769            wx.EVT_MENU(self.parent,event_id,  self._open_closed_page)
770       
771    def _open_closed_page(self, event):   
772        """
773        reopen a closed page
774        """
775        for name, value in self.closed_page_dict.iteritems():
776            if event.GetId() in value:
777                id,fitproblem = value
778                if name !="Model":
779                    data= fitproblem.get_fit_data()
780                    page = self.fit_panel.add_fit_page(data= data,reset=True)
781                    if fitproblem != None:
782                        self.page_finder[page]=fitproblem
783                        if self.sim_page != None:
784                            self.sim_page.draw_page()
785                           
786                else:
787                    model = fitproblem
788                    self.fit_panel.add_model_page(model=model, topmenu=True,
789                                                  reset= True)
790                    break
791   
792    def _reset_schedule_problem(self, value=0):
793        """
794        unschedule or schedule all fitproblem to be fit
795        """
796        for page, fitproblem in self.page_finder.iteritems():
797            fitproblem.schedule_tofit(value)
798           
799    def _fit_helper(self,pars,value, id, title="Single Fit " ):
800        """
801        helper for fitting
802        """
803        metadata = value.get_fit_data()
804        model = value.get_model()
805        smearer = value.get_smearer()
806        qmin , qmax = value.get_range()
807        self.fit_id =id
808        #Create list of parameters for fitting used
809        templist=[]
810       
811        try:
812            #Extra list of parameters and their constraints
813            listOfConstraint= []
814           
815            param = value.get_model_param()
816            if len(param)>0:
817                for item in param:
818                    ## check if constraint
819                    if item[0] !=None and item[1] != None:
820                        listOfConstraint.append((item[0],item[1]))
821                   
822            #Do the single fit
823            self.fitter.set_model(model, self.fit_id,
824                                   pars,constraints = listOfConstraint)
825           
826            self.fitter.set_data(data=metadata,Uid=self.fit_id,
827                                 smearer=smearer,qmin= qmin,qmax=qmax )
828           
829            self.fitter.select_problem_for_fit(Uid= self.fit_id,
830                                               value= value.get_scheduled())
831            value.clear_model_param()
832        except:
833            msg= title +" error: %s" % sys.exc_value
834            wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop"))
835            return
836       
837    def _onSelect(self,event):
838        """
839        when Select data to fit a new page is created .Its reference is
840        added to self.page_finder
841        """
842        self.panel = event.GetEventObject()
843        Plugin.on_perspective(self,event=event)
844        for plottable in self.panel.graph.plottables:
845            if plottable.__class__.__name__ in ["Data1D", "Theory1D"]:
846                if plottable.name == self.panel.graph.selected_plottable:
847                    data = self.create_fittable_data1D(data=plottable)
848                    self.add_fit_page(data=data)
849                    return
850            else:
851                data = self.create_fittable_data2D(data=plottable)
852                self.add_fit_page(data=data)
853           
854    def _single_fit_completed(self,result,pars,cpage, elapsed=None):
855        """
856        Display fit result on one page of the notebook.
857       
858        :param result: result of fit
859        :param pars: list of names of parameters fitted
860        :param current_pg: the page where information will be displayed
861        :param qmin: the minimum value of x to replot the model
862        :param qmax: the maximum value of x to replot model
863         
864        """     
865        try:
866            if result ==None:
867                msg= "Simple Fitting Stop !!!"
868                wx.PostEvent(self.parent, StatusEvent(status=msg,info="warning",
869                                                      type="stop"))
870                return
871            if not numpy.isfinite(result.fitness) or numpy.any(result.pvec ==None )or not numpy.all(numpy.isfinite(result.pvec) ):
872                msg= "Single Fitting did not converge!!!"
873                wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
874                return
875            for page, value in self.page_finder.iteritems():
876                if page==cpage :
877                    model= value.get_model()
878                    break
879            param_name = []
880            i = 0
881            for name in pars:
882                param_name.append(name)
883
884            cpage.onsetValues(result.fitness,param_name, result.pvec,result.stderr)
885           
886        except:
887            msg= "Single Fit completed but Following error occurred:%s"% sys.exc_value
888            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
889                                                  type="stop"))
890            return
891       
892    def _simul_fit_completed(self,result,pars=None,cpage=None, elapsed=None):
893        """
894        Parameter estimation completed,
895        display the results to the user
896       
897        :param alpha: estimated best alpha
898        :param elapsed: computation time
899       
900        """
901        ## fit more than 1 model at the same time
902        try:
903            msg = "" 
904            if result ==None:
905                msg= "Complex Fitting Stop !!!"
906                wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
907                return
908            if not numpy.isfinite(result.fitness) or numpy.any(result.pvec ==None )or not numpy.all(numpy.isfinite(result.pvec) ):
909                msg= "Single Fitting did not converge!!!"
910                wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
911                return
912             
913            for page, value in self.page_finder.iteritems():   
914                if value.get_scheduled()==1:
915                    model = value.get_model()
916                    data =  value.get_fit_data()
917                    small_param_name = []
918                    small_out = []
919                    small_cov = []
920                    i = 0
921                    #Separate result in to data corresponding to each page
922                    for p in result.parameters:
923                        model_name,param_name = self.split_string(p.name) 
924                        if model.name == model_name:
925                            p_name= model.name+"."+param_name
926                            if p.name == p_name:     
927                                if p.value != None and numpy.isfinite(p.value):
928                                    small_out.append(p.value )
929                                    small_param_name.append(param_name)
930                                    small_cov.append(p.stderr)
931
932                    # Display result on each page
933                    page.onsetValues(result.fitness, small_param_name,small_out,small_cov)
934        except:
935             msg= "Simultaneous Fit completed"
936             msg +=" but Following error occurred:%s"%sys.exc_value
937             wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
938             return 
939             
940    def _on_show_panel(self, event):
941        """
942        """
943        #print "_on_show_panel: fitting"
944        pass
945       
946    def _onset_engine_park(self,event):
947        """
948        set engine to park
949        """
950        Plugin.on_perspective(self,event=event)
951        self._on_change_engine('park')
952       
953    def _onset_engine_scipy(self,event):
954        """
955        set engine to scipy
956        """
957        self._on_change_engine('scipy')
958       
959    def _on_slicer_event(self, event):
960        """
961        Receive a panel as event and send it to guiframe
962       
963        :param event: event containing a panel
964       
965        """
966        if event.panel is not None:
967            new_panel = event.panel
968            self.slicer_panels.append(event.panel)
969            # Set group ID if available
970            event_id = self.parent.popup_panel(new_panel)
971            #self.menu3.Append(event_id, new_panel.window_caption,
972            #                 "Show %s plot panel" % new_panel.window_caption)
973            # Set UID to allow us to reference the panel later
974         
975            new_panel.uid = event_id
976            self.mypanels.append(new_panel) 
977       
978    def _onclearslicer(self, event):
979        """
980        Clear the boxslicer when close the panel associate with this slicer
981        """
982        name =event.GetPane().caption
983   
984        for panel in self.slicer_panels:
985            if panel.window_caption==name:
986               
987                for item in self.parent.panels:
988                    if hasattr(self.parent.panels[item],"uid"):
989                        if self.parent.panels[item].uid ==panel.base.uid:
990                            self.parent.panels[item].onClearSlicer(event)
991                            self.parent._mgr.Update()
992                            break 
993                break
994   
995    def _return_engine_type(self):
996        """
997        return the current type of engine
998        """
999        return self._fit_engine
1000     
1001     
1002    def _on_change_engine(self, engine='park'):
1003        """
1004        Allow to select the type of engine to perform fit
1005       
1006        :param engine: the key work of the engine
1007       
1008        """
1009        ## saving fit engine name
1010        self._fit_engine = engine
1011        ## change menu item state
1012        if engine=="park":
1013            self.menu1.FindItemByPosition(0).Check(False)
1014            self.menu1.FindItemByPosition(1).Check(True)
1015        else:
1016            self.menu1.FindItemByPosition(0).Check(True)
1017            self.menu1.FindItemByPosition(1).Check(False)
1018           
1019        ## post a message to status bar
1020        wx.PostEvent(self.parent, StatusEvent(status="Engine set to: %s" % self._fit_engine))
1021   
1022        ## Bind every open fit page with a newevent to know the current fitting engine
1023        import fitpage
1024        event= fitpage.FitterTypeEvent()
1025        event.type = self._fit_engine
1026        for key in self.page_finder.keys():
1027            wx.PostEvent(key, event)
1028       
1029    def _on_model_panel(self, evt):
1030        """
1031        react to model selection on any combo box or model menu.plot the model 
1032       
1033        :param evt: wx.combobox event
1034       
1035        """
1036        model = evt.model
1037        if model == None:
1038            return
1039        smearer = None
1040        qmin = None
1041        qmax = None
1042        if hasattr(evt, "qmin"):
1043            qmin = evt.qmin
1044        if hasattr(evt, "qmax"):
1045            qmax = evt.qmax
1046        if hasattr(evt, "smearer"):
1047            smearer = evt.smearer
1048        model.origin_name = model.name
1049        self.current_pg = self.fit_panel.get_current_page() 
1050        ## make sure nothing is done on self.sim_page
1051        ## example trying to call set_panel on self.sim_page
1052        if self.current_pg != self.sim_page :
1053            if self.page_finder[self.current_pg].get_model()== None:
1054               
1055                model.name = "M"+str(self.index_model)
1056                self.index_model += 1 
1057            else:
1058                model.name= self.page_finder[self.current_pg].get_model().name
1059           
1060            data = self.page_finder[self.current_pg].get_fit_data()
1061           
1062            # save the name containing the data name with the appropriate model
1063            self.page_finder[self.current_pg].set_model(model)
1064            qmin, qmax= self.current_pg.get_range()
1065            self.page_finder[self.current_pg].set_range(qmin=qmin, qmax=qmax)
1066           
1067            if self.sim_page!=None:
1068                self.sim_page.draw_page()
1069       
1070    def _on_model_menu(self, evt):
1071        """
1072        Plot a theory from a model selected from the menu
1073       
1074        :param evt: wx.menu event
1075       
1076        """
1077        model = evt.model
1078        Plugin.on_perspective(self,event=evt)
1079        # Create a model page. If a new page is created, the model
1080        # will be plotted automatically. If a page already exists,
1081        # the content will be updated and the plot refreshed
1082        self.fit_panel.add_model_page(model,topmenu=True)
1083
1084    def _update1D(self,x, output):
1085        """
1086        Update the output of plotting model 1D
1087        """
1088        wx.PostEvent(self.parent, StatusEvent(status="Plot \
1089        #updating ... ",type="update"))
1090        self.ready_fit()
1091        #self.calc_thread.ready(0.01)
1092   
1093    def _fill_default_model2D(self, theory, qmax,qstep, qmin=None):
1094        """
1095        fill Data2D with default value
1096       
1097        :param theory: Data2D to fill
1098       
1099        """
1100        from DataLoader.data_info import Detector, Source
1101       
1102        detector = Detector()
1103        theory.detector.append(detector)         
1104        theory.source= Source()
1105       
1106        ## Default values   
1107        theory.detector[0].distance= 8000   # mm       
1108        theory.source.wavelength= 6         # A     
1109        theory.detector[0].pixel_size.x= 5  # mm
1110        theory.detector[0].pixel_size.y= 5  # mm
1111       
1112        theory.detector[0].beam_center.x= qmax
1113        theory.detector[0].beam_center.y= qmax
1114   
1115        ## create x_bins and y_bins of the model 2D
1116        pixel_width_x = theory.detector[0].pixel_size.x
1117        pixel_width_y = theory.detector[0].pixel_size.y
1118        center_x      = theory.detector[0].beam_center.x/pixel_width_x
1119        center_y      = theory.detector[0].beam_center.y/pixel_width_y
1120
1121        # theory default: assume the beam center is located at the center of sqr detector
1122        xmax = qmax
1123        xmin = -qmax
1124        ymax = qmax
1125        ymin = -qmax
1126       
1127        x=  numpy.linspace(start= -1*qmax,
1128                               stop= qmax,
1129                               num= qstep,
1130                               endpoint=True ) 
1131        y = numpy.linspace(start= -1*qmax,
1132                               stop= qmax,
1133                               num= qstep,
1134                               endpoint=True )
1135         
1136        ## use data info instead
1137        new_x = numpy.tile(x, (len(y),1))
1138        new_y = numpy.tile(y, (len(x),1))
1139        new_y = new_y.swapaxes(0,1)
1140       
1141        # all data reuire now in 1d array
1142        qx_data = new_x.flatten()
1143        qy_data = new_y.flatten()
1144       
1145        q_data = numpy.sqrt(qx_data*qx_data+qy_data*qy_data)
1146        # set all True (standing for unmasked) as default
1147        mask    = numpy.ones(len(qx_data), dtype = bool)
1148       
1149        # calculate the range of qx and qy: this way, it is a little more independent
1150        x_size = xmax- xmin
1151        y_size = ymax -ymin
1152       
1153        # store x and y bin centers in q space
1154        x_bins  = x
1155        y_bins  = y
1156        # bin size: x- & y-directions
1157        xstep = x_size/len(x_bins-1)
1158        ystep = y_size/len(y_bins-1)
1159       
1160        #theory.data = numpy.zeros(len(mask))
1161        theory.err_data = numpy.ones(len(mask))
1162        theory.qx_data = qx_data
1163        theory.qy_data = qy_data 
1164        theory.q_data = q_data
1165        theory.mask = mask           
1166        theory.x_bins = x_bins 
1167        theory.y_bins = y_bins   
1168       
1169        # max and min taking account of the bin sizes
1170        theory.xmin= xmin
1171        theory.xmax= xmax
1172        theory.ymin= ymin
1173        theory.ymax= ymax
1174        theory.group_id = "Model"
1175        theory.id = "Model"
1176       
1177    def _get_plotting_info(self, data=None):
1178        """
1179        get plotting info from data if data !=None else use some default
1180        """
1181        my_info = PlotInfo()
1182        if data !=None:
1183            if hasattr(data,"info"):
1184                x_name, x_units = data.get_xaxis() 
1185                y_name, y_units = data.get_yaxis() 
1186               
1187                my_info._xunit = x_units
1188                my_info._xaxis = x_name
1189                my_info._yunit = y_units
1190                my_info._yaxis = y_name
1191               
1192            my_info.title= data.name
1193            if hasattr(data, "info"):
1194                my_info.info= data.info
1195            if hasattr(data, "group_id"):
1196                my_info.group_id= data.group_id
1197        return my_info
1198               
1199    def _complete1D(self, x,y, elapsed,index,model,data=None):
1200        """
1201        Complete plotting 1D data
1202        """ 
1203        try:
1204            new_plot = Theory1D(x=x, y=y)
1205            my_info = self._get_plotting_info( data)
1206            new_plot.name = model.name
1207            new_plot.id = my_info.id
1208            new_plot.group_id = my_info.group_id
1209           
1210            new_plot.xaxis( my_info._xaxis,  my_info._xunit)
1211            new_plot.yaxis( my_info._yaxis, my_info._yunit)
1212            if data!=None:
1213                if new_plot.id == data.id:
1214                    new_plot.id += "Model"
1215                new_plot.is_data =False 
1216           
1217            title= new_plot.name
1218            # x, y are only in range of index
1219            self.theory_data = new_plot
1220            #new_plot.perspective = self.get_perspective()
1221            # Pass the reset flag to let the plotting event handler
1222            # know that we are replacing the whole plot
1223            if title== None:
1224                title = "Analytical model 1D "
1225            if data ==None:
1226                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1227                             title=str(title), reset=True))
1228            else:
1229                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,title= str(title)))
1230            # Chisqr in fitpage
1231            current_pg=self.fit_panel.get_current_page()
1232            wx.PostEvent(current_pg,Chi2UpdateEvent(output=self._cal_chisqr(data=data,index=index)))
1233            msg = "Plot 1D  complete !"
1234            wx.PostEvent( self.parent, StatusEvent(status=msg , type="stop" ))
1235        except:
1236            msg= " Error occurred when drawing %s Model 1D: "%new_plot.name
1237            msg+= " %s"%sys.exc_value
1238            wx.PostEvent( self.parent, StatusEvent(status= msg, type="stop"))
1239   
1240    def _update2D(self, output,time=None):
1241        """
1242        Update the output of plotting model
1243        """
1244        wx.PostEvent(self.parent, StatusEvent(status="Plot \
1245        #updating ... ",type="update"))
1246        self.ready_fit()
1247        #self.calc_thread.ready(0.01)
1248   
1249    def _complete2D(self, image, data, model, elapsed, index, qmin,
1250                     qmax, qstep=DEFAULT_NPTS):
1251        """
1252        Complete get the result of modelthread and create model 2D
1253        that can be plot.
1254        """
1255        err_image = numpy.zeros(numpy.shape(image))
1256       
1257        theory= Data2D(image= image , err_image= err_image)
1258        theory.name= model.name
1259       
1260        if data ==None:
1261            self._fill_default_model2D(theory=theory, qmax=qmax, qstep=qstep,
1262                                        qmin= qmin)
1263       
1264        else:
1265            theory.id= data.id+"Model"
1266            theory.group_id= data.name+"Model"
1267            theory.x_bins= data.x_bins
1268            theory.y_bins= data.y_bins
1269            theory.detector= data.detector
1270            theory.source= data.source
1271            theory.is_data =False 
1272            theory.qx_data = data.qx_data
1273            theory.qy_data = data.qy_data
1274            theory.q_data = data.q_data
1275            theory.err_data = err_image#numpy.zeros(len(data.err_data))#data.err_data
1276            theory.mask = data.mask
1277            ## plot boundaries
1278            theory.ymin= data.ymin
1279            theory.ymax= data.ymax
1280            theory.xmin= data.xmin
1281            theory.xmax= data.xmax
1282           
1283        self.theory_data = theory
1284        ## plot
1285        wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
1286                         title="Analytical model 2D ", reset=True ))
1287        # Chisqr in fitpage
1288        current_pg = self.fit_panel.get_current_page()
1289        wx.PostEvent(current_pg,
1290            Chi2UpdateEvent(output=self._cal_chisqr(data=data,index=index)))
1291        msg = "Plot 2D complete !"
1292        wx.PostEvent( self.parent, StatusEvent(status=msg, type="stop" ))
1293     
1294    def _on_data_error(self, event):
1295        """
1296        receives and event from plotting plu-gins to store the data name and
1297        their errors of y coordinates for 1Data hide and show error
1298        """
1299        self.err_dy = event.err_dy
1300         
1301    def _draw_model2D(self,model,data=None, smearer= None,description=None, enable2D=False,
1302                      qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, qstep=DEFAULT_NPTS):
1303        """
1304        draw model in 2D
1305       
1306        :param model: instance of the model to draw
1307        :param description: the description of the model
1308        :param enable2D: when True allows to draw model 2D
1309        :param qmin: the minimum value to  draw model 2D
1310        :param qmax: the maximum value to draw model 2D
1311        :param qstep: the number of division of Qx and Qy of the model to draw
1312           
1313        """
1314        x=  numpy.linspace(start= -1*qmax,
1315                               stop= qmax,
1316                               num= qstep,
1317                               endpoint=True ) 
1318        y = numpy.linspace(start= -1*qmax,
1319                               stop= qmax,
1320                               num= qstep,
1321                               endpoint=True )
1322        ## use data info instead
1323        if data !=None:
1324            ## check if data2D to plot
1325            if hasattr(data, "x_bins"):
1326                enable2D = True
1327                x= data.x_bins
1328                y= data.y_bins
1329               
1330        if not enable2D:
1331            return None,None
1332        try:
1333            from model_thread import Calc2D
1334            ## If a thread is already started, stop it
1335            if self.calc_2D != None and self.calc_2D.isrunning():
1336                self.calc_2D.stop()
1337
1338            self.calc_2D = Calc2D(  x= x,
1339                                    y= y,
1340                                    model= model, 
1341                                    data = data,
1342                                    smearer = smearer,
1343                                    qmin= qmin,
1344                                    qmax= qmax,
1345                                    qstep= qstep,
1346                                    completefn= self._complete2D,
1347                                    updatefn= self._update2D )
1348            self.calc_2D.queue()
1349
1350        except:
1351            msg= " Error occurred when drawing %s Model 2D: "%model.name
1352            msg+= " %s"%sys.exc_value
1353            wx.PostEvent( self.parent, StatusEvent(status= msg ))
1354
1355    def _draw_model1D(self, model, data=None, smearer= None,
1356                qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, qstep= DEFAULT_NPTS,enable1D= True):
1357        """
1358        Draw model 1D from loaded data1D
1359       
1360        :param data: loaded data
1361        :param model: the model to plot
1362       
1363        """
1364        x=  numpy.linspace(start= qmin,
1365                           stop= qmax,
1366                           num= qstep,
1367                           endpoint=True
1368                           )
1369        if data!=None:
1370            ## check for data2D
1371            if hasattr(data,"x_bins"):
1372                return
1373            x = data.x
1374            if qmin == DEFAULT_QMIN :
1375                qmin = min(data.x)
1376            if qmax == DEFAULT_QMAX:
1377                qmax = max(data.x) 
1378           
1379       
1380        if not enable1D:
1381            return 
1382   
1383        try:
1384            from model_thread import Calc1D
1385            ## If a thread is already started, stop it
1386            if self.calc_1D!= None and self.calc_1D.isrunning():
1387                self.calc_1D.stop()
1388            self.calc_1D= Calc1D( x= x,
1389                                  data = data,
1390                                  model= model, 
1391                                  qmin = qmin,
1392                                  qmax = qmax,
1393                                  smearer = smearer,
1394                                  completefn = self._complete1D,
1395                                  updatefn = self._update1D  )
1396            self.calc_1D.queue()
1397
1398        except:
1399            msg= " Error occurred when drawing %s Model 1D: "%model.name
1400            msg+= " %s"%sys.exc_value
1401            wx.PostEvent( self.parent, StatusEvent(status= msg ))
1402
1403    def _cal_chisqr(self, data=None, index=None): 
1404        """
1405        Get handy Chisqr using the output from draw1D and 2D,
1406        instead of calling expansive CalcChisqr in guithread
1407        """
1408        # default chisqr
1409        chisqr = None
1410       
1411        # return None if data == None
1412        if data == None: return chisqr
1413       
1414        # Get data: data I, theory I, and data dI in order
1415        if data.__class__.__name__ =="Data2D":
1416            if index == None: index = numpy.ones(len(data.data),ntype=bool)
1417            index = index & (data.err_data !=0 )   # get rid of zero error points
1418            fn = data.data[index] 
1419            gn = self.theory_data.data[index]
1420            en = data.err_data[index]
1421        else:
1422            # 1 d theory from model_thread is only in the range of index
1423            if index == None: index = numpy.ones(len(data.y),ntype=bool)
1424            if data.dy== None or data.dy ==[]:
1425                dy = numpy.ones(len(data.y))
1426            else:
1427                ## Set consitently w/AbstractFitengine: But this should be corrected later.
1428                dy = data.dy
1429                dy[dy==0] = 1 
1430            fn = data.y[index] 
1431            gn = self.theory_data.y
1432            en = dy[index]
1433
1434        # residual
1435        res = (fn - gn)/en
1436        # get chisqr only w/finite
1437        chisqr = numpy.average(res[numpy.isfinite(res)]*res[numpy.isfinite(res)])
1438
1439        return chisqr
1440   
1441   
1442#def profile(fn, *args, **kw):
1443#    import cProfile, pstats, os
1444#    global call_result
1445#    def call():
1446#        global call_result
1447#        call_result = fn(*args, **kw)
1448#    cProfile.runctx('call()', dict(call=call), {}, 'profile.out')
1449#    stats = pstats.Stats('profile.out')
1450#    #stats.sort_stats('time')
1451#    stats.sort_stats('calls')
1452#    stats.print_stats()
1453#    os.unlink('profile.out')
1454#    return call_result
1455if __name__ == "__main__":
1456    i = Plugin()
1457   
1458   
1459   
1460   
Note: See TracBrowser for help on using the repository browser.