source: trunk/GSASII.py @ 884

Last change on this file since 884 was 884, checked in by toby, 10 years ago

add histogram input from a GPX file; minor import fixes

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