source: trunk/GSASII.py @ 2135

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

more fixes to peak exports to get correct FWHM
refactor Merge GUI

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