source: trunk/GSASII.py @ 863

Last change on this file since 863 was 863, checked in by vondreele, 11 years ago

fix to notebook & comment (not allowed) editing
avoid a dead window problem with comments/notebook
fix atom editing problems with no rigid bodies
work on help text

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