source: sasview/src/sas/perspectives/calculator/resolution_calculator_panel.py @ 517f3d4

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 517f3d4 was 18d58a6e, checked in by butler, 10 years ago

add help button to resolution calculator panel and do a few adjustments

  • Property mode set to 100644
File size: 61.8 KB
Line 
1"""
2This 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 os
13import matplotlib
14import math
15#Use the WxAgg back end. The Wx one takes too long to render
16matplotlib.use('WXAgg')
17from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
18from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
19from matplotlib.backend_bases import FigureManagerBase
20# Wx-Pylab magic for displaying plots within an application's window.
21from matplotlib import _pylab_helpers
22# The Figure object is used to create backend-independent plot representations.
23from matplotlib.figure import Figure
24
25#from sas.guicomm.events import StatusEvent 
26from sas.calculator.resolution_calculator import ResolutionCalculator
27from sas.guiframe.events import StatusEvent 
28from sas.perspectives.calculator.calculator_widgets import OutputTextCtrl
29from sas.perspectives.calculator.calculator_widgets import InputTextCtrl
30from wx.lib.scrolledpanel import ScrolledPanel
31from math import fabs
32from sas.perspectives.calculator import calculator_widgets as widget   
33from sas.guiframe.documentation_window import DocumentationWindow
34
35_BOX_WIDTH = 100
36_Q_DEFAULT = 0.0
37#Slit length panel size
38if sys.platform.count("win32") > 0:
39    PANEL_WIDTH = 525
40    PANEL_HEIGHT = 653
41    FONT_VARIANT = 0
42    IS_WIN = True
43else:
44    PANEL_WIDTH = 540
45    PANEL_HEIGHT = 662
46    FONT_VARIANT = 1
47    IS_WIN = False
48
49_SOURCE_MASS = {'Alpha':6.64465620E-24,
50                'Deuteron':3.34358320E-24,
51                'Neutron':1.67492729E-24, 
52                'Photon': 0.0,
53                'Proton':1.67262137E-24,
54                'Triton':5.00826667E-24}
55
56class ResolutionCalculatorPanel(ScrolledPanel):
57    """
58    Provides the Resolution calculator GUI.
59    """
60    ## Internal nickname for the window, used by the AUI manager
61    window_name = "SAS Resolution Estimator"
62    ## Name to appear on the window title bar
63    window_caption = ""
64    ## Flag to tell the AUI manager to put this panel in the center pane
65    CENTER_PANE = True
66   
67    def __init__(self, parent,  *args, **kwds):
68        kwds["size"] = (PANEL_WIDTH * 2, PANEL_HEIGHT)
69        kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
70        ScrolledPanel.__init__(self, parent, *args, **kwds)
71        self.SetupScrolling()
72        self.parent = parent
73       
74        # input defaults
75        self.qx = []
76        self.qy = []
77        # dQ defaults
78        self.sigma_r = None
79        self.sigma_phi = None
80        self.sigma_1d = None
81        # monchromatic or polychromatic
82        self.wave_color = 'mono'
83        self.num_wave = 10
84        self.spectrum_dic = {}
85        # dQ 2d image
86        self.image = None
87        # results of sigmas
88        self.sigma_strings = ' '
89        #Font size
90        self.SetWindowVariant(variant=FONT_VARIANT)
91        # Object that receive status event
92        self.resolution = ResolutionCalculator()
93        # Source selection dic
94        self.source_mass = _SOURCE_MASS
95        #layout attribute
96        self.hint_sizer = None
97        # detector coordinate of estimation of sigmas
98        self.det_coordinate = 'cartesian'
99        self.source_cb = None
100        self._do_layout()
101
102    def _define_structure(self):
103        """
104        Define the main sizers building to build this application.
105        """
106        self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
107        self.vertical_l_sizer = wx.BoxSizer(wx.VERTICAL)
108        self.vertical_r_spacer = wx.BoxSizer(wx.VERTICAL)
109        self.vertical_r_frame = wx.StaticBox(self, -1, '')
110        self.vertical_r_sizer = wx.StaticBoxSizer(self.vertical_r_frame,
111                                                  wx.VERTICAL)
112        self.box_source = wx.StaticBox(self, -1,
113                                str(self.window_caption))
114        self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
115                                                    wx.VERTICAL)
116        self.mass_sizer = wx.BoxSizer(wx.HORIZONTAL)
117        self.intensity_sizer = wx.BoxSizer(wx.HORIZONTAL)
118        self.wavelength_sizer = wx.BoxSizer(wx.HORIZONTAL)
119        self.wavelength_spread_sizer = wx.BoxSizer(wx.HORIZONTAL)
120        self.source_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
121        self.sample_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
122        self.source2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
123        self.sample2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
124        self.sample2detector_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
125        self.detector_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
126        self.detector_pix_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
127        #self.detector_offset_sizer = wx.BoxSizer(wx.HORIZONTAL)
128        self.input_sizer = wx.BoxSizer(wx.VERTICAL)
129        self.output_sizer = wx.BoxSizer(wx.VERTICAL)
130        self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
131        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
132       
133    def _layout_mass(self):
134        """
135        Fill the sizer containing mass
136        """
137        # get the mass
138        mass_value = str(self.resolution.mass)
139        self.mass_txt = wx.StaticText(self, -1, 
140                                'Source: ')
141        self.mass_hint = "Mass of Neutrons m = %s [g]"\
142                                 % str(self.resolution.mass)
143        self.source_cb = wx.ComboBox(self, -1,
144                                style=wx.CB_READONLY,
145                                name = '%s'%mass_value)
146        # Sort source name because wx2.9 on Mac does not support CB_SORT
147        # Custom sorting
148        source_list = []
149        for key, value in self.source_mass.iteritems():
150            name_source = str(key)
151            source_list.append(name_source)
152        source_list.sort()
153        for idx in range(len(source_list)):
154            self.source_cb.Append(source_list[idx], idx)
155        self.source_cb.SetStringSelection("Neutron") 
156        wx.EVT_COMBOBOX(self.source_cb, -1, self._on_source_selection) 
157       
158        # combo box for color
159        self.wave_color_cb =  wx.ComboBox(self, -1,
160                                style=wx.CB_READONLY,
161                                name = 'color')
162        # two choices
163        self.wave_color_cb.Append('Monochromatic')
164        self.wave_color_cb.Append('TOF')
165        self.wave_color_cb.SetStringSelection("Monochromatic") 
166        wx.EVT_COMBOBOX(self.wave_color_cb, -1, self._on_source_color) 
167       
168        source_hint = "Source Selection: Affect on"
169        source_hint += " the gravitational contribution.\n"
170        source_hint += "Mass of %s: m = %s [g]" % \
171                            ('Neutron', str(self.resolution.mass))
172        self.mass_txt.SetToolTipString(source_hint)
173        self.mass_sizer.AddMany([(self.mass_txt, 0, wx.LEFT, 15),
174                                    (self.source_cb, 0, wx.LEFT, 15),
175                                    (self.wave_color_cb, 0, wx.LEFT, 15)])   
176       
177    def _layout_intensity(self):
178        """
179        Fill the sizer containing intensity
180        """
181        # get the intensity
182        intensity_value = str(self.resolution.intensity)
183        intensity_unit_txt = wx.StaticText(self, -1, '[counts/s]')
184        intensity_txt = wx.StaticText(self, -1, 
185                                'Intensity: ')
186        self.intensity_tcl = InputTextCtrl(self, -1, 
187                                        size=(_BOX_WIDTH,-1))
188        intensity_hint = "Intensity of Neutrons"
189        self.intensity_tcl.SetValue(intensity_value)
190        self.intensity_tcl.SetToolTipString(intensity_hint)
191        self.intensity_sizer.AddMany([(intensity_txt, 0, wx.LEFT, 15),
192                                    (self.intensity_tcl, 0, wx.LEFT, 15),
193                                    (intensity_unit_txt,0, wx.LEFT, 10)])   
194
195       
196    def _layout_wavelength(self):
197        """
198        Fill the sizer containing wavelength
199        """
200        # get the wavelength
201        wavelength_value = str(self.resolution.get_wavelength())
202        wavelength_unit_txt = wx.StaticText(self, -1, '[A]')
203        wavelength_txt = wx.StaticText(self, -1, 
204                                'Wavelength: ')
205        self.wavelength_tcl = InputTextCtrl(self, -1, 
206                                         size=(_BOX_WIDTH,-1))
207        wavelength_hint = "Wavelength of Neutrons"
208        self.wavelength_tcl.SetValue(wavelength_value)
209        self.wavelength_tcl.SetToolTipString(wavelength_hint)
210
211        # get the spectrum
212        spectrum_value = self.resolution.get_default_spectrum()
213        self.spectrum_dic['Add new'] = ''
214        self.spectrum_dic['Flat'] = spectrum_value
215       
216        self.spectrum_txt = wx.StaticText(self, -1, 
217                                'Spectrum: ')
218        self.spectrum_cb = wx.ComboBox(self, -1,
219                                style=wx.CB_READONLY,
220                                size=(_BOX_WIDTH,-1),
221                                name = 'spectrum')
222        self.spectrum_cb.Append('Add new')
223        self.spectrum_cb.Append('Flat')
224        wx.EVT_COMBOBOX(self.spectrum_cb, -1, self._on_spectrum_cb) 
225        spectrum_hint = "Wavelength Spectrum: Intensity vs. wavelength"
226        #self.spectrum_cb.SetValue(spectrum_value)
227        self.spectrum_cb.SetStringSelection('Flat') 
228        self.spectrum_cb.SetToolTipString(spectrum_hint)
229        self.wavelength_sizer.AddMany([(wavelength_txt, 0, wx.LEFT, 15),
230                                    (self.wavelength_tcl, 0, wx.LEFT, 5),
231                                    (wavelength_unit_txt,0, wx.LEFT, 5),
232                                    (self.spectrum_txt, 0, wx.LEFT, 20),
233                                    (self.spectrum_cb, 0, wx.LEFT, 5)])   
234        self.spectrum_txt.Show(False)
235        self.spectrum_cb.Show(False)
236       
237    def _layout_wavelength_spread(self):
238        """
239        Fill the sizer containing wavelength
240        """
241        # get the wavelength
242        wavelength_spread_value = str(self.resolution.get_wavelength_spread())
243        wavelength_spread_unit_txt = wx.StaticText(self, -1, '')
244        wavelength_spread_txt = wx.StaticText(self, -1, 
245                                'Wavelength Spread: ')
246        self.wavelength_spread_tcl = InputTextCtrl(self, -1, 
247                                         size=(_BOX_WIDTH,-1))
248        wavelength_spread_hint = "Wavelength  Spread of Neutrons"
249        self.wavelength_spread_tcl.SetValue(wavelength_spread_value)
250        self.wavelength_spread_tcl.SetToolTipString(wavelength_spread_hint)
251        self.wavelength_spread_sizer.AddMany([(wavelength_spread_txt, 0, 
252                                               wx.LEFT, 15),
253                                (self.wavelength_spread_tcl, 0, wx.LEFT, 15),
254                                (wavelength_spread_unit_txt,0, wx.LEFT, 10)])     
255         
256       
257    def _layout_source_aperture(self):
258        """
259        Fill the sizer containing source aperture size
260        """
261        # get the wavelength
262        source_aperture_value = str(self.resolution.source_aperture_size[0])
263        if len(self.resolution.source_aperture_size)>1:
264            source_aperture_value += ", "
265            source_aperture_value += str(\
266                                    self.resolution.source_aperture_size[1])
267        source_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
268        source_aperture_txt = wx.StaticText(self, -1, 
269                                'Source Aperture Size: ')
270        self.source_aperture_tcl = InputTextCtrl(self, -1, 
271                                         size=(_BOX_WIDTH,-1))
272        source_aperture_hint = "Source Aperture Size"
273        self.source_aperture_tcl.SetValue(source_aperture_value)
274        self.source_aperture_tcl.SetToolTipString(source_aperture_hint)
275        self.source_aperture_sizer.AddMany([(source_aperture_txt, 0, 
276                                               wx.LEFT, 15),
277                                (self.source_aperture_tcl, 0, wx.LEFT, 15),
278                                (source_aperture_unit_txt, 0, wx.LEFT, 10)]) 
279
280       
281    def _layout_sample_aperture(self):
282        """
283        Fill the sizer containing sample aperture size
284        """
285        # get the wavelength
286        sample_aperture_value = str(self.resolution.sample_aperture_size[0])
287        if len(self.resolution.sample_aperture_size)>1:
288            sample_aperture_value += ", "
289            sample_aperture_value += str(\
290                                    self.resolution.sample_aperture_size[1])
291        sample_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
292        sample_aperture_txt = wx.StaticText(self, -1, 
293                                'Sample Aperture Size: ')
294        self.sample_aperture_tcl = InputTextCtrl(self, -1, 
295                                         size=(_BOX_WIDTH,-1))
296        sample_aperture_hint = "Sample Aperture Size"
297        self.sample_aperture_tcl.SetValue(sample_aperture_value)
298        self.sample_aperture_tcl.SetToolTipString(sample_aperture_hint)
299        self.sample_aperture_sizer.AddMany([(sample_aperture_txt, 0, 
300                                               wx.LEFT, 15),
301                                (self.sample_aperture_tcl, 0, wx.LEFT, 15),
302                                (sample_aperture_unit_txt, 0, wx.LEFT, 10)]) 
303
304
305    def _layout_source2sample_distance(self):
306        """
307        Fill the sizer containing souce2sample_distance
308        """
309        # get the wavelength
310        source2sample_distance_value = str(\
311                                    self.resolution.source2sample_distance[0])
312
313        source2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
314        source2sample_distance_txt = wx.StaticText(self, -1, 
315                                'Source to Sample Aperture Distance: ')
316        self.source2sample_distance_tcl = InputTextCtrl(self, -1, 
317                                         size=(_BOX_WIDTH,-1))
318        source2sample_distance_hint = "Source to Sample Aperture Distance"
319        self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
320        self.source2sample_distance_tcl.SetToolTipString(\
321                                                source2sample_distance_hint)
322        self.source2sample_distance_sizer.AddMany([(source2sample_distance_txt, 
323                                               0, wx.LEFT, 15),
324                            (self.source2sample_distance_tcl, 0, wx.LEFT, 15),
325                            (source2sample_distance_unit_txt,0, wx.LEFT, 10)]) 
326
327    def _layout_sample2sample_distance(self):
328        """
329        Fill the sizer containing sampleslit2sample_distance
330        """
331        # get the distance
332        sample2sample_distance_value = str(\
333                                    self.resolution.sample2sample_distance[0])
334
335        sample2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
336        sample2sample_distance_txt = wx.StaticText(self, -1, 
337                                'Sample Offset: ')
338        self.sample2sample_distance_tcl = InputTextCtrl(self, -1, 
339                                         size=(_BOX_WIDTH,-1))
340        sample2sample_distance_hint = "Sample Aperture to Sample Distance"
341        self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
342        self.sample2sample_distance_tcl.SetToolTipString(\
343                                                sample2sample_distance_hint)
344        self.sample2sample_distance_sizer.AddMany([(sample2sample_distance_txt, 
345                                               0, wx.LEFT, 15),
346                            (self.sample2sample_distance_tcl, 0, wx.LEFT, 15),
347                            (sample2sample_distance_unit_txt,0, wx.LEFT, 10)]) 
348
349
350
351    def _layout_sample2detector_distance(self):
352        """
353        Fill the sizer containing sample2detector_distance
354        """
355        # get the wavelength
356        sample2detector_distance_value = str(\
357                                    self.resolution.sample2detector_distance[0])
358
359        sample2detector_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
360        sample2detector_distance_txt = wx.StaticText(self, -1, 
361                                'Sample Aperture to Detector Distance: ')
362        self.sample2detector_distance_tcl = InputTextCtrl(self, -1, 
363                                         size=(_BOX_WIDTH,-1))
364        sample2detector_distance_hint = \
365                                "Sample Aperture to Detector Distance"
366        self.sample2detector_distance_tcl.SetValue(\
367                                                sample2detector_distance_value)
368        self.sample2detector_distance_tcl.SetToolTipString(\
369                                                sample2detector_distance_hint)
370        self.sample2detector_distance_sizer.AddMany([\
371                        (sample2detector_distance_txt, 0, wx.LEFT, 15),       
372                        (self.sample2detector_distance_tcl, 0, wx.LEFT, 15),
373                        (sample2detector_distance_unit_txt,0, wx.LEFT, 10)]) 
374       
375    def _layout_detector_size(self):
376        """
377        Fill the sizer containing detector size
378        """
379        # get the wavelength
380        detector_size_value = str(self.resolution.detector_size[0])
381        if len(self.resolution.detector_size)>1:
382            detector_size_value += ", "
383            detector_size_value += str(self.resolution.detector_size[1])
384        detector_size_unit_txt = wx.StaticText(self, -1, '')
385        detector_size_txt = wx.StaticText(self, -1, 
386                                'Number of Pixels on Detector: ')
387        self.detector_size_tcl = InputTextCtrl(self, -1, 
388                                         size=(_BOX_WIDTH,-1))
389        detector_size_hint = "Number of Pixels on Detector"
390        self.detector_size_tcl.SetValue(detector_size_value)
391        self.detector_size_tcl.SetToolTipString(detector_size_hint)
392        self.detector_size_sizer.AddMany([(detector_size_txt, 0, 
393                                               wx.LEFT, 15),
394                                (self.detector_size_tcl, 0, wx.LEFT, 15),
395                                    (detector_size_unit_txt,0, wx.LEFT, 10)]) 
396
397       
398    def _layout_detector_pix_size(self):
399        """
400        Fill the sizer containing detector pixel size
401        """
402        # get the detector_pix_size
403        detector_pix_size_value = str(self.resolution.detector_pix_size[0])
404        if len(self.resolution.detector_pix_size)>1:
405            detector_pix_size_value += ", "
406            detector_pix_size_value += str(self.resolution.detector_pix_size[1])
407        detector_pix_size_unit_txt = wx.StaticText(self, -1, '[cm]')
408        detector_pix_size_txt = wx.StaticText(self, -1, 
409                                'Detector Pixel Size: ')
410        self.detector_pix_size_tcl = InputTextCtrl(self, -1, 
411                                         size=(_BOX_WIDTH,-1))
412        detector_pix_size_hint = "Detector Pixel Size"
413        self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
414        self.detector_pix_size_tcl.SetToolTipString(detector_pix_size_hint)
415        self.detector_pix_size_sizer.AddMany([(detector_pix_size_txt, 0, 
416                                               wx.LEFT, 15),
417                                (self.detector_pix_size_tcl, 0, wx.LEFT, 15),
418                                (detector_pix_size_unit_txt,0, wx.LEFT, 10)])
419       
420    def _layout_input(self):
421        """
422        Fill the sizer containing inputs; qx, qy
423        """
424       
425        q_title = wx.StaticText(self, -1, 
426                            "[Q Location of the Estimation]:")
427        # sizers for inputs
428        inputQx_sizer = wx.BoxSizer(wx.HORIZONTAL)
429        inputQy_sizer = wx.BoxSizer(wx.HORIZONTAL)
430        # get the default dq
431        qx_value = str(_Q_DEFAULT)
432        qy_value = str(_Q_DEFAULT)
433        qx_unit_txt = wx.StaticText(self, -1, '[1/A]  ')
434        qy_unit_txt = wx.StaticText(self, -1, '[1/A]  ')
435        qx_name_txt = wx.StaticText(self, -1, 
436                                'Qx: ')
437        qy_name_txt = wx.StaticText(self, -1, 
438                                'Qy: ')
439        self.qx_tcl = InputTextCtrl(self, -1, 
440                                         size=(_BOX_WIDTH*3,-1))
441        self.qy_tcl = InputTextCtrl(self, -1, 
442                                         size=(_BOX_WIDTH*3,-1))
443        qx_hint = "Type the Qx value."
444        qy_hint = "Type the Qy value."
445        self.qx_tcl.SetValue(qx_value)
446        self.qy_tcl.SetValue(qy_value)
447        self.qx_tcl.SetToolTipString(qx_hint)
448        self.qy_tcl.SetToolTipString(qy_hint)
449        inputQx_sizer.AddMany([(qx_name_txt, 0, wx.LEFT, 15),
450                                    (self.qx_tcl, 0, wx.LEFT, 15),
451                                    (qx_unit_txt, 0, wx.LEFT, 15)])
452        inputQy_sizer.AddMany([(qy_name_txt, 0, wx.LEFT, 15),
453                                    (self.qy_tcl, 0, wx.LEFT, 15),
454                                    (qy_unit_txt, 0, wx.LEFT, 15)])
455        self.input_sizer.AddMany([(q_title, 0, wx.LEFT, 15), 
456                                    (inputQx_sizer, 0,
457                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
458                                    (inputQy_sizer, 0, 
459                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
460                                #(self.compute_button, 0, wx.LEFT, 30)])
461       
462    def _layout_output(self):
463        """
464        Fill the sizer containing dQ|| and dQ+
465        """
466        sigma_title = wx.StaticText(self, -1, 
467                        "[Standard Deviation of the Resolution Distribution]:")
468         # sizers for inputs
469        outputQxy_sizer = wx.BoxSizer(wx.HORIZONTAL)
470        outputQ_sizer = wx.BoxSizer(wx.HORIZONTAL)
471        sigma_unit = '['+'1/A' +']'
472        self.sigma_r_txt = wx.StaticText(self, -1, 
473                                           'Sigma_x:   ')
474        self.sigma_r_tcl = OutputTextCtrl(self, -1, 
475                                                 size=(_BOX_WIDTH*0.8,-1))
476        self.sigma_phi_txt = wx.StaticText(self, -1, 
477                                           'Sigma_y:')
478        self.sigma_phi_tcl = OutputTextCtrl(self, -1, 
479                                                 size=(_BOX_WIDTH*0.8,-1))
480        self.sigma_lamd_txt = wx.StaticText(self, -1, 
481                                           'Sigma_lamd:')
482        self.sigma_lamd_tcl = OutputTextCtrl(self, -1, 
483                                                 size=(_BOX_WIDTH*0.7,-1))
484        sigma_1d_txt = wx.StaticText(self, -1, '( 1D:   Sigma:')
485        self.sigma_1d_tcl = OutputTextCtrl(self, -1, 
486                                                 size=(_BOX_WIDTH*0.7,-1))
487        sigmax_hint = " The x component of the geometric resolution,"
488        sigmax_hint +=  " excluding sigma_lamda."
489        sigmay_hint = " The y component of the geometric resolution,"
490        sigmay_hint +=  " excluding sigma_lamda."
491        sigma_hint_lamd = " The wavelength contribution in the radial direction"
492        sigma_hint_lamd += ".\n Note: The phi component is always zero."
493        sigma_hint_1d = " Resolution in 1-dimension (for 1D data)."
494        self.sigma_r_tcl.SetToolTipString(sigmax_hint)
495        self.sigma_phi_tcl.SetToolTipString(sigmay_hint)
496        self.sigma_lamd_tcl.SetToolTipString(sigma_hint_lamd)
497        self.sigma_1d_tcl.SetToolTipString(sigma_hint_1d)
498        sigma_r_unit_txt = wx.StaticText(self, -1, sigma_unit)
499        sigma_phi_unit_txt = wx.StaticText(self, -1, sigma_unit)
500        sigma_lamd_unit_txt = wx.StaticText(self, -1, sigma_unit)
501        sigma_1d_unit_txt = wx.StaticText(self, -1, sigma_unit+' )')
502        outputQxy_sizer.AddMany([(self.sigma_r_txt, 0, wx.LEFT, 15),
503                                    (self.sigma_r_tcl, 0, wx.LEFT, 15),
504                                    (sigma_r_unit_txt, 0, wx.LEFT, 15),
505                                    (self.sigma_phi_txt, 0, wx.LEFT, 15),
506                                    (self.sigma_phi_tcl, 0, wx.LEFT, 15),
507                                    (sigma_phi_unit_txt, 0, wx.LEFT, 15)])
508        outputQ_sizer.AddMany([(self.sigma_lamd_txt, 0, wx.LEFT, 15),
509                                    (self.sigma_lamd_tcl, 0, wx.LEFT, 15),
510                                    (sigma_lamd_unit_txt, 0, wx.LEFT, 15),
511                                    (sigma_1d_txt, 0, wx.LEFT, 15),
512                                    (self.sigma_1d_tcl, 0, wx.LEFT, 15),
513                                    (sigma_1d_unit_txt, 0, wx.LEFT, 15)])
514        self.output_sizer.AddMany([(sigma_title, 0, wx.LEFT, 15), 
515                                    (outputQxy_sizer, 0,
516                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
517                                    (outputQ_sizer, 0, 
518                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
519       
520   
521    def _layout_hint(self):
522        """
523        Fill the sizer containing hint
524        """
525        hint_msg = ""
526        #hint_msg += "This tool is to approximately compute "
527        #hint_msg += "the instrumental resolution (dQ)."
528
529        self.hint_txt = wx.StaticText(self, -1, hint_msg)
530        self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
531   
532    def _layout_button(self): 
533        """
534        Do the layout for the button widgets
535        """ 
536
537        id = wx.NewId()
538        self.reset_button = wx.Button(self, id, "Reset")
539        hint_on_reset = "..."
540        self.reset_button.SetToolTipString(hint_on_reset)
541        self.Bind(wx.EVT_BUTTON, self.on_reset, id=id)
542        #compute button
543        id = wx.NewId()
544        self.compute_button = wx.Button(self, id, "Compute")
545        hint_on_compute = "Compute... Please wait until finished."
546        self.compute_button.SetToolTipString(hint_on_compute)
547        self.Bind(wx.EVT_BUTTON, self.on_compute, id=id)
548        #help button
549        id = wx.NewId()
550        self.help_button = wx.Button(self, id, "HELP")
551        hint_on_help = "Help on using the Resolution Calculator"
552        self.help_button.SetToolTipString(hint_on_help)
553        self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
554        # close button
555        self.bt_close = wx.Button(self, wx.ID_CANCEL,'Close')
556        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
557        self.bt_close.SetToolTipString("Close this window.")
558
559        self.button_sizer.Add((110, -1))
560        self.button_sizer.AddMany([(self.reset_button, 0, wx.LEFT, 50),
561                                   (self.compute_button, 0, wx.LEFT, 15),
562                                   (self.help_button, 0, wx.LEFT, 15),
563                                   (self.bt_close, 0, wx.LEFT, 15)])
564        self.compute_button.SetFocus()
565       
566    def _layout_image(self):
567        """
568        Layout for image plot
569        """
570        color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
571
572        # Contribution by James C.
573        # Instantiate a figure object that will contain our plots.
574        # Make the fig a little smaller than the default
575        self.figure = Figure(figsize=(6.5, 6), facecolor = 'white')
576       
577        # Initialize the figure canvas, mapping the figure object to the plot
578        # engine backend.
579        self.canvas = FigureCanvas(self, wx.ID_ANY, self.figure)
580
581        # Wx-Pylab magic ...
582        # Make our canvas the active figure manager for pylab so that when
583        # pylab plotting statements are executed they will operate on our
584        # canvas and not create a new frame and canvas for display purposes.
585        # This technique allows this application to execute code that uses
586        # pylab stataments to generate plots and embed these plots in our
587        # application window(s).
588        self.fm = FigureManagerBase(self.canvas, 1)
589        _pylab_helpers.Gcf.set_active(self.fm)
590       
591        # Instantiate the matplotlib navigation toolbar and explicitly show it.
592        mpl_toolbar = Toolbar(self.canvas)
593        # Diable pan
594        mpl_toolbar.DeleteToolByPos(3)
595
596        # Add a toolbar into the frame
597        mpl_toolbar.Realize()
598
599        # Compute before adding the canvas to the sizer
600        self.on_compute()
601       
602        # Fill up the sizer
603        if IS_WIN:
604            gap = 27
605        else:
606            gap = 13
607        self.vertical_r_sizer.Add(self.canvas, 0, 
608                                       wx.ALL|wx.EXPAND, 2) 
609        self.vertical_r_spacer.Add((0, gap)) 
610        self.vertical_r_spacer.Add(self.vertical_r_sizer, 0, 
611                                       wx.ALL|wx.EXPAND, 2)
612        self.vertical_r_spacer.Add((0, gap)) 
613        self.vertical_r_spacer.Add(wx.StaticLine(self), 0, 
614                                       wx.ALL|wx.EXPAND, 2)
615        self.vertical_r_spacer.Add(mpl_toolbar, 0,  wx.ALL|wx.EXPAND, 2)
616
617       
618    def _do_layout(self):
619        """
620            Draw window layout
621        """
622        #  Title of parameters
623        instrument_txt = wx.StaticText(self, -1, 
624                                '[Instrumental Parameters]:')
625        # Build individual layouts
626        self._define_structure()
627        self._layout_mass()
628        #self._layout_intensity()
629        self._layout_wavelength()
630        self._layout_wavelength_spread()
631        self._layout_source_aperture()
632        self._layout_sample_aperture()
633        self._layout_source2sample_distance()
634        self._layout_sample2detector_distance()
635        self._layout_sample2sample_distance()
636        self._layout_detector_size()
637        self._layout_detector_pix_size()
638        self._layout_input()
639        self._layout_output()
640        self._layout_hint()
641        self._layout_button()
642        # Fill the sizers
643        self.boxsizer_source.AddMany([(instrument_txt, 0,
644                                       wx.EXPAND|wx.LEFT, 15),
645                                      (self.mass_sizer, 0,
646                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
647                                      #(self.intensity_sizer, 0,
648                                      #wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
649                                      (self.wavelength_sizer, 0,
650                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
651                                      (self.wavelength_spread_sizer, 0,
652                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
653                                      (self.source_aperture_sizer, 0,
654                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
655                                      (self.sample_aperture_sizer, 0,
656                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
657                                      (self.source2sample_distance_sizer, 0,
658                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
659                                      (self.sample2detector_distance_sizer, 0,
660                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
661                                      (self.sample2sample_distance_sizer, 0,
662                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
663                                      (self.detector_size_sizer, 0,
664                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
665                                      (self.detector_pix_size_sizer, 0,
666                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
667                                      (wx.StaticLine(self), 0, 
668                                       wx.ALL|wx.EXPAND, 5),
669                                      (self.input_sizer, 0,
670                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
671                                      (wx.StaticLine(self), 0, 
672                                       wx.ALL|wx.EXPAND, 5),
673                                      (self.output_sizer, 0,
674                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
675        self.vertical_l_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
676                                       (wx.StaticLine(self), 0, 
677                                       wx.ALL|wx.EXPAND, 5),
678                                  (self.button_sizer, 0,
679                                    wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
680        self.main_sizer.Add(self.vertical_l_sizer, 0, wx.ALL, 10)
681       
682        # Build image plot layout                     
683        self._layout_image()
684        # Add a vertical static line
685        self.main_sizer.Add( wx.StaticLine(self, -1, (2, 2), 
686                            (2,PANEL_HEIGHT * 0.94), style = wx.LI_VERTICAL))
687        # Add the plot to main sizer
688        self.main_sizer.Add(self.vertical_r_spacer, 0, wx.ALL, 10)
689        self.SetSizer(self.main_sizer)
690        self.SetAutoLayout(True)
691       
692
693    def on_help(self, event):   
694        """
695        Bring up the Resolution calculator Documentation whenever
696        the HELP button is clicked.
697       
698        Calls DocumentationWindow with the path of the location within the
699        documentation tree (after /doc/ ....".  Note that when using old
700        versions of Wx (before 2.9) and thus not the release version of
701        installers, the help comes up at the top level of the file as
702        webbrowser does not pass anything past the # to the browser when it is
703        running "file:///...."
704   
705    :param evt: Triggers on clicking the help button
706    """
707               
708        _TreeLocation = "user/perspectives/calculator/resolution_calculator_help.html"
709        _doc_viewer = DocumentationWindow(self, -1, \
710             _TreeLocation,"Resolution Calculator Help")
711
712    def on_close(self, event):
713        """
714        close the window containing this panel
715        """
716        # get ready for other events
717        if event is not None:
718            event.Skip()
719        # Clear the plot
720        if self.image != None:
721            self.image.clf()
722            # reset image
723            self.image = None
724        # Close panel
725        self.parent.OnClose(None)
726       
727   
728    def on_compute(self, event = None): 
729        """
730        Execute the computation of resolution
731        """
732        wx.CallAfter(self.on_compute_call, event)
733       
734    def on_compute_call(self, event=None):
735        """
736        Execute the computation of resolution
737        """
738        # Skip event for next event
739        if event != None:
740            event.Skip()
741            msg = "Please Check your input values "
742            msg += "before starting the computation..."
743
744        # message
745        status_type = 'progress' 
746        msg = 'Calculating...'
747        self._status_info(msg, status_type)
748
749        status_type = 'stop'           
750        # Q min max list default
751        qx_min = []   
752        qx_max = [] 
753        qy_min = [] 
754        qy_max = [] 
755        # possible max qrange
756        self.resolution.qxmin_limit = 0
757        self.resolution.qxmax_limit = 0
758        self.resolution.qymin_limit = 0
759        self.resolution.qymax_limit = 0
760        # q min and max of the detector
761        try:
762            # Get all the values at set to compute
763            # default num bin of wave list
764            self.num_wave = 10
765            wavelength = self._str2longlist(self.wavelength_tcl.GetValue())
766            source = self.source_cb.GetValue()
767            mass = self.source_mass[str(source)]
768            self.resolution.set_neutron_mass(float(mass))
769            wavelength_spread = self._str2longlist(\
770                        self.wavelength_spread_tcl.GetValue().split(';')[0])
771            # Validate the wave inputs
772            wave_input = self._validate_q_input(wavelength, wavelength_spread)
773            if wave_input != None:
774                wavelength, wavelength_spread = wave_input
775   
776            #self.resolution.set_wave(float(wavelength))
777            self.resolution.set_wave(wavelength)
778            #self.resolution.set_wave_spread(float(wavelength_spread))
779            self.resolution.set_wave_spread(wavelength_spread)
780            source_aperture_size = self.source_aperture_tcl.GetValue()
781            source_aperture_size = self._string2list(source_aperture_size)
782            self.resolution.set_source_aperture_size(source_aperture_size)
783            sample_aperture_size = self.sample_aperture_tcl.GetValue()
784            sample_aperture_size = self._string2list(sample_aperture_size)
785            self.resolution.set_sample_aperture_size(sample_aperture_size)
786            source2sample_distance = self.source2sample_distance_tcl.GetValue()
787            source2sample_distance = self._string2list(source2sample_distance)
788            self.resolution.set_source2sample_distance(source2sample_distance)
789            sample2sample_distance = self.sample2sample_distance_tcl.GetValue()
790            sample2sample_distance = self._string2list(sample2sample_distance)
791            self.resolution.set_sample2sample_distance(sample2sample_distance)
792            sample2detector_distance = \
793                                self.sample2detector_distance_tcl.GetValue()
794            sample2detector_distance = \
795                                self._string2list(sample2detector_distance)
796            self.resolution.set_sample2detector_distance(\
797                                                    sample2detector_distance)
798            detector_size = self.detector_size_tcl.GetValue()
799            detector_size = self._string2list(detector_size)
800            self.resolution.set_detector_size(detector_size)
801            detector_pix_size = self.detector_pix_size_tcl.GetValue()
802            detector_pix_size = self._string2list(detector_pix_size)
803            self.resolution.set_detector_pix_size(detector_pix_size)
804            self.qx = self._string2inputlist(self.qx_tcl.GetValue())
805            self.qy = self._string2inputlist(self.qy_tcl.GetValue())
806           
807           
808            # Find min max of qs
809            xmin = min(self.qx)
810            xmax = max(self.qx)
811            ymin = min(self.qy)
812            ymax = max(self.qy)
813            if not self._validate_q_input(self.qx, self.qy):
814                raise
815        except:
816            msg = "An error occured during the resolution computation."
817            msg += "Please check your inputs..."
818            self._status_info(msg, status_type)
819            wx.MessageBox(msg, 'Warning')
820            return
821            #raise ValueError, "Invalid Q Input..."
822
823        # Validate the q inputs
824        q_input = self._validate_q_input(self.qx, self.qy)
825        if q_input != None:
826            self.qx, self.qy = q_input
827       
828        # Make list of q min max for mapping
829        for length in range(len(self.qx)):
830            qx_min.append(xmin)
831            qx_max.append(xmax)
832        for length in range(len(self.qy)):
833            qy_min.append(ymin)
834            qy_max.append(ymax)
835       
836        # Compute the resolution
837        if self.image != None:
838            #_pylab_helpers.Gcf.set_active(self.fm)
839            _pylab_helpers.Gcf.figs = {}
840            # Clear the image before redraw
841            self.image.clf()
842            # reset the image
843            self.resolution.reset_image()
844
845        # Compute and get the image plot
846        try:
847            from sas.perspectives.calculator.resolcal_thread \
848                                                import CalcRes as thread
849            self.sigma_strings = '\nResolution: Computation is finished. \n'
850            cal_res = thread(func = self._map_func,
851                         qx = self.qx,
852                         qy = self.qy,
853                         qx_min = qx_min,
854                         qx_max = qx_max,
855                         qy_min = qy_min,
856                         qy_max = qy_max,
857                         image = self.image,
858                         completefn = self.complete)
859            #self.image = map(self._map_func, self.qx, self.qy,
860            #                 qx_min, qx_max, qy_min, qy_max)[0]
861            cal_res.queue()
862            msg = "Computation is in progress..."
863            #msg = "Finished the resolution computation..."
864            status_type = 'progress'
865            self._status_info(msg, status_type)
866        except:
867            raise
868           
869    def complete(self, image, elapsed=None):
870        """
871        Callafter complete: wx call after needed for stable output
872        """
873        wx.CallAfter(self.complete_cal, image, elapsed)   
874       
875    def complete_cal(self, image, elapsed=None):
876        """
877        Complete computation
878        """
879        self.image = image
880        # Draw lines in image before drawing
881        wave_list, _ = self.resolution.get_wave_list()
882        if len(wave_list) > 1 and wave_list[-1] == max(wave_list):
883            # draw a green rectangle(limit for the longest wavelength
884            # to be involved) for tof inputs
885            self._draw_lines(self.image, color='g')
886        self._draw_lines(self.image, color='r')
887        # Draw image
888        self.image.draw()
889        #self.vertical_r_sizer.Layout()
890       
891        # Get and format the sigmas
892        sigma_r = self.format_number(self.resolution.sigma_1)
893        sigma_phi = self.format_number(self.resolution.sigma_2)
894        sigma_lamd = self.format_number(self.resolution.sigma_lamd)
895        sigma_1d =  self.format_number(self.resolution.sigma_1d)
896
897        # Set output values
898        self.sigma_r_tcl.SetValue(str(sigma_r))
899        self.sigma_phi_tcl.SetValue(str(sigma_phi))
900        self.sigma_lamd_tcl.SetValue(str(sigma_lamd))
901        self.sigma_1d_tcl.SetValue(str(sigma_1d))
902        msg = self.sigma_strings
903        msg += "\n"
904        status_type = 'stop'
905        self._status_info(msg, status_type)
906       
907    def _draw_lines(self, image=None, color='r'):
908        """
909        Draw lines in image if applicable
910        : Param image: pylab object
911        """
912        if image == None:
913            return
914        if color == 'g':
915            # Get the params from resolution
916            # ploting range for largest wavelength
917            qx_min = self.resolution.qx_min
918            qx_max = self.resolution.qx_max
919            qy_min = self.resolution.qy_min
920            qy_max = self.resolution.qy_max
921            # detector range
922            detector_qx_min = self.resolution.detector_qx_min
923            detector_qx_max = self.resolution.detector_qx_max
924            detector_qy_min = self.resolution.detector_qy_min
925            detector_qy_max = self.resolution.detector_qy_max
926        else:
927            qx_min, qx_max, qy_min, qy_max = \
928                                self.resolution.get_detector_qrange()
929            # detector range
930            detector_qx_min = self.resolution.qxmin_limit
931            detector_qx_max = self.resolution.qxmax_limit
932            detector_qy_min = self.resolution.qymin_limit
933            detector_qy_max = self.resolution.qymax_limit
934
935        # Draw zero axis lines
936        if qy_min < 0 and qy_max >= 0:
937            image.axhline(linewidth = 1)
938        if qx_min < 0 and qx_max >= 0:
939            image.axvline(linewidth = 1)
940           
941        # Find x and y ratio values to draw the detector outline
942        x_min = fabs(detector_qx_min - qx_min) / (qx_max - qx_min)
943        x_max = fabs(detector_qx_max - qx_min) / (qx_max - qx_min)
944        y_min = fabs(detector_qy_min - qy_min) / (qy_max - qy_min)
945        y_max = fabs(detector_qy_max - qy_min) / (qy_max - qy_min)
946
947        # Draw Detector outline
948        if detector_qy_min >= qy_min:
949            image.axhline(y = detector_qy_min + 0.0002,
950                               xmin = x_min,
951                               xmax = x_max, 
952                               linewidth = 2, color=color)
953        if detector_qy_max <= qy_max:
954            image.axhline(y = detector_qy_max - 0.0002, 
955                               xmin = x_min, 
956                               xmax = x_max, 
957                               linewidth = 2, color=color)
958        if detector_qx_min >= qx_min:
959            image.axvline(x = detector_qx_min + 0.0002, 
960                               ymin = y_min, 
961                               ymax = y_max, 
962                               linewidth = 2, color=color)
963        if detector_qx_max <= qx_max:
964            image.axvline(x = detector_qx_max - 0.0002, 
965                               ymin = y_min, 
966                               ymax = y_max, 
967                               linewidth = 2, color=color)
968        xmin = min(self.qx)
969        xmax = max(self.qx)
970        ymin = min(self.qy)
971        ymax = max(self.qy)
972        if color != 'g':
973            if xmin < detector_qx_min or xmax > detector_qx_max or \
974                        ymin < detector_qy_min or ymax > detector_qy_max:
975                # message
976                status_type = 'stop' 
977                msg = 'At least one q value located out side of\n'
978                msg += " the detector range (%s < qx < %s, %s < qy < %s),\n" % \
979                        (self.format_number(detector_qx_min), 
980                         self.format_number(detector_qx_max),
981                         self.format_number(detector_qy_min), 
982                         self.format_number(detector_qy_max))
983                msg += " is ignored in computation.\n"
984               
985                self._status_info(msg, status_type)
986                wx.MessageBox(msg, 'Warning')
987       
988    def _map_func(self, qx, qy, qx_min, qx_max, qy_min, qy_max):   
989        """
990        Prepare the Mapping for the computation
991        : params qx, qy, qx_min, qx_max, qy_min, qy_max:
992       
993        : return: image (pylab)
994        """
995        try:
996            qx_value = float(qx)
997            qy_value = float(qy)
998        except:
999            raise
1000        # calculate 2D resolution distribution image
1001        image = self.resolution.compute_and_plot(qx_value, qy_value, 
1002                                 qx_min, qx_max, qy_min, qy_max, 
1003                                 self.det_coordinate)
1004        # record sigmas
1005        self.sigma_strings += " At Qx = %s, Qy = %s; \n"% (qx_value, qy_value)
1006        self._sigma_strings()
1007        return image
1008    def _sigma_strings(self):
1009        """
1010        Recode sigmas as strins
1011        """
1012        sigma_r = self.format_number(self.resolution.sigma_1)
1013        sigma_phi = self.format_number(self.resolution.sigma_2)
1014        sigma_lamd = self.format_number(self.resolution.sigma_lamd)
1015        sigma_1d =  self.format_number(self.resolution.sigma_1d)
1016        # Set output values
1017        self.sigma_strings += "   sigma_x = %s\n"% sigma_r
1018        self.sigma_strings += "   sigma_y = %s\n"% sigma_phi
1019        self.sigma_strings += "   sigma_lamd = %s\n"% sigma_lamd
1020        self.sigma_strings += "   sigma_1D = %s\n"% sigma_1d
1021   
1022    def _validate_q_input(self, qx, qy):   
1023        """
1024        Check if q inputs are valid
1025        : params qx:  qx as a list
1026        : params qy:  qy as a list
1027       
1028        : return: True/False
1029        """
1030        # check qualifications
1031        if qx.__class__.__name__ != 'list':
1032            return None
1033        if qy.__class__.__name__ != 'list' :
1034            return None
1035        if len(qx) < 1:
1036            return None
1037        if len(qy) < 1:
1038            return None
1039        # allow one input
1040        if len(qx) == 1 and len(qy) > 1:
1041            qx = [qx[0] for ind in range(len(qy))]
1042            #self.qx = qx
1043        if len(qy) == 1 and len(qx) > 1:
1044            qy = [qy[0] for ind in range(len(qx))]
1045            #self.qy = qy
1046        # check length
1047        if len(qx) != len(qy):
1048            return None
1049        if qx == None or qy == None:
1050            return None
1051        return qx, qy
1052     
1053    def on_reset(self, event):
1054        """
1055        Execute the reset
1056        """
1057        # skip for another event
1058        if event != None:
1059            event.Skip() 
1060        # init resolution_calculator
1061        self.resolution = ResolutionCalculator()
1062        self.resolution.get_all_instrument_params()
1063        # reset all param values
1064        self.source_cb.SetValue('Neutron')
1065        self._on_source_selection(None)
1066        self.wave_color_cb.SetValue('Monochromatic')
1067        self._on_source_color(None)
1068        #self.intensity_tcl.SetValue(str(self.resolution.intensity))
1069        self.wavelength_tcl.SetValue(str(6.0))
1070        self.wavelength_spread_tcl.SetValue(str(0.125))
1071        self.resolution.set_spectrum(self.spectrum_dic['Flat'])
1072        self.spectrum_txt.Show(False)
1073        self.spectrum_cb.Show(False)
1074        source_aperture_value = str(self.resolution.source_aperture_size[0])
1075        if len(self.resolution.source_aperture_size)>1:
1076            source_aperture_value += ", "
1077            source_aperture_value += \
1078                str(self.resolution.source_aperture_size[1])
1079        self.source_aperture_tcl.SetValue(str(source_aperture_value))
1080        sample_aperture_value = str(self.resolution.sample_aperture_size[0])
1081        if len(self.resolution.sample_aperture_size)>1:
1082            sample_aperture_value += ", "
1083            sample_aperture_value += \
1084                str(self.resolution.sample_aperture_size[1])
1085        self.sample_aperture_tcl.SetValue(sample_aperture_value)
1086        source2sample_distance_value = \
1087            str(self.resolution.source2sample_distance[0])
1088        self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
1089        sample2sample_distance_value = \
1090            str(self.resolution.sample2sample_distance[0])
1091        self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
1092        sample2detector_distance_value = \
1093            str(self.resolution.sample2detector_distance[0])
1094        self.sample2detector_distance_tcl.SetValue(\
1095                                            sample2detector_distance_value)
1096        detector_size_value = str(self.resolution.detector_size[0])
1097        if len(self.resolution.detector_size)>1:
1098            detector_size_value += ", "
1099            detector_size_value += str(self.resolution.detector_size[1])
1100        self.detector_size_tcl.SetValue(detector_size_value)
1101        detector_pix_size_value = str(self.resolution.detector_pix_size[0])
1102        if len(self.resolution.detector_pix_size)>1:
1103            detector_pix_size_value += ", "
1104            detector_pix_size_value += str(self.resolution.detector_pix_size[1])
1105        self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
1106        #layout attribute
1107        self.hint_sizer = None
1108        # reset q inputs
1109        self.qx_tcl.SetValue(str(_Q_DEFAULT))
1110        self.qy_tcl.SetValue(str(_Q_DEFAULT))
1111        # reset sigma outputs
1112        self.sigma_r_tcl.SetValue('')
1113        self.sigma_phi_tcl.SetValue('')
1114        self.sigma_1d_tcl.SetValue('')
1115        # reset radio button
1116        #self.r_phi_rb.SetValue(True)
1117        # Finally re-compute
1118        self.on_compute()
1119        # msg on info
1120        msg = " Finished the resetting..."
1121        self._status_info(msg, 'stop')
1122       
1123    def format_number(self, value=None):
1124        """
1125        Return a float in a standardized, human-readable formatted string
1126        """
1127        try: 
1128            value = float(value)
1129        except:
1130            output = None
1131            return output
1132
1133        output = "%-7.4g" % value
1134        return output.lstrip().rstrip() 
1135     
1136    def _string2list(self, string):
1137        """
1138        Change NNN, NNN to list,ie. [NNN, NNN] where NNN is a number
1139        """
1140        new_string = []
1141        # check the number of floats
1142        try:
1143            strg = float(string)
1144            new_string.append(strg)
1145            #new_string.append(0)
1146        except:
1147            string_split = string.split(',')
1148            if len(string_split) == 2:
1149                str_1 = string_split[0]
1150                str_2 = string_split[1]
1151                new_string.append(float(str_1))
1152                new_string.append(float(str_2))
1153            elif len(string_split) == 1:
1154                str_1 = string_split[0]
1155                new_string.append(float(str_1))
1156            else:
1157                msg = "The numbers must be one or two (separated by ',')..."
1158                self._status_info(msg, 'stop')
1159                raise RuntimeError, msg
1160
1161        return new_string
1162   
1163    def _string2inputlist(self, string):
1164        """
1165        Change NNN, NNN,... to list,ie. [NNN, NNN,...] where NNN is a number
1166       
1167        : return new_string: string like list
1168        """
1169        new_string = []
1170        string_split = string.split(',')
1171        length = len(string_split)
1172        for ind in range(length):
1173            try:
1174                value = float(string_split[ind])
1175                new_string.append(value)
1176            except:
1177                pass
1178       
1179        return new_string
1180   
1181    def _str2longlist(self, string):
1182        """
1183        Change NNN, NNN,... to list, NNN - NNN ; NNN to list, or float to list
1184       
1185        : return new_string: string like list
1186        """
1187        #new_string = []
1188        msg = "Wrong format of intputs."
1189        try:
1190            # is float
1191            out = [float(string)]
1192            return out
1193        except:
1194            if self.wave_color.lower().count('mono') > 0:
1195                wx.MessageBox(msg, 'Warning')
1196            else:
1197                try:
1198                    # has a '-'
1199                    if string.count('-') > 0:
1200                        value = string.split('-')
1201                        if value[1].count(';') > 0:
1202                            # has a ';'
1203                            last_list = value[1].split(';')
1204                            num =  math.ceil(float(last_list[1]))
1205                            max = float(last_list[0])
1206                            self.num_wave = num
1207                        else:
1208                            # default num
1209                            num = self.num_wave
1210                            max = float(value[1])
1211                        min = float(value[0])
1212                        # make a list
1213                        bin_size = math.fabs(max - min) / (num - 1)
1214                        out = [min + bin_size * bnum for bnum in range(num)]
1215                        return out
1216                    if string.count(',') > 0:
1217                        out = self._string2inputlist(string)
1218                        return out
1219                except:
1220                    pass
1221                #    wx.MessageBox(msg, 'Warning')
1222
1223    def _on_xy_coordinate(self, event=None):
1224        """
1225        Set the detector coordinate for sigmas to x-y coordinate
1226        """
1227        if event != None:
1228            event.Skip()       
1229        # Set the coordinate in Cartesian       
1230        self.det_coordinate = 'cartesian'
1231        self.sigma_r_txt.SetLabel('Sigma_x:')
1232        self.sigma_phi_txt.SetLabel('Sigma_y:')
1233        self._onparamEnter()
1234       
1235    def _on_rp_coordinate(self, event=None):
1236        """
1237        Set the detector coordinate for sigmas to polar coordinate
1238        """
1239        if event != None:
1240            event.Skip()       
1241        # Set the coordinate in polar           
1242        self.det_coordinate = 'polar'
1243        self.sigma_r_txt.SetLabel('Sigma_r:   ')
1244        self.sigma_phi_txt.SetLabel('Sigma_phi:')
1245        self._onparamEnter()
1246       
1247    def _status_info(self, msg = '', type = "update"):
1248        """
1249        Status msg
1250        """
1251        if type == "stop":
1252            label = "Compute"
1253            able = True
1254        else:   
1255            label = "Wait..."
1256            able = False
1257        self.compute_button.Enable(able)
1258        self.compute_button.SetLabel(label)
1259        self.compute_button.SetToolTipString(label)
1260        if self.parent.parent != None:
1261            wx.PostEvent(self.parent.parent, 
1262                             StatusEvent(status = msg, type = type ))
1263
1264
1265    def _onparamEnter(self, event = None):
1266        """
1267        On Text_enter_callback, perform compute
1268        """
1269        self.on_compute()
1270       
1271    def _on_source_selection(self, event = None):
1272        """
1273        On source combobox selection
1274        """
1275        if event != None:
1276            combo = event.GetEventObject()
1277            event.Skip()
1278        else:
1279            combo = self.source_cb
1280        selection = combo.GetValue()
1281        mass = self.source_mass[selection]
1282        self.resolution.set_neutron_mass(mass)   
1283        source_hint = "Source Selection: Affect on"
1284        source_hint += " the gravitational contribution.\n"
1285        source_hint += "Mass of %s: m = %s [g]" % \
1286                            (selection, str(self.resolution.get_neutron_mass()))
1287        #source_tip.SetTip(source_hint)
1288        self.mass_txt.ToolTip.SetTip(source_hint)
1289       
1290    def _on_source_color(self, event = None):
1291        """
1292        On source color combobox selection
1293        """
1294        if event != None:
1295            #combo = event.GetEventObject()
1296            event.Skip()
1297        #else:
1298        combo = self.wave_color_cb
1299        selection = combo.GetValue()
1300        self.wave_color = selection
1301        if self.wave_color.lower() == 'tof':
1302            list = self.resolution.get_wave_list()
1303            minw = min(list[0])
1304            if len(list[0]) < 2:
1305                maxw = 2 * minw
1306            else:
1307                maxw = max(list[0])
1308            self.wavelength_tcl.SetValue('%s - %s' % (minw, maxw))
1309            minw = min(list[1])
1310            maxw = max(list[1])
1311            self.wavelength_spread_tcl.SetValue('%s - %s' % (minw, maxw))
1312            spectrum_val = self.spectrum_cb.GetValue()
1313            self.resolution.set_spectrum(self.spectrum_dic[spectrum_val])
1314            self.spectrum_txt.Show(True)
1315            self.spectrum_cb.Show(True)
1316         
1317        else:
1318            wavelength = self.resolution.get_wavelength()
1319            wavelength_spread = self.resolution.get_wavelength_spread()
1320            self.wavelength_tcl.SetValue(str(wavelength))
1321            self.wavelength_spread_tcl.SetValue(str(wavelength_spread))
1322            self.resolution.set_spectrum(self.spectrum_dic['Flat'])
1323            self.spectrum_txt.Show(False)
1324            self.spectrum_cb.Show(False)
1325        self.wavelength_sizer.Layout() 
1326        self.Layout()
1327       
1328    def _on_spectrum_cb(self, event=None):
1329        """
1330        On spectrum ComboBox event
1331        """
1332        if event != None:
1333            #combo = event.GetEventObject()
1334            event.Skip()
1335        else:
1336            raise
1337        selection = self.spectrum_cb.GetValue()
1338        if selection == 'Add new':
1339            path = self._selectDlg()
1340            if path == None:
1341                self.spectrum_cb.SetValue('Flat')
1342                self.resolution.set_spectrum(self.spectrum_dic['Flat'])
1343                msg = "No file has been chosen."
1344                wx.MessageBox(msg, 'Info')
1345                return
1346            try:
1347                basename  = os.path.basename(path)
1348                if basename not in self.spectrum_dic.keys():
1349                    self.spectrum_cb.Append(basename)
1350                self.spectrum_dic[basename] = self._read_file(path)
1351                self.spectrum_cb.SetValue(basename)
1352                self.resolution.set_spectrum(self.spectrum_dic[basename])
1353                return
1354            except:
1355                raise
1356       
1357        self.resolution.set_spectrum(self.spectrum_dic[selection])
1358                             
1359    def _selectDlg(self):
1360        """
1361        open a dialog file to select a customized spectrum
1362        """
1363        dlg = wx.FileDialog(self, 
1364                "Choose a wavelength spectrum file: Intensity vs. wavelength",
1365                self.parent.parent.get_save_location() , "", 
1366                "*.*", wx.OPEN)
1367        path = None
1368        if dlg.ShowModal() == wx.ID_OK:
1369            path = dlg.GetPath()
1370        dlg.Destroy()
1371        return path
1372       
1373    def _read_file(self, path):
1374        """
1375        Read two columns file as tuples of numpy array
1376       
1377        :param path: the path to the file to read
1378       
1379        """
1380        try:
1381            if path == None:
1382                wx.PostEvent(self.parent.parent, StatusEvent(status=\
1383                            " Selected Distribution was not loaded: %s"%path))
1384                return None, None
1385            input_f = open(path, 'r')
1386            buff = input_f.read()
1387            lines = buff.split('\n')
1388           
1389            wavelength = []
1390            intensity = []
1391            for line in lines:
1392                toks = line.split()
1393                try:
1394                    wave = float(toks[0])
1395                    intens = float(toks[1])
1396                    wavelength.append(wave)
1397                    intensity.append(intens)
1398                except:
1399                    # Skip non-data lines
1400                    pass
1401               
1402            return [wavelength, intensity]
1403        except:
1404            raise 
1405       
1406class ResolutionWindow(widget.CHILD_FRAME):
1407    """
1408    Resolution Window
1409    """
1410    def __init__(self, parent = None, manager=None, 
1411                 title = "SAS Resolution Estimator",
1412                 size=(PANEL_WIDTH * 2, PANEL_HEIGHT), *args, **kwds):
1413        kwds['title'] = title
1414        kwds['size'] = size
1415        widget.CHILD_FRAME.__init__(self, parent=parent, *args, **kwds)
1416        self.parent = parent
1417        self.manager = manager
1418        self.panel = ResolutionCalculatorPanel(parent=self)
1419        self.Bind(wx.EVT_CLOSE, self.OnClose)
1420        self.SetPosition((25, 10))
1421        self.Show(True)
1422   
1423    def OnClose(self, event): 
1424        """
1425        On close event
1426        """
1427        _pylab_helpers.Gcf.figs = {}
1428        if self.manager != None:
1429            self.manager.cal_res_frame = None
1430        self.Destroy() 
1431
1432       
1433if __name__ == "__main__": 
1434    app = wx.PySimpleApp()
1435    widget.CHILD_FRAME = wx.Frame
1436    frame = ResolutionWindow()   
1437    frame.Show(True)
1438    app.MainLoop()     
Note: See TracBrowser for help on using the repository browser.