source: trunk/GSASII.py @ 577

Last change on this file since 577 was 577, checked in by toby, 12 years ago

fix error in reporting constraint errors

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