source: trunk/GSASII.py @ 581

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

refactor to simplify import setup

  • Property svn:keywords set to Date Author Revision URL Id
File size: 88.1 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#GSASII
4########### SVN repository information ###################
5# $Date: 2012-04-30 17:42:29 +0000 (Mon, 30 Apr 2012) $
6# $Author: toby $
7# $Revision: 581 $
8# $URL: trunk/GSASII.py $
9# $Id: GSASII.py 581 2012-04-30 17:42:29Z toby $
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='Data tree'),title='&Help' )
129
130    def _init_coll_File_Items(self, parent):
131        parent.Append(help='Open a gsasii project file (*.gpx)', id=wxID_FILEOPEN,
132             kind=wx.ITEM_NORMAL,text='Open project...')
133        parent.Append(help='Save project to old file', id=wxID_FILESAVE, 
134            kind=wx.ITEM_NORMAL,text='Save project')
135        parent.Append(help='Save project to new file', id=wxID_FILESAVEAS, 
136            kind=wx.ITEM_NORMAL,text='Save As...')
137        parent.Append(help='Close project, saving is optional', id=wxID_FILECLOSE, 
138            kind=wx.ITEM_NORMAL,text='Close project')
139        parent.Append(help='Exit from gsasii', id=wxID_FILEEXIT, kind=wx.ITEM_NORMAL,
140            text='Exit')
141        self.Bind(wx.EVT_MENU, self.OnFileOpen, id=wxID_FILEOPEN)
142        self.Bind(wx.EVT_MENU, self.OnFileSave, id=wxID_FILESAVE)
143        self.Bind(wx.EVT_MENU, self.OnFileSaveas, id=wxID_FILESAVEAS)
144        self.Bind(wx.EVT_MENU, self.OnFileClose, id=wxID_FILECLOSE)
145        self.Bind(wx.EVT_MENU, self.OnFileExit, id=wxID_FILEEXIT)
146       
147    def _init_coll_Data_Items(self,parent):
148        parent.Append(help='', id=wxID_PWDRREAD, kind=wx.ITEM_NORMAL,
149            text='Read powder data...')
150        parent.Append(help='',id=wxID_IMGREAD, kind=wx.ITEM_NORMAL,
151            text='Read image data...')
152        parent.Append(help='',id=wxID_READPEAKS, kind=wx.ITEM_NORMAL,
153            text='Read Powder Pattern Peaks...')
154        parent.Append(help='', id=wxID_SNGLREAD, kind=wx.ITEM_NORMAL,
155            text='Read single crystal data...')
156        parent.Append(help='', id=wxID_PWDSUM, kind=wx.ITEM_NORMAL,
157            text='Sum powder data')
158        parent.Append(help='',id=wxID_IMSUM, kind=wx.ITEM_NORMAL,
159            text='Sum image data')
160        parent.Append(help='', id=wxID_ADDPHASE, kind=wx.ITEM_NORMAL,
161            text='Add phase')
162        parent.Append(help='', id=wxID_DELETEPHASE, kind=wx.ITEM_NORMAL,
163            text='Delete phase')
164        parent.Append(help='', id=wxID_DATARENAME, kind=wx.ITEM_NORMAL,
165            text='Rename data') 
166        parent.Append(help='', id=wxID_DATADELETE, kind=wx.ITEM_NORMAL,
167            text='Delete data')
168        self.Bind(wx.EVT_MENU, self.OnPwdrRead, id=wxID_PWDRREAD)
169        self.Bind(wx.EVT_MENU, self.OnPwdrSum, id=wxID_PWDSUM)
170        self.Bind(wx.EVT_MENU, self.OnReadPowderPeaks, id=wxID_READPEAKS)
171        self.Bind(wx.EVT_MENU, self.OnImageRead, id=wxID_IMGREAD)
172        self.Bind(wx.EVT_MENU, self.OnImageSum, id=wxID_IMSUM)
173        self.Bind(wx.EVT_MENU, self.OnSnglRead, id=wxID_SNGLREAD)
174        self.Bind(wx.EVT_MENU, self.OnAddPhase, id=wxID_ADDPHASE)
175        self.Bind(wx.EVT_MENU, self.OnDeletePhase, id=wxID_DELETEPHASE)
176        self.Bind(wx.EVT_MENU, self.OnRenameData, id=wxID_DATARENAME)
177        self.Bind(wx.EVT_MENU, self.OnDataDelete, id=wxID_DATADELETE)
178               
179    def _init_coll_Calculate_Items(self,parent):
180        self.MakePDF = parent.Append(help='Make new PDFs from selected powder patterns', 
181            id=wxID_MAKEPDFS, kind=wx.ITEM_NORMAL,text='Make new PDFs')
182        self.Bind(wx.EVT_MENU, self.OnMakePDFs, id=wxID_MAKEPDFS)
183        self.ViewLSParms = parent.Append(help='View least squares parameters', 
184            id=wxID_VIEWLSPARMS, kind=wx.ITEM_NORMAL,text='View LS parms')
185        self.Bind(wx.EVT_MENU, self.OnViewLSParms, id=wxID_VIEWLSPARMS)
186        self.Refine = parent.Append(help='', id=wxID_REFINE, kind=wx.ITEM_NORMAL,
187            text='Refine')
188        self.Refine.Enable(False)
189        self.Bind(wx.EVT_MENU, self.OnRefine, id=wxID_REFINE)
190        self.SeqRefine = parent.Append(help='', id=wxID_SEQREFINE, kind=wx.ITEM_NORMAL,
191            text='Sequental refine')
192        self.SeqRefine.Enable(False)
193        self.Bind(wx.EVT_MENU, self.OnSeqRefine, id=wxID_SEQREFINE)
194       
195    def _init_Import_routines(self,parent,prefix,readerlist,errprefix):
196        '''import all the import readers matching the prefix
197        '''
198        path2GSAS2 = os.path.dirname(os.path.realpath(__file__)) # location of this file
199        pathlist = sys.path[:]
200        if path2GSAS2 not in pathlist: pathlist.append(path2GSAS2)
201        filelist = []
202        for path in pathlist:
203            for filename in glob.iglob(os.path.join(
204                path,
205                "G2import"+prefix+"*.py")):
206                filelist.append(filename)   
207                #print 'found',filename
208        filelist = sorted(list(set(filelist))) # remove duplicates
209        for filename in filelist:
210            path,rootname = os.path.split(filename)
211            pkg = os.path.splitext(rootname)[0]
212            try:
213                fp = None
214                fp, fppath,desc = imp.find_module(pkg,[path,])
215                pkg = imp.load_module(pkg,fp,fppath,desc)
216                for clss in inspect.getmembers(pkg): # find classes defined in package
217                    if clss[0].startswith('_'): continue
218                    if inspect.isclass(clss[1]):
219                        # check if we have the required methods
220                        for m in 'Reader','ExtensionValidator','ContentsValidator':
221                            if not hasattr(clss[1],m): break
222                            if not callable(getattr(clss[1],m)): break
223                        else:
224                            reader = clss[1]() # create an import instance
225                            readerlist.append(reader)
226            except AttributeError:
227                print 'Import_'+errprefix+': Attribute Error'+str(filename)
228                pass
229            except ImportError:
230                print 'Import_'+errprefix+': Error importing file'+str(filename)
231                pass
232            finally:
233                if fp: fp.close()
234
235    def OnImportGeneric(self,reader,readerlist,label):
236        '''Call the requested import reader or all of the appropriate
237        import readers in response to a menu item
238        '''
239        self.lastimport = ''
240        if reader is None:
241            #print "use all formats"
242            choices = "any file (*.*)|*.*"
243            extdict = {}
244            # compile a list of allowed extensions
245            for rd in readerlist:
246                fmt = rd.formatName
247                for extn in rd.extensionlist:
248                    if not extdict.get(extn): extdict[extn] = []
249                    extdict[extn] += [fmt,]
250            for extn in sorted(extdict.keys(),cmp=lambda x,y: cmp(x.lower(), y.lower())):
251                fmt = ''
252                for f in extdict[extn]:
253                    if fmt != "": fmt += ', '
254                    fmt += f
255                choices += "|" + fmt + " file (*" + extn + ")|*" + extn
256        else:
257            readerlist = [reader,]
258            # compile a list of allowed extensions
259            choices = reader.formatName + " file ("
260            w = ""
261            for extn in reader.extensionlist:
262                if w != "": w += ";"
263                w += "*" + extn
264            choices += w + ")|" + w
265            if not reader.strictExtension:
266                choices += "|any file (*.*)|*.*"
267        # get the file
268        dlg = wx.FileDialog(
269            self, message="Choose "+label+" input file",
270            #defaultDir=os.getcwd(),
271            defaultFile="",
272            wildcard=choices,
273            style=wx.OPEN | wx.CHANGE_DIR
274            )
275        try:
276            if dlg.ShowModal() == wx.ID_OK:
277                file = dlg.GetPath()
278            else: # cancel was pressed
279                return None
280        finally:
281            dlg.Destroy()
282        # set what formats are compatible with this file
283        primaryReaders = []
284        secondaryReaders = []
285        for reader in readerlist:
286            flag = reader.ExtensionValidator(file)
287            if flag is None: 
288                secondaryReaders.append(reader)
289            elif flag:
290                primaryReaders.append(reader)
291        if len(secondaryReaders) + len(primaryReaders) == 0:
292            self.ErrorDialog('No Format','No matching format for file '+file)
293            return None
294       
295        fp = None
296        try:
297            fp = open(file,'r')
298            self.lastimport = file
299            # try the file first with Readers that specify the
300            # files extension and later with ones that allow it
301            for rd in primaryReaders+secondaryReaders:
302                fp.seek(0)  # rewind
303                if not rd.ContentsValidator(fp):
304                    continue # rejected on cursory check
305                try:
306                    fp.seek(0)  # rewind
307                    flag = rd.Reader(file,fp,self)
308                except:
309                    import traceback
310                    print traceback.format_exc()
311                    self.ErrorDialog('Read Error',
312                                     'Error reading file '+file
313                                     +' with format '+ rd.formatName)
314                    continue
315                if not flag: continue
316                return rd
317        except:
318            import traceback
319            print traceback.format_exc()
320            self.ErrorDialog('Open Error','Error on open of file '+file)
321        finally:
322            if fp: fp.close()
323        return None
324
325    def _init_Import_Phase(self,parent):
326        '''import all the G2importphase*.py files that are found in the
327        path and configure the Import Phase menus accordingly
328        '''
329        self.ImportPhaseReaderlist = []
330        self._init_Import_routines(parent,'phase',
331                                   self.ImportPhaseReaderlist,
332                                   'Phase')
333        submenu = wx.Menu()
334        item = parent.AppendMenu(wx.ID_ANY, 'Import Phase menu',
335            submenu, help='Import phase data')
336        item = submenu.Append(wx.ID_ANY,
337                              help='Import phase data based selected by extension',
338                              kind=wx.ITEM_NORMAL,text='Import Phase by extension')
339        self.Bind(wx.EVT_MENU, self.OnImportPhase, id=item.GetId())
340        for reader in self.ImportPhaseReaderlist:
341            item = submenu.Append(wx.ID_ANY,
342                help='Import specific format phase data',
343                kind=wx.ITEM_NORMAL,text='Import Phase '+reader.formatName+'...')
344            self.ImportMenuId[item.GetId()] = reader
345            self.Bind(wx.EVT_MENU, self.OnImportPhase, id=item.GetId())
346
347    def OnImportPhase(self,event):
348        # look up which format was requested
349        reader = self.ImportMenuId.get(event.GetId())
350        rd = self.OnImportGeneric(reader,
351                                  self.ImportPhaseReaderlist,
352                                  'phase')
353        if rd is None: return
354        dlg = wx.TextEntryDialog( # allow editing of phase name
355            self, 'Enter the name for the new phase',
356            'Edit phase name', rd.Phase['General']['Name'],
357            style=wx.OK)
358        dlg.CenterOnParent()
359        if dlg.ShowModal() == wx.ID_OK:
360            rd.Phase['General']['Name'] = dlg.GetValue()
361        dlg.Destroy()
362        PhaseName = rd.Phase['General']['Name']
363        print 'Read phase '+str(PhaseName)+' from file '+str(self.lastimport)
364        self.CheckNotebook()
365        if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
366            sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
367        else:
368            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
369        psub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
370        self.PatternTree.SetItemPyData(psub,rd.Phase)
371        self.PatternTree.Expand(self.root) # make sure phases are seen
372        self.PatternTree.Expand(sub) 
373        self.PatternTree.Expand(psub) 
374        return # success
375       
376    def _init_Import_Sfact(self,parent):
377        '''import all the G2importsfact*.py files that are found in the
378        path and configure the Import Structure Factor menus accordingly
379        '''
380        self.ImportSfactReaderlist = []
381        self._init_Import_routines(parent,'sfact',
382                                   self.ImportSfactReaderlist,
383                                   'Struct_Factor')
384        submenu = wx.Menu()
385        item = parent.AppendMenu(wx.ID_ANY, 'Import Structure Factor menu',
386            submenu, help='Import Structure Factor data')
387        item = submenu.Append(wx.ID_ANY,
388                              help='Import Structure Factor data based selected by extension',
389                              kind=wx.ITEM_NORMAL,text='Import Structure Factor by extension')
390        self.Bind(wx.EVT_MENU, self.OnImportSfact, id=item.GetId())
391        for reader in self.ImportSfactReaderlist:
392            item = submenu.Append(wx.ID_ANY,
393                help='Import specific format Structure Factor data',
394                kind=wx.ITEM_NORMAL,text='Import Structure Factor '+reader.formatName+'...')
395            self.ImportMenuId[item.GetId()] = reader
396            self.Bind(wx.EVT_MENU, self.OnImportSfact, id=item.GetId())
397
398    def OnImportSfact(self,event):
399        # look up which format was requested
400        reader = self.ImportMenuId.get(event.GetId())
401        rd = self.OnImportGeneric(reader,
402                                  self.ImportSfactReaderlist,
403                                  'Structure Factor')
404        if rd is None: return
405        HistName = ospath.basename(self.lastimport)
406        dlg = wx.TextEntryDialog( # allow editing of Structure Factor name
407            self, 'Enter the name for the new Structure Factor',
408            'Edit Structure Factor name', HistName,
409            style=wx.OK)
410        dlg.CenterOnParent()
411        if dlg.ShowModal() == wx.ID_OK:
412            HistName = dlg.GetValue()
413        dlg.Destroy()
414        print 'Read structure factor table '+str(HistName)+' from file '+str(self.lastimport)
415        self.CheckNotebook()
416        Id = self.PatternTree.AppendItem(parent=self.root,
417                                         text='HKLF '+HistName)
418        self.PatternTree.SetItemPyData(Id,rd.RefList)
419        Sub = self.PatternTree.AppendItem(Id,text='Instrument Parameters')
420        self.PatternTree.SetItemPyData(Sub,rd.Parameters)
421        self.PatternTree.SetItemPyData(
422            self.PatternTree.AppendItem(Id,text='HKL Plot Controls'),
423            rd.Controls)
424        self.PatternTree.SelectItem(Id)
425        self.PatternTree.Expand(Id)
426        self.Sngl = Id
427        return # success
428
429    def _init_coll_Import_Items(self,parent):
430        self.ImportPattern = parent.Append(help='',id=wxID_IMPORTPATTERN, kind=wx.ITEM_NORMAL,
431            text='Import Powder Pattern...')
432        self.ImportHKL = parent.Append(help='',id=wxID_IMPORTHKL, kind=wx.ITEM_NORMAL,
433            text='Import HKLs...')
434        self.Bind(wx.EVT_MENU, self.OnImportPattern, id=wxID_IMPORTPATTERN)
435        self.Bind(wx.EVT_MENU, self.OnImportHKL, id=wxID_IMPORTHKL)
436
437    def _init_coll_Export_Items(self,parent):
438        self.ExportPattern = parent.Append(help='Select PWDR item to enable',id=wxID_EXPORTPATTERN, kind=wx.ITEM_NORMAL,
439            text='Export Powder Patterns...')
440        self.ExportPeakList = parent.Append(help='',id=wxID_EXPORTPEAKLIST, kind=wx.ITEM_NORMAL,
441            text='Export All Peak Lists...')
442        self.ExportHKL = parent.Append(help='',id=wxID_EXPORTHKL, kind=wx.ITEM_NORMAL,
443            text='Export HKLs...')
444        self.ExportPDF = parent.Append(help='Select PDF item to enable',id=wxID_EXPORTPDF, kind=wx.ITEM_NORMAL,
445            text='Export PDF...')
446        self.ExportPhase = parent.Append(help='',id=wxID_EXPORTPHASE, kind=wx.ITEM_NORMAL,
447            text='Export Phase...')
448        self.ExportCIF = parent.Append(help='',id=wxID_EXPORTCIF, kind=wx.ITEM_NORMAL,
449            text='Export CIF...')
450        self.ExportPattern.Enable(False)
451        self.ExportPeakList.Enable(True)
452        self.ExportHKL.Enable(False)
453        self.ExportPDF.Enable(False)
454        self.ExportPhase.Enable(False)
455        self.ExportCIF.Enable(False)
456        self.Bind(wx.EVT_MENU, self.OnExportPatterns, id=wxID_EXPORTPATTERN)
457        self.Bind(wx.EVT_MENU, self.OnExportPeakList, id=wxID_EXPORTPEAKLIST)
458        self.Bind(wx.EVT_MENU, self.OnExportHKL, id=wxID_EXPORTHKL)
459        self.Bind(wx.EVT_MENU, self.OnExportPDF, id=wxID_EXPORTPDF)
460        self.Bind(wx.EVT_MENU, self.OnExportPhase, id=wxID_EXPORTPHASE)
461        self.Bind(wx.EVT_MENU, self.OnExportCIF, id=wxID_EXPORTCIF)
462               
463    def _init_utils(self):
464        self.GSASIIMenu = wx.MenuBar()
465        self.File = wx.Menu(title='')
466        self.Data = wx.Menu(title='')       
467        self.Calculate = wx.Menu(title='')       
468        self.Import = wx.Menu(title='')       
469        self.Export = wx.Menu(title='')       
470
471        self._init_coll_GSASIIMenu_Menus(self.GSASIIMenu)
472        self._init_coll_File_Items(self.File)
473        self._init_coll_Data_Items(self.Data)
474        self._init_coll_Calculate_Items(self.Calculate)
475        self.ImportMenuId = {}
476        self._init_Import_Phase(self.Import)
477        self._init_Import_Sfact(self.Import)
478        self._init_coll_Import_Items(self.Import)
479        self._init_coll_Export_Items(self.Export)
480       
481    def _init_ctrls(self, parent):
482        wx.Frame.__init__(self, name='GSASII', parent=parent,
483            size=wx.Size(300, 250),style=wx.DEFAULT_FRAME_STYLE, title='GSAS-II data tree')
484        clientSize = wx.ClientDisplayRect()
485        Size = self.GetSize()
486        xPos = clientSize[2]-Size[0]
487        self.SetPosition(wx.Point(xPos,clientSize[1]))
488        self._init_utils()
489        self.SetMenuBar(self.GSASIIMenu)
490        self.Bind(wx.EVT_SIZE, self.OnSize)
491        self.CreateStatusBar()
492        self.mainPanel = wx.Panel(self,-1)
493       
494        self.PatternTree = wx.TreeCtrl(id=wxID_PATTERNTREE,
495            parent=self.mainPanel, pos=wx.Point(0, 0),style=wx.TR_DEFAULT_STYLE )
496        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED,
497            self.OnPatternTreeSelChanged, id=wxID_PATTERNTREE)
498        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
499            self.OnPatternTreeItemCollapsed, id=wxID_PATTERNTREE)
500        self.PatternTree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
501            self.OnPatternTreeItemExpanded, id=wxID_PATTERNTREE)
502        self.PatternTree.Bind(wx.EVT_TREE_DELETE_ITEM,
503            self.OnPatternTreeItemDelete, id=wxID_PATTERNTREE)
504        self.PatternTree.Bind(wx.EVT_TREE_KEY_DOWN,
505            self.OnPatternTreeKeyDown, id=wxID_PATTERNTREE)
506        self.root = self.PatternTree.AddRoot('Loaded Data: ')
507       
508        plotFrame = wx.Frame(None,-1,'GSASII Plots',size=wx.Size(700,600), \
509            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
510        self.G2plotNB = G2plt.G2PlotNoteBook(plotFrame)
511        plotFrame.Show()
512       
513        self.dataDisplay = None
514       
515    def __init__(self, parent):
516        self._init_ctrls(parent)
517        self.Bind(wx.EVT_CLOSE, self.ExitMain)
518        # various defaults
519        self.oldFocus = None
520        self.GSASprojectfile = ''
521        self.dirname = ospath.expanduser('~')       #start in the users home directory by default; may be meaningless
522        self.undofile = ''
523        self.TreeItemDelete = False
524        self.Offset = [0.0,0.0]
525        self.delOffset = .02
526        self.refOffset = -100.0
527        self.refDelt = .01
528        self.Weight = False
529        self.IparmName = ''
530        self.IfPlot = False
531        self.PatternId = 0
532        self.PickId = 0
533        self.PeakTable = []
534        self.LimitsTable = []
535        self.HKL = []
536        self.Lines = []
537        self.itemPicked = None
538        self.dataFrame = None
539        self.Interpolate = 'nearest'
540        self.ContourColor = 'Paired'
541        self.VcovColor = 'RdYlGn'
542        self.Projection = 'equal area'
543        self.logPlot = False
544        self.qPlot = False
545        self.Contour = False
546        self.Legend = False
547        self.SinglePlot = False
548        self.plotView = 0
549        self.Image = 0
550        self.oldImagefile = ''
551        self.ImageZ = []
552        self.Integrate = 0
553        self.Pwdr = False
554        self.imageDefault = {}
555        self.Sngl = 0
556        self.ifGetRing = False
557        self.setPoly = False
558        arg = sys.argv
559        if len(arg) > 1:
560            self.GSASprojectfile = arg[1]
561            self.dirname = ospath.dirname(arg[1])
562            if self.dirname: os.chdir(self.dirname)
563            G2IO.ProjFileOpen(self)
564            self.PatternTree.Expand(self.root)
565            self.Refine.Enable(True)
566            self.SeqRefine.Enable(True)
567            #self.Solve.Enable(True) # what is this? (BHT)
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.