source: sasview/calculatorview/perspectives/calculator/resolution_calculator_panel.py @ 83267f9

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 83267f9 was be6e99a, checked in by Jae Cho <jhjcho@…>, 14 years ago

fixed problems in the estimator

  • Property mode set to 100644
File size: 47.4 KB
Line 
1"""
2   This software was developed by the University of Tennessee as part of the
3Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4project funded by the US National Science Foundation.
5
6See the license text in license.txt
7
8copyright 2008, 2009, 2010 University of Tennessee
9"""
10import wx
11import sys
12import matplotlib
13#Use the WxAgg back end. The Wx one takes too long to render
14matplotlib.use('WXAgg')
15from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
16from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
17from matplotlib.backend_bases import FigureManagerBase
18# Wx-Pylab magic for displaying plots within an application's window.
19from matplotlib import _pylab_helpers
20# The Figure object is used to create backend-independent plot representations.
21from matplotlib.figure import Figure
22
23#from sans.guicomm.events import StatusEvent 
24from sans.calculator.resolution_calculator import ResolutionCalculator
25from sans.guiframe.events import StatusEvent 
26from calculator_widgets import OutputTextCtrl
27from calculator_widgets import InputTextCtrl
28from wx.lib.scrolledpanel import ScrolledPanel
29from math import fabs
30_BOX_WIDTH = 100
31_Q_DEFAULT = 0.0
32#Slit length panel size
33if sys.platform.count("win32") > 0:
34    PANEL_WIDTH = 525
35    PANEL_HEIGHT = 653
36    FONT_VARIANT = 0
37else:
38    PANEL_WIDTH = 560
39    PANEL_HEIGHT = 692
40    FONT_VARIANT = 1
41
42_SOURCE_MASS = {'Alpha':6.64465620E-24,
43                'Deuteron':3.34358320E-24,
44                'Neutron':1.67492729E-24, 
45                'Photon': 0.0,
46                'Proton':1.67262137E-24,
47                'Triton':5.00826667E-24}
48
49class ResolutionCalculatorPanel(ScrolledPanel):
50    """
51    Provides the Resolution calculator GUI.
52    """
53    ## Internal nickname for the window, used by the AUI manager
54    window_name = "SANS Resolution Estimator"
55    ## Name to appear on the window title bar
56    window_caption = ""
57    ## Flag to tell the AUI manager to put this panel in the center pane
58    CENTER_PANE = True
59   
60    def __init__(self, parent,  *args, **kwds):
61        kwds["size"]= (PANEL_WIDTH * 2, PANEL_HEIGHT)
62        kwds["style"]= wx.FULL_REPAINT_ON_RESIZE
63        ScrolledPanel.__init__(self, parent, *args, **kwds)
64        self.SetupScrolling()
65        self.parent = parent
66       
67        # input defaults
68        self.qx = []
69        self.qy = []
70        # dQ defaults
71        self.sigma_r = None
72        self.sigma_phi = None
73        self.sigma_1d = None
74        # dQ 2d image
75        self.image = None
76        #Font size
77        self.SetWindowVariant(variant=FONT_VARIANT)
78        # Object that receive status event
79        self.resolution = ResolutionCalculator()
80        # Source selection dic
81        self.source_mass = _SOURCE_MASS
82        #layout attribute
83        self.hint_sizer = None
84        # detector coordinate of estimation of sigmas
85        self.det_coordinate = 'cartesian'
86
87        self._do_layout()
88
89    def _define_structure(self):
90        """
91        Define the main sizers building to build this application.
92        """
93        self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
94        self.vertical_l_sizer = wx.BoxSizer(wx.VERTICAL)
95        self.vertical_r_spacer = wx.BoxSizer(wx.VERTICAL)
96        self.vertical_r_frame = wx.StaticBox(self, -1, '')
97        self.vertical_r_sizer = wx.StaticBoxSizer(self.vertical_r_frame,
98                                                  wx.VERTICAL)
99        self.box_source = wx.StaticBox(self, -1,
100                                str(self.window_caption))
101        self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
102                                                    wx.VERTICAL)
103        self.mass_sizer = wx.BoxSizer(wx.HORIZONTAL)
104        self.intensity_sizer = wx.BoxSizer(wx.HORIZONTAL)
105        self.wavelength_sizer = wx.BoxSizer(wx.HORIZONTAL)
106        self.wavelength_spread_sizer = wx.BoxSizer(wx.HORIZONTAL)
107        self.source_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
108        self.sample_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
109        self.source2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
110        self.sample2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
111        self.sample2detector_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
112        self.detector_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
113        self.detector_pix_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
114        #self.detector_offset_sizer = wx.BoxSizer(wx.HORIZONTAL)
115        self.input_sizer = wx.BoxSizer(wx.VERTICAL)
116        self.output_sizer = wx.BoxSizer(wx.VERTICAL)
117        self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
118        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
119       
120    def _layout_mass(self):
121        """
122        Fill the sizer containing mass
123        """
124        # get the mass
125        mass_value = str(self.resolution.mass)
126        self.mass_txt = wx.StaticText(self, -1, 
127                                'Source: ')
128        self.mass_hint = "Mass of Neutrons m = %s [g]"\
129                                 % str(self.resolution.mass)
130        self.source_cb = wx.ComboBox(self, -1,
131                                style=wx.CB_READONLY|wx.CB_SORT,
132                                name = '%s'%mass_value)
133        for key, value in self.source_mass.iteritems():
134            name_source = str(key)
135            self.source_cb.Append(name_source, name_source)
136            self.source_cb.SetStringSelection("Neutron") 
137        wx.EVT_COMBOBOX(self.source_cb,-1, self._on_source_selection)     
138        source_hint = "Source Selection: Affect on"
139        source_hint += " the gravitational contribution.\n"
140        source_hint += "Mass of %s: m = %s [g]" % \
141                            ('Neutron', str(self.resolution.mass))
142        self.mass_txt.SetToolTipString(source_hint)
143        self.mass_sizer.AddMany([(self.mass_txt, 0, wx.LEFT, 15),
144                                    (self.source_cb, 0, wx.LEFT, 15)])   
145       
146    def _layout_intensity(self):
147        """
148        Fill the sizer containing intensity
149        """
150        # get the intensity
151        intensity_value = str(self.resolution.intensity)
152        intensity_unit_txt = wx.StaticText(self, -1, '[counts/s]')
153        intensity_txt = wx.StaticText(self, -1, 
154                                'Intensity: ')
155        self.intensity_tcl = InputTextCtrl(self, -1, 
156                                        size=(_BOX_WIDTH,-1))
157        intensity_hint = "Intensity of Neutrons"
158        self.intensity_tcl.SetValue(intensity_value)
159        self.intensity_tcl.SetToolTipString(intensity_hint)
160        self.intensity_sizer.AddMany([(intensity_txt, 0, wx.LEFT, 15),
161                                    (self.intensity_tcl, 0, wx.LEFT, 15),
162                                    (intensity_unit_txt,0, wx.LEFT, 10)])   
163
164       
165    def _layout_wavelength(self):
166        """
167        Fill the sizer containing wavelength
168        """
169        # get the wavelength
170        wavelength_value = str(self.resolution.wavelength)
171        wavelength_unit_txt = wx.StaticText(self, -1, '[A]')
172        wavelength_txt = wx.StaticText(self, -1, 
173                                'Wavelength: ')
174        self.wavelength_tcl = InputTextCtrl(self, -1, 
175                                         size=(_BOX_WIDTH,-1))
176        wavelength_hint = "Wavelength of Neutrons"
177        self.wavelength_tcl.SetValue(wavelength_value)
178        self.wavelength_tcl.SetToolTipString(wavelength_hint)
179        self.wavelength_sizer.AddMany([(wavelength_txt, 0, wx.LEFT, 15),
180                                    (self.wavelength_tcl, 0, wx.LEFT, 15),
181                                    (wavelength_unit_txt,0, wx.LEFT, 10)])   
182         
183       
184    def _layout_wavelength_spread(self):
185        """
186        Fill the sizer containing wavelength
187        """
188        # get the wavelength
189        wavelength_spread_value = str(self.resolution.wavelength_spread)
190        wavelength_spread_unit_txt = wx.StaticText(self, -1, '')
191        wavelength_spread_txt = wx.StaticText(self, -1, 
192                                'Wavelength Spread: ')
193        self.wavelength_spread_tcl = InputTextCtrl(self, -1, 
194                                         size=(_BOX_WIDTH,-1))
195        wavelength_spread_hint = "Wavelength  Spread of Neutrons"
196        self.wavelength_spread_tcl.SetValue(wavelength_spread_value)
197        self.wavelength_spread_tcl.SetToolTipString(wavelength_spread_hint)
198        self.wavelength_spread_sizer.AddMany([(wavelength_spread_txt, 0, 
199                                               wx.LEFT, 15),
200                                (self.wavelength_spread_tcl, 0, wx.LEFT, 15),
201                                (wavelength_spread_unit_txt,0, wx.LEFT, 10)])     
202         
203       
204    def _layout_source_aperture(self):
205        """
206        Fill the sizer containing source aperture size
207        """
208        # get the wavelength
209        source_aperture_value = str(self.resolution.source_aperture_size[0])
210        if len(self.resolution.source_aperture_size)>1:
211            source_aperture_value += ", "
212            source_aperture_value += str(\
213                                    self.resolution.source_aperture_size[1])
214        source_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
215        source_aperture_txt = wx.StaticText(self, -1, 
216                                'Source Aperture Size: ')
217        self.source_aperture_tcl = InputTextCtrl(self, -1, 
218                                         size=(_BOX_WIDTH,-1))
219        source_aperture_hint = "Source Aperture Size"
220        self.source_aperture_tcl.SetValue(source_aperture_value)
221        self.source_aperture_tcl.SetToolTipString(source_aperture_hint)
222        self.source_aperture_sizer.AddMany([(source_aperture_txt, 0, 
223                                               wx.LEFT, 15),
224                                (self.source_aperture_tcl, 0, wx.LEFT, 15),
225                                    (source_aperture_unit_txt,0, wx.LEFT, 10)]) 
226
227       
228    def _layout_sample_aperture(self):
229        """
230        Fill the sizer containing sample aperture size
231        """
232        # get the wavelength
233        sample_aperture_value = str(self.resolution.sample_aperture_size[0])
234        if len(self.resolution.sample_aperture_size)>1:
235            sample_aperture_value += ", "
236            sample_aperture_value += str(\
237                                    self.resolution.sample_aperture_size[1])
238        sample_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
239        sample_aperture_txt = wx.StaticText(self, -1, 
240                                'Sample Aperture Size: ')
241        self.sample_aperture_tcl = InputTextCtrl(self, -1, 
242                                         size=(_BOX_WIDTH,-1))
243        sample_aperture_hint = "Sample Aperture Size"
244        self.sample_aperture_tcl.SetValue(sample_aperture_value)
245        self.sample_aperture_tcl.SetToolTipString(sample_aperture_hint)
246        self.sample_aperture_sizer.AddMany([(sample_aperture_txt, 0, 
247                                               wx.LEFT, 15),
248                                (self.sample_aperture_tcl, 0, wx.LEFT, 15),
249                                    (sample_aperture_unit_txt,0, wx.LEFT, 10)]) 
250
251
252    def _layout_source2sample_distance(self):
253        """
254        Fill the sizer containing souce2sample_distance
255        """
256        # get the wavelength
257        source2sample_distance_value = str(\
258                                    self.resolution.source2sample_distance[0])
259
260        source2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
261        source2sample_distance_txt = wx.StaticText(self, -1, 
262                                'Source to Sample Aperture Distance: ')
263        self.source2sample_distance_tcl = InputTextCtrl(self, -1, 
264                                         size=(_BOX_WIDTH,-1))
265        source2sample_distance_hint = "Source to Sample Aperture Distance"
266        self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
267        self.source2sample_distance_tcl.SetToolTipString(\
268                                                source2sample_distance_hint)
269        self.source2sample_distance_sizer.AddMany([(source2sample_distance_txt, 
270                                               0, wx.LEFT, 15),
271                            (self.source2sample_distance_tcl, 0, wx.LEFT, 15),
272                            (source2sample_distance_unit_txt,0, wx.LEFT, 10)]) 
273
274    def _layout_sample2sample_distance(self):
275        """
276        Fill the sizer containing sampleslit2sample_distance
277        """
278        # get the distance
279        sample2sample_distance_value = str(\
280                                    self.resolution.sample2sample_distance[0])
281
282        sample2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
283        sample2sample_distance_txt = wx.StaticText(self, -1, 
284                                'Sample Offset: ')
285        self.sample2sample_distance_tcl = InputTextCtrl(self, -1, 
286                                         size=(_BOX_WIDTH,-1))
287        sample2sample_distance_hint = "Sample Aperture to Sample Distance"
288        self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
289        self.sample2sample_distance_tcl.SetToolTipString(\
290                                                sample2sample_distance_hint)
291        self.sample2sample_distance_sizer.AddMany([(sample2sample_distance_txt, 
292                                               0, wx.LEFT, 15),
293                            (self.sample2sample_distance_tcl, 0, wx.LEFT, 15),
294                            (sample2sample_distance_unit_txt,0, wx.LEFT, 10)]) 
295
296
297
298    def _layout_sample2detector_distance(self):
299        """
300        Fill the sizer containing sample2detector_distance
301        """
302        # get the wavelength
303        sample2detector_distance_value = str(\
304                                    self.resolution.sample2detector_distance[0])
305
306        sample2detector_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
307        sample2detector_distance_txt = wx.StaticText(self, -1, 
308                                'Sample Aperture to Detector Distance: ')
309        self.sample2detector_distance_tcl = InputTextCtrl(self, -1, 
310                                         size=(_BOX_WIDTH,-1))
311        sample2detector_distance_hint = \
312                                "Sample Aperture to Detector Distance"
313        self.sample2detector_distance_tcl.SetValue(\
314                                                sample2detector_distance_value)
315        self.sample2detector_distance_tcl.SetToolTipString(\
316                                                sample2detector_distance_hint)
317        self.sample2detector_distance_sizer.AddMany([\
318                            (sample2detector_distance_txt, 0, wx.LEFT, 15),       
319                            (self.sample2detector_distance_tcl, 0, wx.LEFT, 15),
320                            (sample2detector_distance_unit_txt,0, wx.LEFT, 10)]) 
321       
322    def _layout_detector_size(self):
323        """
324        Fill the sizer containing detector size
325        """
326        # get the wavelength
327        detector_size_value = str(self.resolution.detector_size[0])
328        if len(self.resolution.detector_size)>1:
329            detector_size_value += ", "
330            detector_size_value += str(self.resolution.detector_size[1])
331        detector_size_unit_txt = wx.StaticText(self, -1, '')
332        detector_size_txt = wx.StaticText(self, -1, 
333                                'Number of Pixels on Detector: ')
334        self.detector_size_tcl = InputTextCtrl(self, -1, 
335                                         size=(_BOX_WIDTH,-1))
336        detector_size_hint = "Number of Pixels on Detector"
337        self.detector_size_tcl.SetValue(detector_size_value)
338        self.detector_size_tcl.SetToolTipString(detector_size_hint)
339        self.detector_size_sizer.AddMany([(detector_size_txt, 0, 
340                                               wx.LEFT, 15),
341                                (self.detector_size_tcl, 0, wx.LEFT, 15),
342                                    (detector_size_unit_txt,0, wx.LEFT, 10)]) 
343
344       
345    def _layout_detector_pix_size(self):
346        """
347        Fill the sizer containing detector pixel size
348        """
349        # get the detector_pix_size
350        detector_pix_size_value = str(self.resolution.detector_pix_size[0])
351        if len(self.resolution.detector_pix_size)>1:
352            detector_pix_size_value += ", "
353            detector_pix_size_value += str(self.resolution.detector_pix_size[1])
354        detector_pix_size_unit_txt = wx.StaticText(self, -1, '[cm]')
355        detector_pix_size_txt = wx.StaticText(self, -1, 
356                                'Detector Pixel Size: ')
357        self.detector_pix_size_tcl = InputTextCtrl(self, -1, 
358                                         size=(_BOX_WIDTH,-1))
359        detector_pix_size_hint = "Detector Pixel Size"
360        self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
361        self.detector_pix_size_tcl.SetToolTipString(detector_pix_size_hint)
362        self.detector_pix_size_sizer.AddMany([(detector_pix_size_txt, 0, 
363                                               wx.LEFT, 15),
364                                (self.detector_pix_size_tcl, 0, wx.LEFT, 15),
365                                (detector_pix_size_unit_txt,0, wx.LEFT, 10)])
366       
367    def _layout_input(self):
368        """
369        Fill the sizer containing inputs; qx, qy
370        """
371       
372        q_title = wx.StaticText(self, -1, 
373                            "[Q Location of the Estimation]:")
374        # sizers for inputs
375        inputQx_sizer = wx.BoxSizer(wx.HORIZONTAL)
376        inputQy_sizer = wx.BoxSizer(wx.HORIZONTAL)
377        # get the default dq
378        qx_value = str(_Q_DEFAULT)
379        qy_value = str(_Q_DEFAULT)
380        qx_unit_txt = wx.StaticText(self, -1, '[1/A]  ')
381        qy_unit_txt = wx.StaticText(self, -1, '[1/A]  ')
382        qx_name_txt = wx.StaticText(self, -1, 
383                                'Qx: ')
384        qy_name_txt = wx.StaticText(self, -1, 
385                                'Qy: ')
386        self.qx_tcl = InputTextCtrl(self, -1, 
387                                         size=(_BOX_WIDTH*3,-1))
388        self.qy_tcl = InputTextCtrl(self, -1, 
389                                         size=(_BOX_WIDTH*3,-1))
390        qx_hint = "Type the Qx value."
391        qy_hint = "Type the Qy value."
392        self.qx_tcl.SetValue(qx_value)
393        self.qy_tcl.SetValue(qy_value)
394        self.qx_tcl.SetToolTipString(qx_hint)
395        self.qy_tcl.SetToolTipString(qy_hint)
396        inputQx_sizer.AddMany([(qx_name_txt, 0, wx.LEFT, 15),
397                                    (self.qx_tcl, 0, wx.LEFT, 15),
398                                    (qx_unit_txt, 0, wx.LEFT, 15)])
399        inputQy_sizer.AddMany([(qy_name_txt, 0, wx.LEFT, 15),
400                                    (self.qy_tcl, 0, wx.LEFT, 15),
401                                    (qy_unit_txt, 0, wx.LEFT, 15)])
402        self.input_sizer.AddMany([(q_title, 0, wx.LEFT, 15), 
403                                    (inputQx_sizer, 0,
404                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
405                                    (inputQy_sizer, 0, 
406                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
407                                #(self.compute_button, 0, wx.LEFT, 30)])
408       
409    def _layout_output(self):
410        """
411        Fill the sizer containing dQ|| and dQ+
412        """
413        sigma_title = wx.StaticText(self, -1, 
414                        "[Standard Deviation of the Resolution Distribution]:")
415         # sizers for inputs
416        outputQxy_sizer = wx.BoxSizer(wx.HORIZONTAL)
417        outputQ_sizer = wx.BoxSizer(wx.HORIZONTAL)
418        sigma_unit = '['+'1/A' +']'
419        self.sigma_r_txt = wx.StaticText(self, -1, 
420                                           'Sigma_x:   ')
421        self.sigma_r_tcl = OutputTextCtrl(self, -1, 
422                                                 size=(_BOX_WIDTH*0.8,-1))
423        self.sigma_phi_txt = wx.StaticText(self, -1, 
424                                           'Sigma_y:')
425        self.sigma_phi_tcl = OutputTextCtrl(self, -1, 
426                                                 size=(_BOX_WIDTH*0.8,-1))
427        self.sigma_lamd_txt = wx.StaticText(self, -1, 
428                                           'Sigma_lamd:')
429        self.sigma_lamd_tcl = OutputTextCtrl(self, -1, 
430                                                 size=(_BOX_WIDTH*0.7,-1))
431        sigma_1d_txt = wx.StaticText(self, -1, '( 1D:   Sigma:')
432        self.sigma_1d_tcl = OutputTextCtrl(self, -1, 
433                                                 size=(_BOX_WIDTH*0.7,-1))
434        sigmax_hint = " The x component of the geometric resolution,"
435        sigmax_hint +=  " excluding sigma_lamda."
436        sigmay_hint = " The y component of the geometric resolution,"
437        sigmay_hint +=  " excluding sigma_lamda."
438        sigma_hint_lamd = " The wavelength contribution in the radial direction"
439        sigma_hint_lamd += ".\n Note: The phi component is always zero."
440        sigma_hint_1d = " Resolution in 1-dimension (for 1D data)."
441        self.sigma_r_tcl.SetToolTipString(sigmax_hint)
442        self.sigma_phi_tcl.SetToolTipString(sigmay_hint)
443        self.sigma_lamd_tcl.SetToolTipString(sigma_hint_lamd)
444        self.sigma_1d_tcl.SetToolTipString(sigma_hint_1d)
445        sigma_r_unit_txt = wx.StaticText(self, -1, sigma_unit)
446        sigma_phi_unit_txt = wx.StaticText(self, -1, sigma_unit)
447        sigma_lamd_unit_txt = wx.StaticText(self, -1, sigma_unit)
448        sigma_1d_unit_txt = wx.StaticText(self, -1, sigma_unit+' )')
449        outputQxy_sizer.AddMany([(self.sigma_r_txt, 0, wx.LEFT, 15),
450                                    (self.sigma_r_tcl, 0, wx.LEFT, 15),
451                                    (sigma_r_unit_txt, 0, wx.LEFT, 15),
452                                    (self.sigma_phi_txt, 0, wx.LEFT, 15),
453                                    (self.sigma_phi_tcl, 0, wx.LEFT, 15),
454                                    (sigma_phi_unit_txt, 0, wx.LEFT, 15)])
455        outputQ_sizer.AddMany([(self.sigma_lamd_txt, 0, wx.LEFT, 15),
456                                    (self.sigma_lamd_tcl, 0, wx.LEFT, 15),
457                                    (sigma_lamd_unit_txt, 0, wx.LEFT, 15),
458                                    (sigma_1d_txt, 0, wx.LEFT, 15),
459                                    (self.sigma_1d_tcl, 0, wx.LEFT, 15),
460                                    (sigma_1d_unit_txt, 0, wx.LEFT, 15)])
461        self.output_sizer.AddMany([(sigma_title, 0, wx.LEFT, 15), 
462                                    (outputQxy_sizer, 0,
463                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
464                                    (outputQ_sizer, 0, 
465                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
466       
467   
468    def _layout_hint(self):
469        """
470        Fill the sizer containing hint
471        """
472        hint_msg = ""
473        #hint_msg += "This tool is to approximately compute "
474        #hint_msg += "the resolution (dQ)."
475
476        self.hint_txt = wx.StaticText(self, -1, hint_msg)
477        self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
478   
479    def _layout_button(self): 
480        """
481        Do the layout for the button widgets
482        """ 
483        #outerbox_txt = wx.StaticText(self, -1, 'Outer Box')
484        #self.x_y_rb = wx.RadioButton(self, -1,"Cartesian")
485        #self.Bind(wx.EVT_RADIOBUTTON,
486        #          self._on_xy_coordinate, id=self.x_y_rb.GetId())
487        #self.r_phi_rb = wx.RadioButton(self, -1,"Polar")
488        #self.Bind(wx.EVT_RADIOBUTTON,
489        #          self._on_rp_coordinate, id=self.r_phi_rb.GetId())
490        #self.r_phi_rb.SetValue(True)
491        #reset button
492        id = wx.NewId()
493        self.reset_button = wx.Button(self, id, "Reset")
494        hint_on_reset = "..."
495        self.reset_button.SetToolTipString(hint_on_reset)
496        self.Bind(wx.EVT_BUTTON, self.on_reset, id=id)
497        #compute button
498        id = wx.NewId()
499        self.compute_button = wx.Button(self, id, "Compute")
500        hint_on_compute = "..."
501        self.compute_button.SetToolTipString(hint_on_compute)
502        self.Bind(wx.EVT_BUTTON, self.on_compute, id=id)
503        # close button
504        self.bt_close = wx.Button(self, wx.ID_CANCEL,'Close')
505        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
506        self.bt_close.SetToolTipString("Close this window.")
507        """
508        self.button_sizer.AddMany([(self.r_phi_rb,  0, wx.LEFT, 15),
509                                   (self.x_y_rb,  0, wx.LEFT, 15),
510                                   (self.reset_button, 0, wx.LEFT, 50),
511                                   (self.compute_button, 0, wx.LEFT, 15),
512                                   (self.bt_close, 0, wx.LEFT, 15)])#370)])
513        """
514        self.button_sizer.Add((110, -1))
515        self.button_sizer.AddMany([(self.reset_button, 0, wx.LEFT, 50),
516                                   (self.compute_button, 0, wx.LEFT, 15),
517                                   (self.bt_close, 0, wx.LEFT, 15)])
518        self.compute_button.SetFocus()
519       
520    def _layout_image(self):
521        """
522        Layout for image plot
523        """
524        color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
525
526        # Contribution by James C.
527        # Instantiate a figure object that will contain our plots.
528        # Make the fig a little smaller than the default
529        self.figure = Figure(figsize=(6.5, 6), facecolor = 'white')
530       
531        # Initialize the figure canvas, mapping the figure object to the plot
532        # engine backend.
533        self.canvas = FigureCanvas(self, wx.ID_ANY, self.figure)
534
535        # Wx-Pylab magic ...
536        # Make our canvas the active figure manager for pylab so that when
537        # pylab plotting statements are executed they will operate on our
538        # canvas and not create a new frame and canvas for display purposes.
539        # This technique allows this application to execute code that uses
540        # pylab stataments to generate plots and embed these plots in our
541        # application window(s).
542        self.fm = FigureManagerBase(self.canvas, 1)
543        _pylab_helpers.Gcf.set_active(self.fm)
544       
545        # Instantiate the matplotlib navigation toolbar and explicitly show it.
546        mpl_toolbar = Toolbar(self.canvas)
547        # Diable pan
548        mpl_toolbar.DeleteToolByPos(3)
549
550        # Add a toolbar into the frame
551        mpl_toolbar.Realize()
552
553        # Compute before adding the canvas to the sizer
554        self.on_compute()
555
556        # Fill up the sizer
557        self.vertical_r_sizer.Add(self.canvas, -1) 
558        self.vertical_r_spacer.Add((0, 24)) 
559        self.vertical_r_spacer.Add(self.vertical_r_sizer, 0, 
560                                       wx.ALL|wx.EXPAND, 2)
561        self.vertical_r_spacer.Add((0, 30)) 
562        self.vertical_r_spacer.Add(wx.StaticLine(self), 0, 
563                                       wx.ALL|wx.EXPAND, 2)
564        self.vertical_r_spacer.Add(mpl_toolbar, 0,  wx.ALL|wx.EXPAND, 2)
565
566       
567    def _do_layout(self):
568        """
569            Draw window layout
570        """
571        #  Title of parameters
572        instrument_txt = wx.StaticText(self, -1, 
573                                '[Instrumental Parameters]:')
574        # Build individual layouts
575        self._define_structure()
576        self._layout_mass()
577        #self._layout_intensity()
578        self._layout_wavelength()
579        self._layout_wavelength_spread()
580        self._layout_source_aperture()
581        self._layout_sample_aperture()
582        self._layout_source2sample_distance()
583        self._layout_sample2detector_distance()
584        self._layout_sample2sample_distance()
585        self._layout_detector_size()
586        self._layout_detector_pix_size()
587        self._layout_input()
588        self._layout_output()
589        self._layout_hint()
590        self._layout_button()
591        # Fill the sizers
592        self.boxsizer_source.AddMany([(instrument_txt, 0,
593                                       wx.EXPAND|wx.LEFT, 15),
594                                      (self.mass_sizer, 0,
595                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
596                                      #(self.intensity_sizer, 0,
597                                      #wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
598                                      (self.wavelength_sizer, 0,
599                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
600                                      (self.wavelength_spread_sizer, 0,
601                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
602                                      (self.source_aperture_sizer, 0,
603                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
604                                      (self.sample_aperture_sizer, 0,
605                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
606                                      (self.source2sample_distance_sizer, 0,
607                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
608                                      (self.sample2detector_distance_sizer, 0,
609                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
610                                      (self.sample2sample_distance_sizer, 0,
611                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
612                                      (self.detector_size_sizer, 0,
613                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
614                                      (self.detector_pix_size_sizer, 0,
615                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
616                                      (wx.StaticLine(self), 0, 
617                                       wx.ALL|wx.EXPAND, 5),
618                                      (self.input_sizer, 0,
619                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
620                                      (wx.StaticLine(self), 0, 
621                                       wx.ALL|wx.EXPAND, 5),
622                                      (self.output_sizer, 0,
623                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
624        self.vertical_l_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
625                                       (wx.StaticLine(self), 0, 
626                                       wx.ALL|wx.EXPAND, 5),
627                                  (self.button_sizer, 0,
628                                    wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
629        self.main_sizer.Add(self.vertical_l_sizer, 0, wx.ALL, 10)
630        # Build image plot layout                     
631        self._layout_image()
632        # Add a vertical static line
633        self.main_sizer.Add( wx.StaticLine(self, -1, (2,2), 
634                            (2,PANEL_HEIGHT * 0.94), style = wx.LI_VERTICAL))
635        # Add the plot to main sizer
636        self.main_sizer.Add(self.vertical_r_spacer, 0, wx.ALL, 10)
637        self.SetSizer(self.main_sizer)
638        self.SetAutoLayout(True)
639
640    def on_close(self, event):
641        """
642        close the window containing this panel
643        """
644        # get ready for other events
645        if event is not None:
646            event.Skip()
647        # Clear the plot
648        if self.image != None:
649            self.image.clf()
650            #self.image.draw()
651        # Close panel
652        self.parent.Close()
653        # reset image
654        self.image = None
655       
656    def on_compute(self, event = None):
657        """
658        Execute the computation of resolution
659        """
660        # Skip event for next event
661        if event != None:
662            event.Skip()
663            msg = "Please Check your input values "
664            msg += "before starting the computation..."
665
666        # message
667        status_type = 'progress' 
668        msg = 'Calculating...'
669        self._status_info(msg, status_type)
670
671        status_type = 'stop'           
672        # Q min max list default
673        qx_min = []   
674        qx_max = [] 
675        qy_min = [] 
676        qy_max = [] 
677        # Get all the values at set to compute
678        #intensity = self.intensity_tcl.GetValue()
679        #self.resolution.set_intensity(float(intensity))
680        wavelength = self.wavelength_tcl.GetValue()
681        self.resolution.set_wavelength(float(wavelength))
682        source = self.source_cb.GetValue()
683        mass = self.source_mass[str(source)]
684        self.resolution.set_neutron_mass(float(mass))
685        wavelength_spread = self.wavelength_spread_tcl.GetValue()
686        self.resolution.set_wavelength_spread(float(wavelength_spread))
687        source_aperture_size = self.source_aperture_tcl.GetValue()
688        source_aperture_size = self._string2list(source_aperture_size)
689        self.resolution.set_source_aperture_size(source_aperture_size)
690        sample_aperture_size = self.sample_aperture_tcl.GetValue()
691        sample_aperture_size = self._string2list(sample_aperture_size)
692        self.resolution.set_sample_aperture_size(sample_aperture_size)
693        source2sample_distance = self.source2sample_distance_tcl.GetValue()
694        source2sample_distance = self._string2list(source2sample_distance)
695        self.resolution.set_source2sample_distance(source2sample_distance)
696        sample2sample_distance = self.sample2sample_distance_tcl.GetValue()
697        sample2sample_distance = self._string2list(sample2sample_distance)
698        self.resolution.set_sample2sample_distance(sample2sample_distance)
699        sample2detector_distance = self.sample2detector_distance_tcl.GetValue()
700        sample2detector_distance = self._string2list(sample2detector_distance)
701        self.resolution.set_sample2detector_distance(sample2detector_distance)
702        detector_size = self.detector_size_tcl.GetValue()
703        detector_size = self._string2list(detector_size)
704        self.resolution.set_detector_size(detector_size)
705        detector_pix_size = self.detector_pix_size_tcl.GetValue()
706        detector_pix_size = self._string2list(detector_pix_size)
707        self.resolution.set_detector_pix_size(detector_pix_size)
708        self.qx = self._string2inputlist(self.qx_tcl.GetValue())
709        self.qy = self._string2inputlist(self.qy_tcl.GetValue())
710       
711        try:
712            # Find min max of qs
713            xmin = min(self.qx)
714            xmax = max(self.qx)
715            ymin = min(self.qy)
716            ymax = max(self.qy)
717        except:
718            msg = "An error occured during the resolution computation."
719            msg += "Please check your inputs..."
720            self._status_info(msg, status_type)
721            raise ValueError, "Invalid Q Input..."
722
723        # Validate the q inputs
724        self._validate_q_input(self.qx, self.qy)
725       
726        # Make list of q min max for mapping
727        for length in range(len(self.qx)):
728            qx_min.append(xmin)
729            qx_max.append(xmax)
730        for length in range(len(self.qy)):
731            qy_min.append(ymin)
732            qy_max.append(ymax)
733       
734        # Compute the resolution
735        if self.image != None:
736            #_pylab_helpers.Gcf.set_active(self.fm)
737            # Clear the image before redraw
738            self.image.clf()
739            #self.image.draw()
740            # reset the image
741            self.resolution.reset_image()
742
743        # Compute and get the image plot
744        try:
745            self.image = map(self._map_func, self.qx, self.qy, 
746                             qx_min, qx_max, qy_min, qy_max)[0]
747            msg = "Finished the resolution computation..."
748            self._status_info(msg, status_type)
749        except:
750            msg = "An error occured during the resolution computation."
751            msg += "Please check your inputs..."
752            self._status_info(msg, status_type)
753            raise ValueError, "Invalid Q Input: Out of detector range..."
754       
755        # Draw lines in image before drawing
756        self._draw_lines(self.image)
757        # Draw image
758        self.image.draw()
759        #self.vertical_r_sizer.Layout()
760       
761        # Get and format the sigmas
762        sigma_r = self.format_number(self.resolution.sigma_1)
763        sigma_phi = self.format_number(self.resolution.sigma_2)
764        sigma_lamd = self.format_number(self.resolution.sigma_lamd)
765        sigma_1d =  self.format_number(self.resolution.sigma_1d)
766
767        # Set output values
768        self.sigma_r_tcl.SetValue(str(sigma_r))
769        self.sigma_phi_tcl.SetValue(str(sigma_phi))
770        self.sigma_lamd_tcl.SetValue(str(sigma_lamd))
771        self.sigma_1d_tcl.SetValue(str(sigma_1d))
772       
773    def _draw_lines(self, image = None):
774        """
775        Draw lines in image if applicable
776        : Param image: pylab object
777        """
778        if image == None:
779            return
780       
781        # Get the params from resolution
782        # ploting range
783        qx_min = self.resolution.qx_min
784        qx_max = self.resolution.qx_max
785        qy_min = self.resolution.qy_min
786        qy_max = self.resolution.qy_max
787       
788        # detector range
789        detector_qx_min = self.resolution.detector_qx_min
790        detector_qx_max = self.resolution.detector_qx_max
791        detector_qy_min = self.resolution.detector_qy_min
792        detector_qy_max = self.resolution.detector_qy_max
793       
794        # Draw zero axis lines
795        if qy_min < 0 and qy_max >= 0:
796            image.axhline(linewidth = 1)
797        if qx_min < 0 and qx_max >= 0:
798            image.axvline(linewidth = 1)
799           
800        # Find x and y ratio values to draw the detector outline
801        x_min = fabs(detector_qx_min - qx_min) / (qx_max - qx_min)
802        x_max = fabs(detector_qx_max - qx_min) / (qx_max - qx_min)
803        y_min = fabs(detector_qy_min - qy_min) / (qy_max - qy_min)
804        y_max = fabs(detector_qy_max - qy_min) / (qy_max - qy_min)
805       
806        # Draw Detector outline
807        if detector_qy_min >= qy_min:
808            image.axhline(y = detector_qy_min + 0.0002,
809                               xmin = x_min,
810                               xmax = x_max, 
811                               linewidth = 2, color='r')
812        if detector_qy_max <= qy_max:
813            image.axhline(y = detector_qy_max - 0.0002, 
814                               xmin = x_min, 
815                               xmax = x_max, 
816                               linewidth = 2, color='r')
817        if detector_qx_min >= qx_min:
818            image.axvline(x = detector_qx_min + 0.0002, 
819                               ymin = y_min, 
820                               ymax = y_max, 
821                               linewidth = 2, color='r')
822        if detector_qx_max <= qx_max:
823            image.axvline(x = detector_qx_max - 0.0002, 
824                               ymin = y_min, 
825                               ymax = y_max, 
826                               linewidth = 2, color='r')
827
828    def _map_func(self, qx, qy, qx_min, qx_max, qy_min, qy_max):   
829        """
830        Prepare the Mapping for the computation
831        : params qx, qy, qx_min, qx_max, qy_min, qy_max:
832       
833        : return: image (pylab)
834        """
835        # calculate 2D resolution distribution image
836        image = self.resolution.compute_and_plot(float(qx), float(qy), 
837                                 qx_min, qx_max, qy_min, qy_max, 
838                                 self.det_coordinate)
839        return image
840   
841    def _validate_q_input(self, qx, qy):   
842        """
843        Check if q inputs are valid
844        : params qx:  qx as a list
845        : params qy:  qy as a list
846       
847        : return: True/False
848        """
849        # check qualifications
850        if qx.__class__.__name__ != 'list':
851            return False
852        if qy.__class__.__name__ != 'list' :
853            return False
854        if len(qx) < 1:
855            return False
856        if len(qy) < 1:
857            return False
858        # allow one input
859        if len(qx) == 1 and len(qy) > 1:
860            qx = [qx[0] for ind in range(len(qy))]
861            self.qx = qx
862        if len(qy) == 1 and len(qx) > 1:
863            qy = [qy[0] for ind in range(len(qx))]
864            self.qy = qy
865        # check length
866        if len(qx) != len(qy):
867            return False
868
869        return True 
870     
871    def on_reset(self, event):
872        """
873        Execute the reset
874        """
875        # skip for another event
876        if event != None:
877            event.Skip() 
878        # init resolution_calculator
879        self.resolution = ResolutionCalculator()
880        self.resolution.get_all_instrument_params()
881        # reset all param values
882        self.source_cb.SetValue('Neutron')
883        self._on_source_selection(None)
884        #self.intensity_tcl.SetValue(str(self.resolution.intensity))
885        self.wavelength_tcl.SetValue(str(self.resolution.wavelength))
886        self.wavelength_spread_tcl.SetValue(\
887                                        str(self.resolution.wavelength_spread))
888        source_aperture_value = str(self.resolution.source_aperture_size[0])
889        if len(self.resolution.source_aperture_size)>1:
890            source_aperture_value += ", "
891            source_aperture_value += \
892                str(self.resolution.source_aperture_size[1])
893        self.source_aperture_tcl.SetValue(str(source_aperture_value))
894        sample_aperture_value = str(self.resolution.sample_aperture_size[0])
895        if len(self.resolution.sample_aperture_size)>1:
896            sample_aperture_value += ", "
897            sample_aperture_value += \
898                str(self.resolution.sample_aperture_size[1])
899        self.sample_aperture_tcl.SetValue(sample_aperture_value)
900        source2sample_distance_value = \
901            str(self.resolution.source2sample_distance[0])
902        self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
903        sample2sample_distance_value = \
904            str(self.resolution.sample2sample_distance[0])
905        self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
906        sample2detector_distance_value = \
907            str(self.resolution.sample2detector_distance[0])
908        self.sample2detector_distance_tcl.SetValue(\
909                                            sample2detector_distance_value)
910        detector_size_value = str(self.resolution.detector_size[0])
911        if len(self.resolution.detector_size)>1:
912            detector_size_value += ", "
913            detector_size_value += str(self.resolution.detector_size[1])
914        self.detector_size_tcl.SetValue(detector_size_value)
915        detector_pix_size_value = str(self.resolution.detector_pix_size[0])
916        if len(self.resolution.detector_pix_size)>1:
917            detector_pix_size_value += ", "
918            detector_pix_size_value += str(self.resolution.detector_pix_size[1])
919        self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
920        #layout attribute
921        self.hint_sizer = None
922        # reset q inputs
923        self.qx_tcl.SetValue(str(_Q_DEFAULT))
924        self.qy_tcl.SetValue(str(_Q_DEFAULT))
925        # reset sigma outputs
926        self.sigma_r_tcl.SetValue('')
927        self.sigma_phi_tcl.SetValue('')
928        self.sigma_1d_tcl.SetValue('')
929        # reset radio button
930        #self.r_phi_rb.SetValue(True)
931        # Finally re-compute
932        self.on_compute()
933        # msg on info
934        msg = " Finished the resetting..."
935        self._status_info(msg, 'stop')
936       
937    def format_number(self, value=None):
938        """
939        Return a float in a standardized, human-readable formatted string
940        """
941        try: 
942            value = float(value)
943        except:
944            output = None
945            return output
946
947        output = "%-7.4g" % value
948        return output.lstrip().rstrip() 
949     
950    def _string2list(self, string):
951        """
952        Change NNN, NNN to list,ie. [NNN, NNN] where NNN is a number
953        """
954        new_string = []
955        # check the number of floats
956        try:
957            strg = float(string)
958            new_string.append(strg)
959            #new_string.append(0)
960        except:
961            string_split = string.split(',')
962            if len(string_split) == 2:
963                str_1 = string_split[0]
964                str_2 = string_split[1]
965                new_string.append(float(str_1))
966                new_string.append(float(str_2))
967            elif len(string_split) == 1:
968                str_1 = string_split[0]
969                new_string.append(float(str_1))
970            else:
971                msg = "The numbers must be one or two (separated by ',')..."
972                self._status_info(msg, 'stop')
973                raise RuntimeError, msg
974
975        return new_string
976   
977    def _string2inputlist(self, string):
978        """
979        Change NNN, NNN,... to list,ie. [NNN, NNN,...] where NNN is a number
980       
981        : return new_string: string like list
982        """
983        new_string = []
984        string_split = string.split(',')
985        length = len(string_split)
986        for ind in range(length):
987            try:
988                value = float(string_split[ind])
989                new_string.append(value)
990            except:
991                pass
992       
993        return new_string
994
995    def _on_xy_coordinate(self,event=None):
996        """
997        Set the detector coordinate for sigmas to x-y coordinate
998        """
999        if event != None:
1000            event.Skip()       
1001        # Set the coordinate in Cartesian       
1002        self.det_coordinate = 'cartesian'
1003        self.sigma_r_txt.SetLabel('Sigma_x:')
1004        self.sigma_phi_txt.SetLabel('Sigma_y:')
1005        self._onparamEnter()
1006       
1007    def _on_rp_coordinate(self,event=None):
1008        """
1009        Set the detector coordinate for sigmas to polar coordinate
1010        """
1011        if event != None:
1012            event.Skip()       
1013        # Set the coordinate in polar           
1014        self.det_coordinate = 'polar'
1015        self.sigma_r_txt.SetLabel('Sigma_r:   ')
1016        self.sigma_phi_txt.SetLabel('Sigma_phi:')
1017        self._onparamEnter()
1018       
1019    def _status_info(self, msg = '', type = "update"):
1020        """
1021        Status msg
1022        """
1023        if self.parent.parent != None:
1024                wx.PostEvent(self.parent.parent, 
1025                             StatusEvent(status = msg, type = type ))
1026
1027
1028    def _onparamEnter(self, event = None):
1029        """
1030        On Text_enter_callback, perform compute
1031        """
1032        self.on_compute()
1033       
1034    def _on_source_selection(self, event = None):
1035        """
1036        On source combobox selection
1037        """
1038        if event != None:
1039            combo = event.GetEventObject()
1040            event.Skip()
1041        else:
1042            combo = self.source_cb
1043        selection = combo.GetValue()
1044        mass = self.source_mass[selection]
1045        self.resolution.set_neutron_mass(mass)   
1046        source_hint = "Source Selection: Affect on"
1047        source_hint += " the gravitational contribution.\n"
1048        source_hint += "Mass of %s: m = %s [g]" % \
1049                            (selection, str(self.resolution.get_neutron_mass()))
1050        #source_tip.SetTip(source_hint)
1051        self.mass_txt.ToolTip.SetTip(source_hint)
1052       
1053class ResolutionWindow(wx.Frame):
1054    def __init__(self, parent = None, title = "SANS Resolution Estimator",
1055                  size=(PANEL_WIDTH * 2, PANEL_HEIGHT), *args, **kwds):
1056        kwds['title'] = title
1057        kwds['size'] = size
1058        wx.Frame.__init__(self, parent=None, *args, **kwds)
1059        self.parent = parent
1060        self.panel = ResolutionCalculatorPanel(parent=self)
1061        self.Centre()
1062        self.Show(True)
1063       
1064if __name__ == "__main__": 
1065    app = wx.PySimpleApp()
1066    frame = ResolutionWindow()   
1067    frame.Show(True)
1068    app.MainLoop()     
Note: See TracBrowser for help on using the repository browser.