source: trunk/GSASII.py @ 877

Last change on this file since 877 was 877, checked in by vondreele, 9 years ago

finally problem

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 107.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#GSASII
4########### SVN repository information ###################
5# $Date: 2013-03-26 13:58:34 +0000 (Tue, 26 Mar 2013) $
6# $Author: vondreele $
7# $Revision: 877 $
8# $URL: trunk/GSASII.py $
9# $Id: GSASII.py 877 2013-03-26 13:58:34Z vondreele $
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: 877 $")
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 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        try:
561            fp = open(instfile,'Ur')
562            Iparm = {}
563            for S in fp:
564                Iparm[S[:12]] = S[12:-1]
565        except IOError:
566            print('Error reading file:'+str(instfile))
567        finally:       
568            fp.close()
569
570        try:
571            ibanks = int(Iparm.get('INS   BANK  ').strip())
572        except:
573            ibanks = 1
574        hType = Iparm['INS   HTYPE '].strip()
575        if ibanks == 1: # there is only one bank here, return it
576            rd.instbank = 1
577            return Iparm
578        if 'PNT' in hType:
579            rd.instbank = bank
580        elif ibanks != databanks:
581            # number of banks in data and prm file not not agree, need a
582            # choice from a human here
583            choices = []
584            for i in range(1,1+ibanks):
585                choices.append('Bank '+str(i))
586            bank = rd.BlockSelector(
587                choices, self,
588                title='Select an instrument parameter bank for '+
589                os.path.split(rd.powderentry[0])[1]+' BANK '+str(bank)+
590                '\nOr use Cancel to select from the default parameter sets',
591                header='Block Selector')
592        if bank is None: return {}
593        # pull out requested bank # bank from the data, and change the bank to 1
594        IparmS = {}
595        for key in Iparm:
596            if key[4:6] == "  ":
597                IparmS[key] = Iparm[key]
598            elif int(key[4:6].strip()) == bank:
599                IparmS[key[:4]+' 1'+key[6:]] = Iparm[key]
600        rd.instbank = bank
601        return IparmS
602                       
603    def GetPowderIparm(self,rd, prevIparm, lastIparmfile, lastdatafile):
604        '''Open and read an instrument parameter file for a data file
605        Returns the list of parameters used in the data tree
606        '''
607        def SetPowderInstParms(Iparm, rd):
608            '''extracts values from instrument parameters in rd.instdict
609            or in array Iparm.
610            Create and return the contents of the instrument parameter tree entry.
611            '''
612            DataType = Iparm['INS   HTYPE '].strip()[:3]  # take 1st 3 chars
613            # override inst values with values read from data file
614            if rd.instdict.get('type'):
615                DataType = rd.instdict.get('type')
616            data = [DataType,]
617            if 'C' in DataType:
618                wave1 = None
619                wave2 = 0.0
620                if rd.instdict.get('wave'):
621                    wl = rd.instdict.get('wave')
622                    wave1 = wl[0]
623                    if len(wl) > 1: wave2 = wl[1]
624                s = Iparm['INS  1 ICONS']
625                if not wave1:
626                    wave1 = G2IO.sfloat(s[:10])
627                    wave2 = G2IO.sfloat(s[10:20])
628                v = (wave1,wave2,
629                     G2IO.sfloat(s[20:30]),G2IO.sfloat(s[55:65]),G2IO.sfloat(s[40:50])) #get lam1, lam2, zero, pola & ratio
630                if not v[1]:
631                    names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
632                    v = (v[0],v[2],v[4])
633                    codes = [0,0,0,0]
634                else:
635                    names = ['Type','Lam1','Lam2','Zero','I(L2)/I(L1)','Polariz.','U','V','W','X','Y','SH/L','Azimuth']
636                    codes = [0,0,0,0,0,0]
637                data.extend(v)
638                v1 = Iparm['INS  1PRCF1 '].split()                                                 
639                v = Iparm['INS  1PRCF11'].split()
640                data.extend([float(v[0]),float(v[1]),float(v[2])])                  #get GU, GV & GW - always here
641                azm = Iparm.get('INS  1DETAZM')
642                if azm is None: #not in this Iparm file
643                    azm = 0.0
644                else:
645                    azm = float(azm)
646                v = Iparm['INS  1PRCF12'].split()
647                if v1[0] == 3:
648                    data.extend([float(v[0]),float(v[1]),float(v[2])+float(v[3],azm)])  #get LX, LY, S+H/L & azimuth
649                else:
650                    data.extend([0.0,0.0,0.002,azm])                                      #OK defaults if fxn #3 not 1st in iprm file
651                codes.extend([0,0,0,0,0,0,0])
652                return [G2IO.makeInstDict(names,data,codes),{}]
653            elif 'T' in DataType:
654                names = ['Type','2-theta','difC','difA','Zero','alpha','beta-0','beta-1','sig-0','sig-1','X','Y','Azimuth']
655                codes = [0,0,0,0,0,0,0,0,0,0,0,0,0]
656                azm = 0.
657                if 'INS  1DETAZM' in Iparm:
658                    azm = float(Iparm['INS  1DETAZM'])
659                s = Iparm['INS  1BNKPAR'].split()
660                data.extend([G2IO.sfloat(s[1]),])               #2-theta for bank
661                s = Iparm['INS  1 ICONS'].split()
662                data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),G2IO.sfloat(s[2])])    #difC, difA, Zero
663                s = Iparm['INS  1PRCF1 '].split()
664                pfType = int(s[0])
665                s = Iparm['INS  1PRCF11'].split()
666                if abs(pfType) == 1:
667                    data.extend([G2IO.sfloat(s[1]),G2IO.sfloat(s[2]),G2IO.sfloat(s[3])])
668                    s = Iparm['INS  1PRCF12'].split()
669                    data.extend([0.0,G2IO.sfloat(s[1]),0.0,0.0,azm])
670                elif abs(pfType) in [3,4,5]:
671                    data.extend([G2IO.sfloat(s[0]),G2IO.sfloat(s[1]),G2IO.sfloat(s[2])])
672                    if abs(pfType) == 4:
673                        data.extend([0.0,G2IO.sfloat(s[3]),0.0,0.0,azm])
674                    else:
675                        s = Iparm['INS  1PRCF12'].split()
676                        data.extend([0.0,G2IO.sfloat(s[0]),0.0,0.0,azm])                       
677                Inst1 = G2IO.makeInstDict(names,data,codes)
678                Inst2 = {}
679                if pfType < 0:
680                    Ipab = 'INS  1PAB'+str(-pfType)
681                    Npab = int(Iparm[Ipab+'  '].strip())
682                    Inst2['Pdabc'] = []
683                    for i in range(Npab):
684                        k = Ipab+str(i+1).rjust(2)
685                        s = Iparm[k].split()
686                        Inst2['Pdabc'].append([float(t) for t in s])
687                    Inst2['Pdabc'] = np.array(Inst2['Pdabc'])
688                    Inst2['Pdabc'].T[3] += Inst2['Pdabc'].T[0]*Inst1['difC'][0] #turn 3rd col into TOF
689                if 'INS  1I ITYP' in Iparm:
690                    s = Iparm['INS  1I ITYP'].split()
691                    Ityp = int(s[0])
692                    Tminmax = [float(s[1])*1000.,float(s[2])*1000.]
693                    Itypes = ['Exponential','Maxwell/Exponential','','Maxwell/Chebyschev','']
694                    if Ityp in [1,2,4]:
695                        Inst2['Itype'] = Itypes[Ityp-1]
696                        Inst2['Tminmax'] = Tminmax
697                        Icoeff = []
698                        Iesd = []
699                        Icovar = []                   
700                        for i in range(3):
701                            s = Iparm['INS  1ICOFF'+str(i+1)].split()
702                            Icoeff += [float(S) for S in s]
703                            s = Iparm['INS  1IECOF'+str(i+1)].split()
704                            Iesd += [float(S) for S in s]
705                        for i in range(8):
706                            s = Iparm['INS  1IECOR'+str(i+1)].split()
707                            Icovar += [float(S) for S in s]
708                        Inst2['Icoeff'] = Icoeff
709                        Inst2['Iesd'] = Iesd
710                        Inst2['Icovar'] = Icovar
711                return [Inst1,Inst2]
712
713        # stuff we might need from the reader
714        filename = rd.powderentry[0]
715        bank = rd.powderentry[2]
716        numbanks = rd.numbanks
717        # is there an instrument parameter file defined for the current data set?
718        if rd.instparm or (lastdatafile == filename and lastIparmfile):
719            if rd.instparm:
720                instfile = os.path.join(os.path.split(filename)[0],
721                                    rd.instparm)
722            else:
723                # for multiple reads of one data file, reuse the inst parm file
724                instfile = lastIparmfile
725            if os.path.exists(instfile):
726                #print 'debug: try read',instfile
727                instParmList = self.ReadPowderInstprm(instfile)
728                if instParmList is not None:
729                    rd.instfile = instfile
730                    rd.instmsg = 'GSAS-II file '+instfile
731                    return instParmList
732                Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
733                if Iparm:
734                    #print 'debug: success'
735                    rd.instfile = instfile
736                    rd.instmsg = instfile + ' bank ' + str(rd.instbank)
737                    return SetPowderInstParms(Iparm,rd)
738            else:
739                self.ErrorDialog('Open Error','Error opening instrument parameter file '
740                    +str(instfile)+' requested by file '+ filename)
741        # is there an instrument parameter file matching the current file
742        # with extension .inst or .prm? If so read it
743        basename = os.path.splitext(filename)[0]
744        for ext in '.instprm','.prm','.inst','.ins':
745            instfile = basename + ext
746            instParmList = self.ReadPowderInstprm(instfile)
747            if instParmList is not None:
748                rd.instfile = instfile
749                rd.instmsg = 'GSAS-II file '+instfile
750                return instParmList
751            Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
752            if Iparm:
753                #print 'debug: success'
754                rd.instfile = instfile
755                rd.instmsg = instfile + ' bank ' + str(rd.instbank)
756                return SetPowderInstParms(Iparm,rd)
757            else:
758                #print 'debug: open/read failed',instfile
759                pass # fail silently
760
761        # did we read the data file from a zip? If so, look there for a
762        # instrument parameter file
763        if self.zipfile:
764            for ext in '.instprm','.prm','.inst','.ins':
765                instfile = G2IO.ExtractFileFromZip(
766                    self.zipfile,
767                    selection=os.path.split(basename + ext)[1],
768                    parent=self)
769                if instfile is not None and instfile != self.zipfile:
770                    print 'debug:',instfile,'created from ',self.zipfile
771                    instParmList = self.ReadPowderInstprm(instfile)
772                    if instParmList is not None:
773                        rd.instfile = instfile
774                        rd.instmsg = 'GSAS-II file '+instfile
775                        return instParmList
776                    Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
777                    if Iparm:
778                        rd.instfile = instfile
779                        rd.instmsg = instfile + ' bank ' + str(rd.instbank)
780                        return SetPowderInstParms(Iparm,rd)
781                    else:
782                        #print 'debug: open/read for',instfile,'from',self.zipfile,'failed'
783                        pass # fail silently
784
785        while True: # loop until we get a file that works or we get a cancel
786            instfile = ''
787            dlg = wx.FileDialog(
788                self,
789                'Choose inst. param file for "'
790                +rd.idstring
791                +'" (or Cancel for default)',
792                '.', '',
793                'GSAS-II iparm file (*.instprm)|*.instprm|'
794                'GSAS iparm file (*.prm)|*.prm|'
795                'GSAS iparm file (*.inst)|*.inst|'
796                'GSAS iparm file (*.ins)|*.ins|'
797                'All files (*.*)|*.*', 
798                wx.OPEN|wx.CHANGE_DIR)
799            if os.path.exists(lastIparmfile):
800                dlg.SetFilename(lastIparmfile)
801            if dlg.ShowModal() == wx.ID_OK:
802                instfile = dlg.GetPath()
803            dlg.Destroy()
804            if not instfile: break
805            instParmList = self.ReadPowderInstprm(instfile)
806            if instParmList is not None:
807                rd.instfile = instfile
808                rd.instmsg = 'GSAS-II file '+instfile
809                return instParmList
810            Iparm = self.ReadPowderIparm(instfile,bank,numbanks,rd)
811            if Iparm:
812                #print 'debug: success with',instfile
813                rd.instfile = instfile
814                rd.instmsg = instfile + ' bank ' + str(rd.instbank)
815                return SetPowderInstParms(Iparm,rd)
816            else:
817                self.ErrorDialog('Read Error',
818                                 'Error opening/reading file '+str(instfile))
819       
820        # still no success: offer user choice of defaults
821        while True: # loop until we get a choice
822            choices = []
823            head = 'Select from default instrument parameters for '+rd.idstring
824
825            for l in rd.defaultIparm_lbl:
826                choices.append('Defaults for '+l)
827            res = rd.BlockSelector(
828                choices,
829                ParentFrame=self,
830                title=head,
831                header='Select default inst parms',)
832            if res is None: continue
833            rd.instfile = ''
834            rd.instmsg = 'default: '+rd.defaultIparm_lbl[res]
835            return SetPowderInstParms(rd.defaultIparms[res],rd)
836
837    def OnImportPowder(self,event):
838        '''reads powder data using a variety of formats
839        reads an instrument parameter file for each dataset
840        '''
841        reqrdr = self.ImportMenuId.get(event.GetId())  # look up which format was requested
842        rdlist = self.OnImportGeneric(reqrdr,self.ImportPowderReaderlist,
843            'Powder Data',multiple=True)
844        if len(rdlist) == 0: return
845        self.CheckNotebook()
846        Iparm = None
847        lastIparmfile = ''
848        lastdatafile = ''
849        for rd in rdlist:
850            # get instrument parameters for each dataset
851            Iparm1,Iparm2 = self.GetPowderIparm(rd, Iparm, lastIparmfile, lastdatafile)
852            lastIparmfile = rd.instfile
853            lastdatafile = rd.powderentry[0]
854            print 'Read powder data '+str(rd.idstring)+ \
855                ' from file '+str(self.lastimport) + \
856                ' with parameters from '+str(rd.instmsg)
857            # data are read, now store them in the tree
858            Id = self.PatternTree.AppendItem(parent=self.root,
859                text='PWDR '+rd.idstring)
860            if 'T' in Iparm1['Type'][0]:
861                if not rd.clockWd and rd.GSAS:
862                    rd.powderdata[0] *= 100.        #put back the CW centideg correction
863                cw = np.diff(rd.powderdata[0])
864                rd.powderdata[0] = rd.powderdata[0][:-1]+cw/2.
865                rd.powderdata[1] = rd.powderdata[1][:-1]/cw
866                rd.powderdata[2] = rd.powderdata[2][:-1]*cw**2  #1/var=w at this point
867                if 'Itype' in Iparm2:
868                    Ibeg = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][0])
869                    Ifin = np.searchsorted(rd.powderdata[0],Iparm2['Tminmax'][1])
870                    rd.powderdata[0] = rd.powderdata[0][Ibeg:Ifin]
871                    YI,WYI = G2pwd.calcIncident(Iparm2,rd.powderdata[0])
872                    rd.powderdata[1] = rd.powderdata[1][Ibeg:Ifin]/YI
873                    var = 1./rd.powderdata[2][Ibeg:Ifin]
874                    var += WYI*rd.powderdata[1]**2
875                    var /= YI**2
876                    rd.powderdata[2] = 1./var
877                rd.powderdata[3] = np.zeros_like(rd.powderdata[0])                                       
878                rd.powderdata[4] = np.zeros_like(rd.powderdata[0])                                       
879                rd.powderdata[5] = np.zeros_like(rd.powderdata[0])                                       
880            Tmin = min(rd.powderdata[0])
881            Tmax = max(rd.powderdata[0])
882            self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0},rd.powderdata])
883            self.PatternTree.SetItemPyData(
884                self.PatternTree.AppendItem(Id,text='Comments'),
885                rd.comments)
886            self.PatternTree.SetItemPyData(
887                self.PatternTree.AppendItem(Id,text='Limits'),
888                [(Tmin,Tmax),[Tmin,Tmax]])
889            self.PatternId = G2gd.GetPatternTreeItemId(self,Id,'Limits')
890            self.PatternTree.SetItemPyData(
891                self.PatternTree.AppendItem(Id,text='Background'),
892                [['chebyschev',True,3,1.0,0.0,0.0],
893                 {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
894            self.PatternTree.SetItemPyData(
895                self.PatternTree.AppendItem(Id,text='Instrument Parameters'),
896                [Iparm1,Iparm2])
897            self.PatternTree.SetItemPyData(
898                self.PatternTree.AppendItem(Id,text='Sample Parameters'),
899                rd.Sample)
900            self.PatternTree.SetItemPyData(
901                self.PatternTree.AppendItem(Id,text='Peak List')
902                ,[])
903            self.PatternTree.SetItemPyData(
904                self.PatternTree.AppendItem(Id,text='Index Peak List'),
905                [])
906            self.PatternTree.SetItemPyData(
907                self.PatternTree.AppendItem(Id,text='Unit Cells List'),
908                [])
909            self.PatternTree.SetItemPyData(
910                self.PatternTree.AppendItem(Id,text='Reflection Lists'),
911                {})
912            self.PatternTree.Expand(Id)
913        self.PatternTree.SelectItem(Id)
914        return # success
915
916    def _init_Exports(self,parent):
917        '''This is a place holder for when exports are handled in a manner similar to imports
918        '''
919#        submenu = wx.Menu()
920#        item = parent.AppendMenu(
921#            wx.ID_ANY, 'entire project',
922#            submenu, help='Export entire project')
923#        item = submenu.Append(
924#            wx.ID_ANY,
925#            help='this is a module for testing',
926#            kind=wx.ITEM_NORMAL,
927#            text='to test file')
928#        self.Bind(wx.EVT_MENU, self.OnExportTest, id=item.GetId())
929#        import G2export
930#    def OnExportTest(self,event):
931#        import G2export
932#        reload(G2export)
933#        G2export.ProjExport(self)
934
935    def _Add_ExportMenuItems(self,parent):
936        item = parent.Append(
937            help='Select PWDR item to enable',id=wx.ID_ANY,
938            kind=wx.ITEM_NORMAL,
939            text='Export Powder Patterns...')
940        self.ExportPattern.append(item)
941        item.Enable(False)
942        self.Bind(wx.EVT_MENU, self.OnExportPatterns, id=item.GetId())
943
944        item = parent.Append(
945            help='',id=wx.ID_ANY,
946            kind=wx.ITEM_NORMAL,
947            text='Export All Peak Lists...')
948        self.ExportPeakList.append(item)
949        item.Enable(True)
950        self.Bind(wx.EVT_MENU, self.OnExportPeakList, id=item.GetId())
951
952        item = parent.Append(
953            help='',id=wx.ID_ANY,
954            kind=wx.ITEM_NORMAL,
955            text='Export HKLs...')
956        self.ExportHKL.append(item)
957        item.Enable(False)
958        self.Bind(wx.EVT_MENU, self.OnExportHKL, id=item.GetId())
959
960        item = parent.Append(
961            help='Select PDF item to enable',
962            id=wx.ID_ANY,
963            kind=wx.ITEM_NORMAL,
964            text='Export PDF...')
965        self.ExportPDF.append(item)
966        item.Enable(False)
967        self.Bind(wx.EVT_MENU, self.OnExportPDF, id=item.GetId())
968
969        item = parent.Append(
970            help='',id=wx.ID_ANY,
971            kind=wx.ITEM_NORMAL,
972            text='Export Phase...')
973        self.ExportPhase.append(item)
974        item.Enable(False)
975        self.Bind(wx.EVT_MENU, self.OnExportPhase, id=item.GetId())
976
977        item = parent.Append(
978            help='',id=wx.ID_ANY,
979            kind=wx.ITEM_NORMAL,
980            text='Export CIF...')
981        self.ExportCIF.append(item)
982        item.Enable(False)
983        self.Bind(wx.EVT_MENU, self.OnExportCIF, id=item.GetId())
984               
985    def FillMainMenu(self,menubar):
986        '''Define contents of the main GSAS-II menu for the (main) data tree window
987        in the mac, used also for the data item windows as well.
988        '''
989        File = wx.Menu(title='')
990        menubar.Append(menu=File, title='&File')
991        self._Add_FileMenuItems(File)
992        Data = wx.Menu(title='')
993        menubar.Append(menu=Data, title='Data')
994        self._Add_DataMenuItems(Data)
995        Calculate = wx.Menu(title='')       
996        menubar.Append(menu=Calculate, title='&Calculate')
997        self._Add_CalculateMenuItems(Calculate)
998        Import = wx.Menu(title='')       
999        menubar.Append(menu=Import, title='Import')
1000        self._Add_ImportMenu_Phase(Import)
1001        self._Add_ImportMenu_powder(Import)
1002        self._Add_ImportMenu_Sfact(Import)
1003        Export = wx.Menu(title='')       
1004        menubar.Append(menu=Export, title='Export')
1005        self._Add_ExportMenuItems(Export)
1006        #self._init_Exports(Export)
1007        HelpMenu=G2gd.MyHelp(self,helpType='Data tree',
1008            morehelpitems=[('&Tutorials','Tutorials')])
1009        menubar.Append(menu=HelpMenu,title='&Help')
1010
1011    def _init_ctrls(self, parent):
1012        wx.Frame.__init__(self, name='GSASII', parent=parent,
1013            size=wx.Size(400, 250),style=wx.DEFAULT_FRAME_STYLE, title='GSAS-II data tree')
1014        clientSize = wx.ClientDisplayRect()
1015        Size = self.GetSize()
1016        xPos = clientSize[2]-Size[0]
1017        self.SetPosition(wx.Point(xPos,clientSize[1]))
1018        self._init_Imports()
1019        #initialize Menu item objects (these contain lists of menu items that are enabled or disabled)
1020        self.MakePDF = []
1021        self.Refine = []
1022        self.SeqRefine = []
1023        self.ExportPattern = []
1024        self.ExportPeakList = []
1025        self.ExportHKL = []
1026        self.ExportPDF = []
1027        self.ExportPhase = []
1028        self.ExportCIF = []
1029        #
1030        self.GSASIIMenu = wx.MenuBar()
1031        self.FillMainMenu(self.GSASIIMenu)
1032        self.SetMenuBar(self.GSASIIMenu)
1033        self.Bind(wx.EVT_SIZE, self.OnSize)
1034        self.CreateStatusBar()
1035        self.mainPanel = wx.Panel(self,-1)
1036       
1037        wxID_PATTERNTREE = wx.NewId()
1038        self.PatternTree = wx.TreeCtrl(id=wxID_PATTERNTREE,
1039            parent=self.mainPanel, pos=wx.Point(0, 0),style=wx.TR_DEFAULT_STYLE )
1040        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED,
1041            self.OnPatternTreeSelChanged, id=wxID_PATTERNTREE)
1042        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
1043            self.OnPatternTreeItemCollapsed, id=wxID_PATTERNTREE)
1044        self.PatternTree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
1045            self.OnPatternTreeItemExpanded, id=wxID_PATTERNTREE)
1046        self.PatternTree.Bind(wx.EVT_TREE_DELETE_ITEM,
1047            self.OnPatternTreeItemDelete, id=wxID_PATTERNTREE)
1048        self.PatternTree.Bind(wx.EVT_TREE_KEY_DOWN,
1049            self.OnPatternTreeKeyDown, id=wxID_PATTERNTREE)
1050        self.root = self.PatternTree.AddRoot('Loaded Data: ')
1051       
1052        plotFrame = wx.Frame(None,-1,'GSASII Plots',size=wx.Size(700,600), \
1053            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
1054        self.G2plotNB = G2plt.G2PlotNoteBook(plotFrame)
1055        plotFrame.Show()
1056       
1057        self.dataDisplay = None
1058       
1059    def __init__(self, parent):
1060        self._init_ctrls(parent)
1061        self.Bind(wx.EVT_CLOSE, self.ExitMain)
1062        # various defaults
1063        self.oldFocus = None
1064        self.GSASprojectfile = ''
1065        self.dirname = os.path.expanduser('~')       #start in the users home directory by default; may be meaningless
1066        self.undofile = ''
1067        self.TreeItemDelete = False
1068        self.Offset = [0.0,0.0]
1069        self.delOffset = .02
1070        self.refOffset = -100.0
1071        self.refDelt = .01
1072        self.Weight = False
1073        self.IparmName = ''  # to be removed when SelectPowderData & GetInstrumentFile is
1074        self.IfPlot = False
1075        self.PatternId = 0
1076        self.PickId = 0
1077        self.PeakTable = []
1078        self.LimitsTable = []
1079        self.HKL = []
1080        self.Lines = []
1081        self.itemPicked = None
1082        self.dataFrame = None
1083        self.Interpolate = 'nearest'
1084        self.ContourColor = 'Paired'
1085        self.VcovColor = 'RdYlGn'
1086        self.RamaColor = 'Blues'
1087        self.Projection = 'equal area'
1088        self.logPlot = False
1089        self.qPlot = False
1090        self.Contour = False
1091        self.Legend = False
1092        self.SinglePlot = False
1093        self.SubBack = False
1094        self.plotView = 0
1095        self.Image = 0
1096        self.oldImagefile = ''
1097        self.ImageZ = []
1098        self.Integrate = 0
1099        self.imageDefault = {}
1100        self.Sngl = 0
1101        self.ifGetRing = False
1102        self.setPoly = False
1103        arg = sys.argv
1104        if len(arg) > 1:
1105            self.GSASprojectfile = arg[1]
1106            self.dirname = os.path.dirname(arg[1])
1107            if self.dirname: os.chdir(self.dirname)
1108            G2IO.ProjFileOpen(self)
1109            self.PatternTree.Expand(self.root)
1110            for item in self.Refine: item.Enable(True)
1111            for item in self.SeqRefine: item.Enable(True)
1112
1113    def OnSize(self,event):
1114        w,h = self.GetClientSizeTuple()
1115        self.mainPanel.SetSize(wx.Size(w,h))
1116        self.PatternTree.SetSize(wx.Size(w,h))
1117                       
1118    def OnPatternTreeSelChanged(self, event):
1119        if self.TreeItemDelete:
1120            self.TreeItemDelete = False
1121        else:
1122            pltNum = self.G2plotNB.nb.GetSelection()
1123            if pltNum >= 0:                         #to avoid the startup with no plot!
1124                pltPage = self.G2plotNB.nb.GetPage(pltNum)
1125                pltPlot = pltPage.figure
1126            item = event.GetItem()
1127            G2gd.MovePatternTreeToGrid(self,item)
1128            if self.oldFocus:
1129                self.oldFocus.SetFocus()
1130       
1131    def OnPatternTreeItemCollapsed(self, event):
1132        event.Skip()
1133
1134    def OnPatternTreeItemExpanded(self, event):
1135        event.Skip()
1136       
1137    def OnPatternTreeItemDelete(self, event):
1138        self.TreeItemDelete = True
1139
1140    def OnPatternTreeItemActivated(self, event):
1141        event.Skip()
1142       
1143    def OnPatternTreeKeyDown(self,event):
1144        key = event.GetKeyCode()
1145        item = self.PickId
1146        if type(item) is int: return # is this the toplevel in tree?
1147        if key == wx.WXK_UP:
1148            self.oldFocus = wx.Window.FindFocus()
1149            self.PatternTree.GetPrevSibling(item)
1150        elif key == wx.WXK_DOWN:
1151            self.oldFocus = wx.Window.FindFocus()
1152            self.PatternTree.GetNextSibling(item)
1153               
1154    def OnReadPowderPeaks(self,event):
1155        Cuka = 1.54052
1156        self.CheckNotebook()
1157        dlg = wx.FileDialog(self, 'Choose file with peak list', '.', '', 
1158            'peak files (*.txt)|*.txt|All files (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
1159        try:
1160            if dlg.ShowModal() == wx.ID_OK:
1161                self.HKL = []
1162                self.powderfile = dlg.GetPath()
1163                comments,peaks = G2IO.GetPowderPeaks(self.powderfile)
1164                Id = self.PatternTree.AppendItem(parent=self.root,text='PKS '+os.path.basename(self.powderfile))
1165                data = ['PKS',Cuka,0.0]
1166                names = ['Type','Lam','Zero'] 
1167                codes = [0,0,0]
1168                inst = [G2IO.makeInstDict(names,data,codes),{}]
1169                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
1170                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),comments)
1171                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),peaks)
1172                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
1173                self.PatternTree.Expand(Id)
1174                self.PatternTree.SelectItem(Id)
1175                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1176        finally:
1177            dlg.Destroy()
1178           
1179    def OnImageRead(self,event):
1180        self.CheckNotebook()
1181        dlg = wx.FileDialog(
1182            self, 'Choose image files', '.', '',
1183            'Any image file (*.edf;*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img;*.G2img)|'
1184            '*.edf;*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img;*.G2img;*.zip|'
1185            'European detector file (*.edf)|*.edf|'
1186            'Any detector tif (*.tif;*.tiff)|*.tif;*.tiff|'
1187            'MAR file (*.mar*)|*.mar*|'
1188            'GE Image (*.avg;*.sum)|*.avg;*.sum|'
1189            'ADSC Image (*.img)|*.img|'
1190            'GSAS-II Image (*.G2img)|*.G2img|'
1191            'Zip archive (*.zip)|*.zip|'
1192            'All files (*.*)|*.*',
1193            wx.OPEN | wx.MULTIPLE|wx.CHANGE_DIR)
1194        try:
1195            if dlg.ShowModal() == wx.ID_OK:
1196                imagefiles = dlg.GetPaths()
1197                imagefiles.sort()
1198                for imagefile in imagefiles:
1199                    # if a zip file, open and extract
1200                    if os.path.splitext(imagefile)[1].lower() == '.zip':
1201                        extractedfile = G2IO.ExtractFileFromZip(imagefile,parent=self)
1202                        if extractedfile is not None and extractedfile != imagefile:
1203                            imagefile = extractedfile
1204                    Comments,Data,Npix,Image = G2IO.GetImageData(self,imagefile)
1205                    if Comments:
1206                        Id = self.PatternTree.AppendItem(parent=self.root,text='IMG '+os.path.basename(imagefile))
1207                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
1208                        Imax = np.amax(Image)
1209                        Imin = max(0.0,np.amin(Image))          #force positive
1210                        if self.imageDefault:
1211                            Data = copy.copy(self.imageDefault)
1212                            Data['showLines'] = True
1213                            Data['ring'] = []
1214                            Data['rings'] = []
1215                            Data['cutoff'] = 10
1216                            Data['pixLimit'] = 20
1217                            Data['edgemin'] = 100000000
1218                            Data['calibdmin'] = 0.5
1219                            Data['calibskip'] = 0
1220                            Data['ellipses'] = []
1221                            Data['calibrant'] = ''
1222                            Data['GonioAngles'] = [0.,0.,0.]
1223                        else:
1224                            Data['type'] = 'PWDR'
1225                            Data['color'] = 'Paired'
1226                            Data['tilt'] = 0.0
1227                            Data['rotation'] = 0.0
1228                            Data['showLines'] = False
1229                            Data['ring'] = []
1230                            Data['rings'] = []
1231                            Data['cutoff'] = 10
1232                            Data['pixLimit'] = 20
1233                            Data['calibdmin'] = 0.5
1234                            Data['calibskip'] = 0
1235                            Data['edgemin'] = 100000000
1236                            Data['ellipses'] = []
1237                            Data['GonioAngles'] = [0.,0.,0.]
1238                            Data['calibrant'] = ''
1239                            Data['IOtth'] = [2.0,5.0]
1240                            Data['LRazimuth'] = [135,225]
1241                            Data['azmthOff'] = 0.0
1242                            Data['outChannels'] = 2500
1243                            Data['outAzimuths'] = 1
1244                            Data['centerAzm'] = False
1245                            Data['fullIntegrate'] = False
1246                            Data['setRings'] = False
1247                            Data['background image'] = ['',1.0]                           
1248                        Data['setDefault'] = False
1249                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
1250                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)
1251                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
1252                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
1253                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),
1254                            {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'strain':np.zeros((3,3))})
1255                        self.PatternTree.SetItemPyData(Id,[Npix,imagefile])
1256                        self.PickId = Id
1257                        self.Image = Id
1258                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1259                self.PatternTree.SelectItem(G2gd.GetPatternTreeItemId(self,Id,'Image Controls'))             #show last one
1260        finally:
1261            path = dlg.GetDirectory()           # to get Mac/Linux to change directory!
1262            os.chdir(path)
1263            dlg.Destroy()
1264
1265    def CheckNotebook(self):
1266        '''Make sure the data tree has the minimally expected controls
1267        (BHT) correct?
1268        '''
1269        if not G2gd.GetPatternTreeItemId(self,self.root,'Notebook'):
1270            sub = self.PatternTree.AppendItem(parent=self.root,text='Notebook')
1271            self.PatternTree.SetItemPyData(sub,[''])
1272        if not G2gd.GetPatternTreeItemId(self,self.root,'Controls'):
1273            sub = self.PatternTree.AppendItem(parent=self.root,text='Controls')
1274            self.PatternTree.SetItemPyData(sub,{'deriv type':'analytic Hessian',    #default controls
1275                'min dM/M':0.0001,'shift factor':1.,'max cyc':3,'F**2':True,
1276                'minF/sig':0,})
1277        if not G2gd.GetPatternTreeItemId(self,self.root,'Covariance'):
1278            sub = self.PatternTree.AppendItem(parent=self.root,text='Covariance')
1279            self.PatternTree.SetItemPyData(sub,{})
1280        if not G2gd.GetPatternTreeItemId(self,self.root,'Constraints'):
1281            sub = self.PatternTree.AppendItem(parent=self.root,text='Constraints')
1282            self.PatternTree.SetItemPyData(sub,{'Hist':[],'HAP':[],'Phase':[]})
1283        if not G2gd.GetPatternTreeItemId(self,self.root,'Restraints'):
1284            sub = self.PatternTree.AppendItem(parent=self.root,text='Restraints')
1285            self.PatternTree.SetItemPyData(sub,{})
1286        if not G2gd.GetPatternTreeItemId(self,self.root,'Rigid bodies'):
1287            sub = self.PatternTree.AppendItem(parent=self.root,text='Rigid bodies')
1288            self.PatternTree.SetItemPyData(sub,{'Vector':{'AtInfo':{}},
1289                'Residue':{'AtInfo':{}},'Z-matrix':{'AtInfo':{}}})
1290               
1291    class CopyDialog(wx.Dialog):
1292        def __init__(self,parent,title,text,data):
1293            wx.Dialog.__init__(self,parent,-1,title, 
1294                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1295            self.data = data
1296            panel = wx.Panel(self)
1297            mainSizer = wx.BoxSizer(wx.VERTICAL)
1298            topLabl = wx.StaticText(panel,-1,text)
1299            mainSizer.Add((10,10),1)
1300            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1301            mainSizer.Add((10,10),1)
1302            ncols = len(data)/40+1
1303            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=ncols,hgap=2,vgap=2)
1304            for id,item in enumerate(self.data):
1305                ckbox = wx.CheckBox(panel,id,item[1])
1306                ckbox.Bind(wx.EVT_CHECKBOX,self.OnCopyChange)                   
1307                dataGridSizer.Add(ckbox,0,wx.LEFT,10)
1308            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1309            OkBtn = wx.Button(panel,-1,"Ok")
1310            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1311            cancelBtn = wx.Button(panel,-1,"Cancel")
1312            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1313            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1314            btnSizer.Add((20,20),1)
1315            btnSizer.Add(OkBtn)
1316            btnSizer.Add((20,20),1)
1317            btnSizer.Add(cancelBtn)
1318            btnSizer.Add((20,20),1)
1319           
1320            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1321            panel.SetSizer(mainSizer)
1322            panel.Fit()
1323            self.Fit()
1324       
1325        def OnCopyChange(self,event):
1326            id = event.GetId()
1327            self.data[id][0] = self.FindWindowById(id).GetValue()       
1328           
1329        def OnOk(self,event):
1330            parent = self.GetParent()
1331            parent.Raise()
1332            self.EndModal(wx.ID_OK)             
1333           
1334        def OnCancel(self,event):
1335            parent = self.GetParent()
1336            parent.Raise()
1337            self.EndModal(wx.ID_CANCEL)             
1338           
1339        def GetData(self):
1340            return self.data
1341       
1342    class SumDialog(wx.Dialog):
1343        def __init__(self,parent,title,text,dataType,data):
1344            wx.Dialog.__init__(self,parent,-1,title, 
1345                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1346            self.data = data
1347            panel = wx.Panel(self)
1348            mainSizer = wx.BoxSizer(wx.VERTICAL)
1349            topLabl = wx.StaticText(panel,-1,text)
1350            mainSizer.Add((10,10),1)
1351            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1352            mainSizer.Add((10,10),1)
1353            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=2,hgap=2,vgap=2)
1354            for id,item in enumerate(self.data[:-1]):
1355                name = wx.TextCtrl(panel,-1,item[1],size=wx.Size(200,20))
1356                name.SetEditable(False)
1357                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
1358                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
1359                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
1360                dataGridSizer.Add(scale,0,wx.LEFT,10)
1361                dataGridSizer.Add(name,0,wx.RIGHT,10)
1362            if dataType:
1363                dataGridSizer.Add(wx.StaticText(panel,-1,'Sum result name: '+dataType),0, \
1364                    wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
1365                self.name = wx.TextCtrl(panel,-1,self.data[-1],size=wx.Size(200,20),style=wx.TE_PROCESS_ENTER)
1366                self.name.Bind(wx.EVT_TEXT_ENTER,self.OnNameChange)
1367                self.name.Bind(wx.EVT_KILL_FOCUS,self.OnNameChange)
1368                dataGridSizer.Add(self.name,0,wx.RIGHT|wx.TOP,10)
1369            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1370            OkBtn = wx.Button(panel,-1,"Ok")
1371            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1372            cancelBtn = wx.Button(panel,-1,"Cancel")
1373            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1374            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1375            btnSizer.Add((20,20),1)
1376            btnSizer.Add(OkBtn)
1377            btnSizer.Add((20,20),1)
1378            btnSizer.Add(cancelBtn)
1379            btnSizer.Add((20,20),1)
1380           
1381            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1382            panel.SetSizer(mainSizer)
1383            panel.Fit()
1384            self.Fit()
1385
1386        def OnScaleChange(self,event):
1387            id = event.GetId()
1388            value = self.FindWindowById(id).GetValue()
1389            try:
1390                self.data[id][0] = float(value)
1391                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
1392            except ValueError:
1393                if value and '-' not in value[0]:
1394                    print 'bad input - numbers only'
1395                    self.FindWindowById(id).SetValue('0.000')
1396           
1397        def OnNameChange(self,event):
1398            self.data[-1] = self.name.GetValue() 
1399           
1400        def OnOk(self,event):
1401            parent = self.GetParent()
1402            parent.Raise()
1403            self.EndModal(wx.ID_OK)             
1404           
1405        def OnCancel(self,event):
1406            parent = self.GetParent()
1407            parent.Raise()
1408            self.EndModal(wx.ID_CANCEL)             
1409           
1410        def GetData(self):
1411            return self.data
1412           
1413    class ConstraintDialog(wx.Dialog):
1414        '''Window to edit Constraint values
1415        '''
1416        def __init__(self,parent,title,text,data,separator='*'):
1417            wx.Dialog.__init__(self,parent,-1,title, 
1418                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1419            self.data = data
1420            panel = wx.Panel(self)
1421            mainSizer = wx.BoxSizer(wx.VERTICAL)
1422            topLabl = wx.StaticText(panel,-1,text)
1423            mainSizer.Add((10,10),1)
1424            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1425            mainSizer.Add((10,10),1)
1426            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=2,hgap=2,vgap=2)
1427            for id,item in enumerate(self.data[:-1]):
1428                lbl = item[1]
1429                if lbl[-1] != '=': lbl += ' ' + separator + ' '
1430                name = wx.StaticText(panel,-1,lbl,size=wx.Size(200,20),
1431                                     style=wx.ALIGN_RIGHT)
1432                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
1433                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
1434                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
1435                dataGridSizer.Add(name,0,wx.LEFT,10)
1436                dataGridSizer.Add(scale,0,wx.RIGHT,10)
1437            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1438            OkBtn = wx.Button(panel,-1,"Ok")
1439            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1440            cancelBtn = wx.Button(panel,-1,"Cancel")
1441            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1442            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1443            btnSizer.Add((20,20),1)
1444            btnSizer.Add(OkBtn)
1445            btnSizer.Add((20,20),1)
1446            btnSizer.Add(cancelBtn)
1447            btnSizer.Add((20,20),1)
1448           
1449            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1450            panel.SetSizer(mainSizer)
1451            panel.Fit()
1452            self.Fit()
1453            self.CenterOnParent()
1454           
1455        def OnNameChange(self,event):
1456            self.data[-1] = self.name.GetValue() 
1457           
1458        def OnScaleChange(self,event):
1459            id = event.GetId()
1460            value = self.FindWindowById(id).GetValue()
1461            try:
1462                self.data[id][0] = float(value)
1463                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
1464            except ValueError:
1465                if value and '-' not in value[0]:
1466                    print 'bad input - numbers only'
1467                    self.FindWindowById(id).SetValue('0.000')
1468           
1469        def OnOk(self,event):
1470            parent = self.GetParent()
1471            parent.Raise()
1472            self.EndModal(wx.ID_OK)             
1473           
1474        def OnCancel(self,event):
1475            parent = self.GetParent()
1476            parent.Raise()
1477            self.EndModal(wx.ID_CANCEL)             
1478           
1479        def GetData(self):
1480            return self.data
1481           
1482    def OnPwdrSum(self,event):
1483        TextList = []
1484        DataList = []
1485        SumList = []
1486        Names = []
1487        Inst = None
1488        SumItemList = []
1489        Comments = ['Sum equals: \n']
1490        if self.PatternTree.GetCount():
1491            item, cookie = self.PatternTree.GetFirstChild(self.root)
1492            while item:
1493                name = self.PatternTree.GetItemText(item)
1494                Names.append(name)
1495                if 'PWDR' in name:
1496                    TextList.append([0.0,name])
1497                    DataList.append(self.PatternTree.GetItemPyData(item)[1])    # (x,y,w,yc,yb,yd)
1498                    if not Inst:
1499                        Inst = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item, 'Instrument Parameters'))
1500                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1501            if len(TextList) < 2:
1502                self.ErrorDialog('Not enough data to sum','There must be more than one "PWDR" pattern')
1503                return
1504            TextList.append('default_sum_name')               
1505            dlg = self.SumDialog(self,'Sum data','Enter scale for each pattern in summation','PWDR',TextList)
1506            try:
1507                if dlg.ShowModal() == wx.ID_OK:
1508                    lenX = 0
1509                    Xminmax = [0,0]
1510                    Xsum = []
1511                    Ysum = []
1512                    Vsum = []
1513                    result = dlg.GetData()
1514                    for i,item in enumerate(result[:-1]):
1515                        scale,name = item
1516                        data = DataList[i]
1517                        if scale:
1518                            Comments.append("%10.3f %s" % (scale,' * '+name))
1519                            x,y,w,yc,yb,yd = data   #numpy arrays!
1520                            v = 1./w
1521                            if lenX:
1522                                if lenX != len(x):
1523                                    self.ErrorDialog('Data length error','Data to be summed must have same number of points'+ \
1524                                        '\nExpected:'+str(lenX)+ \
1525                                        '\nFound:   '+str(len(x))+'\nfor '+name)
1526                                    return
1527                            else:
1528                                lenX = len(x)
1529                            if Xminmax[1]:
1530                                if Xminmax != [x[0],x[-1]]:
1531                                    self.ErrorDialog('Data range error','Data to be summed must span same range'+ \
1532                                        '\nExpected:'+str(Xminmax[0])+' '+str(Xminmax[1])+ \
1533                                        '\nFound:   '+str(x[0])+' '+str(x[-1])+'\nfor '+name)
1534                                    return
1535                                else:
1536                                    for j,yi in enumerate(y):
1537                                         Ysum[j] += scale*yi
1538                                         Vsum[j] += abs(scale)*v[j]
1539                            else:
1540                                Xminmax = [x[0],x[-1]]
1541                                YCsum = YBsum = YDsum = [0.0 for i in range(lenX)]
1542                                for j,yi in enumerate(y):
1543                                    Xsum.append(x[j])
1544                                    Ysum.append(scale*yi)
1545                                    Vsum.append(abs(scale*v[j]))
1546                    Wsum = 1./np.array(Vsum)
1547                    outname = 'PWDR '+result[-1]
1548                    Id = 0
1549                    if outname in Names:
1550                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
1551                        try:
1552                            if dlg2.ShowModal() == wx.ID_OK:
1553                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
1554                                self.PatternTree.Delete(Id)
1555                        finally:
1556                            dlg2.Destroy()
1557                    Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
1558                    if Id:
1559                        Sample = G2pdG.SetDefaultSample()
1560                        self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0},[np.array(Xsum),np.array(Ysum),np.array(Wsum),
1561                            np.array(YCsum),np.array(YBsum),np.array(YDsum)]])
1562                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
1563                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
1564                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',True,3,1.0,0.0,0.0],
1565                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
1566                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
1567                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
1568                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Peak List'),[])
1569                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[])
1570                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
1571                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
1572                        self.PatternTree.SelectItem(Id)
1573                        self.PatternTree.Expand(Id)
1574                   
1575            finally:
1576                dlg.Destroy()
1577
1578    def OnImageSum(self,event):
1579        TextList = []
1580        DataList = []
1581        SumList = []
1582        Names = []
1583        Inst = []
1584        SumItemList = []
1585        Comments = ['Sum equals: \n']
1586        if self.PatternTree.GetCount():
1587            item, cookie = self.PatternTree.GetFirstChild(self.root)
1588            while item:
1589                name = self.PatternTree.GetItemText(item)
1590                Names.append(name)
1591                if 'IMG' in name:
1592                    TextList.append([0.0,name])
1593                    DataList.append(self.PatternTree.GetItemPyData(item))        #Size,Image
1594                    Data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item,'Image Controls'))
1595                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1596            if len(TextList) < 2:
1597                self.ErrorDialog('Not enough data to sum','There must be more than one "IMG" pattern')
1598                return
1599            TextList.append('default_sum_name')               
1600            dlg = self.SumDialog(self,'Sum data','Enter scale for each image in summation','IMG',TextList)
1601            try:
1602                if dlg.ShowModal() == wx.ID_OK:
1603                    imSize = 0
1604                    result = dlg.GetData()
1605                    First = True
1606                    Found = False
1607                    for i,item in enumerate(result[:-1]):
1608                        scale,name = item
1609                        data = DataList[i]
1610                        if scale:
1611                            Found = True                               
1612                            Comments.append("%10.3f %s" % (scale,' * '+name))
1613                            Npix,imagefile = data
1614                            image = G2IO.GetImageData(self,imagefile,imageOnly=True)
1615                            if First:
1616                                newImage = np.zeros_like(image)
1617                                First = False
1618                            if imSize:
1619                                if imSize != Npix:
1620                                    self.ErrorDialog('Image size error','Images to be summed must be same size'+ \
1621                                        '\nExpected:'+str(imSize)+ \
1622                                        '\nFound:   '+str(Npix)+'\nfor '+name)
1623                                    return
1624                                newImage = newImage+scale*image
1625                            else:
1626                                imSize = Npix
1627                                newImage = newImage+scale*image
1628                            del(image)
1629                    if not Found:
1630                        self.ErrorDialog('Image sum error','No nonzero image multipliers found')
1631                        return
1632                       
1633                    newImage = np.asfarray(newImage,dtype=np.float32)                       
1634                    outname = 'IMG '+result[-1]
1635                    Id = 0
1636                    if outname in Names:
1637                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
1638                        try:
1639                            if dlg2.ShowModal() == wx.ID_OK:
1640                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
1641                        finally:
1642                            dlg2.Destroy()
1643                    else:
1644                        Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
1645                    if Id:
1646                        dlg = wx.FileDialog(self, 'Choose sum image filename', '.', '', 
1647                            'G2img files (*.G2img)|*.G2img', 
1648                            wx.SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1649                        if dlg.ShowModal() == wx.ID_OK:
1650                            newimagefile = dlg.GetPath()
1651                            newimagefile = G2IO.FileDlgFixExt(dlg,newimagefile)
1652                            G2IO.PutG2Image(newimagefile,Comments,Data,Npix,newImage)
1653                            Imax = np.amax(newImage)
1654                            Imin = np.amin(newImage)
1655                            newImage = []
1656                            self.PatternTree.SetItemPyData(Id,[imSize,newimagefile])
1657                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
1658                        del(newImage)
1659                        if self.imageDefault:
1660                            Data = copy.copy(self.imageDefault)
1661                        Data['showLines'] = True
1662                        Data['ring'] = []
1663                        Data['rings'] = []
1664                        Data['cutoff'] = 10
1665                        Data['pixLimit'] = 20
1666                        Data['ellipses'] = []
1667                        Data['calibrant'] = ''
1668                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
1669                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)                                           
1670                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
1671                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
1672                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),{})
1673                        self.PatternTree.SelectItem(Id)
1674                        self.PatternTree.Expand(Id)
1675                        self.PickId = G2gd.GetPatternTreeItemId(self,self.root,outname)
1676                        self.Image = self.PickId
1677            finally:
1678                dlg.Destroy()
1679                     
1680    def OnAddPhase(self,event):
1681        if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
1682            sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
1683        else:
1684            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1685        PhaseName = ''
1686        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
1687            style=wx.OK)
1688        if dlg.ShowModal() == wx.ID_OK:
1689            PhaseName = dlg.GetValue()
1690        dlg.Destroy()
1691        sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
1692        E,SGData = G2spc.SpcGroup('P 1')
1693        self.PatternTree.SetItemPyData(sub,G2IO.SetNewPhase(Name=PhaseName,SGData=SGData))
1694       
1695    def OnDeletePhase(self,event):
1696        #Hmm, also need to delete this phase from Reflection Lists for each PWDR histogram
1697        if self.dataFrame:
1698            self.dataFrame.Clear() 
1699        TextList = []
1700        DelList = []
1701        DelItemList = []
1702        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
1703            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1704        else:
1705            return
1706        if sub:
1707            item, cookie = self.PatternTree.GetFirstChild(sub)
1708            while item:
1709                TextList.append(self.PatternTree.GetItemText(item))
1710                item, cookie = self.PatternTree.GetNextChild(sub, cookie)               
1711            dlg = wx.MultiChoiceDialog(self, 'Which phase to delete?', 'Delete phase', TextList, wx.CHOICEDLG_STYLE)
1712            try:
1713                if dlg.ShowModal() == wx.ID_OK:
1714                    result = dlg.GetSelections()
1715                    for i in result: DelList.append([i,TextList[i]])
1716                    item, cookie = self.PatternTree.GetFirstChild(sub)
1717                    i = 0
1718                    while item:
1719                        if [i,self.PatternTree.GetItemText(item)] in DelList: DelItemList.append(item)
1720                        item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1721                        i += 1
1722                    for item in DelItemList:
1723                        name = self.PatternTree.GetItemText(item)
1724                        self.PatternTree.Delete(item)
1725                        self.G2plotNB.Delete(name)
1726                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1727                    while item:
1728                        name = self.PatternTree.GetItemText(item)
1729                        if 'PWDR' in name:
1730                            Id = G2gd.GetPatternTreeItemId(self,item, 'Reflection Lists')
1731                            refList = self.PatternTree.GetItemPyData(Id)
1732                            for i,item in DelList:
1733                                del(refList[item])
1734                            self.PatternTree.SetItemPyData(Id,refList)
1735                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1736            finally:
1737                dlg.Destroy()
1738               
1739    def OnRenameData(self,event):
1740        name = self.PatternTree.GetItemText(self.PickId)     
1741        if 'PWDR' in name or 'HKLF' in name or 'IMG' in name:
1742            dataType = name[:name.index(' ')+1]                 #includes the ' '
1743            dlg = wx.TextEntryDialog(self,'Data name: '+dataType,'Change data name',
1744                defaultValue=name[name.index(' ')+1:])
1745            try:
1746                if dlg.ShowModal() == wx.ID_OK:
1747                    self.PatternTree.SetItemText(self.PickId,dataType+dlg.GetValue())
1748            finally:
1749                dlg.Destroy()
1750       
1751    def GetFileList(self,fileType,skip=None):        #potentially useful?
1752        fileList = []
1753        Source = ''
1754        id, cookie = self.PatternTree.GetFirstChild(self.root)
1755        while id:
1756            name = self.PatternTree.GetItemText(id)
1757            if fileType in name:
1758                if id == skip:
1759                    Source = name
1760                else:
1761                    fileList.append([False,name,id])
1762            id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1763        if skip:
1764            return fileList,Source
1765        else:
1766            return fileList
1767           
1768    def OnDataDelete(self, event):
1769        TextList = ['All Data']
1770        DelList = []
1771        DelItemList = []
1772        ifPWDR = False
1773        ifIMG = False
1774        ifHKLF = False
1775        ifPDF = False
1776        if self.PatternTree.GetCount():
1777            item, cookie = self.PatternTree.GetFirstChild(self.root)
1778            while item:
1779                name = self.PatternTree.GetItemText(item)
1780                if name not in ['Notebook','Controls','Covariance','Constraints','Restraints','Phases']:
1781                    if 'PWDR' in name: ifPWDR = True
1782                    if 'IMG' in name: ifIMG = True
1783                    if 'HKLF' in name: ifHKLF = True
1784                    if 'PDF' in name: ifPDF = True
1785                    TextList.append(name)
1786                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1787            if ifPWDR: TextList.insert(1,'All PWDR')
1788            if ifIMG: TextList.insert(1,'All IMG')
1789            if ifHKLF: TextList.insert(1,'All HKLF')
1790            if ifPDF: TextList.insert(1,'All PDF')               
1791            dlg = wx.MultiChoiceDialog(self, 'Which data to delete?', 'Delete data', TextList, wx.CHOICEDLG_STYLE)
1792            try:
1793                if dlg.ShowModal() == wx.ID_OK:
1794                    result = dlg.GetSelections()
1795                    for i in result: DelList.append(TextList[i])
1796                    if 'All Data' in DelList:
1797                        DelList = [item for item in TextList if item[:3] != 'All']
1798                    elif 'All PWDR' in DelList:
1799                        DelList = [item for item in TextList if item[:4] == 'PWDR']
1800                    elif 'All IMG' in DelList:
1801                        DelList = [item for item in TextList if item[:3] == 'IMG']
1802                    elif 'All HKLF' in DelList:
1803                        DelList = [item for item in TextList if item[:4] == 'HKLF']
1804                    elif 'All PDF' in DelList:
1805                        DelList = [item for item in TextList if item[:3] == 'PDF']
1806                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1807                    while item:
1808                        if self.PatternTree.GetItemText(item) in DelList: DelItemList.append(item)
1809                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1810                    for item in DelItemList:
1811                        self.PatternTree.Delete(item)
1812                    self.PickId = 0
1813                    wx.CallAfter(G2plt.PlotPatterns,self,True)                        #so plot gets updated
1814            finally:
1815                dlg.Destroy()
1816
1817    def OnFileOpen(self, event):
1818        result = ''
1819        Id = 0
1820        if self.PatternTree.GetChildrenCount(self.root,False):
1821            if self.dataFrame:
1822                self.dataFrame.Clear() 
1823            dlg = wx.MessageDialog(
1824                self,
1825                'Do you want to overwrite the current project? '
1826                'Any unsaved changes will be lost. Press OK to continue.',
1827                'Overwrite?',  wx.OK | wx.CANCEL)
1828            try:
1829                result = dlg.ShowModal()
1830                if result == wx.ID_OK:
1831                    self.PatternTree.DeleteChildren(self.root)
1832                    self.GSASprojectfile = ''
1833                    if self.HKL: self.HKL = []
1834                    if self.G2plotNB.plotList:
1835                        self.G2plotNB.clear()
1836            finally:
1837                dlg.Destroy()
1838        if result != wx.ID_CANCEL:   
1839            if self.dataDisplay: self.dataDisplay.Destroy()
1840            dlg = wx.FileDialog(self, 'Choose GSAS-II project file', '.', '', 
1841                'GSAS-II project file (*.gpx)|*.gpx',wx.OPEN|wx.CHANGE_DIR)
1842            try:
1843                if dlg.ShowModal() == wx.ID_OK:
1844                    self.GSASprojectfile = dlg.GetPath()
1845                    self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
1846                    self.dirname = dlg.GetDirectory()
1847                    G2IO.ProjFileOpen(self)
1848                    self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
1849                    self.PatternTree.Expand(self.root)
1850                    self.HKL = []
1851                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1852                    while item and not Id:
1853                        name = self.PatternTree.GetItemText(item)
1854                        if name[:4] in ['PWDR','HKLF','IMG ','PDF ']:
1855                            Id = item
1856                        elif name == 'Controls':
1857                            data = self.PatternTree.GetItemPyData(item)
1858                            if data:
1859                                for item in self.Refine: item.Enable(True)
1860                                for item in self.SeqRefine: item.Enable(True)
1861                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
1862                    if Id:
1863                        self.PatternTree.SelectItem(Id)
1864                    self.CheckNotebook()
1865                    os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1866            finally:
1867                dlg.Destroy()
1868
1869    def OnFileClose(self, event):
1870        if self.dataFrame:
1871            self.dataFrame.Clear()
1872            self.dataFrame.SetLabel('GSAS-II data display') 
1873        dlg = wx.MessageDialog(self, 'Save current project?', ' ', wx.YES | wx.NO | wx.CANCEL)
1874        try:
1875            result = dlg.ShowModal()
1876            if result == wx.ID_OK:
1877                self.OnFileSaveMenu(event)
1878            if result != wx.ID_CANCEL:
1879                self.GSASprojectfile = ''
1880                self.PatternTree.SetItemText(self.root,'Loaded Data: ')
1881                self.PatternTree.DeleteChildren(self.root)
1882                if self.HKL: self.HKL = []
1883                if self.G2plotNB.plotList:
1884                    self.G2plotNB.clear()
1885        finally:
1886            dlg.Destroy()
1887
1888    def OnFileSave(self, event):
1889       
1890        if self.GSASprojectfile: 
1891            self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
1892            G2IO.ProjFileSave(self)
1893        else:
1894            self.OnFileSaveas(event)
1895
1896    def OnFileSaveas(self, event):
1897        dlg = wx.FileDialog(self, 'Choose GSAS-II project file name', '.', '', 
1898            'GSAS-II project file (*.gpx)|*.gpx',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1899        try:
1900            if dlg.ShowModal() == wx.ID_OK:
1901                self.GSASprojectfile = dlg.GetPath()
1902                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
1903                self.PatternTree.SetItemText(self.root,'Saving project as'+self.GSASprojectfile)
1904                self.SetTitle("GSAS-II data tree: "+
1905                              os.path.split(self.GSASprojectfile)[1])
1906                G2IO.ProjFileSave(self)
1907                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1908        finally:
1909            dlg.Destroy()
1910
1911    def ExitMain(self, event):
1912        if self.undofile:
1913            os.remove(self.undofile)
1914        sys.exit()
1915       
1916    def OnFileExit(self, event):
1917        if self.dataFrame:
1918            self.dataFrame.Clear() 
1919            self.dataFrame.Destroy()
1920        self.Close()
1921       
1922    def OnExportPatterns(self,event):
1923        names = ['All']
1924        exports = []
1925        item, cookie = self.PatternTree.GetFirstChild(self.root)
1926        while item:
1927            name = self.PatternTree.GetItemText(item)
1928            if 'PWDR' in name:
1929                names.append(name)
1930            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1931        if names:
1932            dlg = wx.MultiChoiceDialog(self,'Select','Powder patterns to export',names)
1933            if dlg.ShowModal() == wx.ID_OK:
1934                sel = dlg.GetSelections()
1935                if sel[0] == 0:
1936                    exports = names[1:]
1937                else:
1938                    for x in sel:
1939                        exports.append(names[x])
1940            dlg.Destroy()
1941        if exports:
1942            dlg = wx.FileDialog(self, 'Choose output powder file name', '.', '', 
1943                'GSAS fxye file (*.fxye)|*.fxye|xye file (*.xye)|*.xye',
1944                wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1945            try:
1946                if dlg.ShowModal() == wx.ID_OK:
1947                    powderfile = dlg.GetPath()
1948                    powderfile = G2IO.FileDlgFixExt(dlg,powderfile)
1949                    if 'fxye' in powderfile:
1950                        G2IO.powderFxyeSave(self,exports,powderfile)
1951                    else:       #just xye
1952                        G2IO.powderXyeSave(self,exports,powderfile)
1953            finally:
1954                dlg.Destroy()
1955       
1956    def OnExportPeakList(self,event):
1957        dlg = wx.FileDialog(self, 'Choose output peak list file name', '.', '', 
1958            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1959        try:
1960            if dlg.ShowModal() == wx.ID_OK:
1961                self.peaklistfile = dlg.GetPath()
1962                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
1963                file = open(self.peaklistfile,'w')               
1964                item, cookie = self.PatternTree.GetFirstChild(self.root)
1965                while item:
1966                    name = self.PatternTree.GetItemText(item)
1967                    if 'PWDR' in name:
1968                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
1969                        while item2:
1970                            name2 = self.PatternTree.GetItemText(item2)
1971                            if name2 == 'Peak List':
1972                                peaks = self.PatternTree.GetItemPyData(item2)
1973                                file.write("%s \n" % (name+' Peak List'))               
1974                                for peak in peaks:
1975                                    file.write("%10.5f %12.2f %10.3f %10.3f \n" % \
1976                                        (peak[0],peak[2],peak[4],peak[6]))
1977                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
1978                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
1979                file.close()
1980        finally:
1981            dlg.Destroy()
1982       
1983    def OnExportHKL(self,event):
1984        event.Skip()
1985       
1986    def OnExportPDF(self,event):
1987        #need S(Q) and G(R) to be saved here - probably best from selection?
1988        names = ['All']
1989        exports = []
1990        item, cookie = self.PatternTree.GetFirstChild(self.root)
1991        while item:
1992            name = self.PatternTree.GetItemText(item)
1993            if 'PDF' in name:
1994                names.append(name)
1995            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1996        if names:
1997            dlg = wx.MultiChoiceDialog(self,'Select','PDF patterns to export',names)
1998            if dlg.ShowModal() == wx.ID_OK:
1999                sel = dlg.GetSelections()
2000                if sel[0] == 0:
2001                    exports = names[1:]
2002                else:
2003                    for x in sel:
2004                        exports.append(names[x])
2005            dlg.Destroy()
2006        if exports:
2007            G2IO.PDFSave(self,exports)
2008       
2009    def OnExportPhase(self,event):
2010        event.Skip()
2011       
2012    def OnExportCIF(self,event):
2013        event.Skip()
2014
2015    def OnMakePDFs(self,event):
2016        tth2q = lambda t,w:4.0*math.pi*sind(t/2.0)/w
2017        TextList = ['All PWDR']
2018        PDFlist = []
2019        Names = []
2020        if self.PatternTree.GetCount():
2021            id, cookie = self.PatternTree.GetFirstChild(self.root)
2022            while id:
2023                name = self.PatternTree.GetItemText(id)
2024                Names.append(name)
2025                if 'PWDR' in name:
2026                    TextList.append(name)
2027                id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
2028            if len(TextList) == 1:
2029                self.ErrorDialog('Nothing to make PDFs for','There must be at least one "PWDR" pattern')
2030                return
2031            dlg = wx.MultiChoiceDialog(self,'Make PDF controls','Make PDF controls for:',TextList, wx.CHOICEDLG_STYLE)
2032            try:
2033                if dlg.ShowModal() == wx.ID_OK:
2034                    result = dlg.GetSelections()
2035                    for i in result: PDFlist.append(TextList[i])
2036                    if 0 in result:
2037                        PDFlist = [item for item in TextList if item[:4] == 'PWDR']                       
2038                    for item in PDFlist:
2039                        PWDRname = item[4:]
2040                        Id = self.PatternTree.AppendItem(parent=self.root,text='PDF '+PWDRname)
2041                        Data = {
2042                            'Sample':{'Name':item,'Mult':1.0,'Add':0.0},
2043                            'Sample Bkg.':{'Name':'','Mult':-1.0,'Add':0.0},
2044                            'Container':{'Name':'','Mult':-1.0,'Add':0.0},
2045                            'Container Bkg.':{'Name':'','Mult':-1.0,'Add':0.0},'ElList':{},
2046                            'Geometry':'Cylinder','Diam':1.0,'Pack':0.50,'Form Vol':10.0,
2047                            'DetType':'Image plate','ObliqCoeff':0.2,'Ruland':0.025,'QScaleLim':[0,100],
2048                            'Lorch':True,}
2049                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='PDF Controls'),Data)
2050                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='I(Q)'+PWDRname),[])       
2051                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='S(Q)'+PWDRname),[])       
2052                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='F(Q)'+PWDRname),[])       
2053                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='G(R)'+PWDRname),[])       
2054                for item in self.ExportPDF: item.Enable(True)
2055            finally:
2056                dlg.Destroy()
2057               
2058    def GetPWDRdatafromTree(self,PWDRname):
2059        ''' Returns powder data from GSASII tree
2060        input:
2061            PWDRname = powder histogram name as obtained from GetHistogramNames
2062        return:
2063            PWDRdata = powder data dictionary with:
2064                Data - powder data arrays, Limits, Instrument Parameters, Sample Parameters           
2065        '''
2066        PWDRdata = {}
2067        try:
2068            PWDRdata.update(self.PatternTree.GetItemPyData(PWDRname)[0])            #wtFactor + ?
2069        except ValueError:
2070            PWDRdata['wtFactor'] = 1.0
2071        PWDRdata['Data'] = self.PatternTree.GetItemPyData(PWDRname)[1]          #powder data arrays
2072        PWDRdata['Limits'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Limits'))
2073        PWDRdata['Background'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Background'))
2074        PWDRdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Instrument Parameters'))
2075        PWDRdata['Sample Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Sample Parameters'))
2076        PWDRdata['Reflection Lists'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Reflection Lists'))
2077        if 'ranId' not in PWDRdata['Sample Parameters']:
2078            PWDRdata['Sample Parameters']['ranId'] = ran.randint(0,sys.maxint)
2079        PWDRdata['ranId'] = PWDRdata['Sample Parameters']['ranId']
2080        return PWDRdata
2081
2082    def GetHKLFdatafromTree(self,HKLFname):
2083        ''' Returns single crystal data from GSASII tree
2084        input:
2085            HKLFname = single crystal histogram name as obtained from GetHistogramNames
2086        return:
2087            HKLFdata = single crystal data list of reflections: for each reflection:
2088                HKLF =
2089        '''
2090        HKLFdata = {}
2091        try:
2092            HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
2093        except ValueError:
2094            HKLFdata['wtFactor'] = 1.0
2095        HKLFdata['Data'] = self.PatternTree.GetItemPyData(HKLFname)[1]
2096        HKLFdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,HKLFname,'Instrument Parameters'))
2097        return HKLFdata
2098       
2099    def GetPhaseData(self):
2100        phaseData = {}
2101        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
2102            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
2103        else:
2104            print 'no phases to be refined'
2105            return
2106        if sub:
2107            item, cookie = self.PatternTree.GetFirstChild(sub)
2108            while item:
2109                phaseName = self.PatternTree.GetItemText(item)
2110                phaseData[phaseName] =  self.PatternTree.GetItemPyData(item)
2111                if 'ranId' not in phaseData[phaseName]:
2112                    phaseData[phaseName]['ranId'] = ran.randint(0,sys.maxint)         
2113                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
2114        return phaseData               
2115                   
2116    def GetUsedHistogramsAndPhasesfromTree(self):
2117        ''' Returns all histograms that are found in any phase
2118        and any phase that uses a histogram
2119        return:
2120            Histograms = dictionary of histograms as {name:data,...}
2121            Phases = dictionary of phases that use histograms
2122        '''
2123        phaseData = self.GetPhaseData()
2124        if not phaseData:
2125            return {},{}
2126        Histograms = {}
2127        Phases = {}
2128        pId = 0
2129        hId = 0
2130        for phase in phaseData:
2131            Phase = phaseData[phase]
2132            if Phase['Histograms']:
2133                if phase not in Phases:
2134                    Phase['pId'] = pId
2135                    pId += 1
2136                    Phases[phase] = Phase
2137                for hist in Phase['Histograms']:
2138                    if hist not in Histograms:
2139                        item = G2gd.GetPatternTreeItemId(self,self.root,hist)
2140                        if 'PWDR' in hist[:4]: 
2141                            Histograms[hist] = self.GetPWDRdatafromTree(item)
2142                        elif 'HKLF' in hist[:4]:
2143                            Histograms[hist] = self.GetHKLFdatafromTree(item)
2144                        #future restraint, etc. histograms here           
2145                        Histograms[hist]['hId'] = hId
2146                        hId += 1
2147        return Histograms,Phases
2148       
2149    class ViewParmDialog(wx.Dialog):
2150        def __init__(self,parent,title,parmDict):
2151            wx.Dialog.__init__(self,parent,-1,title,size=(300,430),
2152                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
2153            panel = wx.Panel(self,size=(300,430))
2154            parmNames = parmDict.keys()
2155            parmNames.sort()
2156            parmText = ' p:h:Parameter       refine?              value\n'
2157            for name in parmNames:
2158                parmData = parmDict[name]
2159                try:
2160                    parmText += ' %s \t%12.4g \n'%(name.ljust(19)+'\t'+parmData[1],parmData[0])
2161                except TypeError:
2162                    pass
2163            parmTable = wx.TextCtrl(panel,-1,parmText,
2164                style=wx.TE_MULTILINE|wx.TE_READONLY,size=(290,400))
2165            mainSizer = wx.BoxSizer(wx.VERTICAL)
2166            mainSizer.Add(parmTable)
2167            panel.SetSizer(mainSizer)
2168                           
2169    def OnViewLSParms(self,event):
2170        parmDict = {}
2171        Histograms,Phases = self.GetUsedHistogramsAndPhasesfromTree()
2172        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable = G2str.GetPhaseData(Phases,RestraintDict=None,Print=False)       
2173        hapVary,hapDict,controlDict = G2str.GetHistogramPhaseData(Phases,Histograms,Print=False)
2174        histVary,histDict,controlDict = G2str.GetHistogramData(Histograms,Print=False)
2175        varyList = phaseVary+hapVary+histVary
2176        parmDict.update(phaseDict)
2177        parmDict.update(hapDict)
2178        parmDict.update(histDict)
2179        for parm in parmDict:
2180            if parm.split(':')[-1] in ['Azimuth','Gonio. radius','Lam1','Lam2',
2181                'Omega','Chi','Phi','nDebye','nPeaks']:
2182                parmDict[parm] = [parmDict[parm],' ']
2183            elif parm.split(':')[-2] in ['Ax','Ay','Az','SHmodel','SHord']:
2184                parmDict[parm] = [parmDict[parm],' ']
2185            elif parm in varyList:
2186                parmDict[parm] = [parmDict[parm],'True']
2187            else:
2188                parmDict[parm] = [parmDict[parm],'False']
2189        parmDict[' Num refined'] = [len(varyList),'']
2190        dlg = self.ViewParmDialog(self,'Parameters for least squares',parmDict)
2191        try:
2192            if dlg.ShowModal() == wx.ID_OK:
2193                print 'do something with changes?? - No!'
2194        finally:
2195            dlg.Destroy()
2196       
2197    def OnRefine(self,event):
2198        self.OnFileSave(event)
2199        # check that constraints are OK here
2200        errmsg, warnmsg = G2str.CheckConstraints(self.GSASprojectfile)
2201        if errmsg:
2202            print('Error in constraints:\n'+errmsg+
2203                  '\nRefinement not possible')
2204            self.ErrorDialog('Constraint Error',
2205                             'Error in constraints:\n'+errmsg+
2206                             '\nRefinement not possible')
2207            return
2208        if warnmsg:
2209            print('Conflict between refinment flag settings and constraints:\n'+
2210                  warnmsg+'\nRefinement not possible')
2211            self.ErrorDialog('Refinement Flag Error',
2212                             'Conflict between refinment flag settings and constraints:\n'+
2213                             warnmsg+
2214                             '\nRefinement not possible')
2215            return
2216        #works - but it'd be better if it could restore plots
2217        dlg = wx.ProgressDialog('Residual','All data Rw =',101.0, 
2218            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
2219        screenSize = wx.ClientDisplayRect()
2220        Size = dlg.GetSize()
2221        Size = (int(Size[0]*1.2),Size[1]) # increase size a bit along x
2222        dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
2223        dlg.SetSize(Size)
2224        Rw = 100.00
2225        try:
2226            Rw = G2str.Refine(self.GSASprojectfile,dlg)
2227        finally:
2228            dlg.Destroy()
2229        oldId =  self.PatternTree.GetSelection()
2230        oldName = self.PatternTree.GetItemText(oldId)
2231        parentId = self.PatternTree.GetItemParent(oldId)
2232        parentName = ''
2233        if parentId:
2234            parentName = self.PatternTree.GetItemText(parentId)
2235        dlg = wx.MessageDialog(self,'Load new result?','Refinement results, Rw =%.3f'%(Rw),wx.OK|wx.CANCEL)
2236        try:
2237            if dlg.ShowModal() == wx.ID_OK:
2238                Id = 0
2239                self.PatternTree.DeleteChildren(self.root)
2240                if self.HKL: self.HKL = []
2241                if self.G2plotNB.plotList:
2242                    self.G2plotNB.clear()
2243                G2IO.ProjFileOpen(self)
2244                item, cookie = self.PatternTree.GetFirstChild(self.root)
2245                while item and not Id:
2246                    name = self.PatternTree.GetItemText(item)
2247                    if name[:4] in ['PWDR','HKLF']:
2248                        Id = item
2249                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
2250                if parentName:
2251                    parentId = G2gd.GetPatternTreeItemId(self, self.root, parentName)
2252                    if parentId:
2253                        itemId = G2gd.GetPatternTreeItemId(self, parentId, oldName)
2254                    else:
2255                        itemId = G2gd.GetPatternTreeItemId(self, self.root, oldName)
2256                    self.PatternTree.SelectItem(itemId)
2257                elif Id:
2258                    self.PatternTree.SelectItem(Id)
2259        finally:
2260            dlg.Destroy()
2261
2262    def OnSeqRefine(self,event):
2263        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequental results')
2264        if not Id:
2265            Id = self.PatternTree.AppendItem(self.root,text='Sequental results')
2266            self.PatternTree.SetItemPyData(Id,{})           
2267        self.OnFileSave(event)
2268        # check that constraints are OK here
2269        errmsg, warnmsg = G2str.CheckConstraints(self.GSASprojectfile)
2270        if errmsg:
2271            print('Error in constraints:\n'+errmsg+
2272                  '\nRefinement not possible')
2273            self.ErrorDialog('Constraint Error',
2274                             'Error in constraints:\n'+errmsg+
2275                             '\nRefinement not possible')
2276            return
2277        if warnmsg:
2278            print('Conflict between refinment flag settings and constraints:\n'+
2279                  warnmsg+'\nRefinement not possible')
2280            self.ErrorDialog('Refinement Flag Error',
2281                             'Conflict between refinment flag settings and constraints:\n'+
2282                             warnmsg+'\nRefinement not possible')
2283            return
2284        dlg = wx.ProgressDialog('Residual for histogram 0','Powder profile Rwp =',101.0, 
2285            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
2286        screenSize = wx.ClientDisplayRect()
2287        Size = dlg.GetSize()
2288        Size = (int(Size[0]*1.2),Size[1]) # increase size a bit along x
2289        dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
2290        dlg.SetSize(Size)
2291        try:
2292            G2str.SeqRefine(self.GSASprojectfile,dlg)
2293        finally:
2294            dlg.Destroy()       
2295        dlg = wx.MessageDialog(self,'Load new result?','Refinement results',wx.OK|wx.CANCEL)
2296        try:
2297            if dlg.ShowModal() == wx.ID_OK:
2298                Id = 0
2299                self.PatternTree.DeleteChildren(self.root)
2300                if self.HKL: self.HKL = []
2301                if self.G2plotNB.plotList:
2302                    self.G2plotNB.clear()
2303                G2IO.ProjFileOpen(self)
2304                item, cookie = self.PatternTree.GetFirstChild(self.root)
2305                while item and not Id:
2306                    name = self.PatternTree.GetItemText(item)
2307                    if name[:4] in ['PWDR','HKLF']:
2308                        Id = item
2309                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
2310                if Id:
2311                    self.PatternTree.SelectItem(Id)
2312        finally:
2313            dlg.Destroy()
2314       
2315    def ErrorDialog(self,title,message,parent=None, wtype=wx.OK):
2316        result = None
2317        if parent is None:
2318            dlg = wx.MessageDialog(self, message, title,  wtype)
2319        else:
2320            dlg = wx.MessageDialog(parent, message, title,  wtype)
2321            dlg.CenterOnParent() # not working on Mac
2322        try:
2323            result = dlg.ShowModal()
2324        finally:
2325            dlg.Destroy()
2326        return result
2327
2328class GSASIImain(wx.App):
2329    def OnInit(self):
2330        self.main = GSASII(None)
2331        self.main.Show()
2332        self.SetTopWindow(self.main)
2333        return True
2334
2335def main():
2336    application = GSASIImain(0)
2337    if wxInspector: wxeye.InspectionTool().Show()
2338
2339    #application.main.OnRefine(None)
2340    application.MainLoop()
2341   
2342if __name__ == '__main__':
2343    main()
Note: See TracBrowser for help on using the repository browser.