source: trunk/GSASII.py @ 643

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

allow multiple selection from zip on data input, read structure CIFs w/o atom type

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