source: sasview/calculatorview/perspectives/calculator/resolution_calculator_panel.py @ 148f0dd

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

extended rescal to tof

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