source: sasview/calculatorview/src/sans/perspectives/calculator/resolution_calculator_panel.py @ e35534f

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 e35534f was e35534f, checked in by Jae Cho <jhjcho@…>, 11 years ago

default tool windows position changes: mac fixes

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