source: trunk/GSASII.py @ 795

Last change on this file since 795 was 795, checked in by vondreele, 10 years ago

implement TOF input, peak search & fitting
auto peak search
convert instrument parms to dictionary
add charge flip on max rho

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