source: sasview/theoryview/perspectives/theory/theory.py @ f43827cc

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 f43827cc was 00d3528, checked in by Jae Cho <jhjcho@…>, 15 years ago

updated 2d inputs and 2d model defaults

  • Property mode set to 100644
File size: 17.4 KB
RevLine 
[0277d084]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 )
[00d3528]200         
[0277d084]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
[00d3528]208
[0277d084]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            raise
278            #msg= " Error occurred when drawing %s Model 1D: "%model.name
279            #msg+= " %s"%sys.exc_value
280            #wx.PostEvent( self.parent, StatusEvent(status= msg ))
281            #return 
282       
283    def _update1D(self,x, output):
284        """
285            Update the output of plotting model 1D
286        """
287        wx.PostEvent(self.parent, StatusEvent(status="Plot \
288        #updating ... ",type="update"))
289        self.ready_fit()
290        #self.calc_thread.ready(0.01)
291   
292   
293    def _fill_default_model2D(self, theory, qmax,qstep, qmin=None):
294        """
295            fill Data2D with default value
296            @param theory: Data2D to fill
297        """
298        from DataLoader.data_info import Detector, Source
299       
300        detector = Detector()
[00d3528]301        theory.detector.append(detector)         
[0277d084]302        theory.source= Source()
303       
[00d3528]304        ## Default values   
305        theory.detector[0].distance= 8000   # mm       
306        theory.source.wavelength= 6         # A     
307        theory.detector[0].pixel_size.x= 5  # mm
308        theory.detector[0].pixel_size.y= 5  # mm
309       
[0277d084]310        theory.detector[0].beam_center.x= qmax
311        theory.detector[0].beam_center.y= qmax
[00d3528]312       
313       
[0277d084]314        ## create x_bins and y_bins of the model 2D
315        pixel_width_x = theory.detector[0].pixel_size.x
316        pixel_width_y = theory.detector[0].pixel_size.y
317        center_x      = theory.detector[0].beam_center.x/pixel_width_x
318        center_y      = theory.detector[0].beam_center.y/pixel_width_y
[00d3528]319
320        # theory default: assume the beam center is located at the center of sqr detector
321        xmax = qmax
322        xmin = -qmax
323        ymax = qmax
324        ymin = -qmax
325       
326        x=  numpy.linspace(start= -1*qmax,
327                               stop= qmax,
328                               num= qstep,
329                               endpoint=True ) 
330        y = numpy.linspace(start= -1*qmax,
331                               stop= qmax,
332                               num= qstep,
333                               endpoint=True )
334         
335        ## use data info instead
336        new_x = numpy.tile(x, (len(y),1))
337        new_y = numpy.tile(y, (len(x),1))
338        new_y = new_y.swapaxes(0,1)
[0277d084]339       
[00d3528]340        # all data reuire now in 1d array
341        qx_data = new_x.flatten()
342        qy_data = new_y.flatten()
[0277d084]343       
[00d3528]344        q_data = numpy.sqrt(qx_data*qx_data+qy_data*qy_data)
345        # set all True (standing for unmasked) as default
346        mask    = numpy.ones(len(qx_data), dtype = bool)
347       
348        # calculate the range of qx and qy: this way, it is a little more independent
349        x_size = xmax- xmin
350        y_size = ymax -ymin
351       
352        # store x and y bin centers in q space
353        x_bins  = x
354        y_bins  = y
355        # bin size: x- & y-directions
356        xstep = x_size/len(x_bins-1)
357        ystep = y_size/len(y_bins-1)
358       
359        #theory.data = numpy.zeros(len(mask))
360        theory.err_data = numpy.zeros(len(mask))
361        theory.qx_data = qx_data
362        theory.qy_data = qy_data 
363        theory.q_data = q_data
364        theory.mask = mask           
365        theory.x_bins = x_bins 
366        theory.y_bins = y_bins   
367       
368        # max and min taking account of the bin sizes
369        theory.xmin= xmin - xstep/2
370        theory.xmax= xmax + xstep/2
371        theory.ymin= ymin - ystep/2
372        theory.ymax= ymax + ystep/2
[0277d084]373        theory.group_id ="Model"
374        theory.id ="Model"
375       
376       
377    def _get_plotting_info(self, data=None):
378        """
379            get plotting info from data if data !=None
380            else use some default
381        """
382        my_info = PlotInfo()
383        if data !=None:
384            if hasattr(data,"info"):
385                x_name, x_units = data.get_xaxis() 
386                y_name, y_units = data.get_yaxis() 
387               
388                my_info._xunit = x_units
389                my_info._xaxis = x_name
390                my_info._yunit = y_units
391                my_info._yaxis = y_name
392               
393            my_info.title= data.name
394            if hasattr(data, "info"):
395                my_info.info= data.info
396            if hasattr(data, "group_id"):
397                my_info.group_id= data.group_id
398       
399        return my_info
400               
401               
402    def _complete1D(self, x,y, elapsed,model,data=None):
403        """
404            Complete plotting 1D data
405        """ 
406       
407        try:
408            new_plot = Theory1D(x=x, y=y)
409            my_info = self._get_plotting_info( data)
410            new_plot.name = model.name
411            new_plot.id = my_info.id
412            new_plot.group_id = my_info.group_id
413           
414            new_plot.xaxis( my_info._xaxis,  my_info._xunit)
415            new_plot.yaxis( my_info._yaxis, my_info._yunit)
416            if data!=None:
417                if new_plot.id == data.id:
418                    new_plot.id += "Model"
419                new_plot.is_data =False 
420           
421            # Pass the reset flag to let the plotting event handler
422            # know that we are replacing the whole plot
423           
424            title = "Analytical model 1D "
425            if data ==None:
426                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
427                             title= str(title), reset=True ))
428            else:
429                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
430                             title= str(title)))
431            msg = "Plot 1D  complete !"
432            wx.PostEvent( self.parent, StatusEvent( status= msg , type="stop" ))
433        except:
434            msg= " Error occurred when drawing %s Model 1D: "%new_plot.name
435            msg+= " %s"%sys.exc_value
436            wx.PostEvent( self.parent, StatusEvent(status= msg, type="stop"  ))
437            return 
438                 
439   
440       
441    def _update2D(self, output,time=None):
442        """
443            Update the output of plotting model
444        """
445        wx.PostEvent(self.parent, StatusEvent(status="Plot \
446        #updating ... ",type="update"))
447        self.ready_fit()
448        #self.calc_thread.ready(0.01)
449       
450       
451    def _complete2D(self, image,data, model,  elapsed,qmin, qmax,qstep=DEFAULT_NPTS):
452        """
453            Complete get the result of modelthread and create model 2D
454            that can be plot.
455        """
456        err_image = numpy.zeros(numpy.shape(image))
457       
458        theory= Data2D(image= image , err_image= err_image)
459        theory.name= model.name
[00d3528]460
[0277d084]461        if data ==None:
462            self._fill_default_model2D(theory= theory, qmax=qmax,qstep=qstep, qmin= qmin)
463       
464        else:
465            theory.id= data.id+"Model"
466            theory.group_id= data.name+"Model"
467            theory.x_bins= data.x_bins
468            theory.y_bins= data.y_bins
469            theory.detector= data.detector
470            theory.source= data.source
471            theory.is_data =False 
[00d3528]472            theory.qx_data = data.qx_data
473            theory.qy_data = data.qy_data
474            theory.q_data = data.q_data
475            theory.err_data = data.err_data
476            theory.mask = data.mask
[0277d084]477            ## plot boundaries
478            theory.ymin= data.ymin
479            theory.ymax= data.ymax
480            theory.xmin= data.xmin
481            theory.xmax= data.xmax
482       
483        ## plot
484        wx.PostEvent(self.parent, NewPlotEvent(plot=theory,
485                         title="Analytical model 2D ", reset=True ))
486        msg = "Plot 2D complete !"
487        wx.PostEvent( self.parent, StatusEvent( status= msg , type="stop" ))
488         
489           
Note: See TracBrowser for help on using the repository browser.