source: branch/2frame/GSASII.py @ 2890

Last change on this file since 2890 was 2890, checked in by vondreele, 6 years ago

Constraints now displayed
fix TopLevel? references
fix display issues for Sample Parameters
fix Resttraints display issues

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Date Author Revision URL Id
File size: 211.3 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#GSASII
4########### SVN repository information ###################
5# $Date: 2017-07-01 16:17:10 +0000 (Sat, 01 Jul 2017) $
6# $Author: vondreele $
7# $Revision: 2890 $
8# $URL: branch/2frame/GSASII.py $
9# $Id: GSASII.py 2890 2017-07-01 16:17:10Z vondreele $
10########### SVN repository information ###################
11'''
12*GSAS-II Main Module*
13=====================
14
15Main routines for the GSAS-II program
16'''
17
18import os
19import sys
20import math
21import copy
22import random as ran
23import glob
24import imp
25import inspect
26import numpy as np
27import scipy as sp
28import wx
29import wx.lib.scrolledpanel as wxscroll
30try:  # patch for LANG environment var problem on occasional OSX machines
31    import locale
32    locale.getdefaultlocale()
33except ValueError:
34    print('Fixing location (see https://github.com/matplotlib/matplotlib/issues/5420.)')
35    os.environ['LC_ALL'] = 'en_US.UTF-8'
36    locale.getdefaultlocale()
37import matplotlib as mpl
38try:
39    import OpenGL as ogl
40except ImportError:
41    print('*******************************************************')
42    print('PyOpenGL is missing from your python installation')
43    print('     - we will try to install it')
44    print('*******************************************************')
45    def install_with_easyinstall(package):
46        try: 
47            print "trying a system-wide PyOpenGl install"
48            easy_install.main(['-f',os.path.split(__file__)[0],package])
49            return
50        except:
51            pass
52        try: 
53            print "trying a user level PyOpenGl install"
54            easy_install.main(['-f',os.path.split(__file__)[0],'--user',package])
55            return
56        except:
57            print "Install of '+package+' failed. Please report this information:"
58            import traceback
59            print traceback.format_exc()
60            sys.exit()
61    from setuptools.command import easy_install
62    install_with_easyinstall('PyOpenGl')
63    print('*******************************************************')         
64    print('OpenGL has been installed. Restarting GSAS-II')
65    print('*******************************************************')         
66    loc = os.path.dirname(__file__)
67    import subprocess
68    subprocess.Popen([sys.executable,os.path.join(loc,'GSASII.py')])
69    sys.exit()
70   
71# load the GSAS routines
72import GSASIIpath
73GSASIIpath.SetVersionNumber("$Revision: 2890 $")
74import GSASIIIO as G2IO
75import GSASIIElem as G2elem
76import GSASIIgrid as G2gd
77import GSASIIctrls as G2G
78import GSASIIplot as G2plt
79import GSASIIpwd as G2pwd
80import GSASIIpwdGUI as G2pdG
81import GSASIIspc as G2spc
82import GSASIIstrMain as G2stMn
83import GSASIIstrIO as G2stIO
84import GSASIImath as G2mth
85import GSASIImapvars as G2mv
86import GSASIIobj as G2obj
87import GSASIIlattice as G2lat
88import GSASIIlog as log
89WACV = wx.ALIGN_CENTER_VERTICAL
90#                GSASIIpath.IPyBreak()
91
92__version__ = '0.3.0'
93
94# PATCH: for Mavericks (OS X 10.9.x), wx produces an annoying warning about LucidaGrandeUI.
95# In case stderr has been suppressed there, redirect python error output to stdout. Nobody
96# else should care much about this.
97sys.stderr = sys.stdout
98
99def create(parent):
100    return GSASII(parent)
101
102def SetDefaultDData(dType,histoName,NShkl=0,NDij=0):
103    if dType in ['SXC','SNC']:
104        return {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
105            'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
106            'Extinction':['Lorentzian','None', {'Tbar':0.1,'Cos2TM':0.955,
107            'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]}],
108            'Flack':[0.0,False]}
109    elif dType == 'SNT':
110        return {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
111            'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
112            'Extinction':['Lorentzian','None', {
113            'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]}]}
114    elif 'P' in dType:
115        return {'Histogram':histoName,'Show':False,'Scale':[1.0,False],
116            'Pref.Ori.':['MD',1.0,False,[0,0,1],0,{},[],0.1],
117            'Size':['isotropic',[1.,1.,1.],[False,False,False],[0,0,1],
118                [1.,1.,1.,0.,0.,0.],6*[False,]],
119            'Mustrain':['isotropic',[1000.0,1000.0,1.0],[False,False,False],[0,0,1],
120                NShkl*[0.01,],NShkl*[False,]],
121            'HStrain':[NDij*[0.0,],NDij*[False,]],                         
122            'Extinction':[0.0,False],'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]}}
123
124class GSASIIsplit(wx.SplitterWindow):
125    def __init__(self,parent,ID):
126        wx.SplitterWindow.__init__(self, parent, ID,style = wx.SP_BORDER|wx.SP_LIVE_UPDATE)
127        self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
128        self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
129
130    def OnSashChanged(self, evt):
131        evt.Skip()
132#        print "sash changed to %s\n" % str(evt.GetSashPosition())
133
134    def OnSashChanging(self, evt):
135        evt.Skip()
136#        print "sash changing to %s\n" % str(evt.GetSashPosition())
137
138class GSASII(wx.Frame):
139    '''Define the main GSAS-II frame and its associated menu items
140    '''
141    def MenuBinding(self,event):
142        '''Called when a menu is clicked upon; looks up the binding in table
143        '''
144        log.InvokeMenuCommand(event.GetId(),self,event)
145           
146    def Bind(self,eventtype,handler,*args,**kwargs):
147        '''Override the Bind function so that we can wrap calls that will be logged.
148       
149        N.B. This is a bit kludgy. Menu bindings with an id are wrapped and
150        menu bindings with an object and no id are not.
151        '''
152        if eventtype == wx.EVT_MENU and 'id' in kwargs:
153            menulabels = log.SaveMenuCommand(kwargs['id'],self,handler)
154            if menulabels:
155                wx.Frame.Bind(self,eventtype,self.MenuBinding,*args,**kwargs)
156                return
157        wx.Frame.Bind(self,eventtype,handler,*args,**kwargs)     
158   
159    def _Add_FileMenuItems(self, parent):
160        item = parent.Append(
161            help='Open a GSAS-II project file (*.gpx)', id=wx.ID_ANY,
162            kind=wx.ITEM_NORMAL,text='&Open project...')
163        self.Bind(wx.EVT_MENU, self.OnFileOpen, id=item.GetId())
164        item = parent.Append(
165            help='Save project under current name', id=wx.ID_ANY,
166            kind=wx.ITEM_NORMAL,text='&Save project')
167        self.Bind(wx.EVT_MENU, self.OnFileSave, id=item.GetId())
168        item = parent.Append(
169            help='Save current project to new file', id=wx.ID_ANY,
170            kind=wx.ITEM_NORMAL,text='Save project as...')
171        self.Bind(wx.EVT_MENU, self.OnFileSaveas, id=item.GetId())
172        item = parent.Append(
173            help='Create empty new project, saving current is optional', id=wx.ID_ANY,
174            kind=wx.ITEM_NORMAL,text='&New project')
175        self.Bind(wx.EVT_MENU, self.OnFileClose, id=item.GetId())
176        item = parent.Append(wx.ID_PREFERENCES, text = "&Preferences")
177        self.Bind(wx.EVT_MENU, self.OnPreferences, item)
178        if GSASIIpath.GetConfigValue('debug'):
179            def OnIPython(event):
180                GSASIIpath.IPyBreak()
181            item = parent.Append(wx.ID_ANY, text = "IPython Console")
182            self.Bind(wx.EVT_MENU, OnIPython, item)
183        item = parent.Append(
184            help='Exit from GSAS-II', id=wx.ID_ANY,
185            kind=wx.ITEM_NORMAL,text='&Exit')
186        self.Bind(wx.EVT_MENU, self.OnFileExit, id=item.GetId())
187       
188    def _Add_DataMenuItems(self,parent):
189        item = parent.Append(
190            help='',id=wx.ID_ANY,
191            kind=wx.ITEM_NORMAL,
192            text='Read image data...')
193        self.Bind(wx.EVT_MENU, self.OnImageRead, id=item.GetId())
194        item = parent.Append(
195            help='',id=wx.ID_ANY,
196            kind=wx.ITEM_NORMAL,
197            text='Read Powder Pattern Peaks...')
198        self.Bind(wx.EVT_MENU, self.OnReadPowderPeaks, id=item.GetId())
199        item = parent.Append(
200            help='',id=wx.ID_ANY,
201            kind=wx.ITEM_NORMAL,
202            text='Sum powder data')
203        self.Bind(wx.EVT_MENU, self.OnPwdrSum, id=item.GetId())
204        item = parent.Append(
205            help='',id=wx.ID_ANY,
206            kind=wx.ITEM_NORMAL,
207            text='Sum image data')
208        self.Bind(wx.EVT_MENU, self.OnImageSum, id=item.GetId())
209        item = parent.Append(
210            help='',id=wx.ID_ANY,
211            kind=wx.ITEM_NORMAL,
212            text='Add new phase')
213        self.Bind(wx.EVT_MENU, self.OnAddPhase, id=item.GetId())
214        item = parent.Append(
215            help='',id=wx.ID_ANY,
216            kind=wx.ITEM_NORMAL,
217            text='Delete phase')
218        self.Bind(wx.EVT_MENU, self.OnDeletePhase, id=item.GetId())
219        item = parent.Append(
220            help='Rename the selected data tree item (PWDR, HKLF or IMG)',id=wx.ID_ANY,
221            kind=wx.ITEM_NORMAL,
222            text='Rename tree item') 
223        self.Bind(wx.EVT_MENU, self.OnRenameData, id=item.GetId())
224        item = parent.Append(
225            help='Delete selected data items from data tree',id=wx.ID_ANY,
226            kind=wx.ITEM_NORMAL,
227            text='Delete tree items')
228        self.Bind(wx.EVT_MENU, self.OnDataDelete, id=item.GetId())
229        expandmenu = wx.Menu()
230        item = parent.AppendMenu(
231            wx.ID_ANY, 'Expand tree items', expandmenu, 
232            help='Expand items of type in GSAS-II data tree')
233        for s in 'all','IMG','PWDR','PDF','HKLF','SASD','REFD':
234            if s == 'all':
235                help = 'Expand all items in GSAS-II data tree'
236            else:
237                help = 'Expand '+s+' type items in GSAS-II data tree'
238            item = expandmenu.Append(wx.ID_ANY,kind=wx.ITEM_NORMAL,text=s,help=help)
239            self.Bind(wx.EVT_MENU,self.ExpandAll,id=item.GetId())
240        movemenu = wx.Menu()
241        item = parent.AppendMenu(
242            wx.ID_ANY, 'Move tree items', movemenu, 
243            help='Move items of type items to end of GSAS-II data tree')
244        for s in 'IMG','PWDR','PDF','HKLF','SASD','REFD','Phase':
245            help = 'Move '+s+' type items to end of GSAS-II data tree'
246            item = movemenu.Append(wx.ID_ANY,kind=wx.ITEM_NORMAL,text=s,help=help)
247            self.Bind(wx.EVT_MENU,self.MoveTreeItems,id=item.GetId())
248
249    def _Add_CalculateMenuItems(self,parent):
250        item = parent.Append(help='Create PDF tree entries for selected powder patterns', 
251            id=wx.ID_ANY, kind=wx.ITEM_NORMAL,text='Setup PDFs')
252        self.MakePDF.append(item)
253        self.Bind(wx.EVT_MENU, self.OnMakePDFs, id=item.GetId())
254       
255        item = parent.Append(help='View least squares parameters', 
256            id=wx.ID_ANY, kind=wx.ITEM_NORMAL,text='&View LS parms')
257        self.Bind(wx.EVT_MENU, self.OnShowLSParms, id=item.GetId())
258       
259        item = parent.Append(help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
260            text='&Refine')
261        if len(self.Refine): # extend state for new menus to match main (on mac)
262            state = self.Refine[0].IsEnabled()
263        else:
264            state = False
265        item.Enable(state)
266        self.Refine.append(item)
267        self.Bind(wx.EVT_MENU, self.OnRefine, id=item.GetId())
268       
269        item = parent.Append(help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
270            text='Sequential refine')
271        self.Bind(wx.EVT_MENU, self.OnSeqRefine, id=item.GetId())
272        if len(self.SeqRefine): # extend state for new menus to match main (on mac)
273            state = self.SeqRefine[0].IsEnabled()
274        else:
275            state = False
276        item.Enable(state)
277        self.SeqRefine.append(item) # save menu obj for use in self.EnableSeqRefineMenu
278#        if GSASIIpath.GetConfigValue('debug'): # allow exceptions for debugging
279#            item = parent.Append(help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
280#                text='tree test')
281#            self.Bind(wx.EVT_MENU, self.TreeTest, id=item.GetId())
282
283    def _init_Imports(self):
284        '''import all the G2phase*.py & G2sfact*.py & G2pwd*.py files that
285        are found in the path
286        '''
287
288        self.ImportPhaseReaderlist = []
289        self._init_Import_routines('phase',self.ImportPhaseReaderlist,'Phase')
290        self.ImportSfactReaderlist = []
291        self._init_Import_routines('sfact',self.ImportSfactReaderlist,'Struct_Factor')
292        self.ImportPowderReaderlist = []
293        self._init_Import_routines('pwd',self.ImportPowderReaderlist,'Powder_Data')
294        self.ImportSmallAngleReaderlist = []
295        self._init_Import_routines('sad',self.ImportSmallAngleReaderlist,'SmallAngle_Data')
296        self.ImportReflectometryReaderlist = []
297        self._init_Import_routines('rfd',self.ImportReflectometryReaderlist,'Reflectometry_Data')
298        self.ImportPDFReaderlist = []
299        self._init_Import_routines('pdf',self.ImportPDFReaderlist,'PDF_Data')
300        self.ImportImageReaderlist = []
301        self._init_Import_routines('img',self.ImportImageReaderlist,'Images')
302        self.ImportMenuId = {}
303
304    def _init_Import_routines(self,prefix,readerlist,errprefix):
305        '''import all the import readers matching the prefix
306        '''
307        #path2GSAS2 = os.path.dirname(os.path.realpath(__file__)) # location of this file
308        #pathlist = sys.path[:]
309        #if path2GSAS2 not in pathlist: pathlist.append(path2GSAS2)
310        #path2GSAS2 = os.path.join(
311        #    os.path.dirname(os.path.realpath(__file__)), # location of this file
312        #    'imports')
313        pathlist = sys.path[:]
314        #if path2GSAS2 not in pathlist: pathlist.append(path2GSAS2)
315        if '.' not in pathlist: pathlist.append('.') # insert the directory where G2 is started
316
317        filelist = []
318        for path in pathlist:
319            for filename in glob.iglob(os.path.join(
320                path,
321                "G2"+prefix+"*.py")):
322                filelist.append(filename)   
323                #print 'debug: found',filename
324        filelist = sorted(list(set(filelist))) # remove duplicates
325        for filename in filelist:
326            path,rootname = os.path.split(filename)
327            pkg = os.path.splitext(rootname)[0]
328            try:
329                fp = None
330                fp, fppath,desc = imp.find_module(pkg,[path,])
331                pkg = imp.load_module(pkg,fp,fppath,desc)
332                for clss in inspect.getmembers(pkg): # find classes defined in package
333                    if clss[0].startswith('_'): continue
334                    if inspect.isclass(clss[1]):
335                        # check if we have the required methods
336                        for m in 'Reader','ExtensionValidator','ContentsValidator':
337                            if not hasattr(clss[1],m): break
338                            if not callable(getattr(clss[1],m)): break
339                        else:
340                            reader = clss[1]() # create an import instance
341                            if reader.UseReader:
342                                readerlist.append(reader)
343            except AttributeError:
344                print 'Import_'+errprefix+': Attribute Error '+ filename
345            #except ImportError:
346            #    print 'Import_'+errprefix+': Error importing file '+ filename
347            except Exception,errmsg:
348                print('\nImport_'+errprefix+': Error importing file '+ filename)
349                print(u'Error message: {}\n'.format(errmsg))
350            if fp: fp.close()
351
352    def EnableSeqRefineMenu(self):
353        '''Enable or disable the sequential refinement menu items based on the
354        contents of the Controls 'Seq Data' item (if present)
355        '''
356        controls = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.root, 'Controls'))
357        if controls.get('Seq Data'):
358            for i in self.SeqRefine: i.Enable(True)
359        else:
360            for i in self.SeqRefine: i.Enable(False)
361
362    def PreviewFile(self,filename,fp):
363        'confirm we have the right file'
364        rdmsg = 'File '+ filename +' begins:\n\n'
365        try:
366            rdmsg += fp.read(80)
367            rdmsg += '\n\nDo you want to read this file?'
368        except UnicodeDecodeError:
369            rdmsg = None
370        if rdmsg is None or not all([ord(c) < 128 and ord(c) != 0 for c in rdmsg]): # show only if ASCII
371            rdmsg = 'File '+ filename +' is a binary file. Do you want to read this file?'
372        # it would be better to use something that
373        # would resize better, but this will do for now
374        dlg = wx.MessageDialog(
375            self, rdmsg,
376            'Is this the file you want?', 
377            wx.YES_NO | wx.ICON_QUESTION,
378            )
379        dlg.SetSize((700,300)) # does not resize on Mac
380        result = wx.ID_NO
381        try:
382            result = dlg.ShowModal()
383        finally:
384            dlg.Destroy()
385        if result == wx.ID_NO: return True
386        return False
387   
388    def OnImportGeneric(self,reader,readerlist,label,multiple=False,
389        usedRanIdList=[],Preview=True,load2Tree=False):
390        '''Used for all imports, including Phases, datasets, images...
391
392        Called from :meth:`GSASII.OnImportPhase`, :meth:`GSASII.OnImportImage`,
393        :meth:`GSASII.OnImportSfact`, :meth:`GSASII.OnImportPowder`,
394        :meth:`GSASII.OnImportSmallAngle` and :meth:'GSASII.OnImportReflectometry`
395
396        Uses reader_objects subclassed from :class:`GSASIIobj.ImportPhase`,
397        :class:`GSASIIobj.ImportStructFactor`,
398        :class:`GSASIIobj.ImportPowderData`,
399        :class:`GSASIIobj.ImportSmallAngleData`
400        :class:`GSASIIobj.ImportReflectometryData` or
401        :class:`GSASIIobj.ImportImage`.
402        If a specific reader is specified, only that method will be called,
403        but if no reader is specified, every one that is potentially
404        compatible (by file extension) will be tried on the file(s)
405        selected in the Open File dialog.
406
407        :param reader_object reader: This will be a reference to
408          a particular object to be used to read a file or None,
409          if every appropriate reader should be used.
410
411        :param list readerlist: a list of reader objects appropriate for
412          the current read attempt. At present, this will be either
413          self.ImportPhaseReaderlist, self.ImportSfactReaderlist
414          self.ImportPowderReaderlist or self.ImportImageReaderlist
415          (defined in _init_Imports from the files found in the path),
416          but in theory this list could be tailored.
417          Used only when reader is None.
418
419        :param str label: string to place on the open file dialog:
420          Open `label` input file
421
422        :param bool multiple: True if multiple files can be selected
423          in the file dialog. False is default. At present True is used
424          only for reading of powder data.
425
426        :param list usedRanIdList: an optional list of random Ids that
427          have been used and should not be reused
428
429        :param bool Preview: indicates if a preview of the file should
430          be shown. Default is True, but set to False for image files
431          which are all binary.
432
433        :param bool load2Tree: indicates if the file should be loaded
434          into the data tree immediately (used for images only). True
435          only when called from :meth:`OnImportImage`; causes return
436          value to change to a list of True values rather than
437          reader objects.
438
439        :returns: a list of reader objects (rd_list) that were able
440          to read the specified file(s). This list may be empty.
441        '''
442        self.lastimport = ''
443        self.zipfile = None
444        singlereader = True
445        if reader is None:
446            singlereader = False
447            multiple = False
448            #print "use all formats"
449            choices = "any file (*.*)|*.*"
450            choices += "|zip archive (.zip)|*.zip"
451            extdict = {}
452            # compile a list of allowed extensions
453            for rd in readerlist:
454                fmt = rd.formatName
455                for extn in rd.extensionlist:
456                    if not extdict.get(extn): extdict[extn] = []
457                    extdict[extn] += [fmt,]
458            for extn in sorted(extdict.keys(),cmp=lambda x,y: cmp(x.lower(), y.lower())):
459                fmt = ''
460                for f in extdict[extn]:
461                    if fmt != "": fmt += ', '
462                    fmt += f
463                choices += "|" + fmt + " file (*" + extn + ")|*" + extn
464        else:
465            readerlist = [reader,]
466            # compile a list of allowed extensions
467            choices = reader.formatName + " file ("
468            w = ""
469            for extn in reader.extensionlist:
470                if w != "": w += ";"
471                w += "*" + extn
472            choices += w + ")|" + w
473            choices += "|zip archive (.zip)|*.zip"
474            if not reader.strictExtension:
475                choices += "|any file (*.*)|*.*"
476        # get the file(s)
477        if multiple:
478            mode = wx.OPEN|wx.MULTIPLE
479        else:
480            mode = wx.OPEN
481        filelist = G2G.GetImportFile(self,message="Choose "+label+" input file",
482                    defaultFile="",wildcard=choices,style=mode)
483        rd_list = []
484        filelist1 = []
485        for filename in filelist:
486            # is this a zip file?
487            if os.path.splitext(filename)[1].lower() == '.zip':
488                extractedfiles = G2IO.ExtractFileFromZip(
489                    filename,parent=self,
490                    multipleselect=True)
491                if extractedfiles is None: continue # error or Cancel
492                if extractedfiles != filename:
493                    self.zipfile = filename # save zip name
494                    filelist1 += extractedfiles
495                    continue
496            filelist1.append(filename)
497        filelist = filelist1
498        Start = True    #1st time read - clear selections below
499        for filename in filelist:
500            # is this a zip file?
501            if os.path.splitext(filename)[1].lower() == '.zip':
502                extractedfile = G2IO.ExtractFileFromZip(filename,parent=self)
503                if extractedfile is None: continue # error or Cancel
504                if extractedfile != filename:
505                    filename,self.zipfile = extractedfile,filename # now use the file that was created
506            # determine which formats are compatible with this file
507            primaryReaders = []
508            secondaryReaders = []
509            for rd in readerlist:
510                flag = rd.ExtensionValidator(filename)
511                if flag is None: 
512                    secondaryReaders.append(rd)
513                elif flag:
514                    primaryReaders.append(rd)
515            if len(secondaryReaders) + len(primaryReaders) == 0 and reader:
516                self.ErrorDialog('Not supported','The selected reader cannot read file '+filename)
517                return []
518            elif len(secondaryReaders) + len(primaryReaders) == 0:
519                self.ErrorDialog('No Format','No matching format for file '+filename)
520                return []
521
522            fp = None
523            msg = ''
524            fp = open(filename,'Ur')
525            if len(filelist) == 1 and Preview:
526                if self.PreviewFile(filename,fp): return []
527            self.lastimport = filename # this is probably not what I want to do -- it saves only the
528            # last name in a series. See rd.readfilename for a better name.
529
530            # try the file first with Readers that specify the
531            # file's extension and later with ones that merely allow it
532            errorReport = ''
533            for rd in primaryReaders+secondaryReaders:
534                if Start:   #clear old bank selections to allow new ones to be selected by user
535                    rd.selections = []
536                    rd.dnames = []
537                rd.ReInitialize() # purge anything from a previous read
538                fp.seek(0)  # rewind
539                rd.errors = "" # clear out any old errors
540                if not rd.ContentsValidator(fp): # rejected on cursory check
541                    errorReport += "\n  "+rd.formatName + ' validator error'
542                    if rd.errors: 
543                        errorReport += ': '+rd.errors
544                    continue
545                if len(rd.selections)>1 and Start:
546                    dlg = G2G.G2MultiChoiceDialog(self,'Dataset Selector','Select data to read from the list below',rd.dnames)
547                    if dlg.ShowModal() == wx.ID_OK:
548                        rd.selections = dlg.GetSelections()
549                    Start = False
550                    dlg.Destroy()
551                repeat = True
552                rdbuffer = {} # create temporary storage for file reader
553                block = 0
554                fp.seek(0)  # rewind
555                while repeat: # loop if the reader asks for another pass on the file
556                    block += 1
557                    repeat = False
558                    rd.objname = os.path.basename(filename)
559                    flag = False
560                    if GSASIIpath.GetConfigValue('debug'): # allow exceptions for debugging
561                        flag = rd.Reader(filename,fp,self,buffer=rdbuffer,blocknum=block,
562                            usedRanIdList=usedRanIdList,)
563                    else:
564                        try:
565                            flag = rd.Reader(filename,fp,self,buffer=rdbuffer,
566                                blocknum=block,usedRanIdList=usedRanIdList,)
567                        except rd.ImportException as detail:
568                            rd.errors += "\n  Read exception: "+str(detail)
569                        except Exception as detail:
570                            import traceback
571                            rd.errors += "\n  Unhandled read exception: "+str(detail)
572                            rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
573                    if flag: # this read succeeded
574                        if rd.SciPy:        #was default read by scipy; needs 1 time fixes
575                            G2IO.EditImageParms(self,rd.Data,rd.Comments,rd.Image,filename)
576                            rd.SciPy = False
577                        rd.readfilename = filename
578                        if load2Tree:   #images only
579                            if rd.repeatcount == 1 and not rd.repeat: # skip image number if only one in set
580                                rd.Data['ImageTag'] = None
581                            else:
582                                rd.Data['ImageTag'] = rd.repeatcount
583                            rd.Data['formatName'] = rd.formatName
584                            if rd.sumfile:
585                                rd.readfilename = rd.sumfile
586                            G2IO.LoadImage2Tree(rd.readfilename,self,rd.Comments,rd.Data,rd.Npix,rd.Image)
587                            rd_list.append(True) # save a stub the result before it is written over
588                            del rd.Image
589                        else:                                                   
590                            rd_list.append(copy.deepcopy(rd)) # save the result before it is written over
591                        if rd.repeat:
592                            repeat = True
593                        continue
594                    errorReport += '\n'+rd.formatName + ' read error'
595                    if rd.errors:
596                        errorReport += ': '+rd.errors
597                if rd_list: # read succeeded, was there a warning or any errors?
598                    if rd.warnings:
599                        self.ErrorDialog('Read Warning','The '+ rd.formatName+
600                            ' reader reported a warning message:\n\n'+rd.warnings)
601                    break # success in reading, try no further
602            else:
603                if singlereader:
604                    print('The '+ rd.formatName+' reader was not able to read file '+filename+msg)
605                    try:
606                        print('\n\nError message(s):\n\t'+errorReport)
607                    except:
608                        pass
609                    self.ErrorDialog('Read Error','The '+ rd.formatName+
610                        ' reader was not able to read file '+filename+msg)
611                else:
612                    print('No reader was able to read file '+filename+msg)
613                    try:
614                        print('\n\nError message(s):\n\t'+errorReport)
615                    except:
616                        pass
617                    self.ErrorDialog('Read Error','No reader was able to read file '+filename+msg)
618            if fp: fp.close()
619        return rd_list
620
621    def _Add_ImportMenu_Phase(self,parent):
622        '''configure the Import Phase menus accord to the readers found in _init_Imports
623        '''
624        submenu = wx.Menu()
625        item = parent.AppendMenu(wx.ID_ANY, 'Phase',
626            submenu, help='Import phase data')
627        for reader in self.ImportPhaseReaderlist:
628            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
629                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
630            self.ImportMenuId[item.GetId()] = reader
631            self.Bind(wx.EVT_MENU, self.OnImportPhase, id=item.GetId())
632        item = submenu.Append(wx.ID_ANY,help='Import phase data, use file to try to determine format',
633            kind=wx.ITEM_NORMAL,text='guess format from file')
634        self.Bind(wx.EVT_MENU, self.OnImportPhase, id=item.GetId())
635       
636    def OnImportPhase(self,event):
637        '''Called in response to an Import/Phase/... menu item
638        to read phase information.
639        dict self.ImportMenuId is used to look up the specific
640        reader item associated with the menu item, which will be
641        None for the last menu item, which is the "guess" option
642        where all appropriate formats will be tried.
643        '''
644        # look up which format was requested
645        reqrdr = self.ImportMenuId.get(event.GetId())
646       
647        # make a list of phase names, ranId's and the histograms used in those phases
648        phaseRIdList,usedHistograms = self.GetPhaseInfofromTree()
649        phaseNameList = usedHistograms.keys() # phase names in use
650        usedHKLFhists = [] # used single-crystal histograms
651        for p in usedHistograms:
652            for h in usedHistograms[p]:
653                if h.startswith('HKLF ') and h not in usedHKLFhists:
654                    usedHKLFhists.append(h)
655                   
656                   
657        rdlist = self.OnImportGeneric(reqrdr,self.ImportPhaseReaderlist,
658            'phase',usedRanIdList=phaseRIdList)
659        if len(rdlist) == 0: return
660        # for now rdlist is only expected to have one element
661        # but below will allow multiple phases to be imported
662        # if ever the import routines ever implement multiple phase reads.
663        self.CheckNotebook()
664        newPhaseList = []
665        for rd in rdlist:
666            PhaseName = ''
667            dlg = wx.TextEntryDialog(self, 'Enter the name for the new phase',
668                'Edit phase name', rd.Phase['General']['Name'],style=wx.OK)
669            while PhaseName == '':
670                dlg.CenterOnParent()
671                if dlg.ShowModal() == wx.ID_OK:
672                    PhaseName = dlg.GetValue().strip()
673                else:
674                    dlg.Destroy()
675                    return
676            dlg.Destroy()
677            # make new phase names unique
678            rd.Phase['General']['Name'] = G2obj.MakeUniqueLabel(PhaseName,phaseNameList)
679            PhaseName = rd.Phase['General']['Name'][:]
680            newPhaseList.append(PhaseName)
681            print(u'Read phase {} from file {}'.format(PhaseName,self.lastimport))
682            if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
683                sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
684            else:
685                sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
686            psub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
687            self.PatternTree.SetItemPyData(psub,rd.Phase)
688            self.PatternTree.Expand(self.root) # make sure phases are seen
689            self.PatternTree.Expand(sub) 
690            self.PatternTree.Expand(psub)
691            wx.CallAfter(G2gd.SelectDataTreeItem,self,psub) #bring up new phase General tab
692
693            if rd.Constraints:
694                sub = G2gd.GetPatternTreeItemId(self,self.root,'Constraints') # was created in CheckNotebook if needed
695                Constraints = self.PatternTree.GetItemPyData(sub)               
696                # TODO: make sure that NEWVAR names are unique here?
697                for i in rd.Constraints:
698                    if type(i) is dict:
699                        #for j in i: print j,' --> ',i[j]
700                        if '_Explain' not in Constraints: Constraints['_Explain'] = {}
701                        Constraints['_Explain'].update(i)
702                        continue
703                    Constraints['Phase'].append(i)
704        if not newPhaseList: return # somehow, no new phases
705        # get a list of existing histograms
706        PWDRlist = []
707        HKLFlist = []
708        if self.PatternTree.GetCount():
709            item, cookie = self.PatternTree.GetFirstChild(self.root)
710            while item:
711                name = self.PatternTree.GetItemText(item)
712                if name.startswith('PWDR ') and name not in PWDRlist:
713                    PWDRlist.append(name)
714                if name.startswith('HKLF ') and name not in HKLFlist:
715                    HKLFlist.append(name)
716                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
717        TextList = PWDRlist + HKLFlist
718        if not TextList:
719            return          #no histograms
720        header = 'Select histogram(s) to add to new phase(s):'
721        for phaseName in newPhaseList:
722            header += '\n  '+phaseName
723
724        notOK = True
725        while notOK:
726            result = G2G.ItemSelector(TextList,self,header,header='Add histogram(s)',multiple=True)
727            if not result: return
728            # check that selected single crystal histograms are not already in use!
729            used = [TextList[i] for i in result if TextList[i] in usedHKLFhists]
730            #for i in result:
731            #    if TextList[i] in usedHKLFhists: used.append(TextList[i])
732            if used:
733                msg = 'The following single crystal histogram(s) are already in use'
734                for i in used:
735                    msg += '\n  '+str(i)
736                msg += '\nAre you sure you want to add them to this phase? '
737                msg += 'Associating a single crystal dataset to >1 histogram is usually an error, '
738                msg += 'so No is suggested here.'
739                if self.ErrorDialog('Likely error',msg,self,wtype=wx.YES_NO) == wx.ID_YES: notOK = False
740            else:
741                notOK = False
742        # connect new phases to histograms
743        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
744        if not sub:
745            raise Exception('ERROR -- why are there no phases here?')
746        wx.BeginBusyCursor()
747        item, cookie = self.PatternTree.GetFirstChild(sub)
748        while item: # loop over (new) phases
749            phaseName = self.PatternTree.GetItemText(item)
750            data = self.PatternTree.GetItemPyData(item)
751            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
752            if phaseName not in newPhaseList: continue
753            generalData = data['General']
754            SGData = generalData['SGData']
755            Super = generalData.get('Super',0)
756            SuperVec = []
757            if Super:
758                SuperVec = np.array(generalData['SuperVec'][0])
759            UseList = data['Histograms']
760            NShkl = len(G2spc.MustrainNames(SGData))
761            NDij = len(G2spc.HStrainNames(SGData))
762            for i in result:
763                histoName = TextList[i]
764                if histoName in HKLFlist:
765                    #redo UpdateHKLFdata(histoName) here:
766                    Id = G2gd.GetPatternTreeItemId(self,self.root,histoName)
767                    refDict,reflData = self.PatternTree.GetItemPyData(Id)
768                    G,g = G2lat.cell2Gmat(generalData['Cell'][1:7])
769                    Super = reflData.get('Super',0)
770                    for iref,ref in enumerate(reflData['RefList']):
771                        hkl = ref[:3]
772                        if Super:
773                            H = list(hkl+SuperVec*ref[3])
774                        else:
775                            H = hkl
776                        ref[4+Super] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
777                        iabsnt = G2spc.GenHKLf(H,SGData)[0]
778                        if iabsnt:  #flag space gp. absences
779                            if Super: 
780                                if not ref[2+Super]:
781                                    ref[3+Super] = 0
782                                else:
783                                    ref[3+Super] = 1    #twin id
784                            else:
785                                ref[3] = 0
786                    UseList[histoName] = SetDefaultDData(reflData['Type'],histoName)
787                elif histoName in PWDRlist:
788                    Id = G2gd.GetPatternTreeItemId(self,self.root,histoName)
789                    refList = self.PatternTree.GetItemPyData(
790                        G2gd.GetPatternTreeItemId(self,Id,'Reflection Lists'))
791                    refList[generalData['Name']] = {}
792                    UseList[histoName] = SetDefaultDData('PWDR',histoName,NShkl=NShkl,NDij=NDij)
793                else:
794                    raise Exception('Unexpected histogram '+histoName)
795        wx.EndBusyCursor()
796        self.EnableRefineCommand()
797       
798        return # success
799       
800    def _Add_ImportMenu_Image(self,parent):
801        '''configure the Import Image menus accord to the readers found in _init_Imports
802        '''
803        submenu = wx.Menu()
804        item = parent.AppendMenu(wx.ID_ANY, 'Image',
805            submenu, help='Import image file')
806        for reader in self.ImportImageReaderlist:
807            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
808                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
809            self.ImportMenuId[item.GetId()] = reader
810            self.Bind(wx.EVT_MENU, self.OnImportImage, id=item.GetId())
811        item = submenu.Append(wx.ID_ANY,help='Import image data, use file to try to determine format',
812            kind=wx.ITEM_NORMAL,text='guess format from file')
813        self.Bind(wx.EVT_MENU, self.OnImportImage, id=item.GetId())
814       
815    def OnImportImage(self,event):
816        '''Called in response to an Import/Image/... menu item
817        to read an image from a file. Like all the other imports,
818        dict self.ImportMenuId is used to look up the specific
819        reader item associated with the menu item, which will be
820        None for the last menu item, which is the "guess" option
821        where all appropriate formats will be tried.
822
823        A reader object is filled each time an image is read.
824        '''
825        self.CheckNotebook()
826        # look up which format was requested
827        reqrdr = self.ImportMenuId.get(event.GetId())
828        rdlist = self.OnImportGeneric(reqrdr,self.ImportImageReaderlist,
829            'image',multiple=True,Preview=False,load2Tree=True)
830        if rdlist: 
831            self.PatternTree.SelectItem(G2gd.GetPatternTreeItemId(self,self.Image,'Image Controls'))             #show last image to have beeen read
832                   
833    def _Add_ImportMenu_Sfact(self,parent):
834        '''configure the Import Structure Factor menus accord to the readers found in _init_Imports
835        '''
836        submenu = wx.Menu()
837        item = parent.AppendMenu(wx.ID_ANY, 'Structure Factor',
838            submenu, help='Import Structure Factor data')
839        for reader in self.ImportSfactReaderlist:
840            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,               
841                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
842            self.ImportMenuId[item.GetId()] = reader
843            self.Bind(wx.EVT_MENU, self.OnImportSfact, id=item.GetId())
844        item = submenu.Append(wx.ID_ANY,
845            help='Import Structure Factor, use file to try to determine format',
846            kind=wx.ITEM_NORMAL,
847            text='guess format from file')
848        self.Bind(wx.EVT_MENU, self.OnImportSfact, id=item.GetId())
849
850    def OnImportSfact(self,event):
851        '''Called in response to an Import/Structure Factor/... menu item
852        to read single crystal datasets.
853        dict self.ImportMenuId is used to look up the specific
854        reader item associated with the menu item, which will be
855        None for the last menu item, which is the "guess" option
856        where all appropriate formats will be tried.
857        '''
858        # get a list of existing histograms
859        HKLFlist = []
860        if self.PatternTree.GetCount():
861            item, cookie = self.PatternTree.GetFirstChild(self.root)
862            while item:
863                name = self.PatternTree.GetItemText(item)
864                if name.startswith('HKLF ') and name not in HKLFlist:
865                    HKLFlist.append(name)
866                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
867        # look up which format was requested
868        reqrdr = self.ImportMenuId.get(event.GetId())
869        rdlist = self.OnImportGeneric(reqrdr,self.ImportSfactReaderlist,
870            'Structure Factor',multiple=True)
871        if len(rdlist) == 0: return
872        self.CheckNotebook()
873        newHistList = []
874        for rd in rdlist:
875            HistName = rd.objname
876            if len(rdlist) <= 2: 
877                dlg = wx.TextEntryDialog( # allow editing of Structure Factor name
878                    self, 'Enter the name for the new Structure Factor',
879                    'Edit Structure Factor name', HistName,
880                    style=wx.OK)
881                dlg.CenterOnParent()
882                if dlg.ShowModal() == wx.ID_OK:
883                    HistName = dlg.GetValue()
884                dlg.Destroy()
885            HistName = 'HKLF '+G2obj.StripUnicode(HistName,'_')
886            # make new histogram names unique
887            if len(rd.Banks):
888                for Bank in rd.Banks:
889                    valuesdict = {'wtFactor':1.0,'Dummy':False,'ranId':ran.randint(0,sys.maxint),}
890                    HistName = G2obj.MakeUniqueLabel(HistName,HKLFlist)
891                    print 'Read structure factor table '+HistName+' from file '+self.lastimport
892                    Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
893                    if not Bank['RefDict'].get('FF'):
894                        Bank['RefDict']['FF'] = {}
895                    self.PatternTree.SetItemPyData(Id,[valuesdict,Bank['RefDict']])
896                    Sub = self.PatternTree.AppendItem(Id,text='Instrument Parameters')
897                    self.PatternTree.SetItemPyData(Sub,copy.copy(rd.Parameters))
898                    self.PatternTree.SetItemPyData(
899                        self.PatternTree.AppendItem(Id,text='Reflection List'),{})  #dummy entry for GUI use
900                    newHistList.append(HistName)
901            else:
902                valuesdict = {'wtFactor':1.0,'Dummy':False,'ranId':ran.randint(0,sys.maxint),}
903                HistName = G2obj.MakeUniqueLabel(HistName,HKLFlist)
904                print 'Read structure factor table '+HistName+' from file '+self.lastimport
905                if not rd.RefDict.get('FF'):
906                    rd.RefDict['FF'] = {}
907                Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
908                self.PatternTree.SetItemPyData(Id,[valuesdict,rd.RefDict])
909                Sub = self.PatternTree.AppendItem(Id,text='Instrument Parameters')
910                self.PatternTree.SetItemPyData(Sub,rd.Parameters)
911                self.PatternTree.SetItemPyData(
912                    self.PatternTree.AppendItem(Id,text='Reflection List'),{})  #dummy entry for GUI use
913                newHistList.append(HistName)
914               
915            self.PatternTree.SelectItem(Id)
916            self.PatternTree.Expand(Id)
917            self.Sngl = True
918
919        if not newHistList: return # somehow, no new histograms
920        # make a list of phase names
921        phaseRIdList,usedHistograms = self.GetPhaseInfofromTree()
922        phaseNameList = usedHistograms.keys() # phase names in use
923        if not phaseNameList: return # no phases yet, nothing to do
924        header = 'Select phase(s) to add the new\nsingle crystal dataset(s) to:'
925        for Name in newHistList:
926            header += '\n  '+str(Name)
927        result = G2G.ItemSelector(phaseNameList,self,header,header='Add to phase(s)',multiple=True)
928        if not result: return
929        # connect new phases to histograms
930        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
931        if not sub:
932            raise Exception('ERROR -- why are there no phases here?')
933        wx.BeginBusyCursor()
934        item, cookie = self.PatternTree.GetFirstChild(sub)
935        iph = -1
936        while item: # loop over (new) phases
937            iph += 1
938            data = self.PatternTree.GetItemPyData(item)
939            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
940            if iph not in result: continue
941            generalData = data['General']
942            SGData = generalData['SGData']
943            Super = generalData.get('Super',0)
944            SuperVec = []
945            if Super:
946                SuperVec = np.array(generalData['SuperVec'][0])
947            UseList = data['Histograms']
948            for histoName in newHistList:
949                #redo UpdateHKLFdata(histoName) here:
950                Id = G2gd.GetPatternTreeItemId(self,self.root,histoName)
951                refDict,reflData = self.PatternTree.GetItemPyData(Id)
952                UseList[histoName] = SetDefaultDData(reflData['Type'],histoName)
953                G,g = G2lat.cell2Gmat(generalData['Cell'][1:7])
954                if 'TwMax' in reflData:     #nonmerohedral twins present
955                    UseList[histoName]['Twins'] = []
956                    for iT in range(reflData['TwMax'][0]+1):
957                        if iT in reflData['TwMax'][1]:
958                            UseList[histoName]['Twins'].append([False,0.0])
959                        else:
960                            UseList[histoName]['Twins'].append([np.array([[1,0,0],[0,1,0],[0,0,1]]),[1.0,False,reflData['TwMax'][0]]])
961                else:   #no nonmerohedral twins
962                    UseList[histoName]['Twins'] = [[np.array([[1,0,0],[0,1,0],[0,0,1]]),[1.0,False,0]],]
963                for iref,ref in enumerate(reflData['RefList']):
964                    hkl = ref[:3]
965                    if Super:
966                        H = list(hkl+SuperVec*ref[3])
967                    else:
968                        H = hkl
969                    ref[4+Super] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
970                    iabsnt,mul,Uniq,phi = G2spc.GenHKLf(H,SGData)
971                    if iabsnt:  #flag space gp. absences
972                        if Super: 
973                            if not ref[2+Super]:
974                                ref[3+Super] = 0
975                            else:
976                                ref[3+Super] = 1    #twin id?
977                        else:
978                            ref[3] = 0
979        wx.EndBusyCursor()
980        self.EnableRefineCommand()       
981        return # success
982
983    def _Add_ImportMenu_powder(self,parent):
984        '''configure the Powder Data menus accord to the readers found in _init_Imports
985        '''
986        submenu = wx.Menu()
987        item = parent.AppendMenu(wx.ID_ANY, 'Powder Data',
988            submenu, help='Import Powder data')
989        for reader in self.ImportPowderReaderlist:
990            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
991                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
992            self.ImportMenuId[item.GetId()] = reader
993            self.Bind(wx.EVT_MENU, self.OnImportPowder, id=item.GetId())
994        item = submenu.Append(wx.ID_ANY,
995            help='Import powder data, use file to try to determine format',
996            kind=wx.ITEM_NORMAL,text='guess format from file')
997        self.Bind(wx.EVT_MENU, self.OnImportPowder, id=item.GetId())
998        submenu.AppendSeparator()
999        item = submenu.Append(wx.ID_ANY,
1000            help='Create a powder data set entry that will be simulated',
1001            kind=wx.ITEM_NORMAL,text='Simulate a dataset')
1002        self.Bind(wx.EVT_MENU, self.OnDummyPowder, id=item.GetId())
1003       
1004    def OpenPowderInstprm(self,instfile):
1005        '''Read a GSAS-II (new) instrument parameter file
1006
1007        :param str instfile: name of instrument parameter file
1008
1009        '''
1010        File = open(instfile,'r')
1011        lines = File.readlines()
1012        File.close()
1013        return lines       
1014           
1015    def ReadPowderInstprm(self,instLines,bank,databanks,rd):
1016        '''Read lines from a GSAS-II (new) instrument parameter file
1017        similar to G2pwdGUI.OnLoad
1018        If instprm file has multiple banks each with header #Bank n: ..., this
1019        finds matching bank no. to load - problem with nonmatches?
1020
1021        :param list instLines: strings from GSAS-II parameter file; can be concatenated with ';'
1022        :param int  bank: bank number to check when instprm file has '#BANK n:...' strings
1023            when bank = n then use parameters; otherwise skip that set. Ignored if BANK n:
1024            not present. NB: this kind of instprm file made by a Save all profile command in Instrument Parameters
1025        :return dict: Inst  instrument parameter dict if OK, or
1026                str: Error message if failed   
1027        '''
1028        if 'GSAS-II' not in instLines[0]: # not a valid file
1029            return 'Not a valid GSAS-II instprm file'
1030        newItems = []
1031        newVals = []
1032        Found = False
1033        il = 0
1034        if bank is None: # no bank was specified in the input file, is more than one present in file?
1035            banklist = set([])
1036            for S in instLines:
1037                if S[0] == '#' and 'Bank' in S:
1038                    banklist.add(int(S.split(':')[0].split()[1]))
1039            if len(banklist) > 1: # yes, the user must make a selection
1040                choices = [str(i) for i in banklist]
1041                bank = int(G2G.ItemSelector(choices,self.G2frame,multiple=False))
1042            else:
1043                bank = 1
1044            rd.powderentry[2] = bank
1045        while il < len(instLines):
1046            S = instLines[il]
1047            if S[0] == '#':
1048                if Found:
1049                    break
1050                if 'Bank' in S:
1051                    if bank == int(S.split(':')[0].split()[1]):
1052                        il += 1
1053                        S = instLines[il]
1054                    else:
1055                        il += 1
1056                        S = instLines[il]
1057                        while il < len(instLines) and '#Bank' not in S:
1058                            il += 1
1059                            if il == len(instLines):
1060                                return 'Bank %d not found in instprm file'%(bank)
1061                            S = instLines[il]
1062                        continue
1063                else:   #a non #Bank file
1064                    il += 1
1065                    S = instLines[il]
1066            Found = True
1067            if '"""' in S:
1068                delim = '"""' 
1069            elif "'''" in S:
1070                delim = "'''"
1071            else:
1072                S = S.replace(' ','')
1073                SS = S.strip().split(';')
1074                for s in SS:
1075                    [item,val] = s.split(':',1)
1076                    newItems.append(item)
1077                    try:
1078                        newVals.append(float(val))
1079                    except ValueError:
1080                        newVals.append(val)
1081                il += 1
1082                continue
1083            # read multiline values, delimited by ''' or """
1084            item,val = S.strip().split(':',1)
1085            val = val.replace(delim,'').rstrip()
1086            val += '\n'
1087            while True:
1088                il += 1
1089                if il >= len(instLines): break
1090                S = instLines[il]
1091                if delim in S:
1092                    val += S.replace(delim,'').rstrip()
1093                    val += '\n'
1094                    break
1095                else:
1096                    val += S.rstrip()
1097                    val += '\n'
1098            newItems.append(item)
1099            newVals.append(val)
1100            il += 1
1101        return [G2IO.makeInstDict(newItems,newVals,len(newVals)*[False,]),{}]
1102       
1103    def ReadPowderIparm(self,instfile,bank,databanks,rd):
1104        '''Read a GSAS (old) instrument parameter file
1105
1106        :param str instfile: name of instrument parameter file
1107        :param int bank: the bank number read in the raw data file
1108        :param int databanks: the number of banks in the raw data file.
1109          If the number of banks in the data and instrument parameter files
1110          agree, then the sets of banks are assumed to match up and bank
1111          is used to select the instrument parameter file. If not and not TOF,
1112          the user is asked to make a selection.
1113        :param obj rd: the raw data (histogram) data object. This
1114          sets rd.instbank.
1115
1116        '''
1117        if not os.path.exists(instfile): # no such file
1118            return {}
1119        fp = 0
1120        try:
1121            fp = open(instfile,'Ur')
1122            Iparm = {}
1123            for S in fp:
1124                if '#' in S[0]:
1125                    continue
1126                Iparm[S[:12]] = S[12:-1]
1127        except IOError:
1128            print(u'Error reading file: {}'.format(instfile))
1129        if fp:       
1130            fp.close()
1131
1132        ibanks = int(Iparm.get('INS   BANK  ','1').strip())
1133        if ibanks == 1: # there is only one bank here, return it
1134            rd.instbank = 1
1135            rd.powderentry[2] = 1
1136            return Iparm
1137        if 'PNT' in Iparm['INS   HTYPE ']:      #allow mismatch between banks in data  iparm file for TOF
1138            rd.instbank = bank
1139        elif ibanks != databanks or bank is None:
1140            choices = []
1141            for i in range(1,1+ibanks):
1142                choices.append('Bank '+str(i))
1143            bank = 1 + G2IO.BlockSelector(
1144                choices, self,
1145                title='Select an instrument parameter bank for '+
1146                os.path.split(rd.powderentry[0])[1]+' BANK '+str(bank)+
1147                '\nOr use Cancel to select from the default parameter sets',
1148                header='Block Selector')
1149        if bank is None: return {}
1150        # pull out requested bank # bank from the data, and change the bank to 1
1151        IparmS = {}
1152        for key in Iparm:
1153            if 'INS' in key[:3]:    #skip around rubbish lines in some old iparm files
1154                if key[4:6] == "  ":
1155                    IparmS[key] = Iparm[key]
1156                elif int(key[4:6].strip()) == bank:
1157                    IparmS[key[:4]+' 1'+key[6:]] = Iparm[key]
1158        rd.instbank = bank
1159        return IparmS
1160                       
1161    def GetPowderIparm(self,rd, prevIparm, lastIparmfile, lastdatafile):
1162        '''Open and read an instrument parameter file for a data file
1163        Returns the list of parameters used in the data tree
1164
1165        :param obj rd: the raw data (histogram) data object.
1166
1167        :param str prevIparm: not used
1168
1169        :param str lastIparmfile: Name of last instrument parameter
1170          file that was read, or a empty string.
1171
1172        :param str lastdatafile: Name of last data file that was read.
1173
1174        :returns: a list of two dicts, the first containing instrument parameters
1175          and the second used for TOF lookup tables for profile coeff.
1176
1177        '''
1178        def SetPowderInstParms(Iparm, rd):
1179            '''extracts values from instrument parameters in rd.instdict
1180            or in array Iparm.
1181            Create and return the contents of the instrument parameter tree entry.
1182            '''
1183            Irads = {0:' ',1:'CrKa',2:'FeKa',3:'CuKa',4:'MoKa',5:'AgKa',6:'TiKa',7:'CoKa'}
1184            DataType = Iparm['INS   HTYPE '].strip()[:3]  # take 1st 3 chars
1185            # override inst values with values read from data file
1186            Bank = rd.powderentry[2]    #should be used in multibank iparm files
1187            if rd.instdict.get('type'):
1188                DataType = rd.instdict.get('type')
1189            data = [DataType,]
1190            instname = Iparm.get('INS  1INAME ')
1191            irad = int(Iparm.get('INS  1 IRAD ','0'))
1192            if instname:
1193                rd.Sample['InstrName'] = instname.strip()
1194            if 'C' in DataType:
1195                wave1 = None
1196                wave2 = 0.0
1197                if rd.instdict.get('wave'):
1198                    wl = rd.instdict.get('wave')
1199                    wave1 = wl[0]
1200                    if len(wl) > 1: wave2 = wl[1]
1201                s = Iparm['INS  1 ICONS']
1202                if not wave1:
1203                    wave1 = G2IO.sfloat(s[:10])
1204                    wave2 = G2IO.sfloat(s[10:20])
1205                v = (wave1,wave2,
1206                     G2IO.sfloat(s[20:30])/100.,G2IO.sfloat(s[55:65]),G2IO.sfloat(s[40:50])) #get lam1, lam2, zero, pola & ratio
1207                if not v[1]:
1208                    names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
1209                    v = (v[0],v[2],v[4])
1210                    codes = [0,0,0,0]
1211                    rd.Sample.update({'Type':'Debye-Scherrer','Absorption':[0.,False],'DisplaceX':[0.,False],'DisplaceY':[0.,False]})
1212                else:
1213                    names = ['Type','Lam1','Lam2','Zero','I(L2)/I(L1)','Polariz.','U','V','W','X','Y','SH/L','Azimuth']
1214                    codes = [0,0,0,0,0,0]
1215                    rd.Sample.update({'Type':'Bragg-Brentano','Shift':[0.,False],'Transparency':[0.,False],
1216                        'SurfRoughA':[0.,False],'SurfRoughB':[0.,False]})
1217                data.extend(v)
1218                if 'INS  1PRCF  ' in Iparm:
1219                    v1 = Iparm['INS  1PRCF  '].split()                                                 
1220                    v = Iparm['INS  1PRCF 1'].split()
1221                    data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
1222                    azm = float(Iparm.get('INS  1DETAZM','0.0'))
1223                    v = Iparm['INS  1PRCF 2'].split()
1224                    if v1[0] == 3:
1225                        data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3],azm)])  #get LX, LY, S+H/L & azimuth
1226                    else:
1227                        data.extend([0.0,0.0,0.002,azm])                                      #OK defaults if fxn #3 not 1st in iprm file                   
1228                else:
1229                    v1 = Iparm['INS  1PRCF1 '].split()                                                 
1230                    v = Iparm['INS  1PRCF11'].split()
1231                    data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
1232                    azm = float(Iparm.get('INS  1DETAZM','0.0'))
1233                    v = Iparm['INS  1PRCF12'].split()
1234                    if v1[0] == 3:
1235                        data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3],azm)])  #get LX, LY, S+H/L & azimuth
1236                    else:
1237                        data.extend([0.0,0.0,0.002,azm])                                      #OK defaults if fxn #3 not 1st in iprm file
1238                codes.extend([0,0,0,0,0,0,0])
1239                Iparm1 = G2IO.makeInstDict(names,data,codes)
1240                Iparm1['Source'] = [Irads[irad],Irads[irad]]
1241                Iparm1['Bank'] = [Bank,Bank,0]
1242                return [Iparm1,{}]
1243            elif 'T' in DataType:
1244                names = ['Type','fltPath','2-theta','difC','difA', 'difB','Zero','alpha','beta-0','beta-1',
1245                    'beta-q','sig-0','sig-1','sig-2','sig-q', 'X','Y','Azimuth',]
1246                codes = [0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,]
1247                azm = 0.
1248                if 'INS  1DETAZM' in Iparm:
1249                    azm = float(Iparm['INS  1DETAZM'])
1250                rd.Sample['Azimuth'] = azm
1251                fltPath0 = 20.                      #arbitrary
1252                if 'INS   FPATH1' in Iparm:                   
1253                    s = Iparm['INS   FPATH1'].split()
1254                    fltPath0 = G2IO.sfloat(s[0])
1255                if 'INS  1BNKPAR' not in Iparm:     #bank missing from Iparm file
1256                    return []
1257                s = Iparm['INS  1BNKPAR'].split()
1258                fltPath1 = G2IO.sfloat(s[0])
1259                data.extend([fltPath0+fltPath1,])               #Flight path source-sample-detector
1260                data.extend([G2IO.sfloat(s[1]),])               #2-theta for bank
1261                s = Iparm['INS  1 ICONS'].split()
1262                data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),0.0,G2IO.sfloat(s[2])])    #difC,difA,difB,Zero
1263                if 'INS  1PRCF  ' in Iparm:
1264                    s = Iparm['INS  1PRCF  '].split()
1265                    pfType = int(s[0])
1266                    s = Iparm['INS  1PRCF 1'].split()
1267                    if abs(pfType) == 1:
1268                        data.extend([G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),G2IO.sfloat(s[3])]) #alpha, beta-0, beta-1
1269                        s = Iparm['INS  1PRCF 2'].split()
1270                        data.extend([0.0,0.0,G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
1271                    elif abs(pfType) in [3,4,5]:
1272                        data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),G2IO.sfloat(s[2])]) #alpha, beta-0, beta-1
1273                        if abs(pfType) == 4:
1274                            data.extend([0.0,0.0,G2IO.sfloat(s[3]),0.0,0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
1275                        else:
1276                            s = Iparm['INS  1PRCF 2'].split()
1277                            data.extend([0.0,0.0,G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y                       
1278                    elif abs(pfType) == 2:
1279                        data.extend([G2IO.sfloat(s[1]),0.0,1./G2IO.sfloat(s[3])]) #alpha, beta-0, beta-1
1280                        data.extend([0.0,0.0,G2IO.sfloat(s[1]),0.0,0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y                           
1281                else:
1282                    s = Iparm['INS  1PRCF1 '].split()
1283                    pfType = int(s[0])
1284                    s = Iparm['INS  1PRCF11'].split()
1285                    if abs(pfType) == 1:
1286                        data.extend([G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),G2IO.sfloat(s[3])]) #alpha, beta-0, beta-1
1287                        s = Iparm['INS  1PRCF12'].split()
1288                        data.extend([0.0,0.0,G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
1289                    elif abs(pfType) in [3,4,5]:
1290                        data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),G2IO.sfloat(s[2])]) #alpha, beta-0, beta-1
1291                        if abs(pfType) == 4:
1292                            data.extend([0.0,0.0,G2IO.sfloat(s[3]),0.0,0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y
1293                        else:
1294                            s = Iparm['INS  1PRCF12'].split()
1295                            data.extend([0.0,0.0,G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),0.0,0.0,0.0,azm])    #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y                       
1296                Inst1 = G2IO.makeInstDict(names,data,codes)
1297                Inst1['Bank'] = [Bank,Bank,0]
1298                Inst2 = {}
1299                if pfType < 0:
1300                    Ipab = 'INS  1PAB'+str(-pfType)
1301                    Npab = int(Iparm[Ipab+'  '].strip())
1302                    Inst2['Pdabc'] = []
1303                    for i in range(Npab):
1304                        k = Ipab+str(i+1).rjust(2)
1305                        s = Iparm[k].split()
1306                        Inst2['Pdabc'].append([float(t) for t in s])
1307                    Inst2['Pdabc'] = np.array(Inst2['Pdabc'])
1308                    Inst2['Pdabc'].T[3] += Inst2['Pdabc'].T[0]*Inst1['difC'][0] #turn 3rd col into TOF
1309                if 'INS  1I ITYP' in Iparm:
1310                    s = Iparm['INS  1I ITYP'].split()
1311                    Ityp = int(s[0])
1312                    Tminmax = [float(s[1])*1000.,float(s[2])*1000.]
1313                    Itypes = ['Exponential','Maxwell/Exponential','','Maxwell/Chebyschev','']
1314                    if Ityp in [1,2,4]:
1315                        Inst2['Itype'] = Itypes[Ityp-1]
1316                        Inst2['Tminmax'] = Tminmax
1317                        Icoeff = []
1318                        Iesd = []
1319                        Icovar = []                   
1320                        for i in range(3):
1321                            s = Iparm['INS  1ICOFF'+str(i+1)].split()
1322                            Icoeff += [float(S) for S in s]
1323                            s = Iparm['INS  1IECOF'+str(i+1)].split()
1324                            Iesd += [float(S) for S in s]
1325                        NT = 10
1326                        for i in range(8):
1327                            s = Iparm['INS  1IECOR'+str(i+1)]
1328                            if i == 7:
1329                                NT = 8
1330                            Icovar += [float(s[6*j:6*j+6]) for j in range(NT)]
1331                        Inst2['Icoeff'] = Icoeff
1332                        Inst2['Iesd'] = Iesd
1333                        Inst2['Icovar'] = Icovar
1334                return [Inst1,Inst2]
1335               
1336        def GetDefaultParms(self,rd):
1337            '''Solicits from user a default set of parameters & returns Inst parm dict
1338            param: self: refers to the GSASII main class
1339            param: rd: importer data structure
1340            returns: dict: Instrument parameter dictionary
1341            '''       
1342            sind = lambda x: math.sin(x*math.pi/180.)
1343            tand = lambda x: math.tan(x*math.pi/180.)
1344            import defaultIparms as dI
1345            while True: # loop until we get a choice
1346                choices = []
1347                head = 'Select from default instrument parameters for '+rd.idstring
1348   
1349                for l in dI.defaultIparm_lbl:
1350                    choices.append('Defaults for '+l)
1351                res = G2IO.BlockSelector(choices,ParentFrame=self,title=head,
1352                    header='Select default inst parms',useCancel=True)
1353                if res is None: return None
1354                rd.instfile = ''
1355                if 'lab data' in choices[res]:
1356                    rd.Sample.update({'Type':'Bragg-Brentano','Shift':[0.,False],'Transparency':[0.,False],
1357                        'SurfRoughA':[0.,False],'SurfRoughB':[0.,False]})
1358                else:
1359                    rd.Sample.update({'Type':'Debye-Scherrer','Absorption':[0.,False],'DisplaceX':[0.,False],
1360                        'DisplaceY':[0.,False]})
1361                if 'Generic' in choices[res]:
1362                    dlg = G2G.MultiFloatDialog(self,title='Generic TOF detector bank',
1363                        prompts=['Total FP','2-theta',],values=[25.0,150.,],
1364                            limits=[[6.,200.],[5.,175.],],formats=['%6.2f','%6.1f',])
1365                    if dlg.ShowModal() == wx.ID_OK: #strictly empirical approx.
1366                        FP,tth = dlg.GetValues()
1367                        difC = 505.632*FP*sind(tth/2.)
1368                        sig1 = 50.+2.5e-6*(difC/tand(tth/2.))**2
1369                        bet1 = .00226+7.76e+11/difC**4
1370                        rd.instmsg = 'default: '+dI.defaultIparm_lbl[res]
1371                        Inst = self.ReadPowderInstprm(dI.defaultIparms[res],bank,numbanks,rd)
1372                        Inst[0]['difC'] = [difC,difC,0]
1373                        Inst[0]['sig-1'] = [sig1,sig1,0]
1374                        Inst[0]['beta-1'] = [bet1,bet1,0]
1375                        return Inst    #this is [Inst1,Inst2] a pair of dicts
1376                    dlg.Destroy()
1377                else:
1378                    rd.instmsg = 'default: '+dI.defaultIparm_lbl[res]
1379                    return self.ReadPowderInstprm(dI.defaultIparms[res],bank,numbanks,rd)    #this is [Inst1,Inst2] a pair of dicts
1380
1381        # stuff we might need from the reader
1382        filename = rd.powderentry[0]
1383        bank = rd.powderentry[2]
1384        numbanks = rd.numbanks
1385        #1st priority: is there an instrument parameter file matching the current file
1386        # with extension .instprm, .prm, .inst, or .ins? If so read it
1387        basename = os.path.splitext(filename)[0]
1388        for ext in '.prm','.inst','.ins','.instprm':
1389            if self.zipfile:
1390                instfile = G2IO.ExtractFileFromZip(self.zipfile,
1391                    selection=os.path.split(basename + ext)[1],parent=self)
1392                if instfile == None:
1393                    continue
1394            else:
1395                instfile = basename + ext
1396            if not os.path.exists(instfile):
1397                continue
1398            if 'instprm' in instfile:
1399                Lines = self.OpenPowderInstprm(instfile)
1400                instParmList = self.ReadPowderInstprm(Lines,bank,numbanks,rd)    #this is [Inst1,Inst2] a pair of dicts
1401                if 'list' in str(type(instParmList)):
1402                    rd.instfile = instfile
1403                    rd.instmsg = 'GSAS-II file '+instfile
1404                    return instParmList
1405                else:
1406                    #print 'debug: open/read failed',instfile
1407                    pass # fail silently
1408            else:
1409                Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
1410                if Iparm:
1411                    #print 'debug: success'
1412                    rd.instfile = instfile
1413                    rd.instmsg = instfile + ' bank ' + str(rd.instbank)
1414                    return SetPowderInstParms(Iparm,rd)
1415                else:
1416                    #print 'debug: open/read failed',instfile
1417                    pass # fail silently
1418
1419        #2nd priority: is there an instrument parameter file defined for the current data set?
1420        # or if this is a read on a set of set of files, use the last one again
1421        #if rd.instparm as found in data file header or (lastdatafile == filename and lastIparmfile):
1422        if rd.instparm or lastIparmfile:
1423            if rd.instparm:
1424                instfile = os.path.join(os.path.split(filename)[0],rd.instparm)
1425            else:
1426                # for multiple reads of one data file, reuse the inst parm file
1427                instfile = lastIparmfile
1428#            if self.zipfile:
1429#                instfile = G2IO.ExtractFileFromZip(self.zipfile,
1430#                    selection=os.path.split(instfile)[1],parent=self)
1431            if instfile != None and os.path.exists(instfile):
1432                #print 'debug: try read',instfile
1433                if 'instprm' in instfile:   #GSAS-II file must have .instprm as extension
1434                    Lines = self.OpenPowderInstprm(instfile)
1435                    if Lines is not None:
1436                        instParmList = self.ReadPowderInstprm(Lines,bank,numbanks,rd)   #this is [Inst1,Inst2] a pair of dicts
1437                else:   #old GSAS style iparm file - could be named anything!
1438                    Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
1439                    if Iparm:
1440                        #print 'debug: success'
1441                        rd.instfile = instfile
1442                        rd.instmsg = instfile + ' bank ' + str(rd.instbank)
1443                        instParmList = SetPowderInstParms(Iparm,rd)     #this is [Inst1,Inst2] a pair of dicts
1444                if 'list' in str(type(instParmList)):   #record stuff & return stuff
1445                    rd.instfile = instfile
1446                    rd.instmsg = 'GSAS-II file '+instfile
1447                    return instParmList
1448                else:   #bad iparms - try default
1449                    rd.instmsg = instParmList   #an error message
1450                    return GetDefaultParms(self,rd)
1451            else:
1452                self.ErrorDialog('Open Error',u'Error opening instrument parameter file '   \
1453                    +'{} requested by file '.format(instfile,filename))
1454        #Finally - ask user for Instrument parametrs file - seems it can't be in a zip file
1455        while True: # loop until we get a file that works or we get a cancel
1456            instfile = ''
1457            pth = G2G.GetImportPath(self)
1458            if not pth: pth = '.'
1459            dlg = wx.FileDialog(self,
1460                'Choose inst. param file for "'+rd.idstring+'" (or Cancel for default)',
1461                pth, '',
1462                'GSAS iparm file (*.prm,*.inst,*.ins)|*.prm;*.inst;*.ins|'
1463                'GSAS-II iparm file (*.instprm)|*.instprm|'
1464                'All files (*.*)|*.*', wx.OPEN)
1465            if os.path.exists(lastIparmfile):
1466                dlg.SetFilename(lastIparmfile)
1467            if dlg.ShowModal() == wx.ID_OK:
1468                instfile = dlg.GetPath()
1469            dlg.Destroy()
1470            if not instfile: 
1471                return GetDefaultParms(self,rd) #on Cancel/break
1472            if 'instprm' in instfile:
1473                Lines = self.OpenPowderInstprm(instfile)
1474                if Lines is not None:
1475                    instParmList = self.ReadPowderInstprm(Lines,bank,numbanks,rd)    #this is [Inst1,Inst2] a pair of dicts
1476                if 'list' in str(type(instParmList)):
1477                    rd.instfile = instfile
1478                    rd.instmsg = 'GSAS-II file '+instfile
1479                    return instParmList
1480                else:
1481                    rd.instmsg = instParmList   #an error message
1482                    return GetDefaultParms(self,rd)
1483            else:
1484                Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
1485                if Iparm:
1486                    #print 'debug: success with',instfile
1487                    rd.instfile = instfile
1488                    rd.instmsg = instfile + ' bank ' + str(rd.instbank)
1489                    return SetPowderInstParms(Iparm,rd)
1490                else:
1491                    self.ErrorDialog('Read Error',
1492                                     u'Error opening/reading file {}'.format(instfile))
1493    def EnableRefineCommand(self):
1494        haveData = False
1495        # check for phases connected to histograms
1496        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1497        if not sub: return
1498        item, cookie = self.PatternTree.GetFirstChild(sub)
1499        while item: # loop over phases
1500            data = self.PatternTree.GetItemPyData(item)
1501            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1502            UseList = data['Histograms']
1503            if UseList: haveData = True
1504        if haveData:
1505            self.dataWindow.DataMenu.Enable(G2gd.wxID_DATADELETE,True)
1506            for item in self.Refine: item.Enable(True)
1507        else:
1508            self.dataWindow.DataMenu.Enable(G2gd.wxID_DATADELETE,False)
1509            for item in self.Refine: item.Enable(False)
1510
1511       
1512    def OnImportPowder(self,event):
1513        '''Called in response to an Import/Powder Data/... menu item
1514        to read a powder diffraction data set.
1515        dict self.ImportMenuId is used to look up the specific
1516        reader item associated with the menu item, which will be
1517        None for the last menu item, which is the "guess" option
1518        where all appropriate formats will be tried.
1519
1520        Also reads an instrument parameter file for each dataset.
1521        '''
1522        # get a list of existing histograms
1523        PWDRlist = []
1524        if self.PatternTree.GetCount():
1525            item, cookie = self.PatternTree.GetFirstChild(self.root)
1526            while item:
1527                name = self.PatternTree.GetItemText(item)
1528                if name.startswith('PWDR ') and name not in PWDRlist:
1529                    PWDRlist.append(name)
1530                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1531        # look up which format was requested
1532        reqrdr = self.ImportMenuId.get(event.GetId()) 
1533        rdlist = self.OnImportGeneric(
1534            reqrdr,self.ImportPowderReaderlist,'Powder Data',multiple=True)
1535        if len(rdlist) == 0: return
1536        self.CheckNotebook()
1537        Iparm = None
1538        lastIparmfile = ''
1539        lastdatafile = ''
1540        newHistList = []
1541#        lastVals = []
1542        self.EnablePlot = False
1543        for rd in rdlist:
1544            if 'Instrument Parameters' in rd.pwdparms:
1545                Iparm1,Iparm2 = rd.pwdparms['Instrument Parameters']
1546            else:
1547                # get instrument parameters for each dataset, unless already set
1548#                if lastIparmfile:  # is this histogram like previous?
1549#                    if lastVals != (rd.powderdata[0].min(),rd.powderdata[0].max(),len(rd.powderdata[0])):
1550#                        lastIparmfile = ''
1551                Iparms = self.GetPowderIparm(rd, Iparm, lastIparmfile, lastdatafile)
1552                if not Iparms:  #may have bailed out
1553                    Id = 0
1554                    continue
1555                Iparm1,Iparm2 = Iparms
1556                if rd.repeat_instparm: 
1557                    lastIparmfile = rd.instfile
1558#                    lastVals = (rd.powderdata[0].min(),rd.powderdata[0].max(),len(rd.powderdata[0]))
1559                # override any keys in read instrument parameters with ones set in import
1560                for key in Iparm1: 
1561                    if key in rd.instdict:
1562                        Iparm1[key] = rd.instdict[key]
1563            lastdatafile = rd.powderentry[0]
1564            HistName = 'PWDR '+G2obj.StripUnicode(rd.idstring,'_')
1565            # make new histogram names unique
1566            if HistName in PWDRlist:
1567                dlg = wx.MessageDialog(self,'Skip %s?'%(HistName),'Duplicate data name',wx.YES_NO)
1568                try:
1569                    if dlg.ShowModal() == wx.ID_YES:
1570                        Id = 0
1571                        continue
1572                finally:
1573                    dlg.Destroy()
1574            HistName = G2obj.MakeUniqueLabel(HistName,PWDRlist)
1575            print('Read powder data '+HistName+ 
1576                ' from file '+rd.readfilename +
1577                ' (format: '+ rd.formatName + 
1578                '). Inst parameters from '+rd.instmsg)
1579            # data are read, now store them in the tree
1580            Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
1581            if 'T' in Iparm1['Type'][0]:
1582                if not rd.clockWd and rd.GSAS:
1583                    rd.powderdata[0] *= 100.        #put back the CW centideg correction
1584                cw = np.diff(rd.powderdata[0])
1585                rd.powderdata[0] = rd.powderdata[0][:-1]+cw/2.
1586                if rd.GSAS:     #NB: old GSAS wanted intensities*CW even if normalized!
1587                    npts = min(len(rd.powderdata[0]),len(rd.powderdata[1]),len(cw))
1588                    rd.powderdata[1] = rd.powderdata[1][:npts]/cw[:npts]
1589                    rd.powderdata[2] = rd.powderdata[2][:npts]*cw[:npts]**2  #1/var=w at this point
1590                else:       #NB: from topas/fullprof type files
1591                    rd.powderdata[1] = rd.powderdata[1][:-1]
1592                    rd.powderdata[2] = rd.powderdata[2][:-1]
1593                if 'Itype' in Iparm2:
1594                    Ibeg = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][0])
1595                    Ifin = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][1])
1596                    rd.powderdata[0] = rd.powderdata[0][Ibeg:Ifin]
1597                    YI,WYI = G2pwd.calcIncident(Iparm2,rd.powderdata[0])
1598                    rd.powderdata[1] = rd.powderdata[1][Ibeg:Ifin]/YI
1599                    var = 1./rd.powderdata[2][Ibeg:Ifin]
1600                    var += WYI*rd.powderdata[1]**2
1601                    var /= YI**2
1602                    rd.powderdata[2] = 1./var
1603                rd.powderdata[3] = np.zeros_like(rd.powderdata[0])
1604                rd.powderdata[4] = np.zeros_like(rd.powderdata[0])
1605                rd.powderdata[5] = np.zeros_like(rd.powderdata[0])
1606            Ymin = np.min(rd.powderdata[1])                 
1607            Ymax = np.max(rd.powderdata[1])                 
1608            valuesdict = {
1609                'wtFactor':1.0,
1610                'Dummy':False,
1611                'ranId':ran.randint(0,sys.maxint),
1612                'Offset':[0.0,0.0],'delOffset':0.02*Ymax,'refOffset':-.1*Ymax,'refDelt':0.1*Ymax,
1613                'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
1614                }
1615            # apply user-supplied corrections to powder data
1616            if 'CorrectionCode' in Iparm1:
1617                print('Applying corrections from instprm file')
1618                corr = Iparm1['CorrectionCode'][0]
1619                try:
1620                    exec(corr)
1621                    print('done')
1622                except Exception as err:
1623                    print(u'error: {}'.format(err))
1624                    print('with commands -------------------')
1625                    print(corr)
1626                    print('---------------------------------')
1627                finally:
1628                    del Iparm1['CorrectionCode']
1629            rd.Sample['ranId'] = valuesdict['ranId'] # this should be removed someday
1630            self.PatternTree.SetItemPyData(Id,[valuesdict,rd.powderdata])
1631            self.PatternTree.SetItemPyData(
1632                self.PatternTree.AppendItem(Id,text='Comments'),
1633                rd.comments)
1634            Tmin = min(rd.powderdata[0])
1635            Tmax = max(rd.powderdata[0])
1636            Tmin1 = Tmin
1637            if 'NT' in Iparm1['Type'][0] and G2lat.Pos2dsp(Iparm1,Tmin) < 0.4:               
1638                Tmin1 = G2lat.Dsp2pos(Iparm1,0.4)
1639            self.PatternTree.SetItemPyData(
1640                self.PatternTree.AppendItem(Id,text='Limits'),
1641                rd.pwdparms.get('Limits',[(Tmin,Tmax),[Tmin1,Tmax]])
1642                )
1643            self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
1644            self.PatternTree.SetItemPyData(
1645                self.PatternTree.AppendItem(Id,text='Background'),
1646                rd.pwdparms.get('Background',
1647                    [['chebyschev',True,3,1.0,0.0,0.0],{'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
1648                    )
1649            self.PatternTree.SetItemPyData(
1650                self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
1651                [Iparm1,Iparm2])
1652            self.PatternTree.SetItemPyData(
1653                self.PatternTree.AppendItem(Id,text='Sample Parameters'),
1654                rd.Sample)
1655            self.PatternTree.SetItemPyData(
1656                self.PatternTree.AppendItem(Id,text='Peak List')
1657                ,{'peaks':[],'sigDict':{}})
1658            self.PatternTree.SetItemPyData(
1659                self.PatternTree.AppendItem(Id,text='Index Peak List'),
1660                [[],[]])
1661            self.PatternTree.SetItemPyData(
1662                self.PatternTree.AppendItem(Id,text='Unit Cells List'),
1663                [])
1664            self.PatternTree.SetItemPyData(
1665                self.PatternTree.AppendItem(Id,text='Reflection Lists'),
1666                {})
1667            # if any Control values have been set, move them into tree
1668            Controls = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.root, 'Controls'))
1669            Controls.update(rd.Controls)
1670            newHistList.append(HistName)
1671            rd.repeat_instparm = False  #clear the iparm reuse flag
1672        else:
1673            self.EnablePlot = True
1674            if Id:
1675                self.PatternTree.Expand(Id)
1676                self.PatternTree.SelectItem(Id)
1677
1678        if not newHistList: return # somehow, no new histograms
1679        # make a list of phase names
1680        phaseRIdList,usedHistograms = self.GetPhaseInfofromTree()
1681        phaseNameList = usedHistograms.keys() # phase names in use
1682        if not phaseNameList: return # no phases yet, nothing to do
1683        header = 'Select phase(s) to link\nto the newly-read data:'
1684        for Name in newHistList:
1685            header += '\n  '+str(Name)
1686
1687        result = G2G.ItemSelector(phaseNameList,self,header,header='Add to phase(s)',multiple=True)
1688        if not result: return
1689        # connect new phases to histograms
1690        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1691        if not sub:
1692            raise Exception('ERROR -- why are there no phases here?')
1693        item, cookie = self.PatternTree.GetFirstChild(sub)
1694        iph = -1
1695        while item: # loop over (new) phases
1696            iph += 1
1697            data = self.PatternTree.GetItemPyData(item)
1698            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1699            if iph not in result: continue
1700            generalData = data['General']
1701            SGData = generalData['SGData']
1702            UseList = data['Histograms']
1703            NShkl = len(G2spc.MustrainNames(SGData))
1704            NDij = len(G2spc.HStrainNames(SGData))
1705            for histoName in newHistList:
1706                UseList[histoName] = SetDefaultDData('PWDR',histoName,NShkl=NShkl,NDij=NDij)
1707                Id = G2gd.GetPatternTreeItemId(self,self.root,histoName)
1708                refList = self.PatternTree.GetItemPyData(
1709                    G2gd.GetPatternTreeItemId(self,Id,'Reflection Lists'))
1710                refList[generalData['Name']] = []
1711        self.EnableRefineCommand()
1712        return # success
1713
1714    def OnDummyPowder(self,event):
1715        '''Called in response to Import/Powder Data/Simulate menu item
1716        to create a Dummy powder diffraction data set.
1717
1718        Reads an instrument parameter file and then gets input from the user
1719        '''
1720        # get a list of existing histograms
1721        PWDRlist = []
1722        if self.PatternTree.GetCount():
1723            item, cookie = self.PatternTree.GetFirstChild(self.root)
1724            while item:
1725                name = self.PatternTree.GetItemText(item)
1726                if name.startswith('PWDR ') and name not in PWDRlist:
1727                    PWDRlist.append(name)
1728                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1729        # Initialize a base class reader
1730        rd = G2obj.ImportPowderData(
1731            extensionlist=tuple(),
1732            strictExtension=False,
1733            formatName = 'Simulate dataset',
1734            longFormatName = 'Compute a simulated pattern')
1735        rd.powderentry[0] = '' # no filename
1736        # #self.powderentry[1] = pos # bank offset (N/A here)
1737        rd.powderentry[2] = 1 # only one bank
1738        rd.comments.append('This is a dummy dataset for powder pattern simulation')
1739        self.CheckNotebook()
1740        Iparm = None
1741        lastdatafile = ''
1742        self.zipfile = None
1743        # get instrument parameters for it
1744        Iparm1,Iparm2 = self.GetPowderIparm(rd, Iparm, '', lastdatafile)
1745        if 'T' in Iparm1['Type'][0]:
1746            print('TOF simulation not supported yet')
1747            return False
1748        else:
1749            # need to get name, 2theta start, end, step
1750            rd.idstring = ' CW'
1751            if 'X' in Iparm1['Type'][0]:
1752                rd.idstring = 'CW x-ray simulation'
1753            else:
1754                rd.idstring = 'CW neutron simulation'
1755            # base initial range on wavelength
1756            wave = Iparm1.get('Lam')
1757            if wave:
1758                wave = wave[0]
1759            else:
1760                wave = Iparm1.get('Lam1')
1761                if wave:
1762                    wave = wave[0]
1763        N = 0
1764        while (N < 3): # insist on a dataset with a few points
1765            names = ('dataset name', 'start angle', 'end angle', 'step size')
1766            if not wave or wave < 1.0:
1767                inp = [rd.idstring, 10.,40.,0.005] # see names for what's what
1768            else:
1769                inp = [rd.idstring, 10.,80.,0.01] # see names for what's what
1770            dlg = G2G.ScrolledMultiEditor(
1771                self,[inp] * len(inp),range(len(inp)),names,
1772                header='Enter simulation name and range',
1773                minvals=(None,0.001,0.001,0.0001),
1774                maxvals=(None,180.,180.,.1),
1775                sizevals=((225,-1),)
1776                )
1777            dlg.CenterOnParent()
1778            if dlg.ShowModal() == wx.ID_OK:
1779                if inp[1] > inp[2]:
1780                    end,start,step = inp[1:]
1781                else:               
1782                    start,end,step = inp[1:]
1783                step = abs(step)
1784            else:
1785                return False
1786            N = int((end-start)/step)+1
1787            x = np.linspace(start,end,N,True)
1788            N = len(x)
1789        rd.powderdata = [
1790            np.array(x), # x-axis values
1791            np.zeros_like(x), # powder pattern intensities
1792            np.ones_like(x), # 1/sig(intensity)^2 values (weights)
1793            np.zeros_like(x), # calc. intensities (zero)
1794            np.zeros_like(x), # calc. background (zero)
1795            np.zeros_like(x), # obs-calc profiles
1796            ]
1797        Tmin = rd.powderdata[0][0]
1798        Tmax = rd.powderdata[0][-1]
1799        # data are read, now store them in the tree
1800        HistName = inp[0]
1801        HistName = 'PWDR '+HistName
1802        HistName = G2obj.MakeUniqueLabel(HistName,PWDRlist)  # make new histogram names unique
1803        Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
1804        Ymin = np.min(rd.powderdata[1])
1805        Ymax = np.max(rd.powderdata[1])
1806        valuesdict = {
1807            'wtFactor':1.0,
1808            'Dummy':True,
1809            'ranId':ran.randint(0,sys.maxint),
1810            'Offset':[0.0,0.0],'delOffset':0.02*Ymax,'refOffset':-.1*Ymax,'refDelt':0.1*Ymax,
1811            'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
1812            }
1813        self.PatternTree.SetItemPyData(Id,[valuesdict,rd.powderdata])
1814        self.PatternTree.SetItemPyData(
1815            self.PatternTree.AppendItem(Id,text='Comments'),
1816            rd.comments)
1817        self.PatternTree.SetItemPyData(
1818            self.PatternTree.AppendItem(Id,text='Limits'),
1819            [(Tmin,Tmax),[Tmin,Tmax]])
1820        self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
1821        self.PatternTree.SetItemPyData(
1822            self.PatternTree.AppendItem(Id,text='Background'),
1823            [['chebyschev',True,3,1.0,0.0,0.0],
1824             {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
1825        self.PatternTree.SetItemPyData(
1826            self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
1827            [Iparm1,Iparm2])
1828        self.PatternTree.SetItemPyData(
1829            self.PatternTree.AppendItem(Id,text='Sample Parameters'),
1830            rd.Sample)
1831        self.PatternTree.SetItemPyData(
1832            self.PatternTree.AppendItem(Id,text='Peak List')
1833            ,{'peaks':[],'sigDict':{}})
1834        self.PatternTree.SetItemPyData(
1835            self.PatternTree.AppendItem(Id,text='Index Peak List'),
1836            [[],[]])
1837        self.PatternTree.SetItemPyData(
1838            self.PatternTree.AppendItem(Id,text='Unit Cells List'),
1839            [])
1840        self.PatternTree.SetItemPyData(
1841            self.PatternTree.AppendItem(Id,text='Reflection Lists'),
1842            {})
1843        self.PatternTree.Expand(Id)
1844        self.PatternTree.SelectItem(Id)
1845        print(u'Added simulation powder data {}'.format(HistName)+
1846              ' with parameters from {}'.format(rd.instmsg))
1847
1848        # make a list of phase names
1849        phaseRIdList,usedHistograms = self.GetPhaseInfofromTree()
1850        phaseNameList = usedHistograms.keys() # phase names in use
1851        if not phaseNameList: return # no phases yet, nothing to do
1852        header = 'Select phase(s) to add the new\npowder simulation (dummy) dataset to:'
1853        result = G2G.ItemSelector(phaseNameList,self,header,header='Add to phase(s)',multiple=True)
1854        if not result: return
1855        # connect new phases to histograms
1856        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1857        if not sub:
1858            raise Exception('ERROR -- why are there no phases here?')
1859        item, cookie = self.PatternTree.GetFirstChild(sub)
1860        iph = -1
1861        while item: # loop over (new) phases
1862            iph += 1
1863            data = self.PatternTree.GetItemPyData(item)
1864            item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1865            if iph not in result: continue
1866            generalData = data['General']
1867            SGData = generalData['SGData']
1868            UseList = data['Histograms']
1869            NShkl = len(G2spc.MustrainNames(SGData))
1870            NDij = len(G2spc.HStrainNames(SGData))
1871            UseList[HistName] = SetDefaultDData('PWDR',HistName,NShkl=NShkl,NDij=NDij)
1872            Id = G2gd.GetPatternTreeItemId(self,self.root,HistName)
1873            refList = self.PatternTree.GetItemPyData(
1874                G2gd.GetPatternTreeItemId(self,Id,'Reflection Lists'))
1875            refList[generalData['Name']] = []
1876        self.EnableRefineCommand()
1877        return # success
1878       
1879    def OnPreferences(self,event):
1880        'Edit the GSAS-II configuration variables'
1881        dlg = G2G.SelectConfigSetting(self)
1882        dlg.ShowModal() == wx.ID_OK
1883        dlg.Destroy()
1884
1885    def _Add_ImportMenu_smallangle(self,parent):
1886        '''configure the Small Angle Data menus accord to the readers found in _init_Imports
1887        '''
1888        submenu = wx.Menu()
1889        item = parent.AppendMenu(wx.ID_ANY, 'Small Angle Data',
1890            submenu, help='Import small angle data')
1891        for reader in self.ImportSmallAngleReaderlist:
1892            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
1893                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
1894            self.ImportMenuId[item.GetId()] = reader
1895            self.Bind(wx.EVT_MENU, self.OnImportSmallAngle, id=item.GetId())
1896        # item = submenu.Append(wx.ID_ANY,
1897        #     help='Import small angle data, use file to try to determine format',
1898        #     kind=wx.ITEM_NORMAL,text='guess format from file')
1899        # self.Bind(wx.EVT_MENU, self.OnImportSmallAngle, id=item.GetId())
1900
1901    def OnImportSmallAngle(self,event):
1902        '''Called in response to an Import/Small Angle Data/... menu item
1903        to read a small angle diffraction data set.
1904        dict self.ImportMenuId is used to look up the specific
1905        reader item associated with the menu item, which will be
1906        None for the last menu item, which is the "guess" option
1907        where all appropriate formats will be tried.
1908
1909        '''
1910       
1911        def GetSASDIparm(reader):
1912            parm = reader.instdict
1913            Iparm = {'Type':[parm['type'],parm['type'],0],'Lam':[parm['wave'],
1914                parm['wave'],0],'Azimuth':[0.,0.,0]}           
1915            return Iparm,{}
1916           
1917        # get a list of existing histograms
1918        SASDlist = []
1919        if self.PatternTree.GetCount():
1920            item, cookie = self.PatternTree.GetFirstChild(self.root)
1921            while item:
1922                name = self.PatternTree.GetItemText(item)
1923                if name.startswith('SASD ') and name not in SASDlist:
1924                    SASDlist.append(name)
1925                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1926        # look up which format was requested
1927        reqrdr = self.ImportMenuId.get(event.GetId()) 
1928        rdlist = self.OnImportGeneric(
1929            reqrdr,self.ImportSmallAngleReaderlist,'Small Angle Data',multiple=True)
1930        if len(rdlist) == 0: return
1931        self.CheckNotebook()
1932        newHistList = []
1933        self.EnablePlot = False
1934        for rd in rdlist:
1935            HistName = rd.idstring
1936            HistName = 'SASD '+HistName
1937            # make new histogram names unique
1938            HistName = G2obj.MakeUniqueLabel(HistName,SASDlist)
1939            print 'Read small angle data '+HistName+ \
1940                ' from file '+self.lastimport
1941            # data are read, now store them in the tree
1942            Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
1943            Iparm1,Iparm2 = GetSASDIparm(rd)
1944#            if 'T' in Iparm1['Type'][0]:
1945#                if not rd.clockWd and rd.GSAS:
1946#                    rd.powderdata[0] *= 100.        #put back the CW centideg correction
1947#                cw = np.diff(rd.powderdata[0])
1948#                rd.powderdata[0] = rd.powderdata[0][:-1]+cw/2.
1949#                rd.powderdata[1] = rd.powderdata[1][:-1]/cw
1950#                rd.powderdata[2] = rd.powderdata[2][:-1]*cw**2  #1/var=w at this point
1951#                if 'Itype' in Iparm2:
1952#                    Ibeg = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][0])
1953#                    Ifin = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][1])
1954#                    rd.powderdata[0] = rd.powderdata[0][Ibeg:Ifin]
1955#                    YI,WYI = G2pwd.calcIncident(Iparm2,rd.powderdata[0])
1956#                    rd.powderdata[1] = rd.powderdata[1][Ibeg:Ifin]/YI
1957#                    var = 1./rd.powderdata[2][Ibeg:Ifin]
1958#                    var += WYI*rd.powderdata[1]**2
1959#                    var /= YI**2
1960#                    rd.powderdata[2] = 1./var
1961#                rd.powderdata[3] = np.zeros_like(rd.powderdata[0])                                       
1962#                rd.powderdata[4] = np.zeros_like(rd.powderdata[0])                                       
1963#                rd.powderdata[5] = np.zeros_like(rd.powderdata[0])                                       
1964            Tmin = min(rd.smallangledata[0])
1965            Tmax = max(rd.smallangledata[0])
1966            valuesdict = {
1967                'wtFactor':1.0,
1968                'Dummy':False,
1969                'ranId':ran.randint(0,sys.maxint),
1970                'Offset':[0.0,0.0],
1971                }
1972            rd.Sample['ranId'] = valuesdict['ranId'] # this should be removed someday
1973            self.PatternTree.SetItemPyData(Id,[valuesdict,rd.smallangledata])
1974            self.PatternTree.SetItemPyData(
1975                self.PatternTree.AppendItem(Id,text='Comments'),
1976                rd.comments)
1977            self.PatternTree.SetItemPyData(
1978                self.PatternTree.AppendItem(Id,text='Limits'),
1979                [(Tmin,Tmax),[Tmin,Tmax]])
1980            self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
1981            self.PatternTree.SetItemPyData(
1982                self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
1983                [Iparm1,Iparm2])
1984            self.PatternTree.SetItemPyData(
1985                self.PatternTree.AppendItem(Id,text='Substances'),G2pdG.SetDefaultSubstances())
1986            self.PatternTree.SetItemPyData(
1987                self.PatternTree.AppendItem(Id,text='Sample Parameters'),
1988                rd.Sample)
1989            self.PatternTree.SetItemPyData(
1990                self.PatternTree.AppendItem(Id,text='Models'),G2pdG.SetDefaultSASDModel())
1991            newHistList.append(HistName)
1992        else:
1993            self.EnablePlot = True
1994            self.PatternTree.Expand(Id)
1995            self.PatternTree.SelectItem(Id)
1996           
1997        if not newHistList: return # somehow, no new histograms
1998        return # success
1999       
2000    def _Add_ImportMenu_reflectometry(self,parent):
2001        '''configure the reflectometry Data menus accord to the readers found in _init_Imports
2002        '''
2003        submenu = wx.Menu()
2004        item = parent.AppendMenu(wx.ID_ANY, 'Reflectometry Data',
2005            submenu, help='Import reflectometry data')
2006        for reader in self.ImportReflectometryReaderlist:
2007            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
2008                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
2009            self.ImportMenuId[item.GetId()] = reader
2010            self.Bind(wx.EVT_MENU, self.OnImportReflectometry, id=item.GetId())
2011        # item = submenu.Append(wx.ID_ANY,
2012        #     help='Import reflectometry data, use file to try to determine format',
2013        #     kind=wx.ITEM_NORMAL,text='guess format from file')
2014        # self.Bind(wx.EVT_MENU, self.OnImportReflectometry, id=item.GetId())
2015       
2016    def OnImportReflectometry(self,event):
2017        '''Called in response to an Import/Reflectometry Data/... menu item
2018        to read a reflectometry data set.
2019        dict self.ImportMenuId is used to look up the specific
2020        reader item associated with the menu item, which will be
2021        None for the last menu item, which is the "guess" option
2022        where all appropriate formats will be tried.
2023
2024        '''
2025       
2026        def GetREFDIparm(reader):
2027            parm = reader.instdict
2028            Iparm = {'Type':[parm['type'],parm['type'],0],'Lam':[parm['wave'],
2029                parm['wave'],0],'Azimuth':[0.,0.,0]}           
2030            return Iparm,{}
2031           
2032        # get a list of existing histograms
2033        REFDlist = []
2034        if self.PatternTree.GetCount():
2035            item, cookie = self.PatternTree.GetFirstChild(self.root)
2036            while item:
2037                name = self.PatternTree.GetItemText(item)
2038                if name.startswith('REFD ') and name not in REFDlist:
2039                    REFDlist.append(name)
2040                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2041        # look up which format was requested
2042        reqrdr = self.ImportMenuId.get(event.GetId()) 
2043        rdlist = self.OnImportGeneric(
2044            reqrdr,self.ImportReflectometryReaderlist,'Reflectometry Data',multiple=True)
2045        if len(rdlist) == 0: return
2046        self.CheckNotebook()
2047        newHistList = []
2048        self.EnablePlot = False
2049        for rd in rdlist:
2050            HistName = rd.idstring
2051            HistName = 'REFD '+HistName
2052            # make new histogram names unique
2053            HistName = G2obj.MakeUniqueLabel(HistName,REFDlist)
2054            print 'Read reflectometry data '+HistName+ \
2055                ' from file '+self.lastimport
2056            # data are read, now store them in the tree
2057            Id = self.PatternTree.AppendItem(parent=self.root,text=HistName)
2058            Iparm1,Iparm2 = GetREFDIparm(rd)
2059#            if 'T' in Iparm1['Type'][0]:
2060#                if not rd.clockWd and rd.GSAS:
2061#                    rd.powderdata[0] *= 100.        #put back the CW centideg correction
2062#                cw = np.diff(rd.powderdata[0])
2063#                rd.powderdata[0] = rd.powderdata[0][:-1]+cw/2.
2064#                rd.powderdata[1] = rd.powderdata[1][:-1]/cw
2065#                rd.powderdata[2] = rd.powderdata[2][:-1]*cw**2  #1/var=w at this point
2066#                if 'Itype' in Iparm2:
2067#                    Ibeg = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][0])
2068#                    Ifin = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][1])
2069#                    rd.powderdata[0] = rd.powderdata[0][Ibeg:Ifin]
2070#                    YI,WYI = G2pwd.calcIncident(Iparm2,rd.powderdata[0])
2071#                    rd.powderdata[1] = rd.powderdata[1][Ibeg:Ifin]/YI
2072#                    var = 1./rd.powderdata[2][Ibeg:Ifin]
2073#                    var += WYI*rd.powderdata[1]**2
2074#                    var /= YI**2
2075#                    rd.powderdata[2] = 1./var
2076#                rd.powderdata[3] = np.zeros_like(rd.powderdata[0])                                       
2077#                rd.powderdata[4] = np.zeros_like(rd.powderdata[0])                                       
2078#                rd.powderdata[5] = np.zeros_like(rd.powderdata[0])                                       
2079            Tmin = min(rd.reflectometrydata[0])
2080            Tmax = max(rd.reflectometrydata[0])
2081            ifDQ = np.any(rd.reflectometrydata[5])
2082            valuesdict = {
2083                'wtFactor':1.0,
2084                'Dummy':False,
2085                'ranId':ran.randint(0,sys.maxint),
2086                'Offset':[0.0,0.0],
2087                'ifDQ':ifDQ
2088                }
2089            rd.Sample['ranId'] = valuesdict['ranId'] # this should be removed someday
2090            self.PatternTree.SetItemPyData(Id,[valuesdict,rd.reflectometrydata])
2091            self.PatternTree.SetItemPyData(
2092                self.PatternTree.AppendItem(Id,text='Comments'),
2093                rd.comments)
2094            self.PatternTree.SetItemPyData(
2095                self.PatternTree.AppendItem(Id,text='Limits'),
2096                [(Tmin,Tmax),[Tmin,Tmax]])
2097            self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
2098            self.PatternTree.SetItemPyData(
2099                self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
2100                [Iparm1,Iparm2])
2101            self.PatternTree.SetItemPyData(
2102                self.PatternTree.AppendItem(Id,text='Substances'),G2pdG.SetDefaultSubstances())
2103            self.PatternTree.SetItemPyData(
2104                self.PatternTree.AppendItem(Id,text='Sample Parameters'),
2105                rd.Sample)
2106            self.PatternTree.SetItemPyData(
2107                self.PatternTree.AppendItem(Id,text='Models'),G2pdG.SetDefaultREFDModel())
2108            newHistList.append(HistName)
2109        else:
2110            self.EnablePlot = True
2111            self.PatternTree.Expand(Id)
2112            self.PatternTree.SelectItem(Id)
2113           
2114        if not newHistList: return # somehow, no new histograms
2115        return # success
2116
2117    def _Add_ImportMenu_PDF(self,parent):
2118        '''configure the PDF Data menus accord to the readers found in _init_Imports
2119        '''
2120        submenu = wx.Menu()
2121        item = parent.AppendMenu(wx.ID_ANY, 'PDF G(R) Data',
2122            submenu, help='Import PDF G(R) data')
2123        for reader in self.ImportPDFReaderlist:
2124            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
2125                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
2126            self.ImportMenuId[item.GetId()] = reader
2127            self.Bind(wx.EVT_MENU, self.OnImportPDF, id=item.GetId())
2128        # item = submenu.Append(wx.ID_ANY,
2129        #     help='Import reflectometry data, use file to try to determine format',
2130        #     kind=wx.ITEM_NORMAL,text='guess format from file')
2131        # self.Bind(wx.EVT_MENU, self.OnImportReflectometry, id=item.GetId())
2132       
2133    def OnImportPDF(self,event):
2134        '''Called in response to an Import/PDF G(R) Data/... menu item
2135        to read a PDF G(R) data set.
2136        dict self.ImportMenuId is used to look up the specific
2137        reader item associated with the menu item, which will be
2138        None for the last menu item, which is the "guess" option
2139        where all appropriate formats will be tried.
2140
2141        '''
2142       
2143        # get a list of existing histograms
2144        PDFlist = []
2145        if self.PatternTree.GetCount():
2146            item, cookie = self.PatternTree.GetFirstChild(self.root)
2147            while item:
2148                name = self.PatternTree.GetItemText(item)
2149                if name.startswith('PDF ') and name not in PDFlist:
2150                    PDFlist.append(name)
2151                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2152        # look up which format was requested
2153        reqrdr = self.ImportMenuId.get(event.GetId()) 
2154        rdlist = self.OnImportGeneric(
2155            reqrdr,self.ImportPDFReaderlist,'PDF G(R) Data',multiple=True)
2156        if len(rdlist) == 0: return
2157        self.CheckNotebook()
2158        newHistList = []
2159        self.EnablePlot = False
2160        for rd in rdlist:
2161            HistName = rd.idstring
2162            HistName = 'PDF '+HistName
2163            # make new histogram names unique
2164            HistName = G2obj.MakeUniqueLabel(HistName,PDFlist)
2165            print 'Read PDF G(R) data '+HistName+ \
2166                ' from file '+self.lastimport
2167            # data are read, now store them in the tree
2168            Id = self.PatternTree.AppendItem(self.root,text=HistName)
2169            Ymin = np.min(rd.pdfdata[1])                 
2170            Ymax = np.max(rd.pdfdata[1])                 
2171            valuesdict = {
2172                'wtFactor':1.0,'Dummy':False,'ranId':ran.randint(0,sys.maxint),
2173                'Offset':[0.0,0.0],'delOffset':0.02*Ymax,
2174                'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
2175                }
2176            self.PatternTree.SetItemPyData(
2177                self.PatternTree.AppendItem(Id,text='PDF Controls'),
2178                    {'G(R)':[valuesdict,rd.pdfdata,HistName],'diffGRname':'','diffMult':1.0})
2179            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='PDF Peaks'),
2180                {'Limits':[1.,5.],'Background':[2,[0.,-0.2*np.pi],False],'Peaks':[]})
2181        else:
2182            self.EnablePlot = True
2183            self.PatternTree.Expand(Id)
2184            self.PatternTree.SelectItem(Id)
2185           
2186        if not newHistList: return # somehow, no new histograms
2187        return # success
2188       
2189###############################################################################
2190#Command logging
2191###############################################################################
2192
2193    def OnMacroRecordStatus(self,event,setvalue=None):
2194        '''Called when the record macro menu item is used which toggles the
2195        value. Alternately a value to be set can be provided. Note that this
2196        routine is made more complex because on the Mac there are lots of menu
2197        items (listed in self.MacroStatusList) and this loops over all of them.
2198        '''
2199        nextvalue = log.ShowLogStatus() != True
2200        if setvalue is not None:
2201            nextvalue = setvalue
2202        if nextvalue:
2203            log.LogOn()
2204            set2 = True
2205        else:
2206            log.LogOff()
2207            set2 = False
2208        for menuitem in self.MacroStatusList:
2209            menuitem.Check(set2)
2210
2211    def _init_Macro(self):
2212        '''Define the items in the macro menu.
2213        '''
2214        menu = self.MacroMenu
2215        item = menu.Append(
2216                help='Start or stop recording of menu actions, etc.', id=wx.ID_ANY,
2217                kind=wx.ITEM_CHECK,text='Record actions')
2218        self.MacroStatusList.append(item)
2219        item.Check(log.ShowLogStatus())
2220        self.Bind(wx.EVT_MENU, self.OnMacroRecordStatus, item)
2221
2222        # this may only be of value for development work
2223        item = menu.Append(
2224            help='Show logged commands', id=wx.ID_ANY,
2225            kind=wx.ITEM_NORMAL,text='Show log')
2226        def OnShowLog(event):
2227            print 70*'='
2228            print 'List of logged actions'
2229            for i,line in enumerate(log.G2logList):
2230                if line: print i,line
2231            print 70*'='
2232        self.Bind(wx.EVT_MENU, OnShowLog, item)
2233
2234        item = menu.Append(
2235            help='Clear logged commands', id=wx.ID_ANY,
2236            kind=wx.ITEM_NORMAL,text='Clear log')
2237        def OnClearLog(event): log.G2logList=[None]
2238        self.Bind(wx.EVT_MENU, OnClearLog, item)
2239       
2240        item = menu.Append(
2241            help='Save logged commands to file', id=wx.ID_ANY,
2242            kind=wx.ITEM_NORMAL,text='Save log')
2243        def OnSaveLog(event):
2244            import cPickle
2245            defnam = os.path.splitext(
2246                os.path.split(self.GSASprojectfile)[1]
2247                )[0]+'.gcmd'
2248            dlg = wx.FileDialog(self,
2249                'Choose an file to save past actions', '.', defnam, 
2250                'GSAS-II cmd output (*.gcmd)|*.gcmd',
2251                wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
2252            dlg.CenterOnParent()
2253            try:
2254                if dlg.ShowModal() == wx.ID_OK:
2255                    filename = dlg.GetPath()
2256                    # make sure extension is correct
2257                    filename = os.path.splitext(filename)[0]+'.gcmd'
2258                else:
2259                    filename = None
2260            finally:
2261                dlg.Destroy()
2262            if filename:
2263                fp = open(filename,'wb')
2264                fp.write(str(len(log.G2logList)-1)+'\n')
2265                for item in log.G2logList:
2266                    if item: cPickle.dump(item,fp)
2267                fp.close()
2268        self.Bind(wx.EVT_MENU, OnSaveLog, item)
2269
2270        item = menu.Append(
2271            help='Load logged commands from file', id=wx.ID_ANY,
2272            kind=wx.ITEM_NORMAL,text='Load log')
2273        def OnLoadLog(event):
2274            # this appends. Perhaps we should ask to clear?
2275            import cPickle
2276            defnam = os.path.splitext(
2277                os.path.split(self.GSASprojectfile)[1]
2278                )[0]+'.gcmd'
2279            dlg = wx.FileDialog(self,
2280                'Choose an file to read saved actions', '.', defnam, 
2281                'GSAS-II cmd output (*.gcmd)|*.gcmd',
2282                wx.OPEN)
2283            dlg.CenterOnParent()
2284            try:
2285                if dlg.ShowModal() == wx.ID_OK:
2286                    filename = dlg.GetPath()
2287                    # make sure extension is correct
2288                    filename = os.path.splitext(filename)[0]+'.gcmd'
2289                else:
2290                    filename = None
2291            finally:
2292                dlg.Destroy()
2293            if filename and os.path.exists(filename):
2294                fp = open(filename,'rb')
2295                lines = fp.readline()
2296                for i in range(int(lines)):
2297                    log.G2logList.append(cPickle.load(fp))
2298                fp.close()
2299        self.Bind(wx.EVT_MENU, OnLoadLog, item)
2300
2301        item = menu.Append(
2302            help='Replay saved commands', id=wx.ID_ANY,
2303            kind=wx.ITEM_NORMAL,text='Replay log')
2304        self.Bind(wx.EVT_MENU, log.ReplayLog, item)
2305
2306    def _init_Exports(self,menu):
2307        '''Find exporter routines and add them into menus
2308        '''
2309        # set up the top-level menus
2310        projectmenu = wx.Menu()
2311        item = menu.AppendMenu(
2312            wx.ID_ANY, 'Entire project as',
2313            projectmenu, help='Export entire project')
2314
2315        phasemenu = wx.Menu()
2316        item = menu.AppendMenu(
2317            wx.ID_ANY, 'Phase as',
2318            phasemenu, help='Export phase or sometimes phases')
2319
2320        powdermenu = wx.Menu()
2321        item = menu.AppendMenu(
2322            wx.ID_ANY, 'Powder data as',
2323            powdermenu, help='Export powder diffraction histogram(s)')
2324
2325        singlemenu = wx.Menu()
2326        item = menu.AppendMenu(
2327            wx.ID_ANY, 'Single crystal data as',
2328            singlemenu, help='Export single crystal histogram(s)')
2329
2330        imagemenu = wx.Menu()
2331        item = menu.AppendMenu(
2332            wx.ID_ANY, 'Image data as',
2333            imagemenu, help='Export powder image(s) data')
2334
2335        mapmenu = wx.Menu()
2336        item = menu.AppendMenu(
2337            wx.ID_ANY, 'Maps as',
2338            mapmenu, help='Export density map(s)')
2339
2340        # pdfmenu = wx.Menu()
2341        # item = menu.AppendMenu(
2342        #     wx.ID_ANY, 'PDFs as',
2343        #     pdfmenu, help='Export pair distribution function(s)')
2344
2345        # find all the exporter files
2346        if not self.exporterlist: # this only needs to be done once
2347            pathlist = sys.path
2348            filelist = []
2349            for path in pathlist:
2350                for filename in glob.iglob(os.path.join(path,"G2export*.py")):
2351                    filelist.append(filename)   
2352            filelist = sorted(list(set(filelist))) # remove duplicates
2353            # go through the routines and import them, saving objects that
2354            # have export routines (method Exporter)
2355            for filename in filelist:
2356                path,rootname = os.path.split(filename)
2357                pkg = os.path.splitext(rootname)[0]
2358#                try:
2359                fp = None
2360                fp, fppath,desc = imp.find_module(pkg,[path,])
2361                pkg = imp.load_module(pkg,fp,fppath,desc)
2362                for clss in inspect.getmembers(pkg): # find classes defined in package
2363                    if clss[0].startswith('_'): continue
2364                    if inspect.isclass(clss[1]):
2365                        # check if we have the required methods
2366                        for m in 'Exporter','loadParmDict':
2367                            if not hasattr(clss[1],m): break
2368                            if not callable(getattr(clss[1],m)): break
2369                        else:
2370                            exporter = clss[1](self) # create an export instance
2371                            self.exporterlist.append(exporter)
2372#                except AttributeError:
2373#                    print 'Import_'+errprefix+': Attribute Error'+str(filename)
2374#                    pass
2375#                except ImportError:
2376#                    print 'Import_'+errprefix+': Error importing file'+str(filename)
2377#                    pass
2378                if fp: fp.close()
2379        # Add submenu item(s) for each Exporter by its self-declared type (can be more than one)
2380        for obj in self.exporterlist:
2381            #print 'exporter',obj
2382            for typ in obj.exporttype:
2383                if typ == "project":
2384                    submenu = projectmenu
2385                elif typ == "phase":
2386                    submenu = phasemenu
2387                elif typ == "powder":
2388                    submenu = powdermenu
2389                elif typ == "single":
2390                    submenu = singlemenu
2391                elif typ == "image":
2392                    submenu = imagemenu
2393                elif typ == "map":
2394                    submenu = mapmenu
2395                # elif typ == "pdf":
2396                #     submenu = pdfmenu
2397                else:
2398                    print("Error, unknown type in "+str(obj))
2399                    break
2400                item = submenu.Append(
2401                    wx.ID_ANY,
2402                    help=obj.longFormatName,
2403                    kind=wx.ITEM_NORMAL,
2404                    text=obj.formatName)
2405                self.Bind(wx.EVT_MENU, obj.Exporter, id=item.GetId())
2406                self.ExportLookup[item.GetId()] = typ # lookup table for submenu item
2407        item = imagemenu.Append(wx.ID_ANY,
2408                        help='Export image controls and masks for multiple images',
2409                        kind=wx.ITEM_NORMAL,
2410                        text='Multiple image controls and masks')
2411        self.Bind(wx.EVT_MENU, self.OnSaveMultipleImg, id=item.GetId())
2412        #code to debug an Exporter. hard-code the routine below, to allow a reload before use
2413        # def DebugExport(event):
2414        #      print 'start reload'
2415        #      reload(G2IO)
2416        #      import G2export_pwdr as dev
2417        #      reload(dev)
2418        #      dev.ExportPowderFXYE(self).Exporter(event)
2419        # item = menu.Append(
2420        #     wx.ID_ANY,kind=wx.ITEM_NORMAL,
2421        #     help="debug exporter",text="test Export FXYE")
2422        # self.Bind(wx.EVT_MENU, DebugExport, id=item.GetId())
2423        # # #self.ExportLookup[item.GetId()] = 'image'
2424        # self.ExportLookup[item.GetId()] = 'powder'
2425
2426###############################################################################
2427# Exporters
2428###############################################################################
2429                           
2430    def _Add_ExportMenuItems(self,parent):
2431        # item = parent.Append(
2432        #     help='Select PWDR item to enable',id=wx.ID_ANY,
2433        #     kind=wx.ITEM_NORMAL,
2434        #     text='Export Powder Patterns...')
2435        # self.ExportPattern.append(item)
2436        # item.Enable(False)
2437        # self.Bind(wx.EVT_MENU, self.OnExportPatterns, id=item.GetId())
2438
2439        item = parent.Append(
2440            help='',id=wx.ID_ANY,
2441            kind=wx.ITEM_NORMAL,
2442            text='Export All Peak Lists...')
2443        self.ExportPeakList.append(item)
2444        item.Enable(True)
2445        self.Bind(wx.EVT_MENU, self.OnExportPeakList, id=item.GetId())
2446
2447        item = parent.Append(
2448            help='',id=wx.ID_ANY,
2449            kind=wx.ITEM_NORMAL,
2450            text='Export HKLs...')
2451        self.ExportHKL.append(item)
2452        self.Bind(wx.EVT_MENU, self.OnExportHKL, id=item.GetId())
2453
2454        item = parent.Append(
2455            help='Select PDF item to enable',
2456            id=wx.ID_ANY,
2457            kind=wx.ITEM_NORMAL,
2458            text='Export PDF...')
2459        self.ExportPDF.append(item)
2460        item.Enable(False)
2461        self.Bind(wx.EVT_MENU, self.OnExportPDF, id=item.GetId())
2462           
2463    def FillMainMenu(self,menubar,addhelp=True):
2464        '''Define contents of the main GSAS-II menu for the (main) data tree window.
2465        For the mac, this is also called for the data item windows as well so that
2466        the main menu items are data menu as well.
2467        '''
2468        File = wx.Menu(title='')
2469        menubar.Append(menu=File, title='&File')
2470        self._Add_FileMenuItems(File)
2471        Data = wx.Menu(title='')
2472        menubar.Append(menu=Data, title='Data')
2473        self._Add_DataMenuItems(Data)
2474        Calculate = wx.Menu(title='')       
2475        menubar.Append(menu=Calculate, title='&Calculate')
2476        self._Add_CalculateMenuItems(Calculate)
2477        Import = wx.Menu(title='')       
2478        menubar.Append(menu=Import, title='Import')
2479        self._Add_ImportMenu_Image(Import)
2480        self._Add_ImportMenu_Phase(Import)
2481        self._Add_ImportMenu_powder(Import)
2482        self._Add_ImportMenu_Sfact(Import)
2483        self._Add_ImportMenu_smallangle(Import)
2484        self._Add_ImportMenu_reflectometry(Import)
2485        self._Add_ImportMenu_PDF(Import)
2486
2487        #======================================================================
2488        # Code to help develop/debug an importer, much is hard-coded below
2489        # but module is reloaded before each use, allowing faster testing
2490        # def DebugImport(event):
2491        #     print 'start reload'
2492        #     import G2phase_ISO as dev
2493        #     reload(dev)
2494        #     rd = dev.ISODISTORTPhaseReader()
2495        #     self.ImportMenuId[event.GetId()] = rd
2496        #     self.OnImportPhase(event)
2497            # or ----------------------------------------------------------------------
2498            #self.OnImportGeneric(rd,[],'test of ISODISTORTPhaseReader')
2499            # special debug code
2500            # or ----------------------------------------------------------------------
2501            # filename = '/Users/toby/projects/branton/subgroup_cif.txt'
2502            # fp = open(filename,'Ur')
2503            # if not rd.ContentsValidator(fp):
2504            #     print 'not validated'
2505            #     # make a list of used phase ranId's
2506            # phaseRIdList = []
2507            # sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
2508            # if sub:
2509            #     item, cookie = self.PatternTree.GetFirstChild(sub)
2510            #     while item:
2511            #         phaseName = self.PatternTree.GetItemText(item)
2512            #         ranId = self.PatternTree.GetItemPyData(item).get('ranId')
2513            #         if ranId: phaseRIdList.append(ranId)
2514            #         item, cookie = self.PatternTree.GetNextChild(sub, cookie)
2515            # if rd.Reader(filename,fp,usedRanIdList=phaseRIdList):
2516            #     print 'read OK'
2517        # item = Import.Append(
2518        #     wx.ID_ANY,kind=wx.ITEM_NORMAL,
2519        #     help="debug importer",text="test importer")
2520        # self.Bind(wx.EVT_MENU, DebugImport, id=item.GetId())
2521        #======================================================================
2522        self.ExportMenu = wx.Menu(title='')
2523        menubar.Append(menu=self.ExportMenu, title='Export')
2524        self._init_Exports(self.ExportMenu)
2525        self._Add_ExportMenuItems(self.ExportMenu)
2526        if GSASIIpath.GetConfigValue('Enable_logging'):
2527            self.MacroMenu = wx.Menu(title='')
2528            menubar.Append(menu=self.MacroMenu, title='Macro')
2529            self._init_Macro()
2530        if addhelp:
2531            HelpMenu=G2G.MyHelp(self,includeTree=True,
2532                morehelpitems=[('&Tutorials','Tutorials'),])
2533            menubar.Append(menu=HelpMenu,title='&Help')
2534           
2535    def _init_ctrls(self, parent):
2536        wx.Frame.__init__(self, name='GSASII', parent=parent,
2537            size=wx.Size(700, 450),style=wx.DEFAULT_FRAME_STYLE, title='GSAS-II data tree')
2538        clientSize = wx.ClientDisplayRect()
2539        Size = self.GetSize()
2540        xPos = clientSize[2]-Size[0]
2541        self.SetPosition(wx.Point(xPos,clientSize[1]))
2542        self._init_Imports()
2543        #initialize Menu item objects (these contain lists of menu items that are enabled or disabled)
2544        self.MakePDF = []
2545        self.Refine = []
2546        self.SeqRefine = [] # pointer(s) to Sequential Refinement menu objects
2547        #self.ExportPattern = []
2548        self.ExportPeakList = []
2549        self.ExportHKL = []
2550        self.ExportPDF = []
2551        self.ExportPhase = []
2552        self.ExportCIF = []
2553        #
2554        self.GSASIIMenu = wx.MenuBar()
2555        # create a list of all dataframe menus (appended in PrefillDataMenu)
2556        self.dataMenuBars = [self.GSASIIMenu]
2557        self.MacroStatusList = []
2558        self.FillMainMenu(self.GSASIIMenu)
2559        self.SetMenuBar(self.GSASIIMenu)
2560        self.Bind(wx.EVT_SIZE, self.OnSize)
2561        self.Status = self.CreateStatusBar()
2562#TODO - split window tree on left, data on right
2563        self.mainPanel = GSASIIsplit(self,-1)
2564        self.treePanel = wx.Panel(self.mainPanel, wx.ID_ANY,
2565            style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
2566        self.treePanel.SetAutoLayout(True)
2567        self.dataPanel = wx.Panel(self.mainPanel, wx.ID_ANY,
2568            style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
2569        self.dataWindow = G2gd.DataWindow(self.dataPanel)
2570        self.dataWindow.SetAutoLayout(True)
2571        self.dataWindow.SetInitialSize()
2572        self.mainPanel.SetMinimumPaneSize(100)
2573        self.mainPanel.SplitVertically(self.treePanel, self.dataPanel, 200)
2574        self.dataFrame = self.dataWindow        #kluge!!
2575       
2576        wxID_PATTERNTREE = wx.NewId()
2577        treeSizer = wx.BoxSizer()
2578        self.PatternTree = G2G.G2TreeCtrl(id=wxID_PATTERNTREE,
2579            parent=self.treePanel, size=self.treePanel.GetSize(),style=wx.TR_DEFAULT_STYLE )
2580        treeSizer.Add(self.PatternTree,1,wx.EXPAND)
2581        self.treePanel.SetSizer(treeSizer)
2582        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED,self.OnDataTreeSelChanged)
2583        self.PatternTree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK,self.OnDataTreeSelChanged)
2584        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
2585            self.OnPatternTreeItemCollapsed, id=wxID_PATTERNTREE)
2586        self.PatternTree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
2587            self.OnPatternTreeItemExpanded, id=wxID_PATTERNTREE)
2588        self.PatternTree.Bind(wx.EVT_TREE_DELETE_ITEM,
2589            self.OnPatternTreeItemDelete, id=wxID_PATTERNTREE)
2590        self.PatternTree.Bind(wx.EVT_TREE_KEY_DOWN,
2591            self.OnPatternTreeKeyDown, id=wxID_PATTERNTREE)
2592        self.PatternTree.Bind(wx.EVT_TREE_BEGIN_RDRAG,
2593            self.OnPatternTreeBeginRDrag, id=wxID_PATTERNTREE)       
2594        self.PatternTree.Bind(wx.EVT_TREE_END_DRAG,
2595            self.OnPatternTreeEndDrag, id=wxID_PATTERNTREE)       
2596        self.root = self.PatternTree.root       
2597       
2598        plotFrame = wx.Frame(None,-1,'GSASII Plots',size=wx.Size(700,600), \
2599            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
2600        self.G2plotNB = G2plt.G2PlotNoteBook(plotFrame,G2frame=self)
2601        plotFrame.Show()
2602        self.SetDataSize()
2603       
2604    def __init__(self, parent):
2605        self.ExportLookup = {}
2606        self.exporterlist = []
2607        self._init_ctrls(parent)
2608        self.Image = wx.Image(
2609            os.path.join(GSASIIpath.path2GSAS2,'gsas2.ico'),
2610            wx.BITMAP_TYPE_ICO)
2611        if "wxMSW" in wx.PlatformInfo:
2612            img = self.Image.Scale(16, 16).ConvertToBitmap()
2613        elif "wxGTK" in wx.PlatformInfo:
2614            img = self.Image.Scale(22, 22).ConvertToBitmap()
2615        else:
2616            img = self.Image.ConvertToBitmap()
2617        self.SetIcon(wx.IconFromBitmap(img))
2618        self.Bind(wx.EVT_CLOSE, self.ExitMain)
2619        # various defaults
2620        self.oldFocus = None
2621        self.GSASprojectfile = ''
2622        self.undofile = ''
2623        self.TreeItemDelete = False
2624        self.plotStyle = {'qPlot':False,'dPlot':False,'sqrtPlot':False,'sqPlot':False}
2625        self.Weight = False
2626        self.IfPlot = False
2627        self.DDShowAll = False
2628        self.atmSel = ''
2629        self.PatternId = 0
2630        self.PickId = 0
2631        self.PickIdText = None
2632        self.PeakTable = []
2633        self.LimitsTable = []
2634        self.ifX20 = True   #use M20 /= (1+X20) in powder indexing, etc.
2635        self.HKL = []
2636        self.Lines = []
2637        self.itemPicked = None
2638        self.Interpolate = 'nearest'
2639        self.ContourColor = GSASIIpath.GetConfigValue('Contour_color','Paired')
2640        self.VcovColor = 'RdYlGn'
2641        self.RamaColor = 'Blues'
2642        self.Projection = 'equal area'
2643        self.logPlot = False
2644        self.plusPlot = True
2645        self.ErrorBars = False
2646        self.Contour = False
2647        self.Legend = False
2648        self.SinglePlot = True
2649        self.Waterfall = False
2650        self.selections= None
2651        self.PDFselections = None
2652        self.SubBack = False
2653        self.seqReverse = False
2654        self.seqLines = True #draw lines between points
2655        self.plotView = 0
2656        self.Image = 0
2657        self.oldImagefile = '' # the name of the last image file read
2658        self.oldImageTag = None # the name of the tag for multi-image files
2659        self.PauseIntegration = False
2660        self.ImageZ = []
2661        self.Integrate = 0
2662        self.imageDefault = {}
2663        self.IntgOutList = [] # list of integration tree item Ids created in G2IO.SaveIntegration
2664        self.AutointPWDRnames = [] # list of autoint created PWDR tree item names (to be deleted on a reset)
2665        self.autoIntFrame = None
2666        self.IntegratedList = [] # list of already integrated IMG tree items
2667        self.Sngl = False
2668        self.ifGetRing = False
2669        self.MaskKey = ''           #trigger for making image masks
2670        self.MskDelete = False      #trigger for mask delete
2671        self.StrainKey = ''         #ditto for new strain d-zeros
2672        self.EnablePlot = True
2673        self.hist = ''              # selected histogram in Phase/Data tab
2674        self.dirname = os.path.abspath(os.path.expanduser('~'))       #start in the users home directory by default; may be meaningless
2675        self.TutorialImportDir = None  # location to read tutorial files, set when a tutorial is viewed
2676        self.LastImportDir = None # last-used directory where an import was done
2677        self.LastGPXdir = None    # directory where a GPX file was last read
2678        self.LastExportDir = None  # the last directory used for exports, if any.
2679        self.dataDisplayPhaseText = ''
2680        self.lastTreeSetting = []
2681        self.ExpandingAll = False
2682        self.SeqTblHideList = []
2683               
2684        arg = sys.argv
2685        if len(arg) > 1 and arg[1]:
2686            self.GSASprojectfile = os.path.splitext(arg[1])[0]+'.gpx'
2687            self.dirname = os.path.abspath(os.path.dirname(arg[1]))
2688            if self.dirname: os.chdir(self.dirname)
2689            try:
2690                self.StartProject()         #open the file if possible
2691                return
2692            except Exception:
2693                print 'Error opening or reading file',arg[1]
2694                import traceback
2695                print traceback.format_exc()
2696               
2697        if GSASIIpath.GetConfigValue('Starting_directory'):
2698            try:
2699                pth = GSASIIpath.GetConfigValue('Starting_directory')
2700                pth = os.path.expanduser(pth) 
2701                os.chdir(pth)
2702                self.LastGPXdir = pth
2703            except:
2704                print('Ignoring Config Starting_directory value: '+
2705                      GSASIIpath.GetConfigValue('Starting_directory'))
2706
2707    def GetTreeItemsList(self,item):
2708        return self.PatternTree._getTreeItemsList(item)
2709
2710    def OnSize(self,event):
2711        'Called to make PatternTree fill mainPanel'
2712        w,h = self.GetClientSizeTuple()
2713        self.dataWindow.SetupScrolling()
2714        self.mainPanel.SetSize(wx.Size(w,h+1))
2715        self.mainPanel.SetSize(wx.Size(w,h))
2716        self.PatternTree.SetSize(wx.Size(w,h))
2717        self.dataWindow.SetSize(wx.Size(w,h))
2718#        self.dataWindow.Refresh()
2719#        self.dataWindow.Update()
2720       
2721    def SetDataSize(self):
2722        Size = self.GetSize()
2723        Size[1] += 1        #kluge to ensure scrollbar settings & window properly displayed
2724        self.SetSize(Size)
2725        Size[1] -= 1        #kluge to ensure scrollbar settings & window properly displayed
2726        self.SetSize(Size)
2727                               
2728    def OnDataTreeSelChanged(self, event):
2729        '''Called when a data tree item is selected'''
2730        if self.TreeItemDelete:
2731            self.TreeItemDelete = False
2732        else:
2733            if self.ExpandingAll:
2734                if GSASIIpath.GetConfigValue('debug'): print('Skipping Tree selection due to ExpandAll')
2735                return
2736            pltNum = self.G2plotNB.nb.GetSelection()
2737            if pltNum >= 0:                         #to avoid the startup with no plot!
2738                self.G2plotNB.nb.GetPage(pltNum)
2739            item = event.GetItem()
2740            wx.CallAfter(G2gd.SelectDataTreeItem,self,item,self.oldFocus)
2741            #if self.oldFocus: # now done via last parameter on SelectDataTreeItem
2742            #    wx.CallAfter(self.oldFocus.SetFocus)
2743       
2744    def OnPatternTreeItemCollapsed(self, event):
2745        'Called when a tree item is collapsed - all children will be collapsed'
2746        self.PatternTree.CollapseAllChildren(event.GetItem())
2747
2748    def OnPatternTreeItemExpanded(self, event):
2749        'Called when a tree item is expanded'
2750        self.OnDataTreeSelChanged(event)
2751        event.Skip()
2752       
2753    def OnPatternTreeItemDelete(self, event):
2754        'Called when a tree item is deleted -- not sure what this does'
2755        self.TreeItemDelete = True
2756
2757    def OnPatternTreeItemActivated(self, event):
2758        'Called when a tree item is activated'
2759        event.Skip()
2760       
2761    def OnPatternTreeBeginRDrag(self,event):
2762        event.Allow()
2763        self.BeginDragId = event.GetItem()
2764        self.ParentId = self.PatternTree.GetItemParent(self.BeginDragId)
2765        DragText = self.PatternTree.GetItemText(self.BeginDragId)
2766        self.DragData = [[DragText,self.PatternTree.GetItemPyData(self.BeginDragId)],]
2767        item, cookie = self.PatternTree.GetFirstChild(self.BeginDragId)
2768        while item:     #G2 data tree has no sub children under a child of a tree item
2769            name = self.PatternTree.GetItemText(item)
2770            self.DragData.append([name,self.PatternTree.GetItemPyData(item)])
2771            item, cookie = self.PatternTree.GetNextChild(self.BeginDragId, cookie)                           
2772       
2773    def OnPatternTreeEndDrag(self,event):
2774        event.Allow()
2775        self.EndDragId = event.GetItem()
2776        try:
2777            NewParent = self.PatternTree.GetItemParent(self.EndDragId)
2778        except:
2779            self.EndDragId = self.PatternTree.GetLastChild(self.root)
2780            NewParent = self.root
2781        if self.ParentId != NewParent:
2782            self.ErrorDialog('Drag not allowed','Wrong parent for item dragged')
2783        else:
2784            Name,Item = self.DragData[0]
2785            NewId = self.PatternTree.InsertItem(self.ParentId,self.EndDragId,Name,data=None)
2786            self.PatternTree.SetItemPyData(NewId,Item)
2787            for name,item in self.DragData[1:]:     #loop over children
2788                Id = self.PatternTree.AppendItem(parent=NewId,text=name)
2789                self.PatternTree.SetItemPyData(Id,item)
2790            self.PatternTree.Delete(self.BeginDragId)
2791            G2gd.SelectDataTreeItem(self,NewId)
2792       
2793    def OnPatternTreeKeyDown(self,event): #doesn't exactly work right with Shift key down
2794        'Allows stepping through the tree with the up/down arrow keys'
2795        self.oldFocus = wx.Window.FindFocus()
2796        keyevt = event.GetKeyEvent()
2797        key = event.GetKeyCode()
2798        item = self.PatternTree.GetSelection()
2799        if type(item) is int: return # is this the toplevel in tree?
2800        name = self.PatternTree.GetItemText(item)
2801        parent = self.PatternTree.GetItemParent(item)
2802        if key == wx.WXK_UP:
2803            if keyevt.GetModifiers() == wx.MOD_SHIFT and parent != self.root:
2804                if type(parent) is int: return # is this the toplevel in tree?
2805                prev = self.PatternTree.GetPrevSibling(parent)
2806                NewId = G2gd.GetPatternTreeItemId(self,prev,name)
2807                if NewId:
2808                    self.PatternTree.Collapse(parent)
2809                    self.PatternTree.Expand(prev)
2810                    self.oldFocus = wx.Window.FindFocus()
2811                    wx.CallAfter(self.PatternTree.SelectItem,NewId)
2812                else:
2813                    wx.CallAfter(self.PatternTree.SelectItem,item)
2814            elif sys.platform == "win32":   
2815                self.PatternTree.GetPrevSibling(item)
2816                self.PatternTree.SelectItem(item)
2817            else:
2818                item = self.PatternTree.GetPrevSibling(item)
2819                if item.IsOk(): self.PatternTree.SelectItem(item)
2820        elif key == wx.WXK_DOWN:
2821            if keyevt.GetModifiers() == wx.MOD_SHIFT and parent != self.root:
2822                next = self.PatternTree.GetNextSibling(parent)
2823                NewId = G2gd.GetPatternTreeItemId(self,next,name)
2824                if NewId:
2825                    self.PatternTree.Collapse(parent)
2826                    self.PatternTree.Expand(next)
2827                    self.oldFocus = wx.Window.FindFocus()
2828                    wx.CallAfter(self.PatternTree.SelectItem,NewId)
2829                else:
2830                    wx.CallAfter(self.PatternTree.SelectItem,item)
2831            elif sys.platform == "win32":   
2832                self.PatternTree.GetNextSibling(item)
2833                self.PatternTree.SelectItem(item)
2834            else:   
2835                item = self.PatternTree.GetNextSibling(item)
2836                if item.IsOk(): self.PatternTree.SelectItem(item)
2837               
2838    def OnReadPowderPeaks(self,event):
2839        'Bound to menu Data/Read Powder Peaks'
2840        self.CheckNotebook()
2841        pth = G2G.GetImportPath(self)
2842        if not pth: pth = '.'
2843        dlg = wx.FileDialog(self, 'Choose file with peak list', pth, '', 
2844            'peak files (*.txt)|*.txt|All files (*.*)|*.*',wx.OPEN)
2845        try:
2846            if dlg.ShowModal() == wx.ID_OK:
2847                self.HKL = []
2848                self.powderfile = dlg.GetPath()
2849                comments,peaks,limits,wave = G2IO.GetPowderPeaks(self.powderfile)
2850                Id = self.PatternTree.AppendItem(parent=self.root,text='PKS '+os.path.basename(self.powderfile))
2851                data = ['PKS',wave,0.0]
2852                names = ['Type','Lam','Zero'] 
2853                codes = [0,0,0]
2854                inst = [G2IO.makeInstDict(names,data,codes),{}]
2855                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
2856                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),comments)
2857                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(limits),limits])
2858                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[peaks,[]])
2859                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
2860                self.PatternTree.Expand(Id)
2861                self.PatternTree.SelectItem(Id)
2862                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
2863        finally:
2864            dlg.Destroy()
2865                       
2866    def OnImageRead(self,event):
2867        '''Called to read in an image in any known format. *** Depreciated. ***
2868        '''
2869        G2G.G2MessageBox(self,'Please use the Import/Image/... menu item rather than this','depreciating menu item')
2870
2871    def CheckNotebook(self):
2872        '''Make sure the data tree has the minimally expected controls.
2873        '''
2874        if not G2gd.GetPatternTreeItemId(self,self.root,'Notebook'):
2875            sub = self.PatternTree.AppendItem(parent=self.root,text='Notebook')
2876            self.PatternTree.SetItemPyData(sub,[''])
2877        if not G2gd.GetPatternTreeItemId(self,self.root,'Controls'):
2878            sub = self.PatternTree.AppendItem(parent=self.root,text='Controls')
2879            self.PatternTree.SetItemPyData(sub,copy.copy(G2obj.DefaultControls))
2880        if not G2gd.GetPatternTreeItemId(self,self.root,'Covariance'):
2881            sub = self.PatternTree.AppendItem(parent=self.root,text='Covariance')
2882            self.PatternTree.SetItemPyData(sub,{})
2883        if not G2gd.GetPatternTreeItemId(self,self.root,'Constraints'):
2884            sub = self.PatternTree.AppendItem(parent=self.root,text='Constraints')
2885            self.PatternTree.SetItemPyData(sub,{'Hist':[],'HAP':[],'Phase':[]})
2886        if not G2gd.GetPatternTreeItemId(self,self.root,'Restraints'):
2887            sub = self.PatternTree.AppendItem(parent=self.root,text='Restraints')
2888            self.PatternTree.SetItemPyData(sub,{})
2889        if not G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'):
2890            sub = self.PatternTree.AppendItem(parent=self.root,text='Rigid bodies')
2891            self.PatternTree.SetItemPyData(sub,{'Vector':{'AtInfo':{}},
2892                'Residue':{'AtInfo':{}},'RBIds':{'Vector':[],'Residue':[]}})
2893               
2894    class CopyDialog(wx.Dialog):
2895        '''Creates a dialog for copying control settings between
2896        data tree items'''
2897        def __init__(self,parent,title,text,data):
2898            wx.Dialog.__init__(self,parent,-1,title, 
2899                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
2900            self.data = data
2901            panel = wx.Panel(self)
2902            mainSizer = wx.BoxSizer(wx.VERTICAL)
2903            topLabl = wx.StaticText(panel,-1,text)
2904            mainSizer.Add((10,10),1)
2905            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
2906            mainSizer.Add((10,10),1)
2907            ncols = len(data)/40+1
2908            dataGridSizer = wx.FlexGridSizer(cols=ncols,hgap=2,vgap=2)
2909            for id,item in enumerate(self.data):
2910                ckbox = wx.CheckBox(panel,id,item[1])
2911                ckbox.Bind(wx.EVT_CHECKBOX,self.OnCopyChange)                   
2912                dataGridSizer.Add(ckbox,0,wx.LEFT,10)
2913            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
2914            OkBtn = wx.Button(panel,-1,"Ok")
2915            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
2916            cancelBtn = wx.Button(panel,-1,"Cancel")
2917            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
2918            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
2919            btnSizer.Add((20,20),1)
2920            btnSizer.Add(OkBtn)
2921            btnSizer.Add((20,20),1)
2922            btnSizer.Add(cancelBtn)
2923            btnSizer.Add((20,20),1)
2924           
2925            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
2926            panel.SetSizer(mainSizer)
2927            panel.Fit()
2928            self.Fit()
2929       
2930        def OnCopyChange(self,event):
2931            id = event.GetId()
2932            self.data[id][0] = self.FindWindowById(id).GetValue()       
2933           
2934        def OnOk(self,event):
2935            parent = self.GetParent()
2936            parent.Raise()
2937            self.EndModal(wx.ID_OK)             
2938           
2939        def OnCancel(self,event):
2940            parent = self.GetParent()
2941            parent.Raise()
2942            self.EndModal(wx.ID_CANCEL)             
2943           
2944        def GetData(self):
2945            return self.data
2946       
2947    class SumDialog(wx.Dialog):
2948        '''Allows user to supply scale factor(s) when summing data -
2949        TODO: CAN WE PREVIEW RESULT HERE?'''
2950        def __init__(self,parent,title,text,dataType,data,dataList):
2951            wx.Dialog.__init__(self,parent,-1,title,size=(400,250),
2952                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
2953            self.plotFrame = wx.Frame(self,-1,'Sum Plots',size=wx.Size(700,600), \
2954                style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
2955            self.G2plotNB = G2plt.G2PlotNoteBook(self.plotFrame,G2frame=self)
2956            self.data = data
2957            self.dataList = dataList
2958            self.dataType = dataType
2959            size = (450,350)
2960            panel = wxscroll.ScrolledPanel(self, wx.ID_ANY,size=size,
2961                style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
2962            mainSizer = wx.BoxSizer(wx.VERTICAL)
2963            topLabl = wx.StaticText(panel,-1,text)
2964            mainSizer.Add((10,10),1)
2965            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
2966            mainSizer.Add((10,10),1)
2967            self.dataGridSizer = wx.FlexGridSizer(cols=2,hgap=2,vgap=2)
2968            for id,item in enumerate(self.data[:-1]):
2969                name = wx.TextCtrl(panel,-1,item[1],size=wx.Size(300,20))
2970                name.SetEditable(False)
2971#        azmthOff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'azmthOff',nDig=(10,2),typeHint=float,OnLeave=OnAzmthOff)
2972                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
2973                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
2974                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
2975                self.dataGridSizer.Add(scale,0,wx.LEFT,10)
2976                self.dataGridSizer.Add(name,0,wx.RIGHT,10)
2977            if self.dataType:
2978                self.dataGridSizer.Add(wx.StaticText(panel,-1,'Sum result name: '+self.dataType),0, \
2979                    wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
2980                self.name = wx.TextCtrl(panel,-1,self.data[-1],size=wx.Size(300,20),style=wx.TE_PROCESS_ENTER)
2981                self.name.Bind(wx.EVT_TEXT_ENTER,self.OnNameChange)
2982                self.name.Bind(wx.EVT_KILL_FOCUS,self.OnNameChange)
2983                self.dataGridSizer.Add(self.name,0,wx.RIGHT|wx.TOP,10)
2984                self.dataGridSizer.Add(wx.StaticText(panel,label='All scales value: '),0,  \
2985                    wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
2986#        azmthOff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'azmthOff',nDig=(10,2),typeHint=float,OnLeave=OnAzmthOff)
2987                allScale = wx.TextCtrl(panel,value='',style=wx.TE_PROCESS_ENTER)
2988                allScale.Bind(wx.EVT_TEXT_ENTER,self.OnAllScale)
2989                allScale.Bind(wx.EVT_KILL_FOCUS,self.OnAllScale)
2990                self.dataGridSizer.Add(allScale,0,WACV)
2991            mainSizer.Add(self.dataGridSizer,0,wx.EXPAND)
2992            OkBtn = wx.Button(panel,-1,"Ok")
2993            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
2994            cancelBtn = wx.Button(panel,-1,"Cancel")
2995            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
2996            btnSizer = wx.FlexGridSizer(0,3,10,20)
2997            if self.dataType =='PWDR':
2998                TestBtn = wx.Button(panel,-1,"Test")
2999                TestBtn.Bind(wx.EVT_BUTTON, self.OnTest)
3000                btnSizer.Add(TestBtn)
3001            btnSizer.Add(OkBtn)
3002            btnSizer.Add(cancelBtn)
3003           
3004            panel.SetSizer(mainSizer)
3005            panel.SetAutoLayout(1)
3006            panel.SetupScrolling()
3007            mainSizer.Add((10,10),1)
3008            mainSizer.Add(btnSizer,0,wx.CENTER)
3009            panel.SetSizer(mainSizer)
3010            panel.Fit()
3011            self.Fit()
3012
3013        def OnScaleChange(self,event):
3014            event.Skip()
3015            id = event.GetId()
3016            value = self.FindWindowById(id).GetValue()
3017            try:
3018                self.data[id][0] = float(value)
3019                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
3020            except ValueError:
3021                if value and '-' not in value[0]:
3022                    print 'bad input - numbers only'
3023                    self.FindWindowById(id).SetValue('0.000')
3024                   
3025        def OnAllScale(self,event):
3026            event.Skip()
3027            id = event.GetId()
3028            try:
3029                scale = float(self.FindWindowById(id).GetValue())
3030                self.FindWindowById(id).SetValue('%.3f'%(scale))
3031                entries = self.dataGridSizer.GetChildren()
3032                for i,item in enumerate(self.data[:-1]):
3033                    item[0] = scale
3034                    entries[2*i].GetWindow().SetValue('%.3f'%(scale))
3035                 
3036            except ValueError:
3037                print 'bad input - numbers only'
3038                self.FindWindowById(id).SetValue('')
3039                   
3040           
3041        def OnNameChange(self,event):
3042            event.Skip()
3043            self.data[-1] = self.name.GetValue()
3044           
3045        def OnTest(self,event):
3046            lenX = 0
3047            Xminmax = [0,0]
3048            XY = []
3049            Xsum = []
3050            Ysum = []
3051            Vsum = []
3052            result = self.data
3053            for i,item in enumerate(result[:-1]):
3054                scale,name = item
3055                data = self.dataList[i]
3056                if scale:
3057                    x,y,w,yc,yb,yd = data   #numpy arrays!
3058                    XY.append([x,scale*y])
3059                    v = 1./w
3060                    if lenX:
3061                        if lenX != len(x):
3062                            self.ErrorDialog('Data length error','Data to be summed must have same number of points'+ \
3063                                '\nExpected:'+str(lenX)+ \
3064                                '\nFound:   '+str(len(x))+'\nfor '+name)
3065                            self.OnCancel(event)
3066                    else:
3067                        lenX = len(x)
3068                    if Xminmax[1]:
3069                        if Xminmax != [x[0],x[-1]]:
3070                            self.ErrorDialog('Data range error','Data to be summed must span same range'+ \
3071                                '\nExpected:'+str(Xminmax[0])+' '+str(Xminmax[1])+ \
3072                                '\nFound:   '+str(x[0])+' '+str(x[-1])+'\nfor '+name)
3073                            self.OnCancel(event)
3074                        else:
3075                            for j,yi in enumerate(y):
3076                                 Ysum[j] += scale*yi
3077                                 Vsum[j] += abs(scale)*v[j]
3078                    else:
3079                        Xminmax = [x[0],x[-1]]
3080                        Xsum = x
3081                        Ysum = scale*y
3082                        Vsum = abs(scale*v)
3083            Wsum = 1./np.array(Vsum)
3084            YCsum = np.zeros(lenX)
3085            YBsum = np.zeros(lenX)
3086            YDsum = np.zeros(lenX)
3087            XY.append([Xsum,Ysum])
3088            self.result = [Xsum,Ysum,Wsum,YCsum,YBsum,YDsum]
3089            # N.B. PlotXY expects the first arg to point to G2frame. In this case, we
3090            # create a duplicate (temporary) Plot notebook window that is a child of the
3091            # modal SumDialog dialog (self). This nicely gets deleted when the dialog is destroyed,
3092            # but the plot window is not fully functional, at least on the Mac.
3093            G2plt.PlotXY(self,XY,lines=True,Title='Sum:'+self.data[-1],labelY='Intensity',)
3094            self.plotFrame.Show()
3095                       
3096        def OnOk(self,event):
3097            if self.dataType == 'PWDR': self.OnTest(event)
3098            parent = self.GetParent()
3099            parent.Raise()
3100            self.EndModal(wx.ID_OK)             
3101           
3102        def OnCancel(self,event):
3103            parent = self.GetParent()
3104            parent.Raise()
3105            self.EndModal(wx.ID_CANCEL)             
3106           
3107        def GetData(self):
3108            if self.dataType == 'PWDR':
3109                return self.data,self.result
3110            else:
3111                return self.data
3112                       
3113    def OnPwdrSum(self,event):
3114        'Sum together powder data(?)'
3115        TextList = []
3116        DataList = []
3117        Names = []
3118        Inst = None
3119        Comments = ['Sum equals: \n']
3120        if self.PatternTree.GetCount():
3121            item, cookie = self.PatternTree.GetFirstChild(self.root)
3122            while item:
3123                name = self.PatternTree.GetItemText(item)
3124                Names.append(name)
3125                if 'PWDR' in name:
3126                    TextList.append([0.0,name])
3127                    DataList.append(self.PatternTree.GetItemPyData(item)[1])    # (x,y,w,yc,yb,yd)
3128                    if not Inst:
3129                        Inst = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item, 'Instrument Parameters'))
3130                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3131            if len(TextList) < 2:
3132                self.ErrorDialog('Not enough data to sum','There must be more than one "PWDR" pattern')
3133                return
3134            TextList.append('default_sum_name')               
3135            dlg = self.SumDialog(self,'Sum data','Enter scale for each pattern in summation','PWDR',TextList,DataList)
3136            try:
3137                if dlg.ShowModal() == wx.ID_OK:
3138                    result,sumData = dlg.GetData()
3139                    Xsum,Ysum,Wsum,YCsum,YBsum,YDsum = sumData
3140                    Xminmax = [Xsum[0],Xsum[-1]]
3141                    outname = 'PWDR '+result[-1]
3142                    Id = 0
3143                    if outname in Names:
3144                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
3145                        try:
3146                            if dlg2.ShowModal() == wx.ID_OK:
3147                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
3148                                self.PatternTree.Delete(Id)
3149                        finally:
3150                            dlg2.Destroy()
3151                    Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
3152                    if Id:
3153                        Sample = G2obj.SetDefaultSample()
3154                        Ymin = np.min(Ysum)
3155                        Ymax = np.max(Ysum)
3156                        valuesdict = {
3157                            'wtFactor':1.0,
3158                            'Dummy':False,
3159                            'ranId':ran.randint(0,sys.maxint),
3160                            'Offset':[0.0,0.0],'delOffset':0.02*Ymax,'refOffset':-.1*Ymax,'refDelt':0.1*Ymax,
3161                            'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
3162                            }
3163                        self.PatternTree.SetItemPyData(Id,[valuesdict,[np.array(Xsum),np.array(Ysum),np.array(Wsum),
3164                            np.array(YCsum),np.array(YBsum),np.array(YDsum)]])
3165                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
3166                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
3167                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',True,3,1.0,0.0,0.0],
3168                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
3169                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
3170                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
3171                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Peak List'),{'peaks':[],'sigDict':{}})
3172                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[[],[]])
3173                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
3174                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
3175                        self.PatternTree.SelectItem(Id)
3176                        self.PatternTree.Expand(Id)
3177            finally:
3178                dlg.Destroy()
3179
3180    def OnImageSum(self,event):
3181        'Sum together image data'
3182        TextList = []
3183        DataList = []
3184        IdList = []
3185        Names = []
3186        Comments = ['Sum equals: \n']
3187        if self.PatternTree.GetCount():
3188            item, cookie = self.PatternTree.GetFirstChild(self.root)
3189            while item:
3190                name = self.PatternTree.GetItemText(item)
3191                Names.append(name)
3192                if 'IMG' in name:
3193                    TextList.append([0.0,name])
3194                    DataList.append(self.PatternTree.GetImageLoc(item))        #Size,Image,Tag
3195                    IdList.append(item)
3196                    Data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item,'Image Controls'))
3197                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3198            if len(TextList) < 2:
3199                self.ErrorDialog('Not enough data to sum','There must be more than one "IMG" pattern')
3200                return
3201            TextList.append('default_sum_name')               
3202            dlg = self.SumDialog(self,'Sum data','Enter scale for each image in summation','IMG',TextList,DataList)
3203            try:
3204                if dlg.ShowModal() == wx.ID_OK:
3205                    imSize = 0
3206                    result = dlg.GetData()
3207                    First = True
3208                    Found = False
3209                    for i,item in enumerate(result[:-1]):
3210                        scale,name = item
3211                        if scale:
3212                            Found = True                               
3213                            Comments.append("%10.3f %s" % (scale,' * '+name))
3214                            Npix,imagefile,imagetag = DataList[i]
3215                            imagefile = G2IO.GetCheckImageFile(self,IdList[i])[1]
3216                            image = G2IO.GetImageData(self,imagefile,imageOnly=True,ImageTag=imagetag)
3217                            if First:
3218                                newImage = np.zeros_like(image)
3219                                First = False
3220                            if imSize:
3221                                if imSize != Npix:
3222                                    self.ErrorDialog('Image size error','Images to be summed must be same size'+ \
3223                                        '\nExpected:'+str(imSize)+ \
3224                                        '\nFound:   '+str(Npix)+'\nfor '+name)
3225                                    return
3226                                newImage = newImage+scale*image
3227                            else:
3228                                imSize = Npix
3229                                newImage = newImage+scale*image
3230                            del(image)
3231                    if not Found:
3232                        self.ErrorDialog('Image sum error','No nonzero image multipliers found')
3233                        return
3234                       
3235                       
3236                    newImage = np.array(newImage,dtype=np.int32)                       
3237                    outname = 'IMG '+result[-1]
3238                    Id = 0
3239                    if outname in Names:
3240                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
3241                        try:
3242                            if dlg2.ShowModal() == wx.ID_OK:
3243                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
3244                        finally:
3245                            dlg2.Destroy()
3246                    else:
3247                        Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
3248                    if Id:
3249                        pth = G2G.GetExportPath(self)
3250                        dlg = wx.FileDialog(self, 'Choose sum image filename', pth,outname.split('IMG ')[1], 
3251                            'G2img files (*.G2img)|*.G2img', 
3252                            wx.SAVE|wx.FD_OVERWRITE_PROMPT)
3253                        if dlg.ShowModal() == wx.ID_OK:
3254                            newimagefile = dlg.GetPath()
3255                            newimagefile = G2IO.FileDlgFixExt(dlg,newimagefile)
3256                            G2IO.PutG2Image(newimagefile,Comments,Data,Npix,newImage)
3257                            Imax = np.amax(newImage)
3258                            Imin = np.amin(newImage)
3259                            newImage = []
3260                            self.PatternTree.SetItemPyData(Id,[imSize,newimagefile])
3261                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
3262                        del(newImage)
3263                        if self.imageDefault:
3264                            Data = copy.copy(self.imageDefault)
3265                        Data['formatName'] = 'GSAS-II image'
3266                        Data['showLines'] = True
3267                        Data['ring'] = []
3268                        Data['rings'] = []
3269                        Data['cutoff'] = 10
3270                        Data['pixLimit'] = 20
3271                        Data['ellipses'] = []
3272                        Data['calibrant'] = ''
3273                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
3274                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)                                           
3275                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
3276                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
3277                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),
3278                            {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
3279                        self.PatternTree.SelectItem(Id)
3280                        self.PatternTree.Expand(Id)
3281                        self.PickId = G2gd.GetPatternTreeItemId(self,self.root,outname)
3282                        self.Image = self.PickId
3283            finally:
3284                dlg.Destroy()
3285                     
3286    def OnAddPhase(self,event):
3287        'Add a new, empty phase to the tree. Called by Data/Add Phase menu'
3288        if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3289            sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
3290        else:
3291            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3292        PhaseName = ''
3293        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
3294            style=wx.OK)
3295        if dlg.ShowModal() == wx.ID_OK:
3296            PhaseName = dlg.GetValue()
3297        dlg.Destroy()
3298        sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
3299        E,SGData = G2spc.SpcGroup('P 1')
3300        self.PatternTree.SetItemPyData(sub,G2obj.SetNewPhase(Name=PhaseName,SGData=SGData))
3301        G2gd.SelectDataTreeItem(self,sub) #bring up new phase General tab
3302       
3303    def OnDeletePhase(self,event):
3304        'Delete a phase from the tree. Called by Data/Delete Phase menu'
3305        #Hmm, also need to delete this phase from Reflection Lists for each PWDR histogram
3306        if self.dataFrame:
3307            self.dataFrame.Clear() 
3308        TextList = []
3309        DelList = []
3310        DelItemList = []
3311        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3312            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3313        else:
3314            return
3315        if sub:
3316            item, cookie = self.PatternTree.GetFirstChild(sub)
3317            while item:
3318                TextList.append(self.PatternTree.GetItemText(item))
3319                item, cookie = self.PatternTree.GetNextChild(sub, cookie)               
3320            dlg = wx.MultiChoiceDialog(self, 'Which phase to delete?', 'Delete phase', TextList, wx.CHOICEDLG_STYLE)
3321            try:
3322                if dlg.ShowModal() == wx.ID_OK:
3323                    result = dlg.GetSelections()
3324                    for i in result: DelList.append([i,TextList[i]])
3325                    item, cookie = self.PatternTree.GetFirstChild(sub)
3326                    i = 0
3327                    while item:
3328                        if [i,self.PatternTree.GetItemText(item)] in DelList: DelItemList.append(item)
3329                        item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3330                        i += 1
3331                    for item in DelItemList:
3332                        name = self.PatternTree.GetItemText(item)
3333                        self.PatternTree.Delete(item)
3334                        self.G2plotNB.Delete(name)
3335                    item, cookie = self.PatternTree.GetFirstChild(self.root)
3336                    while item:
3337                        name = self.PatternTree.GetItemText(item)
3338                        if 'PWDR' in name:
3339                            Id = G2gd.GetPatternTreeItemId(self,item, 'Reflection Lists')
3340                            refList = self.PatternTree.GetItemPyData(Id)
3341                            if len(refList):
3342                                for i,item in DelList:
3343                                    if item in refList:
3344                                        del(refList[item])
3345#                            self.PatternTree.SetItemPyData(Id,refList)
3346                        elif 'HKLF' in name:
3347                            data = self.PatternTree.GetItemPyData(item)
3348                            data[0] = {}
3349#                            self.PatternTree.SetItemPyData(item,data)
3350                           
3351                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3352            finally:
3353                dlg.Destroy()
3354               
3355    def OnRenameData(self,event):
3356        'Renames an existing phase. Called by Data/Rename Phase menu'
3357        name = self.PatternTree.GetItemText(self.PickId)     
3358        if 'PWDR' in name or 'HKLF' in name or 'IMG' in name:
3359            if 'Bank' in name:
3360                names = name.split('Bank')
3361                names[1] = ' Bank'+names[1]
3362            elif 'Azm' in name:
3363                names = name.split('Azm')
3364                names[1] = ' Azm'+names[1]
3365            else:
3366                names = [name,'']
3367            dataType = names[0][:names[0].index(' ')+1]                 #includes the ' '
3368            dlg = wx.TextEntryDialog(self,'Data name: '+name,'Change data name',
3369                defaultValue=names[0][names[0].index(' ')+1:])
3370            try:
3371                if dlg.ShowModal() == wx.ID_OK:
3372                    name = dataType+dlg.GetValue()+names[1]
3373                    self.PatternTree.SetItemText(self.PickId,name)
3374            finally:
3375                dlg.Destroy()
3376       
3377    def GetFileList(self,fileType,skip=None):        #potentially useful?
3378        'Appears unused. Note routine of same name in GSASIIpwdGUI'
3379        fileList = []
3380        Source = ''
3381        id, cookie = self.PatternTree.GetFirstChild(self.root)
3382        while id:
3383            name = self.PatternTree.GetItemText(id)
3384            if fileType in name:
3385                if id == skip:
3386                    Source = name
3387                else:
3388                    fileList.append([False,name,id])
3389            id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3390        if skip:
3391            return fileList,Source
3392        else:
3393            return fileList
3394           
3395    def OnDataDelete(self, event):
3396        '''Delete one or more histograms from data tree. Called by the
3397        Data/DeleteData menu
3398        '''
3399        TextList = []
3400        DelList = []
3401        DelItemList = []
3402        nItems = {'PWDR':0,'SASD':0,'REFD':0,'IMG':0,'HKLF':0,'PDF':0}
3403        PDFnames = []
3404        if self.PatternTree.GetCount():
3405            item, cookie = self.PatternTree.GetFirstChild(self.root)
3406            while item:
3407                name = self.PatternTree.GetItemText(item)
3408                if name not in ['Notebook','Controls','Covariance','Constraints',
3409                    'Restraints','Phases','Rigid bodies'] and 'Sequential' not in name:
3410                    if 'PWDR' in name[:4]: nItems['PWDR'] += 1
3411                    if 'SASD' in name[:4]: nItems['SASD'] += 1
3412                    if 'REFD' in name[:4]: nItems['REFD'] += 1
3413                    if 'IMG' in name[:3]:  nItems['IMG'] += 1
3414                    if 'HKLF' in name[:4]: nItems['HKLF'] += 1
3415                    if 'PDF' in name[:3]:
3416                        PDFnames.append(name)
3417                        nItems['PDF'] += 1
3418                    TextList.append(name)
3419                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3420            for pdfName in PDFnames:
3421                try:
3422                    TextList.remove('PWDR'+pdfName[4:])
3423                except ValueError:
3424                    print 'PWDR'+pdfName[4:]+' for '+pdfName+' not found'
3425            dlg = G2G.G2MultiChoiceDialog(self, 'Which data to delete?', 'Delete data', TextList, wx.CHOICEDLG_STYLE)
3426            try:
3427                if dlg.ShowModal() == wx.ID_OK:
3428                    result = dlg.GetSelections()
3429                    for i in result: DelList.append(TextList[i])
3430                    item, cookie = self.PatternTree.GetFirstChild(self.root)
3431                    while item:
3432                        itemName = self.PatternTree.GetItemText(item)
3433                        if itemName in DelList:
3434                            if 'PWDR' in itemName[:4]: nItems['PWDR'] -= 1
3435                            elif 'SASD' in itemName[:4]: nItems['SASD'] -= 1
3436                            elif 'REFD' in itemName[:4]: nItems['REFD'] -= 1
3437                            elif 'IMG' in itemName[:3]: nItems['IMG'] -= 1
3438                            elif 'HKLF' in itemName[:4]: nItems['HKLF'] -= 1
3439                            elif 'PDF' in itemName[:3]: nItems['PDF'] -= 1
3440                            DelItemList.append(item)
3441                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3442                    for item in DelItemList:
3443                        self.PatternTree.Delete(item)
3444                    self.PickId = 0
3445                    self.PickIdText = None
3446                    self.PatternId = 0
3447                    if nItems['PWDR']:
3448                        wx.CallAfter(G2plt.PlotPatterns,self,True)
3449                    else:
3450                        self.G2plotNB.Delete('Powder Patterns')
3451                    if not nItems['IMG']:
3452                        self.G2plotNB.Delete('2D Powder Image')
3453                    if not nItems['HKLF']:
3454                        self.G2plotNB.Delete('Structure Factors')
3455                        if '3D Structure Factors' in self.G2plotNB.plotList:
3456                            self.G2plotNB.Delete('3D Structure Factors')
3457            finally:
3458                dlg.Destroy()
3459
3460    def OnFileOpen(self, event, filename=None):
3461        '''Gets a GSAS-II .gpx project file in response to the
3462        File/Open Project menu button
3463        '''
3464        result = wx.ID_OK
3465        self.EnablePlot = False
3466        if self.PatternTree.GetChildrenCount(self.root,False):
3467            if self.dataFrame:
3468                self.dataFrame.ClearData() 
3469            dlg = wx.MessageDialog(
3470                self,
3471                'Do you want to overwrite the current project? '+
3472                'Any unsaved changes in current project will be lost. Press OK to continue.',
3473                'Overwrite?',  wx.OK | wx.CANCEL)
3474            try:
3475                result = dlg.ShowModal()
3476                if result == wx.ID_OK:
3477                    self.PatternTree.DeleteChildren(self.root)
3478                    self.GSASprojectfile = ''
3479                    self.HKL = []
3480                    if self.G2plotNB.plotList:
3481                        self.G2plotNB.clear()
3482            finally:
3483                dlg.Destroy()
3484        if result != wx.ID_OK: return
3485
3486        if not filename:
3487            if self.LastGPXdir:
3488                pth = self.LastGPXdir
3489            else:
3490                pth = '.'
3491            dlg = wx.FileDialog(self, 'Choose GSAS-II project file', pth, 
3492                wildcard='GSAS-II project file (*.gpx)|*.gpx',style=wx.OPEN)
3493            try:
3494                if dlg.ShowModal() != wx.ID_OK: return
3495                self.GSASprojectfile = dlg.GetPath()
3496                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
3497                self.dirname = dlg.GetDirectory()
3498            finally:
3499                dlg.Destroy()
3500        else:
3501            self.GSASprojectfile = os.path.splitext(filename)[0]+'.gpx'
3502            self.dirname = os.path.split(filename)[0]
3503
3504        try:
3505            self.StartProject()         #open the file if possible
3506        except:
3507            print '\nError opening file ',filename
3508            import traceback
3509            print traceback.format_exc()
3510       
3511    def StartProject(self):
3512        '''Opens a GSAS-II project file & selects the 1st available data set to
3513        display (PWDR, HKLF, REFD or SASD)
3514        '''
3515       
3516        Id = 0
3517        phaseId = None
3518        G2IO.ProjFileOpen(self)
3519        self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
3520        self.PatternTree.Expand(self.root)
3521        self.HKL = []
3522        item, cookie = self.PatternTree.GetFirstChild(self.root)
3523        while item and not Id:
3524            name = self.PatternTree.GetItemText(item)
3525            if name[:4] in ['PWDR','HKLF','IMG ','PDF ','SASD','REFD']:
3526                Id = item
3527            elif name == "Phases":
3528                phaseId = item
3529            elif name == 'Controls':
3530                data = self.PatternTree.GetItemPyData(item)
3531                if data:
3532                    for item in self.Refine: item.Enable(True)
3533                    self.EnableSeqRefineMenu()
3534            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3535        if phaseId: # show all phases
3536            self.PatternTree.Expand(phaseId)
3537        if Id:
3538            self.EnablePlot = True
3539            self.PatternTree.SelectItem(Id)
3540            self.PatternTree.Expand(Id)
3541        elif phaseId:
3542            self.PatternTree.SelectItem(phaseId)
3543        self.CheckNotebook()
3544        if self.dirname: os.chdir(self.dirname)           # to get Mac/Linux to change directory!
3545        pth = os.path.split(os.path.abspath(self.GSASprojectfile))[0]
3546        if GSASIIpath.GetConfigValue('Save_paths'): G2G.SaveGPXdirectory(pth)
3547        self.LastGPXdir = pth
3548
3549    def OnFileClose(self, event):
3550        '''Clears the data tree in response to the
3551        File/New Project menu button. User is given option to save
3552        the project.
3553        '''
3554#        dlg = wx.MessageDialog(self, 'Save current project?', ' ', wx.YES | wx.NO | wx.CANCEL)
3555        try:
3556            result = dlg.ShowModal()
3557            if result == wx.ID_OK:
3558                self.OnFileSaveMenu(event)
3559            if result != wx.ID_CANCEL:
3560                self.GSASprojectfile = ''
3561                self.PatternTree.SetItemText(self.root,'Loaded Data: ')
3562                self.PatternTree.DeleteChildren(self.root)
3563                if self.HKL: self.HKL = []
3564                if self.G2plotNB.plotList:
3565                    self.G2plotNB.clear()
3566        finally:
3567            dlg.Destroy()
3568
3569    def OnFileSave(self, event):
3570        '''Save the current project in response to the
3571        File/Save Project menu button
3572        '''
3573       
3574        if self.GSASprojectfile: 
3575            self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
3576            self.CheckNotebook()
3577            G2IO.ProjFileSave(self)
3578        else:
3579            self.OnFileSaveas(event)
3580
3581    def OnFileSaveas(self, event):
3582        '''Save the current project in response to the
3583        File/Save as menu button
3584        '''
3585        if GSASIIpath.GetConfigValue('Starting_directory'):
3586            pth = GSASIIpath.GetConfigValue('Starting_directory')
3587            pth = os.path.expanduser(pth) 
3588        elif self.LastGPXdir:
3589            pth = self.LastGPXdir
3590        else:
3591            pth = '.'
3592        dlg = wx.FileDialog(self, 'Choose GSAS-II project file name', pth, '', 
3593            'GSAS-II project file (*.gpx)|*.gpx',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
3594        try:
3595            if dlg.ShowModal() == wx.ID_OK:
3596                self.GSASprojectfile = dlg.GetPath()
3597                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
3598                self.PatternTree.SetItemText(self.root,'Saving project as'+self.GSASprojectfile)
3599                self.SetTitle("GSAS-II data tree: "+os.path.split(self.GSASprojectfile)[1])
3600                self.CheckNotebook()
3601                G2IO.ProjFileSave(self)
3602                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
3603        finally:
3604            dlg.Destroy()
3605           
3606    def ExpandAll(self,event):
3607        '''Expand all tree items or those of a single type
3608        '''
3609        txt = self.GetMenuBar().GetLabel(event.Id)
3610        if txt == 'all':
3611            self.ExpandingAll = True
3612            try:
3613                self.PatternTree.ExpandAll()
3614            finally:
3615                self.ExpandingAll = False
3616        else:
3617            self.ExpandingAll = True
3618            try:
3619                item, cookie = self.PatternTree.GetFirstChild(self.root)
3620                while item:
3621                    name = self.PatternTree.GetItemText(item)
3622                    if name.startswith(txt+' '): self.PatternTree.Expand(item)
3623                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3624            finally:
3625                self.ExpandingAll = False
3626
3627    def MoveTreeItems(self,event):
3628        '''Move tree items of a single type to the end of the tree
3629        '''
3630        txt = self.GetMenuBar().GetLabel(event.Id)
3631        # make a list of items to copy
3632        copyList = []
3633        item, cookie = self.PatternTree.GetFirstChild(self.root)
3634        while item:
3635            if self.PatternTree.GetItemText(item).startswith(txt+' '):
3636                copyList.append(item)
3637            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3638       
3639        self.ExpandingAll = True
3640        try:
3641            for item in copyList:
3642                name = self.PatternTree.GetItemText(item)
3643                newId = self.PatternTree.AppendItem(self.root,name)
3644                self.PatternTree.SetItemPyData(newId,self.PatternTree.GetItemPyData(item))
3645                chld, chldcookie = self.PatternTree.GetFirstChild(item)
3646                while chld:
3647                    chname = self.PatternTree.GetItemText(chld)
3648                    newCh = self.PatternTree.AppendItem(newId,chname)
3649                    self.PatternTree.SetItemPyData(newCh,self.PatternTree.GetItemPyData(chld))
3650                    chld, chldcookie = self.PatternTree.GetNextChild(item, chldcookie)
3651                self.PatternTree.Delete(item)
3652        finally:
3653            self.ExpandingAll = False
3654        G2gd.SelectDataTreeItem(self,self.root)
3655           
3656    def ExitMain(self, event):
3657        '''Called if the main window is closed'''
3658        if self.G2plotNB:
3659            self.G2plotNB.Destroy()
3660        if self.dataFrame:
3661            self.dataFrame.Destroy()
3662        if self.undofile:
3663            os.remove(self.undofile)
3664        sys.exit()
3665       
3666    def OnFileExit(self, event):
3667        '''Called in response to the File/Quit menu button'''
3668        if self.G2plotNB:
3669            self.G2plotNB.Destroy()
3670        if self.dataFrame:
3671            self.dataFrame.Destroy()
3672        self.Close()
3673       
3674    def OnExportPeakList(self,event):
3675        nptand = lambda x: np.tan(x*math.pi/180.)
3676        pth = G2G.GetExportPath(self)
3677        dlg = wx.FileDialog(self, 'Choose output peak list file name', pth, '', 
3678            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
3679        try:
3680            if dlg.ShowModal() == wx.ID_OK:
3681                self.peaklistfile = dlg.GetPath()
3682                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
3683                file = open(self.peaklistfile,'w')               
3684                item, cookie = self.PatternTree.GetFirstChild(self.root)
3685                while item:
3686                    name = self.PatternTree.GetItemText(item)
3687                    if 'PWDR' in name:
3688                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
3689                        wave = 0.0
3690                        while item2:
3691                            name2 = self.PatternTree.GetItemText(item2)
3692                            if name2 == 'Instrument Parameters':
3693                                Inst = self.PatternTree.GetItemPyData(item2)[0]
3694                                Type = Inst['Type'][0]
3695                                if 'T' not in Type:
3696                                    wave = G2mth.getWave(Inst)
3697                            elif name2 == 'Peak List':
3698                                pkdata = self.PatternTree.GetItemPyData(item2)
3699                                peaks = pkdata['peaks']
3700                                sigDict = pkdata['sigDict']
3701                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
3702                        file.write("#%s \n" % (name+' Peak List'))
3703                        if wave:
3704                            file.write('#wavelength = %10.6f\n'%(wave))
3705                        if 'T' in Type:
3706                            file.write('#%9s %10s %10s %12s %10s %10s %10s %10s %10s\n'%('pos','dsp','esd','int','alp','bet','sig','gam','FWHM'))                                   
3707                        else:
3708                            file.write('#%9s %10s %10s %12s %10s %10s %10s\n'%('pos','dsp','esd','int','sig','gam','FWHM'))
3709                        for ip,peak in enumerate(peaks):
3710                            dsp = G2lat.Pos2dsp(Inst,peak[0])
3711                            if 'T' in Type:  #TOF - more cols
3712                                esds = {'pos':0.,'int':0.,'alp':0.,'bet':0.,'sig':0.,'gam':0.}
3713                                for name in esds.keys():
3714                                    esds[name] = sigDict.get('%s%d'%(name,ip),0.)
3715                                sig = np.sqrt(peak[8])
3716                                gam = peak[10]
3717                                esddsp = G2lat.Pos2dsp(Inst,esds['pos'])
3718                                FWHM = G2pwd.getgamFW(gam,sig)      #to get delta-TOF from Gam(peak)
3719                                file.write("%10.2f %10.5f %10.5f %12.2f %10.3f %10.3f %10.3f %10.3f %10.3f\n" % \
3720                                    (peak[0],dsp,esddsp,peak[2],np.sqrt(max(0.0001,peak[4])),peak[6],peak[8],peak[10],FWHM))
3721                            else:               #CW
3722                                #get esds from sigDict for each peak & put in output - esds for sig & gam from UVWXY?
3723                                esds = {'pos':0.,'int':0.,'sig':0.,'gam':0.}
3724                                for name in esds.keys():
3725                                    esds[name] = sigDict.get('%s%d'%(name,ip),0.)
3726                                sig = np.sqrt(peak[4]) #var -> sig
3727                                gam = peak[6]
3728                                esddsp = 0.5*esds['pos']*dsp/nptand(peak[0]/2.)
3729                                FWHM = G2pwd.getgamFW(gam,sig)      #to get delta-2-theta in deg. from Gam(peak)
3730                                file.write("%10.4f %10.5f %10.5f %12.2f %10.5f %10.5f %10.5f \n" % \
3731                                    (peak[0],dsp,esddsp,peak[2],np.sqrt(max(0.0001,peak[4]))/100.,peak[6]/100.,FWHM/100.)) #convert to deg
3732                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
3733                file.close()
3734        finally:
3735            dlg.Destroy()
3736       
3737    def OnExportHKL(self,event):
3738        pth = G2G.GetExportPath(self)
3739        dlg = wx.FileDialog(self, 'Choose output reflection list file name', pth, '', 
3740            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
3741        try:
3742            if dlg.ShowModal() == wx.ID_OK:
3743                self.peaklistfile = dlg.GetPath()
3744                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
3745                file = open(self.peaklistfile,'w')               
3746                item, cookie = self.PatternTree.GetFirstChild(self.root)
3747                while item:
3748                    name = self.PatternTree.GetItemText(item)
3749                    if 'PWDR' in name:
3750                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
3751                        while item2:
3752                            name2 = self.PatternTree.GetItemText(item2)
3753                            if name2 == 'Reflection Lists':
3754                                data = self.PatternTree.GetItemPyData(item2)
3755                                phases = data.keys()
3756                                for phase in phases:
3757                                    peaks = data[phase]
3758                                    I100 = peaks['RefList'].T[8]*np.array([refl[11] for refl in peaks['RefList']])
3759                                    Imax = np.max(I100)
3760                                    if Imax:
3761                                        I100 *= 100.0/Imax
3762                                    file.write("%s %s %s \n" % (name,phase,' Reflection List'))
3763                                    if 'T' in peaks.get('Type','PXC'):
3764                                        file.write('%s \n'%('   h   k   l   m   d-space       TOF       wid     Fo**2     Fc**2     Icorr      Prfo     Trans      ExtP      I100'))
3765                                    else:               
3766                                        file.write('%s \n'%('   h   k   l   m   d-space   2-theta       wid     Fo**2     Fc**2     Icorr      Prfo     Trans      ExtP      I100'))
3767                                    for ipk,peak in enumerate(peaks['RefList']):
3768                                        if 'T' in peaks.get('Type','PXC'):
3769                                            sig = np.sqrt(peak[6])
3770                                            gam = peak[7]
3771                                            FWHM = G2pwd.getgamFW(gam,sig)
3772                                            file.write(" %3d %3d %3d %3d%10.5f%10.2f%10.5f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" % \
3773                                                (int(peak[0]),int(peak[1]),int(peak[2]),int(peak[3]),peak[4],peak[5],FWHM,peak[8],
3774                                                peak[9],peak[11],peak[12],peak[13],peak[14],I100[ipk]))
3775                                        else:
3776                                            sig = np.sqrt(peak[6])
3777                                            gam = peak[7]
3778                                            FWHM = G2pwd.getgamFW(gam,sig)
3779                                            file.write(" %3d %3d %3d %3d%10.5f%10.5f%10.5f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" % \
3780                                                (int(peak[0]),int(peak[1]),int(peak[2]),int(peak[3]),peak[4],peak[5],FWHM/100.,
3781                                                peak[8],peak[9],peak[11],peak[12],peak[13],peak[14],I100[ipk]))
3782                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
3783                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
3784                file.close()
3785        finally:
3786            dlg.Destroy()
3787       
3788    def OnExportPDF(self,event):
3789        #need S(Q) and G(R) to be saved here - probably best from selection?
3790        names = G2pdG.GetFileList(self,'PDF')
3791        exports = []
3792        if names:
3793            od = {'label_1':'Export I(Q)','value_1':False,'label_2':'Export S(Q)','value_2':False,
3794                  'label_3':'Export F(Q)','value_3':False,'label_4':'Export G(R)','value_4':True,
3795                  'label_5':'Make G(R) for pdfGUI','value_5':False}
3796            dlg = G2G.G2MultiChoiceDialog(self,'Select','PDF patterns to export',names,extraOpts=od)
3797            if dlg.ShowModal() == wx.ID_OK:
3798                sel = dlg.GetSelections()
3799                for x in sel:
3800                    exports.append(names[x])
3801            dlg.Destroy()
3802        if exports:
3803            PDFsaves = [od['value_1'],od['value_2'],od['value_3'],od['value_4'],od['value_5']]
3804            G2IO.PDFSave(self,exports,PDFsaves)
3805       
3806    def OnMakePDFs(self,event):
3807        '''Sets up PDF data structure filled with defaults; if found chemical formula is inserted
3808        so a default PDF can be made.
3809        '''
3810        sind = lambda x: math.sin(x*math.pi/180.)
3811        tth2q = lambda t,w:4.0*math.pi*sind(t/2.0)/w
3812        tof2q = lambda t,C:2.0*math.pi*C/t
3813        TextList = []
3814        ElLists = []
3815        Qlimits = []
3816        Names = []
3817        if self.PatternTree.GetCount():
3818            id, cookie = self.PatternTree.GetFirstChild(self.root)
3819            while id:
3820                name = self.PatternTree.GetItemText(id)
3821                Names.append(name)
3822                if 'PWDR' in name:
3823                    TextList.append(name)
3824                    Data = self.PatternTree.GetItemPyData(id)[1]
3825                    pwdrMin = np.min(Data[1])
3826                    Comments = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,id,'Comments'))
3827                    Parms = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,id,'Instrument Parameters'))[0]
3828                    fullLimits = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,id,'Limits'))[0]
3829                    if 'C' in Parms['Type'][0]:
3830                        wave = G2mth.getWave(Parms)
3831                        qMax = tth2q(fullLimits[1],wave)
3832                    else:   #'T'of
3833                        qMax = tof2q(fullLimits[0],Parms['difC'][1])
3834                    Qlimits.append([0.9*qMax,qMax])
3835                    ElList = {}
3836                    sumnum = 1.
3837                    for item in Comments:           #grab chemical formula from Comments
3838                        if 'formula' in item[:15].lower():
3839                            formula = item.split('=')[1].split()
3840                            try:
3841                                elems = formula[::2]
3842                                nums = formula[1::2]
3843                                Formula = zip(elems,nums)
3844                                sumnum = 0.
3845                                for [elem,num] in Formula:
3846                                    ElData = G2elem.GetElInfo(elem,Parms)
3847                                    ElData['FormulaNo'] = float(num)
3848                                    sumnum += float(num)
3849                                    ElList[elem] = ElData
3850                               
3851                            except ValueError:
3852                                ElData = G2elem.GetElInfo(formula[0],Parms)
3853                                ElData['FormulaNo'] = 1.0
3854                                ElList[elem] = ElData
3855                    ElLists.append(ElList)
3856                id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3857            if len(TextList) < 1:
3858                self.ErrorDialog('Nothing to make PDFs for','There must be at least one "PWDR" pattern')
3859                return
3860            dlg = G2G.G2MultiChoiceDialog(self,'Make PDF controls','Make PDF controls for:',TextList, wx.CHOICEDLG_STYLE)
3861            try:
3862                if dlg.ShowModal() == wx.ID_OK:
3863                    for i in dlg.GetSelections():
3864                        PDFnames = G2gd.GetPatternTreeDataNames(self,['PDF ',])
3865                        G2obj.CreatePDFitems(self,TextList[i],ElLists[i],Qlimits[i],sumnum,pwdrMin,PDFnames)
3866                for item in self.ExportPDF: item.Enable(True)
3867            finally:
3868                dlg.Destroy()
3869               
3870    def GetPWDRdatafromTree(self,PWDRname):
3871        ''' Returns powder data from GSASII tree
3872
3873        :param str PWDRname: a powder histogram name as obtained from
3874          :meth:`GSASIIstruct.GetHistogramNames`
3875
3876        :returns: PWDRdata = powder data dictionary with
3877          Powder data arrays, Limits, Instrument Parameters,
3878          Sample Parameters           
3879        '''
3880        PWDRdata = {}
3881        try:
3882            PWDRdata.update(self.PatternTree.GetItemPyData(PWDRname)[0])            #wtFactor + ?
3883        except ValueError:
3884            PWDRdata['wtFactor'] = 1.0
3885        PWDRdata['Data'] = self.PatternTree.GetItemPyData(PWDRname)[1]          #powder data arrays
3886        PWDRdata['Limits'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Limits'))
3887        PWDRdata['Background'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Background'))
3888        PWDRdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Instrument Parameters'))
3889        PWDRdata['Sample Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Sample Parameters'))
3890        PWDRdata['Reflection Lists'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Reflection Lists'))
3891        if 'ranId' not in PWDRdata:  # patch, add a random Id
3892            PWDRdata['ranId'] = ran.randint(0,sys.maxint)
3893        if 'ranId' not in PWDRdata['Sample Parameters']:  # I hope this becomes obsolete at some point
3894            PWDRdata['Sample Parameters']['ranId'] = PWDRdata['ranId']
3895        return PWDRdata
3896
3897    def GetHKLFdatafromTree(self,HKLFname):
3898        ''' Returns single crystal data from GSASII tree
3899
3900        :param str HKLFname: a single crystal histogram name as obtained
3901          from
3902          :meth:`GSASIIstruct.GetHistogramNames`
3903
3904        :returns: HKLFdata = single crystal data list of reflections
3905
3906        '''
3907        HKLFdata = {}
3908        HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
3909#        try:
3910#            HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
3911#        except ValueError:
3912#            HKLFdata['wtFactor'] = 1.0
3913        HKLFdata['Data'] = self.PatternTree.GetItemPyData(HKLFname)[1]
3914        HKLFdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,HKLFname,'Instrument Parameters'))
3915        return HKLFdata
3916       
3917    def GetPhaseData(self):
3918        '''Returns a dict with defined phases.
3919        Note routine :func:`GSASIIstrIO.GetPhaseData` also exists to
3920        get same info from GPX file.
3921        '''
3922        phaseData = {}
3923        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3924            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3925        else:
3926            print 'no phases found in GetPhaseData'
3927            sub = None
3928        if sub:
3929            item, cookie = self.PatternTree.GetFirstChild(sub)
3930            while item:
3931                phaseName = self.PatternTree.GetItemText(item)
3932                phaseData[phaseName] =  self.PatternTree.GetItemPyData(item)
3933                if 'ranId' not in phaseData[phaseName]:
3934                    phaseData[phaseName]['ranId'] = ran.randint(0,sys.maxint)         
3935                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3936        return phaseData
3937
3938    def GetPhaseInfofromTree(self):
3939        '''Get the phase names and their rId values,
3940        also the histograms used in each phase.
3941
3942        :returns: (phaseRIdList, usedHistograms) where
3943
3944          * phaseRIdList is a list of random Id values for each phase
3945          * usedHistograms is a dict where the keys are the phase names
3946            and the values for each key are a list of the histogram names
3947            used in each phase.
3948        '''
3949        phaseRIdList = []
3950        usedHistograms = {}
3951        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3952        if sub:
3953            item, cookie = self.PatternTree.GetFirstChild(sub)
3954            while item:
3955                phaseName = self.PatternTree.GetItemText(item)
3956                ranId = self.PatternTree.GetItemPyData(item).get('ranId')
3957                if ranId: phaseRIdList.append(ranId)
3958                data = self.PatternTree.GetItemPyData(item)
3959                UseList = data['Histograms']
3960                usedHistograms[phaseName] = UseList.keys()
3961                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3962        return phaseRIdList,usedHistograms
3963
3964    def GetPhaseNames(self):
3965        '''Returns a list of defined phases.
3966        Note routine :func:`GSASIIstrIO.GetPhaseNames` also exists to
3967        get same info from GPX file.
3968        '''
3969        phaseNames = []
3970        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3971            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3972        else:
3973            print 'no phases found in GetPhaseNames'
3974            sub = None
3975        if sub:
3976            item, cookie = self.PatternTree.GetFirstChild(sub)
3977            while item:
3978                phase = self.PatternTree.GetItemText(item)
3979                phaseNames.append(phase)
3980                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3981        return phaseNames
3982   
3983    def GetHistogramNames(self,hType):
3984        """ Returns a list of histogram names found in the GSASII data tree
3985        Note routine :func:`GSASIIstrIO.GetHistogramNames` also exists to
3986        get same info from GPX file.
3987       
3988        :param str hType: list of histogram types
3989        :return: list of histogram names
3990       
3991        """
3992        HistogramNames = []
3993        if self.PatternTree.GetCount():
3994            item, cookie = self.PatternTree.GetFirstChild(self.root)
3995            while item:
3996                name = self.PatternTree.GetItemText(item)
3997                if name[:4] in hType:
3998                    HistogramNames.append(name)       
3999                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
4000
4001        return HistogramNames
4002                   
4003    def GetUsedHistogramsAndPhasesfromTree(self):
4004        ''' Returns all histograms that are found in any phase
4005        and any phase that uses a histogram.
4006        This also assigns numbers to used phases and histograms by the
4007        order they appear in the file.
4008        Note routine :func:`GSASIIstrIO.GetUsedHistogramsAndPhasesfromTree` also exists to
4009        get same info from GPX file.
4010
4011        :returns: (Histograms,Phases)
4012
4013            * Histograms = dictionary of histograms as {name:data,...}
4014            * Phases = dictionary of phases that use histograms
4015        '''
4016        Histograms = {}
4017        Phases = {}
4018        phaseNames = self.GetPhaseNames()
4019        phaseData = self.GetPhaseData()
4020        histoList = self.GetHistogramNames(['PWDR','HKLF'])
4021
4022        for phase in phaseData:
4023            Phase = phaseData[phase]
4024            pId = phaseNames.index(phase)
4025            Phase['pId'] = pId
4026            if Phase['Histograms']:
4027                if phase not in Phases:
4028                    Phases[phase] = Phase
4029                for hist in Phase['Histograms']:
4030                    if 'Use' not in Phase['Histograms'][hist]:      #patch: add Use flag as True
4031                        Phase['Histograms'][hist]['Use'] = True         
4032                    if hist not in Histograms and Phase['Histograms'][hist]['Use']:
4033                        item = G2gd.GetPatternTreeItemId(self,self.root,hist)
4034                        if item:
4035                            if 'PWDR' in hist[:4]: 
4036                                Histograms[hist] = self.GetPWDRdatafromTree(item)
4037                            elif 'HKLF' in hist[:4]:
4038                                Histograms[hist] = self.GetHKLFdatafromTree(item)
4039                            hId = histoList.index(hist)
4040                            Histograms[hist]['hId'] = hId
4041                        else: # would happen if a referenced histogram were renamed or deleted
4042                            print('For phase "'+phase+
4043                                  '" unresolved reference to histogram "'+hist+'"')
4044        #G2obj.IndexAllIds(Histograms=Histograms,Phases=Phases)
4045        G2obj.IndexAllIds(Histograms=Histograms,Phases=phaseData)
4046        return Histograms,Phases
4047       
4048    def MakeLSParmDict(self):
4049        '''Load all parameters used for computation from the tree into a
4050        dict of paired values [value, refine flag]. Note that this is
4051        different than the parmDict used in the refinement, which only has
4052        values.
4053
4054        Note that similar things are done in
4055        :meth:`GSASIIIO.ExportBaseclass.loadParmDict` (from the tree) and
4056        :func:`GSASIIstrMain.Refine` and :func:`GSASIIstrMain.SeqRefine` (from
4057        a GPX file).
4058
4059        :returns: (parmDict,varyList) where:
4060
4061         * parmDict is a dict with values and refinement flags
4062           for each parameter and
4063         * varyList is a list of variables (refined parameters).
4064        '''
4065        parmDict = {}
4066        Histograms,Phases = self.GetUsedHistogramsAndPhasesfromTree()
4067        for phase in Phases:
4068            if 'pId' not in Phases[phase]:
4069                self.ErrorDialog('View parameter error','You must run least squares at least once')
4070                raise Exception,'No pId for phase '+phase
4071        rigidbodyDict = self.PatternTree.GetItemPyData(   
4072            G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'))
4073        rbVary,rbDict = G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
4074        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
4075        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable,MFtable,maxSSwave = G2stIO.GetPhaseData(Phases,RestraintDict=None,rbIds=rbIds,Print=False)       
4076        hapVary,hapDict,controlDict = G2stIO.GetHistogramPhaseData(Phases,Histograms,Print=False)
4077        histVary,histDict,controlDict = G2stIO.GetHistogramData(Histograms,Print=False)
4078        varyList = rbVary+phaseVary+hapVary+histVary
4079        parmDict.update(rbDict)
4080        parmDict.update(phaseDict)
4081        parmDict.update(hapDict)
4082        parmDict.update(histDict)
4083        for parm in parmDict:
4084            if parm.split(':')[-1] in ['Azimuth','Gonio. radius','Lam1','Lam2',
4085                'Omega','Chi','Phi','nDebye','nPeaks']:
4086                parmDict[parm] = [parmDict[parm],'-']
4087            elif parm.split(':')[-2] in ['Ax','Ay','Az','SHmodel','SHord']:
4088                parmDict[parm] = [parmDict[parm],'-']
4089            elif parm in varyList:
4090                parmDict[parm] = [parmDict[parm],'T']
4091            else:
4092                parmDict[parm] = [parmDict[parm],'F']
4093        # for i in parmDict: print i,'\t',parmDict[i]
4094        # fl = open('parmDict.dat','wb')
4095        # import cPickle
4096        # cPickle.dump(parmDict,fl,1)
4097        # fl.close()
4098        return parmDict,varyList
4099
4100    def OnShowLSParms(self,event):
4101        '''Displays a window showing all parameters in the refinement.
4102        Called from the Calculate/View LS Parms menu.
4103        '''
4104        try:
4105            parmDict,varyList = self.MakeLSParmDict()
4106        except:
4107            print('Error retrieving parameters')
4108            return
4109        parmValDict = {}
4110        for i in parmDict:
4111            parmValDict[i] = parmDict[i][0]
4112           
4113        reqVaryList = tuple(varyList) # save requested variables
4114        try:
4115            # process constraints
4116            sub = G2gd.GetPatternTreeItemId(self,self.root,'Constraints') 
4117            Constraints = self.PatternTree.GetItemPyData(sub)
4118            constList = []
4119            for item in Constraints:
4120                if item.startswith('_'): continue
4121                constList += Constraints[item]
4122            G2mv.InitVars()
4123            constrDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
4124            groups,parmlist = G2mv.GroupConstraints(constrDict)
4125            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmValDict)
4126            G2mv.Map2Dict(parmValDict,varyList)
4127        except:
4128            pass
4129        dlg = G2gd.ShowLSParms(self,'Least Squares Parameters',parmValDict,varyList,reqVaryList)
4130        dlg.ShowModal()
4131        dlg.Destroy()
4132
4133    def OnRefine(self,event):
4134        '''Perform a refinement.
4135        Called from the Calculate/Refine menu.
4136        '''
4137        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
4138        if Id:
4139            dlg = wx.MessageDialog(
4140                self,
4141                'Your last refinement was sequential. Continue with "Refine", removing previous sequential results?',
4142                'Remove sequential results?',wx.OK|wx.CANCEL)
4143            if dlg.ShowModal() == wx.ID_OK:
4144                self.PatternTree.Delete(Id)
4145                dlg.Destroy()
4146            else:
4147                dlg.Destroy()
4148                return
4149        self.OnFileSave(event)
4150        # check that constraints are OK here
4151        errmsg, warnmsg = G2stIO.ReadCheckConstraints(self.GSASprojectfile)
4152        if errmsg:
4153            self.ErrorDialog('Refinement error',errmsg)
4154            return
4155        if warnmsg:
4156            print('Conflict between refinment flag settings and constraints:\n'+
4157                warnmsg+'\nRefinement not possible')
4158            self.ErrorDialog('Refinement Flag Error',
4159                'Conflict between refinement flag settings and constraints:\n'+
4160                warnmsg+'\nRefinement not possible')
4161            return
4162        dlg = wx.ProgressDialog('Residual','All data Rw =',101.0, 
4163            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT,
4164            parent=self)
4165        Size = dlg.GetSize()
4166        if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
4167            dlg.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
4168        dlg.CenterOnParent()
4169        Rw = 100.00
4170        self.SaveTreeSetting()
4171        self.PatternTree.SaveExposedItems()       
4172        try:
4173            OK,Msg = G2stMn.Refine(self.GSASprojectfile,dlg)    #Msg is Rvals dict if Ok=True
4174        finally:
4175            dlg.Update(101.) # forces the Auto_Hide; needed after move w/Win & wx3.0
4176            dlg.Destroy()
4177            wx.Yield()
4178        if OK:
4179            Rw = Msg['Rwp']
4180            lamMax = Msg.get('lamMax',0.001)
4181            text = 'Load new result?'
4182            if lamMax >= 10.:
4183                text += '\nWARNING: Steepest descents dominates;'+   \
4184                ' minimum may not have been reached\nor result may be false minimum.'+  \
4185                ' You should reconsider your parameter suite'
4186            dlg2 = wx.MessageDialog(self,text,'Refinement results, Rw =%.3f'%(Rw),wx.OK|wx.CANCEL)
4187            try:
4188                if dlg2.ShowModal() == wx.ID_OK:
4189                    self.PatternTree.DeleteChildren(self.root)
4190                    self.HKL = []
4191                    G2IO.ProjFileOpen(self,False)
4192                    self.PatternTree.RestoreExposedItems()       
4193                    self.ResetPlots()
4194            finally:
4195                dlg2.Destroy()
4196        else:
4197            self.ErrorDialog('Refinement error',Msg)
4198       
4199    def SaveTreeSetting(self):
4200        'Save the last tree setting'
4201        oldId =  self.PatternTree.GetSelection()        #retain current selection
4202        oldPath = self.GetTreeItemsList(oldId)
4203        self.lastTreeSetting = oldPath
4204        # note that for reasons unclear, it does not seem necessary to reload the Atoms tab
4205        #parentName = ''
4206        #tabId = None
4207        # parentId = self.PatternTree.GetItemParent(oldId)
4208        # if parentId:
4209        #     parentName = self.PatternTree.GetItemText(parentId)     #find the current data tree name
4210        #     if 'Phases' in parentName:
4211        #         tabId = self.dataDisplay.GetSelection()
4212        #self.lastTreeSetting = oldPath,tabId
4213        #GSASIIpath.IPyBreak()
4214       
4215    def TestResetPlot(self,event):
4216        '''Debug code to test cleaning up plots after a refinement'''
4217        #for i in range(self.G2plotNB.nb.GetPageCount()):
4218        #    [self.G2plotNB.nb.GetPageText(i)
4219        # save current tree item and (if needed) atoms tab
4220        self.SaveTreeSetting()
4221        self.ResetPlots()
4222       
4223    def ResetPlots(self):
4224        '''This reloads the current tree item, often drawing a plot. It refreshes any plots
4225        that have registered a refresh routine (see G2plotNB.RegisterRedrawRoutine)
4226        and deletes all plots that have not been refreshed and
4227        require one (see G2plotNB.SetNoDelete).
4228        '''
4229        lastRaisedPlotTab = self.G2plotNB.lastRaisedPlotTab # save the last page saved
4230        #print 'lastRaisedPlotTab=',lastRaisedPlotTab
4231        self.G2plotNB.lastRaisedPlotTab = None
4232        # mark displayed plots as invalid
4233        for lbl,frame in zip(self.G2plotNB.plotList,self.G2plotNB.panelList):
4234            frame.plotInvalid = True
4235        # reload current tree item, triggering the routine to redraw the data window and possibly a plot
4236        #oldPath,tabId = self.lastTreeSetting
4237        oldPath = self.lastTreeSetting
4238        Id = self.root
4239        for txt in oldPath:
4240            Id = G2gd.GetPatternTreeItemId(self, Id, txt)
4241        self.PickIdText = None  #force reload of page
4242        if Id:
4243            self.PickId = Id
4244            self.PatternTree.SelectItem(Id)
4245        # update other self-updating plots
4246#        for lbl,frame in zip(self.G2plotNB.plotList,self.G2plotNB.panelList):
4247#            if frame.plotInvalid and frame.replotFunction:
4248#                frame.replotFunction(*frame.replotArgs,**frame.replotKWargs)
4249        # delete any remaining plots that are still invalid and need a refresh
4250        for lbl,frame in zip(self.G2plotNB.plotList,self.G2plotNB.panelList):
4251            if frame.plotInvalid and frame.plotRequiresRedraw:
4252                self.G2plotNB.Delete(lbl)
4253        # put the previously last-raised tab on top, if present. If not, use the one corresponding to
4254        # the last tree item to be selected
4255        wx.CallAfter(self.G2plotNB.RaiseLastPage,lastRaisedPlotTab,self.G2plotNB.lastRaisedPlotTab)
4256       
4257    def OnSeqRefine(self,event):
4258        '''Perform a sequential refinement.
4259        Called from the Calculate/Sequential refine menu.
4260        '''
4261        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
4262        if not Id:
4263            Id = self.PatternTree.AppendItem(self.root,text='Sequential results')
4264            self.PatternTree.SetItemPyData(Id,{})           
4265        self.G2plotNB.Delete('Sequential refinement')    #clear away probably invalid plot
4266        Controls = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.root, 'Controls'))
4267        if not Controls.get('Seq Data'):
4268            print('Error: a sequential refinement has not been set up')
4269            return
4270        Controls['ShowCell'] = True
4271        self.OnFileSave(event)
4272        # check that constraints are OK here
4273        errmsg, warnmsg = G2stIO.ReadCheckConstraints(self.GSASprojectfile)
4274        if errmsg:
4275            self.ErrorDialog('Refinement error',errmsg)
4276            return
4277        if warnmsg:
4278            print('Conflict between refinment flag settings and constraints:\n'+
4279                  warnmsg+'\nRefinement not possible')
4280            self.ErrorDialog('Refinement Flag Error',
4281                             'Conflict between refinment flag settings and constraints:\n'+
4282                             warnmsg+'\nRefinement not possible')
4283            return
4284        self.PatternTree.SaveExposedItems()       
4285        dlg = wx.ProgressDialog('Residual for histogram 0','Powder profile Rwp =',101.0, 
4286            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT,
4287            parent=self)           
4288        Size = dlg.GetSize()
4289        if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
4290            dlg.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
4291        dlg.CenterOnParent()
4292        try:
4293            OK,Msg = G2stMn.SeqRefine(self.GSASprojectfile,dlg)     #Msg is Rvals dict if Ok=True
4294        finally:
4295            dlg.Update(101.) # forces the Auto_Hide; needed after move w/Win & wx3.0
4296            dlg.Destroy()
4297            wx.Yield()
4298        if OK:
4299            dlg = wx.MessageDialog(self,'Load new result?','Refinement results',wx.OK|wx.CANCEL)
4300            try:
4301                if dlg.ShowModal() == wx.ID_OK:
4302                    self.PickIdText = None  #force reload of PickId contents
4303                    self.PatternTree.DeleteChildren(self.root)
4304                    if len(self.HKL): self.HKL = []
4305                    if self.G2plotNB.plotList:
4306                        self.G2plotNB.clear()
4307                    G2IO.ProjFileOpen(self,False)
4308                    self.PatternTree.RestoreExposedItems()
4309                    self.ResetPlots()
4310                    Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
4311                    self.PatternTree.SelectItem(Id)
4312            finally:
4313                dlg.Destroy()
4314            self.SeqTblHideList = []
4315        else:
4316            self.ErrorDialog('Sequential refinement error',Msg)
4317       
4318    def ErrorDialog(self,title,message,parent=None, wtype=wx.OK):
4319        'Display an error message'
4320        result = None
4321        if parent is None:
4322            dlg = wx.MessageDialog(self, message, title,  wtype)
4323        else:
4324            dlg = wx.MessageDialog(parent, message, title,  wtype)
4325            dlg.CenterOnParent() # not working on Mac
4326        try:
4327            result = dlg.ShowModal()
4328        finally:
4329            dlg.Destroy()
4330        return result
4331   
4332    def OnSaveMultipleImg(self,event):
4333        '''Select and save multiple image parameter and mask files
4334        '''
4335        G2IO.SaveMultipleImg(self)
4336       
4337class GSASIImain(wx.App):
4338    '''Defines a wxApp for GSAS-II
4339
4340    Creates a wx frame (self.main) which contains the display of the
4341    data tree.
4342    '''
4343    def OnInit(self):
4344        '''Called automatically when the app is created.'''
4345        import platform
4346        if '2.7' not in sys.version[:5]:
4347            dlg = wx.MessageDialog(None, 
4348                'GSAS-II requires Python 2.7.x\n Yours is '+sys.version.split()[0],
4349                'Python version error',  wx.OK)
4350            try:
4351                dlg.ShowModal()
4352            finally:
4353                dlg.Destroy()
4354            sys.exit()
4355        self.main = GSASII(None)
4356        self.main.Show()
4357        self.SetTopWindow(self.main)
4358        # save the current package versions
4359        self.main.PackageVersions = []
4360        self.main.PackageVersions.append(['Python',sys.version.split()[0]])
4361        for p in (wx,mpl,np,sp,ogl):
4362            self.main.PackageVersions.append([p.__name__,p.__version__])
4363        try:
4364            self.main.PackageVersions.append([Image.__name__,Image.VERSION])
4365        except:
4366            try:
4367                from PIL import PILLOW_VERSION
4368                self.main.PackageVersions.append([Image.__name__,PILLOW_VERSION])
4369            except:
4370                pass
4371        self.main.PackageVersions.append(['Platform',sys.platform+' '+platform.architecture()[0]+' '+platform.machine()])
4372       
4373        return True
4374    # def MacOpenFile(self, filename):
4375    #     '''Called on Mac every time a file is dropped on the app when it is running,
4376    #     treat this like a File/Open project menu action.
4377    #     Should be ignored on other platforms
4378    #     '''
4379    #     # PATCH: Canopy 1.4 script main seems dropped on app; ignore .py files
4380    #     print 'MacOpen',filename
4381    #     if os.path.splitext(filename)[1] == '.py': return
4382    #     # end PATCH
4383    #     self.main.OnFileOpen(None,filename)
4384    # removed because this gets triggered when a file is on the command line in canopy 1.4 -- not likely used anyway
4385       
4386def main():
4387    '''Start up the GSAS-II application'''
4388    #application = GSASIImain() # don't redirect output, someday we
4389    # may want to do this if we can
4390    application = GSASIImain(0)
4391    if GSASIIpath.GetConfigValue('wxInspector'):
4392        import wx.lib.inspection as wxeye
4393        wxeye.InspectionTool().Show()
4394
4395    #application.main.OnRefine(None)
4396    application.MainLoop()
4397   
4398if __name__ == '__main__':
4399    # print versions
4400    print "Python module versions loaded:"
4401    print "  Python:     ",sys.version.split()[0]
4402    print "  wx:         ",wx.__version__
4403    print "  matplotlib: ",mpl.__version__
4404    print "  numpy:      ",np.__version__
4405    print "  scipy:      ",sp.__version__
4406    print "  OpenGL:     ",ogl.__version__
4407    try:
4408        from PIL import Image
4409        try:
4410            from PIL import PILLOW_VERSION
4411            version = PILLOW_VERSION
4412        except:
4413            version = Image.VERSION
4414        print "  PIL.Image:  ",version
4415    except ImportError:
4416        try:
4417            import Image
4418            print "Image (PIL):",Image.VERSION
4419        except ImportError:
4420            print "Image module not present; Note that PIL (Python Imaging Library) or pillow is needed for some image operations"
4421    import platform
4422    print "  Platform:   ",sys.platform,platform.architecture()[0],platform.machine()
4423    try:
4424        import mkl
4425        print "  Max threads:",mkl.get_max_threads()
4426    except:
4427        pass
4428    #print "wxPython description",wx.PlatformInfo
4429    print "This is GSAS-II revision "+str(GSASIIpath.GetVersionNumber())+'\n'
4430    GSASIIpath.InvokeDebugOpts()
4431    main() # start the GUI
Note: See TracBrowser for help on using the repository browser.