source: trunk/GSASII.py @ 886

Last change on this file since 886 was 886, checked in by toby, 9 years ago

make GSAS iparm files the default option; suppress iparm reuse for GPX data import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 107.4 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#GSASII
4########### SVN repository information ###################
5# $Date: 2013-04-14 00:08:32 +0000 (Sun, 14 Apr 2013) $
6# $Author: toby $
7# $Revision: 886 $
8# $URL: trunk/GSASII.py $
9# $Id: GSASII.py 886 2013-04-14 00:08:32Z toby $
10########### SVN repository information ###################
11
12import os
13import sys
14import math
15import copy
16import random as ran
17import time
18import copy
19import glob
20import imp
21import inspect
22import numpy as np
23import scipy as sp
24import wx
25import matplotlib as mpl
26import wx.lib.inspection as wxeye
27try:
28    import OpenGL as ogl
29except ImportError:
30    print('*******************************************************')
31    print('PyOpenGL is missing from your python installation')
32    print('     - we will try to install it')
33    print('*******************************************************')
34    def install_with_easyinstall(package):
35        try: 
36            print "trying a system-wide PyOpenGl install"
37            easy_install.main(['-f',os.path.split(__file__)[0],package])
38            return
39        except:
40            pass
41        try: 
42            print "trying a user level PyOpenGl install"
43            easy_install.main(['-f',os.path.split(__file__)[0],'--user',package])
44            return
45        except:
46            print "Install of '+package+' failed. Please report this information:"
47            import traceback
48            print traceback.format_exc()
49            sys.exit()
50    from setuptools.command import easy_install
51    install_with_easyinstall('PyOpenGl')
52    print('*******************************************************')         
53    print('OpenGL has been installed. Please restart GSAS-II')
54    print('*******************************************************')         
55    sys.exit()
56
57# load the GSAS routines
58import GSASIIpath
59GSASIIpath.SetVersionNumber("$Revision: 886 $")
60import GSASIIIO as G2IO
61import GSASIIgrid as G2gd
62import GSASIIplot as G2plt
63import GSASIIpwd as G2pwd
64import GSASIIpwdGUI as G2pdG
65import GSASIIspc as G2spc
66import GSASIIstruct as G2str
67import GSASIImapvars as G2mv
68import GSASIIsolve as G2sol
69
70#wx inspector - use as needed
71wxInspector = False
72
73# print versions
74print "Python module versions loaded:"
75print "python:     ",sys.version[:5]
76print "wxpython:   ",wx.__version__
77print "matplotlib: ",mpl.__version__
78print "numpy:      ",np.__version__
79print "scipy:      ",sp.__version__
80print "OpenGL:     ",ogl.__version__
81try:
82    import mkl
83    print "Max threads ",mkl.get_max_threads()
84except:
85    pass
86#    print "MKL module not present"
87__version__ = '0.2.0'
88G2gd.__version__ = __version__
89print "This is GSAS-II version:     ",__version__,' revision '+str(GSASIIpath.GetVersionNumber())
90
91# useful degree trig functions
92sind = lambda x: math.sin(x*math.pi/180.)
93cosd = lambda x: math.cos(x*math.pi/180.)
94tand = lambda x: math.tan(x*math.pi/180.)
95asind = lambda x: 180.*math.asin(x)/math.pi
96acosd = lambda x: 180.*math.acos(x)/math.pi
97atan2d = lambda x,y: 180.*math.atan2(y,x)/math.pi
98
99def create(parent):
100    return GSASII(parent)
101
102class GSASII(wx.Frame):
103   
104    def _Add_FileMenuItems(self, parent):
105        item = parent.Append(
106            help='Open a gsasii project file (*.gpx)', id=wx.ID_ANY,
107            kind=wx.ITEM_NORMAL,text='&Open project...')
108        self.Bind(wx.EVT_MENU, self.OnFileOpen, id=item.GetId())
109        item = parent.Append(
110            help='Save project to old file', id=wx.ID_ANY,
111            kind=wx.ITEM_NORMAL,text='&Save project')
112        self.Bind(wx.EVT_MENU, self.OnFileSave, id=item.GetId())
113        item = parent.Append(
114            help='Save project to new file', id=wx.ID_ANY,
115            kind=wx.ITEM_NORMAL,text='Save As...')
116        self.Bind(wx.EVT_MENU, self.OnFileSaveas, id=item.GetId())
117        item = parent.Append(
118            help='Close project, saving is optional', id=wx.ID_ANY,
119            kind=wx.ITEM_NORMAL,text='&Close project')
120        self.Bind(wx.EVT_MENU, self.OnFileClose, id=item.GetId())
121        item = parent.Append(
122            help='Exit from gsasii', id=wx.ID_ANY,
123            kind=wx.ITEM_NORMAL,text='&Exit')
124        self.Bind(wx.EVT_MENU, self.OnFileExit, id=item.GetId())
125       
126    def _Add_DataMenuItems(self,parent):
127        item = parent.Append(
128            help='',id=wx.ID_ANY,
129            kind=wx.ITEM_NORMAL,
130            text='Read image data...')
131        self.Bind(wx.EVT_MENU, self.OnImageRead, id=item.GetId())
132        item = parent.Append(
133            help='',id=wx.ID_ANY,
134            kind=wx.ITEM_NORMAL,
135            text='Read Powder Pattern Peaks...')
136        self.Bind(wx.EVT_MENU, self.OnReadPowderPeaks, id=item.GetId())
137        item = parent.Append(
138            help='',id=wx.ID_ANY,
139            kind=wx.ITEM_NORMAL,
140            text='Sum powder data')
141        self.Bind(wx.EVT_MENU, self.OnPwdrSum, id=item.GetId())
142        item = parent.Append(
143            help='',id=wx.ID_ANY,
144            kind=wx.ITEM_NORMAL,
145            text='Sum image data')
146        self.Bind(wx.EVT_MENU, self.OnImageSum, id=item.GetId())
147        item = parent.Append(
148            help='',id=wx.ID_ANY,
149            kind=wx.ITEM_NORMAL,
150            text='Add phase')
151        self.Bind(wx.EVT_MENU, self.OnAddPhase, id=item.GetId())
152        item = parent.Append(
153            help='',id=wx.ID_ANY,
154            kind=wx.ITEM_NORMAL,
155            text='Delete phase')
156        self.Bind(wx.EVT_MENU, self.OnDeletePhase, id=item.GetId())
157        item = parent.Append(
158            help='',id=wx.ID_ANY,
159            kind=wx.ITEM_NORMAL,
160            text='Rename data') 
161        self.Bind(wx.EVT_MENU, self.OnRenameData, id=item.GetId())
162        item = parent.Append(
163            help='',id=wx.ID_ANY,
164            kind=wx.ITEM_NORMAL,
165            text='Delete data')
166        self.Bind(wx.EVT_MENU, self.OnDataDelete, id=item.GetId())
167               
168    def _Add_CalculateMenuItems(self,parent):
169        item = parent.Append(help='Make new PDFs from selected powder patterns', 
170            id=wx.ID_ANY, kind=wx.ITEM_NORMAL,text='Make new PDFs')
171        self.MakePDF.append(item)
172#        item.Enable(False)
173        self.Bind(wx.EVT_MENU, self.OnMakePDFs, id=item.GetId())
174       
175        item = parent.Append(help='View least squares parameters', 
176            id=wx.ID_ANY, kind=wx.ITEM_NORMAL,text='&View LS parms')
177        self.Bind(wx.EVT_MENU, self.OnViewLSParms, id=item.GetId())
178       
179        item = parent.Append(help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
180            text='&Refine')
181        self.Refine.append(item)
182        item.Enable(False)
183        self.Bind(wx.EVT_MENU, self.OnRefine, id=item.GetId())
184       
185        item = parent.Append(help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
186            text='Sequental refine')
187        self.SeqRefine.append(item)
188        item.Enable(False)
189        self.Bind(wx.EVT_MENU, self.OnSeqRefine, id=item.GetId())
190       
191    def _init_Imports(self):
192        '''import all the G2phase*.py & G2sfact*.py & G2pwd*.py files that
193        are found in the path
194        '''
195
196        self.ImportPhaseReaderlist = []
197        self._init_Import_routines('phase',self.ImportPhaseReaderlist,'Phase')
198        self.ImportSfactReaderlist = []
199        self._init_Import_routines('sfact',self.ImportSfactReaderlist,'Struct_Factor')
200        self.ImportPowderReaderlist = []
201        self._init_Import_routines('pwd',self.ImportPowderReaderlist,'Powder_Data')
202        self.ImportMenuId = {}
203
204    def _init_Import_routines(self,prefix,readerlist,errprefix):
205        '''import all the import readers matching the prefix
206        '''
207        #path2GSAS2 = os.path.dirname(os.path.realpath(__file__)) # location of this file
208        #pathlist = sys.path[:]
209        #if path2GSAS2 not in pathlist: pathlist.append(path2GSAS2)
210        path2GSAS2 = os.path.join(
211            os.path.dirname(os.path.realpath(__file__)), # location of this file
212            'imports')
213        pathlist = sys.path[:]
214        if path2GSAS2 not in pathlist: pathlist.append(path2GSAS2)
215
216        filelist = []
217        for path in pathlist:
218            for filename in glob.iglob(os.path.join(
219                path,
220                "G2"+prefix+"*.py")):
221                filelist.append(filename)   
222                #print 'debug: found',filename
223        filelist = sorted(list(set(filelist))) # remove duplicates
224        for filename in filelist:
225            path,rootname = os.path.split(filename)
226            pkg = os.path.splitext(rootname)[0]
227            try:
228                fp = None
229                fp, fppath,desc = imp.find_module(pkg,[path,])
230                pkg = imp.load_module(pkg,fp,fppath,desc)
231                for clss in inspect.getmembers(pkg): # find classes defined in package
232                    if clss[0].startswith('_'): continue
233                    if inspect.isclass(clss[1]):
234                        # check if we have the required methods
235                        for m in 'Reader','ExtensionValidator','ContentsValidator':
236                            if not hasattr(clss[1],m): break
237                            if not callable(getattr(clss[1],m)): break
238                        else:
239                            reader = clss[1]() # create an import instance
240                            readerlist.append(reader)
241            except AttributeError:
242                print 'Import_'+errprefix+': Attribute Error'+str(filename)
243                pass
244            except ImportError:
245                print 'Import_'+errprefix+': Error importing file'+str(filename)
246                pass
247            if fp: fp.close()
248
249    def OnImportGeneric(self,reader,readerlist,label,multiple=False):
250        '''Call the requested import reader or all of the appropriate
251        import readers in response to a menu item
252        '''
253        self.lastimport = ''
254        self.zipfile = None
255        if reader is None:
256            multiple = False
257            #print "use all formats"
258            choices = "any file (*.*)|*.*"
259            choices += "|zip archive (.zip)|*.zip"
260            extdict = {}
261            # compile a list of allowed extensions
262            for rd in readerlist:
263                fmt = rd.formatName
264                for extn in rd.extensionlist:
265                    if not extdict.get(extn): extdict[extn] = []
266                    extdict[extn] += [fmt,]
267            for extn in sorted(extdict.keys(),cmp=lambda x,y: cmp(x.lower(), y.lower())):
268                fmt = ''
269                for f in extdict[extn]:
270                    if fmt != "": fmt += ', '
271                    fmt += f
272                choices += "|" + fmt + " file (*" + extn + ")|*" + extn
273        else:
274            readerlist = [reader,]
275            # compile a list of allowed extensions
276            choices = reader.formatName + " file ("
277            w = ""
278            for extn in reader.extensionlist:
279                if w != "": w += ";"
280                w += "*" + extn
281            choices += w + ")|" + w
282            choices += "|zip archive (.zip)|*.zip"
283            if not reader.strictExtension:
284                choices += "|any file (*.*)|*.*"
285        # get the file(s)
286        if multiple:
287            mode = style=wx.OPEN | wx.CHANGE_DIR | wx.MULTIPLE
288        else:
289            mode = style=wx.OPEN | wx.CHANGE_DIR
290        dlg = wx.FileDialog(self, message="Choose "+label+" input file",
291            defaultFile="",wildcard=choices, style=mode)
292        try:
293            if dlg.ShowModal() == wx.ID_OK:
294                if multiple:
295                    filelist = dlg.GetPaths()
296                    if len(filelist) == 0: return []
297                else:
298                    filename = dlg.GetPath()
299                    filelist = [filename,]
300                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
301            else: # cancel was pressed
302                return []
303        finally:
304            dlg.Destroy()
305        rd_list = []
306        filelist1 = []
307        for filename in filelist:
308            # is this a zip file?
309            if os.path.splitext(filename)[1].lower() == '.zip':
310                extractedfiles = G2IO.ExtractFileFromZip(
311                    filename,parent=self,
312                    multipleselect=True)
313                if extractedfiles is None: continue # error or Cancel
314                if extractedfiles != filename:
315                    self.zipfile = filename # save zip name
316                    filelist1 += extractedfiles
317                    continue
318            filelist1.append(filename)
319        filelist = filelist1
320        for filename in filelist:
321            # is this a zip file?
322            if os.path.splitext(filename)[1].lower() == '.zip':
323                extractedfile = G2IO.ExtractFileFromZip(filename,parent=self)
324                if extractedfile is None: continue # error or Cancel
325                if extractedfile != filename:
326                    filename,self.zipfile = extractedfile,filename # now use the file that was created
327            # set what formats are compatible with this file
328            primaryReaders = []
329            secondaryReaders = []
330            for reader in readerlist:
331                flag = reader.ExtensionValidator(filename)
332                if flag is None: 
333                    secondaryReaders.append(reader)
334                elif flag:
335                    primaryReaders.append(reader)
336            if len(secondaryReaders) + len(primaryReaders) == 0:
337                self.ErrorDialog('No Format','No matching format for file '+filename)
338                return []
339
340            fp = None
341            msg = ''
342            try:
343                fp = open(filename,'Ur')
344                if len(filelist) == 1:
345                    # confirm we have the right file
346                    rdmsg = 'File '+str(filename)+' begins:\n\n'
347                    for i in range(3):
348                        rdmsg += fp.readline()
349                    rdmsg += '\n\nDo you want to read this file?'
350                    if not all([ord(c) < 128 and ord(c) != 0 for c in rdmsg]): # show only if ASCII
351                        rdmsg = 'File '+str(
352                            filename)+' is a binary file. Do you want to read this file?'
353                    result = wx.ID_NO
354                    # it would be better to use something that
355                    # would resize better, but this will do for now
356                    dlg = wx.MessageDialog(
357                        self, rdmsg,
358                        'Is this the file you want?', 
359                        wx.YES_NO | wx.ICON_QUESTION,
360                        )
361                    dlg.SetSize((700,300)) # does not resize on Mac
362                    try:
363                        result = dlg.ShowModal()
364                    finally:
365                        dlg.Destroy()
366                    if result == wx.ID_NO: return []
367                           
368                self.lastimport = filename
369                # try the file first with Readers that specify the
370                # files extension and later with ones that allow it
371                flag = False
372                for rd in primaryReaders+secondaryReaders:
373                    try:
374                        fp.seek(0)  # rewind
375                        if not rd.ContentsValidator(fp): continue # rejected on cursory check
376                        repeat = True
377                        rdbuffer = {} # create temporary storage for file reader
378                        block = 0
379                        while repeat:
380                            block += 1
381                            repeat = False
382                            fp.seek(0)  # rewind
383                            rd.objname = os.path.basename(filename)
384                            flag = rd.Reader(filename,fp,self,
385                                             buffer=rdbuffer,
386                                             blocknum=block)
387                            if flag:
388                                rd_list.append(copy.deepcopy(rd)) # success
389                                if rd.repeat: repeat = True
390                    except:
391                        import traceback
392                        print traceback.format_exc()
393                        msg += '\nError reading file '+filename+' with format '+ rd.formatName
394                        #self.ErrorDialog('Read Error',
395                        #                 'Error reading file '+filename
396                        #                 +' with format '+ rd.formatName)
397                        continue
398                    if flag:
399                        if rd.warnings:
400                            self.ErrorDialog('Read Warning','The '+ rd.formatName+
401                                             ' reader reported a warning message:\n\n'+
402                                             rd.warnings)
403                        break # success reading
404                else:
405                    self.ErrorDialog('Read Error','No reader is able to read from file '+filename+msg)
406            except:
407                import traceback
408                print traceback.format_exc()
409                self.ErrorDialog('Open Error','Error on open of file '+filename)
410            if fp: fp.close()
411        return rd_list
412
413    def _Add_ImportMenu_Phase(self,parent):
414        '''configure the Import Phase menus accord to the readers found in _init_Imports
415        '''
416        submenu = wx.Menu()
417        item = parent.AppendMenu(wx.ID_ANY, 'Phase',
418            submenu, help='Import phase data')
419        for reader in self.ImportPhaseReaderlist:
420            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
421                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
422            self.ImportMenuId[item.GetId()] = reader
423            self.Bind(wx.EVT_MENU, self.OnImportPhase, id=item.GetId())
424        item = submenu.Append(wx.ID_ANY,
425                              help='Import phase data, use file to try to determine format',
426                              kind=wx.ITEM_NORMAL,
427                              text='guess format from file')
428        self.Bind(wx.EVT_MENU, self.OnImportPhase, id=item.GetId())
429
430    def OnImportPhase(self,event):
431        # look up which format was requested
432        reqrdr = self.ImportMenuId.get(event.GetId())
433        rdlist = self.OnImportGeneric(reqrdr,
434                                  self.ImportPhaseReaderlist,
435                                  'phase')
436        if len(rdlist) == 0: return
437        # for now rdlist is only expected to have one element
438        # but this will allow multiple phases to be imported
439        self.CheckNotebook()
440        for rd in rdlist:
441            dlg = wx.TextEntryDialog( # allow editing of phase name
442                self, 'Enter the name for the new phase',
443                'Edit phase name', rd.Phase['General']['Name'],
444                style=wx.OK)
445            dlg.CenterOnParent()
446            if dlg.ShowModal() == wx.ID_OK:
447                rd.Phase['General']['Name'] = dlg.GetValue()
448            dlg.Destroy()
449            PhaseName = rd.Phase['General']['Name']
450            print 'Read phase '+str(PhaseName)+' from file '+str(self.lastimport)
451            if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
452                sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
453            else:
454                sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
455            psub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
456            self.PatternTree.SetItemPyData(psub,rd.Phase)
457            self.PatternTree.Expand(self.root) # make sure phases are seen
458            self.PatternTree.Expand(sub) 
459            self.PatternTree.Expand(psub) 
460        return # success
461       
462    def _Add_ImportMenu_Sfact(self,parent):
463        '''configure the Import Structure Factor menus accord to the readers found in _init_Imports
464        '''
465        submenu = wx.Menu()
466        item = parent.AppendMenu(wx.ID_ANY, 'Structure Factor',
467            submenu, help='Import Structure Factor data')
468        for reader in self.ImportSfactReaderlist:
469            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,               
470                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
471            self.ImportMenuId[item.GetId()] = reader
472            self.Bind(wx.EVT_MENU, self.OnImportSfact, id=item.GetId())
473        item = submenu.Append(wx.ID_ANY,
474            help='Import Structure Factor, use file to try to determine format',
475            kind=wx.ITEM_NORMAL,
476            text='guess format from file')
477        self.Bind(wx.EVT_MENU, self.OnImportSfact, id=item.GetId())
478
479    def OnImportSfact(self,event):
480        # look up which format was requested
481        reqrdr = self.ImportMenuId.get(event.GetId())
482        rdlist = self.OnImportGeneric(reqrdr,self.ImportSfactReaderlist,
483            'Structure Factor')
484        if len(rdlist) == 0: return
485        self.CheckNotebook()
486        for rd in rdlist:
487            HistName = rd.objname
488            if len(rdlist) <= 2: 
489                dlg = wx.TextEntryDialog( # allow editing of Structure Factor name
490                    self, 'Enter the name for the new Structure Factor',
491                    'Edit Structure Factor name', HistName,
492                    style=wx.OK)
493                dlg.CenterOnParent()
494                if dlg.ShowModal() == wx.ID_OK:
495                    HistName = dlg.GetValue()
496                dlg.Destroy()
497            print 'Read structure factor table '+str(HistName)+' from file '+str(self.lastimport)
498            Id = self.PatternTree.AppendItem(parent=self.root,
499                                             text='HKLF '+HistName)
500            self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0},rd.RefList])
501            Sub = self.PatternTree.AppendItem(Id,text='Instrument Parameters')
502            self.PatternTree.SetItemPyData(Sub,rd.Parameters)
503            self.PatternTree.SetItemPyData(
504                self.PatternTree.AppendItem(Id,text='HKL Plot Controls'),
505                rd.Controls)
506            self.PatternTree.SetItemPyData(
507                self.PatternTree.AppendItem(Id,text='Reflection List'),[])  #dummy entry for GUI use
508            self.PatternTree.SelectItem(Id)
509            self.PatternTree.Expand(Id)
510            self.Sngl = Id
511        return # success
512
513    def _Add_ImportMenu_powder(self,parent):
514        '''configure the Powder Data menus accord to the readers found in _init_Imports
515        '''
516        submenu = wx.Menu()
517        item = parent.AppendMenu(wx.ID_ANY, 'Powder Data',
518            submenu, help='Import Powder data')
519        for reader in self.ImportPowderReaderlist:
520            item = submenu.Append(wx.ID_ANY,help=reader.longFormatName,
521                kind=wx.ITEM_NORMAL,text='from '+reader.formatName+' file')
522            self.ImportMenuId[item.GetId()] = reader
523            self.Bind(wx.EVT_MENU, self.OnImportPowder, id=item.GetId())
524        item = submenu.Append(wx.ID_ANY,
525            help='Import powder data, use file to try to determine format',
526            kind=wx.ITEM_NORMAL,text='guess format from file')
527        self.Bind(wx.EVT_MENU, self.OnImportPowder, id=item.GetId())
528           
529    def ReadPowderInstprm(self,instfile):       #fix the write routine for [inst1,inst2] style
530        '''Read a GSAS-II (new) instrument parameter file'''
531        if os.path.splitext(instfile)[1].lower() != '.instprm': # invalid file
532            return None           
533        if not os.path.exists(instfile): # no such file
534            return None
535        File = open(instfile,'r')
536        S = File.readline()
537        if not S.startswith('#GSAS-II'): # not a valid file
538            File.close()
539            return None
540        newItems = []
541        newVals = []
542        while S:
543            if S[0] == '#':
544                S = File.readline()
545                continue
546            [item,val] = S[:-1].split(':')
547            newItems.append(item)
548            try:
549                newVals.append(float(val))
550            except ValueError:
551                newVals.append(val)                       
552            S = File.readline()               
553        File.close()
554        return G2IO.makeInstDict(newItems,newVals,len(newVals)*[False,])
555       
556    def ReadPowderIparm(self,instfile,bank,databanks,rd):
557        '''Read a GSAS (old) instrument parameter file'''
558        if not os.path.exists(instfile): # no such file
559            return {}
560        fp = 0
561        try:
562            fp = open(instfile,'Ur')
563            Iparm = {}
564            for S in fp:
565                Iparm[S[:12]] = S[12:-1]
566        except IOError:
567            print('Error reading file:'+str(instfile))
568        if fp:       
569            fp.close()
570
571        ibanks = int(Iparm.get('INS   BANK  ','1').strip())
572        hType = Iparm['INS   HTYPE '].strip()
573        if ibanks == 1: # there is only one bank here, return it
574            rd.instbank = 1
575            return Iparm
576        if 'PNT' in hType:
577            rd.instbank = bank
578        elif ibanks != databanks:
579            # number of banks in data and prm file not not agree, need a
580            # choice from a human here
581            choices = []
582            for i in range(1,1+ibanks):
583                choices.append('Bank '+str(i))
584            bank = rd.BlockSelector(
585                choices, self,
586                title='Select an instrument parameter bank for '+
587                os.path.split(rd.powderentry[0])[1]+' BANK '+str(bank)+
588                '\nOr use Cancel to select from the default parameter sets',
589                header='Block Selector')
590        if bank is None: return {}
591        # pull out requested bank # bank from the data, and change the bank to 1
592        IparmS = {}
593        for key in Iparm:
594            if key[4:6] == "  ":
595                IparmS[key] = Iparm[key]
596            elif int(key[4:6].strip()) == bank:
597                IparmS[key[:4]+' 1'+key[6:]] = Iparm[key]
598        rd.instbank = bank
599        return IparmS
600                       
601    def GetPowderIparm(self,rd, prevIparm, lastIparmfile, lastdatafile):
602        '''Open and read an instrument parameter file for a data file
603        Returns the list of parameters used in the data tree
604        '''
605        def SetPowderInstParms(Iparm, rd):
606            '''extracts values from instrument parameters in rd.instdict
607            or in array Iparm.
608            Create and return the contents of the instrument parameter tree entry.
609            '''
610            DataType = Iparm['INS   HTYPE '].strip()[:3]  # take 1st 3 chars
611            # override inst values with values read from data file
612            if rd.instdict.get('type'):
613                DataType = rd.instdict.get('type')
614            data = [DataType,]
615            if 'C' in DataType:
616                wave1 = None
617                wave2 = 0.0
618                if rd.instdict.get('wave'):
619                    wl = rd.instdict.get('wave')
620                    wave1 = wl[0]
621                    if len(wl) > 1: wave2 = wl[1]
622                s = Iparm['INS  1 ICONS']
623                if not wave1:
624                    wave1 = G2IO.sfloat(s[:10])
625                    wave2 = G2IO.sfloat(s[10:20])
626                v = (wave1,wave2,
627                     G2IO.sfloat(s[20:30]),G2IO.sfloat(s[55:65]),G2IO.sfloat(s[40:50])) #get lam1, lam2, zero, pola & ratio
628                if not v[1]:
629                    names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
630                    v = (v[0],v[2],v[4])
631                    codes = [0,0,0,0]
632                else:
633                    names = ['Type','Lam1','Lam2','Zero','I(L2)/I(L1)','Polariz.','U','V','W','X','Y','SH/L','Azimuth']
634                    codes = [0,0,0,0,0,0]
635                data.extend(v)
636                v1 = Iparm['INS  1PRCF1 '].split()                                                 
637                v = Iparm['INS  1PRCF11'].split()
638                data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
639                azm = float(Iparm.get('INS  1DETAZM','0.0'))
640                v = Iparm['INS  1PRCF12'].split()
641                if v1[0] == 3:
642                    data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3],azm)])  #get LX, LY, S+H/L & azimuth
643                else:
644                    data.extend([0.0,0.0,0.002,azm])                                      #OK defaults if fxn #3 not 1st in iprm file
645                codes.extend([0,0,0,0,0,0,0])
646                return [G2IO.makeInstDict(names,data,codes),{}]
647            elif 'T' in DataType:
648                names = ['Type','2-theta','difC','difA','Zero','alpha','beta-0','beta-1','sig-0','sig-1','X','Y','Azimuth']
649                codes = [0,0,0,0,0,0,0,0,0,0,0,0,0]
650                azm = 0.
651                if 'INS  1DETAZM' in Iparm:
652                    azm = float(Iparm['INS  1DETAZM'])
653                s = Iparm['INS  1BNKPAR'].split()
654                data.extend([G2IO.sfloat(s[1]),])               #2-theta for bank
655                s = Iparm['INS  1 ICONS'].split()
656                data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),G2IO.sfloat(s[2])])    #difC, difA, Zero
657                s = Iparm['INS  1PRCF1 '].split()
658                pfType = int(s[0])
659                s = Iparm['INS  1PRCF11'].split()
660                if abs(pfType) == 1:
661                    data.extend([G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),G2IO.sfloat(s[3])])
662                    s = Iparm['INS  1PRCF12'].split()
663                    data.extend([0.0,G2IO.sfloat(s[1]),0.0,0.0,azm])
664                elif abs(pfType) in [3,4,5]:
665                    data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),G2IO.sfloat(s[2])])
666                    if abs(pfType) == 4:
667                        data.extend([0.0,G2IO.sfloat(s[3]),0.0,0.0,azm])
668                    else:
669                        s = Iparm['INS  1PRCF12'].split()
670                        data.extend([0.0,G2IO.sfloat(s[0]),0.0,0.0,azm])                       
671                Inst1 = G2IO.makeInstDict(names,data,codes)
672                Inst2 = {}
673                if pfType < 0:
674                    Ipab = 'INS  1PAB'+str(-pfType)
675                    Npab = int(Iparm[Ipab+'  '].strip())
676                    Inst2['Pdabc'] = []
677                    for i in range(Npab):
678                        k = Ipab+str(i+1).rjust(2)
679                        s = Iparm[k].split()
680                        Inst2['Pdabc'].append([float(t) for t in s])
681                    Inst2['Pdabc'] = np.array(Inst2['Pdabc'])
682                    Inst2['Pdabc'].T[3] += Inst2['Pdabc'].T[0]*Inst1['difC'][0] #turn 3rd col into TOF
683                if 'INS  1I ITYP' in Iparm:
684                    s = Iparm['INS  1I ITYP'].split()
685                    Ityp = int(s[0])
686                    Tminmax = [float(s[1])*1000.,float(s[2])*1000.]
687                    Itypes = ['Exponential','Maxwell/Exponential','','Maxwell/Chebyschev','']
688                    if Ityp in [1,2,4]:
689                        Inst2['Itype'] = Itypes[Ityp-1]
690                        Inst2['Tminmax'] = Tminmax
691                        Icoeff = []
692                        Iesd = []
693                        Icovar = []                   
694                        for i in range(3):
695                            s = Iparm['INS  1ICOFF'+str(i+1)].split()
696                            Icoeff += [float(S) for S in s]
697                            s = Iparm['INS  1IECOF'+str(i+1)].split()
698                            Iesd += [float(S) for S in s]
699                        for i in range(8):
700                            s = Iparm['INS  1IECOR'+str(i+1)].split()
701                            Icovar += [float(S) for S in s]
702                        Inst2['Icoeff'] = Icoeff
703                        Inst2['Iesd'] = Iesd
704                        Inst2['Icovar'] = Icovar
705                return [Inst1,Inst2]
706
707        # stuff we might need from the reader
708        filename = rd.powderentry[0]
709        bank = rd.powderentry[2]
710        numbanks = rd.numbanks
711        # is there an instrument parameter file defined for the current data set?
712        if rd.instparm or (lastdatafile == filename and lastIparmfile):
713            if rd.instparm:
714                instfile = os.path.join(os.path.split(filename)[0],
715                                    rd.instparm)
716            else:
717                # for multiple reads of one data file, reuse the inst parm file
718                instfile = lastIparmfile
719            if os.path.exists(instfile):
720                #print 'debug: try read',instfile
721                instParmList = self.ReadPowderInstprm(instfile)
722                if instParmList is not None:
723                    rd.instfile = instfile
724                    rd.instmsg = 'GSAS-II file '+instfile
725                    return instParmList
726                Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
727                if Iparm:
728                    #print 'debug: success'
729                    rd.instfile = instfile
730                    rd.instmsg = instfile + ' bank ' + str(rd.instbank)
731                    return SetPowderInstParms(Iparm,rd)
732            else:
733                self.ErrorDialog('Open Error','Error opening instrument parameter file '
734                    +str(instfile)+' requested by file '+ filename)
735        # is there an instrument parameter file matching the current file
736        # with extension .inst or .prm? If so read it
737        basename = os.path.splitext(filename)[0]
738        for ext in '.instprm','.prm','.inst','.ins':
739            instfile = basename + ext
740            instParmList = self.ReadPowderInstprm(instfile)
741            if instParmList is not None:
742                rd.instfile = instfile
743                rd.instmsg = 'GSAS-II file '+instfile
744                return instParmList
745            Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
746            if Iparm:
747                #print 'debug: success'
748                rd.instfile = instfile
749                rd.instmsg = instfile + ' bank ' + str(rd.instbank)
750                return SetPowderInstParms(Iparm,rd)
751            else:
752                #print 'debug: open/read failed',instfile
753                pass # fail silently
754
755        # did we read the data file from a zip? If so, look there for a
756        # instrument parameter file
757        if self.zipfile:
758            for ext in '.instprm','.prm','.inst','.ins':
759                instfile = G2IO.ExtractFileFromZip(
760                    self.zipfile,
761                    selection=os.path.split(basename + ext)[1],
762                    parent=self)
763                if instfile is not None and instfile != self.zipfile:
764                    print 'debug:',instfile,'created from ',self.zipfile
765                    instParmList = self.ReadPowderInstprm(instfile)
766                    if instParmList is not None:
767                        rd.instfile = instfile
768                        rd.instmsg = 'GSAS-II file '+instfile
769                        return instParmList
770                    Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
771                    if Iparm:
772                        rd.instfile = instfile
773                        rd.instmsg = instfile + ' bank ' + str(rd.instbank)
774                        return SetPowderInstParms(Iparm,rd)
775                    else:
776                        #print 'debug: open/read for',instfile,'from',self.zipfile,'failed'
777                        pass # fail silently
778
779        while True: # loop until we get a file that works or we get a cancel
780            instfile = ''
781            dlg = wx.FileDialog(
782                self,
783                'Choose inst. param file for "'
784                +rd.idstring
785                +'" (or Cancel for default)',
786                '.', '',
787                'GSAS iparm file (*.prm,*.inst,*.ins)|*.prm;*.inst;*.ins|'
788                'GSAS-II iparm file (*.instprm)|*.instprm|'
789                'All files (*.*)|*.*', 
790                wx.OPEN|wx.CHANGE_DIR)
791            if os.path.exists(lastIparmfile):
792                dlg.SetFilename(lastIparmfile)
793            if dlg.ShowModal() == wx.ID_OK:
794                instfile = dlg.GetPath()
795            dlg.Destroy()
796            if not instfile: break
797            instParmList = self.ReadPowderInstprm(instfile)
798            if instParmList is not None:
799                rd.instfile = instfile
800                rd.instmsg = 'GSAS-II file '+instfile
801                return instParmList
802            Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
803            if Iparm:
804                #print 'debug: success with',instfile
805                rd.instfile = instfile
806                rd.instmsg = instfile + ' bank ' + str(rd.instbank)
807                return SetPowderInstParms(Iparm,rd)
808            else:
809                self.ErrorDialog('Read Error',
810                                 'Error opening/reading file '+str(instfile))
811       
812        # still no success: offer user choice of defaults
813        while True: # loop until we get a choice
814            choices = []
815            head = 'Select from default instrument parameters for '+rd.idstring
816
817            for l in rd.defaultIparm_lbl:
818                choices.append('Defaults for '+l)
819            res = rd.BlockSelector(
820                choices,
821                ParentFrame=self,
822                title=head,
823                header='Select default inst parms',)
824            if res is None: continue
825            rd.instfile = ''
826            rd.instmsg = 'default: '+rd.defaultIparm_lbl[res]
827            return SetPowderInstParms(rd.defaultIparms[res],rd)
828
829    def OnImportPowder(self,event):
830        '''reads powder data using a variety of formats
831        reads an instrument parameter file for each dataset
832        '''
833        reqrdr = self.ImportMenuId.get(event.GetId())  # look up which format was requested
834        rdlist = self.OnImportGeneric(
835            reqrdr,self.ImportPowderReaderlist,'Powder Data',multiple=True)
836        if len(rdlist) == 0: return
837        self.CheckNotebook()
838        Iparm = None
839        lastIparmfile = ''
840        lastdatafile = ''
841        for rd in rdlist:
842            # get instrument parameters for each dataset
843            Iparm1,Iparm2 = self.GetPowderIparm(rd, Iparm, lastIparmfile, lastdatafile)
844            if rd.repeat_instparm: 
845                lastIparmfile = rd.instfile
846            lastdatafile = rd.powderentry[0]
847            print 'Read powder data '+str(rd.idstring)+ \
848                ' from file '+str(self.lastimport) + \
849                ' with parameters from '+str(rd.instmsg)
850            # data are read, now store them in the tree
851            Id = self.PatternTree.AppendItem(parent=self.root,
852                text='PWDR '+rd.idstring)
853            if 'T' in Iparm1['Type'][0]:
854                if not rd.clockWd and rd.GSAS:
855                    rd.powderdata[0] *= 100.        #put back the CW centideg correction
856                cw = np.diff(rd.powderdata[0])
857                rd.powderdata[0] = rd.powderdata[0][:-1]+cw/2.
858                rd.powderdata[1] = rd.powderdata[1][:-1]/cw
859                rd.powderdata[2] = rd.powderdata[2][:-1]*cw**2  #1/var=w at this point
860                if 'Itype' in Iparm2:
861                    Ibeg = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][0])
862                    Ifin = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][1])
863                    rd.powderdata[0] = rd.powderdata[0][Ibeg:Ifin]
864                    YI,WYI = G2pwd.calcIncident(Iparm2,rd.powderdata[0])
865                    rd.powderdata[1] = rd.powderdata[1][Ibeg:Ifin]/YI
866                    var = 1./rd.powderdata[2][Ibeg:Ifin]
867                    var += WYI*rd.powderdata[1]**2
868                    var /= YI**2
869                    rd.powderdata[2] = 1./var
870                rd.powderdata[3] = np.zeros_like(rd.powderdata[0])                                       
871                rd.powderdata[4] = np.zeros_like(rd.powderdata[0])                                       
872                rd.powderdata[5] = np.zeros_like(rd.powderdata[0])                                       
873            Tmin = min(rd.powderdata[0])
874            Tmax = max(rd.powderdata[0])
875            self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0},rd.powderdata])
876            self.PatternTree.SetItemPyData(
877                self.PatternTree.AppendItem(Id,text='Comments'),
878                rd.comments)
879            self.PatternTree.SetItemPyData(
880                self.PatternTree.AppendItem(Id,text='Limits'),
881                [(Tmin,Tmax),[Tmin,Tmax]])
882            self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
883            self.PatternTree.SetItemPyData(
884                self.PatternTree.AppendItem(Id,text='Background'),
885                [['chebyschev',True,3,1.0,0.0,0.0],
886                 {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
887            self.PatternTree.SetItemPyData(
888                self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
889                [Iparm1,Iparm2])
890            self.PatternTree.SetItemPyData(
891                self.PatternTree.AppendItem(Id,text='Sample Parameters'),
892                rd.Sample)
893            self.PatternTree.SetItemPyData(
894                self.PatternTree.AppendItem(Id,text='Peak List')
895                ,[])
896            self.PatternTree.SetItemPyData(
897                self.PatternTree.AppendItem(Id,text='Index Peak List'),
898                [])
899            self.PatternTree.SetItemPyData(
900                self.PatternTree.AppendItem(Id,text='Unit Cells List'),
901                [])
902            self.PatternTree.SetItemPyData(
903                self.PatternTree.AppendItem(Id,text='Reflection Lists'),
904                {})
905            self.PatternTree.Expand(Id)
906        self.PatternTree.SelectItem(Id)
907        return # success
908
909    def _init_Exports(self,parent):
910        '''This is a place holder for when exports are handled in a manner similar to imports
911        '''
912#        submenu = wx.Menu()
913#        item = parent.AppendMenu(
914#            wx.ID_ANY, 'entire project',
915#            submenu, help='Export entire project')
916#        item = submenu.Append(
917#            wx.ID_ANY,
918#            help='this is a module for testing',
919#            kind=wx.ITEM_NORMAL,
920#            text='to test file')
921#        self.Bind(wx.EVT_MENU, self.OnExportTest, id=item.GetId())
922#        import G2export
923#    def OnExportTest(self,event):
924#        import G2export
925#        reload(G2export)
926#        G2export.ProjExport(self)
927
928    def _Add_ExportMenuItems(self,parent):
929        item = parent.Append(
930            help='Select PWDR item to enable',id=wx.ID_ANY,
931            kind=wx.ITEM_NORMAL,
932            text='Export Powder Patterns...')
933        self.ExportPattern.append(item)
934        item.Enable(False)
935        self.Bind(wx.EVT_MENU, self.OnExportPatterns, id=item.GetId())
936
937        item = parent.Append(
938            help='',id=wx.ID_ANY,
939            kind=wx.ITEM_NORMAL,
940            text='Export All Peak Lists...')
941        self.ExportPeakList.append(item)
942        item.Enable(True)
943        self.Bind(wx.EVT_MENU, self.OnExportPeakList, id=item.GetId())
944
945        item = parent.Append(
946            help='',id=wx.ID_ANY,
947            kind=wx.ITEM_NORMAL,
948            text='Export HKLs...')
949        self.ExportHKL.append(item)
950        item.Enable(False)
951        self.Bind(wx.EVT_MENU, self.OnExportHKL, id=item.GetId())
952
953        item = parent.Append(
954            help='Select PDF item to enable',
955            id=wx.ID_ANY,
956            kind=wx.ITEM_NORMAL,
957            text='Export PDF...')
958        self.ExportPDF.append(item)
959        item.Enable(False)
960        self.Bind(wx.EVT_MENU, self.OnExportPDF, id=item.GetId())
961
962        item = parent.Append(
963            help='',id=wx.ID_ANY,
964            kind=wx.ITEM_NORMAL,
965            text='Export Phase...')
966        self.ExportPhase.append(item)
967        item.Enable(False)
968        self.Bind(wx.EVT_MENU, self.OnExportPhase, id=item.GetId())
969
970        item = parent.Append(
971            help='',id=wx.ID_ANY,
972            kind=wx.ITEM_NORMAL,
973            text='Export CIF...')
974        self.ExportCIF.append(item)
975        item.Enable(False)
976        self.Bind(wx.EVT_MENU, self.OnExportCIF, id=item.GetId())
977               
978    def FillMainMenu(self,menubar):
979        '''Define contents of the main GSAS-II menu for the (main) data tree window
980        in the mac, used also for the data item windows as well.
981        '''
982        File = wx.Menu(title='')
983        menubar.Append(menu=File, title='&File')
984        self._Add_FileMenuItems(File)
985        Data = wx.Menu(title='')
986        menubar.Append(menu=Data, title='Data')
987        self._Add_DataMenuItems(Data)
988        Calculate = wx.Menu(title='')       
989        menubar.Append(menu=Calculate, title='&Calculate')
990        self._Add_CalculateMenuItems(Calculate)
991        Import = wx.Menu(title='')       
992        menubar.Append(menu=Import, title='Import')
993        self._Add_ImportMenu_Phase(Import)
994        self._Add_ImportMenu_powder(Import)
995        self._Add_ImportMenu_Sfact(Import)
996        Export = wx.Menu(title='')       
997        menubar.Append(menu=Export, title='Export')
998        self._Add_ExportMenuItems(Export)
999        #self._init_Exports(Export)
1000        HelpMenu=G2gd.MyHelp(self,helpType='Data tree',
1001            morehelpitems=[('&Tutorials','Tutorials')])
1002        menubar.Append(menu=HelpMenu,title='&Help')
1003
1004    def _init_ctrls(self, parent):
1005        wx.Frame.__init__(self, name='GSASII', parent=parent,
1006            size=wx.Size(400, 250),style=wx.DEFAULT_FRAME_STYLE, title='GSAS-II data tree')
1007        clientSize = wx.ClientDisplayRect()
1008        Size = self.GetSize()
1009        xPos = clientSize[2]-Size[0]
1010        self.SetPosition(wx.Point(xPos,clientSize[1]))
1011        self._init_Imports()
1012        #initialize Menu item objects (these contain lists of menu items that are enabled or disabled)
1013        self.MakePDF = []
1014        self.Refine = []
1015        self.SeqRefine = []
1016        self.ExportPattern = []
1017        self.ExportPeakList = []
1018        self.ExportHKL = []
1019        self.ExportPDF = []
1020        self.ExportPhase = []
1021        self.ExportCIF = []
1022        #
1023        self.GSASIIMenu = wx.MenuBar()
1024        self.FillMainMenu(self.GSASIIMenu)
1025        self.SetMenuBar(self.GSASIIMenu)
1026        self.Bind(wx.EVT_SIZE, self.OnSize)
1027        self.CreateStatusBar()
1028        self.mainPanel = wx.Panel(self,-1)
1029       
1030        wxID_PATTERNTREE = wx.NewId()
1031        self.PatternTree = wx.TreeCtrl(id=wxID_PATTERNTREE,
1032            parent=self.mainPanel, pos=wx.Point(0, 0),style=wx.TR_DEFAULT_STYLE )
1033        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED,
1034            self.OnPatternTreeSelChanged, id=wxID_PATTERNTREE)
1035        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
1036            self.OnPatternTreeItemCollapsed, id=wxID_PATTERNTREE)
1037        self.PatternTree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
1038            self.OnPatternTreeItemExpanded, id=wxID_PATTERNTREE)
1039        self.PatternTree.Bind(wx.EVT_TREE_DELETE_ITEM,
1040            self.OnPatternTreeItemDelete, id=wxID_PATTERNTREE)
1041        self.PatternTree.Bind(wx.EVT_TREE_KEY_DOWN,
1042            self.OnPatternTreeKeyDown, id=wxID_PATTERNTREE)
1043        self.root = self.PatternTree.AddRoot('Loaded Data: ')
1044       
1045        plotFrame = wx.Frame(None,-1,'GSASII Plots',size=wx.Size(700,600), \
1046            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
1047        self.G2plotNB = G2plt.G2PlotNoteBook(plotFrame)
1048        plotFrame.Show()
1049       
1050        self.dataDisplay = None
1051       
1052    def __init__(self, parent):
1053        self._init_ctrls(parent)
1054        self.Bind(wx.EVT_CLOSE, self.ExitMain)
1055        # various defaults
1056        self.oldFocus = None
1057        self.GSASprojectfile = ''
1058        self.dirname = os.path.expanduser('~')       #start in the users home directory by default; may be meaningless
1059        self.undofile = ''
1060        self.TreeItemDelete = False
1061        self.Offset = [0.0,0.0]
1062        self.delOffset = .02
1063        self.refOffset = -100.0
1064        self.refDelt = .01
1065        self.Weight = False
1066        self.IparmName = ''  # to be removed when SelectPowderData & GetInstrumentFile is
1067        self.IfPlot = False
1068        self.PatternId = 0
1069        self.PickId = 0
1070        self.PeakTable = []
1071        self.LimitsTable = []
1072        self.HKL = []
1073        self.Lines = []
1074        self.itemPicked = None
1075        self.dataFrame = None
1076        self.Interpolate = 'nearest'
1077        self.ContourColor = 'Paired'
1078        self.VcovColor = 'RdYlGn'
1079        self.RamaColor = 'Blues'
1080        self.Projection = 'equal area'
1081        self.logPlot = False
1082        self.qPlot = False
1083        self.Contour = False
1084        self.Legend = False
1085        self.SinglePlot = False
1086        self.SubBack = False
1087        self.plotView = 0
1088        self.Image = 0
1089        self.oldImagefile = ''
1090        self.ImageZ = []
1091        self.Integrate = 0
1092        self.imageDefault = {}
1093        self.Sngl = 0
1094        self.ifGetRing = False
1095        self.setPoly = False
1096        arg = sys.argv
1097        if len(arg) > 1:
1098            self.GSASprojectfile = arg[1]
1099            self.dirname = os.path.dirname(arg[1])
1100            if self.dirname: os.chdir(self.dirname)
1101            G2IO.ProjFileOpen(self)
1102            self.PatternTree.Expand(self.root)
1103            for item in self.Refine: item.Enable(True)
1104            for item in self.SeqRefine: item.Enable(True)
1105
1106    def OnSize(self,event):
1107        w,h = self.GetClientSizeTuple()
1108        self.mainPanel.SetSize(wx.Size(w,h))
1109        self.PatternTree.SetSize(wx.Size(w,h))
1110                       
1111    def OnPatternTreeSelChanged(self, event):
1112        if self.TreeItemDelete:
1113            self.TreeItemDelete = False
1114        else:
1115            pltNum = self.G2plotNB.nb.GetSelection()
1116            if pltNum >= 0:                         #to avoid the startup with no plot!
1117                pltPage = self.G2plotNB.nb.GetPage(pltNum)
1118                pltPlot = pltPage.figure
1119            item = event.GetItem()
1120            G2gd.MovePatternTreeToGrid(self,item)
1121            if self.oldFocus:
1122                self.oldFocus.SetFocus()
1123       
1124    def OnPatternTreeItemCollapsed(self, event):
1125        event.Skip()
1126
1127    def OnPatternTreeItemExpanded(self, event):
1128        event.Skip()
1129       
1130    def OnPatternTreeItemDelete(self, event):
1131        self.TreeItemDelete = True
1132
1133    def OnPatternTreeItemActivated(self, event):
1134        event.Skip()
1135       
1136    def OnPatternTreeKeyDown(self,event):
1137        key = event.GetKeyCode()
1138        item = self.PickId
1139        if type(item) is int: return # is this the toplevel in tree?
1140        if key == wx.WXK_UP:
1141            self.oldFocus = wx.Window.FindFocus()
1142            self.PatternTree.GetPrevSibling(item)
1143        elif key == wx.WXK_DOWN:
1144            self.oldFocus = wx.Window.FindFocus()
1145            self.PatternTree.GetNextSibling(item)
1146               
1147    def OnReadPowderPeaks(self,event):
1148        Cuka = 1.54052
1149        self.CheckNotebook()
1150        dlg = wx.FileDialog(self, 'Choose file with peak list', '.', '', 
1151            'peak files (*.txt)|*.txt|All files (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
1152        try:
1153            if dlg.ShowModal() == wx.ID_OK:
1154                self.HKL = []
1155                self.powderfile = dlg.GetPath()
1156                comments,peaks = G2IO.GetPowderPeaks(self.powderfile)
1157                Id = self.PatternTree.AppendItem(parent=self.root,text='PKS '+os.path.basename(self.powderfile))
1158                data = ['PKS',Cuka,0.0]
1159                names = ['Type','Lam','Zero'] 
1160                codes = [0,0,0]
1161                inst = [G2IO.makeInstDict(names,data,codes),{}]
1162                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
1163                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),comments)
1164                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),peaks)
1165                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
1166                self.PatternTree.Expand(Id)
1167                self.PatternTree.SelectItem(Id)
1168                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1169        finally:
1170            dlg.Destroy()
1171           
1172    def OnImageRead(self,event):
1173        self.CheckNotebook()
1174        dlg = wx.FileDialog(
1175            self, 'Choose image files', '.', '',
1176            'Any image file (*.edf;*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img;*.G2img)|'
1177            '*.edf;*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img;*.G2img;*.zip|'
1178            'European detector file (*.edf)|*.edf|'
1179            'Any detector tif (*.tif;*.tiff)|*.tif;*.tiff|'
1180            'MAR file (*.mar*)|*.mar*|'
1181            'GE Image (*.avg;*.sum)|*.avg;*.sum|'
1182            'ADSC Image (*.img)|*.img|'
1183            'GSAS-II Image (*.G2img)|*.G2img|'
1184            'Zip archive (*.zip)|*.zip|'
1185            'All files (*.*)|*.*',
1186            wx.OPEN | wx.MULTIPLE|wx.CHANGE_DIR)
1187        try:
1188            if dlg.ShowModal() == wx.ID_OK:
1189                imagefiles = dlg.GetPaths()
1190                imagefiles.sort()
1191                for imagefile in imagefiles:
1192                    # if a zip file, open and extract
1193                    if os.path.splitext(imagefile)[1].lower() == '.zip':
1194                        extractedfile = G2IO.ExtractFileFromZip(imagefile,parent=self)
1195                        if extractedfile is not None and extractedfile != imagefile:
1196                            imagefile = extractedfile
1197                    Comments,Data,Npix,Image = G2IO.GetImageData(self,imagefile)
1198                    if Comments:
1199                        Id = self.PatternTree.AppendItem(parent=self.root,text='IMG '+os.path.basename(imagefile))
1200                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
1201                        Imax = np.amax(Image)
1202                        Imin = max(0.0,np.amin(Image))          #force positive
1203                        if self.imageDefault:
1204                            Data = copy.copy(self.imageDefault)
1205                            Data['showLines'] = True
1206                            Data['ring'] = []
1207                            Data['rings'] = []
1208                            Data['cutoff'] = 10
1209                            Data['pixLimit'] = 20
1210                            Data['edgemin'] = 100000000
1211                            Data['calibdmin'] = 0.5
1212                            Data['calibskip'] = 0
1213                            Data['ellipses'] = []
1214                            Data['calibrant'] = ''
1215                            Data['GonioAngles'] = [0.,0.,0.]
1216                        else:
1217                            Data['type'] = 'PWDR'
1218                            Data['color'] = 'Paired'
1219                            Data['tilt'] = 0.0
1220                            Data['rotation'] = 0.0
1221                            Data['showLines'] = False
1222                            Data['ring'] = []
1223                            Data['rings'] = []
1224                            Data['cutoff'] = 10
1225                            Data['pixLimit'] = 20
1226                            Data['calibdmin'] = 0.5
1227                            Data['calibskip'] = 0
1228                            Data['edgemin'] = 100000000
1229                            Data['ellipses'] = []
1230                            Data['GonioAngles'] = [0.,0.,0.]
1231                            Data['calibrant'] = ''
1232                            Data['IOtth'] = [2.0,5.0]
1233                            Data['LRazimuth'] = [135,225]
1234                            Data['azmthOff'] = 0.0
1235                            Data['outChannels'] = 2500
1236                            Data['outAzimuths'] = 1
1237                            Data['centerAzm'] = False
1238                            Data['fullIntegrate'] = False
1239                            Data['setRings'] = False
1240                            Data['background image'] = ['',1.0]                           
1241                        Data['setDefault'] = False
1242                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
1243                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)
1244                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
1245                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
1246                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),
1247                            {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'strain':np.zeros((3,3))})
1248                        self.PatternTree.SetItemPyData(Id,[Npix,imagefile])
1249                        self.PickId = Id
1250                        self.Image = Id
1251                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1252                self.PatternTree.SelectItem(G2gd.GetPatternTreeItemId(self,Id,'Image Controls'))             #show last one
1253        finally:
1254            path = dlg.GetDirectory()           # to get Mac/Linux to change directory!
1255            os.chdir(path)
1256            dlg.Destroy()
1257
1258    def CheckNotebook(self):
1259        '''Make sure the data tree has the minimally expected controls
1260        (BHT) correct?
1261        '''
1262        if not G2gd.GetPatternTreeItemId(self,self.root,'Notebook'):
1263            sub = self.PatternTree.AppendItem(parent=self.root,text='Notebook')
1264            self.PatternTree.SetItemPyData(sub,[''])
1265        if not G2gd.GetPatternTreeItemId(self,self.root,'Controls'):
1266            sub = self.PatternTree.AppendItem(parent=self.root,text='Controls')
1267            self.PatternTree.SetItemPyData(sub,{'deriv type':'analytic Hessian',    #default controls
1268                'min dM/M':0.0001,'shift factor':1.,'max cyc':3,'F**2':True,
1269                'minF/sig':0,})
1270        if not G2gd.GetPatternTreeItemId(self,self.root,'Covariance'):
1271            sub = self.PatternTree.AppendItem(parent=self.root,text='Covariance')
1272            self.PatternTree.SetItemPyData(sub,{})
1273        if not G2gd.GetPatternTreeItemId(self,self.root,'Constraints'):
1274            sub = self.PatternTree.AppendItem(parent=self.root,text='Constraints')
1275            self.PatternTree.SetItemPyData(sub,{'Hist':[],'HAP':[],'Phase':[]})
1276        if not G2gd.GetPatternTreeItemId(self,self.root,'Restraints'):
1277            sub = self.PatternTree.AppendItem(parent=self.root,text='Restraints')
1278            self.PatternTree.SetItemPyData(sub,{})
1279        if not G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'):
1280            sub = self.PatternTree.AppendItem(parent=self.root,text='Rigid bodies')
1281            self.PatternTree.SetItemPyData(sub,{'Vector':{'AtInfo':{}},
1282                'Residue':{'AtInfo':{}},'RBIds':{'Vector':[],'Residue':[]}})
1283               
1284    class CopyDialog(wx.Dialog):
1285        def __init__(self,parent,title,text,data):
1286            wx.Dialog.__init__(self,parent,-1,title, 
1287                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1288            self.data = data
1289            panel = wx.Panel(self)
1290            mainSizer = wx.BoxSizer(wx.VERTICAL)
1291            topLabl = wx.StaticText(panel,-1,text)
1292            mainSizer.Add((10,10),1)
1293            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1294            mainSizer.Add((10,10),1)
1295            ncols = len(data)/40+1
1296            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=ncols,hgap=2,vgap=2)
1297            for id,item in enumerate(self.data):
1298                ckbox = wx.CheckBox(panel,id,item[1])
1299                ckbox.Bind(wx.EVT_CHECKBOX,self.OnCopyChange)                   
1300                dataGridSizer.Add(ckbox,0,wx.LEFT,10)
1301            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1302            OkBtn = wx.Button(panel,-1,"Ok")
1303            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1304            cancelBtn = wx.Button(panel,-1,"Cancel")
1305            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1306            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1307            btnSizer.Add((20,20),1)
1308            btnSizer.Add(OkBtn)
1309            btnSizer.Add((20,20),1)
1310            btnSizer.Add(cancelBtn)
1311            btnSizer.Add((20,20),1)
1312           
1313            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1314            panel.SetSizer(mainSizer)
1315            panel.Fit()
1316            self.Fit()
1317       
1318        def OnCopyChange(self,event):
1319            id = event.GetId()
1320            self.data[id][0] = self.FindWindowById(id).GetValue()       
1321           
1322        def OnOk(self,event):
1323            parent = self.GetParent()
1324            parent.Raise()
1325            self.EndModal(wx.ID_OK)             
1326           
1327        def OnCancel(self,event):
1328            parent = self.GetParent()
1329            parent.Raise()
1330            self.EndModal(wx.ID_CANCEL)             
1331           
1332        def GetData(self):
1333            return self.data
1334       
1335    class SumDialog(wx.Dialog):
1336        def __init__(self,parent,title,text,dataType,data):
1337            wx.Dialog.__init__(self,parent,-1,title, 
1338                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1339            self.data = data
1340            panel = wx.Panel(self)
1341            mainSizer = wx.BoxSizer(wx.VERTICAL)
1342            topLabl = wx.StaticText(panel,-1,text)
1343            mainSizer.Add((10,10),1)
1344            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1345            mainSizer.Add((10,10),1)
1346            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=2,hgap=2,vgap=2)
1347            for id,item in enumerate(self.data[:-1]):
1348                name = wx.TextCtrl(panel,-1,item[1],size=wx.Size(200,20))
1349                name.SetEditable(False)
1350                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
1351                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
1352                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
1353                dataGridSizer.Add(scale,0,wx.LEFT,10)
1354                dataGridSizer.Add(name,0,wx.RIGHT,10)
1355            if dataType:
1356                dataGridSizer.Add(wx.StaticText(panel,-1,'Sum result name: '+dataType),0, \
1357                    wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
1358                self.name = wx.TextCtrl(panel,-1,self.data[-1],size=wx.Size(200,20),style=wx.TE_PROCESS_ENTER)
1359                self.name.Bind(wx.EVT_TEXT_ENTER,self.OnNameChange)
1360                self.name.Bind(wx.EVT_KILL_FOCUS,self.OnNameChange)
1361                dataGridSizer.Add(self.name,0,wx.RIGHT|wx.TOP,10)
1362            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1363            OkBtn = wx.Button(panel,-1,"Ok")
1364            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1365            cancelBtn = wx.Button(panel,-1,"Cancel")
1366            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1367            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1368            btnSizer.Add((20,20),1)
1369            btnSizer.Add(OkBtn)
1370            btnSizer.Add((20,20),1)
1371            btnSizer.Add(cancelBtn)
1372            btnSizer.Add((20,20),1)
1373           
1374            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1375            panel.SetSizer(mainSizer)
1376            panel.Fit()
1377            self.Fit()
1378
1379        def OnScaleChange(self,event):
1380            id = event.GetId()
1381            value = self.FindWindowById(id).GetValue()
1382            try:
1383                self.data[id][0] = float(value)
1384                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
1385            except ValueError:
1386                if value and '-' not in value[0]:
1387                    print 'bad input - numbers only'
1388                    self.FindWindowById(id).SetValue('0.000')
1389           
1390        def OnNameChange(self,event):
1391            self.data[-1] = self.name.GetValue() 
1392           
1393        def OnOk(self,event):
1394            parent = self.GetParent()
1395            parent.Raise()
1396            self.EndModal(wx.ID_OK)             
1397           
1398        def OnCancel(self,event):
1399            parent = self.GetParent()
1400            parent.Raise()
1401            self.EndModal(wx.ID_CANCEL)             
1402           
1403        def GetData(self):
1404            return self.data
1405           
1406    class ConstraintDialog(wx.Dialog):
1407        '''Window to edit Constraint values
1408        '''
1409        def __init__(self,parent,title,text,data,separator='*'):
1410            wx.Dialog.__init__(self,parent,-1,title, 
1411                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1412            self.data = data
1413            panel = wx.Panel(self)
1414            mainSizer = wx.BoxSizer(wx.VERTICAL)
1415            topLabl = wx.StaticText(panel,-1,text)
1416            mainSizer.Add((10,10),1)
1417            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1418            mainSizer.Add((10,10),1)
1419            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=2,hgap=2,vgap=2)
1420            for id,item in enumerate(self.data[:-1]):
1421                lbl = item[1]
1422                if lbl[-1] != '=': lbl += ' ' + separator + ' '
1423                name = wx.StaticText(panel,-1,lbl,size=wx.Size(200,20),
1424                                     style=wx.ALIGN_RIGHT)
1425                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
1426                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
1427                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
1428                dataGridSizer.Add(name,0,wx.LEFT,10)
1429                dataGridSizer.Add(scale,0,wx.RIGHT,10)
1430            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1431            OkBtn = wx.Button(panel,-1,"Ok")
1432            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1433            cancelBtn = wx.Button(panel,-1,"Cancel")
1434            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1435            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1436            btnSizer.Add((20,20),1)
1437            btnSizer.Add(OkBtn)
1438            btnSizer.Add((20,20),1)
1439            btnSizer.Add(cancelBtn)
1440            btnSizer.Add((20,20),1)
1441           
1442            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1443            panel.SetSizer(mainSizer)
1444            panel.Fit()
1445            self.Fit()
1446            self.CenterOnParent()
1447           
1448        def OnNameChange(self,event):
1449            self.data[-1] = self.name.GetValue() 
1450           
1451        def OnScaleChange(self,event):
1452            id = event.GetId()
1453            value = self.FindWindowById(id).GetValue()
1454            try:
1455                self.data[id][0] = float(value)
1456                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
1457            except ValueError:
1458                if value and '-' not in value[0]:
1459                    print 'bad input - numbers only'
1460                    self.FindWindowById(id).SetValue('0.000')
1461           
1462        def OnOk(self,event):
1463            parent = self.GetParent()
1464            parent.Raise()
1465            self.EndModal(wx.ID_OK)             
1466           
1467        def OnCancel(self,event):
1468            parent = self.GetParent()
1469            parent.Raise()
1470            self.EndModal(wx.ID_CANCEL)             
1471           
1472        def GetData(self):
1473            return self.data
1474           
1475    def OnPwdrSum(self,event):
1476        TextList = []
1477        DataList = []
1478        SumList = []
1479        Names = []
1480        Inst = None
1481        SumItemList = []
1482        Comments = ['Sum equals: \n']
1483        if self.PatternTree.GetCount():
1484            item, cookie = self.PatternTree.GetFirstChild(self.root)
1485            while item:
1486                name = self.PatternTree.GetItemText(item)
1487                Names.append(name)
1488                if 'PWDR' in name:
1489                    TextList.append([0.0,name])
1490                    DataList.append(self.PatternTree.GetItemPyData(item)[1])    # (x,y,w,yc,yb,yd)
1491                    if not Inst:
1492                        Inst = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item, 'Instrument Parameters'))
1493                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1494            if len(TextList) < 2:
1495                self.ErrorDialog('Not enough data to sum','There must be more than one "PWDR" pattern')
1496                return
1497            TextList.append('default_sum_name')               
1498            dlg = self.SumDialog(self,'Sum data','Enter scale for each pattern in summation','PWDR',TextList)
1499            try:
1500                if dlg.ShowModal() == wx.ID_OK:
1501                    lenX = 0
1502                    Xminmax = [0,0]
1503                    Xsum = []
1504                    Ysum = []
1505                    Vsum = []
1506                    result = dlg.GetData()
1507                    for i,item in enumerate(result[:-1]):
1508                        scale,name = item
1509                        data = DataList[i]
1510                        if scale:
1511                            Comments.append("%10.3f %s" % (scale,' * '+name))
1512                            x,y,w,yc,yb,yd = data   #numpy arrays!
1513                            v = 1./w
1514                            if lenX:
1515                                if lenX != len(x):
1516                                    self.ErrorDialog('Data length error','Data to be summed must have same number of points'+ \
1517                                        '\nExpected:'+str(lenX)+ \
1518                                        '\nFound:   '+str(len(x))+'\nfor '+name)
1519                                    return
1520                            else:
1521                                lenX = len(x)
1522                            if Xminmax[1]:
1523                                if Xminmax != [x[0],x[-1]]:
1524                                    self.ErrorDialog('Data range error','Data to be summed must span same range'+ \
1525                                        '\nExpected:'+str(Xminmax[0])+' '+str(Xminmax[1])+ \
1526                                        '\nFound:   '+str(x[0])+' '+str(x[-1])+'\nfor '+name)
1527                                    return
1528                                else:
1529                                    for j,yi in enumerate(y):
1530                                         Ysum[j] += scale*yi
1531                                         Vsum[j] += abs(scale)*v[j]
1532                            else:
1533                                Xminmax = [x[0],x[-1]]
1534                                YCsum = YBsum = YDsum = [0.0 for i in range(lenX)]
1535                                for j,yi in enumerate(y):
1536                                    Xsum.append(x[j])
1537                                    Ysum.append(scale*yi)
1538                                    Vsum.append(abs(scale*v[j]))
1539                    Wsum = 1./np.array(Vsum)
1540                    outname = 'PWDR '+result[-1]
1541                    Id = 0
1542                    if outname in Names:
1543                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
1544                        try:
1545                            if dlg2.ShowModal() == wx.ID_OK:
1546                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
1547                                self.PatternTree.Delete(Id)
1548                        finally:
1549                            dlg2.Destroy()
1550                    Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
1551                    if Id:
1552                        Sample = G2pdG.SetDefaultSample()
1553                        self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0},[np.array(Xsum),np.array(Ysum),np.array(Wsum),
1554                            np.array(YCsum),np.array(YBsum),np.array(YDsum)]])
1555                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
1556                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
1557                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',True,3,1.0,0.0,0.0],
1558                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
1559                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
1560                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
1561                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Peak List'),[])
1562                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[])
1563                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
1564                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
1565                        self.PatternTree.SelectItem(Id)
1566                        self.PatternTree.Expand(Id)
1567                   
1568            finally:
1569                dlg.Destroy()
1570
1571    def OnImageSum(self,event):
1572        TextList = []
1573        DataList = []
1574        SumList = []
1575        Names = []
1576        Inst = []
1577        SumItemList = []
1578        Comments = ['Sum equals: \n']
1579        if self.PatternTree.GetCount():
1580            item, cookie = self.PatternTree.GetFirstChild(self.root)
1581            while item:
1582                name = self.PatternTree.GetItemText(item)
1583                Names.append(name)
1584                if 'IMG' in name:
1585                    TextList.append([0.0,name])
1586                    DataList.append(self.PatternTree.GetItemPyData(item))        #Size,Image
1587                    Data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item,'Image Controls'))
1588                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1589            if len(TextList) < 2:
1590                self.ErrorDialog('Not enough data to sum','There must be more than one "IMG" pattern')
1591                return
1592            TextList.append('default_sum_name')               
1593            dlg = self.SumDialog(self,'Sum data','Enter scale for each image in summation','IMG',TextList)
1594            try:
1595                if dlg.ShowModal() == wx.ID_OK:
1596                    imSize = 0
1597                    result = dlg.GetData()
1598                    First = True
1599                    Found = False
1600                    for i,item in enumerate(result[:-1]):
1601                        scale,name = item
1602                        data = DataList[i]
1603                        if scale:
1604                            Found = True                               
1605                            Comments.append("%10.3f %s" % (scale,' * '+name))
1606                            Npix,imagefile = data
1607                            image = G2IO.GetImageData(self,imagefile,imageOnly=True)
1608                            if First:
1609                                newImage = np.zeros_like(image)
1610                                First = False
1611                            if imSize:
1612                                if imSize != Npix:
1613                                    self.ErrorDialog('Image size error','Images to be summed must be same size'+ \
1614                                        '\nExpected:'+str(imSize)+ \
1615                                        '\nFound:   '+str(Npix)+'\nfor '+name)
1616                                    return
1617                                newImage = newImage+scale*image
1618                            else:
1619                                imSize = Npix
1620                                newImage = newImage+scale*image
1621                            del(image)
1622                    if not Found:
1623                        self.ErrorDialog('Image sum error','No nonzero image multipliers found')
1624                        return
1625                       
1626                    newImage = np.asfarray(newImage,dtype=np.float32)                       
1627                    outname = 'IMG '+result[-1]
1628                    Id = 0
1629                    if outname in Names:
1630                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
1631                        try:
1632                            if dlg2.ShowModal() == wx.ID_OK:
1633                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
1634                        finally:
1635                            dlg2.Destroy()
1636                    else:
1637                        Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
1638                    if Id:
1639                        dlg = wx.FileDialog(self, 'Choose sum image filename', '.', '', 
1640                            'G2img files (*.G2img)|*.G2img', 
1641                            wx.SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1642                        if dlg.ShowModal() == wx.ID_OK:
1643                            newimagefile = dlg.GetPath()
1644                            newimagefile = G2IO.FileDlgFixExt(dlg,newimagefile)
1645                            G2IO.PutG2Image(newimagefile,Comments,Data,Npix,newImage)
1646                            Imax = np.amax(newImage)
1647                            Imin = np.amin(newImage)
1648                            newImage = []
1649                            self.PatternTree.SetItemPyData(Id,[imSize,newimagefile])
1650                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
1651                        del(newImage)
1652                        if self.imageDefault:
1653                            Data = copy.copy(self.imageDefault)
1654                        Data['showLines'] = True
1655                        Data['ring'] = []
1656                        Data['rings'] = []
1657                        Data['cutoff'] = 10
1658                        Data['pixLimit'] = 20
1659                        Data['ellipses'] = []
1660                        Data['calibrant'] = ''
1661                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
1662                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)                                           
1663                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
1664                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
1665                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),{})
1666                        self.PatternTree.SelectItem(Id)
1667                        self.PatternTree.Expand(Id)
1668                        self.PickId = G2gd.GetPatternTreeItemId(self,self.root,outname)
1669                        self.Image = self.PickId
1670            finally:
1671                dlg.Destroy()
1672                     
1673    def OnAddPhase(self,event):
1674        if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
1675            sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
1676        else:
1677            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1678        PhaseName = ''
1679        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
1680            style=wx.OK)
1681        if dlg.ShowModal() == wx.ID_OK:
1682            PhaseName = dlg.GetValue()
1683        dlg.Destroy()
1684        sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
1685        E,SGData = G2spc.SpcGroup('P 1')
1686        self.PatternTree.SetItemPyData(sub,G2IO.SetNewPhase(Name=PhaseName,SGData=SGData))
1687       
1688    def OnDeletePhase(self,event):
1689        #Hmm, also need to delete this phase from Reflection Lists for each PWDR histogram
1690        if self.dataFrame:
1691            self.dataFrame.Clear() 
1692        TextList = []
1693        DelList = []
1694        DelItemList = []
1695        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
1696            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1697        else:
1698            return
1699        if sub:
1700            item, cookie = self.PatternTree.GetFirstChild(sub)
1701            while item:
1702                TextList.append(self.PatternTree.GetItemText(item))
1703                item, cookie = self.PatternTree.GetNextChild(sub, cookie)               
1704            dlg = wx.MultiChoiceDialog(self, 'Which phase to delete?', 'Delete phase', TextList, wx.CHOICEDLG_STYLE)
1705            try:
1706                if dlg.ShowModal() == wx.ID_OK:
1707                    result = dlg.GetSelections()
1708                    for i in result: DelList.append([i,TextList[i]])
1709                    item, cookie = self.PatternTree.GetFirstChild(sub)
1710                    i = 0
1711                    while item:
1712                        if [i,self.PatternTree.GetItemText(item)] in DelList: DelItemList.append(item)
1713                        item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1714                        i += 1
1715                    for item in DelItemList:
1716                        name = self.PatternTree.GetItemText(item)
1717                        self.PatternTree.Delete(item)
1718                        self.G2plotNB.Delete(name)
1719                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1720                    while item:
1721                        name = self.PatternTree.GetItemText(item)
1722                        if 'PWDR' in name:
1723                            Id = G2gd.GetPatternTreeItemId(self,item, 'Reflection Lists')
1724                            refList = self.PatternTree.GetItemPyData(Id)
1725                            for i,item in DelList:
1726                                del(refList[item])
1727                            self.PatternTree.SetItemPyData(Id,refList)
1728                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1729            finally:
1730                dlg.Destroy()
1731               
1732    def OnRenameData(self,event):
1733        name = self.PatternTree.GetItemText(self.PickId)     
1734        if 'PWDR' in name or 'HKLF' in name or 'IMG' in name:
1735            dataType = name[:name.index(' ')+1]                 #includes the ' '
1736            dlg = wx.TextEntryDialog(self,'Data name: '+dataType,'Change data name',
1737                defaultValue=name[name.index(' ')+1:])
1738            try:
1739                if dlg.ShowModal() == wx.ID_OK:
1740                    self.PatternTree.SetItemText(self.PickId,dataType+dlg.GetValue())
1741            finally:
1742                dlg.Destroy()
1743       
1744    def GetFileList(self,fileType,skip=None):        #potentially useful?
1745        fileList = []
1746        Source = ''
1747        id, cookie = self.PatternTree.GetFirstChild(self.root)
1748        while id:
1749            name = self.PatternTree.GetItemText(id)
1750            if fileType in name:
1751                if id == skip:
1752                    Source = name
1753                else:
1754                    fileList.append([False,name,id])
1755            id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1756        if skip:
1757            return fileList,Source
1758        else:
1759            return fileList
1760           
1761    def OnDataDelete(self, event):
1762        TextList = ['All Data']
1763        DelList = []
1764        DelItemList = []
1765        ifPWDR = False
1766        ifIMG = False
1767        ifHKLF = False
1768        ifPDF = False
1769        if self.PatternTree.GetCount():
1770            item, cookie = self.PatternTree.GetFirstChild(self.root)
1771            while item:
1772                name = self.PatternTree.GetItemText(item)
1773                if name not in ['Notebook','Controls','Covariance','Constraints','Restraints','Phases']:
1774                    if 'PWDR' in name: ifPWDR = True
1775                    if 'IMG' in name: ifIMG = True
1776                    if 'HKLF' in name: ifHKLF = True
1777                    if 'PDF' in name: ifPDF = True
1778                    TextList.append(name)
1779                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1780            if ifPWDR: TextList.insert(1,'All PWDR')
1781            if ifIMG: TextList.insert(1,'All IMG')
1782            if ifHKLF: TextList.insert(1,'All HKLF')
1783            if ifPDF: TextList.insert(1,'All PDF')               
1784            dlg = wx.MultiChoiceDialog(self, 'Which data to delete?', 'Delete data', TextList, wx.CHOICEDLG_STYLE)
1785            try:
1786                if dlg.ShowModal() == wx.ID_OK:
1787                    result = dlg.GetSelections()
1788                    for i in result: DelList.append(TextList[i])
1789                    if 'All Data' in DelList:
1790                        DelList = [item for item in TextList if item[:3] != 'All']
1791                    elif 'All PWDR' in DelList:
1792                        DelList = [item for item in TextList if item[:4] == 'PWDR']
1793                    elif 'All IMG' in DelList:
1794                        DelList = [item for item in TextList if item[:3] == 'IMG']
1795                    elif 'All HKLF' in DelList:
1796                        DelList = [item for item in TextList if item[:4] == 'HKLF']
1797                    elif 'All PDF' in DelList:
1798                        DelList = [item for item in TextList if item[:3] == 'PDF']
1799                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1800                    while item:
1801                        if self.PatternTree.GetItemText(item) in DelList: DelItemList.append(item)
1802                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1803                    for item in DelItemList:
1804                        self.PatternTree.Delete(item)
1805                    self.PickId = 0
1806                    wx.CallAfter(G2plt.PlotPatterns,self,True)                        #so plot gets updated
1807            finally:
1808                dlg.Destroy()
1809
1810    def OnFileOpen(self, event):
1811        result = ''
1812        Id = 0
1813        if self.PatternTree.GetChildrenCount(self.root,False):
1814            if self.dataFrame:
1815                self.dataFrame.Clear() 
1816            dlg = wx.MessageDialog(
1817                self,
1818                'Do you want to overwrite the current project? '
1819                'Any unsaved changes will be lost. Press OK to continue.',
1820                'Overwrite?',  wx.OK | wx.CANCEL)
1821            try:
1822                result = dlg.ShowModal()
1823                if result == wx.ID_OK:
1824                    self.PatternTree.DeleteChildren(self.root)
1825                    self.GSASprojectfile = ''
1826                    if self.HKL: self.HKL = []
1827                    if self.G2plotNB.plotList:
1828                        self.G2plotNB.clear()
1829            finally:
1830                dlg.Destroy()
1831        if result != wx.ID_CANCEL:   
1832            if self.dataDisplay: self.dataDisplay.Destroy()
1833            dlg = wx.FileDialog(self, 'Choose GSAS-II project file', '.', '', 
1834                'GSAS-II project file (*.gpx)|*.gpx',wx.OPEN|wx.CHANGE_DIR)
1835            try:
1836                if dlg.ShowModal() == wx.ID_OK:
1837                    self.GSASprojectfile = dlg.GetPath()
1838                    self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
1839                    self.dirname = dlg.GetDirectory()
1840                    G2IO.ProjFileOpen(self)
1841                    self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
1842                    self.PatternTree.Expand(self.root)
1843                    self.HKL = []
1844                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1845                    while item and not Id:
1846                        name = self.PatternTree.GetItemText(item)
1847                        if name[:4] in ['PWDR','HKLF','IMG ','PDF ']:
1848                            Id = item
1849                        elif name == 'Controls':
1850                            data = self.PatternTree.GetItemPyData(item)
1851                            if data:
1852                                for item in self.Refine: item.Enable(True)
1853                                for item in self.SeqRefine: item.Enable(True)
1854                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
1855                    if Id:
1856                        self.PatternTree.SelectItem(Id)
1857                    self.CheckNotebook()
1858                    os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1859            finally:
1860                dlg.Destroy()
1861
1862    def OnFileClose(self, event):
1863        if self.dataFrame:
1864            self.dataFrame.Clear()
1865            self.dataFrame.SetLabel('GSAS-II data display') 
1866        dlg = wx.MessageDialog(self, 'Save current project?', ' ', wx.YES | wx.NO | wx.CANCEL)
1867        try:
1868            result = dlg.ShowModal()
1869            if result == wx.ID_OK:
1870                self.OnFileSaveMenu(event)
1871            if result != wx.ID_CANCEL:
1872                self.GSASprojectfile = ''
1873                self.PatternTree.SetItemText(self.root,'Loaded Data: ')
1874                self.PatternTree.DeleteChildren(self.root)
1875                if self.HKL: self.HKL = []
1876                if self.G2plotNB.plotList:
1877                    self.G2plotNB.clear()
1878        finally:
1879            dlg.Destroy()
1880
1881    def OnFileSave(self, event):
1882       
1883        if self.GSASprojectfile: 
1884            self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
1885            G2IO.ProjFileSave(self)
1886        else:
1887            self.OnFileSaveas(event)
1888
1889    def OnFileSaveas(self, event):
1890        dlg = wx.FileDialog(self, 'Choose GSAS-II project file name', '.', '', 
1891            'GSAS-II project file (*.gpx)|*.gpx',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1892        try:
1893            if dlg.ShowModal() == wx.ID_OK:
1894                self.GSASprojectfile = dlg.GetPath()
1895                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
1896                self.PatternTree.SetItemText(self.root,'Saving project as'+self.GSASprojectfile)
1897                self.SetTitle("GSAS-II data tree: "+
1898                              os.path.split(self.GSASprojectfile)[1])
1899                G2IO.ProjFileSave(self)
1900                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1901        finally:
1902            dlg.Destroy()
1903
1904    def ExitMain(self, event):
1905        if self.undofile:
1906            os.remove(self.undofile)
1907        sys.exit()
1908       
1909    def OnFileExit(self, event):
1910        if self.dataFrame:
1911            self.dataFrame.Clear() 
1912            self.dataFrame.Destroy()
1913        self.Close()
1914       
1915    def OnExportPatterns(self,event):
1916        names = ['All']
1917        exports = []
1918        item, cookie = self.PatternTree.GetFirstChild(self.root)
1919        while item:
1920            name = self.PatternTree.GetItemText(item)
1921            if 'PWDR' in name:
1922                names.append(name)
1923            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1924        if names:
1925            dlg = wx.MultiChoiceDialog(self,'Select','Powder patterns to export',names)
1926            if dlg.ShowModal() == wx.ID_OK:
1927                sel = dlg.GetSelections()
1928                if sel[0] == 0:
1929                    exports = names[1:]
1930                else:
1931                    for x in sel:
1932                        exports.append(names[x])
1933            dlg.Destroy()
1934        if exports:
1935            dlg = wx.FileDialog(self, 'Choose output powder file name', '.', '', 
1936                'GSAS fxye file (*.fxye)|*.fxye|xye file (*.xye)|*.xye',
1937                wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1938            try:
1939                if dlg.ShowModal() == wx.ID_OK:
1940                    powderfile = dlg.GetPath()
1941                    powderfile = G2IO.FileDlgFixExt(dlg,powderfile)
1942                    if 'fxye' in powderfile:
1943                        G2IO.powderFxyeSave(self,exports,powderfile)
1944                    else:       #just xye
1945                        G2IO.powderXyeSave(self,exports,powderfile)
1946            finally:
1947                dlg.Destroy()
1948       
1949    def OnExportPeakList(self,event):
1950        dlg = wx.FileDialog(self, 'Choose output peak list file name', '.', '', 
1951            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1952        try:
1953            if dlg.ShowModal() == wx.ID_OK:
1954                self.peaklistfile = dlg.GetPath()
1955                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
1956                file = open(self.peaklistfile,'w')               
1957                item, cookie = self.PatternTree.GetFirstChild(self.root)
1958                while item:
1959                    name = self.PatternTree.GetItemText(item)
1960                    if 'PWDR' in name:
1961                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
1962                        while item2:
1963                            name2 = self.PatternTree.GetItemText(item2)
1964                            if name2 == 'Peak List':
1965                                peaks = self.PatternTree.GetItemPyData(item2)
1966                                file.write("%s \n" % (name+' Peak List'))               
1967                                for peak in peaks:
1968                                    file.write("%10.5f %12.2f %10.3f %10.3f \n" % \
1969                                        (peak[0],peak[2],peak[4],peak[6]))
1970                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
1971                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
1972                file.close()
1973        finally:
1974            dlg.Destroy()
1975       
1976    def OnExportHKL(self,event):
1977        event.Skip()
1978       
1979    def OnExportPDF(self,event):
1980        #need S(Q) and G(R) to be saved here - probably best from selection?
1981        names = ['All']
1982        exports = []
1983        item, cookie = self.PatternTree.GetFirstChild(self.root)
1984        while item:
1985            name = self.PatternTree.GetItemText(item)
1986            if 'PDF' in name:
1987                names.append(name)
1988            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1989        if names:
1990            dlg = wx.MultiChoiceDialog(self,'Select','PDF patterns to export',names)
1991            if dlg.ShowModal() == wx.ID_OK:
1992                sel = dlg.GetSelections()
1993                if sel[0] == 0:
1994                    exports = names[1:]
1995                else:
1996                    for x in sel:
1997                        exports.append(names[x])
1998            dlg.Destroy()
1999        if exports:
2000            G2IO.PDFSave(self,exports)
2001       
2002    def OnExportPhase(self,event):
2003        event.Skip()
2004       
2005    def OnExportCIF(self,event):
2006        event.Skip()
2007
2008    def OnMakePDFs(self,event):
2009        tth2q = lambda t,w:4.0*math.pi*sind(t/2.0)/w
2010        TextList = ['All PWDR']
2011        PDFlist = []
2012        Names = []
2013        if self.PatternTree.GetCount():
2014            id, cookie = self.PatternTree.GetFirstChild(self.root)
2015            while id:
2016                name = self.PatternTree.GetItemText(id)
2017                Names.append(name)
2018                if 'PWDR' in name:
2019                    TextList.append(name)
2020                id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2021            if len(TextList) == 1:
2022                self.ErrorDialog('Nothing to make PDFs for','There must be at least one "PWDR" pattern')
2023                return
2024            dlg = wx.MultiChoiceDialog(self,'Make PDF controls','Make PDF controls for:',TextList, wx.CHOICEDLG_STYLE)
2025            try:
2026                if dlg.ShowModal() == wx.ID_OK:
2027                    result = dlg.GetSelections()
2028                    for i in result: PDFlist.append(TextList[i])
2029                    if 0 in result:
2030                        PDFlist = [item for item in TextList if item[:4] == 'PWDR']                       
2031                    for item in PDFlist:
2032                        PWDRname = item[4:]
2033                        Id = self.PatternTree.AppendItem(parent=self.root,text='PDF '+PWDRname)
2034                        Data = {
2035                            'Sample':{'Name':item,'Mult':1.0,'Add':0.0},
2036                            'Sample Bkg.':{'Name':'','Mult':-1.0,'Add':0.0},
2037                            'Container':{'Name':'','Mult':-1.0,'Add':0.0},
2038                            'Container Bkg.':{'Name':'','Mult':-1.0,'Add':0.0},'ElList':{},
2039                            'Geometry':'Cylinder','Diam':1.0,'Pack':0.50,'Form Vol':10.0,
2040                            'DetType':'Image plate','ObliqCoeff':0.2,'Ruland':0.025,'QScaleLim':[0,100],
2041                            'Lorch':True,}
2042                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='PDF Controls'),Data)
2043                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='I(Q)'+PWDRname),[])       
2044                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='S(Q)'+PWDRname),[])       
2045                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='F(Q)'+PWDRname),[])       
2046                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='G(R)'+PWDRname),[])       
2047                for item in self.ExportPDF: item.Enable(True)
2048            finally:
2049                dlg.Destroy()
2050               
2051    def GetPWDRdatafromTree(self,PWDRname):
2052        ''' Returns powder data from GSASII tree
2053        input:
2054            PWDRname = powder histogram name as obtained from GetHistogramNames
2055        return:
2056            PWDRdata = powder data dictionary with:
2057                Data - powder data arrays, Limits, Instrument Parameters, Sample Parameters           
2058        '''
2059        PWDRdata = {}
2060        try:
2061            PWDRdata.update(self.PatternTree.GetItemPyData(PWDRname)[0])            #wtFactor + ?
2062        except ValueError:
2063            PWDRdata['wtFactor'] = 1.0
2064        PWDRdata['Data'] = self.PatternTree.GetItemPyData(PWDRname)[1]          #powder data arrays
2065        PWDRdata['Limits'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Limits'))
2066        PWDRdata['Background'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Background'))
2067        PWDRdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Instrument Parameters'))
2068        PWDRdata['Sample Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Sample Parameters'))
2069        PWDRdata['Reflection Lists'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Reflection Lists'))
2070        if 'ranId' not in PWDRdata['Sample Parameters']:
2071            PWDRdata['Sample Parameters']['ranId'] = ran.randint(0,sys.maxint)
2072        PWDRdata['ranId'] = PWDRdata['Sample Parameters']['ranId']
2073        return PWDRdata
2074
2075    def GetHKLFdatafromTree(self,HKLFname):
2076        ''' Returns single crystal data from GSASII tree
2077        input:
2078            HKLFname = single crystal histogram name as obtained from GetHistogramNames
2079        return:
2080            HKLFdata = single crystal data list of reflections: for each reflection:
2081                HKLF =
2082        '''
2083        HKLFdata = {}
2084        try:
2085            HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
2086        except ValueError:
2087            HKLFdata['wtFactor'] = 1.0
2088        HKLFdata['Data'] = self.PatternTree.GetItemPyData(HKLFname)[1]
2089        HKLFdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,HKLFname,'Instrument Parameters'))
2090        return HKLFdata
2091       
2092    def GetPhaseData(self):
2093        phaseData = {}
2094        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
2095            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
2096        else:
2097            print 'no phases to be refined'
2098            return
2099        if sub:
2100            item, cookie = self.PatternTree.GetFirstChild(sub)
2101            while item:
2102                phaseName = self.PatternTree.GetItemText(item)
2103                phaseData[phaseName] =  self.PatternTree.GetItemPyData(item)
2104                if 'ranId' not in phaseData[phaseName]:
2105                    phaseData[phaseName]['ranId'] = ran.randint(0,sys.maxint)         
2106                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
2107        return phaseData               
2108                   
2109    def GetUsedHistogramsAndPhasesfromTree(self):
2110        ''' Returns all histograms that are found in any phase
2111        and any phase that uses a histogram
2112        return:
2113            Histograms = dictionary of histograms as {name:data,...}
2114            Phases = dictionary of phases that use histograms
2115        '''
2116        phaseData = self.GetPhaseData()
2117        if not phaseData:
2118            return {},{}
2119        Histograms = {}
2120        Phases = {}
2121        pId = 0
2122        hId = 0
2123        for phase in phaseData:
2124            Phase = phaseData[phase]
2125            if Phase['Histograms']:
2126                if phase not in Phases:
2127                    Phase['pId'] = pId
2128                    pId += 1
2129                    Phases[phase] = Phase
2130                for hist in Phase['Histograms']:
2131                    if hist not in Histograms:
2132                        item = G2gd.GetPatternTreeItemId(self,self.root,hist)
2133                        if 'PWDR' in hist[:4]: 
2134                            Histograms[hist] = self.GetPWDRdatafromTree(item)
2135                        elif 'HKLF' in hist[:4]:
2136                            Histograms[hist] = self.GetHKLFdatafromTree(item)
2137                        #future restraint, etc. histograms here           
2138                        Histograms[hist]['hId'] = hId
2139                        hId += 1
2140        return Histograms,Phases
2141       
2142    class ViewParmDialog(wx.Dialog):
2143        def __init__(self,parent,title,parmDict):
2144            wx.Dialog.__init__(self,parent,-1,title,size=(300,430),
2145                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
2146            panel = wx.Panel(self,size=(300,430))
2147            parmNames = parmDict.keys()
2148            parmNames.sort()
2149            parmText = ' p:h:Parameter       refine?              value\n'
2150            for name in parmNames:
2151                parmData = parmDict[name]
2152                try:
2153                    parmText += ' %s \t%12.4g \n'%(name.ljust(19)+'\t'+parmData[1],parmData[0])
2154                except TypeError:
2155                    pass
2156            parmTable = wx.TextCtrl(panel,-1,parmText,
2157                style=wx.TE_MULTILINE|wx.TE_READONLY,size=(290,400))
2158            mainSizer = wx.BoxSizer(wx.VERTICAL)
2159            mainSizer.Add(parmTable)
2160            panel.SetSizer(mainSizer)
2161                           
2162    def OnViewLSParms(self,event):
2163        parmDict = {}
2164        Histograms,Phases = self.GetUsedHistogramsAndPhasesfromTree()
2165        rigidbodyDict = self.PatternTree.GetItemPyData(   
2166            G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'))
2167        rbVary,rbDict = G2str.GetRigidBodyModels(rigidbodyDict,Print=False)
2168        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
2169        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable = G2str.GetPhaseData(Phases,RestraintDict=None,rbIds=rbIds,Print=False)       
2170        hapVary,hapDict,controlDict = G2str.GetHistogramPhaseData(Phases,Histograms,Print=False)
2171        histVary,histDict,controlDict = G2str.GetHistogramData(Histograms,Print=False)
2172        varyList = rbVary+phaseVary+hapVary+histVary
2173        parmDict.update(rbDict)
2174        parmDict.update(phaseDict)
2175        parmDict.update(hapDict)
2176        parmDict.update(histDict)
2177        for parm in parmDict:
2178            if parm.split(':')[-1] in ['Azimuth','Gonio. radius','Lam1','Lam2',
2179                'Omega','Chi','Phi','nDebye','nPeaks']:
2180                parmDict[parm] = [parmDict[parm],' ']
2181            elif parm.split(':')[-2] in ['Ax','Ay','Az','SHmodel','SHord']:
2182                parmDict[parm] = [parmDict[parm],' ']
2183            elif parm in varyList:
2184                parmDict[parm] = [parmDict[parm],'True']
2185            else:
2186                parmDict[parm] = [parmDict[parm],'False']
2187        parmDict[' Num refined'] = [len(varyList),'']
2188        dlg = self.ViewParmDialog(self,'Parameters for least squares',parmDict)
2189        try:
2190            if dlg.ShowModal() == wx.ID_OK:
2191                print 'do something with changes?? - No!'
2192        finally:
2193            dlg.Destroy()
2194       
2195    def OnRefine(self,event):
2196        self.OnFileSave(event)
2197        # check that constraints are OK here
2198        errmsg, warnmsg = G2str.CheckConstraints(self.GSASprojectfile)
2199        if errmsg:
2200            print('Error in constraints:\n'+errmsg+
2201                  '\nRefinement not possible')
2202            self.ErrorDialog('Constraint Error',
2203                             'Error in constraints:\n'+errmsg+
2204                             '\nRefinement not possible')
2205            return
2206        if warnmsg:
2207            print('Conflict between refinment flag settings and constraints:\n'+
2208                  warnmsg+'\nRefinement not possible')
2209            self.ErrorDialog('Refinement Flag Error',
2210                             'Conflict between refinment flag settings and constraints:\n'+
2211                             warnmsg+
2212                             '\nRefinement not possible')
2213            return
2214        #works - but it'd be better if it could restore plots
2215        dlg = wx.ProgressDialog('Residual','All data Rw =',101.0, 
2216            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
2217        screenSize = wx.ClientDisplayRect()
2218        Size = dlg.GetSize()
2219        Size = (int(Size[0]*1.2),Size[1]) # increase size a bit along x
2220        dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
2221        dlg.SetSize(Size)
2222        Rw = 100.00
2223        try:
2224            Rw = G2str.Refine(self.GSASprojectfile,dlg)
2225        finally:
2226            dlg.Destroy()
2227        oldId =  self.PatternTree.GetSelection()
2228        oldName = self.PatternTree.GetItemText(oldId)
2229        parentId = self.PatternTree.GetItemParent(oldId)
2230        parentName = ''
2231        if parentId:
2232            parentName = self.PatternTree.GetItemText(parentId)
2233        dlg = wx.MessageDialog(self,'Load new result?','Refinement results, Rw =%.3f'%(Rw),wx.OK|wx.CANCEL)
2234        try:
2235            if dlg.ShowModal() == wx.ID_OK:
2236                Id = 0
2237                self.PatternTree.DeleteChildren(self.root)
2238                if self.HKL: self.HKL = []
2239                if self.G2plotNB.plotList:
2240                    self.G2plotNB.clear()
2241                G2IO.ProjFileOpen(self)
2242                item, cookie = self.PatternTree.GetFirstChild(self.root)
2243                while item and not Id:
2244                    name = self.PatternTree.GetItemText(item)
2245                    if name[:4] in ['PWDR','HKLF']:
2246                        Id = item
2247                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
2248                if parentName:
2249                    parentId = G2gd.GetPatternTreeItemId(self, self.root, parentName)
2250                    if parentId:
2251                        itemId = G2gd.GetPatternTreeItemId(self, parentId, oldName)
2252                    else:
2253                        itemId = G2gd.GetPatternTreeItemId(self, self.root, oldName)
2254                    self.PatternTree.SelectItem(itemId)
2255                elif Id:
2256                    self.PatternTree.SelectItem(Id)
2257        finally:
2258            dlg.Destroy()
2259
2260    def OnSeqRefine(self,event):
2261        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequental results')
2262        if not Id:
2263            Id = self.PatternTree.AppendItem(self.root,text='Sequental results')
2264            self.PatternTree.SetItemPyData(Id,{})           
2265        self.OnFileSave(event)
2266        # check that constraints are OK here
2267        errmsg, warnmsg = G2str.CheckConstraints(self.GSASprojectfile)
2268        if errmsg:
2269            print('Error in constraints:\n'+errmsg+
2270                  '\nRefinement not possible')
2271            self.ErrorDialog('Constraint Error',
2272                             'Error in constraints:\n'+errmsg+
2273                             '\nRefinement not possible')
2274            return
2275        if warnmsg:
2276            print('Conflict between refinment flag settings and constraints:\n'+
2277                  warnmsg+'\nRefinement not possible')
2278            self.ErrorDialog('Refinement Flag Error',
2279                             'Conflict between refinment flag settings and constraints:\n'+
2280                             warnmsg+'\nRefinement not possible')
2281            return
2282        dlg = wx.ProgressDialog('Residual for histogram 0','Powder profile Rwp =',101.0, 
2283            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
2284        screenSize = wx.ClientDisplayRect()
2285        Size = dlg.GetSize()
2286        Size = (int(Size[0]*1.2),Size[1]) # increase size a bit along x
2287        dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
2288        dlg.SetSize(Size)
2289        try:
2290            G2str.SeqRefine(self.GSASprojectfile,dlg)
2291        finally:
2292            dlg.Destroy()       
2293        dlg = wx.MessageDialog(self,'Load new result?','Refinement results',wx.OK|wx.CANCEL)
2294        try:
2295            if dlg.ShowModal() == wx.ID_OK:
2296                Id = 0
2297                self.PatternTree.DeleteChildren(self.root)
2298                if self.HKL: self.HKL = []
2299                if self.G2plotNB.plotList:
2300                    self.G2plotNB.clear()
2301                G2IO.ProjFileOpen(self)
2302                item, cookie = self.PatternTree.GetFirstChild(self.root)
2303                while item and not Id:
2304                    name = self.PatternTree.GetItemText(item)
2305                    if name[:4] in ['PWDR','HKLF']:
2306                        Id = item
2307                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
2308                if Id:
2309                    self.PatternTree.SelectItem(Id)
2310        finally:
2311            dlg.Destroy()
2312       
2313    def ErrorDialog(self,title,message,parent=None, wtype=wx.OK):
2314        result = None
2315        if parent is None:
2316            dlg = wx.MessageDialog(self, message, title,  wtype)
2317        else:
2318            dlg = wx.MessageDialog(parent, message, title,  wtype)
2319            dlg.CenterOnParent() # not working on Mac
2320        try:
2321            result = dlg.ShowModal()
2322        finally:
2323            dlg.Destroy()
2324        return result
2325
2326class GSASIImain(wx.App):
2327    def OnInit(self):
2328        self.main = GSASII(None)
2329        self.main.Show()
2330        self.SetTopWindow(self.main)
2331        return True
2332
2333def main():
2334    application = GSASIImain(0)
2335    if wxInspector: wxeye.InspectionTool().Show()
2336
2337    #application.main.OnRefine(None)
2338    application.MainLoop()
2339   
2340if __name__ == '__main__':
2341    main()
Note: See TracBrowser for help on using the repository browser.