source: sasview/src/sas/perspectives/calculator/resolution_calculator_panel.py @ 1ee0772

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 1ee0772 was b9a5f0e, checked in by krzywon, 10 years ago

90% complete with the conversion.

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