source: trunk/GSASII.py @ 2486

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

fix mag form factor lookup - some aren't chemical valences (e.g. Fe+4)
fix mag form factor periodic table - nonmagnetic atoms now not shown
fix powder reflection mark & diff curve placement issues
fix issues with mag structure drawings - fill unit cell, etc.
fix structure transform to make magnetic cells (still needs making of constraints)
fix problem of mustrain & hstrain coeff changes with change in space group
add print to file of covariance matrix - user request
fix magnetic moment site symmetry restrictions
work on mag structure factor calcs.
change EXP file importer to ignore magnetic symmetry from GSAS

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