source: sasview/theoryview/perspectives/theory/theory.py @ 6cda91f

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 6cda91f was 9e2cfee, checked in by Gervaise Alina <gervyh@…>, 14 years ago

reverse theory.py to version 3050

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