source: trunk/GSASII.py @ 600

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