source: trunk/GSASII.py @ 776

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

revise menu creation to add 2nd separator on mac and put Help as final menu in Win/Linux?

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 102.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#GSASII
4########### SVN repository information ###################
5# $Date: 2012-10-03 21:49:39 +0000 (Wed, 03 Oct 2012) $
6# $Author: toby $
7# $Revision: 776 $
8# $URL: trunk/GSASII.py $
9# $Id: GSASII.py 776 2012-10-03 21:49:39Z 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: 776 $")
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        #initialize Menu item objects (these contain lists of menu items that are enabled or disabled)
948        self.MakePDF = []
949        self.Refine = []
950        self.SeqRefine = []
951        self.ExportPattern = []
952        self.ExportPeakList = []
953        self.ExportHKL = []
954        self.ExportPDF = []
955        self.ExportPhase = []
956        self.ExportCIF = []
957        #
958        self.GSASIIMenu = wx.MenuBar()
959        self.FillMainMenu(self.GSASIIMenu)
960        self.SetMenuBar(self.GSASIIMenu)
961        self.Bind(wx.EVT_SIZE, self.OnSize)
962        self.CreateStatusBar()
963        self.mainPanel = wx.Panel(self,-1)
964       
965        wxID_PATTERNTREE = wx.NewId()
966        self.PatternTree = wx.TreeCtrl(id=wxID_PATTERNTREE,
967            parent=self.mainPanel, pos=wx.Point(0, 0),style=wx.TR_DEFAULT_STYLE )
968        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED,
969            self.OnPatternTreeSelChanged, id=wxID_PATTERNTREE)
970        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
971            self.OnPatternTreeItemCollapsed, id=wxID_PATTERNTREE)
972        self.PatternTree.Bind(wx.EVT_TREE_ITEM_EXPANDED,
973            self.OnPatternTreeItemExpanded, id=wxID_PATTERNTREE)
974        self.PatternTree.Bind(wx.EVT_TREE_DELETE_ITEM,
975            self.OnPatternTreeItemDelete, id=wxID_PATTERNTREE)
976        self.PatternTree.Bind(wx.EVT_TREE_KEY_DOWN,
977            self.OnPatternTreeKeyDown, id=wxID_PATTERNTREE)
978        self.root = self.PatternTree.AddRoot('Loaded Data: ')
979       
980        plotFrame = wx.Frame(None,-1,'GSASII Plots',size=wx.Size(700,600), \
981            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX)
982        self.G2plotNB = G2plt.G2PlotNoteBook(plotFrame)
983        plotFrame.Show()
984       
985        self.dataDisplay = None
986       
987    def __init__(self, parent):
988        self._init_ctrls(parent)
989        self.Bind(wx.EVT_CLOSE, self.ExitMain)
990        # various defaults
991        self.oldFocus = None
992        self.GSASprojectfile = ''
993        self.dirname = os.path.expanduser('~')       #start in the users home directory by default; may be meaningless
994        self.undofile = ''
995        self.TreeItemDelete = False
996        self.Offset = [0.0,0.0]
997        self.delOffset = .02
998        self.refOffset = -100.0
999        self.refDelt = .01
1000        self.Weight = False
1001        self.IparmName = ''  # to be removed when SelectPowderData & GetInstrumentFile is
1002        self.IfPlot = False
1003        self.PatternId = 0
1004        self.PickId = 0
1005        self.PeakTable = []
1006        self.LimitsTable = []
1007        self.HKL = []
1008        self.Lines = []
1009        self.itemPicked = None
1010        self.dataFrame = None
1011        self.Interpolate = 'nearest'
1012        self.ContourColor = 'Paired'
1013        self.VcovColor = 'RdYlGn'
1014        self.Projection = 'equal area'
1015        self.logPlot = False
1016        self.qPlot = False
1017        self.Contour = False
1018        self.Legend = False
1019        self.SinglePlot = False
1020        self.plotView = 0
1021        self.Image = 0
1022        self.oldImagefile = ''
1023        self.ImageZ = []
1024        self.Integrate = 0
1025        self.imageDefault = {}
1026        self.Sngl = 0
1027        self.ifGetRing = False
1028        self.setPoly = False
1029        arg = sys.argv
1030        if len(arg) > 1:
1031            self.GSASprojectfile = arg[1]
1032            self.dirname = os.path.dirname(arg[1])
1033            if self.dirname: os.chdir(self.dirname)
1034            G2IO.ProjFileOpen(self)
1035            self.PatternTree.Expand(self.root)
1036            for item in self.Refine: item.Enable(True)
1037            for item in self.SeqRefine: item.Enable(True)
1038
1039    def OnSize(self,event):
1040        w,h = self.GetClientSizeTuple()
1041        self.mainPanel.SetSize(wx.Size(w,h))
1042        self.PatternTree.SetSize(wx.Size(w,h))
1043                       
1044    def OnPatternTreeSelChanged(self, event):
1045        if self.TreeItemDelete:
1046            self.TreeItemDelete = False
1047        else:
1048            pltNum = self.G2plotNB.nb.GetSelection()
1049            if pltNum >= 0:                         #to avoid the startup with no plot!
1050                pltPage = self.G2plotNB.nb.GetPage(pltNum)
1051                pltPlot = pltPage.figure
1052            item = event.GetItem()
1053            G2gd.MovePatternTreeToGrid(self,item)
1054            if self.oldFocus:
1055                self.oldFocus.SetFocus()
1056       
1057    def OnPatternTreeItemCollapsed(self, event):
1058        event.Skip()
1059
1060    def OnPatternTreeItemExpanded(self, event):
1061        event.Skip()
1062       
1063    def OnPatternTreeItemDelete(self, event):
1064        self.TreeItemDelete = True
1065
1066    def OnPatternTreeItemActivated(self, event):
1067        event.Skip()
1068       
1069    def OnPatternTreeKeyDown(self,event):
1070        key = event.GetKeyCode()
1071        item = self.PickId
1072        if type(item) is int: return # is this the toplevel in tree?
1073        if key == wx.WXK_UP:
1074            self.oldFocus = wx.Window.FindFocus()
1075            self.PatternTree.GetPrevSibling(item)
1076        elif key == wx.WXK_DOWN:
1077            self.oldFocus = wx.Window.FindFocus()
1078            self.PatternTree.GetNextSibling(item)
1079               
1080    def OnReadPowderPeaks(self,event):
1081        Cuka = 1.54052
1082        self.CheckNotebook()
1083        dlg = wx.FileDialog(self, 'Choose file with peak list', '.', '', 
1084            'peak files (*.txt)|*.txt|All files (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
1085        try:
1086            if dlg.ShowModal() == wx.ID_OK:
1087                self.HKL = []
1088                self.powderfile = dlg.GetPath()
1089                comments,peaks = G2IO.GetPowderPeaks(self.powderfile)
1090                Id = self.PatternTree.AppendItem(parent=self.root,text='PKS '+os.path.basename(self.powderfile))
1091                data = ['PKS',Cuka,0.0]
1092                names = ['Type','Lam','Zero'] 
1093                codes = [0,0]
1094                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),[tuple(data),data,codes,names])
1095                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),comments)
1096                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),peaks)
1097                self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
1098                self.PatternTree.Expand(Id)
1099                self.PatternTree.SelectItem(Id)
1100                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1101        finally:
1102            dlg.Destroy()
1103           
1104    def OnImageRead(self,event):
1105        self.CheckNotebook()
1106        dlg = wx.FileDialog(
1107            self, 'Choose image files', '.', '',
1108            'Any image file (*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img;*.G2img)|'
1109            '*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img;*.G2img;*.zip|'
1110            'Any detector tif (*.tif;*.tiff)|*.tif;*.tiff|'
1111            'MAR file (*.mar*)|*.mar*|'
1112            'GE Image (*.avg;*.sum)|*.avg;*.sum|'
1113            'ADSC Image (*.img)|*.img|'
1114            'GSAS-II Image (*.G2img)|*.G2img|'
1115            'Zip archive (*.zip)|*.zip|'
1116            'All files (*.*)|*.*',
1117            wx.OPEN | wx.MULTIPLE|wx.CHANGE_DIR)
1118        try:
1119            if dlg.ShowModal() == wx.ID_OK:
1120                imagefiles = dlg.GetPaths()
1121                imagefiles.sort()
1122                for imagefile in imagefiles:
1123                    # if a zip file, open and extract
1124                    if os.path.splitext(imagefile)[1].lower() == '.zip':
1125                        extractedfile = G2IO.ExtractFileFromZip(imagefile,parent=self)
1126                        if extractedfile is not None and extractedfile != imagefile:
1127                            imagefile = extractedfile
1128                    Comments,Data,Npix,Image = G2IO.GetImageData(self,imagefile)
1129                    if Comments:
1130                        Id = self.PatternTree.AppendItem(parent=self.root,text='IMG '+os.path.basename(imagefile))
1131                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
1132                        Imax = np.amax(Image)
1133                        Imin = max(0.0,np.amin(Image))          #force positive
1134                        if self.imageDefault:
1135                            Data = copy.copy(self.imageDefault)
1136                            Data['showLines'] = True
1137                            Data['ring'] = []
1138                            Data['rings'] = []
1139                            Data['cutoff'] = 10
1140                            Data['pixLimit'] = 20
1141                            Data['edgemin'] = 100000000
1142                            Data['calibdmin'] = 0.5
1143                            Data['calibskip'] = 0
1144                            Data['ellipses'] = []
1145                            Data['calibrant'] = ''
1146                        else:
1147                            Data['type'] = 'PWDR'
1148                            Data['color'] = 'Paired'
1149                            Data['tilt'] = 0.0
1150                            Data['rotation'] = 0.0
1151                            Data['showLines'] = False
1152                            Data['ring'] = []
1153                            Data['rings'] = []
1154                            Data['cutoff'] = 10
1155                            Data['pixLimit'] = 20
1156                            Data['calibdmin'] = 0.5
1157                            Data['calibskip'] = 0
1158                            Data['edgemin'] = 100000000
1159                            Data['ellipses'] = []
1160                            Data['calibrant'] = ''
1161                            Data['IOtth'] = [2.0,5.0]
1162                            Data['LRazimuth'] = [135,225]
1163                            Data['azmthOff'] = 0.0
1164                            Data['outChannels'] = 2500
1165                            Data['outAzimuths'] = 1
1166                            Data['centerAzm'] = False
1167                            Data['fullIntegrate'] = False
1168                            Data['setRings'] = False
1169                            Data['background image'] = ['',1.0]                           
1170                        Data['setDefault'] = False
1171                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
1172                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)
1173                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
1174                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
1175                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),
1176                            {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'strain':np.zeros((3,3))})
1177                        self.PatternTree.SetItemPyData(Id,[Npix,imagefile])
1178                        self.PickId = Id
1179                        self.Image = Id
1180                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1181                self.PatternTree.SelectItem(G2gd.GetPatternTreeItemId(self,Id,'Image Controls'))             #show last one
1182        finally:
1183            path = dlg.GetDirectory()           # to get Mac/Linux to change directory!
1184            os.chdir(path)
1185            dlg.Destroy()
1186
1187    def CheckNotebook(self):
1188        '''Make sure the data tree has the minimally expected controls
1189        (BHT) correct?
1190        '''
1191        if not G2gd.GetPatternTreeItemId(self,self.root,'Notebook'):
1192            sub = self.PatternTree.AppendItem(parent=self.root,text='Notebook')
1193            self.PatternTree.SetItemPyData(sub,[''])
1194        if not G2gd.GetPatternTreeItemId(self,self.root,'Controls'):
1195            sub = self.PatternTree.AppendItem(parent=self.root,text='Controls')
1196            self.PatternTree.SetItemPyData(sub,{})
1197        if not G2gd.GetPatternTreeItemId(self,self.root,'Covariance'):
1198            sub = self.PatternTree.AppendItem(parent=self.root,text='Covariance')
1199            self.PatternTree.SetItemPyData(sub,{})
1200        if not G2gd.GetPatternTreeItemId(self,self.root,'Constraints'):
1201            sub = self.PatternTree.AppendItem(parent=self.root,text='Constraints')
1202            self.PatternTree.SetItemPyData(sub,{'Hist':[],'HAP':[],'Phase':[]})
1203        if not G2gd.GetPatternTreeItemId(self,self.root,'Restraints'):
1204            sub = self.PatternTree.AppendItem(parent=self.root,text='Restraints')
1205            self.PatternTree.SetItemPyData(sub,{})
1206           
1207               
1208    class CopyDialog(wx.Dialog):
1209        def __init__(self,parent,title,text,data):
1210            wx.Dialog.__init__(self,parent,-1,title, 
1211                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1212            self.data = data
1213            panel = wx.Panel(self)
1214            mainSizer = wx.BoxSizer(wx.VERTICAL)
1215            topLabl = wx.StaticText(panel,-1,text)
1216            mainSizer.Add((10,10),1)
1217            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1218            mainSizer.Add((10,10),1)
1219            ncols = len(data)/40+1
1220            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=ncols,hgap=2,vgap=2)
1221            for id,item in enumerate(self.data):
1222                ckbox = wx.CheckBox(panel,id,item[1])
1223                ckbox.Bind(wx.EVT_CHECKBOX,self.OnCopyChange)                   
1224                dataGridSizer.Add(ckbox,0,wx.LEFT,10)
1225            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1226            OkBtn = wx.Button(panel,-1,"Ok")
1227            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1228            cancelBtn = wx.Button(panel,-1,"Cancel")
1229            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1230            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1231            btnSizer.Add((20,20),1)
1232            btnSizer.Add(OkBtn)
1233            btnSizer.Add((20,20),1)
1234            btnSizer.Add(cancelBtn)
1235            btnSizer.Add((20,20),1)
1236           
1237            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1238            panel.SetSizer(mainSizer)
1239            panel.Fit()
1240            self.Fit()
1241       
1242        def OnCopyChange(self,event):
1243            id = event.GetId()
1244            self.data[id][0] = self.FindWindowById(id).GetValue()       
1245           
1246        def OnOk(self,event):
1247            parent = self.GetParent()
1248            parent.Raise()
1249            self.EndModal(wx.ID_OK)             
1250           
1251        def OnCancel(self,event):
1252            parent = self.GetParent()
1253            parent.Raise()
1254            self.EndModal(wx.ID_CANCEL)             
1255           
1256        def GetData(self):
1257            return self.data
1258       
1259    class SumDialog(wx.Dialog):
1260        def __init__(self,parent,title,text,dataType,data):
1261            wx.Dialog.__init__(self,parent,-1,title, 
1262                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1263            self.data = data
1264            panel = wx.Panel(self)
1265            mainSizer = wx.BoxSizer(wx.VERTICAL)
1266            topLabl = wx.StaticText(panel,-1,text)
1267            mainSizer.Add((10,10),1)
1268            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1269            mainSizer.Add((10,10),1)
1270            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=2,hgap=2,vgap=2)
1271            for id,item in enumerate(self.data[:-1]):
1272                name = wx.TextCtrl(panel,-1,item[1],size=wx.Size(200,20))
1273                name.SetEditable(False)
1274                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
1275                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
1276                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
1277                dataGridSizer.Add(scale,0,wx.LEFT,10)
1278                dataGridSizer.Add(name,0,wx.RIGHT,10)
1279            if dataType:
1280                dataGridSizer.Add(wx.StaticText(panel,-1,'Sum result name: '+dataType),0, \
1281                    wx.LEFT|wx.TOP|wx.ALIGN_CENTER_VERTICAL,10)
1282                self.name = wx.TextCtrl(panel,-1,self.data[-1],size=wx.Size(200,20),style=wx.TE_PROCESS_ENTER)
1283                self.name.Bind(wx.EVT_TEXT_ENTER,self.OnNameChange)
1284                self.name.Bind(wx.EVT_KILL_FOCUS,self.OnNameChange)
1285                dataGridSizer.Add(self.name,0,wx.RIGHT|wx.TOP,10)
1286            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1287            OkBtn = wx.Button(panel,-1,"Ok")
1288            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1289            cancelBtn = wx.Button(panel,-1,"Cancel")
1290            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1291            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1292            btnSizer.Add((20,20),1)
1293            btnSizer.Add(OkBtn)
1294            btnSizer.Add((20,20),1)
1295            btnSizer.Add(cancelBtn)
1296            btnSizer.Add((20,20),1)
1297           
1298            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1299            panel.SetSizer(mainSizer)
1300            panel.Fit()
1301            self.Fit()
1302
1303        def OnScaleChange(self,event):
1304            id = event.GetId()
1305            value = self.FindWindowById(id).GetValue()
1306            try:
1307                self.data[id][0] = float(value)
1308                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
1309            except ValueError:
1310                if value and '-' not in value[0]:
1311                    print 'bad input - numbers only'
1312                    self.FindWindowById(id).SetValue('0.000')
1313           
1314        def OnNameChange(self,event):
1315            self.data[-1] = self.name.GetValue() 
1316           
1317        def OnOk(self,event):
1318            parent = self.GetParent()
1319            parent.Raise()
1320            self.EndModal(wx.ID_OK)             
1321           
1322        def OnCancel(self,event):
1323            parent = self.GetParent()
1324            parent.Raise()
1325            self.EndModal(wx.ID_CANCEL)             
1326           
1327        def GetData(self):
1328            return self.data
1329           
1330    class ConstraintDialog(wx.Dialog):
1331        '''Window to edit Constraint values
1332        '''
1333        def __init__(self,parent,title,text,data,separator='*'):
1334            wx.Dialog.__init__(self,parent,-1,title, 
1335                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1336            self.data = data
1337            panel = wx.Panel(self)
1338            mainSizer = wx.BoxSizer(wx.VERTICAL)
1339            topLabl = wx.StaticText(panel,-1,text)
1340            mainSizer.Add((10,10),1)
1341            mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
1342            mainSizer.Add((10,10),1)
1343            dataGridSizer = wx.FlexGridSizer(rows=len(data),cols=2,hgap=2,vgap=2)
1344            for id,item in enumerate(self.data[:-1]):
1345                lbl = item[1]
1346                if lbl[-1] != '=': lbl += ' ' + separator + ' '
1347                name = wx.StaticText(panel,-1,lbl,size=wx.Size(200,20),
1348                                     style=wx.ALIGN_RIGHT)
1349                scale = wx.TextCtrl(panel,id,'%.3f'%(item[0]),style=wx.TE_PROCESS_ENTER)
1350                scale.Bind(wx.EVT_TEXT_ENTER,self.OnScaleChange)
1351                scale.Bind(wx.EVT_KILL_FOCUS,self.OnScaleChange)
1352                dataGridSizer.Add(name,0,wx.LEFT,10)
1353                dataGridSizer.Add(scale,0,wx.RIGHT,10)
1354            mainSizer.Add(dataGridSizer,0,wx.EXPAND)
1355            OkBtn = wx.Button(panel,-1,"Ok")
1356            OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1357            cancelBtn = wx.Button(panel,-1,"Cancel")
1358            cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1359            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1360            btnSizer.Add((20,20),1)
1361            btnSizer.Add(OkBtn)
1362            btnSizer.Add((20,20),1)
1363            btnSizer.Add(cancelBtn)
1364            btnSizer.Add((20,20),1)
1365           
1366            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1367            panel.SetSizer(mainSizer)
1368            panel.Fit()
1369            self.Fit()
1370            self.CenterOnParent()
1371           
1372        def OnNameChange(self,event):
1373            self.data[-1] = self.name.GetValue() 
1374           
1375        def OnScaleChange(self,event):
1376            id = event.GetId()
1377            value = self.FindWindowById(id).GetValue()
1378            try:
1379                self.data[id][0] = float(value)
1380                self.FindWindowById(id).SetValue('%.3f'%(self.data[id][0]))
1381            except ValueError:
1382                if value and '-' not in value[0]:
1383                    print 'bad input - numbers only'
1384                    self.FindWindowById(id).SetValue('0.000')
1385           
1386        def OnOk(self,event):
1387            parent = self.GetParent()
1388            parent.Raise()
1389            self.EndModal(wx.ID_OK)             
1390           
1391        def OnCancel(self,event):
1392            parent = self.GetParent()
1393            parent.Raise()
1394            self.EndModal(wx.ID_CANCEL)             
1395           
1396        def GetData(self):
1397            return self.data
1398           
1399    def OnPwdrSum(self,event):
1400        TextList = []
1401        DataList = []
1402        SumList = []
1403        Names = []
1404        Inst = []
1405        SumItemList = []
1406        Comments = ['Sum equals: \n']
1407        if self.PatternTree.GetCount():
1408            item, cookie = self.PatternTree.GetFirstChild(self.root)
1409            while item:
1410                name = self.PatternTree.GetItemText(item)
1411                Names.append(name)
1412                if 'PWDR' in name:
1413                    TextList.append([0.0,name])
1414                    DataList.append(self.PatternTree.GetItemPyData(item)[1])    # (x,y,w,yc,yb,yd)
1415                    if not Inst:
1416                        Inst = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item, 'Instrument Parameters'))
1417                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1418            if len(TextList) < 2:
1419                self.ErrorDialog('Not enough data to sum','There must be more than one "PWDR" pattern')
1420                return
1421            TextList.append('default_sum_name')               
1422            dlg = self.SumDialog(self,'Sum data','Enter scale for each pattern in summation','PWDR',TextList)
1423            try:
1424                if dlg.ShowModal() == wx.ID_OK:
1425                    lenX = 0
1426                    Xminmax = [0,0]
1427                    Xsum = []
1428                    Ysum = []
1429                    Vsum = []
1430                    result = dlg.GetData()
1431                    for i,item in enumerate(result[:-1]):
1432                        scale,name = item
1433                        data = DataList[i]
1434                        if scale:
1435                            Comments.append("%10.3f %s" % (scale,' * '+name))
1436                            x,y,w,yc,yb,yd = data   #numpy arrays!
1437                            v = 1./w
1438                            if lenX:
1439                                if lenX != len(x):
1440                                    self.ErrorDialog('Data length error','Data to be summed must have same number of points'+ \
1441                                        '\nExpected:'+str(lenX)+ \
1442                                        '\nFound:   '+str(len(x))+'\nfor '+name)
1443                                    return
1444                            else:
1445                                lenX = len(x)
1446                            if Xminmax[1]:
1447                                if Xminmax != [x[0],x[-1]]:
1448                                    self.ErrorDialog('Data range error','Data to be summed must span same range'+ \
1449                                        '\nExpected:'+str(Xminmax[0])+' '+str(Xminmax[1])+ \
1450                                        '\nFound:   '+str(x[0])+' '+str(x[-1])+'\nfor '+name)
1451                                    return
1452                                else:
1453                                    for j,yi in enumerate(y):
1454                                         Ysum[j] += scale*yi
1455                                         Vsum[j] += abs(scale)*v[j]
1456                            else:
1457                                Xminmax = [x[0],x[-1]]
1458                                YCsum = YBsum = YDsum = [0.0 for i in range(lenX)]
1459                                for j,yi in enumerate(y):
1460                                    Xsum.append(x[j])
1461                                    Ysum.append(scale*yi)
1462                                    Vsum.append(abs(scale*v[j]))
1463                    Wsum = 1./np.array(Vsum)
1464                    outname = 'PWDR '+result[-1]
1465                    Id = 0
1466                    if outname in Names:
1467                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
1468                        try:
1469                            if dlg2.ShowModal() == wx.ID_OK:
1470                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
1471                                self.PatternTree.Delete(Id)
1472                        finally:
1473                            dlg2.Destroy()
1474                    Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
1475                    if Id:
1476                        Sample = G2pdG.SetDefaultSample()
1477                        self.PatternTree.SetItemPyData(Id,[{'wtFactor':1.0},[np.array(Xsum),np.array(Ysum),np.array(Wsum),
1478                            np.array(YCsum),np.array(YBsum),np.array(YDsum)]])
1479                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
1480                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
1481                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',True,3,1.0,0.0,0.0],
1482                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
1483                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Instrument Parameters'),Inst)
1484                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
1485                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Peak List'),[])
1486                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Index Peak List'),[])
1487                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Unit Cells List'),[])             
1488                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
1489                        self.PatternTree.SelectItem(Id)
1490                        self.PatternTree.Expand(Id)
1491                   
1492            finally:
1493                dlg.Destroy()
1494
1495    def OnImageSum(self,event):
1496        TextList = []
1497        DataList = []
1498        SumList = []
1499        Names = []
1500        Inst = []
1501        SumItemList = []
1502        Comments = ['Sum equals: \n']
1503        if self.PatternTree.GetCount():
1504            item, cookie = self.PatternTree.GetFirstChild(self.root)
1505            while item:
1506                name = self.PatternTree.GetItemText(item)
1507                Names.append(name)
1508                if 'IMG' in name:
1509                    TextList.append([0.0,name])
1510                    DataList.append(self.PatternTree.GetItemPyData(item))        #Size,Image
1511                    Data = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,item,'Image Controls'))
1512                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1513            if len(TextList) < 2:
1514                self.ErrorDialog('Not enough data to sum','There must be more than one "IMG" pattern')
1515                return
1516            TextList.append('default_sum_name')               
1517            dlg = self.SumDialog(self,'Sum data','Enter scale for each image in summation','IMG',TextList)
1518            try:
1519                if dlg.ShowModal() == wx.ID_OK:
1520                    imSize = 0
1521                    result = dlg.GetData()
1522                    First = True
1523                    Found = False
1524                    for i,item in enumerate(result[:-1]):
1525                        scale,name = item
1526                        data = DataList[i]
1527                        if scale:
1528                            Found = True                               
1529                            Comments.append("%10.3f %s" % (scale,' * '+name))
1530                            Npix,imagefile = data
1531                            image = G2IO.GetImageData(self,imagefile,imageOnly=True)
1532                            if First:
1533                                newImage = np.zeros_like(image)
1534                                First = False
1535                            if imSize:
1536                                if imSize != Npix:
1537                                    self.ErrorDialog('Image size error','Images to be summed must be same size'+ \
1538                                        '\nExpected:'+str(imSize)+ \
1539                                        '\nFound:   '+str(Npix)+'\nfor '+name)
1540                                    return
1541                                newImage = newImage+scale*image
1542                            else:
1543                                imSize = Npix
1544                                newImage = newImage+scale*image
1545                            del(image)
1546                    if not Found:
1547                        self.ErrorDialog('Image sum error','No nonzero image multipliers found')
1548                        return
1549                       
1550                    newImage = np.asfarray(newImage,dtype=np.float32)                       
1551                    outname = 'IMG '+result[-1]
1552                    Id = 0
1553                    if outname in Names:
1554                        dlg2 = wx.MessageDialog(self,'Overwrite data?','Duplicate data name',wx.OK|wx.CANCEL)
1555                        try:
1556                            if dlg2.ShowModal() == wx.ID_OK:
1557                                Id = G2gd.GetPatternTreeItemId(self,self.root,name)
1558                        finally:
1559                            dlg2.Destroy()
1560                    else:
1561                        Id = self.PatternTree.AppendItem(parent=self.root,text=outname)
1562                    if Id:
1563                        dlg = wx.FileDialog(self, 'Choose sum image filename', '.', '', 
1564                            'G2img files (*.G2img)|*.G2img', 
1565                            wx.SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1566                        if dlg.ShowModal() == wx.ID_OK:
1567                            newimagefile = dlg.GetPath()
1568                            newimagefile = G2IO.FileDlgFixExt(dlg,newimagefile)
1569                            G2IO.PutG2Image(newimagefile,Comments,Data,Npix,newImage)
1570                            Imax = np.amax(newImage)
1571                            Imin = np.amin(newImage)
1572                            newImage = []
1573                            self.PatternTree.SetItemPyData(Id,[imSize,newimagefile])
1574                            self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Comments'),Comments)
1575                        del(newImage)
1576                        if self.imageDefault:
1577                            Data = copy.copy(self.imageDefault)
1578                        Data['showLines'] = True
1579                        Data['ring'] = []
1580                        Data['rings'] = []
1581                        Data['cutoff'] = 10
1582                        Data['pixLimit'] = 20
1583                        Data['ellipses'] = []
1584                        Data['calibrant'] = ''
1585                        Data['range'] = [(Imin,Imax),[Imin,Imax]]
1586                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Image Controls'),Data)                                           
1587                        Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
1588                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Masks'),Masks)
1589                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='Stress/Strain'),{})
1590                        self.PatternTree.SelectItem(Id)
1591                        self.PatternTree.Expand(Id)
1592                        self.PickId = G2gd.GetPatternTreeItemId(self,self.root,outname)
1593                        self.Image = self.PickId
1594            finally:
1595                dlg.Destroy()
1596                     
1597    def OnAddPhase(self,event):
1598        if not G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
1599            sub = self.PatternTree.AppendItem(parent=self.root,text='Phases')
1600        else:
1601            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1602        PhaseName = ''
1603        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
1604            style=wx.OK)
1605        if dlg.ShowModal() == wx.ID_OK:
1606            PhaseName = dlg.GetValue()
1607        dlg.Destroy()
1608        sub = self.PatternTree.AppendItem(parent=sub,text=PhaseName)
1609        E,SGData = G2spc.SpcGroup('P 1')
1610        self.PatternTree.SetItemPyData(sub,G2IO.SetNewPhase(Name=PhaseName,SGData=SGData))
1611       
1612    def OnDeletePhase(self,event):
1613        #Hmm, also need to delete this phase from Reflection Lists for each PWDR histogram
1614        if self.dataFrame:
1615            self.dataFrame.Clear() 
1616        TextList = []
1617        DelList = []
1618        DelItemList = []
1619        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
1620            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
1621        else:
1622            return
1623        if sub:
1624            item, cookie = self.PatternTree.GetFirstChild(sub)
1625            while item:
1626                TextList.append(self.PatternTree.GetItemText(item))
1627                item, cookie = self.PatternTree.GetNextChild(sub, cookie)               
1628            dlg = wx.MultiChoiceDialog(self, 'Which phase to delete?', 'Delete phase', TextList, wx.CHOICEDLG_STYLE)
1629            try:
1630                if dlg.ShowModal() == wx.ID_OK:
1631                    result = dlg.GetSelections()
1632                    for i in result: DelList.append([i,TextList[i]])
1633                    item, cookie = self.PatternTree.GetFirstChild(sub)
1634                    i = 0
1635                    while item:
1636                        if [i,self.PatternTree.GetItemText(item)] in DelList: DelItemList.append(item)
1637                        item, cookie = self.PatternTree.GetNextChild(sub, cookie)
1638                        i += 1
1639                    for item in DelItemList:
1640                        name = self.PatternTree.GetItemText(item)
1641                        self.PatternTree.Delete(item)
1642                        self.G2plotNB.Delete(name)
1643                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1644                    while item:
1645                        name = self.PatternTree.GetItemText(item)
1646                        if 'PWDR' in name:
1647                            Id = G2gd.GetPatternTreeItemId(self,item, 'Reflection Lists')
1648                            refList = self.PatternTree.GetItemPyData(Id)
1649                            for i,item in DelList:
1650                                del(refList[item])
1651                            self.PatternTree.SetItemPyData(Id,refList)
1652                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1653            finally:
1654                dlg.Destroy()
1655               
1656    def OnRenameData(self,event):
1657        name = self.PatternTree.GetItemText(self.PickId)     
1658        if 'PWDR' in name or 'HKLF' in name or 'IMG' in name:
1659            dataType = name[:name.index(' ')+1]                 #includes the ' '
1660            dlg = wx.TextEntryDialog(self,'Data name: '+dataType,'Change data name',
1661                defaultValue=name[name.index(' ')+1:])
1662            try:
1663                if dlg.ShowModal() == wx.ID_OK:
1664                    self.PatternTree.SetItemText(self.PickId,dataType+dlg.GetValue())
1665            finally:
1666                dlg.Destroy()
1667       
1668    def GetFileList(self,fileType,skip=None):        #potentially useful?
1669        fileList = []
1670        Source = ''
1671        id, cookie = self.PatternTree.GetFirstChild(self.root)
1672        while id:
1673            name = self.PatternTree.GetItemText(id)
1674            if fileType in name:
1675                if id == skip:
1676                    Source = name
1677                else:
1678                    fileList.append([False,name,id])
1679            id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1680        if skip:
1681            return fileList,Source
1682        else:
1683            return fileList
1684           
1685    def OnDataDelete(self, event):
1686        TextList = ['All Data']
1687        DelList = []
1688        DelItemList = []
1689        ifPWDR = False
1690        ifIMG = False
1691        ifHKLF = False
1692        ifPDF = False
1693        if self.PatternTree.GetCount():
1694            item, cookie = self.PatternTree.GetFirstChild(self.root)
1695            while item:
1696                name = self.PatternTree.GetItemText(item)
1697                if name not in ['Notebook','Controls','Covariance','Constraints','Restraints','Phases']:
1698                    if 'PWDR' in name: ifPWDR = True
1699                    if 'IMG' in name: ifIMG = True
1700                    if 'HKLF' in name: ifHKLF = True
1701                    if 'PDF' in name: ifPDF = True
1702                    TextList.append(name)
1703                item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1704            if ifPWDR: TextList.insert(1,'All PWDR')
1705            if ifIMG: TextList.insert(1,'All IMG')
1706            if ifHKLF: TextList.insert(1,'All HKLF')
1707            if ifPDF: TextList.insert(1,'All PDF')               
1708            dlg = wx.MultiChoiceDialog(self, 'Which data to delete?', 'Delete data', TextList, wx.CHOICEDLG_STYLE)
1709            try:
1710                if dlg.ShowModal() == wx.ID_OK:
1711                    result = dlg.GetSelections()
1712                    for i in result: DelList.append(TextList[i])
1713                    if 'All Data' in DelList:
1714                        DelList = [item for item in TextList if item[:3] != 'All']
1715                    elif 'All PWDR' in DelList:
1716                        DelList = [item for item in TextList if item[:4] == 'PWDR']
1717                    elif 'All IMG' in DelList:
1718                        DelList = [item for item in TextList if item[:3] == 'IMG']
1719                    elif 'All HKLF' in DelList:
1720                        DelList = [item for item in TextList if item[:4] == 'HKLF']
1721                    elif 'All PDF' in DelList:
1722                        DelList = [item for item in TextList if item[:3] == 'PDF']
1723                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1724                    while item:
1725                        if self.PatternTree.GetItemText(item) in DelList: DelItemList.append(item)
1726                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1727                    for item in DelItemList:
1728                        self.PatternTree.Delete(item)
1729                    self.PickId = 0
1730                    wx.CallAfter(G2plt.PlotPatterns,self,True)                        #so plot gets updated
1731            finally:
1732                dlg.Destroy()
1733
1734    def OnFileOpen(self, event):
1735        result = ''
1736        Id = 0
1737        if self.PatternTree.GetChildrenCount(self.root,False):
1738            if self.dataFrame:
1739                self.dataFrame.Clear() 
1740            dlg = wx.MessageDialog(
1741                self,
1742                'Do you want to overwrite the current project? '
1743                'Any unsaved changes will be lost. Press OK to continue.',
1744                'Overwrite?',  wx.OK | wx.CANCEL)
1745            try:
1746                result = dlg.ShowModal()
1747                if result == wx.ID_OK:
1748                    self.PatternTree.DeleteChildren(self.root)
1749                    self.GSASprojectfile = ''
1750                    if self.HKL: self.HKL = []
1751                    if self.G2plotNB.plotList:
1752                        self.G2plotNB.clear()
1753            finally:
1754                dlg.Destroy()
1755        if result != wx.ID_CANCEL:   
1756            if self.dataDisplay: self.dataDisplay.Destroy()
1757            dlg = wx.FileDialog(self, 'Choose GSAS-II project file', '.', '', 
1758                'GSAS-II project file (*.gpx)|*.gpx',wx.OPEN|wx.CHANGE_DIR)
1759            try:
1760                if dlg.ShowModal() == wx.ID_OK:
1761                    self.GSASprojectfile = dlg.GetPath()
1762                    self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
1763                    self.dirname = dlg.GetDirectory()
1764                    G2IO.ProjFileOpen(self)
1765                    self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
1766                    self.PatternTree.Expand(self.root)
1767                    self.HKL = []
1768                    item, cookie = self.PatternTree.GetFirstChild(self.root)
1769                    while item and not Id:
1770                        name = self.PatternTree.GetItemText(item)
1771                        if name[:4] in ['PWDR','HKLF','IMG ','PDF ']:
1772                            Id = item
1773                        elif name == 'Controls':
1774                            data = self.PatternTree.GetItemPyData(item)
1775                            if data:
1776                                for item in self.Refine: item.Enable(True)
1777                                for item in self.SeqRefine: item.Enable(True)
1778                        item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
1779                    if Id:
1780                        self.PatternTree.SelectItem(Id)
1781                    self.CheckNotebook()
1782                    os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1783            finally:
1784                dlg.Destroy()
1785
1786    def OnFileClose(self, event):
1787        if self.dataFrame:
1788            self.dataFrame.Clear()
1789            self.dataFrame.SetLabel('GSAS-II data display') 
1790        dlg = wx.MessageDialog(self, 'Save current project?', ' ', wx.YES | wx.NO | wx.CANCEL)
1791        try:
1792            result = dlg.ShowModal()
1793            if result == wx.ID_OK:
1794                self.OnFileSaveMenu(event)
1795            if result != wx.ID_CANCEL:
1796                self.GSASprojectfile = ''
1797                self.PatternTree.SetItemText(self.root,'Loaded Data: ')
1798                self.PatternTree.DeleteChildren(self.root)
1799                if self.HKL: self.HKL = []
1800                if self.G2plotNB.plotList:
1801                    self.G2plotNB.clear()
1802        finally:
1803            dlg.Destroy()
1804
1805    def OnFileSave(self, event):
1806        if self.GSASprojectfile: 
1807            self.PatternTree.SetItemText(self.root,'Loaded Data: '+self.GSASprojectfile)
1808            G2IO.ProjFileSave(self)
1809        else:
1810            self.OnFileSaveas(event)
1811
1812    def OnFileSaveas(self, event):
1813        dlg = wx.FileDialog(self, 'Choose GSAS-II project file name', '.', '', 
1814            'GSAS-II project file (*.gpx)|*.gpx',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1815        try:
1816            if dlg.ShowModal() == wx.ID_OK:
1817                self.GSASprojectfile = dlg.GetPath()
1818                self.GSASprojectfile = G2IO.FileDlgFixExt(dlg,self.GSASprojectfile)
1819                self.PatternTree.SetItemText(self.root,'Saving project as'+self.GSASprojectfile)
1820                self.SetTitle("GSAS-II data tree: "+
1821                              os.path.split(self.GSASprojectfile)[1])
1822                G2IO.ProjFileSave(self)
1823                os.chdir(dlg.GetDirectory())           # to get Mac/Linux to change directory!
1824        finally:
1825            dlg.Destroy()
1826
1827    def ExitMain(self, event):
1828        if self.undofile:
1829            os.remove(self.undofile)
1830        sys.exit()
1831       
1832    def OnFileExit(self, event):
1833        if self.dataFrame:
1834            self.dataFrame.Clear() 
1835            self.dataFrame.Destroy()
1836        self.Close()
1837       
1838    def OnExportPatterns(self,event):
1839        names = ['All']
1840        exports = []
1841        item, cookie = self.PatternTree.GetFirstChild(self.root)
1842        while item:
1843            name = self.PatternTree.GetItemText(item)
1844            if 'PWDR' in name:
1845                names.append(name)
1846            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1847        if names:
1848            dlg = wx.MultiChoiceDialog(self,'Select','Powder patterns to export',names)
1849            if dlg.ShowModal() == wx.ID_OK:
1850                sel = dlg.GetSelections()
1851                if sel[0] == 0:
1852                    exports = names[1:]
1853                else:
1854                    for x in sel:
1855                        exports.append(names[x])
1856            dlg.Destroy()
1857        if exports:
1858            dlg = wx.FileDialog(self, 'Choose output powder file name', '.', '', 
1859                'GSAS fxye file (*.fxye)|*.fxye|xye file (*.xye)|*.xye',
1860                wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1861            try:
1862                if dlg.ShowModal() == wx.ID_OK:
1863                    powderfile = dlg.GetPath()
1864                    powderfile = G2IO.FileDlgFixExt(dlg,powderfile)
1865                    if 'fxye' in powderfile:
1866                        G2IO.powderFxyeSave(self,exports,powderfile)
1867                    else:       #just xye
1868                        G2IO.powderXyeSave(self,exports,powderfile)
1869            finally:
1870                dlg.Destroy()
1871       
1872    def OnExportPeakList(self,event):
1873        dlg = wx.FileDialog(self, 'Choose output peak list file name', '.', '', 
1874            '(*.*)|*.*',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1875        try:
1876            if dlg.ShowModal() == wx.ID_OK:
1877                self.peaklistfile = dlg.GetPath()
1878                self.peaklistfile = G2IO.FileDlgFixExt(dlg,self.peaklistfile)
1879                file = open(self.peaklistfile,'w')               
1880                item, cookie = self.PatternTree.GetFirstChild(self.root)
1881                while item:
1882                    name = self.PatternTree.GetItemText(item)
1883                    if 'PWDR' in name:
1884                        item2, cookie2 = self.PatternTree.GetFirstChild(item)
1885                        while item2:
1886                            name2 = self.PatternTree.GetItemText(item2)
1887                            if name2 == 'Peak List':
1888                                peaks = self.PatternTree.GetItemPyData(item2)
1889                                file.write("%s \n" % (name+' Peak List'))               
1890                                for peak in peaks:
1891                                    file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
1892                                        (peak[0],peak[2],peak[4],peak[6]))
1893                            item2, cookie2 = self.PatternTree.GetNextChild(item, cookie2)                           
1894                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)                           
1895                file.close()
1896        finally:
1897            dlg.Destroy()
1898       
1899    def OnExportHKL(self,event):
1900        event.Skip()
1901       
1902    def OnExportPDF(self,event):
1903        #need S(Q) and G(R) to be saved here - probably best from selection?
1904        names = ['All']
1905        exports = []
1906        item, cookie = self.PatternTree.GetFirstChild(self.root)
1907        while item:
1908            name = self.PatternTree.GetItemText(item)
1909            if 'PDF' in name:
1910                names.append(name)
1911            item, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1912        if names:
1913            dlg = wx.MultiChoiceDialog(self,'Select','PDF patterns to export',names)
1914            if dlg.ShowModal() == wx.ID_OK:
1915                sel = dlg.GetSelections()
1916                if sel[0] == 0:
1917                    exports = names[1:]
1918                else:
1919                    for x in sel:
1920                        exports.append(names[x])
1921            dlg.Destroy()
1922        if exports:
1923            G2IO.PDFSave(self,exports)
1924       
1925    def OnExportPhase(self,event):
1926        event.Skip()
1927       
1928    def OnExportCIF(self,event):
1929        event.Skip()
1930
1931    def OnMakePDFs(self,event):
1932        tth2q = lambda t,w:4.0*math.pi*sind(t/2.0)/w
1933        TextList = ['All PWDR']
1934        PDFlist = []
1935        Names = []
1936        if self.PatternTree.GetCount():
1937            id, cookie = self.PatternTree.GetFirstChild(self.root)
1938            while id:
1939                name = self.PatternTree.GetItemText(id)
1940                Names.append(name)
1941                if 'PWDR' in name:
1942                    TextList.append(name)
1943                id, cookie = self.PatternTree.GetNextChild(self.root, cookie)
1944            if len(TextList) == 1:
1945                self.ErrorDialog('Nothing to make PDFs for','There must be at least one "PWDR" pattern')
1946                return
1947            dlg = wx.MultiChoiceDialog(self,'Make PDF controls','Make PDF controls for:',TextList, wx.CHOICEDLG_STYLE)
1948            try:
1949                if dlg.ShowModal() == wx.ID_OK:
1950                    result = dlg.GetSelections()
1951                    for i in result: PDFlist.append(TextList[i])
1952                    if 0 in result:
1953                        PDFlist = [item for item in TextList if item[:4] == 'PWDR']                       
1954                    for item in PDFlist:
1955                        PWDRname = item[4:]
1956                        Id = self.PatternTree.AppendItem(parent=self.root,text='PDF '+PWDRname)
1957                        Data = {
1958                            'Sample':{'Name':item,'Mult':1.0,'Add':0.0},
1959                            'Sample Bkg.':{'Name':'','Mult':-1.0,'Add':0.0},
1960                            'Container':{'Name':'','Mult':-1.0,'Add':0.0},
1961                            'Container Bkg.':{'Name':'','Mult':-1.0,'Add':0.0},'ElList':{},
1962                            'Geometry':'Cylinder','Diam':1.0,'Pack':0.50,'Form Vol':10.0,
1963                            'DetType':'Image plate','ObliqCoeff':0.2,'Ruland':0.025,'QScaleLim':[0,100],
1964                            'Lorch':True,}
1965                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='PDF Controls'),Data)
1966                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='I(Q)'+PWDRname),[])       
1967                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='S(Q)'+PWDRname),[])       
1968                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='F(Q)'+PWDRname),[])       
1969                        self.PatternTree.SetItemPyData(self.PatternTree.AppendItem(Id,text='G(R)'+PWDRname),[])       
1970                for item in self.ExportPDF: item.Enable(True)
1971            finally:
1972                dlg.Destroy()
1973               
1974    def GetPWDRdatafromTree(self,PWDRname):
1975        ''' Returns powder data from GSASII tree
1976        input:
1977            PWDRname = powder histogram name as obtained from GetHistogramNames
1978        return:
1979            PWDRdata = powder data dictionary with:
1980                Data - powder data arrays, Limits, Instrument Parameters, Sample Parameters           
1981        '''
1982        PWDRdata = {}
1983        try:
1984            PWDRdata.update(self.PatternTree.GetItemPyData(PWDRname)[0])            #wtFactor + ?
1985        except ValueError:
1986            PWDRdata['wtFactor'] = 1.0
1987        PWDRdata['Data'] = self.PatternTree.GetItemPyData(PWDRname)[1]          #powder data arrays
1988        PWDRdata['Limits'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Limits'))
1989        PWDRdata['Background'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Background'))
1990        PWDRdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Instrument Parameters'))
1991        PWDRdata['Sample Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Sample Parameters'))
1992        PWDRdata['Reflection Lists'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,PWDRname,'Reflection Lists'))
1993        if 'ranId' not in PWDRdata['Sample Parameters']:
1994            PWDRdata['Sample Parameters']['ranId'] = ran.randint(0,sys.maxint)
1995        PWDRdata['ranId'] = PWDRdata['Sample Parameters']['ranId']
1996        return PWDRdata
1997
1998    def GetHKLFdatafromTree(self,HKLFname):
1999        ''' Returns single crystal data from GSASII tree
2000        input:
2001            HKLFname = single crystal histogram name as obtained from GetHistogramNames
2002        return:
2003            HKLFdata = single crystal data list of reflections: for each reflection:
2004                HKLF =
2005        '''
2006        HKLFdata = {}
2007        try:
2008            HKLFdata.update(self.PatternTree.GetItemPyData(HKLFname)[0])            #wtFactor + ?
2009        except ValueError:
2010            HKLFdata['wtFactor'] = 1.0
2011        HKLFdata['Data'] = self.PatternTree.GetItemPyData(HKLFname)[1]
2012        HKLFdata['Instrument Parameters'] = self.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(self,HKLFname,'Instrument Parameters'))
2013        return HKLFdata
2014       
2015    def GetPhaseData(self):
2016        phaseData = {}
2017        if G2gd.GetPatternTreeItemId(self,self.root,'Phases'):
2018            sub = G2gd.GetPatternTreeItemId(self,self.root,'Phases')
2019        else:
2020            print 'no phases to be refined'
2021            return
2022        if sub:
2023            item, cookie = self.PatternTree.GetFirstChild(sub)
2024            while item:
2025                phaseName = self.PatternTree.GetItemText(item)
2026                phaseData[phaseName] =  self.PatternTree.GetItemPyData(item)
2027                if 'ranId' not in phaseData[phaseName]:
2028                    phaseData[phaseName]['ranId'] = ran.randint(0,sys.maxint)         
2029                item, cookie = self.PatternTree.GetNextChild(sub, cookie)
2030        return phaseData               
2031                   
2032    def GetUsedHistogramsAndPhasesfromTree(self):
2033        ''' Returns all histograms that are found in any phase
2034        and any phase that uses a histogram
2035        return:
2036            Histograms = dictionary of histograms as {name:data,...}
2037            Phases = dictionary of phases that use histograms
2038        '''
2039        phaseData = self.GetPhaseData()
2040        if not phaseData:
2041            return {},{}
2042        Histograms = {}
2043        Phases = {}
2044        pId = 0
2045        hId = 0
2046        for phase in phaseData:
2047            Phase = phaseData[phase]
2048            if Phase['Histograms']:
2049                if phase not in Phases:
2050                    Phase['pId'] = pId
2051                    pId += 1
2052                    Phases[phase] = Phase
2053                for hist in Phase['Histograms']:
2054                    if hist not in Histograms:
2055                        item = G2gd.GetPatternTreeItemId(self,self.root,hist)
2056                        if 'PWDR' in hist[:4]: 
2057                            Histograms[hist] = self.GetPWDRdatafromTree(item)
2058                        elif 'HKLF' in hist[:4]:
2059                            Histograms[hist] = self.GetHKLFdatafromTree(item)
2060                        #future restraint, etc. histograms here           
2061                        Histograms[hist]['hId'] = hId
2062                        hId += 1
2063        return Histograms,Phases
2064       
2065    class ViewParmDialog(wx.Dialog):
2066        def __init__(self,parent,title,parmDict):
2067            wx.Dialog.__init__(self,parent,-1,title,size=(300,430),
2068                pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
2069            panel = wx.Panel(self,size=(300,430))
2070            parmNames = parmDict.keys()
2071            parmNames.sort()
2072            parmText = ' p:h:Parameter       refine?              value\n'
2073            for name in parmNames:
2074                parmData = parmDict[name]
2075                try:
2076                    parmText += ' %s \t%12.4g \n'%(name.ljust(19)+'\t'+parmData[1],parmData[0])
2077                except TypeError:
2078                    pass
2079            parmTable = wx.TextCtrl(panel,-1,parmText,
2080                style=wx.TE_MULTILINE|wx.TE_READONLY,size=(290,400))
2081            mainSizer = wx.BoxSizer(wx.VERTICAL)
2082            mainSizer.Add(parmTable)
2083            panel.SetSizer(mainSizer)
2084                           
2085    def OnViewLSParms(self,event):
2086        parmDict = {}
2087        Histograms,Phases = self.GetUsedHistogramsAndPhasesfromTree()
2088        print Histograms.keys()
2089        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable = G2str.GetPhaseData(Phases,RestraintDict=None,Print=False)       
2090        hapVary,hapDict,controlDict = G2str.GetHistogramPhaseData(Phases,Histograms,Print=False)
2091        histVary,histDict,controlDict = G2str.GetHistogramData(Histograms,Print=False)
2092        varyList = phaseVary+hapVary+histVary
2093        parmDict.update(phaseDict)
2094        parmDict.update(hapDict)
2095        parmDict.update(histDict)
2096        for parm in parmDict:
2097            if parm.split(':')[-1] in ['Azimuth','Gonio. radius','Lam1','Lam2',
2098                'Omega','Chi','Phi','nDebye','nPeaks']:
2099                parmDict[parm] = [parmDict[parm],' ']
2100            elif parm.split(':')[-2] in ['Ax','Ay','Az','SHmodel','SHord']:
2101                parmDict[parm] = [parmDict[parm],' ']
2102            elif parm in varyList:
2103                parmDict[parm] = [parmDict[parm],'True']
2104            else:
2105                parmDict[parm] = [parmDict[parm],'False']
2106        parmDict[' Num refined'] = [len(varyList),'']
2107        dlg = self.ViewParmDialog(self,'Parameters for least squares',parmDict)
2108        try:
2109            if dlg.ShowModal() == wx.ID_OK:
2110                print 'do something with changes?? - No!'
2111        finally:
2112            dlg.Destroy()
2113       
2114    def OnRefine(self,event):
2115        self.OnFileSave(event)
2116        # check that constraints are OK here
2117        errmsg, warnmsg = G2str.CheckConstraints(self.GSASprojectfile)
2118        if errmsg:
2119            print('Error in constraints:\n'+errmsg+
2120                  '\nRefinement not possible')
2121            self.ErrorDialog('Constraint Error',
2122                             'Error in constraints:\n'+errmsg+
2123                             '\nRefinement not possible')
2124            return
2125        if warnmsg:
2126            print('Conflict between refinment flag settings and constraints:\n'+
2127                  warnmsg+'\nRefinement not possible')
2128            self.ErrorDialog('Refinement Flag Error',
2129                             'Conflict between refinment flag settings and constraints:\n'+
2130                             warnmsg+
2131                             '\nRefinement not possible')
2132            return
2133        #works - but it'd be better if it could restore plots
2134        dlg = wx.ProgressDialog('Residual','All data Rw =',101.0, 
2135            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
2136        screenSize = wx.ClientDisplayRect()
2137        Size = dlg.GetSize()
2138        Size = (int(Size[0]*1.2),Size[1]) # increase size a bit along x
2139        dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
2140        dlg.SetSize(Size)
2141        Rw = 100.00
2142        try:
2143            Rw = G2str.Refine(self.GSASprojectfile,dlg)
2144        finally:
2145            dlg.Destroy()
2146        oldId =  self.PatternTree.GetSelection()
2147        oldName = self.PatternTree.GetItemText(oldId)
2148        parentId = self.PatternTree.GetItemParent(oldId)
2149        parentName = ''
2150        if parentId:
2151            parentName = self.PatternTree.GetItemText(parentId)
2152        dlg = wx.MessageDialog(self,'Load new result?','Refinement results, Rw =%.3f'%(Rw),wx.OK|wx.CANCEL)
2153        try:
2154            if dlg.ShowModal() == wx.ID_OK:
2155                Id = 0
2156                self.PatternTree.DeleteChildren(self.root)
2157                if self.HKL: self.HKL = []
2158                if self.G2plotNB.plotList:
2159                    self.G2plotNB.clear()
2160                G2IO.ProjFileOpen(self)
2161                item, cookie = self.PatternTree.GetFirstChild(self.root)
2162                while item and not Id:
2163                    name = self.PatternTree.GetItemText(item)
2164                    if name[:4] in ['PWDR','HKLF']:
2165                        Id = item
2166                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
2167                if parentName:
2168                    parentId = G2gd.GetPatternTreeItemId(self, self.root, parentName)
2169                    if parentId:
2170                        itemId = G2gd.GetPatternTreeItemId(self, parentId, oldName)
2171                    else:
2172                        itemId = G2gd.GetPatternTreeItemId(self, self.root, oldName)
2173                    self.PatternTree.SelectItem(itemId)
2174                elif Id:
2175                    self.PatternTree.SelectItem(Id)
2176        finally:
2177            dlg.Destroy()
2178
2179    def OnSeqRefine(self,event):
2180        Id = G2gd.GetPatternTreeItemId(self,self.root,'Sequental results')
2181        if not Id:
2182            Id = self.PatternTree.AppendItem(self.root,text='Sequental results')
2183            self.PatternTree.SetItemPyData(Id,{})           
2184        self.OnFileSave(event)
2185        # check that constraints are OK here
2186        errmsg, warnmsg = G2str.CheckConstraints(self.GSASprojectfile)
2187        if errmsg:
2188            print('Error in constraints:\n'+errmsg+
2189                  '\nRefinement not possible')
2190            self.ErrorDialog('Constraint Error',
2191                             'Error in constraints:\n'+errmsg+
2192                             '\nRefinement not possible')
2193            return
2194        if warnmsg:
2195            print('Conflict between refinment flag settings and constraints:\n'+
2196                  warnmsg+'\nRefinement not possible')
2197            self.ErrorDialog('Refinement Flag Error',
2198                             'Conflict between refinment flag settings and constraints:\n'+
2199                             warnmsg+'\nRefinement not possible')
2200            return
2201        dlg = wx.ProgressDialog('Residual for histogram 0','Powder profile Rwp =',101.0, 
2202            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
2203        screenSize = wx.ClientDisplayRect()
2204        Size = dlg.GetSize()
2205        Size = (int(Size[0]*1.2),Size[1]) # increase size a bit along x
2206        dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
2207        dlg.SetSize(Size)
2208        try:
2209            G2str.SeqRefine(self.GSASprojectfile,dlg)
2210        finally:
2211            dlg.Destroy()       
2212        dlg = wx.MessageDialog(self,'Load new result?','Refinement results',wx.OK|wx.CANCEL)
2213        try:
2214            if dlg.ShowModal() == wx.ID_OK:
2215                Id = 0
2216                self.PatternTree.DeleteChildren(self.root)
2217                if self.HKL: self.HKL = []
2218                if self.G2plotNB.plotList:
2219                    self.G2plotNB.clear()
2220                G2IO.ProjFileOpen(self)
2221                item, cookie = self.PatternTree.GetFirstChild(self.root)
2222                while item and not Id:
2223                    name = self.PatternTree.GetItemText(item)
2224                    if name[:4] in ['PWDR','HKLF']:
2225                        Id = item
2226                    item, cookie = self.PatternTree.GetNextChild(self.root, cookie)               
2227                if Id:
2228                    self.PatternTree.SelectItem(Id)
2229        finally:
2230            dlg.Destroy()
2231       
2232    def ErrorDialog(self,title,message,parent=None, wtype=wx.OK):
2233        result = None
2234        if parent is None:
2235            dlg = wx.MessageDialog(self, message, title,  wtype)
2236        else:
2237            dlg = wx.MessageDialog(parent, message, title,  wtype)
2238            dlg.CenterOnParent() # not working on Mac
2239        try:
2240            result = dlg.ShowModal()
2241        finally:
2242            dlg.Destroy()
2243        return result
2244
2245class GSASIImain(wx.App):
2246    def OnInit(self):
2247        self.main = GSASII(None)
2248        self.main.Show()
2249        self.SetTopWindow(self.main)
2250        return True
2251
2252def main():
2253    application = GSASIImain(0)
2254    if wxInspector: wxeye.InspectionTool().Show()
2255
2256    #application.main.OnRefine(None)
2257    application.MainLoop()
2258   
2259if __name__ == '__main__':
2260    main()
Note: See TracBrowser for help on using the repository browser.