source: trunk/GSASII.py @ 798

Last change on this file since 798 was 798, checked in by vondreele, 13 years ago

more peak fitting work including TOF

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