source: trunk/GSASII.py @ 717

Last change on this file since 717 was 717, checked in by vondreele, 10 years ago

more working directory changes

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