source: trunk/GSASII.py @ 804

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

remove a "finally" that isn't needed & gives errors sometimes

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