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

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 c1bffa5 was af6b53c, checked in by Doucet, Mathieu <doucetm@…>, 10 years ago

pylint fixes

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