source: trunk/GSASII.py @ 615

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

add powder CIF importer, minor other updates to readers

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