source: trunk/GSASII.py @ 2579

Last change on this file since 2579 was 2579, checked in by vondreele, 5 years ago

implement file selection for multi-PDF plots
replace "type" with "plotType" on all ISFGplot calls (bad variable name choice!)

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