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

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 cf9b6950 was 90a7bbd, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working save state

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