source: trunk/GSASII.py @ 660

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

try revision number tracking

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