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

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 a2cb1f9 was a2cb1f9, checked in by Jae Cho <jhjcho@…>, 13 years ago

cleaned up around on_Fit and added sleep

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