source: trunk/GSASII.py @ 792

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

change instrument parameters to dict from lists
chase down effects - got them all?
start on TOF; read TimeMap? style data - not complete

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