source: trunk/GSASII.py @ 831

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

more on rigid bodies

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