source: sasview/sansview/perspectives/fitting/fitting.py @ 73b3ae2

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 73b3ae2 was 3cd5806, checked in by Gervaise Alina <gervyh@…>, 14 years ago

bindind save button with guiframe toolbar

  • 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._extensions = '.fitv'
115        self.temp_state = []
116        self.state_index = 0
117        self.sfile_ext = None
118        # Log startup
119        logging.info("Fitting plug-in started") 
120       
121    def populate_menu(self, owner):
122        """
123        Create a menu for the Fitting plug-in
124       
125        :param id: id to create a menu
126        :param owner: owner of menu
127       
128        :return: list of information to populate the main menu
129       
130        """
131        #Menu for fitting
132        self.menu1 = wx.Menu()
133           #menu for model
134        menu2 = wx.Menu()
135        self.menu_mng.populate_menu(menu2, owner)
136        id2 = wx.NewId()
137        owner.Bind(models.EVT_MODEL,self._on_model_menu)
138        #Set park engine
139        id3 = wx.NewId()
140        scipy_help= "Scipy Engine: Perform Simple fit. More in Help window...."
141        self.menu1.AppendCheckItem(id3, "Simple Fit  [Scipy]",scipy_help) 
142        wx.EVT_MENU(owner, id3,  self._onset_engine_scipy)
143       
144        id3 = wx.NewId()
145        park_help = "Park Engine: Perform Complex fit. More in Help window...."
146        self.menu1.AppendCheckItem(id3, "Complex Fit  [Park]",park_help) 
147        wx.EVT_MENU(owner, id3,  self._onset_engine_park)
148       
149        self.menu1.FindItemByPosition(0).Check(True)
150        self.menu1.FindItemByPosition(1).Check(False)
151           
152        self.menu1.AppendSeparator()
153        id1 = wx.NewId()
154        simul_help = "Allow to edit fit engine with multiple model and data"
155        self.menu1.Append(id1, '&Simultaneous Page',simul_help)
156        wx.EVT_MENU(owner, id1, self.on_add_sim_page)
157       
158        self.fit_panel.set_owner(owner)
159        self.fit_panel.set_model_list(self.menu_mng.get_model_list())
160   
161        #create  menubar items
162        return [(self.menu1, "Fitting")]
163               
164    def on_add_sim_page(self, event):
165        """
166        Create a page to access simultaneous fit option
167        """
168        if self.sim_page != None:
169            msg= "Simultaneous Fit page already opened"
170            wx.PostEvent(self.parent, StatusEvent(status= msg))
171            return 
172       
173        self.sim_page= self.fit_panel.add_sim_page()
174       
175    def help(self, evt):
176        """
177        Show a general help dialog.
178        """
179        from help_panel import  HelpWindow
180        frame = HelpWindow(None, -1, 'HelpWindow')   
181        frame.Show(True)
182       
183    def get_context_menu(self, graph=None):
184        """
185        Get the context menu items available for P(r).them allow fitting option
186        for Data2D and Data1D only.
187       
188        :param graph: the Graph object to which we attach the context menu
189       
190        :return: a list of menu items with call-back function
191       
192        :note: if Data1D was generated from Theory1D 
193                the fitting option is not allowed
194               
195        """
196        self.graph = graph
197        fit_option = "Select data for fitting"
198        fit_hint =  "Dialog with fitting parameters "
199       
200        for item in graph.plottables:
201            if item.__class__.__name__ is "Data2D":
202               
203                if hasattr(item,"is_data"):
204                    if item.is_data:
205                        return [[fit_option, fit_hint, self._onSelect]]
206                    else:
207                        return [] 
208                return [[fit_option, fit_hint, self._onSelect]]
209            else:
210                if item.name == graph.selected_plottable :
211                    if item.name in ["$I_{obs}(q)$","$I_{fit}(q)$",
212                                     "$P_{fit}(r)$"]:
213                        return [] 
214                    if hasattr(item, "group_id"):
215                        # if is_data is true , this in an actual data loaded
216                        #else it is a data created from a theory model
217                        if hasattr(item,"is_data"):
218                            if item.is_data:
219                                return [[fit_option, fit_hint,
220                                          self._onSelect]]
221                            else:
222                                return [] 
223                        else:
224                           return [[fit_option, fit_hint, self._onSelect]]
225        return []   
226
227
228    def get_panels(self, parent):
229        """
230        Create and return a list of panel objects
231        """
232        self.parent = parent
233        self.parent.Bind(EVT_FITSTATE_UPDATE, self.on_set_state_helper)
234        # Creation of the fit panel
235        self.fit_panel = FitPanel(self.parent, -1)
236        #Set the manager for the main panel
237        self.fit_panel.set_manager(self)
238        # List of windows used for the perspective
239        self.perspective = []
240        self.perspective.append(self.fit_panel.window_name)
241        # take care of saving  data, model and page associated with each other
242        self.page_finder = {}
243        #index number to create random model name
244        self.index_model = 0
245        self.index_theory= 0
246        self.parent.Bind(EVT_SLICER_PANEL, self._on_slicer_event)
247        self.parent.Bind(ERR_DATA, self._on_data_error)
248        self.parent.Bind(EVT_REMOVE_DATA, self._closed_fitpage)
249        self.parent.Bind(EVT_SLICER_PARS_UPDATE, self._onEVT_SLICER_PANEL)
250        self.parent._mgr.Bind(wx.aui.EVT_AUI_PANE_CLOSE,self._onclearslicer)   
251        #Create reader when fitting panel are created
252        self.state_reader = Reader(self.set_state)   
253       
254        #append that reader to list of available reader
255        loader = Loader()
256        loader.associate_file_reader(".fitv", self.state_reader)
257        loader.associate_file_reader(".svs", self.state_reader)
258        #Send the fitting panel to guiframe
259        self.mypanels.append(self.fit_panel) 
260     
261        return self.mypanels
262   
263    def set_default_perspective(self):
264        """
265        Call back method that True to notify the parent that the current plug-in
266        can be set as default  perspective.
267        when returning False, the plug-in is not candidate for an automatic
268        default perspective setting
269        """
270        return True
271   
272    def set_data(self, data_list):
273        """
274        receive a list of data to fit
275        """
276        selected_data_list = []
277        if len(data_list) > MAX_NBR_DATA :
278            from fitting_widgets import DataDialog
279            dlg = DataDialog(data_list=data_list, nb_data=MAX_NBR_DATA)
280            if dlg.ShowModal() == wx.ID_OK:
281                selected_data_list = dlg.get_data()
282        else:
283            selected_data_list = data_list
284        for data in selected_data_list:
285            self.add_fit_page(data=data)
286            wx.PostEvent(self.parent, NewPlotEvent(plot=data, 
287                                                   title=str(data.title)))
288   
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        self._on_change_engine('park')
954       
955    def _onset_engine_scipy(self,event):
956        """
957        set engine to scipy
958        """
959        self._on_change_engine('scipy')
960       
961    def _on_slicer_event(self, event):
962        """
963        Receive a panel as event and send it to guiframe
964       
965        :param event: event containing a panel
966       
967        """
968        if event.panel is not None:
969            new_panel = event.panel
970            self.slicer_panels.append(event.panel)
971            # Set group ID if available
972            event_id = self.parent.popup_panel(new_panel)
973            #self.menu3.Append(event_id, new_panel.window_caption,
974            #                 "Show %s plot panel" % new_panel.window_caption)
975            # Set id to allow us to reference the panel later
976         
977            new_panel.uid = event_id
978            self.mypanels.append(new_panel) 
979       
980    def _onclearslicer(self, event):
981        """
982        Clear the boxslicer when close the panel associate with this slicer
983        """
984        name =event.GetPane().caption
985   
986        for panel in self.slicer_panels:
987            if panel.window_caption==name:
988               
989                for item in self.parent.panels:
990                    if hasattr(self.parent.panels[item],"uid"):
991                        if self.parent.panels[item].uid ==panel.base.uid:
992                            self.parent.panels[item].onClearSlicer(event)
993                            self.parent._mgr.Update()
994                            break 
995                break
996   
997    def _return_engine_type(self):
998        """
999        return the current type of engine
1000        """
1001        return self._fit_engine
1002     
1003     
1004    def _on_change_engine(self, engine='park'):
1005        """
1006        Allow to select the type of engine to perform fit
1007       
1008        :param engine: the key work of the engine
1009       
1010        """
1011        ## saving fit engine name
1012        self._fit_engine = engine
1013        ## change menu item state
1014        if engine=="park":
1015            self.menu1.FindItemByPosition(0).Check(False)
1016            self.menu1.FindItemByPosition(1).Check(True)
1017        else:
1018            self.menu1.FindItemByPosition(0).Check(True)
1019            self.menu1.FindItemByPosition(1).Check(False)
1020        ## post a message to status bar
1021        msg = "Engine set to: %s" % self._fit_engine
1022        wx.PostEvent(self.parent, 
1023                     StatusEvent(status=msg))
1024        ## Bind every open fit page with a newevent to
1025        #know the current fitting engine
1026        #import fitpage
1027        event = fitpage.FitterTypeEvent()
1028        event.type = self._fit_engine
1029        for key in self.page_finder.keys():
1030            wx.PostEvent(key, event)
1031       
1032    def _on_model_panel(self, evt):
1033        """
1034        react to model selection on any combo box or model menu.plot the model 
1035       
1036        :param evt: wx.combobox event
1037       
1038        """
1039        model = evt.model
1040        if model == None:
1041            return
1042        smearer = None
1043        qmin = None
1044        qmax = None
1045        if hasattr(evt, "qmin"):
1046            qmin = evt.qmin
1047        if hasattr(evt, "qmax"):
1048            qmax = evt.qmax
1049        if hasattr(evt, "smearer"):
1050            smearer = evt.smearer
1051        model.origin_name = model.name
1052        self.current_pg = self.fit_panel.get_current_page() 
1053        ## make sure nothing is done on self.sim_page
1054        ## example trying to call set_panel on self.sim_page
1055        if self.current_pg != self.sim_page :
1056            if self.page_finder[self.current_pg].get_model() is None:
1057                model.name = "M" + str(self.index_model)
1058                self.index_model += 1 
1059            else:
1060                model.name= self.page_finder[self.current_pg].get_model().name
1061            data = self.page_finder[self.current_pg].get_fit_data()
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        msg = "Plot updating ... "
1089        wx.PostEvent(self.parent, StatusEvent(status=msg,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
1122        #center is located at the center of sqr detector
1123        xmax = qmax
1124        xmin = -qmax
1125        ymax = qmax
1126        ymin = -qmax
1127       
1128        x=  numpy.linspace(start= -1*qmax,
1129                               stop=qmax,
1130                               num=qstep,
1131                               endpoint=True) 
1132        y = numpy.linspace(start=-1*qmax,
1133                               stop= qmax,
1134                               num= qstep,
1135                               endpoint=True)
1136         
1137        ## use data info instead
1138        new_x = numpy.tile(x, (len(y),1))
1139        new_y = numpy.tile(y, (len(x),1))
1140        new_y = new_y.swapaxes(0,1)
1141       
1142        # all data reuire now in 1d array
1143        qx_data = new_x.flatten()
1144        qy_data = new_y.flatten()
1145       
1146        q_data = numpy.sqrt(qx_data*qx_data+qy_data*qy_data)
1147        # set all True (standing for unmasked) as default
1148        mask    = numpy.ones(len(qx_data), dtype = bool)
1149       
1150        # calculate the range of qx and qy: this way,
1151        # it is a little more independent
1152        x_size = xmax- xmin
1153        y_size = ymax -ymin
1154       
1155        # store x and y bin centers in q space
1156        x_bins  = x
1157        y_bins  = y
1158        # bin size: x- & y-directions
1159        xstep = x_size/len(x_bins-1)
1160        ystep = y_size/len(y_bins-1)
1161       
1162        #theory.data = numpy.zeros(len(mask))
1163        theory.err_data = numpy.ones(len(mask))
1164        theory.qx_data = qx_data
1165        theory.qy_data = qy_data 
1166        theory.q_data = q_data
1167        theory.mask = mask           
1168        theory.x_bins = x_bins 
1169        theory.y_bins = y_bins   
1170       
1171        # max and min taking account of the bin sizes
1172        theory.xmin = xmin
1173        theory.xmax = xmax
1174        theory.ymin = ymin
1175        theory.ymax = ymax
1176        theory.group_id = "Model"
1177        theory.id = "Model"
1178       
1179    def _get_plotting_info(self, data=None):
1180        """
1181        get plotting info from data if data !=None else use some default
1182        """
1183        my_info = PlotInfo()
1184        if data !=None:
1185            if hasattr(data,"info"):
1186                x_name, x_units = data.get_xaxis() 
1187                y_name, y_units = data.get_yaxis() 
1188               
1189                my_info._xunit = x_units
1190                my_info._xaxis = x_name
1191                my_info._yunit = y_units
1192                my_info._yaxis = y_name
1193               
1194            my_info.title= data.name
1195            if hasattr(data, "info"):
1196                my_info.info= data.info
1197            if hasattr(data, "group_id"):
1198                my_info.group_id= data.group_id
1199        return my_info
1200               
1201    def _complete1D(self, x,y, elapsed,index,model,data=None):
1202        """
1203        Complete plotting 1D data
1204        """ 
1205        try:
1206            new_plot = Theory1D(x=x, y=y)
1207            my_info = self._get_plotting_info( data)
1208            new_plot.name = model.name
1209            new_plot.id = my_info.id
1210            new_plot.group_id = my_info.group_id
1211           
1212            new_plot.xaxis(my_info._xaxis,  my_info._xunit)
1213            new_plot.yaxis(my_info._yaxis, my_info._yunit)
1214            if data != None:
1215                if new_plot.id == data.id:
1216                    new_plot.id += "Model"
1217                new_plot.is_data =False 
1218           
1219            title = new_plot.name
1220            # x, y are only in range of index
1221            self.theory_data = new_plot
1222            #new_plot.perspective = self.get_perspective()
1223            # Pass the reset flag to let the plotting event handler
1224            # know that we are replacing the whole plot
1225            if title is None:
1226                title = "Analytical model 1D "
1227            if data is None:
1228                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1229                             title=str(title), reset=True))
1230            else:
1231                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1232                                                       title= str(title)))
1233            # Chisqr in fitpage
1234            current_pg = self.fit_panel.get_current_page()
1235            wx.PostEvent(current_pg,
1236                         Chi2UpdateEvent(output=self._cal_chisqr(data=data,
1237                                                                 index=index)))
1238            msg = "Plot 1D  complete !"
1239            wx.PostEvent( self.parent, StatusEvent(status=msg, type="stop" ))
1240        except:
1241            msg = " Error occurred when drawing %s Model 1D: " % new_plot.name
1242            msg += " %s"  % sys.exc_value
1243            wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
1244   
1245    def _update2D(self, output,time=None):
1246        """
1247        Update the output of plotting model
1248        """
1249        wx.PostEvent(self.parent, StatusEvent(status="Plot \
1250        #updating ... ", type="update"))
1251        self.ready_fit()
1252        #self.calc_thread.ready(0.01)
1253   
1254    def _complete2D(self, image, data, model, elapsed, index, qmin,
1255                     qmax, qstep=DEFAULT_NPTS):
1256        """
1257        Complete get the result of modelthread and create model 2D
1258        that can be plot.
1259        """
1260        err_image = numpy.zeros(numpy.shape(image))
1261       
1262        theory= Data2D(image=image, err_image=err_image)
1263        theory.name = model.name
1264       
1265        if data is None:
1266            self._fill_default_model2D(theory=theory, 
1267                                       qmax=qmax, 
1268                                       qstep=qstep,
1269                                        qmin= qmin)
1270       
1271        else:
1272            theory.id = data.id + "Model"
1273            theory.group_id = data.name + "Model"
1274            theory.x_bins = data.x_bins
1275            theory.y_bins = data.y_bins
1276            theory.detector = data.detector
1277            theory.source = data.source
1278            theory.is_data = False 
1279            theory.qx_data = data.qx_data
1280            theory.qy_data = data.qy_data
1281            theory.q_data = data.q_data
1282            #numpy.zeros(len(data.err_data))#data.err_data
1283            theory.err_data = err_image
1284            theory.mask = data.mask
1285            ## plot boundaries
1286            theory.ymin = data.ymin
1287            theory.ymax = data.ymax
1288            theory.xmin = data.xmin
1289            theory.xmax = data.xmax
1290        self.theory_data = theory
1291        ## plot
1292        wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
1293                         title="Analytical model 2D ", reset=True))
1294        # Chisqr in fitpage
1295        current_pg = self.fit_panel.get_current_page()
1296        wx.PostEvent(current_pg,
1297            Chi2UpdateEvent(output=self._cal_chisqr(data=data, index=index)))
1298        msg = "Plot 2D complete !"
1299        wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
1300     
1301    def _on_data_error(self, event):
1302        """
1303        receives and event from plotting plu-gins to store the data name and
1304        their errors of y coordinates for 1Data hide and show error
1305        """
1306        self.err_dy = event.err_dy
1307         
1308    def _draw_model2D(self, model, data=None, smearer=None,
1309                      description=None, enable2D=False,
1310                      qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX,
1311                       qstep=DEFAULT_NPTS):
1312        """
1313        draw model in 2D
1314       
1315        :param model: instance of the model to draw
1316        :param description: the description of the model
1317        :param enable2D: when True allows to draw model 2D
1318        :param qmin: the minimum value to  draw model 2D
1319        :param qmax: the maximum value to draw model 2D
1320        :param qstep: the number of division of Qx and Qy of the model to draw
1321           
1322        """
1323        x=  numpy.linspace(start=-1*qmax,
1324                               stop=qmax,
1325                               num=qstep,
1326                               endpoint=True) 
1327        y = numpy.linspace(start= -1*qmax,
1328                               stop=qmax,
1329                               num=qstep,
1330                               endpoint=True)
1331        ## use data info instead
1332        if data is not None:
1333            ## check if data2D to plot
1334            if hasattr(data, "x_bins"):
1335                enable2D = True
1336                x = data.x_bins
1337                y = data.y_bins
1338               
1339        if not enable2D:
1340            return None, None
1341        try:
1342            from model_thread import Calc2D
1343            ## If a thread is already started, stop it
1344            if (self.calc_2D is not None) and self.calc_2D.isrunning():
1345                self.calc_2D.stop()
1346
1347            self.calc_2D = Calc2D(x=x,
1348                                    y=y,
1349                                    model=model, 
1350                                    data=data,
1351                                    smearer=smearer,
1352                                    qmin=qmin,
1353                                    qmax=qmax,
1354                                    qstep=qstep,
1355                                    completefn=self._complete2D,
1356                                    updatefn=self._update2D)
1357            self.calc_2D.queue()
1358
1359        except:
1360            msg = " Error occurred when drawing %s Model 2D: " % model.name
1361            msg += " %s" % sys.exc_value
1362            wx.PostEvent(self.parent, StatusEvent(status=msg))
1363
1364    def _draw_model1D(self, model, data=None, smearer=None,
1365                qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, 
1366                qstep=DEFAULT_NPTS, enable1D=True):
1367        """
1368        Draw model 1D from loaded data1D
1369       
1370        :param data: loaded data
1371        :param model: the model to plot
1372       
1373        """
1374        x=  numpy.linspace(start=qmin,
1375                           stop=qmax,
1376                           num=qstep,
1377                           endpoint=True
1378                           )
1379        if data is not None:
1380            ## check for data2D
1381            if hasattr(data,"x_bins"):
1382                return
1383            x = data.x
1384           
1385            if qmin == None :
1386                qmin == DEFAULT_QMIN
1387
1388            if qmax == None:
1389                qmax == DEFAULT_QMAX
1390               
1391        if not enable1D:
1392            return 
1393        try:
1394            from model_thread import Calc1D
1395            ## If a thread is already started, stop it
1396            if (self.calc_1D is not None) and self.calc_1D.isrunning():
1397                self.calc_1D.stop()
1398            self.calc_1D = Calc1D(x=x,
1399                                  data=data,
1400                                  model=model, 
1401                                  qmin=qmin,
1402                                  qmax=qmax,
1403                                  smearer=smearer,
1404                                  completefn=self._complete1D,
1405                                  updatefn=self._update1D)
1406            self.calc_1D.queue()
1407
1408        except:
1409            msg = " Error occurred when drawing %s Model 1D: " % model.name
1410            msg += " %s" % sys.exc_value
1411            wx.PostEvent(self.parent, StatusEvent(status=msg))
1412
1413    def _cal_chisqr(self, data=None, index=None): 
1414        """
1415        Get handy Chisqr using the output from draw1D and 2D,
1416        instead of calling expansive CalcChisqr in guithread
1417        """
1418        # default chisqr
1419        chisqr = None
1420       
1421        # return None if data == None
1422        if data == None: return chisqr
1423       
1424        # Get data: data I, theory I, and data dI in order
1425        if data.__class__.__name__ =="Data2D":
1426            if index == None: 
1427                index = numpy.ones(len(data.data),ntype=bool)
1428            # get rid of zero error points
1429            index = index & (data.err_data != 0) 
1430            fn = data.data[index] 
1431            gn = self.theory_data.data[index]
1432            en = data.err_data[index]
1433        else:
1434            # 1 d theory from model_thread is only in the range of index
1435            if index == None:
1436                index = numpy.ones(len(data.y), ntype=bool)
1437            if data.dy == None or data.dy == []:
1438                dy = numpy.ones(len(data.y))
1439            else:
1440                ## Set consitently w/AbstractFitengine:
1441                # But this should be corrected later.
1442                dy = data.dy
1443                dy[dy==0] = 1 
1444            fn = data.y[index] 
1445            gn = self.theory_data.y
1446            en = dy[index]
1447        # residual
1448        res = (fn - gn)/en
1449        # get chisqr only w/finite
1450        val = res[numpy.isfinite(res)]*res[numpy.isfinite(res)]
1451        chisqr = numpy.average(val)
1452        return chisqr
1453   
1454   
1455#def profile(fn, *args, **kw):
1456#    import cProfile, pstats, os
1457#    global call_result
1458#    def call():
1459#        global call_result
1460#        call_result = fn(*args, **kw)
1461#    cProfile.runctx('call()', dict(call=call), {}, 'profile.out')
1462#    stats = pstats.Stats('profile.out')
1463#    #stats.sort_stats('time')
1464#    stats.sort_stats('calls')
1465#    stats.print_stats()
1466#    os.unlink('profile.out')
1467#    return call_result
1468if __name__ == "__main__":
1469    i = Plugin()
1470   
1471   
1472   
1473   
Note: See TracBrowser for help on using the repository browser.