source: trunk/GSASII.py @ 696

Last change on this file since 696 was 696, checked in by vondreele, 10 years ago

begin implementation of image strain analysis - GUI stuff first
make image plot respond & clean up display some.
fix atom selection so N can be selected from periodic table
remove crash when Pawley refl not found in reflection set - it's now skipped

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