source: trunk/GSASII.py @ 812

Last change on this file since 812 was 812, checked in by vondreele, 9 years ago

add restraint macro files
fix a triclinic error in genHlaue
continue development of restraints

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