source: sasview/src/sas/perspectives/calculator/gen_scatter_panel.py @ b69edaa

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 b69edaa was 3db44fb, checked in by butler, 10 years ago

1) Fixed second issue that was caused by the recent cleanup of
DocumentationWindow?: loading html at anchor point for context help
(broken). In order to preserve the cleanup, the class was refactored to
take another parameter: html instruction string. This keeps it general
to accept not only the # anchor but alos queries of all sorts in the
future. Thus all modules using this class were also edited to match.

2) in process of editing the dozen or so instances did a bit of code
cleanup and pylint cleanup.

  • Property mode set to 100644
File size: 72.7 KB
RevLine 
[318b5bbb]1"""
[49ab5d7]2Generic Scattering panel.
[318b5bbb]3This module relies on guiframe manager.
4"""
5
6import wx
7import sys
8import os
9import numpy
10#import math
11import wx.aui as aui
12#import wx.lib.agw.aui as aui
13import logging
14import time
15
16import matplotlib
17matplotlib.interactive(False)
18#Use the WxAgg back end. The Wx one takes too long to render
19matplotlib.use('WXAgg')
20
[79492222]21#from sas.guiframe.gui_manager import MDIFrame
22from sas.data_util.calcthread import CalcThread
23from sas.guiframe.local_perspectives.plotting.SimplePlot import PlotFrame
[49ab5d7]24from sas.guiframe.dataFitting import Data2D
[79492222]25from sas.guiframe.dataFitting import Data1D
26from sas.dataloader.data_info import Detector
27from sas.dataloader.data_info import Source
28from sas.guiframe.panel_base import PanelBase
29from sas.guiframe.utils import format_number
[49ab5d7]30from sas.guiframe.events import StatusEvent
31from sas.calculator import sas_gen
[79492222]32from sas.perspectives.calculator.calculator_widgets import OutputTextCtrl
33from sas.perspectives.calculator.calculator_widgets import InputTextCtrl
[318b5bbb]34from wx.lib.scrolledpanel import ScrolledPanel
[79492222]35from sas.perspectives.calculator.load_thread import GenReader
36from sas.plottools.arrow3d import Arrow3D
37from sas.perspectives.calculator import calculator_widgets as widget
[49ab5d7]38from sas.guiframe.events import NewPlotEvent
[3f5d75b]39from sas.guiframe.documentation_window import DocumentationWindow
[077207b]40
[318b5bbb]41_BOX_WIDTH = 76
42#Slit length panel size
43if sys.platform.count("win32") > 0:
[60dca65c]44    PANEL_TOP = 0
[318b5bbb]45    PANEL_WIDTH = 570
46    PANEL_HEIGHT = 370
47    FONT_VARIANT = 0
48else:
[d5419f7f]49    PANEL_TOP = 60
[aaaf9b4]50    PANEL_WIDTH = 620
51    PANEL_HEIGHT = 370
[318b5bbb]52    FONT_VARIANT = 1
[077207b]53_QMAX_DEFAULT = 0.3
[49ab5d7]54_NPTS_DEFAULT = 50
[9624cda]55_Q1D_MIN = 0.001
[318b5bbb]56
57def add_icon(parent, frame):
58    """
59    Add icon in the frame
60    """
61    if parent != None:
62        if hasattr(frame, "IsIconized"):
63            if not frame.IsIconized():
64                try:
65                    icon = parent.GetIcon()
66                    frame.SetIcon(icon)
67                except:
[49ab5d7]68                    pass
[318b5bbb]69
70def _set_error(panel, item, show_msg=False):
[49ab5d7]71    """
[318b5bbb]72    Set_error dialog
73    """
74    if item != None:
75        item.SetBackgroundColour("pink")
76        item.Refresh()
77    if show_msg:
[46be5e6]78        msg = "Error: wrong (or out of range) value entered."
[318b5bbb]79        if panel.parent.parent != None:
[49ab5d7]80            wx.PostEvent(panel.parent.parent,
81                     StatusEvent(status=msg, info='Error'))
[318b5bbb]82            panel.SetFocus()
83    return False
84
[3f5d75b]85
86
[318b5bbb]87class CalcGen(CalcThread):
88    """
89    Computation
90    """
91    def __init__(self,
[49ab5d7]92                 id= -1,
93                 input=None,
94                 completefn=None,
95                 updatefn=None,
[9624cda]96                 #elapsed = 0,
[49ab5d7]97                 yieldtime=0.01,
98                 worktime=0.01):
[318b5bbb]99        """
100        """
[cd89c6f]101        CalcThread.__init__(self, completefn,
[318b5bbb]102                 updatefn,
103                 yieldtime,
104                 worktime)
105        self.starttime = 0
[49ab5d7]106        self.id = id
107        self.input = input
[9624cda]108        self.update_fn = updatefn
[49ab5d7]109
[318b5bbb]110    def compute(self):
111        """
112        excuting computation
113        """
[9624cda]114        #elapsed = time.time() - self.starttime
115        self.starttime = time.time()
116        self.complete(input=self.input, update=self.update_fn)
[49ab5d7]117
[318b5bbb]118class SasGenPanel(ScrolledPanel, PanelBase):
119    """
120        Provides the sas gen calculator GUI.
121    """
122    ## Internal nickname for the window, used by the AUI manager
[b9a5f0e]123    window_name = "Generic SAS Calculator"
[318b5bbb]124    ## Name to appear on the window title bar
[b9a5f0e]125    window_caption = "Generic SAS "
[49ab5d7]126
[318b5bbb]127    def __init__(self, parent, *args, **kwds):
[49ab5d7]128        ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER,
[318b5bbb]129                               *args, **kwds)
130        #kwds['style'] = wx.SUNKEN_BORDER
131        PanelBase.__init__(self)
132        #Font size
133        self.SetWindowVariant(variant=FONT_VARIANT)
134        self.SetupScrolling()
135        #thread to read data
136        self.reader = None
137        self.ext = None
[b9a5f0e]138        self.id = 'GenSAS'
[318b5bbb]139        self.file_name = ''
140        self.time_text = None
[3657667]141        self.orient_combo = None
[b9a5f0e]142        self.omfreader = sas_gen.OMFReader()
143        self.sldreader = sas_gen.SLDReader()
144        self.pdbreader = sas_gen.PDBReader()
145        self.model = sas_gen.GenSAS()
[318b5bbb]146        self.param_dic = self.model.params
147        self.parameters = []
148        self.data = None
149        self.scale2d = None
[9624cda]150        self.is_avg = False
[318b5bbb]151        self.plot_frame = None
152        self.qmax_x = _QMAX_DEFAULT
153        self.npts_x = _NPTS_DEFAULT
154        self.sld_data = None
155        self.graph_num = 1
156        self.default_shape = 'rectangular'
157        # Object that receive status event
158        self.parent = parent
159        self._do_layout()
160        self._create_default_sld_data()
161        self._create_default_2d_data()
162        wx.CallAfter(self._set_sld_data_helper)
[49ab5d7]163
[318b5bbb]164    def _define_structure(self):
165        """
166            Define the main sizers building to build this application.
167        """
168        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
169        self.box_source = wx.StaticBox(self, -1, str("SLD Data File"))
170        self.box_parameters = wx.StaticBox(self, -1, str("Input Parameters"))
171        self.box_qrange = wx.StaticBox(self, -1, str("Q Range"))
172        self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
173                                                    wx.VERTICAL)
174        self.boxsizer_parameters = wx.StaticBoxSizer(self.box_parameters,
175                                                    wx.VERTICAL)
176        self.boxsizer_qrange = wx.StaticBoxSizer(self.box_qrange,
177                                                    wx.VERTICAL)
178        self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
179        self.param_sizer = wx.BoxSizer(wx.HORIZONTAL)
180        self.shape_sizer = wx.BoxSizer(wx.HORIZONTAL)
181        self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
182        self.qrange_sizer = wx.BoxSizer(wx.HORIZONTAL)
183        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
[49ab5d7]184
[318b5bbb]185    def _layout_data_name(self):
186        """
187            Fill the sizer containing data's name
188        """
189        data_name_txt = wx.StaticText(self, -1, 'Data: ')
[49ab5d7]190        self.data_name_tcl = OutputTextCtrl(self, -1,
[318b5bbb]191                                            size=(_BOX_WIDTH * 4, -1))
192        data_hint = "Loaded data"
193        self.data_name_tcl.SetToolTipString(data_hint)
194        #control that triggers importing data
195        id = wx.NewId()
196        self.browse_button = wx.Button(self, id, "Load")
[3f5d75b]197        hint_on_browse = "Click to load data into this panel."
198        self.browse_button.SetToolTipString(hint_on_browse)
[318b5bbb]199        self.Bind(wx.EVT_BUTTON, self.on_load_data, id=id)
200        self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT, 15),
201                                      (self.data_name_tcl, 0, wx.LEFT, 10),
202                                      (self.browse_button, 0, wx.LEFT, 10)])
203    def _layout_param_size(self):
204        """
205            Fill the sizer containing slit size information
206        """
207        self.parameters = []
208        sizer = wx.GridBagSizer(3, 6)
209        model = self.model
210        details = self.model.details
211        params = self.model.params
212        ix = 0
213        iy = 0
214        param_title = wx.StaticText(self, -1, 'Parameter')
215        sizer.Add(param_title, (iy, ix), (1, 1), \
216                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
217        ix += 1
218        value_title = wx.StaticText(self, -1, 'Value')
219        sizer.Add(value_title, (iy, ix), (1, 1), \
220                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
221        ix += 1
222        unit_title = wx.StaticText(self, -1, 'Unit')
223        sizer.Add(unit_title, (iy, ix), (1, 1), \
224                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
225        key_list = params.keys()
226        key_list.sort()
227        for param in key_list:
228            iy += 1
229            ix = 0
230            p_name = wx.StaticText(self, -1, param)
231            sizer.Add(p_name, (iy, ix), (1, 1), \
232                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
233            ## add parameter value
234            ix += 1
235            value = model.getParam(param)
236            ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 2, 20),
237                                style=wx.TE_PROCESS_ENTER)
238            #ctl.SetToolTipString(\
239            #            "Hit 'Enter' after typing to update the plot.")
240            ctl.SetValue(format_number(value, True))
241            sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
242            ## add unit
243            ix += 1
244            unit = wx.StaticText(self, -1, details[param][0])
245            sizer.Add(unit, (iy, ix), (1, 1), \
246                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
247            self.parameters.append([p_name, ctl, unit])
[49ab5d7]248
[318b5bbb]249        self.param_sizer.Add(sizer, 0, wx.LEFT, 10)
[49ab5d7]250
[318b5bbb]251    def _layout_hint(self):
252        """
[49ab5d7]253            Fill the sizer containing hint
[318b5bbb]254        """
[78807b1]255        hint_msg = "We support omf, sld or pdb data files only."
[49ab5d7]256        hint_msg += "         "
[aaaf9b4]257        if FONT_VARIANT < 1:
[49ab5d7]258            hint_msg += "Very "
[aaaf9b4]259        hint_msg += "SLOW drawing -->"
[318b5bbb]260        hint_txt = wx.StaticText(self, -1, hint_msg)
[49ab5d7]261
[318b5bbb]262        id = wx.NewId()
263        self.draw_button = wx.Button(self, id, "Arrow Draw")
264        hint_on_draw = "Draw with arrows. Caution: it is a very slow drawing."
265        self.draw_button.SetToolTipString(hint_on_draw)
266        self.draw_button.Bind(wx.EVT_BUTTON, self.sld_draw, id=id)
[49ab5d7]267
[318b5bbb]268        self.draw_button.Enable(False)
269        self.hint_sizer.AddMany([(hint_txt, 0, wx.LEFT, 15),
[78807b1]270                                 (self.draw_button, 0, wx.LEFT, 7)])
[49ab5d7]271
[318b5bbb]272    def _layout_shape(self):
273        """
274        Fill the shape sizer
275        """
276        label_txt = wx.StaticText(self, -1, "Shape:")
277        self.shape_combo = self._fill_shape_combo()
278        self.shape_sizer.AddMany([(label_txt, 0, wx.LEFT, 15),
279                                (self.shape_combo, 0, wx.LEFT, 5)])
[49ab5d7]280
[318b5bbb]281    def _fill_shape_combo(self):
282        """
283        Fill up the shape combo box
284        """
[49ab5d7]285        shape_combo = wx.ComboBox(self, -1, size=(150, -1),
286                                      style=wx.CB_READONLY)
[318b5bbb]287        shape_combo.Append('Rectangular')
288        shape_combo.Append('Ellipsoid')
289        shape_combo.Bind(wx.EVT_COMBOBOX, self._on_shape_select)
290        shape_combo.SetSelection(0)
291        return shape_combo
[49ab5d7]292
[318b5bbb]293    def _on_shape_select(self, event):
294        """
295        On selecting a shape
296        """
297        event.Skip()
[49ab5d7]298        label = event.GetEventObject().GetValue().lower()
[318b5bbb]299        self.default_shape = label
300        self.parent.set_omfpanel_default_shap(self.default_shape)
301        self.parent.set_omfpanel_npts()
[49ab5d7]302
[3657667]303    def _fill_orient_combo(self):
304        """
305        Fill up the orientation combo box: used only for atomic structure
306        """
[49ab5d7]307        orient_combo = wx.ComboBox(self, -1, size=(150, -1),
308                                      style=wx.CB_READONLY)
[3657667]309        orient_combo.Append('Fixed orientation')
[9624cda]310        orient_combo.Append('Debye full avg.')
311        #orient_combo.Append('Debye sph. sym.')
[49ab5d7]312
[3657667]313        orient_combo.Bind(wx.EVT_COMBOBOX, self._on_orient_select)
314        orient_combo.SetSelection(0)
315        return orient_combo
[49ab5d7]316
[3657667]317    def _on_orient_select(self, event):
318        """
319        On selecting a orientation
320        """
321        event.Skip()
322        cb = event.GetEventObject()
[9624cda]323        if cb.GetCurrentSelection() == 2:
324            self.is_avg = None
325        else:
326            is_avg = cb.GetCurrentSelection() == 1
327            self.is_avg = is_avg
328        self.model.set_is_avg(self.is_avg)
[49ab5d7]329        self.set_est_time()
330
[318b5bbb]331    def _layout_qrange(self):
332        """
333        Fill the sizer containing qrange
334        """
335        sizer = wx.GridBagSizer(2, 3)
336        ix = 0
337        iy = 0
338        #key_list.sort()
339        name = wx.StaticText(self, -1, 'No. of Qx (Qy) bins: ')
340        sizer.Add(name, (iy, ix), (1, 1), \
341                        wx.EXPAND | wx.ADJUST_MINSIZE, 0)
342        ## add parameter value
343        ix += 1
344        self.npt_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20),
345                            style=wx.TE_PROCESS_ENTER)
346        self.npt_ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
347        self.npt_ctl.SetValue(format_number(self.npts_x, True))
348        sizer.Add(self.npt_ctl, (iy, ix), (1, 1), wx.EXPAND)
349        ## add unit
350        ix += 1
351        unit = wx.StaticText(self, -1, '')
352        sizer.Add(unit, (iy, ix), (1, 1), \
353                        wx.EXPAND | wx.ADJUST_MINSIZE, 0)
354        iy += 1
355        ix = 0
356        name = wx.StaticText(self, -1, 'Qx (Qy) Max: ')
357        sizer.Add(name, (iy, ix), (1, 1), \
358                        wx.EXPAND | wx.ADJUST_MINSIZE, 0)
359        ## add parameter value
360        ix += 1
361        self.qmax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20),
362                            style=wx.TE_PROCESS_ENTER)
[49ab5d7]363        self.qmax_ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
[318b5bbb]364        self.qmax_ctl.SetValue(format_number(self.qmax_x, True))
365        sizer.Add(self.qmax_ctl, (iy, ix), (1, 1), wx.EXPAND)
366        ## add unit
367        ix += 1
368        unit = wx.StaticText(self, -1, '[1/A]')
369        sizer.Add(unit, (iy, ix), (1, 1), \
370                        wx.EXPAND | wx.ADJUST_MINSIZE, 0)
371        self.qrange_sizer.Add(sizer, 0, wx.LEFT, 10)
[49ab5d7]372
373    def _layout_button(self):
[318b5bbb]374        """
375            Do the layout for the button widgets
[49ab5d7]376        """
[2d8018f]377        self.est_time = '*Estimated Computation time :\n  %s'
[49ab5d7]378        self.time_text = wx.StaticText(self, -1, self.est_time % str('2 sec'))
[3657667]379        self.orient_combo = self._fill_orient_combo()
380        self.orient_combo.Show(False)
[d5419f7f]381
[49ab5d7]382        self.bt_compute = wx.Button(self, wx.NewId(), 'Compute')
[318b5bbb]383        self.bt_compute.Bind(wx.EVT_BUTTON, self.on_compute)
384        self.bt_compute.SetToolTipString("Compute 2D Scattering Pattern.")
[d5419f7f]385
[49ab5d7]386        self.bt_help = wx.Button(self, wx.NewId(), 'HELP')
[3f5d75b]387        self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
388        self.bt_help.SetToolTipString("Help on Scatter Calculator")
[d5419f7f]389
390        self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
391        self.bt_close.Bind(wx.EVT_BUTTON, self.on_panel_close)
392        self.bt_close.SetToolTipString("Close this window")
393
[318b5bbb]394        self.button_sizer.AddMany([(self.time_text , 0, wx.LEFT, 20),
[3f5d75b]395                                   (self.orient_combo , 0, wx.LEFT, 20),
396                                   (self.bt_compute, 0, wx.LEFT, 20),
[d5419f7f]397                                   (self.bt_help, 0, wx.LEFT, 20),
398                                   (self.bt_close, 0, wx.LEFT, 5)])
[49ab5d7]399
[318b5bbb]400    def estimate_ctime(self):
401        """
[3657667]402        Calculation time estimation
[318b5bbb]403        """
[2d8018f]404        # magic equation: not very accurate
405        factor = 1
[318b5bbb]406        n_qbins = float(self.npt_ctl.GetValue())
407        n_qbins *= n_qbins
408        n_pixs = float(self.parent.get_npix())
[9624cda]409        if self.is_avg:
[2d8018f]410            factor = 6
[9624cda]411            n_pixs *= (n_pixs / 200)
[318b5bbb]412        x_in = n_qbins * n_pixs / 100000
[49ab5d7]413        etime = factor + 0.085973 * x_in
[318b5bbb]414        return int(etime)
[49ab5d7]415
[318b5bbb]416    def set_est_time(self):
417        """
418        Set text for est. computation time
419        """
[9624cda]420        unit = 'sec'
[318b5bbb]421        if self.time_text != None:
[9624cda]422            self.time_text.SetForegroundColour('black')
[318b5bbb]423            etime = self.estimate_ctime()
[9624cda]424            if etime > 60:
425                etime /= 60
426                unit = 'min'
427                self.time_text.SetForegroundColour('red')
428            time_str = str(etime) + ' ' + unit
[49ab5d7]429            self.time_text.SetLabel(self.est_time % time_str)
430
[318b5bbb]431    def _do_layout(self):
432        """
[3657667]433        Draw window content
[318b5bbb]434        """
435        self._define_structure()
436        self._layout_data_name()
437        self._layout_param_size()
438        self._layout_qrange()
439        self._layout_hint()
440        self._layout_shape()
441        self._layout_button()
442        self.boxsizer_source.AddMany([(self.data_name_sizer, 0,
[49ab5d7]443                                        wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
[318b5bbb]444                                      (self.hint_sizer, 0,
[49ab5d7]445                                        wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
446                                      (self.shape_sizer, 0,
447                                        wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
[318b5bbb]448        self.boxsizer_parameters.AddMany([(self.param_sizer, 0,
[49ab5d7]449                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
[318b5bbb]450        self.boxsizer_qrange.AddMany([(self.qrange_sizer, 0,
[49ab5d7]451                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
452        self.main_sizer.AddMany([(self.boxsizer_source, 0,
453                                  wx.EXPAND | wx.ALL, 10),
454                                 (self.boxsizer_parameters, 0,
455                                  wx.EXPAND | wx.ALL, 10),
456                                 (self.boxsizer_qrange, 0,
457                                  wx.EXPAND | wx.ALL, 10),
[318b5bbb]458                                 (self.button_sizer, 0,
[49ab5d7]459                                  wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
[318b5bbb]460        self.SetSizer(self.main_sizer)
461        self.SetAutoLayout(True)
[49ab5d7]462
[318b5bbb]463    def _create_default_sld_data(self):
464        """
465        Making default sld-data
466        """
467        sld_n_default = 6.97e-06
[b9a5f0e]468        omfdata = sas_gen.OMFData()
469        omf2sld = sas_gen.OMF2SLD()
[318b5bbb]470        omf2sld.set_data(omfdata, self.default_shape)
471        self.sld_data = omf2sld.output
472        self.sld_data.is_data = False
473        self.sld_data.filename = "Default SLD Profile"
474        self.sld_data.set_sldn(sld_n_default)
[49ab5d7]475        self.data_name_tcl.SetValue(self.sld_data.filename)
476
[318b5bbb]477    def choose_data_file(self, location=None):
478        """
479        Choosing a dtata file
480        """
481        path = None
482        filename = ''
483        if location == None:
484            location = os.getcwd()
[968f72d]485
486        exts = "*" + self.omfreader.ext[0]
487        exts += ", *" + self.sldreader.ext[0]
488        exts += ", *" + self.pdbreader.ext[0]
[49ab5d7]489        all_type = "All GEN files (%s, %s) | %s" % (exts.upper(), exts.lower(),
490                                               exts.lower().replace(',', ';'))
[968f72d]491        wildcard = [all_type]
[318b5bbb]492        omf_type = self.omfreader.type
493        sld_type = self.sldreader.type
[dbc5dc9b]494        pdb_type = self.pdbreader.type
[968f72d]495
[318b5bbb]496        for type in sld_type:
497            wildcard.append(type)
498        for type in omf_type:
499            wildcard.append(type)
[077207b]500        for type in pdb_type:
501            wildcard.append(type)
[318b5bbb]502        wildcard = '|'.join(wildcard)
503        dlg = wx.FileDialog(self, "Choose a file", location,
504                            "", wildcard, wx.OPEN)
505        if dlg.ShowModal() == wx.ID_OK:
506            path = dlg.GetPath()
507            filename = os.path.basename(path)
[49ab5d7]508        dlg.Destroy()
[318b5bbb]509        return path
[49ab5d7]510
[318b5bbb]511    def on_load_data(self, event):
512        """
513        Open a file dialog to allow the user to select a given file.
514        The user is only allow to load file with extension .omf, .txt, .sld.
515        Display the slit size corresponding to the loaded data.
516        """
517        location = self.parent.get_path()
518        path = self.choose_data_file(location=location)
519        if path is None:
[49ab5d7]520            return
521
[318b5bbb]522        self.shape_sizer.ShowItems(False)
523        self.default_shape = 'rectangular'
524        self.parent.set_omfpanel_default_shap(self.default_shape)
[49ab5d7]525
[318b5bbb]526        self.parent.set_file_location(os.path.dirname(path))
527        try:
528            #Load data
529            self.ext = os.path.splitext(path)[-1]
530            if self.ext in self.omfreader.ext:
531                loader = self.omfreader
532            elif self.ext in self.sldreader.ext:
533                loader = self.sldreader
[dbc5dc9b]534            elif self.ext in self.pdbreader.ext:
535                loader = self.pdbreader
[318b5bbb]536            else:
537                loader = None
538            if self.reader is not None and self.reader.isrunning():
539                self.reader.stop()
[077207b]540            self.browse_button.Enable(False)
541            self.browse_button.SetLabel("Loading...")
[318b5bbb]542            if self.parent.parent is not None:
[49ab5d7]543                wx.PostEvent(self.parent.parent,
[318b5bbb]544                                StatusEvent(status="Loading...",
545                                type="progress"))
546            self.reader = GenReader(path=path, loader=loader,
547                                    completefn=self.complete_loading,
548                                    updatefn=self.load_update)
549            self.reader.queue()
[077207b]550            #self.load_update()
[318b5bbb]551        except:
552            self.ext = None
553            if self.parent.parent is None:
[49ab5d7]554                return
[b9a5f0e]555            msg = "Generic SAS Calculator: %s" % (sys.exc_value)
[318b5bbb]556            wx.PostEvent(self.parent.parent,
557                          StatusEvent(status=msg, type='stop'))
558            self.SetFocus()
[49ab5d7]559            return
560
[318b5bbb]561    def load_update(self):
562        """
563        print update on the status bar
[49ab5d7]564        """
[318b5bbb]565        if self.parent.parent is None:
[49ab5d7]566                return
[318b5bbb]567        if self.reader.isrunning():
568            type = "progress"
569        else:
570            type = "stop"
571        wx.PostEvent(self.parent.parent, StatusEvent(status="",
572                                                  type=type))
[49ab5d7]573
[318b5bbb]574    def complete_loading(self, data=None, filename=''):
575        """
576        Complete the loading
577        """
578        #compute the slit size
[077207b]579        self.browse_button.Enable(True)
580        self.browse_button.SetLabel('Load')
[318b5bbb]581        try:
[3cfa760]582            is_pdbdata = False
[318b5bbb]583            filename = data.filename
584            self.data_name_tcl.SetValue(str(filename))
585            self.file_name = filename.split('.')[0]
[3657667]586            self.orient_combo.SetSelection(0)
[9624cda]587            self.is_avg = False
[318b5bbb]588            if self.ext in self.omfreader.ext:
[b9a5f0e]589                gen = sas_gen.OMF2SLD()
[318b5bbb]590                gen.set_data(data)
591                #omf_data = data
592                self.sld_data = gen.get_magsld()
593            elif self.ext in self.sldreader.ext:
594                self.sld_data = data
[dbc5dc9b]595            elif self.ext in self.pdbreader.ext:
596                self.sld_data = data
[3cfa760]597                is_pdbdata = True
[318b5bbb]598                #omf_data = None
599            else:
600                raise
[3657667]601            self.orient_combo.Show(is_pdbdata)
602            self.button_sizer.Layout()
[318b5bbb]603            self._set_sld_data_helper(True)
604        except:
605            if self.parent.parent is None:
[077207b]606                raise
[318b5bbb]607            msg = "Loading Error: This file format is not supported "
[49ab5d7]608            msg += "for GenSAS."
[318b5bbb]609            wx.PostEvent(self.parent.parent,
610                          StatusEvent(status=msg, type='stop', info='Error'))
611            self.SetFocus()
[49ab5d7]612            return
[318b5bbb]613        if self.parent.parent is None:
[49ab5d7]614            return
615
[318b5bbb]616        msg = "Load Complete"
617        wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type='stop'))
618        self.SetFocus()
[49ab5d7]619
[318b5bbb]620    def _set_sld_data_helper(self, is_draw=False):
621        """
622        Set sld data helper
623        """
[9624cda]624        #is_avg = self.orient_combo.GetCurrentSelection() == 1
625        self.model.set_is_avg(self.is_avg)
[318b5bbb]626        self.model.set_sld_data(self.sld_data)
[49ab5d7]627
628        self.draw_button.Enable(self.sld_data != None)
[318b5bbb]629        wx.CallAfter(self.parent.set_sld_data, self.sld_data)
[afd45674]630        self._update_model_params()
[318b5bbb]631        if is_draw:
[1de85f4]632            wx.CallAfter(self.sld_draw, None, False)
[49ab5d7]633
[afd45674]634    def _update_model_params(self):
635        """
636        Update the model parameter values
637        """
638        for list in self.parameters:
639            param_name = list[0].GetLabelText()
640            val = str(self.model.params[param_name])
641            list[1].SetValue(val)
[49ab5d7]642
[afd45674]643    def set_volume_ctl_val(self, val):
644        """
645        Set volume txtctrl value
646        """
647        for list in self.parameters:
648            param_name = list[0].GetLabelText()
649            if param_name.lower() == 'total_volume':
650                list[1].SetValue(val)
651                list[1].Refresh()
652                break
[49ab5d7]653
[318b5bbb]654    def _onparamEnter(self, event):
655        """
656        On param enter
657        """
658        try:
659            item = event.GetEventObject()
660            self._check_value()
661            item.Refresh()
662        except:
663            pass
[49ab5d7]664
[1de85f4]665    def sld_draw(self, event=None, has_arrow=True):
[318b5bbb]666        """
667        Draw 3D sld profile
668        """
669        flag = self.parent.check_omfpanel_inputs()
670        if not flag:
671            infor = 'Error'
672            msg = 'Error: Wrong inputs in the SLD info panel.'
673            # inform msg to wx
674            wx.PostEvent(self.parent.parent,
675                    StatusEvent(status=msg, info=infor))
676            self.SetFocus()
677            return
678
679        self.sld_data = self.parent.get_sld_from_omf()
[49ab5d7]680        output = self.sld_data
[318b5bbb]681        #frame_size = wx.Size(470, 470)   
[d4895dd]682        self.plot_frame = PlotFrame(self, -1, 'testView')
[318b5bbb]683        frame = self.plot_frame
684        frame.Show(False)
685        add_icon(self.parent, frame)
[49ab5d7]686        panel = frame.plotpanel
[318b5bbb]687        try:
688            # mpl >= 1.0.0
689            ax = panel.figure.gca(projection='3d')
690        except:
691            # mpl < 1.0.0
692            try:
693                from mpl_toolkits.mplot3d import Axes3D
694                ax = Axes3D(panel.figure)
695            except:
696                logging.error("PlotPanel could not import Axes3D")
697                raise
[49ab5d7]698        panel.dimension = 3
[1de85f4]699        graph_title = self._sld_plot_helper(ax, output, has_arrow)
[fdb134b9]700        # Use y, z axes (in mpl 3d) as z, y axes
[b9a5f0e]701        # that consistent with our SAS detector coords.
[49ab5d7]702        ax.set_xlabel('x ($\A%s$)' % output.pos_unit)
703        ax.set_ylabel('z ($\A%s$)' % output.pos_unit)
704        ax.set_zlabel('y ($\A%s$)' % output.pos_unit)
705        panel.subplot.figure.subplots_adjust(left=0.05, right=0.95,
[fdb134b9]706                                             bottom=0.05, top=0.96)
707        if output.pix_type == 'atom':
708            ax.legend(loc='upper left', prop={'size':10})
709        num_graph = str(self.graph_num)
[49ab5d7]710        frame.SetTitle('Graph %s: %s' % (num_graph, graph_title))
[fdb134b9]711        wx.CallAfter(frame.Show, True)
712        self.graph_num += 1
713
714    def _sld_plot_helper(self, ax, output, has_arrow=False):
715        """
716        Actual plot definition happens here
717        :Param ax: axis3d
718        :Param output: sld_data [MagSLD]
719        :Param has_arrow: whether or not draws M vector [bool]
720        """
721        # Set the locals
[49ab5d7]722        color_dic = {'H':'blue', 'D':'purple', 'N': 'orange',
[fdb134b9]723                     'O':'red', 'C':'green', 'P':'cyan', 'Other':'k'}
[dbc5dc9b]724        marker = ','
725        m_size = 2
[1de85f4]726        graph_title = self.file_name
727        graph_title += "   3D SLD Profile "
[318b5bbb]728        pos_x = output.pos_x
729        pos_y = output.pos_y
730        pos_z = output.pos_z
731        sld_mx = output.sld_mx
732        sld_my = output.sld_my
[49ab5d7]733        sld_mz = output.sld_mz
734        pix_symbol = output.pix_symbol
[fdb134b9]735        if output.pix_type == 'atom':
736            marker = 'o'
737            m_size = 3.5
738        sld_tot = (numpy.fabs(sld_mx) + numpy.fabs(sld_my) + \
[318b5bbb]739                   numpy.fabs(sld_mz) + numpy.fabs(output.sld_n))
[49ab5d7]740        is_nonzero = sld_tot > 0.0
741        is_zero = sld_tot == 0.0
[fdb134b9]742        # I. Plot null points
[318b5bbb]743        if is_zero.any():
[49ab5d7]744            ax.plot(pos_x[is_zero], pos_z[is_zero], pos_y[is_zero], marker,
745                    c="y", alpha=0.5, markeredgecolor='y', markersize=m_size)
[318b5bbb]746            pos_x = pos_x[is_nonzero]
747            pos_y = pos_y[is_nonzero]
748            pos_z = pos_z[is_nonzero]
749            sld_mx = sld_mx[is_nonzero]
750            sld_my = sld_my[is_nonzero]
751            sld_mz = sld_mz[is_nonzero]
[3657667]752            pix_symbol = output.pix_symbol[is_nonzero]
[fdb134b9]753        # II. Plot selective points in color
[3657667]754        other_color = numpy.ones(len(pix_symbol), dtype='bool')
[dbc01f2]755        for key in color_dic.keys():
[3657667]756            chosen_color = pix_symbol == key
[440006a]757            if numpy.any(chosen_color):
[49ab5d7]758                other_color = other_color & (chosen_color != True)
[dbc01f2]759                color = color_dic[key]
[49ab5d7]760                ax.plot(pos_x[chosen_color], pos_z[chosen_color],
761                        pos_y[chosen_color], marker, c=color, alpha=0.5,
762                        markeredgecolor=color, markersize=m_size, label=key)
[fdb134b9]763        # III. Plot All others       
[440006a]764        if numpy.any(other_color):
[fdb134b9]765            a_name = ''
766            if output.pix_type == 'atom':
767                # Get atom names not in the list
768                a_names = [symb  for symb in pix_symbol \
769                           if symb not in color_dic.keys()]
770                a_name = a_names[0]
771                for name in a_names:
772                    new_name = ", " + name
[644f95b]773                    if a_name.count(name) == 0:
[fdb134b9]774                        a_name += new_name
775            # plot in black
[49ab5d7]776            ax.plot(pos_x[other_color], pos_z[other_color], pos_y[other_color],
777                    marker, c="k", alpha=0.5, markeredgecolor="k",
778                    markersize=m_size, label=a_name)
[fdb134b9]779        # IV. Draws atomic bond with grey lines if any
780        if output.has_conect:
[11363ee]781            for ind in range(len(output.line_x)):
[49ab5d7]782                ax.plot(output.line_x[ind], output.line_z[ind],
783                        output.line_y[ind], '-', lw=0.6, c="grey", alpha=0.3)
[fdb134b9]784        # V. Draws magnetic vectors
[49ab5d7]785        if has_arrow and len(pos_x) > 0:
786            graph_title += " - Magnetic Vector as Arrow -"
[1de85f4]787            panel = self.plot_frame.plotpanel
[9624cda]788            def _draw_arrow(input=None, update=None):
[318b5bbb]789                """
[fdb134b9]790                draw magnetic vectors w/arrow
[318b5bbb]791                """
792                max_mx = max(numpy.fabs(sld_mx))
793                max_my = max(numpy.fabs(sld_my))
794                max_mz = max(numpy.fabs(sld_mz))
795                max_m = max(max_mx, max_my, max_mz)
796                try:
[49ab5d7]797                    max_step = max(output.xstepsize, output.ystepsize,
[318b5bbb]798                                   output.zstepsize)
799                except:
800                    max_step = 0
801                if max_step <= 0:
802                    max_step = 5
803                try:
804                    if max_m != 0:
805                        unit_x2 = sld_mx / max_m
806                        unit_y2 = sld_my / max_m
807                        unit_z2 = sld_mz / max_m
808                        # 0.8 is for avoiding the color becomes white=(1,1,1))
809                        color_x = numpy.fabs(unit_x2 * 0.8)
810                        color_y = numpy.fabs(unit_y2 * 0.8)
811                        color_z = numpy.fabs(unit_z2 * 0.8)
812                        x2 = pos_x + unit_x2 * max_step
813                        y2 = pos_y + unit_y2 * max_step
814                        z2 = pos_z + unit_z2 * max_step
815                        x_arrow = numpy.column_stack((pos_x, x2))
816                        y_arrow = numpy.column_stack((pos_y, y2))
817                        z_arrow = numpy.column_stack((pos_z, z2))
[fdb134b9]818                        colors = numpy.column_stack((color_x, color_y, color_z))
[49ab5d7]819                        arrows = Arrow3D(panel, x_arrow, z_arrow, y_arrow,
820                                        colors, mutation_scale=10, lw=1,
821                                        arrowstyle="->", alpha=0.5)
822                        ax.add_artist(arrows)
[318b5bbb]823                except:
[49ab5d7]824                    pass
[318b5bbb]825                msg = "Arrow Drawing completed.\n"
826                status_type = 'stop'
[49ab5d7]827                self._status_info(msg, status_type)
[1de85f4]828            msg = "Arrow Drawing is in progress..."
829            status_type = 'progress'
[49ab5d7]830            self._status_info(msg, status_type)
[1de85f4]831            draw_out = CalcGen(input=ax,
832                             completefn=_draw_arrow, updatefn=self._update)
833            draw_out.queue()
834        return graph_title
[49ab5d7]835
[318b5bbb]836    def set_input_params(self):
837        """
838        Set model parameters
839        """
840        for list in self.parameters:
841            param_name = list[0].GetLabelText()
842            param_value = float(list[1].GetValue())
843            self.model.setParam(param_name, param_value)
[49ab5d7]844
[318b5bbb]845    def on_compute(self, event):
846        """
847        Compute I(qx, qy)
848        """
849        flag = self.parent.check_omfpanel_inputs()
850        if not flag and self.parent.parent != None:
851            infor = 'Error'
852            msg = 'Error: Wrong inputs in the SLD info panel.'
853            # inform msg to wx
854            wx.PostEvent(self.parent.parent,
855                    StatusEvent(status=msg, info=infor))
856            self.SetFocus()
857            return
858        self.sld_data = self.parent.get_sld_from_omf()
859        if self.sld_data == None:
860            if self.parent.parent != None:
861                infor = 'Error'
862                msg = 'Error: No data has been selected.'
863                # inform msg to wx
864                wx.PostEvent(self.parent.parent,
865                        StatusEvent(status=msg, info=infor))
866                self.SetFocus()
867            return
868        flag = self._check_value()
869        if not flag:
870            _set_error(self, None, True)
871            return
872        try:
873            self.model.set_sld_data(self.sld_data)
874            self.set_input_params()
[9624cda]875            if self.is_avg or self.is_avg == None:
876                self._create_default_1d_data()
877                i_out = numpy.zeros(len(self.data.y))
878                inputs = [self.data.x, [], i_out]
879            else:
880                self._create_default_2d_data()
881                i_out = numpy.zeros(len(self.data.data))
[49ab5d7]882                inputs = [self.data.qx_data, self.data.qy_data, i_out]
883
[318b5bbb]884            msg = "Computation is in progress..."
885            status_type = 'progress'
886            self._status_info(msg, status_type)
[49ab5d7]887            cal_out = CalcGen(input=inputs,
888                              completefn=self.complete,
[9714ff5]889                              updatefn=self._update)
[49ab5d7]890            cal_out.queue()
891
[318b5bbb]892        except:
[49ab5d7]893            msg = "%s." % sys.exc_value
[318b5bbb]894            status_type = 'stop'
895            self._status_info(msg, status_type)
896            wx.PostEvent(self.parent.parent,
897                        StatusEvent(status=msg, info='Error'))
898            self.SetFocus()
899
[49ab5d7]900    def on_help(self, event):
[3f5d75b]901        """
902        Bring up the General scattering Calculator Documentation whenever
[49ab5d7]903        the HELP button is clicked.
904
[3f5d75b]905        Calls DocumentationWindow with the path of the location within the
[49ab5d7]906        documentation tree (after /doc/ ....".  Note that when using old
907        versions of Wx (before 2.9) and thus not the release version of
908        installers, the help comes up at the top level of the file as
[3f5d75b]909        webbrowser does not pass anything past the # to the browser when it is
910        running "file:///...."
[49ab5d7]911
[3f5d75b]912    :param evt: Triggers on clicking the help button
913    """
[49ab5d7]914
[3f5d75b]915        _TreeLocation = "user/perspectives/calculator/sas_calculator_help.html"
[3db44fb]916        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
917                                          "General Scattering Calculator Help")
[3f5d75b]918
[318b5bbb]919    def _check_value(self):
920        """
921        Check input values if float
922        """
923        flag = True
924        self.npt_ctl.SetBackgroundColour("white")
925        self.qmax_ctl.SetBackgroundColour("white")
926        try:
[49ab5d7]927            npt_val = float(self.npt_ctl.GetValue())
[46be5e6]928            if npt_val < 2 or npt_val > 1000:
[318b5bbb]929                raise
930            self.npt_ctl.SetValue(str(int(npt_val)))
931            self.set_est_time()
932        except:
[49ab5d7]933            flag = _set_error(self, self.npt_ctl)
[318b5bbb]934        try:
[49ab5d7]935            qmax_val = float(self.qmax_ctl.GetValue())
[46be5e6]936            if qmax_val <= 0 or qmax_val > 1000:
[318b5bbb]937                raise
938        except:
[49ab5d7]939            flag = _set_error(self, self.qmax_ctl)
[318b5bbb]940        for list in self.parameters:
941            list[1].SetBackgroundColour("white")
942            param_name = list[0].GetLabelText()
[49ab5d7]943            try:
[318b5bbb]944                param_val = float(list[1].GetValue())
945                if param_name.count('frac') > 0:
946                    if param_val < 0 or param_val > 1:
947                       raise
948            except:
949                flag = _set_error(self, list[1])
950        return flag
[49ab5d7]951
952    def _status_info(self, msg='', type="update"):
[318b5bbb]953        """
954        Status msg
955        """
956        if type == "stop":
957            label = "Compute"
958            able = True
[49ab5d7]959        else:
[318b5bbb]960            label = "Wait..."
961            able = False
962        self.bt_compute.Enable(able)
963        self.bt_compute.SetLabel(label)
964        self.bt_compute.SetToolTipString(label)
965        if self.parent.parent != None:
[49ab5d7]966            wx.PostEvent(self.parent.parent,
967                             StatusEvent(status=msg, type=type))
[318b5bbb]968
969    def _update(self, time=None):
970        """
[9624cda]971        Update the progress bar
[318b5bbb]972        """
[9624cda]973        if self.parent.parent == None:
974            return
975        type = "progress"
976        msg = "Please wait. Computing... (Note: Window may look frozen.)"
977        wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
978                                                  type=type))
[49ab5d7]979
980    def complete(self, input, update=None):
[318b5bbb]981        """
982        Gen compute complete function
983        :Param input: input list [qx_data, qy_data, i_out]
984        """
[9624cda]985        out = numpy.empty(0)
[2d8018f]986        #s = time.time()
[9624cda]987        for ind in range(len(input[0])):
988            if self.is_avg:
989                if ind % 1 == 0 and update != None:
990                    update()
991                    time.sleep(0.1)
[49ab5d7]992                inputi = [input[0][ind:ind + 1], [], input[2][ind:ind + 1]]
[9624cda]993                outi = self.model.run(inputi)
994                out = numpy.append(out, outi)
995            else:
996                if ind % 50 == 0  and update != None:
997                    update()
998                    time.sleep(0.001)
[49ab5d7]999                inputi = [input[0][ind:ind + 1], input[1][ind:ind + 1],
1000                          input[2][ind:ind + 1]]
[9624cda]1001                outi = self.model.runXY(inputi)
1002                out = numpy.append(out, outi)
[2d8018f]1003        #print time.time() - s
[9624cda]1004        if self.is_avg or self.is_avg == None:
1005            self._draw1D(out)
1006        else:
1007            #out = self.model.runXY(input)
1008            self._draw2D(out)
[49ab5d7]1009
[318b5bbb]1010        msg = "Gen computation completed.\n"
1011        status_type = 'stop'
1012        self._status_info(msg, status_type)
[49ab5d7]1013
[318b5bbb]1014    def _create_default_2d_data(self):
1015        """
1016        Create 2D data by default
1017        Only when the page is on theory mode.
1018        :warning: This data is never plotted.
1019        """
1020        self.qmax_x = float(self.qmax_ctl.GetValue())
1021        self.npts_x = int(float(self.npt_ctl.GetValue()))
1022        self.data = Data2D()
1023        qmax = self.qmax_x #/ numpy.sqrt(2)
1024        self.data.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
1025        self.data.yaxis('\\rm{Q_{y}}', '\AA^{-1}')
1026        self.data.is_data = False
1027        self.data.id = str(self.uid) + " GenData"
1028        self.data.group_id = str(self.uid) + " Model2D"
1029        ## Default values
1030        self.data.detector.append(Detector())
1031        index = len(self.data.detector) - 1
1032        self.data.detector[index].distance = 8000   # mm
1033        self.data.source.wavelength = 6             # A
1034        self.data.detector[index].pixel_size.x = 5  # mm
1035        self.data.detector[index].pixel_size.y = 5  # mm
1036        self.data.detector[index].beam_center.x = qmax
1037        self.data.detector[index].beam_center.y = qmax
1038        xmax = qmax
1039        xmin = -qmax
1040        ymax = qmax
1041        ymin = -qmax
1042        qstep = self.npts_x
1043
1044        x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
1045        y = numpy.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
1046        ## use data info instead
1047        new_x = numpy.tile(x, (len(y), 1))
1048        new_y = numpy.tile(y, (len(x), 1))
1049        new_y = new_y.swapaxes(0, 1)
1050        # all data reuire now in 1d array
1051        qx_data = new_x.flatten()
1052        qy_data = new_y.flatten()
1053        q_data = numpy.sqrt(qx_data * qx_data + qy_data * qy_data)
1054        # set all True (standing for unmasked) as default
1055        mask = numpy.ones(len(qx_data), dtype=bool)
1056        # store x and y bin centers in q space
1057        x_bins = x
1058        y_bins = y
1059        self.data.source = Source()
1060        self.data.data = numpy.ones(len(mask))
1061        self.data.err_data = numpy.ones(len(mask))
1062        self.data.qx_data = qx_data
1063        self.data.qy_data = qy_data
1064        self.data.q_data = q_data
1065        self.data.mask = mask
1066        self.data.x_bins = x_bins
1067        self.data.y_bins = y_bins
1068        # max and min taking account of the bin sizes
1069        self.data.xmin = xmin
1070        self.data.xmax = xmax
1071        self.data.ymin = ymin
1072        self.data.ymax = ymax
[9624cda]1073
1074    def _create_default_1d_data(self):
1075        """
1076        Create 2D data by default
1077        Only when the page is on theory mode.
1078        :warning: This data is never plotted.
1079                    residuals.x = data_copy.x[index]
1080            residuals.dy = numpy.ones(len(residuals.y))
1081            residuals.dx = None
1082            residuals.dxl = None
1083            residuals.dxw = None
1084        """
1085        self.qmax_x = float(self.qmax_ctl.GetValue())
1086        self.npts_x = int(float(self.npt_ctl.GetValue()))
1087        qmax = self.qmax_x #/ numpy.sqrt(2)
1088        ## Default values
1089        xmax = qmax
1090        xmin = qmax * _Q1D_MIN
1091        qstep = self.npts_x
1092        x = numpy.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
1093        # store x and y bin centers in q space
1094        #self.data.source = Source()
1095        y = numpy.ones(len(x))
1096        dy = numpy.zeros(len(x))
1097        dx = numpy.zeros(len(x))
1098        self.data = Data1D(x=x, y=y)
1099        self.data.dx = dx
1100        self.data.dy = dy
1101
1102    def _draw1D(self, y_out):
1103        """
1104        Complete get the result of modelthread and create model 2D
1105        that can be plot.
1106        """
1107        page_id = self.id
1108        data = self.data
[49ab5d7]1109
[9624cda]1110        model = self.model
1111        state = None
[49ab5d7]1112
[9624cda]1113        new_plot = Data1D(x=data.x, y=y_out)
1114        new_plot.dx = data.dx
1115        new_plot.dy = data.dy
1116        new_plot.xaxis('\\rm{Q_{x}}', '\AA^{-1}')
1117        new_plot.yaxis('\\rm{Intensity}', 'cm^{-1}')
1118        new_plot.is_data = False
1119        new_plot.id = str(self.uid) + " GenData1D"
1120        new_plot.group_id = str(self.uid) + " Model1D"
1121        new_plot.name = model.name + '1d'
1122        new_plot.title = "Generic model1D "
1123        new_plot.id = str(page_id) + ': ' + self.file_name \
[49ab5d7]1124                        + ' #%s' % str(self.graph_num) + "_1D"
1125        new_plot.group_id = str(page_id) + " Model1D" + \
1126                             ' #%s' % str(self.graph_num) + "_1D"
[9624cda]1127        new_plot.is_data = False
1128
1129        title = new_plot.title
1130        _yaxis, _yunit = new_plot.get_yaxis()
1131        _xaxis, _xunit = new_plot.get_xaxis()
1132        new_plot.xaxis(str(_xaxis), str(_xunit))
1133        new_plot.yaxis(str(_yaxis), str(_yunit))
[49ab5d7]1134
[9624cda]1135        if new_plot.is_data:
1136            data_name = str(new_plot.name)
1137        else:
1138            data_name = str(model.__class__.__name__) + '1d'
1139
1140        if len(title) > 1:
[49ab5d7]1141            new_plot.title = "Gen Theory for %s " % model.name + data_name
[9624cda]1142        new_plot.name = new_plot.id
1143        new_plot.label = new_plot.id
1144        #theory_data = deepcopy(new_plot)
1145        if self.parent.parent != None:
1146            self.parent.parent.update_theory(data_id=new_plot.id,
1147                                           theory=new_plot,
1148                                           state=state)
1149        title = new_plot.title
1150        num_graph = str(self.graph_num)
[49ab5d7]1151        wx.CallAfter(self.parent.draw_graph, new_plot,
1152                     title="GEN Graph %s: " % num_graph + new_plot.id)
[9624cda]1153        self.graph_num += 1
[49ab5d7]1154
[318b5bbb]1155    def _draw2D(self, image):
1156        """
1157        Complete get the result of modelthread and create model 2D
1158        that can be plot.
1159        """
1160        page_id = self.id
1161        data = self.data
[49ab5d7]1162
[318b5bbb]1163        model = self.model
1164        qmin = 0.0
1165        state = None
[49ab5d7]1166
[318b5bbb]1167        numpy.nan_to_num(image)
1168        new_plot = Data2D(image=image, err_image=data.err_data)
1169        new_plot.name = model.name + '2d'
1170        new_plot.title = "Generic model 2D "
1171        new_plot.id = str(page_id) + ': ' + self.file_name \
[49ab5d7]1172                        + ' #%s' % str(self.graph_num) + "_2D"
[9624cda]1173        new_plot.group_id = str(page_id) + " Model2D" \
[49ab5d7]1174                        + ' #%s' % str(self.graph_num) + "_2D"
[318b5bbb]1175        new_plot.detector = data.detector
1176        new_plot.source = data.source
1177        new_plot.is_data = False
1178        new_plot.qx_data = data.qx_data
1179        new_plot.qy_data = data.qy_data
1180        new_plot.q_data = data.q_data
1181        new_plot.mask = data.mask
1182        ## plot boundaries
1183        new_plot.ymin = data.ymin
1184        new_plot.ymax = data.ymax
1185        new_plot.xmin = data.xmin
1186        new_plot.xmax = data.xmax
1187        title = data.title
1188        _yaxis, _yunit = data.get_yaxis()
1189        _xaxis, _xunit = data.get_xaxis()
1190        new_plot.xaxis(str(_xaxis), str(_xunit))
1191        new_plot.yaxis(str(_yaxis), str(_yunit))
[49ab5d7]1192
[318b5bbb]1193        new_plot.is_data = False
1194        if data.is_data:
1195            data_name = str(data.name)
1196        else:
1197            data_name = str(model.__class__.__name__) + '2d'
1198
1199        if len(title) > 1:
[49ab5d7]1200            new_plot.title = "Gen Theory for %s " % model.name + data_name
[318b5bbb]1201        new_plot.name = new_plot.id
1202        new_plot.label = new_plot.id
1203        #theory_data = deepcopy(new_plot)
1204        if self.parent.parent != None:
1205            self.parent.parent.update_theory(data_id=data.id,
1206                                           theory=new_plot,
1207                                           state=state)
1208        title = new_plot.title
1209        num_graph = str(self.graph_num)
[49ab5d7]1210        wx.CallAfter(self.parent.draw_graph, new_plot,
1211                     title="GEN Graph %s: " % num_graph + new_plot.id)
[318b5bbb]1212        self.graph_num += 1
[49ab5d7]1213
[318b5bbb]1214    def set_scale2d(self, scale):
1215        """
1216        Set SLD plot scale
1217        """
1218        self.scale2d = None
[49ab5d7]1219
[318b5bbb]1220    def on_panel_close(self, event):
1221        """
[d5419f7f]1222        close the window containing this panel
[318b5bbb]1223        """
[d5419f7f]1224        self.parent.Close()
[49ab5d7]1225
[318b5bbb]1226class OmfPanel(ScrolledPanel, PanelBase):
1227    """
1228        Provides the sas gen calculator GUI.
1229    """
1230    ## Internal nickname for the window, used by the AUI manager
1231    window_name = "SLD Pixel Info"
1232    ## Name to appear on the window title bar
1233    window_caption = "SLD Pixel Info "
[49ab5d7]1234
[318b5bbb]1235    def __init__(self, parent, *args, **kwds):
[49ab5d7]1236        ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER,
[318b5bbb]1237                               *args, **kwds)
1238        PanelBase.__init__(self)
1239        #Font size
1240        self.SetWindowVariant(variant=FONT_VARIANT)
[49ab5d7]1241        self.SetupScrolling()
[318b5bbb]1242        # Object that receive status event
1243        self.parent = parent
[49ab5d7]1244        self.sld_data = sas_gen.MagSLD([0], [0], [0])
[318b5bbb]1245        self.sld_ctl = None
1246        self.default_shape = 'rectangular'
1247        self._do_layout()
[49ab5d7]1248
[318b5bbb]1249    def set_slddata(self, slddata):
1250        """
1251        Set sld data related items
1252        """
1253        self.sld_data = slddata
1254        self._set_slddata_ctr_val(slddata)
1255        # Make sure that self._set_slddata_ctr_val() is finished
1256        wx.CallAfter(self._set_omfdata_ctr, slddata)
[49ab5d7]1257
[318b5bbb]1258    def get_sld_val(self):
1259        """
1260        Set sld_n of slddata on sld input
1261        """
1262        sld_sets = {}
1263        if not self.sld_data.is_data:
1264            self._get_other_val()
1265        for list in self.slds:
1266            if list[1].IsEnabled():
1267                list[1].SetBackgroundColour("white")
1268                list[1].Refresh()
1269                try:
1270                    val = float(list[1].GetValue())
1271                    sld_sets[list[0]] = val
1272                except:
1273                    flag = _set_error(self, list[1])
1274                    if not flag:
1275                        return self.sld_data
1276            else:
[cd89c6f]1277               sld_sets[list[0]] = None
[318b5bbb]1278        for key in sld_sets.keys():
1279            key_low = key.lower()
1280            if key_low.count('mx') > 0:
1281                if sld_sets[key] == None:
1282                    sld_sets[key] = self.sld_data.sld_mx
1283                mx = sld_sets[key]
1284            elif key_low.count('my') > 0:
1285                if sld_sets[key] == None:
1286                    sld_sets[key] = self.sld_data.sld_my
1287                my = sld_sets[key]
1288            elif key_low.count('mz') > 0:
1289                if sld_sets[key] == None:
1290                    sld_sets[key] = self.sld_data.sld_mz
1291                mz = sld_sets[key]
1292            else:
1293                if sld_sets[key] != None:
1294                    self.sld_data.set_sldn(sld_sets[key])
1295        self.sld_data.set_sldms(mx, my, mz)
1296        self._set_slddata_ctr_val(self.sld_data)
[49ab5d7]1297
[318b5bbb]1298        return self.sld_data
[49ab5d7]1299
[dbc01f2]1300    def get_pix_volumes(self):
[318b5bbb]1301        """
1302        Get the pixel volume
1303        """
[dbc01f2]1304        vol = self.sld_data.vol_pix
[49ab5d7]1305
[dbc01f2]1306        return vol
[49ab5d7]1307
1308    def _get_other_val(self):
[318b5bbb]1309        """
1310        """
[b9a5f0e]1311        omfdata = sas_gen.OMFData()
[318b5bbb]1312        sets = {}
1313        try:
1314            for lst in self.stepsize:
1315                if lst[1].IsEnabled():
1316                    val = float(lst[1].GetValue())
1317                    sets[lst[0]] = val
1318                else:
1319                    sets[lst[0]] = None
1320                    return
1321            for lst in self.nodes:
1322                if lst[1].IsEnabled():
1323                    val = float(lst[1].GetValue())
1324                    sets[lst[0]] = val
1325                else:
1326                    sets[lst[0]] = None
1327                    return
[49ab5d7]1328
[318b5bbb]1329            for key in sets.keys():
[c4f6851]1330                setattr(omfdata, key, sets[key])
[318b5bbb]1331
[b9a5f0e]1332            omf2sld = sas_gen.OMF2SLD()
[318b5bbb]1333            omf2sld.set_data(omfdata, self.default_shape)
1334            self.sld_data = omf2sld.output
1335            self.sld_data.is_data = False
1336            self.sld_data.filename = "Default SLD Profile"
1337        except:
[49ab5d7]1338            msg = "OMF Panel: %s" % sys.exc_value
[318b5bbb]1339            infor = 'Error'
1340            #logging.error(msg)
1341            if self.parent.parent != None:
1342                # inform msg to wx
1343                wx.PostEvent(self.parent.parent,
1344                        StatusEvent(status=msg, info=infor))
1345                self.SetFocus()
[49ab5d7]1346
[318b5bbb]1347    def _set_slddata_ctr_val(self, slddata):
1348        """
1349        Set slddata crl
1350        """
1351        try:
1352            val = str(len(slddata.sld_n))
1353        except:
1354            val = 'Unknown'
1355        self.npix_ctl.SetValue(val)
[49ab5d7]1356
1357    def _set_omfdata_ctr(self, omfdata):
[318b5bbb]1358        """
1359        Set the textctr box values
1360        """
[49ab5d7]1361
[318b5bbb]1362        if omfdata == None:
1363            self._set_none_text()
1364            return
1365        nodes_list = self._get_nodes_key_list(omfdata)
1366        step_list = self._get_step_key_list(omfdata)
1367        for ctr_list in self.nodes:
1368            for key in nodes_list.keys():
1369                if ctr_list[0] == key:
1370                    ctr_list[1].SetValue(format_number(nodes_list[key], True))
1371                    ctr_list[1].Enable(not omfdata.is_data)
1372                    break
1373        for ctr_list in self.stepsize:
1374            for key in step_list.keys():
1375                if ctr_list[0] == key:
1376                    ctr_list[1].SetValue(format_number(step_list[key], True))
1377                    ctr_list[1].Enable(not omfdata.is_data)
[49ab5d7]1378                    break
1379
[318b5bbb]1380    def _set_none_text(self):
1381        """
1382        Set Unknown in textctrls
1383        """
1384        val = 'Unknown'
1385        for ctr_list in self.nodes:
1386            ctr_list[1].SetValue(val)
1387        for ctr_list in self.stepsize:
1388            ctr_list[1].SetValue(val)
[49ab5d7]1389
[318b5bbb]1390    def _define_structure(self):
1391        """
1392        Define the main sizers building to build this application.
1393        """
1394        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
[49ab5d7]1395
[318b5bbb]1396        self.npixels_sizer = wx.BoxSizer(wx.HORIZONTAL)
[49ab5d7]1397        self.box_sld = wx.StaticBox(self, -1,
[be0fe41]1398                                    str("Mean SLD"))
[318b5bbb]1399        self.box_node = wx.StaticBox(self, -1, str("Nodes"))
1400        self.boxsizer_sld = wx.StaticBoxSizer(self.box_sld, wx.VERTICAL)
1401        self.box_stepsize = wx.StaticBox(self, -1, str("Step Size"))
1402        self.boxsizer_node = wx.StaticBoxSizer(self.box_node, wx.VERTICAL)
1403        self.boxsizer_stepsize = wx.StaticBoxSizer(self.box_stepsize,
1404                                                    wx.VERTICAL)
1405        self.sld_sizer = wx.BoxSizer(wx.HORIZONTAL)
1406        self.node_sizer = wx.BoxSizer(wx.HORIZONTAL)
1407        self.step_sizer = wx.BoxSizer(wx.HORIZONTAL)
1408        self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
1409        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
[49ab5d7]1410
[318b5bbb]1411    def _layout_npix(self):
1412        """
1413        Build No of pixels sizer
1414        """
[49ab5d7]1415        num_pix_text = wx.StaticText(self, -1, "No. of Pixels: ")
[318b5bbb]1416        self.npix_ctl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1417                                style=wx.TE_PROCESS_ENTER)
1418        self._set_slddata_ctr_val(self.sld_data)
[49ab5d7]1419        self._set_omfdata_ctr(self.sld_data)
[318b5bbb]1420        self.npixels_sizer.AddMany([(num_pix_text, 0,
[49ab5d7]1421                                          wx.EXPAND | wx.LEFT | wx.TOP, 5),
[318b5bbb]1422                                     (self.npix_ctl, 0,
[49ab5d7]1423                                     wx.EXPAND | wx.TOP, 5)])
[318b5bbb]1424
1425    def _layout_slds(self):
1426        """
1427        Build nuclear sld sizer
1428        """
1429        self.slds = []
1430        omfdata = self.sld_data
1431        if omfdata == None:
1432            raise
1433        sld_key_list = self._get_slds_key_list(omfdata)
1434        # Dic is not sorted
1435        key_list = [key for key in sld_key_list.keys()]
1436        # Sort here
1437        key_list.sort()
1438        is_data = self.sld_data.is_data
1439        sizer = wx.GridBagSizer(2, 3)
1440        ix = 0
1441        iy = -1
1442        for key in key_list:
1443            value = sld_key_list[key]
1444            iy += 1
1445            ix = 0
1446            name = wx.StaticText(self, -1, key)
1447            sizer.Add(name, (iy, ix), (1, 1), \
1448                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1449            ## add parameter value
1450            ix += 1
1451            ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1452                                style=wx.TE_PROCESS_ENTER)
1453            ctl.SetValue(format_number(value, True))
1454            ctl.Enable(not is_data)
1455            sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
1456            ## add unit
1457            ix += 1
1458            s_unit = '[' + omfdata.sld_unit + ']'
1459            unit = wx.StaticText(self, -1, s_unit)
1460            sizer.Add(unit, (iy, ix), (1, 1), \
1461                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1462            self.slds.append([key, ctl, unit])
[49ab5d7]1463        self.sld_sizer.Add(sizer, 0, wx.LEFT, 10)
1464
[318b5bbb]1465    def _layout_nodes(self):
1466        """
1467        Fill the sizer containing data's name
1468        """
1469        self.nodes = []
1470        omfdata = self.sld_data
1471        if omfdata == None:
1472            raise
1473        key_list = self._get_nodes_key_list(omfdata)
1474        is_data = self.sld_data.is_data
1475        sizer = wx.GridBagSizer(2, 3)
1476        ix = 0
1477        iy = -1
1478        for key, value in key_list.iteritems():
1479            iy += 1
1480            ix = 0
1481            name = wx.StaticText(self, -1, key)
1482            sizer.Add(name, (iy, ix), (1, 1), \
1483                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1484            ## add parameter value
1485            ix += 1
1486            ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1487                                style=wx.TE_PROCESS_ENTER)
[49ab5d7]1488            ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
[318b5bbb]1489            ctl.SetValue(format_number(value, True))
1490            ctl.Enable(not is_data)
1491            sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
1492            ## add unit
1493            ix += 1
1494            unit = wx.StaticText(self, -1, '')
1495            sizer.Add(unit, (iy, ix), (1, 1), \
1496                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1497            self.nodes.append([key, ctl, unit])
1498        self.node_sizer.Add(sizer, 0, wx.LEFT, 10)
[49ab5d7]1499
[318b5bbb]1500    def _layout_stepsize(self):
1501        """
1502        Fill the sizer containing slit size information
1503        """
1504        self.stepsize = []
1505        omfdata = self.sld_data
1506        if omfdata == None:
1507            raise
1508        key_list = self._get_step_key_list(omfdata)
1509        is_data = self.sld_data.is_data
1510        sizer = wx.GridBagSizer(2, 3)
1511        ix = 0
1512        iy = -1
1513        #key_list.sort()
1514        for key, value in key_list.iteritems():
1515            iy += 1
1516            ix = 0
1517            name = wx.StaticText(self, -1, key)
1518            sizer.Add(name, (iy, ix), (1, 1), \
1519                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1520            ## add parameter value
1521            ix += 1
1522            ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1523                                style=wx.TE_PROCESS_ENTER)
[49ab5d7]1524            ctl.Bind(wx.EVT_TEXT, self._onstepsize)
[318b5bbb]1525            ctl.SetValue(format_number(value, True))
1526            ctl.Enable(not is_data)
1527            sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
1528            ## add unit
1529            ix += 1
1530            p_unit = '[' + omfdata.pos_unit + ']'
1531            unit = wx.StaticText(self, -1, p_unit)
1532            sizer.Add(unit, (iy, ix), (1, 1), \
1533                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1534            self.stepsize.append([key, ctl, unit])
1535        self.step_sizer.Add(sizer, 0, wx.LEFT, 10)
[49ab5d7]1536
[318b5bbb]1537    def _layout_hint(self):
1538        """
[49ab5d7]1539        Fill the sizer containing hint
[318b5bbb]1540        """
1541        hint_msg = "Load an omf or 3d sld profile data file."
1542        self.hint_txt = wx.StaticText(self, -1, hint_msg)
1543        self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
[49ab5d7]1544
1545    def _layout_button(self):
[318b5bbb]1546        """
1547        Do the layout for the button widgets
[49ab5d7]1548        """
1549        self.bt_draw = wx.Button(self, wx.NewId(), 'Draw Points')
[318b5bbb]1550        self.bt_draw.Bind(wx.EVT_BUTTON, self.on_sld_draw)
1551        self.bt_draw.SetToolTipString("Draw a scatter plot for sld profile.")
[49ab5d7]1552        self.bt_save = wx.Button(self, wx.NewId(), 'Save SLD Data')
[318b5bbb]1553        self.bt_save.Bind(wx.EVT_BUTTON, self.on_save)
1554        self.bt_save.Enable(False)
1555        self.bt_save.SetToolTipString("Save SLD data.")
1556        self.button_sizer.AddMany([(self.bt_draw, 0, wx.LEFT, 10),
1557                                   (self.bt_save, 0, wx.LEFT, 10)])
[49ab5d7]1558
[318b5bbb]1559    def _do_layout(self):
1560        """
[3f5d75b]1561        Draw omf panel content, used to define sld s.
[49ab5d7]1562
[318b5bbb]1563        """
1564        self._define_structure()
1565        self._layout_nodes()
1566        self._layout_stepsize()
1567        self._layout_npix()
1568        self._layout_slds()
1569        #self._layout_hint()
1570        self._layout_button()
1571        self.boxsizer_node.AddMany([(self.node_sizer, 0,
[49ab5d7]1572                                    wx.EXPAND | wx.TOP, 5),
[318b5bbb]1573                                     (self.hint_sizer, 0,
[49ab5d7]1574                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
[318b5bbb]1575        self.boxsizer_stepsize.AddMany([(self.step_sizer, 0,
[49ab5d7]1576                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
[318b5bbb]1577        self.boxsizer_sld.AddMany([(self.sld_sizer, 0,
[49ab5d7]1578                                     wx.EXPAND | wx.BOTTOM, 5), ])
1579        self.main_sizer.AddMany([(self.npixels_sizer, 0, wx.EXPAND | wx.ALL, 10),
1580                        (self.boxsizer_sld, 0, wx.EXPAND | wx.ALL, 10),
1581                        (self.boxsizer_node, 0, wx.EXPAND | wx.ALL, 10),
1582                        (self.boxsizer_stepsize, 0, wx.EXPAND | wx.ALL, 10),
1583                        (self.button_sizer, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
[318b5bbb]1584        self.SetSizer(self.main_sizer)
1585        self.SetAutoLayout(True)
[49ab5d7]1586
[318b5bbb]1587    def _get_nodes_key_list(self, data):
1588        """
1589        Return nodes key list
[49ab5d7]1590
[318b5bbb]1591        :Param data: OMFData
1592        """
[49ab5d7]1593        key_list = {'xnodes' : data.xnodes,
[318b5bbb]1594                    'ynodes' : data.ynodes,
1595                    'znodes' : data.znodes}
1596        return key_list
[49ab5d7]1597
[318b5bbb]1598    def _get_slds_key_list(self, data):
1599        """
1600        Return nodes key list
[49ab5d7]1601
[318b5bbb]1602        :Param data: OMFData
1603        """
[49ab5d7]1604        key_list = {'Nucl.' : data.sld_n,
[318b5bbb]1605                    'Mx' : data.sld_mx,
1606                    'My' : data.sld_my,
1607                    'Mz' : data.sld_mz}
1608        return key_list
1609
1610    def _get_step_key_list(self, data):
1611        """
1612        Return step key list
[49ab5d7]1613
[318b5bbb]1614        :Param data: OMFData
1615        """
[49ab5d7]1616        key_list = {'xstepsize' : data.xstepsize,
[318b5bbb]1617                    'ystepsize' : data.ystepsize,
1618                    'zstepsize' : data.zstepsize}
[49ab5d7]1619        return key_list
1620
[318b5bbb]1621    def set_sld_ctr(self, sld_data):
1622        """
[077207b]1623        Set sld textctrls
[318b5bbb]1624        """
1625        if sld_data == None:
1626            for ctr_list in self.slds:
1627                ctr_list[1].Enable(False)
1628                #break   
1629            return
[49ab5d7]1630
[318b5bbb]1631        self.sld_data = sld_data
1632        sld_list = self._get_slds_key_list(sld_data)
1633        for ctr_list in self.slds:
1634            for key in sld_list.keys():
1635                if ctr_list[0] == key:
1636                    min_val = numpy.min(sld_list[key])
1637                    max_val = numpy.max(sld_list[key])
1638                    mean_val = numpy.mean(sld_list[key])
[077207b]1639                    enable = (min_val == max_val) and \
1640                             sld_data.pix_type == 'pixel'
[318b5bbb]1641                    ctr_list[1].SetValue(format_number(mean_val, True))
1642                    ctr_list[1].Enable(enable)
[dbc01f2]1643                    #ctr_list[2].SetLabel("[" + sld_data.sld_unit + "]")
[49ab5d7]1644                    break
[318b5bbb]1645
1646    def on_sld_draw(self, event):
1647        """
1648        Draw sld profile as scattered plot
1649        """
1650        self.parent.sld_draw()
[49ab5d7]1651
[318b5bbb]1652    def on_save(self, event):
1653        """
1654        Close the window containing this panel
1655        """
1656        flag = True
1657        flag = self.check_inputs()
1658        if not flag:
1659            return
1660        self.sld_data = self.get_sld_val()
1661        self.parent.set_main_panel_sld_data(self.sld_data)
[49ab5d7]1662
1663        reader = sas_gen.SLDReader()
[318b5bbb]1664        extension = '*.sld'
1665        path = None
[49ab5d7]1666        data = None
[318b5bbb]1667        location = self.parent.get_path()
1668        dlg = wx.FileDialog(self, "Save sld file",
1669                            location, "sld_file",
[49ab5d7]1670                             extension,
[318b5bbb]1671                             wx.SAVE)
1672        if dlg.ShowModal() == wx.ID_OK:
1673            path = dlg.GetPath()
1674            self.parent.set_file_location(os.path.dirname(path))
1675        else:
1676            return None
1677        dlg.Destroy()
1678        try:
1679            if path is None:
1680                return
[49ab5d7]1681
[318b5bbb]1682            data = self.parent.get_sld_data()
1683            fName = os.path.splitext(path)[0] + '.' + extension.split('.')[-1]
1684            if data != None:
1685                try:
1686                    reader.write(fName, data)
1687                except:
1688                    raise
1689            else:
1690                msg = "%s cannot write %s\n" % ('Generic Scattering', str(path))
1691                infor = 'Error'
1692                #logging.error(msg)
1693                if self.parent.parent != None:
1694                    # inform msg to wx
1695                    wx.PostEvent(self.parent.parent,
1696                            StatusEvent(status=msg, info=infor))
1697                    self.SetFocus()
1698            return
1699        except:
1700            msg = "Error occurred while saving. "
1701            infor = 'Error'
1702            if self.parent.parent != None:
1703                # inform msg to wx
1704                wx.PostEvent(self.parent.parent,
[49ab5d7]1705                        StatusEvent(status=msg, info=infor))
1706                self.SetFocus()
[318b5bbb]1707
1708    def _onparamEnter(self, event):
1709        """
1710        """
1711        flag = True
1712        if event != None:
1713            event.Skip()
1714            ctl = event.GetEventObject()
1715            ctl.SetBackgroundColour("white")
1716            #_set_error(self, ctl)
1717        try:
1718            float(ctl.GetValue())
1719        except:
1720            flag = _set_error(self, ctl)
1721        if flag:
1722            npts = 1
1723            for item in self.nodes:
1724                n_val = float(item[1].GetValue())
1725                if n_val <= 0:
1726                    item[1].SetBackgroundColour("pink")
1727                    npts = -1
1728                    break
[dbc5dc9b]1729                if numpy.isfinite(n_val):
1730                    npts *= int(n_val)
[318b5bbb]1731            if npts > 0:
1732                nop = self.set_npts_from_slddata()
1733                if nop == None:
1734                    nop = npts
1735                self.display_npts(nop)
[49ab5d7]1736
[318b5bbb]1737        ctl.Refresh()
1738        return flag
[49ab5d7]1739
[afd45674]1740    def _set_volume_ctr_val(self, npts):
1741        """
1742        Set total volume
1743        """
1744        total_volume = npts * self.sld_data.vol_pix[0]
1745        self.parent.set_volume_ctr_val(total_volume)
[49ab5d7]1746
[dbc01f2]1747    def _onstepsize(self, event):
1748        """
1749        On stepsize event
1750        """
1751        flag = True
1752        if event != None:
1753            event.Skip()
1754            ctl = event.GetEventObject()
1755            ctl.SetBackgroundColour("white")
1756
1757        if flag and not self.sld_data.is_data:#ctl.IsEnabled():
1758            s_size = 1.0
1759            try:
1760                for item in self.stepsize:
1761                    s_val = float(item[1].GetValue())
1762                    if s_val <= 0:
1763                        item[1].SetBackgroundColour("pink")
1764                        ctl.Refresh()
1765                        return
1766                    if numpy.isfinite(s_val):
1767                        s_size *= s_val
1768                self.sld_data.set_pixel_volumes(s_size)
[afd45674]1769                if ctl.IsEnabled():
1770                    total_volume = sum(self.sld_data.vol_pix)
1771                    self.parent.set_volume_ctr_val(total_volume)
[dbc01f2]1772            except:
1773                pass
1774        ctl.Refresh()
[49ab5d7]1775
1776
[318b5bbb]1777    def set_npts_from_slddata(self):
1778        """
1779        Set total n. of points form the sld data
1780        """
1781        try:
1782            sld_data = self.parent.get_sld_from_omf()
1783            #nop = (nop * numpy.pi) / 6
1784            nop = len(sld_data.sld_n)
1785        except:
1786            nop = None
1787        return nop
[49ab5d7]1788
[318b5bbb]1789    def display_npts(self, nop):
1790        """
1791        Displays Npts ctrl
1792        """
1793        try:
1794            self.npix_ctl.SetValue(str(nop))
1795            self.npix_ctl.Refresh()
1796            self.parent.set_etime()
[afd45674]1797            wx.CallAfter(self._set_volume_ctr_val, nop)
[318b5bbb]1798        except:
1799            # On Init
1800            pass
[49ab5d7]1801
[318b5bbb]1802    def check_inputs(self):
1803        """
1804        check if the inputs are valid
1805        """
1806        flag = self._check_input_helper(self.slds)
1807        if flag:
1808            flag = self._check_input_helper(self.nodes)
1809        if flag:
1810            flag = self._check_input_helper(self.stepsize)
1811        return flag
[49ab5d7]1812
[318b5bbb]1813    def _check_input_helper(self, list):
1814        """
1815        Check list values
1816        """
1817        flag = True
1818        for item in list:
1819            item[1].SetBackgroundColour("white")
1820            item[1].Refresh()
1821            try:
1822                float(item[1].GetValue())
1823            except:
1824                flag = _set_error(self, item[1])
1825                break
1826        return flag
1827
[d0923a3]1828class SasGenWindow(widget.CHILD_FRAME):
[318b5bbb]1829    """
1830    GEN SAS main window
1831    """
[49ab5d7]1832    def __init__(self, parent=None, manager=None, title="Generic Scattering Calculator",
[3f5d75b]1833                size=(PANEL_WIDTH * 1.4, PANEL_HEIGHT * 1.65), *args, **kwds):
[318b5bbb]1834        """
1835        Init
1836        """
[cd89c6f]1837        kwds['size'] = size
1838        kwds['title'] = title
[d0923a3]1839        widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
[318b5bbb]1840        self.parent = parent
[ae84427]1841        self.base = manager
[318b5bbb]1842        self.omfpanel = OmfPanel(parent=self)
1843        self.panel = SasGenPanel(parent=self)
1844        self.data = None
[b9a5f0e]1845        self.omfdata = sas_gen.OMFData()
[318b5bbb]1846        self.sld_data = None
[49ab5d7]1847        self._default_save_location = os.getcwd()
1848
[318b5bbb]1849        self._mgr = aui.AuiManager(self)
1850        self._mgr.SetDockSizeConstraint(0.5, 0.5)
1851        self._plot_title = ''
1852        self.scale2d = 'log_{10}'
[ae84427]1853        self.Bind(wx.EVT_CLOSE, self.on_close)
[49ab5d7]1854
1855
[318b5bbb]1856        self.build_panels()
[60dca65c]1857        self.SetPosition((wx.LEFT, PANEL_TOP))
[318b5bbb]1858        self.Show(True)
[49ab5d7]1859
[318b5bbb]1860    def build_panels(self):
1861        """
1862        """
[49ab5d7]1863
[318b5bbb]1864        self.set_sld_data(self.sld_data)
1865        self._mgr.AddPane(self.panel, aui.AuiPaneInfo().
1866                              Name(self.panel.window_name).
1867                              CenterPane().
1868                              # This is where we set the size of
1869                              # the application window
[49ab5d7]1870                              BestSize(wx.Size(PANEL_WIDTH,
[318b5bbb]1871                                               PANEL_HEIGHT)).
[49ab5d7]1872                              Show())
[318b5bbb]1873        self._mgr.AddPane(self.omfpanel, aui.AuiPaneInfo().
1874                              Name(self.omfpanel.window_name).
1875                              Caption(self.omfpanel.window_caption).
1876                              CloseButton(False).
1877                              Right().
1878                              Floatable(False).
[49ab5d7]1879                              BestSize(wx.Size(PANEL_WIDTH / 2.5, PANEL_HEIGHT)).
1880                              Show())
[318b5bbb]1881        self._mgr.Update()
1882
1883    def get_sld_data(self):
1884        """
1885        Return slddata
1886        """
1887        return self.sld_data
[49ab5d7]1888
[318b5bbb]1889    def get_sld_from_omf(self):
1890        """
1891        """
1892        self.sld_data = self.omfpanel.get_sld_val()
1893        return self.sld_data
[49ab5d7]1894
[318b5bbb]1895    def set_sld_n(self, sld):
1896        """
1897        """
1898        self.panel.sld_data = sld
1899        self.panel.model.set_sld_data(sld)
[49ab5d7]1900
[318b5bbb]1901    def set_sld_data(self, data):
1902        """
1903        Set omfdata
1904        """
1905        if data == None:
1906            return
1907        self.sld_data = data
[49ab5d7]1908        enable = (not data == None)
[318b5bbb]1909        self._set_omfpanel_sld_data(self.sld_data)
1910        self.omfpanel.bt_save.Enable(enable)
1911        self.set_etime()
[49ab5d7]1912
[318b5bbb]1913    def set_omfpanel_npts(self):
1914        """
1915        Set Npts in omf panel
1916        """
1917        nop = self.omfpanel.set_npts_from_slddata()
1918        self.omfpanel.display_npts(nop)
[49ab5d7]1919
[318b5bbb]1920    def _set_omfpanel_sld_data(self, data):
1921        """
1922        Set sld_data in omf panel
1923        """
[49ab5d7]1924        self.omfpanel.set_slddata(data)
[318b5bbb]1925        self.omfpanel.set_sld_ctr(data)
[49ab5d7]1926
[318b5bbb]1927    def check_omfpanel_inputs(self):
1928        """
1929        Check OMF panel inputs
1930        """
[49ab5d7]1931        return self.omfpanel.check_inputs()
1932
[318b5bbb]1933    def set_main_panel_sld_data(self, sld_data):
1934        """
1935        """
1936        self.sld_data = sld_data
[49ab5d7]1937
[318b5bbb]1938    def set_file_location(self, path):
1939        """
1940        File location
1941        """
1942        self._default_save_location = path
[49ab5d7]1943
[318b5bbb]1944    def get_path(self):
1945        """
1946        File location
1947        """
1948        return self._default_save_location
[49ab5d7]1949
[318b5bbb]1950    def draw_graph(self, plot, title=''):
1951        """
1952        """
[49ab5d7]1953        try:
[62af27a9]1954            wx.PostEvent(self.parent, NewPlotEvent(plot=plot, title=title))
1955        except:
1956            # standalone
1957            frame = PlotFrame(self, -1, 'testView', self.scale2d)
1958            #add_icon(self.parent, frame)
1959            frame.add_plot(plot)
1960            frame.SetTitle(title)
1961            frame.Show(True)
1962            frame.SetFocus()
1963
[49ab5d7]1964    def set_schedule_full_draw(self, panel=None, func='del'):
[ae84427]1965        """
1966        Send full draw to gui frame
1967        """
[62af27a9]1968        if self.parent != None:
1969            self.parent.set_schedule_full_draw(panel, func)
[49ab5d7]1970
[318b5bbb]1971    def get_npix(self):
1972        """
1973        Get no. of pixels from omf panel
1974        """
1975        n_pix = self.omfpanel.npix_ctl.GetValue()
1976        return n_pix
[49ab5d7]1977
[dbc01f2]1978    def get_pix_volumes(self):
[318b5bbb]1979        """
1980        Get a pixel volume
1981        """
[dbc01f2]1982        vol = self.omfpanel.get_pix_volumes()
[318b5bbb]1983        return vol
[49ab5d7]1984
[afd45674]1985    def set_volume_ctr_val(self, val):
1986        """
1987        Set volume txtctl value
1988        """
1989        try:
1990            self.panel.set_volume_ctl_val(str(val))
1991        except:
1992            print "self.panel is not initialized yet"
[49ab5d7]1993
[318b5bbb]1994    def set_omfpanel_default_shap(self, shape):
1995        """
1996        Set default_shape in omfpanel
1997        """
1998        self.omfpanel.default_shape = shape
[49ab5d7]1999
[318b5bbb]2000    def set_etime(self):
2001        """
2002        Sets est. computation time on panel
2003        """
2004        self.panel.set_est_time()
[49ab5d7]2005
[318b5bbb]2006    def get_sld_data_from_omf(self):
2007        """
2008        """
[49ab5d7]2009        data = self.omfpanel.get_sld_val()
[318b5bbb]2010        return data
[49ab5d7]2011
[318b5bbb]2012    def set_scale2d(self, scale):
2013        """
2014        """
2015        self.scale2d = scale
[49ab5d7]2016
[318b5bbb]2017    def on_panel_close(self, event):
2018        """
2019        """
2020        #Not implemented
[49ab5d7]2021
[318b5bbb]2022    def on_open_file(self, event):
2023        """
2024        On Open
2025        """
2026        self.panel.on_load_data(event)
[49ab5d7]2027
[318b5bbb]2028    def sld_draw(self):
2029        """
2030        sld draw
2031        """
[1de85f4]2032        self.panel.sld_draw(event=None, has_arrow=False)
[49ab5d7]2033
[318b5bbb]2034    def on_save_file(self, event):
2035        """
2036        On Close
2037        """
2038        self.omfpanel.on_save(event)
[49ab5d7]2039
[318b5bbb]2040    def on_close(self, event):
2041        """
2042        Close
2043        """
[ae84427]2044        if self.base != None:
2045            self.base.gen_frame = None
[318b5bbb]2046        self.Destroy()
[49ab5d7]2047
2048if __name__ == "__main__":
[318b5bbb]2049    app = wx.PySimpleApp()
[62af27a9]2050    widget.CHILD_FRAME = wx.Frame
[49ab5d7]2051    SGframe = SasGenWindow()
[cd89c6f]2052    SGframe.Show(True)
[49ab5d7]2053    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.