source: sasview/theoryview/perspectives/theory/theory.py @ 06c7fcc

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 06c7fcc was 75a8723, checked in by Jae Cho <jhjcho@…>, 14 years ago

fixed chi2 bug, not calculating chi2 for model generated 2d data

  • Property mode set to 100644
File size: 17.4 KB
Line 
1
2import wx
3import sys
4import numpy
5import math
6import logging
7
8import models
9import model_panel
10from model_panel import ModelPanel
11from sans.guicomm.events import NewPlotEvent, StatusEvent
12from sans.guiframe.dataFitting import Data2D
13from sans.guiframe.dataFitting import Theory1D
14
15DEFAULT_BEAM = 0.005
16DEFAULT_QMIN = 0.001
17DEFAULT_QMAX = 0.13
18DEFAULT_NPTS = 50
19
20class PlotInfo:
21    """
22        store some plotting field
23    """
24    _xunit = 'A^{-1}'
25    _xaxis= "\\rm{Q}"
26    _yunit = "cm^{-1}"
27    _yaxis= "\\rm{Intensity} "
28    id = "Model"
29    group_id = "Model"
30    title= None
31    info= None
32   
33class Plugin:
34    """
35        This class defines the interface for a Plugin class
36        for calculator perspective
37    """
38   
39    def __init__(self, standalone=True):
40        """
41            Abstract class for gui_manager Plugins.
42        """
43        ## Plug-in name. It will appear on the application menu.
44        self.sub_menu = "Theory"       
45       
46        ## Reference to the parent window. Filled by get_panels() below.
47        self.parent = None
48       
49        ## List of panels that you would like to open in AUI windows
50        #  for your plug-in. This defines your plug-in "perspective"
51        self.perspective = []
52        # Log startup
53        logging.info("Theory plug-in started")   
54       
55        #Provide list of models existing in the application
56        self.menu_mng = models.ModelManager()
57        # reference to the current running thread
58        self.calc_2D= None
59        self.calc_1D= None
60       
61    def populate_menu(self, id, owner):
62        """
63            Create and return the list of application menu
64            items for the plug-in.
65           
66            @param id: deprecated. Un-used.
67            @param parent: parent window
68            @return: plug-in menu
69        """
70        return []
71     
72    def get_panels(self, parent):
73        """
74            Create and return the list of wx.Panels for your plug-in.
75            Define the plug-in perspective.
76           
77            Panels should inherit from DefaultPanel defined below,
78            or should present the same interface. They must define
79            "window_caption" and "window_name".
80           
81            @param parent: parent window
82            @return: list of panels
83        """
84        ## Save a reference to the parent
85        self.parent = parent
86        # Define a panel
87        self.model_panel= ModelPanel(self.parent, page_info =None,
88                model_list_box= self.menu_mng.get_model_list().get_list())
89        self.model_panel.set_manager(self)
90       
91        # If needed, add its name to the perspective list
92        self.perspective.append(self.model_panel.window_name)
93        self.parent.Bind(model_panel.EVT_MODEL_BOX,self._on_model_panel)
94        # Return the list of panels
95        return [self.model_panel]
96   
97    def get_context_menu(self, graph=None):
98        """
99            This method is optional.
100       
101            When the context menu of a plot is rendered, the
102            get_context_menu method will be called to give you a
103            chance to add a menu item to the context menu.
104           
105            A ref to a Graph object is passed so that you can
106            investigate the plot content and decide whether you
107            need to add items to the context menu. 
108           
109            This method returns a list of menu items.
110            Each item is itself a list defining the text to
111            appear in the menu, a tool-tip help text, and a
112            call-back method.
113           
114            @param graph: the Graph object to which we attach the context menu
115            @return: a list of menu items with call-back function
116        """
117        return []   
118   
119    def get_perspective(self):
120        """
121            Get the list of panel names for this perspective
122        """
123        return self.perspective
124   
125    def on_perspective(self, event):
126        """
127            Call back function for the perspective menu item.
128            We notify the parent window that the perspective
129            has changed.
130            @param event: menu event
131        """
132        self.parent.set_perspective(self.perspective)
133   
134    def post_init(self):
135        """
136            Post initialization call back to close the loose ends
137        """
138        pass
139           
140    def draw_model(self, model, data= None,smearer= None,
141                   enable1D= True, enable2D= False,
142                   qmin= DEFAULT_QMIN, qmax= DEFAULT_QMAX, qstep= DEFAULT_NPTS):
143        """
144             Draw model.
145             @param model: the model to draw
146             @param name: the name of the model to draw
147             @param data: the data on which the model is based to be drawn
148             @param description: model's description
149             @param enable1D: if true enable drawing model 1D
150             @param enable2D: if true enable drawing model 2D
151             @param qmin:  Range's minimum value to draw model
152             @param qmax:  Range's maximum value to draw model
153             @param qstep: number of step to divide the x and y-axis
154             
155        """
156        ## draw model 1D with no loaded data
157        self._draw_model1D( model= model, data= data,enable1D=enable1D, smearer= smearer,
158                           qmin= qmin, qmax= qmax, qstep= qstep )
159        ## draw model 2D with no initial data
160        self._draw_model2D(model=model,
161                           data = data,
162                           enable2D= enable2D,
163                           qmin=qmin,
164                           qmax=qmax,
165                           qstep=qstep)
166       
167    def _on_model_panel(self, evt):
168        """
169            react to model selection on any combo box or model menu.plot the model 
170            @param evt: wx.combobox event
171        """
172        model = evt.model
173        qmin = evt.qmin
174        qmax = evt.qmax
175        qstep = evt.qstep
176        if model ==None:
177            return
178        # save model name
179        self.draw_model(model=model, qmin=qmin, qmax=qmax, qstep=qstep)
180       
181    def _draw_model2D(self,model,data=None, enable2D=False,
182                      qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, qstep=DEFAULT_NPTS):
183        """
184            draw model in 2D
185            @param model: instance of the model to draw
186            @param enable2D: when True allows to draw model 2D
187            @param qmin: the minimum value to  draw model 2D
188            @param qmax: the maximum value to draw model 2D
189            @param qstep: the number of division of Qx and Qy of the model to draw
190           
191        """
192        x=  numpy.linspace(start= -1*qmax,
193                               stop= qmax,
194                               num= qstep,
195                               endpoint=True ) 
196        y = numpy.linspace(start= -1*qmax,
197                               stop= qmax,
198                               num= qstep,
199                               endpoint=True )
200         
201        ## use data info instead
202        if data !=None:
203            ## check if data2D to plot
204            if hasattr(data, "x_bins"):
205                enable2D = True
206                x= data.x_bins
207                y= data.y_bins
208
209        if not enable2D:
210            return
211        try:
212            from model_thread import Calc2D
213            ## If a thread is already started, stop it
214            if self.calc_2D != None and self.calc_2D.isrunning():
215                self.calc_2D.stop()
216            self.calc_2D = Calc2D(  x= x,
217                                    y= y,
218                                    model= model, 
219                                    data = data,
220                                    qmin= qmin,
221                                    qmax= qmax,
222                                    qstep= qstep,
223                                    completefn= self._complete2D,
224                                    updatefn= self._update2D )
225            self.calc_2D.queue()
226           
227        except:
228            raise
229            #msg= " Error occurred when drawing %s Model 2D: "%model.name
230            #msg+= " %s"%sys.exc_value
231            #wx.PostEvent( self.parent, StatusEvent(status= msg ))
232            #return 
233   
234    def _draw_model1D(self, model, data=None, smearer= None,
235                qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, qstep= DEFAULT_NPTS,
236                enable1D= True):
237        """
238            Draw model 1D from loaded data1D
239            @param data: loaded data
240            @param model: the model to plot
241        """
242        x=  numpy.linspace(start= qmin,
243                           stop= qmax,
244                           num= qstep,
245                           endpoint=True
246                           )
247        if data!=None:
248            ## check for data2D
249            if hasattr(data,"x_bins"):
250                return
251            x = data.x
252            if qmin == DEFAULT_QMIN :
253                qmin = min(data.x)
254            if qmax == DEFAULT_QMAX:
255                qmax = max(data.x) 
256           
257       
258        if not enable1D:
259            return
260   
261        try:
262            from model_thread import Calc1D
263            ## If a thread is already started, stop it
264            if self.calc_1D!= None and self.calc_1D.isrunning():
265                self.calc_1D.stop()
266            self.calc_1D= Calc1D( x= x,
267                                  data = data,
268                                  model= model, 
269                                  qmin = qmin,
270                                  qmax = qmax,
271                                  smearer = smearer,
272                                  completefn = self._complete1D,
273                                  updatefn = self._update1D  )
274            self.calc_1D.queue()
275           
276        except:
277            msg = " Error occurred when drawing %s Model 1D: "%model.name
278            msg += " %s"%sys.exc_value
279            wx.PostEvent(self.parent, StatusEvent(status=msg))
280           
281    def _update1D(self,x, output):
282        """
283            Update the output of plotting model 1D
284        """
285        wx.PostEvent(self.parent, StatusEvent(status="Plot \
286        #updating ... ",type="update"))
287        self.ready_fit()
288        #self.calc_thread.ready(0.01)
289   
290   
291    def _fill_default_model2D(self, theory, qmax,qstep, qmin=None):
292        """
293            fill Data2D with default value
294            @param theory: Data2D to fill
295        """
296        from DataLoader.data_info import Detector, Source
297       
298        detector = Detector()
299        theory.detector.append(detector)         
300        theory.source= Source()
301       
302        ## Default values   
303        theory.detector[0].distance= 8000   # mm       
304        theory.source.wavelength= 6         # A     
305        theory.detector[0].pixel_size.x= 5  # mm
306        theory.detector[0].pixel_size.y= 5  # mm
307       
308        theory.detector[0].beam_center.x= qmax
309        theory.detector[0].beam_center.y= qmax
310       
311       
312        ## create x_bins and y_bins of the model 2D
313        pixel_width_x = theory.detector[0].pixel_size.x
314        pixel_width_y = theory.detector[0].pixel_size.y
315        center_x      = theory.detector[0].beam_center.x/pixel_width_x
316        center_y      = theory.detector[0].beam_center.y/pixel_width_y
317
318        # theory default: assume the beam center is located at the center of sqr detector
319        xmax = qmax
320        xmin = -qmax
321        ymax = qmax
322        ymin = -qmax
323       
324        x=  numpy.linspace(start= -1*qmax,
325                               stop= qmax,
326                               num= qstep,
327                               endpoint=True ) 
328        y = numpy.linspace(start= -1*qmax,
329                               stop= qmax,
330                               num= qstep,
331                               endpoint=True )
332         
333        ## use data info instead
334        new_x = numpy.tile(x, (len(y),1))
335        new_y = numpy.tile(y, (len(x),1))
336        new_y = new_y.swapaxes(0,1)
337       
338        # all data reuire now in 1d array
339        qx_data = new_x.flatten()
340        qy_data = new_y.flatten()
341       
342        q_data = numpy.sqrt(qx_data*qx_data+qy_data*qy_data)
343        # set all True (standing for unmasked) as default
344        mask    = numpy.ones(len(qx_data), dtype = bool)
345       
346        # calculate the range of qx and qy: this way, it is a little more independent
347        x_size = xmax- xmin
348        y_size = ymax -ymin
349       
350        # store x and y bin centers in q space
351        x_bins  = x
352        y_bins  = y
353        # bin size: x- & y-directions
354        xstep = x_size/len(x_bins-1)
355        ystep = y_size/len(y_bins-1)
356       
357        #theory.data = numpy.zeros(len(mask))
358        theory.err_data = numpy.ones(len(mask))
359        theory.qx_data = qx_data
360        theory.qy_data = qy_data 
361        theory.q_data = q_data
362        theory.mask = mask           
363        theory.x_bins = x_bins 
364        theory.y_bins = y_bins   
365       
366        # max and min taking account of the bin sizes
367        theory.xmin= xmin
368        theory.xmax= xmax
369        theory.ymin= ymin
370        theory.ymax= ymax
371        theory.group_id ="Model"
372        theory.id ="Model"
373       
374       
375    def _get_plotting_info(self, data=None):
376        """
377            get plotting info from data if data !=None
378            else use some default
379        """
380        my_info = PlotInfo()
381        if data !=None:
382            if hasattr(data,"info"):
383                x_name, x_units = data.get_xaxis() 
384                y_name, y_units = data.get_yaxis() 
385               
386                my_info._xunit = x_units
387                my_info._xaxis = x_name
388                my_info._yunit = y_units
389                my_info._yaxis = y_name
390               
391            my_info.title= data.name
392            if hasattr(data, "info"):
393                my_info.info= data.info
394            if hasattr(data, "group_id"):
395                my_info.group_id= data.group_id
396       
397        return my_info
398               
399               
400    def _complete1D(self, x,y, elapsed,model,data=None):
401        """
402            Complete plotting 1D data
403        """ 
404       
405        try:
406            new_plot = Theory1D(x=x, y=y)
407            my_info = self._get_plotting_info( data)
408            new_plot.name = model.name
409            new_plot.id = my_info.id
410            new_plot.group_id = my_info.group_id
411           
412            new_plot.xaxis( my_info._xaxis,  my_info._xunit)
413            new_plot.yaxis( my_info._yaxis, my_info._yunit)
414            if data!=None:
415                if new_plot.id == data.id:
416                    new_plot.id += "Model"
417                new_plot.is_data =False 
418           
419            # Pass the reset flag to let the plotting event handler
420            # know that we are replacing the whole plot
421           
422            title = "Analytical model 1D "
423            if data ==None:
424                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
425                             title= str(title), reset=True ))
426            else:
427                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
428                             title= str(title)))
429            msg = "Plot 1D  complete !"
430            wx.PostEvent( self.parent, StatusEvent( status= msg , type="stop" ))
431        except:
432            msg= " Error occurred when drawing %s Model 1D: "%new_plot.name
433            msg+= " %s"%sys.exc_value
434            wx.PostEvent( self.parent, StatusEvent(status= msg, type="stop"  ))
435            return 
436                 
437   
438       
439    def _update2D(self, output,time=None):
440        """
441            Update the output of plotting model
442        """
443        wx.PostEvent(self.parent, StatusEvent(status="Plot \
444        #updating ... ",type="update"))
445        self.ready_fit()
446        #self.calc_thread.ready(0.01)
447       
448       
449    def _complete2D(self, image,data, model,  elapsed,qmin, qmax,qstep=DEFAULT_NPTS):
450        """
451            Complete get the result of modelthread and create model 2D
452            that can be plot.
453        """
454        err_image = numpy.zeros(numpy.shape(image))
455       
456        theory= Data2D(image= image , err_image= err_image)
457        theory.name= model.name
458
459        if data ==None:
460            self._fill_default_model2D(theory= theory, qmax=qmax,qstep=qstep, qmin= qmin)
461       
462        else:
463            theory.id= data.id+"Model"
464            theory.group_id= data.name+"Model"
465            theory.x_bins= data.x_bins
466            theory.y_bins= data.y_bins
467            theory.detector= data.detector
468            theory.source= data.source
469            theory.is_data =False 
470            theory.qx_data = data.qx_data
471            theory.qy_data = data.qy_data
472            theory.q_data = data.q_data
473            theory.err_data = data.err_data
474            theory.mask = data.mask
475            ## plot boundaries
476            theory.ymin= data.ymin
477            theory.ymax= data.ymax
478            theory.xmin= data.xmin
479            theory.xmax= data.xmax
480       
481        ## plot
482        wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
483                         title="Analytical model 2D ", reset=True ))
484        msg = "Plot 2D complete !"
485        wx.PostEvent( self.parent, StatusEvent( status= msg , type="stop" ))
486         
487           
Note: See TracBrowser for help on using the repository browser.