source: sasview/src/sas/sasgui/perspectives/calculator/sld_panel.py @ d619341

Last change on this file since d619341 was d0248bd, checked in by butler, 9 years ago

linked new help to all Tools menu panels remaining.

  • Property mode set to 100644
File size: 21.1 KB
Line 
1"""
2This module provide GUI for the neutron scattering length density calculator
3
4"""
5
6import wx
7import math
8import sys
9
10from sas.sasgui.guiframe.panel_base import PanelBase
11
12from sas.sasgui.guiframe.utils import format_number
13from sas.sasgui.guiframe.utils import check_float
14from sas.sasgui.guiframe.events import StatusEvent
15
16# the calculator default value for wavelength is 6
17#import periodictable
18from periodictable import formula
19from periodictable.xsf import xray_energy
20from periodictable.xsf import xray_sld_from_atoms
21from periodictable.nsf import neutron_scattering
22from sas.sasgui.perspectives.calculator import calculator_widgets as widget
23from sas.sasgui.guiframe.documentation_window import DocumentationWindow
24
25WAVELENGTH = 6.0
26_BOX_WIDTH = 76
27_STATICBOX_WIDTH = 350
28_SCALE = 1e-6
29
30#SLD panel size
31if sys.platform.count("win32") > 0:
32    PANEL_TOP = 0
33    _STATICBOX_WIDTH = 350
34    PANEL_SIZE = 400
35    FONT_VARIANT = 0
36else:
37    PANEL_TOP = 60
38    _STATICBOX_WIDTH = 380
39    PANEL_SIZE = 410
40    FONT_VARIANT = 1
41
42class SldPanel(wx.Panel, PanelBase):
43    """
44    Provides the SLD calculator GUI.
45    """
46    ## Internal nickname for the window, used by the AUI manager
47    window_name = "SLD Calculator"
48    ## Name to appear on the window title bar
49    window_caption = "SLD Calculator"
50    ## Flag to tell the AUI manager to put this panel in the center pane
51    CENTER_PANE = True
52
53    def __init__(self, parent, base=None, *args, **kwds):
54        """
55        """
56        wx.Panel.__init__(self, parent, *args, **kwds)
57        PanelBase.__init__(self)
58        #Font size
59        self.SetWindowVariant(variant=FONT_VARIANT)
60        # Object that receive status event
61        self.base = base
62        self.wavelength = WAVELENGTH
63        self.parent = parent
64        #layout attribute
65        self.compound_ctl = None
66        self.density_ctl = None
67        self.compound = ""
68        self.density = ""
69        self.wavelength_ctl = None
70        self.neutron_sld_real_ctl = None
71        self.neutron_sld_im_ctl = None
72        self.mo_ka_sld_real_ctl = None
73        self.mo_ka_sld_im_ctl = None
74        self.cu_ka_sld_real_ctl = None
75        self.cu_ka_sld_im_ctl = None
76        self.neutron_abs_ctl = None
77        self.neutron_inc_ctl = None
78        self.neutron_length_ctl = None
79        self.button_calculate = None
80        #Draw the panel
81        self._do_layout()
82        self.SetAutoLayout(True)
83        self.Layout()
84
85    def _do_layout(self):
86        """
87        Draw window content
88        """
89        unit_a = '[A]'
90        unit_density = '[g/cm^(3)]'
91        unit_sld = '[1/A^(2)]'
92        unit_cm1 = '[1/cm]'
93        unit_cm = '[cm]'
94        sizer_input = wx.GridBagSizer(5, 5)
95        sizer_output = wx.GridBagSizer(5, 5)
96        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
97        sizer1 = wx.BoxSizer(wx.HORIZONTAL)
98        sizer2 = wx.BoxSizer(wx.HORIZONTAL)
99        sizer3 = wx.BoxSizer(wx.HORIZONTAL)
100        #---------inputs----------------
101        inputbox = wx.StaticBox(self, -1, "Input")
102        boxsizer1 = wx.StaticBoxSizer(inputbox, wx.VERTICAL)
103        boxsizer1.SetMinSize((_STATICBOX_WIDTH, -1))
104
105        compound_txt = wx.StaticText(self, -1, 'Compound ')
106        self.compound_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH * 2, -1))
107        density_txt = wx.StaticText(self, -1, 'Density ')
108        self.density_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
109        unit_density_txt = wx.StaticText(self, -1, unit_density)
110        wavelength_txt = wx.StaticText(self, -1, 'Wavelength ')
111        self.wavelength_ctl = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, -1))
112        self.wavelength_ctl.SetValue(str(self.wavelength))
113        unit_a_txt = wx.StaticText(self, -1, unit_a)
114        iy = 0
115        ix = 0
116        sizer_input.Add(compound_txt, (iy, ix), (1, 1),
117                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
118        ix += 1
119        sizer_input.Add(self.compound_ctl, (iy, ix), (1, 1),
120                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
121        iy += 1
122        ix = 0
123        sizer_input.Add(density_txt, (iy, ix), (1, 1),
124                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
125        ix += 1
126        sizer_input.Add(self.density_ctl, (iy, ix), (1, 1),
127                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
128        ix += 1
129        sizer_input.Add(unit_density_txt, (iy, ix), (1, 1),
130                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
131        iy += 1
132        ix = 0
133        sizer_input.Add(wavelength_txt, (iy, ix), (1, 1),
134                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
135        ix += 1
136        sizer_input.Add(self.wavelength_ctl, (iy, ix), (1, 1),
137                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
138        ix += 1
139        sizer_input.Add(unit_a_txt, (iy, ix), (1, 1),
140                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
141        boxsizer1.Add(sizer_input)
142        sizer1.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
143        #---------Outputs sizer--------
144        outputbox = wx.StaticBox(self, -1, "Output")
145        boxsizer2 = wx.StaticBoxSizer(outputbox, wx.VERTICAL)
146        boxsizer2.SetMinSize((_STATICBOX_WIDTH, -1))
147
148        i_complex = '- i'
149        neutron_sld_txt = wx.StaticText(self, -1, 'Neutron SLD')
150        self.neutron_sld_real_ctl = wx.TextCtrl(self, -1,
151                                                 size=(_BOX_WIDTH, -1))
152        self.neutron_sld_real_ctl.SetEditable(False)
153        self.neutron_sld_real_ctl.SetToolTipString("Neutron SLD real.")
154        self.neutron_sld_im_ctl = wx.TextCtrl(self, -1,
155                                              size=(_BOX_WIDTH, -1))
156        self.neutron_sld_im_ctl.SetEditable(False)
157        self.neutron_sld_im_ctl.SetToolTipString("Neutron SLD imaginary.")
158        neutron_sld_units_txt = wx.StaticText(self, -1, unit_sld)
159
160        cu_ka_sld_txt = wx.StaticText(self, -1, 'Cu Ka SLD')
161        self.cu_ka_sld_real_ctl = wx.TextCtrl(self, -1,
162                                               size=(_BOX_WIDTH, -1))
163        self.cu_ka_sld_real_ctl.SetEditable(False)
164        self.cu_ka_sld_real_ctl.SetToolTipString("Cu Ka SLD real.")
165        self.cu_ka_sld_im_ctl = wx.TextCtrl(self, -1,
166                                            size=(_BOX_WIDTH, -1))
167        self.cu_ka_sld_im_ctl.SetEditable(False)
168        self.cu_ka_sld_im_ctl.SetToolTipString("Cu Ka SLD imaginary.")
169        cu_ka_sld_units_txt = wx.StaticText(self, -1, unit_sld)
170
171        mo_ka_sld_txt = wx.StaticText(self, -1, 'Mo Ka SLD')
172        self.mo_ka_sld_real_ctl = wx.TextCtrl(self, -1,
173                                               size=(_BOX_WIDTH, -1))
174        self.mo_ka_sld_real_ctl.SetEditable(False)
175        self.mo_ka_sld_real_ctl.SetToolTipString("Mo Ka SLD real.")
176        self.mo_ka_sld_im_ctl = wx.TextCtrl(self, -1,
177                                             size=(_BOX_WIDTH, -1))
178        self.mo_ka_sld_im_ctl.SetEditable(False)
179        self.mo_ka_sld_im_ctl.SetToolTipString("Mo Ka SLD imaginary.")
180        mo_ka_sld_units_txt = wx.StaticText(self, -1, unit_sld)
181
182        neutron_inc_txt = wx.StaticText(self, -1, 'Neutron Inc. Xs')
183        self.neutron_inc_ctl = wx.TextCtrl(self, -1,
184                                            size=(_BOX_WIDTH, -1))
185        self.neutron_inc_ctl.SetEditable(False)
186        self.neutron_inc_ctl.SetToolTipString("Neutron Inc. Xs")
187        neutron_inc_units_txt = wx.StaticText(self, -1, unit_cm1)
188
189        neutron_abs_txt = wx.StaticText(self, -1, 'Neutron Abs. Xs')
190        self.neutron_abs_ctl = wx.TextCtrl(self, -1,
191                                           size=(_BOX_WIDTH, -1))
192        self.neutron_abs_ctl.SetEditable(False)
193        self.neutron_abs_ctl.SetToolTipString("Neutron Abs. Xs")
194        neutron_abs_units_txt = wx.StaticText(self, -1, unit_cm1)
195
196        neutron_length_txt = wx.StaticText(self, -1, 'Neutron 1/e length')
197        self.neutron_length_ctl = wx.TextCtrl(self, -1,
198                                               size=(_BOX_WIDTH, -1))
199        self.neutron_length_ctl.SetEditable(False)
200        self.neutron_length_ctl.SetToolTipString("Neutron 1/e length")
201        neutron_length_units_txt = wx.StaticText(self, -1, unit_cm)
202
203        iy = 0
204        ix = 0
205        sizer_output.Add(neutron_sld_txt, (iy, ix), (1, 1),
206                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
207        ix += 1
208        sizer_output.Add(self.neutron_sld_real_ctl, (iy, ix), (1, 1),
209                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
210        ix += 1
211        sizer_output.Add(wx.StaticText(self, -1, i_complex),
212                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
213        ix += 1
214        sizer_output.Add(self.neutron_sld_im_ctl,
215                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
216        ix += 1
217        sizer_output.Add(neutron_sld_units_txt,
218                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
219        iy += 1
220        ix = 0
221        sizer_output.Add(cu_ka_sld_txt, (iy, ix), (1, 1),
222                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
223        ix += 1
224        sizer_output.Add(self.cu_ka_sld_real_ctl, (iy, ix), (1, 1),
225                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
226        ix += 1
227        sizer_output.Add(wx.StaticText(self, -1, i_complex),
228                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
229        ix += 1
230        sizer_output.Add(self.cu_ka_sld_im_ctl,
231                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
232        ix += 1
233        sizer_output.Add(cu_ka_sld_units_txt,
234                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
235        iy += 1
236        ix = 0
237        sizer_output.Add(mo_ka_sld_txt, (iy, ix), (1, 1),
238                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
239        ix += 1
240        sizer_output.Add(self.mo_ka_sld_real_ctl, (iy, ix), (1, 1),
241                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
242        ix += 1
243        sizer_output.Add(wx.StaticText(self, -1, i_complex),
244                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
245        ix += 1
246        sizer_output.Add(self.mo_ka_sld_im_ctl,
247                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
248        ix += 1
249        sizer_output.Add(mo_ka_sld_units_txt,
250                         (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 0)
251        iy += 1
252        ix = 0
253        sizer_output.Add(neutron_inc_txt, (iy, ix), (1, 1),
254                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
255        ix += 1
256        sizer_output.Add(self.neutron_inc_ctl, (iy, ix), (1, 1),
257                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
258        ix += 2
259        sizer_output.Add(neutron_inc_units_txt, (iy, ix), (1, 1),
260                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
261        iy += 1
262        ix = 0
263        sizer_output.Add(neutron_abs_txt, (iy, ix), (1, 1),
264                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
265        ix += 1
266        sizer_output.Add(self.neutron_abs_ctl, (iy, ix), (1, 1),
267                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
268        ix += 2
269        sizer_output.Add(neutron_abs_units_txt, (iy, ix), (1, 1),
270                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
271        iy += 1
272        ix = 0
273        sizer_output.Add(neutron_length_txt, (iy, ix), (1, 1),
274                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
275        ix += 1
276        sizer_output.Add(self.neutron_length_ctl, (iy, ix), (1, 1),
277                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
278        ix += 2
279        sizer_output.Add(neutron_length_units_txt, (iy, ix), (1, 1),
280                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
281        boxsizer2.Add(sizer_output)
282        sizer2.Add(boxsizer2, 0, wx.EXPAND | wx.ALL, 10)
283        #-----Button  sizer------------
284
285        id = wx.NewId()
286        self.button_calculate = wx.Button(self, id, "Calculate")
287        self.button_calculate.SetToolTipString("Calculate SLD.")
288        self.Bind(wx.EVT_BUTTON, self.calculateSld, id=id)
289
290        id = wx.NewId()
291        self.button_help = wx.Button(self, id, "HELP")
292        self.button_help.SetToolTipString("help on SLD calculator.")
293        self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
294
295        self.button_close = wx.Button(self, wx.ID_CANCEL, 'Close')
296        self.button_close.Bind(wx.EVT_BUTTON, self.on_close)
297        self.button_close.SetToolTipString("Close this window.")
298
299        sizer_button.Add((150, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
300        sizer_button.Add(self.button_calculate, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
301        sizer_button.Add(self.button_help, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
302        sizer_button.Add(self.button_close, 0, wx.RIGHT | wx.ADJUST_MINSIZE, 20)
303        sizer3.Add(sizer_button)
304        #---------layout----------------
305        vbox = wx.BoxSizer(wx.VERTICAL)
306        vbox.Add(sizer1)
307        vbox.Add(sizer2)
308        vbox.Add(sizer3)
309        vbox.Fit(self)
310        self.SetSizer(vbox)
311
312    def on_help(self, event):
313        """
314        Bring up the SLD Documentation whenever
315        the HELP button is clicked.
316
317        Calls DocumentationWindow with the path of the location within the
318        documentation tree (after /doc/ ....".  Note that when using old
319        versions of Wx (before 2.9) and thus not the release version of
320        installers, the help comes up at the top level of the file as
321        webbrowser does not pass anything past the # to the browser when it is
322        running "file:///...."
323
324    :param evt: Triggers on clicking the help button
325    """
326
327        _TreeLocation = "user/sasgui/perspectives/calculator/"
328        _TreeLocation += "sld_calculator_help.html"
329        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
330                                          "General Scattering Calculator Help")
331
332    def on_close(self, event):
333        """
334        close the window containing this panel
335        """
336        self.parent.Close()
337
338    def calculate_xray_sld(self, element):
339        """
340        Get an element and compute the corresponding SLD for a given formula
341
342        :param element:  elements a string of existing atom
343
344        """
345        myformula = formula(str(element))
346        if len(myformula.atoms) != 1:
347            return
348        element = myformula.atoms.keys()[0]
349        energy = xray_energy(element.K_alpha)
350
351        self.sld_formula = formula(str(self.compound), density=self.density)
352        atom = self.sld_formula.atoms
353        return xray_sld_from_atoms(atom, density=self.density, energy=energy)
354
355    def check_inputs(self):
356        """Check validity user inputs"""
357        flag = True
358        msg = ""
359        if check_float(self.density_ctl):
360            self.density = float(self.density_ctl.GetValue())
361        else:
362            flag = False
363            msg += "Error for Density value :expect float"
364
365        self.wavelength = self.wavelength_ctl.GetValue()
366        if str(self.wavelength).lstrip().rstrip() == "":
367            self.wavelength = WAVELENGTH
368            self.wavelength_ctl.SetValue(str(WAVELENGTH))
369            self.wavelength_ctl.SetBackgroundColour(wx.WHITE)
370            self.wavelength_ctl.Refresh()
371            msg += "Default value for wavelength is 6.0"
372        else:
373            if check_float(self.wavelength_ctl):
374                self.wavelength = float(self.wavelength)
375            else:
376                flag = False
377                msg += "Error for wavelength value :expect float"
378
379        self.compound = self.compound_ctl.GetValue().lstrip().rstrip()
380        if self.compound != "":
381            try :
382                formula(self.compound)
383                self.compound_ctl.SetBackgroundColour(wx.WHITE)
384                self.compound_ctl.Refresh()
385            except:
386                self.compound_ctl.SetBackgroundColour("pink")
387                self.compound_ctl.Refresh()
388                flag = False
389                msg += "Enter correct formula"
390        else:
391            self.compound_ctl.SetBackgroundColour("pink")
392            self.compound_ctl.Refresh()
393            flag = False
394            msg += "Enter a formula"
395        return flag, msg
396
397    def calculate_sld_helper(self, element, density, molecule_formula):
398        """
399        Get an element and compute the corresponding SLD for a given formula
400
401        :param element:  elements a string of existing atom
402
403        """
404        element_formula = formula(str(element))
405        if len(element_formula.atoms) != 1:
406            return
407        element = element_formula.atoms.keys()[0]
408        energy = xray_energy(element.K_alpha)
409        atom = molecule_formula.atoms
410        return xray_sld_from_atoms(atom, density=density, energy=energy)
411
412
413    def calculateSld(self, event):
414        """
415            Calculate the neutron scattering density length of a molecule
416        """
417        self.clear_outputs()
418        try:
419            #Check validity user inputs
420            flag, msg = self.check_inputs()
421            if self.base is not None and msg.lstrip().rstrip() != "":
422                msg = "SLD Calculator: %s" % str(msg)
423                wx.PostEvent(self.base, StatusEvent(status=msg))
424            if not flag:
425               return
426            #get ready to compute
427            self.sld_formula = formula(self.compound,
428                                            density=self.density)
429            (sld_real, sld_im, _), (_, absorp, incoh), \
430                        length = neutron_scattering(compound=self.compound,
431                                   density=self.density,
432                                   wavelength=self.wavelength)
433            cu_real, cu_im = self.calculate_sld_helper(element="Cu",
434                                                 density=self.density,
435                                        molecule_formula=self.sld_formula)
436            mo_real, mo_im = self.calculate_sld_helper(element="Mo",
437                                                       density=self.density,
438                                     molecule_formula=self.sld_formula)
439            # set neutron sld values
440            val = format_number(sld_real * _SCALE)
441            self.neutron_sld_real_ctl.SetValue(val)
442            val = format_number(math.fabs(sld_im) * _SCALE)
443            self.neutron_sld_im_ctl.SetValue(val)
444            # Compute the Cu SLD
445            self.cu_ka_sld_real_ctl.SetValue(format_number(cu_real * _SCALE))
446            val = format_number(math.fabs(cu_im) * _SCALE)
447            self.cu_ka_sld_im_ctl.SetValue(val)
448            # Compute the Mo SLD
449            self.mo_ka_sld_real_ctl.SetValue(format_number(mo_real * _SCALE))
450            val = format_number(math.fabs(mo_im) * _SCALE)
451            self.mo_ka_sld_im_ctl.SetValue(val)
452            # set incoherence and absorption
453            self.neutron_inc_ctl.SetValue(format_number(incoh))
454            self.neutron_abs_ctl.SetValue(format_number(absorp))
455            # Neutron length
456            self.neutron_length_ctl.SetValue(format_number(length))
457            # display wavelength
458            self.wavelength_ctl.SetValue(str(self.wavelength))
459        except:
460            if self.base is not None:
461                msg = "SLD Calculator: %s" % (sys.exc_value)
462                wx.PostEvent(self.base, StatusEvent(status=msg))
463        if event is not None:
464            event.Skip()
465
466    def clear_outputs(self):
467        """
468        Clear the outputs textctrl
469        """
470        self.neutron_sld_real_ctl.SetValue("")
471        self.neutron_sld_im_ctl.SetValue("")
472        self.mo_ka_sld_real_ctl.SetValue("")
473        self.mo_ka_sld_im_ctl.SetValue("")
474        self.cu_ka_sld_real_ctl.SetValue("")
475        self.cu_ka_sld_im_ctl.SetValue("")
476        self.neutron_abs_ctl.SetValue("")
477        self.neutron_inc_ctl.SetValue("")
478        self.neutron_length_ctl.SetValue("")
479
480
481class SldWindow(widget.CHILD_FRAME):
482    """
483    """
484    def __init__(self, parent=None, title="SLD Calculator",
485                  base=None, manager=None,
486                  size=(PANEL_SIZE, PANEL_SIZE), *args, **kwds):
487        """
488        """
489        kwds['title'] = title
490        kwds['size'] = size
491        widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
492        """
493        """
494        self.parent = parent
495        self.base = base
496        self.manager = manager
497        self.panel = SldPanel(self, base=base)
498        self.Bind(wx.EVT_CLOSE, self.on_close)
499        self.SetPosition((wx.LEFT, PANEL_TOP))
500        self.Show(True)
501
502    def on_close(self, event):
503        """
504        On close event
505        """
506        if self.manager != None:
507            self.manager.sld_frame = None
508        self.Destroy()
509
510
511class ViewApp(wx.App):
512    """
513    """
514    def OnInit(self):
515        """
516        """
517        widget.CHILD_FRAME = wx.Frame
518        frame = SldWindow(None, title='SLD Calculator')
519        frame.Show(True)
520        self.SetTopWindow(frame)
521        return True
522
523
524if __name__ == "__main__":
525    app = ViewApp(0)
526    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.