source: trunk/GSASII.py @ 765

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

refactor menus on Mac, clean up main menu generation

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