source: trunk/GSASII.py @ 891

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

Fix bug reading instprm file

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