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

Last change on this file since 2895 was 2895, checked in by toby, 4 years ago

merge trunk changes to 2984

  • 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-03 00:27:09 +0000 (Mon, 03 Jul 2017) $
6# $Author: toby $
7# $Revision: 2895 $
8# $URL: branch/2frame/GSASII.py $
9# $Id: GSASII.py 2895 2017-07-03 00:27:09Z toby $
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: 2895 $")
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.dataPanel = wx.Panel(self.mainPanel, wx.ID_ANY,
2567            style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
2568        self.mainPanel.SetMinimumPaneSize(100)
2569        self.mainPanel.SplitVertically(self.treePanel, self.dataPanel, 200)
2570       
2571        wxID_PATTERNTREE = wx.NewId()
2572        treeSizer = wx.BoxSizer()
2573        self.treePanel.SetSizer(treeSizer)
2574        self.PatternTree = G2G.G2TreeCtrl(id=wxID_PATTERNTREE,
2575            parent=self.treePanel, size=self.treePanel.GetClientSize(),style=wx.TR_DEFAULT_STYLE )
2576        treeSizer.Add(self.PatternTree,1,wx.EXPAND|wx.ALL,0)
2577        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED,self.OnDataTreeSelChanged)
2578        self.PatternTree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK,self.OnDataTreeSelChanged)
2579        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
2580            self.OnPatternTreeItemCollapsed, id=wxID_PATTERNTREE)
2581        self.PatternTree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
2582            self.OnPatternTreeItemExpanded, id=wxID_PATTERNTREE)
2583        self.PatternTree.Bind(wx.EVT_TREE_DELETE_ITEM,
2584            self.OnPatternTreeItemDelete, id=wxID_PATTERNTREE)
2585        self.PatternTree.Bind(wx.EVT_TREE_KEY_DOWN,
2586            self.OnPatternTreeKeyDown, id=wxID_PATTERNTREE)
2587        self.PatternTree.Bind(wx.EVT_TREE_BEGIN_RDRAG,
2588            self.OnPatternTreeBeginRDrag, id=wxID_PATTERNTREE)       
2589        self.PatternTree.Bind(wx.EVT_TREE_END_DRAG,
2590            self.OnPatternTreeEndDrag, id=wxID_PATTERNTREE)       
2591        self.root = self.PatternTree.root       
2592       
2593        self.dataWindow = G2gd.DataWindow(self.dataPanel)
2594        self.dataWindow.SetSize(self.dataPanel.GetClientSize())
2595        self.dataWindow.SetAutoLayout(True)
2596        self.dataWindow.SetInitialSize()
2597        self.dataFrame = self.dataWindow        #kluge!!
2598#        self.SetDataSize()
2599       
2600       
2601        plotFrame = wx.Frame(None,-1,'GSASII Plots',size=wx.Size(700,600), \
2602            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
2603        self.G2plotNB = G2plt.G2PlotNoteBook(plotFrame,G2frame=self)
2604        plotFrame.Show()
2605       
2606    def __init__(self, parent):
2607        self.ExportLookup = {}
2608        self.exporterlist = []
2609        self._init_ctrls(parent)
2610        self.Image = wx.Image(
2611            os.path.join(GSASIIpath.path2GSAS2,'gsas2.ico'),
2612            wx.BITMAP_TYPE_ICO)
2613        if "wxMSW" in wx.PlatformInfo:
2614            img = self.Image.Scale(16, 16).ConvertToBitmap()
2615        elif "wxGTK" in wx.PlatformInfo:
2616            img = self.Image.Scale(22, 22).ConvertToBitmap()
2617        else:
2618            img = self.Image.ConvertToBitmap()
2619        self.SetIcon(wx.IconFromBitmap(img))
2620        self.Bind(wx.EVT_CLOSE, self.ExitMain)
2621        # various defaults
2622        self.oldFocus = None
2623        self.GSASprojectfile = ''
2624        self.undofile = ''
2625        self.TreeItemDelete = False
2626        self.plotStyle = {'qPlot':False,'dPlot':False,'sqrtPlot':False,'sqPlot':False}
2627        self.Weight = False
2628        self.IfPlot = False
2629        self.DDShowAll = False
2630        self.atmSel = ''
2631        self.PatternId = 0
2632        self.PickId = 0
2633        self.PickIdText = None
2634        self.PeakTable = []
2635        self.LimitsTable = []
2636        self.ifX20 = True   #use M20 /= (1+X20) in powder indexing, etc.
2637        self.HKL = []
2638        self.Lines = []
2639        self.itemPicked = None
2640        self.Interpolate = 'nearest'
2641        self.ContourColor = GSASIIpath.GetConfigValue('Contour_color','Paired')
2642        self.VcovColor = 'RdYlGn'
2643        self.RamaColor = 'Blues'
2644        self.Projection = 'equal area'
2645        self.logPlot = False
2646        self.plusPlot = True
2647        self.ErrorBars = False
2648        self.Contour = False
2649        self.Legend = False
2650        self.SinglePlot = True
2651        self.Waterfall = False
2652        self.selections= None
2653        self.PDFselections = None
2654        self.SubBack = False
2655        self.seqReverse = False
2656        self.seqLines = True #draw lines between points
2657        self.plotView = 0
2658        self.Image = 0
2659        self.oldImagefile = '' # the name of the last image file read
2660        self.oldImageTag = None # the name of the tag for multi-image files
2661        self.PauseIntegration = False
2662        self.ImageZ = []
2663        self.Integrate = 0
2664        self.imageDefault = {}
2665        self.IntgOutList = [] # list of integration tree item Ids created in G2IO.SaveIntegration
2666        self.AutointPWDRnames = [] # list of autoint created PWDR tree item names (to be deleted on a reset)
2667        self.autoIntFrame = None
2668        self.IntegratedList = [] # list of already integrated IMG tree items
2669        self.Sngl = False
2670        self.ifGetRing = False
2671        self.MaskKey = ''           #trigger for making image masks
2672        self.MskDelete = False      #trigger for mask delete
2673        self.StrainKey = ''         #ditto for new strain d-zeros
2674        self.EnablePlot = True
2675        self.hist = ''              # selected histogram in Phase/Data tab
2676        self.dirname = os.path.abspath(os.path.expanduser('~'))       #start in the users home directory by default; may be meaningless
2677        self.TutorialImportDir = None  # location to read tutorial files, set when a tutorial is viewed
2678        self.LastImportDir = None # last-used directory where an import was done
2679        self.LastGPXdir = None    # directory where a GPX file was last read
2680        self.LastExportDir = None  # the last directory used for exports, if any.
2681        self.dataDisplayPhaseText = ''
2682        self.lastTreeSetting = []
2683        self.ExpandingAll = False
2684        self.SeqTblHideList = []
2685               
2686        arg = sys.argv
2687        if len(arg) > 1 and arg[1]:
2688            self.GSASprojectfile = os.path.splitext(arg[1])[0]+'.gpx'
2689            self.dirname = os.path.abspath(os.path.dirname(arg[1]))
2690            if self.dirname: os.chdir(self.dirname)
2691            try:
2692                self.StartProject()         #open the file if possible
2693                return
2694            except Exception:
2695                print 'Error opening or reading file',arg[1]
2696                import traceback
2697                print traceback.format_exc()
2698               
2699        if GSASIIpath.GetConfigValue('Starting_directory'):
2700            try:
2701                pth = GSASIIpath.GetConfigValue('Starting_directory')
2702                pth = os.path.expanduser(pth) 
2703                os.chdir(pth)
2704                self.LastGPXdir = pth
2705            except:
2706                print('Ignoring Config Starting_directory value: '+
2707                      GSASIIpath.GetConfigValue('Starting_directory'))
2708
2709    def GetTreeItemsList(self,item):
2710        return self.PatternTree._getTreeItemsList(item)
2711
2712    def OnSize(self,event):
2713        'Called to make PatternTree fill mainPanel'
2714        w,h = self.GetClientSizeTuple()
2715        self.dataWindow.SetupScrolling()
2716        self.mainPanel.SetSize(wx.Size(w,h))
2717        self.PatternTree.SetSize(wx.Size(w,h))
2718        self.dataWindow.SetSize(self.dataPanel.GetClientSize())
2719       
2720    def SetDataSize(self):
2721        Size = self.GetSize()
2722        self.SetSize(Size)
2723        Size[1] += 1        #kluge to ensure scrollbar settings & window properly displayed
2724        self.SetSize(Size)
2725                               
2726    def OnDataTreeSelChanged(self, event):
2727        '''Called when a data tree item is selected'''
2728        if self.TreeItemDelete:
2729            self.TreeItemDelete = False
2730        else:
2731            if self.ExpandingAll:
2732                if GSASIIpath.GetConfigValue('debug'): print('Skipping Tree selection due to ExpandAll')
2733                return
2734            pltNum = self.G2plotNB.nb.GetSelection()
2735            if pltNum >= 0:                         #to avoid the startup with no plot!
2736                self.G2plotNB.nb.GetPage(pltNum)
2737            item = event.GetItem()
2738            wx.CallAfter(G2gd.SelectDataTreeItem,self,item,self.oldFocus)
2739            #if self.oldFocus: # now done via last parameter on SelectDataTreeItem
2740            #    wx.CallAfter(self.oldFocus.SetFocus)
2741       
2742    def OnPatternTreeItemCollapsed(self, event):
2743        'Called when a tree item is collapsed - all children will be collapsed'
2744        self.PatternTree.CollapseAllChildren(event.GetItem())
2745
2746    def OnPatternTreeItemExpanded(self, event):
2747        'Called when a tree item is expanded'
2748        self.OnDataTreeSelChanged(event)
2749        event.Skip()
2750       
2751    def OnPatternTreeItemDelete(self, event):
2752        'Called when a tree item is deleted -- not sure what this does'
2753        self.TreeItemDelete = True
2754
2755    def OnPatternTreeItemActivated(self, event):
2756        'Called when a tree item is activated'
2757        event.Skip()
2758       
2759    def OnPatternTreeBeginRDrag(self,event):
2760        event.Allow()
2761        self.BeginDragId = event.GetItem()
2762        self.ParentId = self.PatternTree.GetItemParent(self.BeginDragId)
2763        DragText = self.PatternTree.GetItemText(self.BeginDragId)
2764        self.DragData = [[DragText,self.PatternTree.GetItemPyData(self.BeginDragId)],]
2765        item, cookie = self.PatternTree.GetFirstChild(self.BeginDragId)
2766        while item:     #G2 data tree has no sub children under a child of a tree item
2767            name = self.PatternTree.GetItemText(item)
2768            self.DragData.append([name,self.PatternTree.GetItemPyData(item)])
2769            item, cookie = self.PatternTree.GetNextChild(self.BeginDragId, cookie)                           
2770       
2771    def OnPatternTreeEndDrag(self,event):
2772        event.Allow()
2773        self.EndDragId = event.GetItem()
2774        try:
2775            NewParent = self.PatternTree.GetItemParent(self.EndDragId)
2776        except:
2777            self.EndDragId = self.PatternTree.GetLastChild(self.root)
2778            NewParent = self.root
2779        if self.ParentId != NewParent:
2780            self.ErrorDialog('Drag not allowed','Wrong parent for item dragged')
2781        else:
2782            Name,Item = self.DragData[0]
2783            NewId = self.PatternTree.InsertItem(self.ParentId,self.EndDragId,Name,data=None)
2784            self.PatternTree.SetItemPyData(NewId,Item)
2785            for name,item in self.DragData[1:]:     #loop over children
2786                Id = self.PatternTree.AppendItem(parent=NewId,text=name)
2787                self.PatternTree.SetItemPyData(Id,item)
2788            self.PatternTree.Delete(self.BeginDragId)
2789            G2gd.SelectDataTreeItem(self,NewId)
2790       
2791    def OnPatternTreeKeyDown(self,event): #doesn't exactly work right with Shift key down
2792        'Allows stepping through the tree with the up/down arrow keys'
2793        self.oldFocus = wx.Window.FindFocus()
2794        keyevt = event.GetKeyEvent()
2795        key = event.GetKeyCode()
2796        item = self.PatternTree.GetSelection()
2797        if type(item) is int: return # is this the toplevel in tree?
2798        name = self.PatternTree.GetItemText(item)
2799        parent = self.PatternTree.GetItemParent(item)
2800        if key == wx.WXK_UP:
2801            if keyevt.GetModifiers() == wx.MOD_SHIFT and parent != self.root:
2802                if type(parent) is int: return # is this the toplevel in tree?
2803                prev = self.PatternTree.GetPrevSibling(parent)
2804                NewId = G2gd.GetPatternTreeItemId(self,prev,name)
2805                if NewId:
2806                    self.PatternTree.Collapse(parent)
2807                    self.PatternTree.Expand(prev)
2808                    self.oldFocus = wx.Window.FindFocus()
2809                    wx.CallAfter(self.PatternTree.SelectItem,NewId)
2810                else:
2811                    wx.CallAfter(self.PatternTree.SelectItem,item)
2812            elif sys.platform == "win32":   
2813                self.PatternTree.GetPrevSibling(item)
2814                self.PatternTree.SelectItem(item)
2815            else:
2816                item = self.PatternTree.GetPrevSibling(item)
2817                if item.IsOk(): self.PatternTree.SelectItem(item)
2818        elif key == wx.WXK_DOWN:
2819            if keyevt.GetModifiers() == wx.MOD_SHIFT and parent != self.root:
2820                next = self.PatternTree.GetNextSibling(parent)
2821                NewId = G2gd.GetPatternTreeItemId(self,next,name)
2822                if NewId:
2823                    self.PatternTree.Collapse(parent)
2824                    self.PatternTree.Expand(next)
2825                    self.oldFocus = wx.Window.FindFocus()
2826                    wx.CallAfter(self.PatternTree.SelectItem,NewId)
2827                else:
2828                    wx.CallAfter(self.PatternTree.SelectItem,item)
2829            elif sys.platform == "win32":   
2830                self.PatternTree.GetNextSibling(item)
2831                self.PatternTree.SelectItem(item)
2832            else:   
2833                item = self.PatternTree.GetNextSibling(item)
2834                if item.IsOk(): self.PatternTree.SelectItem(item)
2835               
2836    def OnReadPowderPeaks(self,event):
2837        'Bound to menu Data/Read Powder Peaks'
2838        self.CheckNotebook()
2839        pth = G2G.GetImportPath(self)
2840        if not pth: pth = '.'
2841        dlg = wx.FileDialog(self, 'Choose file with peak list', pth, '', 
2842            'peak files (*.txt)|*.txt|All files (*.*)|*.*',wx.OPEN)
2843        try:
2844            if dlg.ShowModal() == wx.ID_OK:
2845                self.HKL = []
2846                self.powderfile = dlg.GetPath()
2847                comments,peaks,limits,wave = G2IO.GetPowderPeaks(self.powderfile)
2848                Id = self.PatternTree.AppendItem(parent=self.root,text='PKS '+os.path.basename(self.powderfile))
2849                data = ['PKS',wave,0.0]
2850                names = ['Type','Lam','Zero'] 
2851                codes = [0,0,0]
2852                inst = [G2IO.makeInstDict(names,data,codes),{}]
2853                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
2854                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),comments)
2855                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(limits),limits])
2856                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[peaks,[]])
2857                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
2858                self.PatternTree.Expand(Id)
2859                self.PatternTree.SelectItem(Id)
2860                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
2861        finally:
2862            dlg.Destroy()
2863                       
2864    def OnImageRead(self,event):
2865        '''Called to read in an image in any known format. *** Depreciated. ***
2866        '''
2867        G2G.G2MessageBox(self,'Please use the Import/Image/... menu item rather than this','depreciating menu item')
2868
2869    def CheckNotebook(self):
2870        '''Make sure the data tree has the minimally expected controls.
2871        '''
2872        if not G2gd.GetPatternTreeItemId(self,self.root,'Notebook'):
2873            sub = self.PatternTree.AppendItem(parent=self.root,text='Notebook')
2874            self.PatternTree.SetItemPyData(sub,[''])
2875        if not G2gd.GetPatternTreeItemId(self,self.root,'Controls'):
2876            sub = self.PatternTree.AppendItem(parent=self.root,text='Controls')
2877            self.PatternTree.SetItemPyData(sub,copy.copy(G2obj.DefaultControls))
2878        if not G2gd.GetPatternTreeItemId(self,self.root,'Covariance'):
2879            sub = self.PatternTree.AppendItem(parent=self.root,text='Covariance')
2880            self.PatternTree.SetItemPyData(sub,{})
2881        if not G2gd.GetPatternTreeItemId(self,self.root,'Constraints'):
2882            sub = self.PatternTree.AppendItem(parent=self.root,text='Constraints')
2883            self.PatternTree.SetItemPyData(sub,{'Hist':[],'HAP':[],'Phase':[]})
2884        if not G2gd.GetPatternTreeItemId(self,self.root,'Restraints'):
2885            sub = self.PatternTree.AppendItem(parent=self.root,text='Restraints')
2886            self.PatternTree.SetItemPyData(sub,{})
2887        if not G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'):
2888            sub = self.PatternTree.AppendItem(parent=self.root,text='Rigid bodies')
2889            self.PatternTree.SetItemPyData(sub,{'Vector':{'AtInfo':{}},
2890                'Residue':{'AtInfo':{}},'RBIds':{'Vector':[],'Residue':[]}})
2891               
2892    class CopyDialog(wx.Dialog):
2893        '''Creates a dialog for copying control settings between
2894        data tree items'''
2895        def __init__(self,parent,title,text,data):
2896            wx.Dialog.__init__(self,parent,-1,title, 
2897                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
2898            self.data = data
2899            panel = wx.Panel(self)
2900            mainSizer = wx.BoxSizer(wx.VERTICAL)
2901            topLabl = wx.StaticText(panel,-1,text)
2902            mainSizer.Add((10,10),1)
2903            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
2904            mainSizer.Add((10,10),1)
2905            ncols = len(data)/40+1
2906            dataGridSizer = wx.FlexGridSizer(cols=ncols,hgap=2,vgap=2)
2907            for id,item in enumerate(self.data):
2908                ckbox = wx.CheckBox(panel,id,item[1])
2909                ckbox.Bind(wx.EVT_CHECKBOX,self.OnCopyChange)                   
2910                dataGridSizer.Add(ckbox,0,wx.LEFT,10)
2911            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
2912            OkBtn = wx.Button(panel,-1,"Ok")
2913            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
2914            cancelBtn = wx.Button(panel,-1,"Cancel")
2915            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
2916            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
2917            btnSizer.Add((20,20),1)
2918            btnSizer.Add(OkBtn)
2919            btnSizer.Add((20,20),1)
2920            btnSizer.Add(cancelBtn)
2921            btnSizer.Add((20,20),1)
2922           
2923            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
2924            panel.SetSizer(mainSizer)
2925            panel.Fit()
2926            self.Fit()
2927       
2928        def OnCopyChange(self,event):
2929            id = event.GetId()
2930            self.data[id][0] = self.FindWindowById(id).GetValue()       
2931           
2932        def OnOk(self,event):
2933            parent = self.GetParent()
2934            parent.Raise()
2935            self.EndModal(wx.ID_OK)             
2936           
2937        def OnCancel(self,event):
2938            parent = self.GetParent()
2939            parent.Raise()
2940            self.EndModal(wx.ID_CANCEL)             
2941           
2942        def GetData(self):
2943            return self.data
2944       
2945    class SumDialog(wx.Dialog):
2946        '''Allows user to supply scale factor(s) when summing data -
2947        TODO: CAN WE PREVIEW RESULT HERE?'''
2948        def __init__(self,parent,title,text,dataType,data,dataList):
2949            wx.Dialog.__init__(self,parent,-1,title,size=(400,250),
2950                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
2951            self.plotFrame = wx.Frame(self,-1,'Sum Plots',size=wx.Size(700,600), \
2952                style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
2953            self.G2plotNB = G2plt.G2PlotNoteBook(self.plotFrame,G2frame=self)
2954            self.data = data
2955            self.dataList = dataList
2956            self.dataType = dataType
2957            size = (450,350)
2958            panel = wxscroll.ScrolledPanel(self, wx.ID_ANY,size=size,
2959                style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
2960            mainSizer = wx.BoxSizer(wx.VERTICAL)
2961            topLabl = wx.StaticText(panel,-1,text)
2962            mainSizer.Add((10,10),1)
2963            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
2964            mainSizer.Add((10,10),1)
2965            self.dataGridSizer = wx.FlexGridSizer(cols=2,hgap=2,vgap=2)
2966            for id,item in enumerate(self.data[:-1]):
2967                name = wx.TextCtrl(panel,-1,item[1],size=wx.Size(300,20))
2968                name.SetEditable(False)
2969#        azmthOff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'azmthOff',nDig=(10,2),typeHint=float,OnLeave=OnAzmthOff)
2970                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
2971                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
2972                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
2973                self.dataGridSizer.Add(scale,0,wx.LEFT,10)
2974                self.dataGridSizer.Add(name,0,wx.RIGHT,10)
2975            if self.dataType:
2976                self.dataGridSizer.Add(wx.StaticText(panel,-1,'Sum result name: '+self.dataType),0, \
2977                    wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
2978                self.name = wx.TextCtrl(panel,-1,self.data[-1],size=wx.Size(300,20),style=wx.TE_PROCESS_ENTER)
2979                self.name.Bind(wx.EVT_TEXT_ENTER,self.OnNameChange)
2980                self.name.Bind(wx.EVT_KILL_FOCUS,self.OnNameChange)
2981                self.dataGridSizer.Add(self.name,0,wx.RIGHT|wx.TOP,10)
2982                self.dataGridSizer.Add(wx.StaticText(panel,label='All scales value: '),0,  \
2983                    wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
2984#        azmthOff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'azmthOff',nDig=(10,2),typeHint=float,OnLeave=OnAzmthOff)
2985                allScale = wx.TextCtrl(panel,value='',style=wx.TE_PROCESS_ENTER)
2986                allScale.Bind(wx.EVT_TEXT_ENTER,self.OnAllScale)
2987                allScale.Bind(wx.EVT_KILL_FOCUS,self.OnAllScale)
2988                self.dataGridSizer.Add(allScale,0,WACV)
2989            mainSizer.Add(self.dataGridSizer,0,wx.EXPAND)
2990            OkBtn = wx.Button(panel,-1,"Ok")
2991            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
2992            cancelBtn = wx.Button(panel,-1,"Cancel")
2993            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
2994            btnSizer = wx.FlexGridSizer(0,3,10,20)
2995            if self.dataType =='PWDR':
2996                TestBtn = wx.Button(panel,-1,"Test")
2997                TestBtn.Bind(wx.EVT_BUTTON, self.OnTest)
2998                btnSizer.Add(TestBtn)
2999            btnSizer.Add(OkBtn)
3000            btnSizer.Add(cancelBtn)
3001           
3002            panel.SetSizer(mainSizer)
3003            panel.SetAutoLayout(1)
3004            panel.SetupScrolling()
3005            mainSizer.Add((10,10),1)
3006            mainSizer.Add(btnSizer,0,wx.CENTER)
3007            panel.SetSizer(mainSizer)
3008            panel.Fit()
3009            self.Fit()
3010
3011        def OnScaleChange(self,event):
3012            event.Skip()
3013            id = event.GetId()
3014            value = self.FindWindowById(id).GetValue()
3015            try:
3016                self.data[id][0] = float(value)
3017                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
3018            except ValueError:
3019                if value and '-' not in value[0]:
3020                    print 'bad input - numbers only'
3021                    self.FindWindowById(id).SetValue('0.000')
3022                   
3023        def OnAllScale(self,event):
3024            event.Skip()
3025            id = event.GetId()
3026            try:
3027                scale = float(self.FindWindowById(id).GetValue())
3028                self.FindWindowById(id).SetValue('%.3f'%(scale))
3029                entries = self.dataGridSizer.GetChildren()
3030                for i,item in enumerate(self.data[:-1]):
3031                    item[0] = scale
3032                    entries[2*i].GetWindow().SetValue('%.3f'%(scale))
3033                 
3034            except ValueError:
3035                print 'bad input - numbers only'
3036                self.FindWindowById(id).SetValue('')
3037                   
3038           
3039        def OnNameChange(self,event):
3040            event.Skip()
3041            self.data[-1] = self.name.GetValue()
3042           
3043        def OnTest(self,event):
3044            lenX = 0
3045            Xminmax = [0,0]
3046            XY = []
3047            Xsum = []
3048            Ysum = []
3049            Vsum = []
3050            result = self.data
3051            for i,item in enumerate(result[:-1]):
3052                scale,name = item
3053                data = self.dataList[i]
3054                if scale:
3055                    x,y,w,yc,yb,yd = data   #numpy arrays!
3056                    XY.append([x,scale*y])
3057                    v = 1./w
3058                    if lenX:
3059                        if lenX != len(x):
3060                            self.ErrorDialog('Data length error','Data to be summed must have same number of points'+ \
3061                                '\nExpected:'+str(lenX)+ \
3062                                '\nFound:   '+str(len(x))+'\nfor '+name)
3063                            self.OnCancel(event)
3064                    else:
3065                        lenX = len(x)
3066                    if Xminmax[1]:
3067                        if Xminmax != [x[0],x[-1]]:
3068                            self.ErrorDialog('Data range error','Data to be summed must span same range'+ \
3069                                '\nExpected:'+str(Xminmax[0])+' '+str(Xminmax[1])+ \
3070                                '\nFound:   '+str(x[0])+' '+str(x[-1])+'\nfor '+name)
3071                            self.OnCancel(event)
3072                        else:
3073                            for j,yi in enumerate(y):
3074                                 Ysum[j] += scale*yi
3075                                 Vsum[j] += abs(scale)*v[j]
3076                    else:
3077                        Xminmax = [x[0],x[-1]]
3078                        Xsum = x
3079                        Ysum = scale*y
3080                        Vsum = abs(scale*v)
3081            Wsum = 1./np.array(Vsum)
3082            YCsum = np.zeros(lenX)
3083            YBsum = np.zeros(lenX)
3084            YDsum = np.zeros(lenX)
3085            XY.append([Xsum,Ysum])
3086            self.result = [Xsum,Ysum,Wsum,YCsum,YBsum,YDsum]
3087            # N.B. PlotXY expects the first arg to point to G2frame. In this case, we
3088            # create a duplicate (temporary) Plot notebook window that is a child of the
3089            # modal SumDialog dialog (self). This nicely gets deleted when the dialog is destroyed,
3090            # but the plot window is not fully functional, at least on the Mac.
3091            G2plt.PlotXY(self,XY,lines=True,Title='Sum:'+self.data[-1],labelY='Intensity',)
3092            self.plotFrame.Show()
3093                       
3094        def OnOk(self,event):
3095            if self.dataType == 'PWDR': self.OnTest(event)
3096            parent = self.GetParent()
3097            parent.Raise()
3098            self.EndModal(wx.ID_OK)             
3099           
3100        def OnCancel(self,event):
3101            parent = self.GetParent()
3102            parent.Raise()
3103            self.EndModal(wx.ID_CANCEL)             
3104           
3105        def GetData(self):
3106            if self.dataType == 'PWDR':
3107                return self.data,self.result
3108            else:
3109                return self.data
3110                       
3111    def OnPwdrSum(self,event):
3112        'Sum together powder data(?)'
3113        TextList = []
3114        DataList = []
3115        Names = []
3116        Inst = None
3117        Comments = ['Sum equals: \n']
3118        if self.PatternTree.GetCount():
3119            item, cookie = self.PatternTree.GetFirstChild(self.root)
3120            while item:
3121                name = self.PatternTree.GetItemText(item)
3122                Names.append(name)
3123                if 'PWDR' in name:
3124                    TextList.append([0.0,name])
3125                    DataList.append(self.PatternTree.GetItemPyData(item)[1])    # (x,y,w,yc,yb,yd)
3126                    if not Inst:
3127                        Inst = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item, 'Instrument Parameters'))
3128                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3129            if len(TextList) < 2:
3130                self.ErrorDialog('Not enough data to sum','There must be more than one "PWDR" pattern')
3131                return
3132            TextList.append('default_sum_name')               
3133            dlg = self.SumDialog(self,'Sum data','Enter scale for each pattern in summation','PWDR',TextList,DataList)
3134            try:
3135                if dlg.ShowModal() == wx.ID_OK:
3136                    result,sumData = dlg.GetData()
3137                    Xsum,Ysum,Wsum,YCsum,YBsum,YDsum = sumData
3138                    Xminmax = [Xsum[0],Xsum[-1]]
3139                    outname = 'PWDR '+result[-1]
3140                    Id = 0
3141                    if outname in Names:
3142                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
3143                        try:
3144                            if dlg2.ShowModal() == wx.ID_OK:
3145                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
3146                                self.PatternTree.Delete(Id)
3147                        finally:
3148                            dlg2.Destroy()
3149                    Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
3150                    if Id:
3151                        Sample = G2obj.SetDefaultSample()
3152                        Ymin = np.min(Ysum)
3153                        Ymax = np.max(Ysum)
3154                        valuesdict = {
3155                            'wtFactor':1.0,
3156                            'Dummy':False,
3157                            'ranId':ran.randint(0,sys.maxint),
3158                            'Offset':[0.0,0.0],'delOffset':0.02*Ymax,'refOffset':-.1*Ymax,'refDelt':0.1*Ymax,
3159                            'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
3160                            }
3161                        self.PatternTree.SetItemPyData(Id,[valuesdict,[np.array(Xsum),np.array(Ysum),np.array(Wsum),
3162                            np.array(YCsum),np.array(YBsum),np.array(YDsum)]])
3163                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
3164                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
3165                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',True,3,1.0,0.0,0.0],
3166                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
3167                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
3168                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
3169                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Peak List'),{'peaks':[],'sigDict':{}})
3170                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[[],[]])
3171                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
3172                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
3173                        self.PatternTree.SelectItem(Id)
3174                        self.PatternTree.Expand(Id)
3175            finally:
3176                dlg.Destroy()
3177
3178    def OnImageSum(self,event):
3179        'Sum together image data'
3180        TextList = []
3181        DataList = []
3182        IdList = []
3183        Names = []
3184        Comments = ['Sum equals: \n']
3185        if self.PatternTree.GetCount():
3186            item, cookie = self.PatternTree.GetFirstChild(self.root)
3187            while item:
3188                name = self.PatternTree.GetItemText(item)
3189                Names.append(name)
3190                if 'IMG' in name:
3191                    TextList.append([0.0,name])
3192                    DataList.append(self.PatternTree.GetImageLoc(item))        #Size,Image,Tag
3193                    IdList.append(item)
3194                    Data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item,'Image Controls'))
3195                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3196            if len(TextList) < 2:
3197                self.ErrorDialog('Not enough data to sum','There must be more than one "IMG" pattern')
3198                return
3199            TextList.append('default_sum_name')               
3200            dlg = self.SumDialog(self,'Sum data','Enter scale for each image in summation','IMG',TextList,DataList)
3201            try:
3202                if dlg.ShowModal() == wx.ID_OK:
3203                    imSize = 0
3204                    result = dlg.GetData()
3205                    First = True
3206                    Found = False
3207                    for i,item in enumerate(result[:-1]):
3208                        scale,name = item
3209                        if scale:
3210                            Found = True                               
3211                            Comments.append("%10.3f %s" % (scale,' * '+name))
3212                            Npix,imagefile,imagetag = DataList[i]
3213                            imagefile = G2IO.GetCheckImageFile(self,IdList[i])[1]
3214                            image = G2IO.GetImageData(self,imagefile,imageOnly=True,ImageTag=imagetag)
3215                            if First:
3216                                newImage = np.zeros_like(image)
3217                                First = False
3218                            if imSize:
3219                                if imSize != Npix:
3220                                    self.ErrorDialog('Image size error','Images to be summed must be same size'+ \
3221                                        '\nExpected:'+str(imSize)+ \
3222                                        '\nFound:   '+str(Npix)+'\nfor '+name)
3223                                    return
3224                                newImage = newImage+scale*image
3225                            else:
3226                                imSize = Npix
3227                                newImage = newImage+scale*image
3228                            del(image)
3229                    if not Found:
3230                        self.ErrorDialog('Image sum error','No nonzero image multipliers found')
3231                        return
3232                       
3233                       
3234                    newImage = np.array(newImage,dtype=np.int32)                       
3235                    outname = 'IMG '+result[-1]
3236                    Id = 0
3237                    if outname in Names:
3238                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
3239                        try:
3240                            if dlg2.ShowModal() == wx.ID_OK:
3241                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
3242                        finally:
3243                            dlg2.Destroy()
3244                    else:
3245                        Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
3246                    if Id:
3247                        pth = G2G.GetExportPath(self)
3248                        dlg = wx.FileDialog(self, 'Choose sum image filename', pth,outname.split('IMG ')[1], 
3249                            'G2img files (*.G2img)|*.G2img', 
3250                            wx.SAVE|wx.FD_OVERWRITE_PROMPT)
3251                        if dlg.ShowModal() == wx.ID_OK:
3252                            newimagefile = dlg.GetPath()
3253                            newimagefile = G2IO.FileDlgFixExt(dlg,newimagefile)
3254                            G2IO.PutG2Image(newimagefile,Comments,Data,Npix,newImage)
3255                            Imax = np.amax(newImage)
3256                            Imin = np.amin(newImage)
3257                            newImage = []
3258                            self.PatternTree.SetItemPyData(Id,[imSize,newimagefile])
3259                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
3260                        del(newImage)
3261                        if self.imageDefault:
3262                            Data = copy.copy(self.imageDefault)
3263                        Data['formatName'] = 'GSAS-II image'
3264                        Data['showLines'] = True
3265                        Data['ring'] = []
3266                        Data['rings'] = []
3267                        Data['cutoff'] = 10
3268                        Data['pixLimit'] = 20
3269                        Data['ellipses'] = []
3270                        Data['calibrant'] = ''
3271                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
3272                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)                                           
3273                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
3274                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
3275                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),
3276                            {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
3277                        self.PatternTree.SelectItem(Id)
3278                        self.PatternTree.Expand(Id)
3279                        self.PickId = G2gd.GetPatternTreeItemId(self,self.root,outname)
3280                        self.Image = self.PickId
3281            finally:
3282                dlg.Destroy()
3283                     
3284    def OnAddPhase(self,event):
3285        'Add a new, empty phase to the tree. Called by Data/Add Phase menu'
3286        if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3287            sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
3288        else:
3289            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3290        PhaseName = ''
3291        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
3292            style=wx.OK)
3293        if dlg.ShowModal() == wx.ID_OK:
3294            PhaseName = dlg.GetValue()
3295        dlg.Destroy()
3296        sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
3297        E,SGData = G2spc.SpcGroup('P 1')
3298        self.PatternTree.SetItemPyData(sub,G2obj.SetNewPhase(Name=PhaseName,SGData=SGData))
3299        G2gd.SelectDataTreeItem(self,sub) #bring up new phase General tab
3300       
3301    def OnDeletePhase(self,event):
3302        'Delete a phase from the tree. Called by Data/Delete Phase menu'
3303        #Hmm, also need to delete this phase from Reflection Lists for each PWDR histogram
3304        if self.dataFrame:
3305            self.dataFrame.Clear() 
3306        TextList = []
3307        DelList = []
3308        DelItemList = []
3309        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3310            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3311        else:
3312            return
3313        if sub:
3314            item, cookie = self.PatternTree.GetFirstChild(sub)
3315            while item:
3316                TextList.append(self.PatternTree.GetItemText(item))
3317                item, cookie = self.PatternTree.GetNextChild(sub, cookie)               
3318            dlg = wx.MultiChoiceDialog(self, 'Which phase to delete?', 'Delete phase', TextList, wx.CHOICEDLG_STYLE)
3319            try:
3320                if dlg.ShowModal() == wx.ID_OK:
3321                    result = dlg.GetSelections()
3322                    for i in result: DelList.append([i,TextList[i]])
3323                    item, cookie = self.PatternTree.GetFirstChild(sub)
3324                    i = 0
3325                    while item:
3326                        if [i,self.PatternTree.GetItemText(item)] in DelList: DelItemList.append(item)
3327                        item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3328                        i += 1
3329                    for item in DelItemList:
3330                        name = self.PatternTree.GetItemText(item)
3331                        self.PatternTree.Delete(item)
3332                        self.G2plotNB.Delete(name)
3333                    item, cookie = self.PatternTree.GetFirstChild(self.root)
3334                    while item:
3335                        name = self.PatternTree.GetItemText(item)
3336                        if 'PWDR' in name:
3337                            Id = G2gd.GetPatternTreeItemId(self,item, 'Reflection Lists')
3338                            refList = self.PatternTree.GetItemPyData(Id)
3339                            if len(refList):
3340                                for i,item in DelList:
3341                                    if item in refList:
3342                                        del(refList[item])
3343#                            self.PatternTree.SetItemPyData(Id,refList)
3344                        elif 'HKLF' in name:
3345                            data = self.PatternTree.GetItemPyData(item)
3346                            data[0] = {}
3347#                            self.PatternTree.SetItemPyData(item,data)
3348                           
3349                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3350            finally:
3351                dlg.Destroy()
3352               
3353    def OnRenameData(self,event):
3354        'Renames an existing phase. Called by Data/Rename Phase menu'
3355        name = self.PatternTree.GetItemText(self.PickId)     
3356        if 'PWDR' in name or 'HKLF' in name or 'IMG' in name:
3357            if 'Bank' in name:
3358                names = name.split('Bank')
3359                names[1] = ' Bank'+names[1]
3360            elif 'Azm' in name:
3361                names = name.split('Azm')
3362                names[1] = ' Azm'+names[1]
3363            else:
3364                names = [name,'']
3365            dataType = names[0][:names[0].index(' ')+1]                 #includes the ' '
3366            dlg = wx.TextEntryDialog(self,'Data name: '+name,'Change data name',
3367                defaultValue=names[0][names[0].index(' ')+1:])
3368            try:
3369                if dlg.ShowModal() == wx.ID_OK:
3370                    name = dataType+dlg.GetValue()+names[1]
3371                    self.PatternTree.SetItemText(self.PickId,name)
3372            finally:
3373                dlg.Destroy()
3374       
3375    def GetFileList(self,fileType,skip=None):        #potentially useful?
3376        'Appears unused. Note routine of same name in GSASIIpwdGUI'
3377        fileList = []
3378        Source = ''
3379        id, cookie = self.PatternTree.GetFirstChild(self.root)
3380        while id:
3381            name = self.PatternTree.GetItemText(id)
3382            if fileType in name:
3383                if id == skip:
3384                    Source = name
3385                else:
3386                    fileList.append([False,name,id])
3387            id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3388        if skip:
3389            return fileList,Source
3390        else:
3391            return fileList
3392           
3393    def OnDataDelete(self, event):
3394        '''Delete one or more histograms from data tree. Called by the
3395        Data/DeleteData menu
3396        '''
3397        TextList = []
3398        DelList = []
3399        DelItemList = []
3400        nItems = {'PWDR':0,'SASD':0,'REFD':0,'IMG':0,'HKLF':0,'PDF':0}
3401        PDFnames = []
3402        if self.PatternTree.GetCount():
3403            item, cookie = self.PatternTree.GetFirstChild(self.root)
3404            while item:
3405                name = self.PatternTree.GetItemText(item)
3406                if name not in ['Notebook','Controls','Covariance','Constraints',
3407                    'Restraints','Phases','Rigid bodies'] and 'Sequential' not in name:
3408                    if 'PWDR' in name[:4]: nItems['PWDR'] += 1
3409                    if 'SASD' in name[:4]: nItems['SASD'] += 1
3410                    if 'REFD' in name[:4]: nItems['REFD'] += 1
3411                    if 'IMG' in name[:3]:  nItems['IMG'] += 1
3412                    if 'HKLF' in name[:4]: nItems['HKLF'] += 1
3413                    if 'PDF' in name[:3]:
3414                        PDFnames.append(name)
3415                        nItems['PDF'] += 1
3416                    TextList.append(name)
3417                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3418            for pdfName in PDFnames:
3419                try:
3420                    TextList.remove('PWDR'+pdfName[4:])
3421                except ValueError:
3422                    print 'PWDR'+pdfName[4:]+' for '+pdfName+' not found'
3423            dlg = G2G.G2MultiChoiceDialog(self, 'Which data to delete?', 'Delete data', TextList, wx.CHOICEDLG_STYLE)
3424            try:
3425                if dlg.ShowModal() == wx.ID_OK:
3426                    result = dlg.GetSelections()
3427                    for i in result: DelList.append(TextList[i])
3428                    item, cookie = self.PatternTree.GetFirstChild(self.root)
3429                    while item:
3430                        itemName = self.PatternTree.GetItemText(item)
3431                        if itemName in DelList:
3432                            if 'PWDR' in itemName[:4]: nItems['PWDR'] -= 1
3433                            elif 'SASD' in itemName[:4]: nItems['SASD'] -= 1
3434                            elif 'REFD' in itemName[:4]: nItems['REFD'] -= 1
3435                            elif 'IMG' in itemName[:3]: nItems['IMG'] -= 1
3436                            elif 'HKLF' in itemName[:4]: nItems['HKLF'] -= 1
3437                            elif 'PDF' in itemName[:3]: nItems['PDF'] -= 1
3438                            DelItemList.append(item)
3439                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3440                    for item in DelItemList:
3441                        self.PatternTree.Delete(item)
3442                    self.PickId = 0
3443                    self.PickIdText = None
3444                    self.PatternId = 0
3445                    if nItems['PWDR']:
3446                        wx.CallAfter(G2plt.PlotPatterns,self,True)
3447                    else:
3448                        self.G2plotNB.Delete('Powder Patterns')
3449                    if not nItems['IMG']:
3450                        self.G2plotNB.Delete('2D Powder Image')
3451                    if not nItems['HKLF']:
3452                        self.G2plotNB.Delete('Structure Factors')
3453                        if '3D Structure Factors' in self.G2plotNB.plotList:
3454                            self.G2plotNB.Delete('3D Structure Factors')
3455            finally:
3456                dlg.Destroy()
3457
3458    def OnFileOpen(self, event, filename=None):
3459        '''Gets a GSAS-II .gpx project file in response to the
3460        File/Open Project menu button
3461        '''
3462        result = wx.ID_OK
3463        self.EnablePlot = False
3464        if self.PatternTree.GetChildrenCount(self.root,False):
3465            if self.dataFrame:
3466                self.dataFrame.ClearData() 
3467            dlg = wx.MessageDialog(
3468                self,
3469                'Do you want to overwrite the current project? '+
3470                'Any unsaved changes in current project will be lost. Press OK to continue.',
3471                'Overwrite?',  wx.OK | wx.CANCEL)
3472            try:
3473                result = dlg.ShowModal()
3474                if result == wx.ID_OK:
3475                    self.PatternTree.DeleteChildren(self.root)
3476                    self.GSASprojectfile = ''
3477                    self.HKL = []
3478                    if self.G2plotNB.plotList:
3479                        self.G2plotNB.clear()
3480            finally:
3481                dlg.Destroy()
3482        if result != wx.ID_OK: return
3483
3484        if not filename:
3485            if self.LastGPXdir:
3486                pth = self.LastGPXdir
3487            else:
3488                pth = '.'
3489            dlg = wx.FileDialog(self, 'Choose GSAS-II project file', pth, 
3490                wildcard='GSAS-II project file (*.gpx)|*.gpx',style=wx.OPEN)
3491            try:
3492                if dlg.ShowModal() != wx.ID_OK: return
3493                self.GSASprojectfile = dlg.GetPath()
3494                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
3495                self.dirname = dlg.GetDirectory()
3496            finally:
3497                dlg.Destroy()
3498        else:
3499            self.GSASprojectfile = os.path.splitext(filename)[0]+'.gpx'
3500            self.dirname = os.path.split(filename)[0]
3501
3502        try:
3503            self.StartProject()         #open the file if possible
3504        except:
3505            print '\nError opening file ',filename
3506            import traceback
3507            print traceback.format_exc()
3508       
3509    def StartProject(self):
3510        '''Opens a GSAS-II project file & selects the 1st available data set to
3511        display (PWDR, HKLF, REFD or SASD)
3512        '''
3513       
3514        Id = 0
3515        phaseId = None
3516        G2IO.ProjFileOpen(self)
3517        self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
3518        self.PatternTree.Expand(self.root)
3519        self.HKL = []
3520        item, cookie = self.PatternTree.GetFirstChild(self.root)
3521        while item and not Id:
3522            name = self.PatternTree.GetItemText(item)
3523            if name[:4] in ['PWDR','HKLF','IMG ','PDF ','SASD','REFD']:
3524                Id = item
3525            elif name == "Phases":
3526                phaseId = item
3527            elif name == 'Controls':
3528                data = self.PatternTree.GetItemPyData(item)
3529                if data:
3530                    for item in self.Refine: item.Enable(True)
3531                    self.EnableSeqRefineMenu()
3532            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3533        if phaseId: # show all phases
3534            self.PatternTree.Expand(phaseId)
3535        if Id:
3536            self.EnablePlot = True
3537            self.PatternTree.SelectItem(Id)
3538            self.PatternTree.Expand(Id)
3539        elif phaseId:
3540            self.PatternTree.SelectItem(phaseId)
3541        self.CheckNotebook()
3542        if self.dirname: os.chdir(self.dirname)           # to get Mac/Linux to change directory!
3543        pth = os.path.split(os.path.abspath(self.GSASprojectfile))[0]
3544        if GSASIIpath.GetConfigValue('Save_paths'): G2G.SaveGPXdirectory(pth)
3545        self.LastGPXdir = pth
3546
3547    def OnFileClose(self, event):
3548        '''Clears the data tree in response to the
3549        File/New Project menu button. User is given option to save
3550        the project.
3551        '''
3552#        dlg = wx.MessageDialog(self, 'Save current project?', ' ', wx.YES | wx.NO | wx.CANCEL)
3553        try:
3554            result = dlg.ShowModal()
3555            if result == wx.ID_OK:
3556                self.OnFileSaveMenu(event)
3557            if result != wx.ID_CANCEL:
3558                self.GSASprojectfile = ''
3559                self.PatternTree.SetItemText(self.root,'Loaded Data: ')
3560                self.PatternTree.DeleteChildren(self.root)
3561                if self.HKL: self.HKL = []
3562                if self.G2plotNB.plotList:
3563                    self.G2plotNB.clear()
3564        finally:
3565            dlg.Destroy()
3566
3567    def OnFileSave(self, event):
3568        '''Save the current project in response to the
3569        File/Save Project menu button
3570        '''
3571       
3572        if self.GSASprojectfile: 
3573            self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
3574            self.CheckNotebook()
3575            G2IO.ProjFileSave(self)
3576        else:
3577            self.OnFileSaveas(event)
3578
3579    def OnFileSaveas(self, event):
3580        '''Save the current project in response to the
3581        File/Save as menu button
3582        '''
3583        if GSASIIpath.GetConfigValue('Starting_directory'):
3584            pth = GSASIIpath.GetConfigValue('Starting_directory')
3585            pth = os.path.expanduser(pth) 
3586        elif self.LastGPXdir:
3587            pth = self.LastGPXdir
3588        else:
3589            pth = '.'
3590        dlg = wx.FileDialog(self, 'Choose GSAS-II project file name', pth, '', 
3591            'GSAS-II project file (*.gpx)|*.gpx',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
3592        try:
3593            if dlg.ShowModal() == wx.ID_OK:
3594                self.GSASprojectfile = dlg.GetPath()
3595                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
3596                self.PatternTree.SetItemText(self.root,'Saving project as'+self.GSASprojectfile)
3597                self.SetTitle("GSAS-II data tree: "+os.path.split(self.GSASprojectfile)[1])
3598                self.CheckNotebook()
3599                G2IO.ProjFileSave(self)
3600                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
3601        finally:
3602            dlg.Destroy()
3603           
3604    def ExpandAll(self,event):
3605        '''Expand all tree items or those of a single type
3606        '''
3607        txt = self.GetMenuBar().GetLabel(event.Id)
3608        if txt == 'all':
3609            self.ExpandingAll = True
3610            try:
3611                self.PatternTree.ExpandAll()
3612            finally:
3613                self.ExpandingAll = False
3614        else:
3615            self.ExpandingAll = True
3616            try:
3617                item, cookie = self.PatternTree.GetFirstChild(self.root)
3618                while item:
3619                    name = self.PatternTree.GetItemText(item)
3620                    if name.startswith(txt+' '): self.PatternTree.Expand(item)
3621                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3622            finally:
3623                self.ExpandingAll = False
3624
3625    def MoveTreeItems(self,event):
3626        '''Move tree items of a single type to the end of the tree
3627        '''
3628        txt = self.GetMenuBar().GetLabel(event.Id)
3629        # make a list of items to copy
3630        copyList = []
3631        item, cookie = self.PatternTree.GetFirstChild(self.root)
3632        while item:
3633            if self.PatternTree.GetItemText(item).startswith(txt+' '):
3634                copyList.append(item)
3635            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3636       
3637        self.ExpandingAll = True
3638        try:
3639            for item in copyList:
3640                name = self.PatternTree.GetItemText(item)
3641                newId = self.PatternTree.AppendItem(self.root,name)
3642                self.PatternTree.SetItemPyData(newId,self.PatternTree.GetItemPyData(item))
3643                chld, chldcookie = self.PatternTree.GetFirstChild(item)
3644                while chld:
3645                    chname = self.PatternTree.GetItemText(chld)
3646                    newCh = self.PatternTree.AppendItem(newId,chname)
3647                    self.PatternTree.SetItemPyData(newCh,self.PatternTree.GetItemPyData(chld))
3648                    chld, chldcookie = self.PatternTree.GetNextChild(item, chldcookie)
3649                self.PatternTree.Delete(item)
3650        finally:
3651            self.ExpandingAll = False
3652        G2gd.SelectDataTreeItem(self,self.root)
3653           
3654    def ExitMain(self, event):
3655        '''Called if the main window is closed'''
3656        if self.G2plotNB:
3657            self.G2plotNB.Destroy()
3658        if self.dataFrame:
3659            self.dataFrame.Destroy()
3660        if self.undofile:
3661            os.remove(self.undofile)
3662        sys.exit()
3663       
3664    def OnFileExit(self, event):
3665        '''Called in response to the File/Quit menu button'''
3666        if self.G2plotNB:
3667            self.G2plotNB.Destroy()
3668        if self.dataFrame:
3669            self.dataFrame.Destroy()
3670        self.Close()
3671       
3672    def OnExportPeakList(self,event):
3673        nptand = lambda x: np.tan(x*math.pi/180.)
3674        pth = G2G.GetExportPath(self)
3675        dlg = wx.FileDialog(self, 'Choose output peak list file name', pth, '', 
3676            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
3677        try:
3678            if dlg.ShowModal() == wx.ID_OK:
3679                self.peaklistfile = dlg.GetPath()
3680                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
3681                file = open(self.peaklistfile,'w')               
3682                item, cookie = self.PatternTree.GetFirstChild(self.root)
3683                while item:
3684                    name = self.PatternTree.GetItemText(item)
3685                    if 'PWDR' in name:
3686                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
3687                        wave = 0.0
3688                        while item2:
3689                            name2 = self.PatternTree.GetItemText(item2)
3690                            if name2 == 'Instrument Parameters':
3691                                Inst = self.PatternTree.GetItemPyData(item2)[0]
3692                                Type = Inst['Type'][0]
3693                                if 'T' not in Type:
3694                                    wave = G2mth.getWave(Inst)
3695                            elif name2 == 'Peak List':
3696                                pkdata = self.PatternTree.GetItemPyData(item2)
3697                                peaks = pkdata['peaks']
3698                                sigDict = pkdata['sigDict']
3699                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
3700                        file.write("#%s \n" % (name+' Peak List'))
3701                        if wave:
3702                            file.write('#wavelength = %10.6f\n'%(wave))
3703                        if 'T' in Type:
3704                            file.write('#%9s %10s %10s %12s %10s %10s %10s %10s %10s\n'%('pos','dsp','esd','int','alp','bet','sig','gam','FWHM'))                                   
3705                        else:
3706                            file.write('#%9s %10s %10s %12s %10s %10s %10s\n'%('pos','dsp','esd','int','sig','gam','FWHM'))
3707                        for ip,peak in enumerate(peaks):
3708                            dsp = G2lat.Pos2dsp(Inst,peak[0])
3709                            if 'T' in Type:  #TOF - more cols
3710                                esds = {'pos':0.,'int':0.,'alp':0.,'bet':0.,'sig':0.,'gam':0.}
3711                                for name in esds.keys():
3712                                    esds[name] = sigDict.get('%s%d'%(name,ip),0.)
3713                                sig = np.sqrt(peak[8])
3714                                gam = peak[10]
3715                                esddsp = G2lat.Pos2dsp(Inst,esds['pos'])
3716                                FWHM = G2pwd.getgamFW(gam,sig)      #to get delta-TOF from Gam(peak)
3717                                file.write("%10.2f %10.5f %10.5f %12.2f %10.3f %10.3f %10.3f %10.3f %10.3f\n" % \
3718                                    (peak[0],dsp,esddsp,peak[2],np.sqrt(max(0.0001,peak[4])),peak[6],peak[8],peak[10],FWHM))
3719                            else:               #CW
3720                                #get esds from sigDict for each peak & put in output - esds for sig & gam from UVWXY?
3721                                esds = {'pos':0.,'int':0.,'sig':0.,'gam':0.}
3722                                for name in esds.keys():
3723                                    esds[name] = sigDict.get('%s%d'%(name,ip),0.)
3724                                sig = np.sqrt(peak[4]) #var -> sig
3725                                gam = peak[6]
3726                                esddsp = 0.5*esds['pos']*dsp/nptand(peak[0]/2.)
3727                                FWHM = G2pwd.getgamFW(gam,sig)      #to get delta-2-theta in deg. from Gam(peak)
3728                                file.write("%10.4f %10.5f %10.5f %12.2f %10.5f %10.5f %10.5f \n" % \
3729                                    (peak[0],dsp,esddsp,peak[2],np.sqrt(max(0.0001,peak[4]))/100.,peak[6]/100.,FWHM/100.)) #convert to deg
3730                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
3731                file.close()
3732        finally:
3733            dlg.Destroy()
3734       
3735    def OnExportHKL(self,event):
3736        pth = G2G.GetExportPath(self)
3737        dlg = wx.FileDialog(self, 'Choose output reflection list file name', pth, '', 
3738            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
3739        try:
3740            if dlg.ShowModal() == wx.ID_OK:
3741                self.peaklistfile = dlg.GetPath()
3742                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
3743                file = open(self.peaklistfile,'w')               
3744                item, cookie = self.PatternTree.GetFirstChild(self.root)
3745                while item:
3746                    name = self.PatternTree.GetItemText(item)
3747                    if 'PWDR' in name:
3748                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
3749                        while item2:
3750                            name2 = self.PatternTree.GetItemText(item2)
3751                            if name2 == 'Reflection Lists':
3752                                data = self.PatternTree.GetItemPyData(item2)
3753                                phases = data.keys()
3754                                for phase in phases:
3755                                    peaks = data[phase]
3756                                    I100 = peaks['RefList'].T[8]*np.array([refl[11] for refl in peaks['RefList']])
3757                                    Imax = np.max(I100)
3758                                    if Imax:
3759                                        I100 *= 100.0/Imax
3760                                    file.write("%s %s %s \n" % (name,phase,' Reflection List'))
3761                                    if 'T' in peaks.get('Type','PXC'):
3762                                        file.write('%s \n'%('   h   k   l   m   d-space       TOF       wid     Fo**2     Fc**2     Icorr      Prfo     Trans      ExtP      I100'))
3763                                    else:               
3764                                        file.write('%s \n'%('   h   k   l   m   d-space   2-theta       wid     Fo**2     Fc**2     Icorr      Prfo     Trans      ExtP      I100'))
3765                                    for ipk,peak in enumerate(peaks['RefList']):
3766                                        if 'T' in peaks.get('Type','PXC'):
3767                                            sig = np.sqrt(peak[6])
3768                                            gam = peak[7]
3769                                            FWHM = G2pwd.getgamFW(gam,sig)
3770                                            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" % \
3771                                                (int(peak[0]),int(peak[1]),int(peak[2]),int(peak[3]),peak[4],peak[5],FWHM,peak[8],
3772                                                peak[9],peak[11],peak[12],peak[13],peak[14],I100[ipk]))
3773                                        else:
3774                                            sig = np.sqrt(peak[6])
3775                                            gam = peak[7]
3776                                            FWHM = G2pwd.getgamFW(gam,sig)
3777                                            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" % \
3778                                                (int(peak[0]),int(peak[1]),int(peak[2]),int(peak[3]),peak[4],peak[5],FWHM/100.,
3779                                                peak[8],peak[9],peak[11],peak[12],peak[13],peak[14],I100[ipk]))
3780                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
3781                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
3782                file.close()
3783        finally:
3784            dlg.Destroy()
3785       
3786    def OnExportPDF(self,event):
3787        #need S(Q) and G(R) to be saved here - probably best from selection?
3788        names = G2pdG.GetFileList(self,'PDF')
3789        exports = []
3790        if names:
3791            od = {'label_1':'Export I(Q)','value_1':False,'label_2':'Export S(Q)','value_2':False,
3792                  'label_3':'Export F(Q)','value_3':False,'label_4':'Export G(R)','value_4':True,
3793                  'label_5':'Make G(R) for pdfGUI','value_5':False}
3794            dlg = G2G.G2MultiChoiceDialog(self,'Select','PDF patterns to export',names,extraOpts=od)
3795            if dlg.ShowModal() == wx.ID_OK:
3796                sel = dlg.GetSelections()
3797                for x in sel:
3798                    exports.append(names[x])
3799            dlg.Destroy()
3800        if exports:
3801            PDFsaves = [od['value_1'],od['value_2'],od['value_3'],od['value_4'],od['value_5']]
3802            G2IO.PDFSave(self,exports,PDFsaves)
3803       
3804    def OnMakePDFs(self,event):
3805        '''Sets up PDF data structure filled with defaults; if found chemical formula is inserted
3806        so a default PDF can be made.
3807        '''
3808        sind = lambda x: math.sin(x*math.pi/180.)
3809        tth2q = lambda t,w:4.0*math.pi*sind(t/2.0)/w
3810        tof2q = lambda t,C:2.0*math.pi*C/t
3811        TextList = []
3812        ElLists = []
3813        Qlimits = []
3814        Names = []
3815        if self.PatternTree.GetCount():
3816            id, cookie = self.PatternTree.GetFirstChild(self.root)
3817            while id:
3818                name = self.PatternTree.GetItemText(id)
3819                Names.append(name)
3820                if 'PWDR' in name:
3821                    TextList.append(name)
3822                    Data = self.PatternTree.GetItemPyData(id)[1]
3823                    pwdrMin = np.min(Data[1])
3824                    Comments = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,id,'Comments'))
3825                    Parms = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,id,'Instrument Parameters'))[0]
3826                    fullLimits = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,id,'Limits'))[0]
3827                    if 'C' in Parms['Type'][0]:
3828                        wave = G2mth.getWave(Parms)
3829                        qMax = tth2q(fullLimits[1],wave)
3830                    else:   #'T'of
3831                        qMax = tof2q(fullLimits[0],Parms['difC'][1])
3832                    Qlimits.append([0.9*qMax,qMax])
3833                    ElList = {}
3834                    sumnum = 1.
3835                    for item in Comments:           #grab chemical formula from Comments
3836                        if 'formula' in item[:15].lower():
3837                            formula = item.split('=')[1].split()
3838                            try:
3839                                elems = formula[::2]
3840                                nums = formula[1::2]
3841                                Formula = zip(elems,nums)
3842                                sumnum = 0.
3843                                for [elem,num] in Formula:
3844                                    ElData = G2elem.GetElInfo(elem,Parms)
3845                                    ElData['FormulaNo'] = float(num)
3846                                    sumnum += float(num)
3847                                    ElList[elem] = ElData
3848                               
3849                            except ValueError:
3850                                ElData = G2elem.GetElInfo(formula[0],Parms)
3851                                ElData['FormulaNo'] = 1.0
3852                                ElList[elem] = ElData
3853                    ElLists.append(ElList)
3854                id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
3855            if len(TextList) < 1:
3856                self.ErrorDialog('Nothing to make PDFs for','There must be at least one "PWDR" pattern')
3857                return
3858            dlg = G2G.G2MultiChoiceDialog(self,'Make PDF controls','Make PDF controls for:',TextList, wx.CHOICEDLG_STYLE)
3859            try:
3860                if dlg.ShowModal() == wx.ID_OK:
3861                    for i in dlg.GetSelections():
3862                        PDFnames = G2gd.GetPatternTreeDataNames(self,['PDF ',])
3863                        G2obj.CreatePDFitems(self,TextList[i],ElLists[i],Qlimits[i],sumnum,pwdrMin,PDFnames)
3864                for item in self.ExportPDF: item.Enable(True)
3865            finally:
3866                dlg.Destroy()
3867               
3868    def GetPWDRdatafromTree(self,PWDRname):
3869        ''' Returns powder data from GSASII tree
3870
3871        :param str PWDRname: a powder histogram name as obtained from
3872          :meth:`GSASIIstruct.GetHistogramNames`
3873
3874        :returns: PWDRdata = powder data dictionary with
3875          Powder data arrays, Limits, Instrument Parameters,
3876          Sample Parameters           
3877        '''
3878        PWDRdata = {}
3879        try:
3880            PWDRdata.update(self.PatternTree.GetItemPyData(PWDRname)[0])            #wtFactor + ?
3881        except ValueError:
3882            PWDRdata['wtFactor'] = 1.0
3883        PWDRdata['Data'] = self.PatternTree.GetItemPyData(PWDRname)[1]          #powder data arrays
3884        PWDRdata['Limits'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Limits'))
3885        PWDRdata['Background'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Background'))
3886        PWDRdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Instrument Parameters'))
3887        PWDRdata['Sample Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Sample Parameters'))
3888        PWDRdata['Reflection Lists'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Reflection Lists'))
3889        if 'ranId' not in PWDRdata:  # patch, add a random Id
3890            PWDRdata['ranId'] = ran.randint(0,sys.maxint)
3891        if 'ranId' not in PWDRdata['Sample Parameters']:  # I hope this becomes obsolete at some point
3892            PWDRdata['Sample Parameters']['ranId'] = PWDRdata['ranId']
3893        return PWDRdata
3894
3895    def GetHKLFdatafromTree(self,HKLFname):
3896        ''' Returns single crystal data from GSASII tree
3897
3898        :param str HKLFname: a single crystal histogram name as obtained
3899          from
3900          :meth:`GSASIIstruct.GetHistogramNames`
3901
3902        :returns: HKLFdata = single crystal data list of reflections
3903
3904        '''
3905        HKLFdata = {}
3906        HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
3907#        try:
3908#            HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
3909#        except ValueError:
3910#            HKLFdata['wtFactor'] = 1.0
3911        HKLFdata['Data'] = self.PatternTree.GetItemPyData(HKLFname)[1]
3912        HKLFdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,HKLFname,'Instrument Parameters'))
3913        return HKLFdata
3914       
3915    def GetPhaseData(self):
3916        '''Returns a dict with defined phases.
3917        Note routine :func:`GSASIIstrIO.GetPhaseData` also exists to
3918        get same info from GPX file.
3919        '''
3920        phaseData = {}
3921        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3922            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3923        else:
3924            print 'no phases found in GetPhaseData'
3925            sub = None
3926        if sub:
3927            item, cookie = self.PatternTree.GetFirstChild(sub)
3928            while item:
3929                phaseName = self.PatternTree.GetItemText(item)
3930                phaseData[phaseName] =  self.PatternTree.GetItemPyData(item)
3931                if 'ranId' not in phaseData[phaseName]:
3932                    phaseData[phaseName]['ranId'] = ran.randint(0,sys.maxint)         
3933                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3934        return phaseData
3935
3936    def GetPhaseInfofromTree(self):
3937        '''Get the phase names and their rId values,
3938        also the histograms used in each phase.
3939
3940        :returns: (phaseRIdList, usedHistograms) where
3941
3942          * phaseRIdList is a list of random Id values for each phase
3943          * usedHistograms is a dict where the keys are the phase names
3944            and the values for each key are a list of the histogram names
3945            used in each phase.
3946        '''
3947        phaseRIdList = []
3948        usedHistograms = {}
3949        sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3950        if sub:
3951            item, cookie = self.PatternTree.GetFirstChild(sub)
3952            while item:
3953                phaseName = self.PatternTree.GetItemText(item)
3954                ranId = self.PatternTree.GetItemPyData(item).get('ranId')
3955                if ranId: phaseRIdList.append(ranId)
3956                data = self.PatternTree.GetItemPyData(item)
3957                UseList = data['Histograms']
3958                usedHistograms[phaseName] = UseList.keys()
3959                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3960        return phaseRIdList,usedHistograms
3961
3962    def GetPhaseNames(self):
3963        '''Returns a list of defined phases.
3964        Note routine :func:`GSASIIstrIO.GetPhaseNames` also exists to
3965        get same info from GPX file.
3966        '''
3967        phaseNames = []
3968        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
3969            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
3970        else:
3971            print 'no phases found in GetPhaseNames'
3972            sub = None
3973        if sub:
3974            item, cookie = self.PatternTree.GetFirstChild(sub)
3975            while item:
3976                phase = self.PatternTree.GetItemText(item)
3977                phaseNames.append(phase)
3978                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
3979        return phaseNames
3980   
3981    def GetHistogramNames(self,hType):
3982        """ Returns a list of histogram names found in the GSASII data tree
3983        Note routine :func:`GSASIIstrIO.GetHistogramNames` also exists to
3984        get same info from GPX file.
3985       
3986        :param str hType: list of histogram types
3987        :return: list of histogram names
3988       
3989        """
3990        HistogramNames = []
3991        if self.PatternTree.GetCount():
3992            item, cookie = self.PatternTree.GetFirstChild(self.root)
3993            while item:
3994                name = self.PatternTree.GetItemText(item)
3995                if name[:4] in hType:
3996                    HistogramNames.append(name)       
3997                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
3998
3999        return HistogramNames
4000                   
4001    def GetUsedHistogramsAndPhasesfromTree(self):
4002        ''' Returns all histograms that are found in any phase
4003        and any phase that uses a histogram.
4004        This also assigns numbers to used phases and histograms by the
4005        order they appear in the file.
4006        Note routine :func:`GSASIIstrIO.GetUsedHistogramsAndPhasesfromTree` also exists to
4007        get same info from GPX file.
4008
4009        :returns: (Histograms,Phases)
4010
4011            * Histograms = dictionary of histograms as {name:data,...}
4012            * Phases = dictionary of phases that use histograms
4013        '''
4014        Histograms = {}
4015        Phases = {}
4016        phaseNames = self.GetPhaseNames()
4017        phaseData = self.GetPhaseData()
4018        histoList = self.GetHistogramNames(['PWDR','HKLF'])
4019
4020        for phase in phaseData:
4021            Phase = phaseData[phase]
4022            pId = phaseNames.index(phase)
4023            Phase['pId'] = pId
4024            if Phase['Histograms']:
4025                if phase not in Phases:
4026                    Phases[phase] = Phase
4027                for hist in Phase['Histograms']:
4028                    if 'Use' not in Phase['Histograms'][hist]:      #patch: add Use flag as True
4029                        Phase['Histograms'][hist]['Use'] = True         
4030                    if hist not in Histograms and Phase['Histograms'][hist]['Use']:
4031                        item = G2gd.GetPatternTreeItemId(self,self.root,hist)
4032                        if item:
4033                            if 'PWDR' in hist[:4]: 
4034                                Histograms[hist] = self.GetPWDRdatafromTree(item)
4035                            elif 'HKLF' in hist[:4]:
4036                                Histograms[hist] = self.GetHKLFdatafromTree(item)
4037                            hId = histoList.index(hist)
4038                            Histograms[hist]['hId'] = hId
4039                        else: # would happen if a referenced histogram were renamed or deleted
4040                            print('For phase "'+phase+
4041                                  '" unresolved reference to histogram "'+hist+'"')
4042        #G2obj.IndexAllIds(Histograms=Histograms,Phases=Phases)
4043        G2obj.IndexAllIds(Histograms=Histograms,Phases=phaseData)
4044        return Histograms,Phases
4045       
4046    def MakeLSParmDict(self):
4047        '''Load all parameters used for computation from the tree into a
4048        dict of paired values [value, refine flag]. Note that this is
4049        different than the parmDict used in the refinement, which only has
4050        values.
4051
4052        Note that similar things are done in
4053        :meth:`GSASIIIO.ExportBaseclass.loadParmDict` (from the tree) and
4054        :func:`GSASIIstrMain.Refine` and :func:`GSASIIstrMain.SeqRefine` (from
4055        a GPX file).
4056
4057        :returns: (parmDict,varyList) where:
4058
4059         * parmDict is a dict with values and refinement flags
4060           for each parameter and
4061         * varyList is a list of variables (refined parameters).
4062        '''
4063        parmDict = {}
4064        Histograms,Phases = self.GetUsedHistogramsAndPhasesfromTree()
4065        for phase in Phases:
4066            if 'pId' not in Phases[phase]:
4067                self.ErrorDialog('View parameter error','You must run least squares at least once')
4068                raise Exception,'No pId for phase '+phase
4069        rigidbodyDict = self.PatternTree.GetItemPyData(   
4070            G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'))
4071        rbVary,rbDict = G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
4072        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
4073        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable,MFtable,maxSSwave = G2stIO.GetPhaseData(Phases,RestraintDict=None,rbIds=rbIds,Print=False)       
4074        hapVary,hapDict,controlDict = G2stIO.GetHistogramPhaseData(Phases,Histograms,Print=False)
4075        histVary,histDict,controlDict = G2stIO.GetHistogramData(Histograms,Print=False)
4076        varyList = rbVary+phaseVary+hapVary+histVary
4077        parmDict.update(rbDict)
4078        parmDict.update(phaseDict)
4079        parmDict.update(hapDict)
4080        parmDict.update(histDict)
4081        for parm in parmDict:
4082            if parm.split(':')[-1] in ['Azimuth','Gonio. radius','Lam1','Lam2',
4083                'Omega','Chi','Phi','nDebye','nPeaks']:
4084                parmDict[parm] = [parmDict[parm],'-']
4085            elif parm.split(':')[-2] in ['Ax','Ay','Az','SHmodel','SHord']:
4086                parmDict[parm] = [parmDict[parm],'-']
4087            elif parm in varyList:
4088                parmDict[parm] = [parmDict[parm],'T']
4089            else:
4090                parmDict[parm] = [parmDict[parm],'F']
4091        # for i in parmDict: print i,'\t',parmDict[i]
4092        # fl = open('parmDict.dat','wb')
4093        # import cPickle
4094        # cPickle.dump(parmDict,fl,1)
4095        # fl.close()
4096        return parmDict,varyList
4097
4098    def OnShowLSParms(self,event):
4099        '''Displays a window showing all parameters in the refinement.
4100        Called from the Calculate/View LS Parms menu.
4101        '''
4102        try:
4103            parmDict,varyList = self.MakeLSParmDict()
4104        except:
4105            print('Error retrieving parameters')
4106            return
4107        parmValDict = {}
4108        for i in parmDict:
4109            parmValDict[i] = parmDict[i][0]
4110           
4111        reqVaryList = tuple(varyList) # save requested variables
4112        try:
4113            # process constraints
4114            sub = G2gd.GetPatternTreeItemId(self,self.root,'Constraints') 
4115            Constraints = self.PatternTree.GetItemPyData(sub)
4116            constList = []
4117            for item in Constraints:
4118                if item.startswith('_'): continue
4119                constList += Constraints[item]
4120            G2mv.InitVars()
4121            constrDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
4122            groups,parmlist = G2mv.GroupConstraints(constrDict)
4123            G2mv.GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmValDict)
4124            G2mv.Map2Dict(parmValDict,varyList)
4125        except:
4126            pass
4127        dlg = G2gd.ShowLSParms(self,'Least Squares Parameters',parmValDict,varyList,reqVaryList)
4128        dlg.ShowModal()
4129        dlg.Destroy()
4130
4131    def OnRefine(self,event):
4132        '''Perform a refinement.
4133        Called from the Calculate/Refine menu.
4134        '''
4135        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
4136        if Id:
4137            dlg = wx.MessageDialog(
4138                self,
4139                'Your last refinement was sequential. Continue with "Refine", removing previous sequential results?',
4140                'Remove sequential results?',wx.OK|wx.CANCEL)
4141            if dlg.ShowModal() == wx.ID_OK:
4142                self.PatternTree.Delete(Id)
4143                dlg.Destroy()
4144            else:
4145                dlg.Destroy()
4146                return
4147        self.OnFileSave(event)
4148        # check that constraints are OK here
4149        errmsg, warnmsg = G2stIO.ReadCheckConstraints(self.GSASprojectfile)
4150        if errmsg:
4151            self.ErrorDialog('Refinement error',errmsg)
4152            return
4153        if warnmsg:
4154            print('Conflict between refinment flag settings and constraints:\n'+
4155                warnmsg+'\nRefinement not possible')
4156            self.ErrorDialog('Refinement Flag Error',
4157                'Conflict between refinement flag settings and constraints:\n'+
4158                warnmsg+'\nRefinement not possible')
4159            return
4160        dlg = wx.ProgressDialog('Residual','All data Rw =',101.0, 
4161            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT,
4162            parent=self)
4163        Size = dlg.GetSize()
4164        if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
4165            dlg.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
4166        dlg.CenterOnParent()
4167        Rw = 100.00
4168        self.SaveTreeSetting()
4169        self.PatternTree.SaveExposedItems()       
4170        try:
4171            OK,Msg = G2stMn.Refine(self.GSASprojectfile,dlg)    #Msg is Rvals dict if Ok=True
4172        finally:
4173            dlg.Update(101.) # forces the Auto_Hide; needed after move w/Win & wx3.0
4174            dlg.Destroy()
4175            wx.Yield()
4176        if OK:
4177            Rw = Msg['Rwp']
4178            lamMax = Msg.get('lamMax',0.001)
4179            lst = os.path.splitext(os.path.abspath(self.GSASprojectfile))[0]
4180            text = u'Detailed results are in '+lst+'.lst\n\nLoad new result?'
4181            if lamMax >= 10.:
4182                text += '\nWARNING: Steepest descents dominates;'+   \
4183                ' minimum may not have been reached\nor result may be false minimum.'+  \
4184                ' You should reconsider your parameter suite'
4185            dlg2 = wx.MessageDialog(self,text,'Refinement results, Rw =%.3f'%(Rw),wx.OK|wx.CANCEL)
4186            try:
4187                if dlg2.ShowModal() == wx.ID_OK:
4188                    self.PatternTree.DeleteChildren(self.root)
4189                    self.HKL = []
4190                    G2IO.ProjFileOpen(self,False)
4191                    self.PatternTree.RestoreExposedItems()       
4192                    self.ResetPlots()
4193            finally:
4194                dlg2.Destroy()
4195        else:
4196            self.ErrorDialog('Refinement error',Msg)
4197       
4198    def SaveTreeSetting(self):
4199        'Save the last tree setting'
4200        oldId =  self.PatternTree.GetSelection()        #retain current selection
4201        oldPath = self.GetTreeItemsList(oldId)
4202        self.lastTreeSetting = oldPath
4203        # note that for reasons unclear, it does not seem necessary to reload the Atoms tab
4204        #parentName = ''
4205        #tabId = None
4206        # parentId = self.PatternTree.GetItemParent(oldId)
4207        # if parentId:
4208        #     parentName = self.PatternTree.GetItemText(parentId)     #find the current data tree name
4209        #     if 'Phases' in parentName:
4210        #         tabId = self.dataDisplay.GetSelection()
4211        #self.lastTreeSetting = oldPath,tabId
4212        #GSASIIpath.IPyBreak()
4213       
4214    def TestResetPlot(self,event):
4215        '''Debug code to test cleaning up plots after a refinement'''
4216        #for i in range(self.G2plotNB.nb.GetPageCount()):
4217        #    [self.G2plotNB.nb.GetPageText(i)
4218        # save current tree item and (if needed) atoms tab
4219        self.SaveTreeSetting()
4220        self.ResetPlots()
4221       
4222    def ResetPlots(self):
4223        '''This reloads the current tree item, often drawing a plot. It refreshes any plots
4224        that have registered a refresh routine (see G2plotNB.RegisterRedrawRoutine)
4225        and deletes all plots that have not been refreshed and
4226        require one (see G2plotNB.SetNoDelete).
4227        '''
4228        lastRaisedPlotTab = self.G2plotNB.lastRaisedPlotTab # save the last page saved
4229        #print 'lastRaisedPlotTab=',lastRaisedPlotTab
4230        self.G2plotNB.lastRaisedPlotTab = None
4231        # mark displayed plots as invalid
4232        for lbl,frame in zip(self.G2plotNB.plotList,self.G2plotNB.panelList):
4233            frame.plotInvalid = True
4234        # reload current tree item, triggering the routine to redraw the data window and possibly a plot
4235        #oldPath,tabId = self.lastTreeSetting
4236        oldPath = self.lastTreeSetting
4237        Id = self.root
4238        for txt in oldPath:
4239            Id = G2gd.GetPatternTreeItemId(self, Id, txt)
4240        self.PickIdText = None  #force reload of page
4241        if Id:
4242            self.PickId = Id
4243            self.PatternTree.SelectItem(Id)
4244        # update other self-updating plots
4245#        for lbl,frame in zip(self.G2plotNB.plotList,self.G2plotNB.panelList):
4246#            if frame.plotInvalid and frame.replotFunction:
4247#                frame.replotFunction(*frame.replotArgs,**frame.replotKWargs)
4248        # delete any remaining plots that are still invalid and need a refresh
4249        for lbl,frame in zip(self.G2plotNB.plotList,self.G2plotNB.panelList):
4250            if frame.plotInvalid and frame.plotRequiresRedraw:
4251                self.G2plotNB.Delete(lbl)
4252        # put the previously last-raised tab on top, if present. If not, use the one corresponding to
4253        # the last tree item to be selected
4254        wx.CallAfter(self.G2plotNB.RaiseLastPage,lastRaisedPlotTab,self.G2plotNB.lastRaisedPlotTab)
4255       
4256    def OnSeqRefine(self,event):
4257        '''Perform a sequential refinement.
4258        Called from the Calculate/Sequential refine menu.
4259        '''
4260        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
4261        if not Id:
4262            Id = self.PatternTree.AppendItem(self.root,text='Sequential results')
4263            self.PatternTree.SetItemPyData(Id,{})           
4264        self.G2plotNB.Delete('Sequential refinement')    #clear away probably invalid plot
4265        Controls = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,self.root, 'Controls'))
4266        if not Controls.get('Seq Data'):
4267            print('Error: a sequential refinement has not been set up')
4268            return
4269        Controls['ShowCell'] = True
4270        self.OnFileSave(event)
4271        # check that constraints are OK here
4272        errmsg, warnmsg = G2stIO.ReadCheckConstraints(self.GSASprojectfile)
4273        if errmsg:
4274            self.ErrorDialog('Refinement error',errmsg)
4275            return
4276        if warnmsg:
4277            print('Conflict between refinment flag settings and constraints:\n'+
4278                  warnmsg+'\nRefinement not possible')
4279            self.ErrorDialog('Refinement Flag Error',
4280                             'Conflict between refinment flag settings and constraints:\n'+
4281                             warnmsg+'\nRefinement not possible')
4282            return
4283        self.PatternTree.SaveExposedItems()       
4284        dlg = wx.ProgressDialog('Residual for histogram 0','Powder profile Rwp =',101.0, 
4285            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT,
4286            parent=self)           
4287        Size = dlg.GetSize()
4288        if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
4289            dlg.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
4290        dlg.CenterOnParent()
4291        try:
4292            OK,Msg = G2stMn.SeqRefine(self.GSASprojectfile,dlg,G2plt.SequentialPlotPattern,self)     #Msg is Rvals dict if Ok=True
4293        finally:
4294            dlg.Update(101.) # forces the Auto_Hide; needed after move w/Win & wx3.0
4295            dlg.Destroy()
4296            wx.Yield()
4297        if OK:
4298            dlg = wx.MessageDialog(self,'Load new result?','Refinement results',wx.OK|wx.CANCEL)
4299            try:
4300                if dlg.ShowModal() == wx.ID_OK:
4301                    self.PickIdText = None  #force reload of PickId contents
4302                    self.PatternTree.DeleteChildren(self.root)
4303                    if len(self.HKL): self.HKL = []
4304                    if self.G2plotNB.plotList:
4305                        self.G2plotNB.clear()
4306                    G2IO.ProjFileOpen(self,False)
4307                    self.PatternTree.RestoreExposedItems()
4308                    self.ResetPlots()
4309                    Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequential results')
4310                    self.PatternTree.SelectItem(Id)
4311            finally:
4312                dlg.Destroy()
4313            self.SeqTblHideList = []
4314        else:
4315            self.ErrorDialog('Sequential refinement error',Msg)
4316       
4317    def ErrorDialog(self,title,message,parent=None, wtype=wx.OK):
4318        'Display an error message'
4319        result = None
4320        if parent is None:
4321            dlg = wx.MessageDialog(self, message, title,  wtype)
4322        else:
4323            dlg = wx.MessageDialog(parent, message, title,  wtype)
4324            dlg.CenterOnParent() # not working on Mac
4325        try:
4326            result = dlg.ShowModal()
4327        finally:
4328            dlg.Destroy()
4329        return result
4330   
4331    def OnSaveMultipleImg(self,event):
4332        '''Select and save multiple image parameter and mask files
4333        '''
4334        G2IO.SaveMultipleImg(self)
4335       
4336class GSASIImain(wx.App):
4337    '''Defines a wxApp for GSAS-II
4338
4339    Creates a wx frame (self.main) which contains the display of the
4340    data tree.
4341    '''
4342    def OnInit(self):
4343        '''Called automatically when the app is created.'''
4344        import platform
4345        if '2.7' not in sys.version[:5]:
4346            dlg = wx.MessageDialog(None, 
4347                'GSAS-II requires Python 2.7.x\n Yours is '+sys.version.split()[0],
4348                'Python version error',  wx.OK)
4349            try:
4350                dlg.ShowModal()
4351            finally:
4352                dlg.Destroy()
4353            sys.exit()
4354        self.main = GSASII(None)
4355        self.main.Show()
4356        self.SetTopWindow(self.main)
4357        # save the current package versions
4358        self.main.PackageVersions = []
4359        self.main.PackageVersions.append(['Python',sys.version.split()[0]])
4360        for p in (wx,mpl,np,sp,ogl):
4361            self.main.PackageVersions.append([p.__name__,p.__version__])
4362        try:
4363            self.main.PackageVersions.append([Image.__name__,Image.VERSION])
4364        except:
4365            try:
4366                from PIL import PILLOW_VERSION
4367                self.main.PackageVersions.append([Image.__name__,PILLOW_VERSION])
4368            except:
4369                pass
4370        self.main.PackageVersions.append(['Platform',sys.platform+' '+platform.architecture()[0]+' '+platform.machine()])
4371       
4372        return True
4373    # def MacOpenFile(self, filename):
4374    #     '''Called on Mac every time a file is dropped on the app when it is running,
4375    #     treat this like a File/Open project menu action.
4376    #     Should be ignored on other platforms
4377    #     '''
4378    #     # PATCH: Canopy 1.4 script main seems dropped on app; ignore .py files
4379    #     print 'MacOpen',filename
4380    #     if os.path.splitext(filename)[1] == '.py': return
4381    #     # end PATCH
4382    #     self.main.OnFileOpen(None,filename)
4383    # removed because this gets triggered when a file is on the command line in canopy 1.4 -- not likely used anyway
4384       
4385def main():
4386    '''Start up the GSAS-II application'''
4387    #application = GSASIImain() # don't redirect output, someday we
4388    # may want to do this if we can
4389    application = GSASIImain(0)
4390    if GSASIIpath.GetConfigValue('wxInspector'):
4391        import wx.lib.inspection as wxeye
4392        wxeye.InspectionTool().Show()
4393
4394    #application.main.OnRefine(None)
4395    application.MainLoop()
4396   
4397if __name__ == '__main__':
4398    # print versions
4399    print "Python module versions loaded:"
4400    print "  Python:     ",sys.version.split()[0]
4401    print "  wx:         ",wx.__version__
4402    print "  matplotlib: ",mpl.__version__
4403    print "  numpy:      ",np.__version__
4404    print "  scipy:      ",sp.__version__
4405    print "  OpenGL:     ",ogl.__version__
4406    try:
4407        from PIL import Image
4408        try:
4409            from PIL import PILLOW_VERSION
4410            version = PILLOW_VERSION
4411        except:
4412            version = Image.VERSION
4413        print "  PIL.Image:  ",version
4414    except ImportError:
4415        try:
4416            import Image
4417            print "Image (PIL):",Image.VERSION
4418        except ImportError:
4419            print "Image module not present; Note that PIL (Python Imaging Library) or pillow is needed for some image operations"
4420    import platform
4421    print "  Platform:   ",sys.platform,platform.architecture()[0],platform.machine()
4422    try:
4423        import mkl
4424        print "  Max threads:",mkl.get_max_threads()
4425    except:
4426        pass
4427    #print "wxPython description",wx.PlatformInfo
4428    print "This is GSAS-II revision "+str(GSASIIpath.GetVersionNumber())+'\n'
4429    GSASIIpath.InvokeDebugOpts()
4430    main() # start the GUI
Note: See TracBrowser for help on using the repository browser.