source: trunk/GSASII.py @ 794

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

still more iparm fixes - maybe that's all of them?

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