source: trunk/GSASII.py @ 641

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

add support for zipped data and zip up largest exercise files

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