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

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 6f59a98 was 0277d084, checked in by Gervaise Alina <gervyh@…>, 15 years ago

add theory view

  • Property mode set to 100644
File size: 16.3 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        ## use data info instead
201        if data !=None:
202            ## check if data2D to plot
203            if hasattr(data, "x_bins"):
204                enable2D = True
205                x= data.x_bins
206                y= data.y_bins
207           
208        if not enable2D:
209            return
210        try:
211            from model_thread import Calc2D
212            ## If a thread is already started, stop it
213            if self.calc_2D != None and self.calc_2D.isrunning():
214                self.calc_2D.stop()
215            self.calc_2D = Calc2D(  x= x,
216                                    y= y,
217                                    model= model, 
218                                    data = data,
219                                    qmin= qmin,
220                                    qmax= qmax,
221                                    qstep= qstep,
222                                    completefn= self._complete2D,
223                                    updatefn= self._update2D )
224            self.calc_2D.queue()
225           
226        except:
227            raise
228            #msg= " Error occurred when drawing %s Model 2D: "%model.name
229            #msg+= " %s"%sys.exc_value
230            #wx.PostEvent( self.parent, StatusEvent(status= msg ))
231            #return 
232   
233    def _draw_model1D(self, model, data=None, smearer= None,
234                qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, qstep= DEFAULT_NPTS,
235                enable1D= True):
236        """
237            Draw model 1D from loaded data1D
238            @param data: loaded data
239            @param model: the model to plot
240        """
241        x=  numpy.linspace(start= qmin,
242                           stop= qmax,
243                           num= qstep,
244                           endpoint=True
245                           )
246        if data!=None:
247            ## check for data2D
248            if hasattr(data,"x_bins"):
249                return
250            x = data.x
251            if qmin == DEFAULT_QMIN :
252                qmin = min(data.x)
253            if qmax == DEFAULT_QMAX:
254                qmax = max(data.x) 
255           
256       
257        if not enable1D:
258            return
259   
260        try:
261            from model_thread import Calc1D
262            ## If a thread is already started, stop it
263            if self.calc_1D!= None and self.calc_1D.isrunning():
264                self.calc_1D.stop()
265            self.calc_1D= Calc1D( x= x,
266                                  data = data,
267                                  model= model, 
268                                  qmin = qmin,
269                                  qmax = qmax,
270                                  smearer = smearer,
271                                  completefn = self._complete1D,
272                                  updatefn = self._update1D  )
273            self.calc_1D.queue()
274           
275        except:
276            raise
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            #return 
281       
282    def _update1D(self,x, output):
283        """
284            Update the output of plotting model 1D
285        """
286        wx.PostEvent(self.parent, StatusEvent(status="Plot \
287        #updating ... ",type="update"))
288        self.ready_fit()
289        #self.calc_thread.ready(0.01)
290   
291   
292    def _fill_default_model2D(self, theory, qmax,qstep, qmin=None):
293        """
294            fill Data2D with default value
295            @param theory: Data2D to fill
296        """
297        from DataLoader.data_info import Detector, Source
298       
299        detector = Detector()
300        theory.detector.append(detector) 
301           
302        theory.detector[0].distance=1e+32
303        theory.source= Source()
304        theory.source.wavelength=2*math.pi/1e+32
305     
306        ## Create detector for Model 2D
307        xmax=2*theory.detector[0].distance*math.atan(\
308                            qmax/(4*math.pi/theory.source.wavelength))
309       
310        theory.detector[0].pixel_size.x= xmax/(qstep/2-0.5)
311        theory.detector[0].pixel_size.y= xmax/(qstep/2-0.5)
312        theory.detector[0].beam_center.x= qmax
313        theory.detector[0].beam_center.y= qmax
314        ## create x_bins and y_bins of the model 2D
315        distance   = theory.detector[0].distance
316        pixel      = qstep/2-1
317        theta      = pixel / distance / qstep#100.0
318        wavelength = theory.source.wavelength
319        pixel_width_x = theory.detector[0].pixel_size.x
320        pixel_width_y = theory.detector[0].pixel_size.y
321        center_x      = theory.detector[0].beam_center.x/pixel_width_x
322        center_y      = theory.detector[0].beam_center.y/pixel_width_y
323       
324       
325        size_x, size_y= numpy.shape(theory.data)
326        for i_x in range(size_x):
327            theta = (i_x-center_x)*pixel_width_x / distance
328            qx = 4.0*math.pi/wavelength * math.tan(theta/2.0)
329            theory.x_bins.append(qx)   
330        for i_y in range(size_y):
331            theta = (i_y-center_y)*pixel_width_y / distance
332            qy =4.0*math.pi/wavelength * math.tan(theta/2.0)
333            theory.y_bins.append(qy)
334           
335        theory.group_id ="Model"
336        theory.id ="Model"
337        ## determine plot boundaries
338        theory.xmin= -qmax
339        theory.xmax= qmax
340        theory.ymin= -qmax
341        theory.ymax= qmax
342       
343       
344    def _get_plotting_info(self, data=None):
345        """
346            get plotting info from data if data !=None
347            else use some default
348        """
349        my_info = PlotInfo()
350        if data !=None:
351            if hasattr(data,"info"):
352                x_name, x_units = data.get_xaxis() 
353                y_name, y_units = data.get_yaxis() 
354               
355                my_info._xunit = x_units
356                my_info._xaxis = x_name
357                my_info._yunit = y_units
358                my_info._yaxis = y_name
359               
360            my_info.title= data.name
361            if hasattr(data, "info"):
362                my_info.info= data.info
363            if hasattr(data, "group_id"):
364                my_info.group_id= data.group_id
365       
366        return my_info
367               
368               
369    def _complete1D(self, x,y, elapsed,model,data=None):
370        """
371            Complete plotting 1D data
372        """ 
373       
374        try:
375            new_plot = Theory1D(x=x, y=y)
376            my_info = self._get_plotting_info( data)
377            new_plot.name = model.name
378            new_plot.id = my_info.id
379            new_plot.group_id = my_info.group_id
380           
381            new_plot.xaxis( my_info._xaxis,  my_info._xunit)
382            new_plot.yaxis( my_info._yaxis, my_info._yunit)
383            if data!=None:
384                if new_plot.id == data.id:
385                    new_plot.id += "Model"
386                new_plot.is_data =False 
387           
388            # Pass the reset flag to let the plotting event handler
389            # know that we are replacing the whole plot
390           
391            title = "Analytical model 1D "
392            if data ==None:
393                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
394                             title= str(title), reset=True ))
395            else:
396                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
397                             title= str(title)))
398            msg = "Plot 1D  complete !"
399            wx.PostEvent( self.parent, StatusEvent( status= msg , type="stop" ))
400        except:
401            msg= " Error occurred when drawing %s Model 1D: "%new_plot.name
402            msg+= " %s"%sys.exc_value
403            wx.PostEvent( self.parent, StatusEvent(status= msg, type="stop"  ))
404            return 
405                 
406   
407       
408    def _update2D(self, output,time=None):
409        """
410            Update the output of plotting model
411        """
412        wx.PostEvent(self.parent, StatusEvent(status="Plot \
413        #updating ... ",type="update"))
414        self.ready_fit()
415        #self.calc_thread.ready(0.01)
416       
417       
418    def _complete2D(self, image,data, model,  elapsed,qmin, qmax,qstep=DEFAULT_NPTS):
419        """
420            Complete get the result of modelthread and create model 2D
421            that can be plot.
422        """
423     
424   
425        err_image = numpy.zeros(numpy.shape(image))
426       
427        theory= Data2D(image= image , err_image= err_image)
428        theory.name= model.name
429       
430        if data ==None:
431            self._fill_default_model2D(theory= theory, qmax=qmax,qstep=qstep, qmin= qmin)
432       
433        else:
434            theory.id= data.id+"Model"
435            theory.group_id= data.name+"Model"
436            theory.x_bins= data.x_bins
437            theory.y_bins= data.y_bins
438            theory.detector= data.detector
439            theory.source= data.source
440            theory.is_data =False 
441            ## plot boundaries
442            theory.ymin= data.ymin
443            theory.ymax= data.ymax
444            theory.xmin= data.xmin
445            theory.xmax= data.xmax
446     
447       
448        ## plot
449        wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
450                         title="Analytical model 2D ", reset=True ))
451        msg = "Plot 2D complete !"
452        wx.PostEvent( self.parent, StatusEvent( status= msg , type="stop" ))
453         
454           
Note: See TracBrowser for help on using the repository browser.