source: sasview/sansview/perspectives/fitting/fitting.py @ 5a0d01b3

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 5a0d01b3 was 75fbd17, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on save state

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