source: trunk/GSASII.py @ 1574

Last change on this file since 1574 was 1574, checked in by toby, 8 years ago

import PWDR parms when importing from GPX

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