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

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

Moving things around. Will definitely not build.

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