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

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 f036c692 was 13913ec, checked in by Jae Cho <jhjcho@…>, 14 years ago

bug fixes: Q range Npts_fit and chisqr

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