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

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 5cc39f10 was 72323d1, checked in by Gervaise Alina <gervyh@…>, 14 years ago

updating model in datapanel

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