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

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

working loading data in fitting perspectives

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