source: trunk/GSASIIIO.py @ 2817

Last change on this file since 2817 was 2817, checked in by vondreele, 6 years ago

major revision - move all importers to GSASIIobj & make them independent of wx so they can be used in a scripting environment.
Still to move are PhaseSelector?, and 3 BlockSelector? dialogs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 90.2 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2017-05-02 15:03:41 +0000 (Tue, 02 May 2017) $
4# $Author: vondreele $
5# $Revision: 2817 $
6# $URL: trunk/GSASIIIO.py $
7# $Id: GSASIIIO.py 2817 2017-05-02 15:03:41Z vondreele $
8########### SVN repository information ###################
9'''
10*GSASIIIO: Misc I/O routines*
11=============================
12
13Module with miscellaneous routines for input and output. Many
14are GUI routines to interact with user.
15
16Includes support for image reading.
17
18Also includes base classes for data import routines.
19
20'''
21"""GSASIIIO: functions for IO of data
22   Copyright: 2008, Robert B. Von Dreele (Argonne National Laboratory)
23"""
24import wx
25import math
26import numpy as np
27import copy
28import cPickle
29import sys
30import re
31import random as ran
32import GSASIIpath
33GSASIIpath.SetVersionNumber("$Revision: 2817 $")
34import GSASIIgrid as G2gd
35import GSASIIspc as G2spc
36import GSASIIobj as G2obj
37import GSASIIlattice as G2lat
38import GSASIImath as G2mth
39import GSASIIpwdGUI as G2pdG
40import GSASIIimgGUI as G2imG
41import GSASIIimage as G2img
42import GSASIIElem as G2el
43import GSASIIstrIO as G2stIO
44import GSASIImapvars as G2mv
45import GSASIIctrls as G2G
46import os
47import os.path as ospath
48
49DEBUG = False       #=True for various prints
50TRANSP = False      #=true to transpose images for testing
51if GSASIIpath.GetConfigValue('Transpose'): TRANSP = True
52npsind = lambda x: np.sin(x*np.pi/180.)
53
54def sfloat(S):
55    'Convert a string to float. An empty field or a unconvertable value is treated as zero'
56    if S.strip():
57        try:
58            return float(S)
59        except ValueError:
60            pass
61    return 0.0
62
63def sint(S):
64    'Convert a string to int. An empty field is treated as zero'
65    if S.strip():
66        return int(S)
67    else:
68        return 0
69
70def trim(val):
71    '''Simplify a string containing leading and trailing spaces
72    as well as newlines, tabs, repeated spaces etc. into a shorter and
73    more simple string, by replacing all ranges of whitespace
74    characters with a single space.
75
76    :param str val: the string to be simplified
77
78    :returns: the (usually) shortened version of the string
79    '''
80    return re.sub('\s+', ' ', val).strip()
81
82def makeInstDict(names,data,codes):
83    inst = dict(zip(names,zip(data,data,codes)))
84    for item in inst:
85        inst[item] = list(inst[item])
86    return inst
87
88def FileDlgFixExt(dlg,file):
89    'this is needed to fix a problem in linux wx.FileDialog'
90    ext = dlg.GetWildcard().split('|')[2*dlg.GetFilterIndex()+1].strip('*')
91    if ext not in file:
92        file += ext
93    return file
94       
95def GetPowderPeaks(fileName):
96    'Read powder peaks from a file'
97    sind = lambda x: math.sin(x*math.pi/180.)
98    asind = lambda x: 180.*math.asin(x)/math.pi
99    wave = 1.54052
100    File = open(fileName,'Ur')
101    Comments = []
102    peaks = []
103    S = File.readline()
104    while S:
105        if S[:1] == '#':
106            Comments.append(S[:-1])
107        else:
108            item = S.split()
109            if len(item) == 1:
110                peaks.append([float(item[0]),1.0])
111            elif len(item) > 1:
112                peaks.append([float(item[0]),float(item[0])])
113        S = File.readline()
114    File.close()
115    if Comments:
116       print 'Comments on file:'
117       for Comment in Comments: 
118            print Comment
119            if 'wavelength' in Comment:
120                wave = float(Comment.split('=')[1])
121    Peaks = []
122    if peaks[0][0] > peaks[-1][0]:          # d-spacings - assume CuKa
123        for peak in peaks:
124            dsp = peak[0]
125            sth = wave/(2.0*dsp)
126            if sth < 1.0:
127                tth = 2.0*asind(sth)
128            else:
129                break
130            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
131    else:                                   #2-thetas - assume Cuka (for now)
132        for peak in peaks:
133            tth = peak[0]
134            dsp = wave/(2.0*sind(tth/2.0))
135            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
136    limits = [1000.,0.]
137    for peak in Peaks:
138        limits[0] = min(limits[0],peak[0])
139        limits[1] = max(limits[1],peak[0])
140    limits[0] = max(1.,(int(limits[0]-1.)/5)*5.)
141    limits[1] = min(170.,(int(limits[1]+1.)/5)*5.)
142    return Comments,Peaks,limits,wave
143
144def GetCheckImageFile(G2frame,treeId):
145    '''Try to locate an image file if the project and image have been moved
146    together. If the image file cannot be found, request the location from
147    the user.
148
149    :param wx.Frame G2frame: main GSAS-II Frame and data object
150    :param wx.Id treeId: Id for the main tree item for the image
151    :returns: Npix,imagefile,imagetag with (Npix) number of pixels,
152       imagefile, if it exists, or the name of a file that does exist or False if the user presses Cancel
153       and (imagetag) an optional image number
154
155    '''
156    Npix,Imagefile,imagetag = G2frame.PatternTree.GetImageLoc(treeId)
157    if isinstance(Imagefile,list):
158        imagefile,imagetag = Imagefile
159    else:
160        imagefile = Imagefile
161    if not os.path.exists(imagefile):
162        print 'Image file '+imagefile+' not found'
163        fil = imagefile.replace('\\','/') # windows?!
164        # see if we can find a file with same name or in a similarly named sub-dir
165        pth,fil = os.path.split(fil)
166        prevpth = None
167        while pth and pth != prevpth:
168            prevpth = pth
169            if os.path.exists(os.path.join(G2frame.dirname,fil)):
170                print 'found image file '+os.path.join(G2frame.dirname,fil)
171                imagefile = os.path.join(G2frame.dirname,fil)
172                G2frame.PatternTree.UpdateImageLoc(treeId,imagefile)
173                return Npix,imagefile,imagetag
174            pth,enddir = os.path.split(pth)
175            fil = os.path.join(enddir,fil)
176        # not found as a subdirectory, drop common parts of path for last saved & image file names
177        #    if image was .../A/B/C/imgs/ima.ge
178        #      & GPX was  .../A/B/C/refs/fil.gpx but is now .../NEW/TEST/TEST1
179        #    will look for .../NEW/TEST/TEST1/imgs/ima.ge, .../NEW/TEST/imgs/ima.ge, .../NEW/imgs/ima.ge and so on
180        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
181        gpxPath = Controls.get('LastSavedAs','').replace('\\','/').split('/') # blank in older .GPX files
182        imgPath = imagefile.replace('\\','/').split('/')
183        for p1,p2 in zip(gpxPath,imgPath):
184            if p1 == p2:
185                gpxPath.pop(0),imgPath.pop(0)
186            else:
187                break
188        fil = os.path.join(*imgPath) # file with non-common prefix elements
189        prevpth = None
190        pth = os.path.abspath(G2frame.dirname)
191        while pth and pth != prevpth:
192            prevpth = pth
193            if os.path.exists(os.path.join(pth,fil)):
194                print 'found image file '+os.path.join(pth,fil)
195                imagefile = os.path.join(pth,fil)
196                G2frame.PatternTree.UpdateImageLoc(treeId,imagefile)
197                return Npix,imagefile,imagetag
198            pth,enddir = os.path.split(pth)
199        #GSASIIpath.IPyBreak()
200
201    if not os.path.exists(imagefile):
202        prevnam = os.path.split(imagefile)[1]
203        prevext = os.path.splitext(imagefile)[1]
204        wildcard = 'Image format (*'+prevext+')|*'+prevext
205        dlg = wx.FileDialog(G2frame, 'Previous image file ('+prevnam+') not found; open here', '.', prevnam,
206                            wildcard,wx.OPEN)
207        try:
208            dlg.SetFilename(''+ospath.split(imagefile)[1])
209            if dlg.ShowModal() == wx.ID_OK:
210                imagefile = dlg.GetPath()
211                G2frame.PatternTree.UpdateImageLoc(treeId,imagefile)
212            else:
213                imagefile = False
214        finally:
215            dlg.Destroy()
216    return Npix,imagefile,imagetag
217
218def EditImageParms(parent,Data,Comments,Image,filename):
219    dlg = wx.Dialog(parent, wx.ID_ANY, 'Edit image parameters',
220                    style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
221    def onClose(event):
222        dlg.EndModal(wx.ID_OK)
223    mainsizer = wx.BoxSizer(wx.VERTICAL)
224    h,w = Image.shape[:2]
225    mainsizer.Add(wx.StaticText(dlg,wx.ID_ANY,'File '+str(filename)+'\nImage size: '+str(h)+' x '+str(w)),
226        0,wx.ALIGN_LEFT|wx.ALL, 2)
227   
228    vsizer = wx.BoxSizer(wx.HORIZONTAL)
229    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Wavelength (\xC5) '),
230        0,wx.ALIGN_LEFT|wx.ALL, 2)
231    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'wavelength')
232    vsizer.Add(wdgt)
233    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
234
235    vsizer = wx.BoxSizer(wx.HORIZONTAL)
236    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Pixel size (\xb5m). Width '),
237        0,wx.ALIGN_LEFT|wx.ALL, 2)
238    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],0,
239                                 size=(50,-1))
240    vsizer.Add(wdgt)
241    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Height '),wx.ALIGN_LEFT|wx.ALL, 2)
242    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],1,size=(50,-1))
243    vsizer.Add(wdgt)
244    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
245
246    vsizer = wx.BoxSizer(wx.HORIZONTAL)
247    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Sample to detector (mm) '),
248        0,wx.ALIGN_LEFT|wx.ALL, 2)
249    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'distance')
250    vsizer.Add(wdgt)
251    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
252
253    vsizer = wx.BoxSizer(wx.HORIZONTAL)
254    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Beam center (pixels). X = '),
255        0,wx.ALIGN_LEFT|wx.ALL, 2)
256    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],0,size=(75,-1))
257    vsizer.Add(wdgt)
258    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Y = '),wx.ALIGN_LEFT|wx.ALL, 2)
259    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],1,size=(75,-1))
260    vsizer.Add(wdgt)
261    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
262
263    vsizer = wx.BoxSizer(wx.HORIZONTAL)
264    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Comments '),
265        0,wx.ALIGN_LEFT|wx.ALL, 2)
266    wdgt = G2G.ValidatedTxtCtrl(dlg,Comments,0,size=(250,-1))
267    vsizer.Add(wdgt)
268    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
269
270    btnsizer = wx.StdDialogButtonSizer()
271    OKbtn = wx.Button(dlg, wx.ID_OK, 'Continue')
272    OKbtn.SetDefault()
273    OKbtn.Bind(wx.EVT_BUTTON,onClose)
274    btnsizer.AddButton(OKbtn) # not sure why this is needed
275    btnsizer.Realize()
276    mainsizer.Add(btnsizer, 1, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 5)
277    dlg.SetSizer(mainsizer)
278    dlg.CenterOnParent()
279    dlg.ShowModal()
280   
281def LoadImage2Tree(imagefile,G2frame,Comments,Data,Npix,Image):
282    '''Load an image into the tree. Saves the location of the image, as well as the
283    ImageTag (where there is more than one image in the file), if defined.
284    '''
285    ImgNames = G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
286    TreeLbl = 'IMG '+os.path.basename(imagefile)
287    ImageTag = Data.get('ImageTag')
288    if ImageTag:
289        TreeLbl += ' #'+'%04d'%(ImageTag)
290        imageInfo = (imagefile,ImageTag)
291    else:
292        imageInfo = imagefile
293    TreeName = G2obj.MakeUniqueLabel(TreeLbl,ImgNames)
294    Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=TreeName)
295    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)
296    Imax = np.amax(Image)
297    if G2frame.imageDefault:
298        Data = copy.copy(G2frame.imageDefault)
299        Data['showLines'] = True
300        Data['ring'] = []
301        Data['rings'] = []
302        Data['cutoff'] = 10
303        Data['pixLimit'] = 20
304        Data['edgemin'] = 100000000
305        Data['calibdmin'] = 0.5
306        Data['calibskip'] = 0
307        Data['ellipses'] = []
308        Data['calibrant'] = ''
309        Data['GonioAngles'] = [0.,0.,0.]
310        Data['DetDepthRef'] = False
311    else:
312        Data['type'] = 'PWDR'
313        Data['color'] = 'Paired'
314        Data['tilt'] = 0.0
315        Data['rotation'] = 0.0
316        Data['showLines'] = False
317        Data['ring'] = []
318        Data['rings'] = []
319        Data['cutoff'] = 10
320        Data['pixLimit'] = 20
321        Data['calibdmin'] = 0.5
322        Data['calibskip'] = 0
323        Data['edgemin'] = 100000000
324        Data['ellipses'] = []
325        Data['GonioAngles'] = [0.,0.,0.]
326        Data['DetDepth'] = 0.
327        Data['DetDepthRef'] = False
328        Data['calibrant'] = ''
329        Data['IOtth'] = [2.0,5.0]
330        Data['LRazimuth'] = [0.,180.]
331        Data['azmthOff'] = 0.0
332        Data['outChannels'] = 2500
333        Data['outAzimuths'] = 1
334        Data['centerAzm'] = False
335        Data['fullIntegrate'] = False
336        Data['setRings'] = False
337        Data['background image'] = ['',-1.0]                           
338        Data['dark image'] = ['',-1.0]
339        Data['Flat Bkg'] = 0.0
340    Data['setDefault'] = False
341    Data['range'] = [(0,Imax),[0,Imax]]
342    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Image Controls'),Data)
343    Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(0,Imax),[0,Imax]]}
344    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Masks'),Masks)
345    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Stress/Strain'),
346        {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
347    G2frame.PatternTree.SetItemPyData(Id,[Npix,imageInfo])
348    G2frame.PickId = Id
349    G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
350    G2frame.Image = Id
351
352def GetImageData(G2frame,imagefile,imageOnly=False,ImageTag=None,FormatName=''):
353    '''Read a single image with an image importer.
354
355    :param wx.Frame G2frame: main GSAS-II Frame and data object.
356    :param str imagefile: name of image file
357    :param bool imageOnly: If True return only the image,
358      otherwise  (default) return more (see below)
359    :param int/str ImageTag: specifies a particular image to be read from a file.
360      First image is read if None (default).
361    :param str formatName: the image reader formatName
362
363    :returns: an image as a numpy array or a list of four items:
364      Comments, Data, Npix and the Image, as selected by imageOnly
365
366    '''
367    # determine which formats are compatible with this file
368    primaryReaders = []
369    secondaryReaders = []
370    for rd in G2frame.ImportImageReaderlist:
371        flag = rd.ExtensionValidator(imagefile)
372        if flag is None: 
373            secondaryReaders.append(rd)
374        elif flag:
375            if not FormatName:
376                primaryReaders.append(rd)
377            elif FormatName == rd.formatName:
378                primaryReaders.append(rd)
379    if len(secondaryReaders) + len(primaryReaders) == 0:
380        print('Error: No matching format for file '+imagefile)
381        raise Exception('No image read')
382    fp = None
383    errorReport = ''
384    if not imagefile:
385        return
386    fp = open(imagefile,'Ur')
387    for rd in primaryReaders+secondaryReaders:
388        rd.ReInitialize() # purge anything from a previous read
389        fp.seek(0)  # rewind
390        rd.errors = "" # clear out any old errors
391        if not rd.ContentsValidator(fp): # rejected on cursory check
392            errorReport += "\n  "+rd.formatName + ' validator error'
393            if rd.errors: 
394                errorReport += ': '+rd.errors
395                continue
396        if imageOnly:
397            ParentFrame = None # prevent GUI access on reread
398        else:
399            ParentFrame = G2frame
400        if GSASIIpath.GetConfigValue('debug'):
401            flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=ImageTag)
402        else:
403            flag = False
404            try:
405                flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=ImageTag)
406            except rd.ImportException as detail:
407                rd.errors += "\n  Read exception: "+str(detail)
408            except Exception as detail:
409                import traceback
410                rd.errors += "\n  Unhandled read exception: "+str(detail)
411                rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
412        if flag: # this read succeeded
413            if rd.Image is None:
414                raise Exception('No image read. Strange!')
415            if GSASIIpath.GetConfigValue('Transpose'):
416                print 'Transposing Image!'
417                rd.Image = rd.Image.T
418            #rd.readfilename = imagefile
419            if imageOnly:
420                return rd.Image
421            else:
422                return rd.Comments,rd.Data,rd.Npix,rd.Image
423    else:
424        print('Error reading file '+imagefile)
425        print('Error messages(s)\n'+errorReport)
426        raise Exception('No image read')   
427
428def ReadImages(G2frame,imagefile):
429    '''Read one or more images from a file and put them into the Tree
430    using image importers. Called only in :meth:`AutoIntFrame.OnTimerLoop`.
431
432    :param wx.Frame G2frame: main GSAS-II Frame and data object.
433    :param str imagefile: name of image file
434
435    :returns: a list of the id's of the IMG tree items created
436    '''
437    # determine which formats are compatible with this file
438    primaryReaders = []
439    secondaryReaders = []
440    for rd in G2frame.ImportImageReaderlist:
441        flag = rd.ExtensionValidator(imagefile)
442        if flag is None:
443            secondaryReaders.append(rd)
444        elif flag:
445            primaryReaders.append(rd)
446    if len(secondaryReaders) + len(primaryReaders) == 0:
447        print('Error: No matching format for file '+imagefile)
448        raise Exception('No image read')
449    errorReport = ''
450    fp = open(imagefile,'Ur')
451    rdbuffer = {} # create temporary storage for file reader
452    for rd in primaryReaders+secondaryReaders:
453        rd.ReInitialize() # purge anything from a previous read
454        fp.seek(0)  # rewind
455        rd.errors = "" # clear out any old errors
456        if not rd.ContentsValidator(fp): # rejected on cursory check
457            errorReport += "\n  "+rd.formatName + ' validator error'
458            if rd.errors: 
459                errorReport += ': '+rd.errors
460                continue
461        ParentFrame = G2frame
462        block = 0
463        repeat = True
464        CreatedIMGitems = []
465        while repeat: # loop if the reader asks for another pass on the file
466            block += 1
467            repeat = False
468            if GSASIIpath.GetConfigValue('debug'):
469                flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=block,Buffer=rdbuffer)
470            else:
471                flag = False
472                try:
473                    flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=block,Buffer=rdbuffer)
474                except rd.ImportException as detail:
475                    rd.errors += "\n  Read exception: "+str(detail)
476                except Exception as detail:
477                    import traceback
478                    rd.errors += "\n  Unhandled read exception: "+str(detail)
479                    rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
480            if flag: # this read succeeded
481                if rd.Image is None:
482                    raise Exception('No image read. Strange!')
483                if GSASIIpath.GetConfigValue('Transpose'):
484                    print 'Transposing Image!'
485                    rd.Image = rd.Image.T
486                rd.Data['ImageTag'] = rd.repeatcount
487                LoadImage2Tree(imagefile,G2frame,rd.Comments,rd.Data,rd.Npix,rd.Image)
488                repeat = rd.repeat
489            CreatedIMGitems.append(G2frame.Image)
490        if CreatedIMGitems: return CreatedIMGitems
491    else:
492        print('Error reading file '+imagefile)
493        print('Error messages(s)\n'+errorReport)
494        return []
495        #raise Exception('No image read')   
496
497def SaveMultipleImg(G2frame):
498    if not G2frame.PatternTree.GetCount():
499        print 'no images!'
500        return
501    choices = G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
502    if len(choices) == 1:
503        names = choices
504    else:
505        dlg = G2G.G2MultiChoiceDialog(G2frame,'Stress/Strain fitting','Select images to fit:',choices)
506        dlg.SetSelections([])
507        names = []
508        if dlg.ShowModal() == wx.ID_OK:
509            names = [choices[sel] for sel in dlg.GetSelections()]
510        dlg.Destroy()
511    if not names: return
512    for name in names:
513        Id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, name)
514        Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(Id)
515        imroot = os.path.splitext(imagefile)[0]
516        if imagetag:
517            imroot += '_' + str(imagetag)
518        Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Image Controls'))
519        print('Writing '+imroot+'.imctrl')
520        File = open(imroot+'.imctrl','w')
521        keys = ['type','wavelength','calibrant','distance','center',
522                    'tilt','rotation','azmthOff','fullIntegrate','LRazimuth',
523                    'IOtth','outChannels','outAzimuths','invert_x','invert_y','DetDepth',
524                    'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
525                    'binType','SampleShape','PolaVal','SampleAbs','dark image','background image']
526        for key in keys:
527            if key not in Data: continue    #uncalibrated!
528            File.write(key+':'+str(Data[key])+'\n')
529        File.close()
530        mask = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Masks'))
531        G2imG.CleanupMasks(mask)
532        print('Writing '+imroot+'.immask')
533        File = open(imroot+'.immask','w')
534        for key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']:
535            File.write(key+':'+str(mask[key])+'\n')
536        File.close()
537       
538def PutG2Image(filename,Comments,Data,Npix,image):
539    'Write an image as a python pickle - might be better as an .edf file?'
540    File = open(filename,'wb')
541    cPickle.dump([Comments,Data,Npix,image],File,1)
542    File.close()
543    return
544   
545def ProjFileOpen(G2frame,showProvenance=True):
546    'Read a GSAS-II project file and load into the G2 data tree'
547    if not os.path.exists(G2frame.GSASprojectfile):
548        print ('\n*** Error attempt to open project file that does not exist:\n   '+
549               str(G2frame.GSASprojectfile))
550        return
551    LastSavedUsing = None
552    file = open(G2frame.GSASprojectfile,'rb')
553    if showProvenance: print 'loading from file: ',G2frame.GSASprojectfile
554    G2frame.SetTitle("GSAS-II data tree: "+
555                     os.path.split(G2frame.GSASprojectfile)[1])
556    wx.BeginBusyCursor()
557    try:
558        while True:
559            try:
560                data = cPickle.load(file)
561            except EOFError:
562                break
563            datum = data[0]
564           
565            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=datum[0])
566            if datum[0].startswith('PWDR'):               
567                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
568                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
569                G2frame.PatternTree.SetItemPyData(Id,datum[1][:3])  #temp. trim off junk (patch?)
570            elif datum[0].startswith('HKLF'): 
571                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
572                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
573                G2frame.PatternTree.SetItemPyData(Id,datum[1])
574            else:
575                G2frame.PatternTree.SetItemPyData(Id,datum[1])             
576                if datum[0] == 'Controls' and 'LastSavedUsing' in datum[1]:
577                    LastSavedUsing = datum[1]['LastSavedUsing']
578                if datum[0] == 'Controls' and 'PythonVersions' in datum[1] and GSASIIpath.GetConfigValue('debug') and showProvenance:
579                    print('Packages used to create .GPX file:')
580                    if 'dict' in str(type(datum[1]['PythonVersions'])):  #patch
581                        for p in sorted(datum[1]['PythonVersions'],key=lambda s: s.lower()):
582                            print({:<14s}: {:s}".format(p[0],p[1]))
583                    else:
584                        for p in datum[1]['PythonVersions']:
585                            print({:<12s} {:s}".format(p[0]+':',p[1]))
586            oldPDF = False
587            for datus in data[1:]:
588#patch - 1/23/17 PDF cleanup
589                if datus[0][:4] in ['I(Q)','S(Q)','F(Q)','G(R)']:
590                    oldPDF = True
591                    data[1][1][datus[0][:4]] = copy.deepcopy(datus[1][:2])
592                    continue
593#end PDF cleanup
594                sub = G2frame.PatternTree.AppendItem(Id,datus[0])
595#patch
596                if datus[0] == 'Instrument Parameters' and len(datus[1]) == 1:
597                    if datum[0].startswith('PWDR'):
598                        datus[1] = [dict(zip(datus[1][3],zip(datus[1][0],datus[1][1],datus[1][2]))),{}]
599                    else:
600                        datus[1] = [dict(zip(datus[1][2],zip(datus[1][0],datus[1][1]))),{}]
601                    for item in datus[1][0]:               #zip makes tuples - now make lists!
602                        datus[1][0][item] = list(datus[1][0][item])
603#end patch
604                G2frame.PatternTree.SetItemPyData(sub,datus[1])
605            if 'PDF ' in datum[0][:4] and oldPDF:
606                sub = G2frame.PatternTree.AppendItem(Id,'PDF Peaks')
607                G2frame.PatternTree.SetItemPyData(sub,{'Limits':[1.,5.],'Background':[2,[0.,-0.2*np.pi],False],'Peaks':[]})
608            if datum[0].startswith('IMG'):                   #retrieve image default flag & data if set
609                Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Image Controls'))
610                if Data['setDefault']:
611                    G2frame.imageDefault = Data               
612        file.close()
613        if LastSavedUsing:
614            print('GPX load successful. Last saved with GSAS-II revision '+LastSavedUsing)
615        else:
616            print('project load successful')
617        G2frame.NewPlot = True
618    except:
619        msg = wx.MessageDialog(G2frame,message="Error reading file "+
620            str(G2frame.GSASprojectfile)+". This is not a GSAS-II .gpx file",
621            caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
622        msg.ShowModal()
623    finally:
624        wx.EndBusyCursor()
625        G2frame.Status.SetStatusText('Mouse RB click item to refresh/raise; RB drag/drop to reorder')
626   
627def ProjFileSave(G2frame):
628    'Save a GSAS-II project file'
629    if not G2frame.PatternTree.IsEmpty():
630        file = open(G2frame.GSASprojectfile,'wb')
631        print 'save to file: ',G2frame.GSASprojectfile
632        # stick the file name into the tree and version info into tree so they are saved.
633        # (Controls should always be created at this point)
634        try:
635            Controls = G2frame.PatternTree.GetItemPyData(
636                G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
637            Controls['LastSavedAs'] = os.path.abspath(G2frame.GSASprojectfile)
638            Controls['LastSavedUsing'] = str(GSASIIpath.GetVersionNumber())
639            Controls['PythonVersions'] = G2frame.PackageVersions
640        except:
641            pass
642        wx.BeginBusyCursor()
643        try:
644            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
645            while item:
646                data = []
647                name = G2frame.PatternTree.GetItemText(item)
648                data.append([name,G2frame.PatternTree.GetItemPyData(item)])
649                item2, cookie2 = G2frame.PatternTree.GetFirstChild(item)
650                while item2:
651                    name = G2frame.PatternTree.GetItemText(item2)
652                    data.append([name,G2frame.PatternTree.GetItemPyData(item2)])
653                    item2, cookie2 = G2frame.PatternTree.GetNextChild(item, cookie2)                           
654                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                           
655                cPickle.dump(data,file,1)
656            file.close()
657            pth = os.path.split(os.path.abspath(G2frame.GSASprojectfile))[0]
658            if GSASIIpath.GetConfigValue('Save_paths'): G2G.SaveGPXdirectory(pth)
659            G2frame.LastGPXdir = pth
660        finally:
661            wx.EndBusyCursor()
662        print('project save successful')
663
664def SaveIntegration(G2frame,PickId,data,Overwrite=False):
665    'Save image integration results as powder pattern(s)'
666    azms = G2frame.Integrate[1]
667    X = G2frame.Integrate[2][:-1]
668    N = len(X)
669    Id = G2frame.PatternTree.GetItemParent(PickId)
670    name = G2frame.PatternTree.GetItemText(Id)
671    name = name.replace('IMG ',data['type']+' ')
672    Comments = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Comments'))
673    if 'PWDR' in name:
674        names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
675        codes = [0 for i in range(11)]
676    elif 'SASD' in name:
677        names = ['Type','Lam','Zero','Azimuth'] 
678        codes = [0 for i in range(4)]
679        X = 4.*np.pi*npsind(X/2.)/data['wavelength']    #convert to q
680    Xminmax = [X[0],X[-1]]
681    Azms = []
682    dazm = 0.
683    if data['fullIntegrate'] and data['outAzimuths'] == 1:
684        Azms = [45.0,]                              #a poor man's average?
685    else:
686        for i,azm in enumerate(azms[:-1]):
687            if azm > 360. and azms[i+1] > 360.:
688                Azms.append(G2img.meanAzm(azm%360.,azms[i+1]%360.))
689            else:   
690                Azms.append(G2img.meanAzm(azm,azms[i+1]))
691        dazm = np.min(np.abs(np.diff(azms)))/2.
692    G2frame.IntgOutList = []
693    for i,azm in enumerate(azms[:-1]):
694        Aname = name+" Azm= %.2f"%((azm+dazm)%360.)
695        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
696        # if Overwrite delete any duplicate
697        if Overwrite and G2gd.GetPatternTreeItemId(G2frame,G2frame.root,Aname):
698            print('Replacing '+Aname)
699            item = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,Aname)
700            G2frame.PatternTree.Delete(item)
701        else:
702            nOcc = 0
703            while item:
704                Name = G2frame.PatternTree.GetItemText(item)
705                if Aname in Name:
706                    nOcc += 1
707                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
708            if nOcc:
709                Aname += '(%d)'%(nOcc)
710        Sample = G2obj.SetDefaultSample()       #set as Debye-Scherrer
711        Sample['Gonio. radius'] = data['distance']
712        Sample['Omega'] = data['GonioAngles'][0]
713        Sample['Chi'] = data['GonioAngles'][1]
714        Sample['Phi'] = data['GonioAngles'][2]
715        Sample['Azimuth'] = (azm+dazm)%360.    #put here as bin center
716        polariz = 0.99    #set default polarization for synchrotron radiation!
717        for item in Comments:
718            if 'polariz' in item:
719                try:
720                    polariz = float(item.split('=')[1])
721                except:
722                    polariz = 0.99
723        if 'PWDR' in Aname:
724            parms = ['PXC',data['wavelength'],0.0,polariz,1.0,-0.10,0.4,0.30,1.0,0.0001,Azms[i]]
725        elif 'SASD' in Aname:
726            Sample['Trans'] = data['SampleAbs'][0]
727            parms = ['LXC',data['wavelength'],0.0,Azms[i]]
728        Y = G2frame.Integrate[0][i]
729        Ymin = np.min(Y)
730        Ymax = np.max(Y)
731        W = np.where(Y>0.,1./Y,1.e-6)                    #probably not true
732        Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=Aname)
733        G2frame.IntgOutList.append(Id)
734        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
735        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
736        if 'PWDR' in Aname:
737            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0],
738                {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
739        inst = [dict(zip(names,zip(parms,parms,codes))),{}]
740        for item in inst[0]:
741            inst[0][item] = list(inst[0][item])
742        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
743        if 'PWDR' in Aname:
744            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
745            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Peak List'),{'sigDict':{},'peaks':[]})
746            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Index Peak List'),[[],[]])
747            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Unit Cells List'),[])
748            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Reflection Lists'),{})
749        elif 'SASD' in Aname:             
750            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Substances'),G2pdG.SetDefaultSubstances())
751            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
752            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Models'),G2pdG.SetDefaultSASDModel())
753        valuesdict = {
754            'wtFactor':1.0,
755            'Dummy':False,
756            'ranId':ran.randint(0,sys.maxint),
757            'Offset':[0.0,0.0],'delOffset':0.02*Ymax,'refOffset':-0.1*Ymax,'refDelt':0.1*Ymax,
758            'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
759            }
760        G2frame.PatternTree.SetItemPyData(
761            Id,[valuesdict,
762                [np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
763    return Id       #last powder pattern generated
764   
765def XYsave(G2frame,XY,labelX='X',labelY='Y',names=None):
766    'Save XY table data'
767    pth = G2G.GetExportPath(G2frame)
768    dlg = wx.FileDialog(
769        G2frame, 'Enter csv filename for XY table', pth, '',
770        'XY table file (*.csv)|*.csv',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
771    try:
772        if dlg.ShowModal() == wx.ID_OK:
773            filename = dlg.GetPath()
774            filename = os.path.splitext(filename)[0]+'.csv'
775            File = open(filename,'w')
776        else:
777            filename = None
778    finally:
779        dlg.Destroy()
780    if not filename:
781        return
782    for i in range(len(XY)):
783        if names != None:
784            header = '%s,%s(%s)\n'%(labelX,labelY,names[i])
785        else:
786            header = '%s,%s(%d)\n'%(labelX,labelY,i)
787        File.write(header)
788        for x,y in XY[i].T:
789            File.write('%.3f,%.3f\n'%(x,y))   
790    File.close()
791    print ' XY data saved to: ',filename
792           
793def PDFSave(G2frame,exports,PDFsaves):
794    'Save a PDF I(Q), S(Q), F(Q) and G(r)  in column formats'
795    import scipy.interpolate as scintp
796    for export in exports:
797        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
798        PDFControls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, PickId,'PDF Controls'))
799        if PDFsaves[0]:     #I(Q)
800            iqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.iq')
801            iqdata = PDFControls['I(Q)'][0]
802            iqfxn = scintp.interp1d(iqdata[0],iqdata[1],kind='linear')
803            iqfile = open(iqfilename,'w')
804            iqfile.write('#T I(Q) %s\n'%(export))
805            iqfile.write('#L Q     I(Q)\n')
806            qnew = np.arange(iqdata[0][0],iqdata[0][-1],0.005)
807            iqnew = zip(qnew,iqfxn(qnew))
808            for q,iq in iqnew:
809                iqfile.write("%15.6g %15.6g\n" % (q,iq))
810            iqfile.close()
811            print ' I(Q) saved to: ',iqfilename
812           
813        if PDFsaves[1]:     #S(Q)
814            sqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.sq')
815            sqdata = PDFControls['S(Q)'][1]
816            sqfxn = scintp.interp1d(sqdata[0],sqdata[1],kind='linear')
817            sqfile = open(sqfilename,'w')
818            sqfile.write('#T S(Q) %s\n'%(export))
819            sqfile.write('#L Q     S(Q)\n')
820            qnew = np.arange(sqdata[0][0],sqdata[0][-1],0.005)
821            sqnew = zip(qnew,sqfxn(qnew))
822            for q,sq in sqnew:
823                sqfile.write("%15.6g %15.6g\n" % (q,sq))
824            sqfile.close()
825            print ' S(Q) saved to: ',sqfilename
826           
827        if PDFsaves[2]:     #F(Q)
828            fqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.fq')
829            fqdata = PDFControls['F(Q)'][1]
830            fqfxn = scintp.interp1d(fqdata[0],fqdata[1],kind='linear')
831            fqfile = open(sqfilename,'w')
832            fqfile.write('#T F(Q) %s\n'%(export))
833            fqfile.write('#L Q     F(Q)\n')
834            qnew = np.arange(sqdata[0][0],sqdata[0][-1],0.005)
835            fqnew = zip(qnew,fqfxn(qnew))
836            for q,fq in fqnew:
837                fqfile.write("%15.6g %15.6g\n" % (q,fq))
838            fqfile.close()
839            print ' F(Q) saved to: ',fqfilename
840           
841        if PDFsaves[3]:     #G(R)
842            grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
843            grdata = PDFControls['G(R)'][1]
844            grfxn = scintp.interp1d(grdata[0],grdata[1],kind='linear')
845            grfile = open(grfilename,'w')
846            grfile.write('#T G(R) %s\n'%(export))
847            grfile.write('#L R     G(R)\n')
848            rnew = np.arange(grdata[0][0],grdata[0][-1],0.010)
849            grnew = zip(rnew,grfxn(rnew))
850            for r,gr in grnew:
851                grfile.write("%15.6g %15.6g\n" % (r,gr))
852            grfile.close()
853            print ' G(R) saved to: ',grfilename
854       
855        if PDFsaves[4]: #pdfGUI file for G(R)
856            pId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, 'PWDR'+export[4:])
857            Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, pId,'Instrument Parameters'))[0]
858            Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, pId,'Limits'))
859            grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
860            grdata = PDFControls['G(R)'][1]
861            qdata = PDFControls['I(Q)'][1][0]
862            grfxn = scintp.interp1d(grdata[0],grdata[1],kind='linear')
863            grfile = open(grfilename,'w')
864            rnew = np.arange(grdata[0][0],grdata[0][-1],0.010)
865            grnew = zip(rnew,grfxn(rnew))
866
867            grfile.write('[DEFAULT]\n')
868            grfile.write('\n')
869            grfile.write('version = GSAS-II-v'+str(GSASIIpath.GetVersionNumber())+'\n')
870            grfile.write('\n')
871            grfile.write('# input and output specifications\n')
872            grfile.write('dataformat = Qnm\n')
873            grfile.write('inputfile = %s\n'%(PDFControls['Sample']['Name']))
874            grfile.write('backgroundfile = %s\n'%(PDFControls['Sample Bkg.']['Name']))
875            grfile.write('outputtype = gr\n')
876            grfile.write('\n')
877            grfile.write('# PDF calculation setup\n')
878            if 'x' in Inst['Type']:
879                grfile.write('mode = %s\n'%('xray'))
880            elif 'N' in Inst['Type']:
881                grfile.write('mode = %s\n'%('neutron'))
882            wave = G2mth.getMeanWave(Inst)
883            grfile.write('wavelength = %.5f\n'%(wave))
884            formula = ''
885            for el in PDFControls['ElList']:
886                formula += el
887                num = PDFControls['ElList'][el]['FormulaNo']
888                if num == round(num):
889                    formula += '%d'%(int(num))
890                else:
891                    formula += '%.2f'%(num)
892            grfile.write('composition = %s\n'%(formula))
893            grfile.write('bgscale = %.3f\n'%(-PDFControls['Sample Bkg.']['Mult']))
894            highQ = 2.*np.pi/G2lat.Pos2dsp(Inst,Limits[1][1])
895            grfile.write('qmaxinst = %.2f\n'%(highQ))
896            grfile.write('qmin = %.5f\n'%(qdata[0]))
897            grfile.write('qmax = %.4f\n'%(qdata[-1]))
898            grfile.write('rmin = %.2f\n'%(PDFControls['Rmin']))
899            grfile.write('rmax = %.2f\n'%(PDFControls['Rmax']))
900            grfile.write('rstep = 0.01\n')
901           
902           
903            grfile.write('\n')
904            grfile.write('# End of config '+63*'-')
905            grfile.write('\n')
906            grfile.write('#### start data\n')
907            grfile.write('#S 1\n')
908            grfile.write('#L r($\AA$)  G($\AA^{-2}$)\n')           
909            for r,gr in grnew:
910                grfile.write("%15.2F %15.6F\n" % (r,gr))
911            grfile.close()
912            print ' G(R) saved to: ',grfilename
913   
914def PeakListSave(G2frame,file,peaks):
915    'Save powder peaks to a data file'
916    print 'save peak list to file: ',G2frame.peaklistfile
917    if not peaks:
918        dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
919        try:
920            dlg.ShowModal()
921        finally:
922            dlg.Destroy()
923        return
924    for peak in peaks:
925        file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
926            (peak[0],peak[2],peak[4],peak[6]))
927    print 'peak list saved'
928             
929def IndexPeakListSave(G2frame,peaks):
930    'Save powder peaks from the indexing list'
931    file = open(G2frame.peaklistfile,'wa')
932    print 'save index peak list to file: ',G2frame.peaklistfile
933    wx.BeginBusyCursor()
934    try:
935        if not peaks:
936            dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
937            try:
938                dlg.ShowModal()
939            finally:
940                dlg.Destroy()
941            return
942        for peak in peaks:
943            file.write("%12.6f\n" % (peak[7]))
944        file.close()
945    finally:
946        wx.EndBusyCursor()
947    print 'index peak list saved'
948   
949class MultipleChoicesDialog(wx.Dialog):
950    '''A dialog that offers a series of choices, each with a
951    title and a wx.Choice widget. Intended to be used Modally.
952    typical input:
953
954        *  choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
955        *  headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
956       
957    selections are placed in self.chosen when OK is pressed
958
959    Also see GSASIIctrls
960    '''
961    def __init__(self,choicelist,headinglist,
962                 head='Select options',
963                 title='Please select from options below',
964                 parent=None):
965        self.chosen = []
966        wx.Dialog.__init__(
967            self,parent,wx.ID_ANY,head, 
968            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
969        panel = wx.Panel(self)
970        mainSizer = wx.BoxSizer(wx.VERTICAL)
971        mainSizer.Add((10,10),1)
972        topLabl = wx.StaticText(panel,wx.ID_ANY,title)
973        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.CENTER,10)
974        self.ChItems = []
975        for choice,lbl in zip(choicelist,headinglist):
976            mainSizer.Add((10,10),1)
977            self.chosen.append(0)
978            topLabl = wx.StaticText(panel,wx.ID_ANY,' '+lbl)
979            mainSizer.Add(topLabl,0,wx.ALIGN_LEFT,10)
980            self.ChItems.append(wx.Choice(self, wx.ID_ANY, (100, 50), choices = choice))
981            mainSizer.Add(self.ChItems[-1],0,wx.ALIGN_CENTER,10)
982
983        OkBtn = wx.Button(panel,-1,"Ok")
984        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
985        cancelBtn = wx.Button(panel,-1,"Cancel")
986        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
987        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
988        btnSizer.Add((20,20),1)
989        btnSizer.Add(OkBtn)
990        btnSizer.Add((20,20),1)
991        btnSizer.Add(cancelBtn)
992        btnSizer.Add((20,20),1)
993        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
994        panel.SetSizer(mainSizer)
995        panel.Fit()
996        self.Fit()
997       
998    def OnOk(self,event):
999        parent = self.GetParent()
1000        if parent is not None: parent.Raise()
1001        # save the results from the choice widgets
1002        self.chosen = []
1003        for w in self.ChItems:
1004            self.chosen.append(w.GetSelection())
1005        self.EndModal(wx.ID_OK)             
1006           
1007    def OnCancel(self,event):
1008        parent = self.GetParent()
1009        if parent is not None: parent.Raise()
1010        self.chosen = []
1011        self.EndModal(wx.ID_CANCEL)             
1012           
1013def ExtractFileFromZip(filename, selection=None, confirmread=True,
1014                       confirmoverwrite=True, parent=None,
1015                       multipleselect=False):
1016    '''If the filename is a zip file, extract a file from that
1017    archive.
1018
1019    :param list Selection: used to predefine the name of the file
1020      to be extracted. Filename case and zip directory name are
1021      ignored in selection; the first matching file is used.
1022
1023    :param bool confirmread: if True asks the user to confirm before expanding
1024      the only file in a zip
1025
1026    :param bool confirmoverwrite: if True asks the user to confirm
1027      before overwriting if the extracted file already exists
1028
1029    :param bool multipleselect: if True allows more than one zip
1030      file to be extracted, a list of file(s) is returned.
1031      If only one file is present, do not ask which one, otherwise
1032      offer a list of choices (unless selection is used).
1033   
1034    :returns: the name of the file that has been created or a
1035      list of files (see multipleselect)
1036
1037    If the file is not a zipfile, return the name of the input file.
1038    If the zipfile is empty or no file has been selected, return None
1039    '''
1040    import zipfile # do this now, since we can save startup time by doing this only on need
1041    import shutil
1042    zloc = os.path.split(filename)[0]
1043    if not zipfile.is_zipfile(filename):
1044        #print("not zip")
1045        return filename
1046
1047    z = zipfile.ZipFile(filename,'r')
1048    zinfo = z.infolist()
1049
1050    if len(zinfo) == 0:
1051        #print('Zip has no files!')
1052        zlist = [-1]
1053    if selection:
1054        choices = [os.path.split(i.filename)[1].lower() for i in zinfo]
1055        if selection.lower() in choices:
1056            zlist = [choices.index(selection.lower())]
1057        else:
1058            print('debug: file '+str(selection)+' was not found in '+str(filename))
1059            zlist = [-1]
1060    elif len(zinfo) == 1 and confirmread:
1061        result = wx.ID_NO
1062        dlg = wx.MessageDialog(
1063            parent,
1064            'Is file '+str(zinfo[0].filename)+
1065            ' what you want to extract from '+
1066            str(os.path.split(filename)[1])+'?',
1067            'Confirm file', 
1068            wx.YES_NO | wx.ICON_QUESTION)
1069        try:
1070            result = dlg.ShowModal()
1071        finally:
1072            dlg.Destroy()
1073        if result == wx.ID_NO:
1074            zlist = [-1]
1075        else:
1076            zlist = [0]
1077    elif len(zinfo) == 1:
1078        zlist = [0]
1079    elif multipleselect:
1080        # select one or more from a from list
1081        choices = [i.filename for i in zinfo]
1082        dlg = G2G.G2MultiChoiceDialog(parent,'Select file(s) to extract from zip file '+str(filename),
1083            'Choose file(s)',choices)
1084        if dlg.ShowModal() == wx.ID_OK:
1085            zlist = dlg.GetSelections()
1086        else:
1087            zlist = []
1088        dlg.Destroy()
1089    else:
1090        # select one from a from list
1091        choices = [i.filename for i in zinfo]
1092        dlg = wx.SingleChoiceDialog(parent,
1093            'Select file to extract from zip file'+str(filename),'Choose file',
1094            choices,)
1095        if dlg.ShowModal() == wx.ID_OK:
1096            zlist = [dlg.GetSelection()]
1097        else:
1098            zlist = [-1]
1099        dlg.Destroy()
1100       
1101    outlist = []
1102    for zindex in zlist:
1103        if zindex >= 0:
1104            efil = os.path.join(zloc, os.path.split(zinfo[zindex].filename)[1])
1105            if os.path.exists(efil) and confirmoverwrite:
1106                result = wx.ID_NO
1107                dlg = wx.MessageDialog(parent,
1108                    'File '+str(efil)+' already exists. OK to overwrite it?',
1109                    'Confirm overwrite',wx.YES_NO | wx.ICON_QUESTION)
1110                try:
1111                    result = dlg.ShowModal()
1112                finally:
1113                    dlg.Destroy()
1114                if result == wx.ID_NO:
1115                    zindex = -1
1116        if zindex >= 0:
1117            # extract the file to the current directory, regardless of it's original path
1118            #z.extract(zinfo[zindex],zloc)
1119            eloc,efil = os.path.split(zinfo[zindex].filename)
1120            outfile = os.path.join(zloc, efil)
1121            fpin = z.open(zinfo[zindex])
1122            fpout = file(outfile, "wb")
1123            shutil.copyfileobj(fpin, fpout)
1124            fpin.close()
1125            fpout.close()
1126            outlist.append(outfile)
1127    z.close()
1128    if multipleselect and len(outlist) >= 1:
1129        return outlist
1130    elif len(outlist) == 1:
1131        return outlist[0]
1132    else:
1133        return None
1134
1135######################################################################
1136# base classes for reading various types of data files
1137#   not used directly, only by subclassing
1138######################################################################
1139def BlockSelector(ChoiceList, ParentFrame=None,title='Select a block',
1140    size=None, header='Block Selector',useCancel=True):
1141    ''' Provide a wx dialog to select a block if the file contains more
1142    than one set of data and one must be selected
1143    '''
1144    if useCancel:
1145        dlg = wx.SingleChoiceDialog(
1146            ParentFrame,title, header,ChoiceList)
1147    else:
1148        dlg = wx.SingleChoiceDialog(
1149            ParentFrame,title, header,ChoiceList,
1150            style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK|wx.CENTRE)
1151    if size: dlg.SetSize(size)
1152    dlg.CenterOnParent()
1153    if dlg.ShowModal() == wx.ID_OK:
1154        sel = dlg.GetSelection()
1155        return sel
1156    else:
1157        return None
1158    dlg.Destroy()
1159
1160def MultipleBlockSelector(ChoiceList, ParentFrame=None,
1161    title='Select a block',size=None, header='Block Selector'):
1162    '''Provide a wx dialog to select a block of data if the
1163    file contains more than one set of data and one must be
1164    selected.
1165
1166    :returns: a list of the selected blocks
1167    '''
1168    dlg = wx.MultiChoiceDialog(ParentFrame,title, header,ChoiceList+['Select all'],
1169        wx.CHOICEDLG_STYLE)
1170    dlg.CenterOnScreen()
1171    if size: dlg.SetSize(size)
1172    if dlg.ShowModal() == wx.ID_OK:
1173        sel = dlg.GetSelections()
1174    else:
1175        return []
1176    dlg.Destroy()
1177    selected = []
1178    if len(ChoiceList) in sel:
1179        return range(len(ChoiceList))
1180    else:
1181        return sel
1182    return selected
1183
1184def MultipleChoicesSelector(choicelist, headinglist, ParentFrame=None, **kwargs):
1185    '''A modal dialog that offers a series of choices, each with a title and a wx.Choice
1186    widget. Typical input:
1187   
1188       * choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1189       
1190       * headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1191       
1192    optional keyword parameters are: head (window title) and title
1193    returns a list of selected indicies for each choice (or None)
1194    '''
1195    result = None
1196    dlg = MultipleChoicesDialog(choicelist,headinglist,
1197        parent=ParentFrame, **kwargs)         
1198    dlg.CenterOnParent()
1199    if dlg.ShowModal() == wx.ID_OK:
1200        result = dlg.chosen
1201    dlg.Destroy()
1202    return result
1203
1204def PhaseSelector(self, ChoiceList, ParentFrame=None,
1205    title='Select a phase', size=None,header='Phase Selector'):
1206    ''' Provide a wx dialog to select a phase if the file contains more
1207    than one phase
1208    '''
1209    return BlockSelector(ChoiceList,ParentFrame,title,
1210        size,header)
1211
1212def ShowBusy():
1213    wx.BeginBusyCursor()
1214#        wx.Yield() # make it happen now!
1215
1216def DoneBusy():
1217    wx.EndBusyCursor()
1218    wx.Yield() # make it happen now!
1219######################################################################
1220def striphist(var,insChar=''):
1221    'strip a histogram number from a var name'
1222    sv = var.split(':')
1223    if len(sv) <= 1: return var
1224    if sv[1]:
1225        sv[1] = insChar
1226    return ':'.join(sv)
1227class ExportBaseclass(object):
1228    '''Defines a base class for the exporting of GSAS-II results.
1229
1230    This class is subclassed in the various exports/G2export_*.py files. Those files
1231    are imported in :meth:`GSASII.GSASII._init_Exports` which defines the
1232    appropriate menu items for each one and the .Exporter method is called
1233    directly from the menu item.
1234
1235    Routines may also define a .Writer method, which is used to write a single
1236    file without invoking any GUI objects.
1237    '''
1238    def __init__(self,G2frame,formatName,extension,longFormatName=None,):
1239        self.G2frame = G2frame
1240        self.formatName = formatName # short string naming file type
1241        self.extension = extension
1242        if longFormatName: # longer string naming file type
1243            self.longFormatName = longFormatName
1244        else:
1245            self.longFormatName = formatName
1246        self.OverallParms = {}
1247        self.Phases = {}
1248        self.Histograms = {}
1249        self.powderDict = {}
1250        self.xtalDict = {}
1251        self.parmDict = {}
1252        self.sigDict = {}
1253        # updated in InitExport:
1254        self.currentExportType = None # type of export that has been requested
1255        # updated in ExportSelect (when used):
1256        self.phasenam = None # a list of selected phases
1257        self.histnam = None # a list of selected histograms
1258        self.filename = None # name of file to be written (single export) or template (multiple files)
1259        self.dirname = '' # name of directory where file(s) will be written
1260        self.fullpath = '' # name of file being written -- full path
1261       
1262        # items that should be defined in a subclass of this class
1263        self.exporttype = []  # defines the type(s) of exports that the class can handle.
1264        # The following types are defined: 'project', "phase", "powder", "single"
1265        self.multiple = False # set as True if the class can export multiple phases or histograms
1266        # self.multiple is ignored for "project" exports
1267
1268    def InitExport(self,event):
1269        '''Determines the type of menu that called the Exporter and
1270        misc initialization.
1271        '''
1272        self.filename = None # name of file to be written (single export)
1273        self.dirname = '' # name of file to be written (multiple export)
1274        if event:
1275            self.currentExportType = self.G2frame.ExportLookup.get(event.Id)
1276
1277    def MakePWDRfilename(self,hist):
1278        '''Make a filename root (no extension) from a PWDR histogram name
1279
1280        :param str hist: the histogram name in data tree (starts with "PWDR ")
1281        '''
1282        file0 = ''
1283        file1 = hist[5:]
1284        # replace repeated blanks
1285        while file1 != file0:
1286            file0 = file1
1287            file1 = file0.replace('  ',' ').strip()
1288        file0 = file1.replace('Azm= ','A')
1289        # if angle has unneeded decimal places on aziumuth, remove them
1290        if file0[-3:] == '.00': file0 = file0[:-3]
1291        file0 = file0.replace('.','_')
1292        file0 = file0.replace(' ','_')
1293        return file0
1294
1295    def ExportSelect(self,AskFile='ask'):
1296        '''Selects histograms or phases when needed. Sets a default file name when
1297        requested into self.filename; always sets a default directory in self.dirname.
1298
1299        :param bool AskFile: Determines how this routine processes getting a
1300          location to store the current export(s).
1301         
1302          * if AskFile is 'ask' (default option), get the name of the file to be written;
1303            self.filename and self.dirname are always set. In the case where
1304            multiple files must be generated, the export routine should do this
1305            based on self.filename as a template.
1306          * if AskFile is 'dir', get the name of the directory to be used;
1307            self.filename is not used, but self.dirname is always set. The export routine
1308            will always generate the file name.
1309          * if AskFile is 'single', get only the name of the directory to be used when
1310            multiple items will be written (as multiple files) are used
1311            *or* a complete file name is requested when a single file
1312            name is selected. self.dirname is always set and self.filename used
1313            only when a single file is selected.
1314          * if AskFile is 'default', creates a name of the file to be used from
1315            the name of the project (.gpx) file. If the project has not been saved,
1316            then the name of file is requested.
1317            self.filename and self.dirname are always set. In the case where
1318            multiple file names must be generated, the export routine should do this
1319            based on self.filename.
1320          * if AskFile is 'default-dir', sets self.dirname from the project (.gpx)
1321            file. If the project has not been saved, then a directory is requested.
1322            self.filename is not used.
1323
1324        :returns: True in case of an error
1325        '''
1326       
1327        numselected = 1
1328        if self.currentExportType == 'phase':
1329            if len(self.Phases) == 0:
1330                self.G2frame.ErrorDialog(
1331                    'Empty project',
1332                    'Project does not contain any phases.')
1333                return True
1334            elif len(self.Phases) == 1:
1335                self.phasenam = self.Phases.keys()
1336            elif self.multiple: 
1337                choices = sorted(self.Phases.keys())
1338                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1339                if phasenum is None: return True
1340                self.phasenam = [choices[i] for i in phasenum]
1341                if not self.phasenam: return True
1342                numselected = len(self.phasenam)
1343            else:
1344                choices = sorted(self.Phases.keys())
1345                phasenum = G2G.ItemSelector(choices,self.G2frame)
1346                if phasenum is None: return True
1347                self.phasenam = [choices[phasenum]]
1348                numselected = len(self.phasenam)
1349        elif self.currentExportType == 'single':
1350            if len(self.xtalDict) == 0:
1351                self.G2frame.ErrorDialog(
1352                    'Empty project',
1353                    'Project does not contain any single crystal data.')
1354                return True
1355            elif len(self.xtalDict) == 1:
1356                self.histnam = self.xtalDict.values()
1357            elif self.multiple:
1358                choices = sorted(self.xtalDict.values())
1359                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1360                if not hnum: return True
1361                self.histnam = [choices[i] for i in hnum]
1362                numselected = len(self.histnam)
1363            else:
1364                choices = sorted(self.xtalDict.values())
1365                hnum = G2G.ItemSelector(choices,self.G2frame)
1366                if hnum is None: return True
1367                self.histnam = [choices[hnum]]
1368                numselected = len(self.histnam)
1369        elif self.currentExportType == 'powder':
1370            if len(self.powderDict) == 0:
1371                self.G2frame.ErrorDialog(
1372                    'Empty project',
1373                    'Project does not contain any powder data.')
1374                return True
1375            elif len(self.powderDict) == 1:
1376                self.histnam = self.powderDict.values()
1377            elif self.multiple:
1378                choices = sorted(self.powderDict.values())
1379                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1380                if not hnum: return True
1381                self.histnam = [choices[i] for i in hnum]
1382                numselected = len(self.histnam)
1383            else:
1384                choices = sorted(self.powderDict.values())
1385                hnum = G2G.ItemSelector(choices,self.G2frame)
1386                if hnum is None: return True
1387                self.histnam = [choices[hnum]]
1388                numselected = len(self.histnam)
1389        elif self.currentExportType == 'image':
1390            if len(self.Histograms) == 0:
1391                self.G2frame.ErrorDialog(
1392                    'Empty project',
1393                    'Project does not contain any images.')
1394                return True
1395            elif len(self.Histograms) == 1:
1396                self.histnam = self.Histograms.keys()
1397            else:
1398                choices = sorted(self.Histograms.keys())
1399                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
1400                if self.multiple:
1401                    if not hnum: return True
1402                    self.histnam = [choices[i] for i in hnum]
1403                else:
1404                    if hnum is None: return True
1405                    self.histnam = [choices[hnum]]
1406                numselected = len(self.histnam)
1407        if self.currentExportType == 'map':
1408            # search for phases with maps
1409            mapPhases = []
1410            choices = []
1411            for phasenam in sorted(self.Phases):
1412                phasedict = self.Phases[phasenam] # pointer to current phase info           
1413                if len(phasedict['General']['Map'].get('rho',[])):
1414                    mapPhases.append(phasenam)
1415                    if phasedict['General']['Map'].get('Flip'):
1416                        choices.append('Charge flip map: '+str(phasenam))
1417                    elif phasedict['General']['Map'].get('MapType'):
1418                        choices.append(
1419                            str(phasedict['General']['Map'].get('MapType'))
1420                            + ' map: ' + str(phasenam))
1421                    else:
1422                        choices.append('unknown map: '+str(phasenam))
1423            # select a map if needed
1424            if len(mapPhases) == 0:
1425                self.G2frame.ErrorDialog(
1426                    'Empty project',
1427                    'Project does not contain any maps.')
1428                return True
1429            elif len(mapPhases) == 1:
1430                self.phasenam = mapPhases
1431            else: 
1432                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
1433                if self.multiple:
1434                    if not phasenum: return True
1435                    self.phasenam = [mapPhases[i] for i in phasenum]
1436                else:
1437                    if phasenum is None: return True
1438                    self.phasenam = [mapPhases[phasenum]]
1439            numselected = len(self.phasenam)
1440
1441        # items selected, now set self.dirname and usually self.filename
1442        if AskFile == 'ask' or (AskFile == 'single' and numselected == 1) or (
1443            AskFile == 'default' and not self.G2frame.GSASprojectfile
1444            ):
1445            filename = self.askSaveFile()
1446            if not filename: return True
1447            self.dirname,self.filename = os.path.split(filename)
1448        elif AskFile == 'dir' or AskFile == 'single' or (
1449            AskFile == 'default-dir' and not self.G2frame.GSASprojectfile
1450            ):
1451            self.dirname = self.askSaveDirectory()
1452            if not self.dirname: return True
1453        elif AskFile == 'default-dir' or AskFile == 'default':
1454            self.dirname,self.filename = os.path.split(
1455                os.path.splitext(self.G2frame.GSASprojectfile)[0] + self.extension
1456                )
1457        else:
1458            raise Exception('This should not happen!')
1459
1460    def loadParmDict(self):
1461        '''Load the GSAS-II refinable parameters from the tree into a dict (self.parmDict). Update
1462        refined values to those from the last cycle and set the uncertainties for the
1463        refined parameters in another dict (self.sigDict).
1464
1465        Expands the parm & sig dicts to include values derived from constraints.
1466        '''
1467        self.parmDict = {}
1468        self.sigDict = {}
1469        rigidbodyDict = {}
1470        covDict = {}
1471        consDict = {}
1472        Histograms,Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
1473        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
1474        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
1475        while item:
1476            name = self.G2frame.PatternTree.GetItemText(item)
1477            if name == 'Rigid bodies':
1478                 rigidbodyDict = self.G2frame.PatternTree.GetItemPyData(item)
1479            elif name == 'Covariance':
1480                 covDict = self.G2frame.PatternTree.GetItemPyData(item)
1481            elif name == 'Constraints':
1482                 consDict = self.G2frame.PatternTree.GetItemPyData(item)
1483            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
1484        rbVary,rbDict =  G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
1485        self.parmDict.update(rbDict)
1486        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
1487        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtables,BLtables,MFtables,maxSSwave =  G2stIO.GetPhaseData(
1488            Phases,RestraintDict=None,rbIds=rbIds,Print=False)
1489        self.parmDict.update(phaseDict)
1490        hapVary,hapDict,controlDict =  G2stIO.GetHistogramPhaseData(
1491            Phases,Histograms,Print=False,resetRefList=False)
1492        self.parmDict.update(hapDict)
1493        histVary,histDict,controlDict =  G2stIO.GetHistogramData(Histograms,Print=False)
1494        self.parmDict.update(histDict)
1495        self.parmDict.update(zip(
1496            covDict.get('varyList',[]),
1497            covDict.get('variables',[])))
1498        self.sigDict = dict(zip(
1499            covDict.get('varyList',[]),
1500            covDict.get('sig',[])))
1501        # expand to include constraints: first compile a list of constraints
1502        constList = []
1503        for item in consDict:
1504            if item.startswith('_'): continue
1505            constList += consDict[item]
1506        # now process the constraints
1507        G2mv.InitVars()
1508        constDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
1509        varyList = covDict.get('varyListStart')
1510        if varyList is None and len(constDict) == 0:
1511            # no constraints can use varyList
1512            varyList = covDict.get('varyList')
1513        elif varyList is None:
1514            # old GPX file from before pre-constraint varyList is saved
1515            print ' *** Old refinement: Please use Calculate/Refine to redo  ***'
1516            raise Exception(' *** Export aborted ***')
1517        else:
1518            varyList = list(varyList)
1519        try:
1520            groups,parmlist = G2mv.GroupConstraints(constDict)
1521            G2mv.GenerateConstraints(groups,parmlist,varyList,constDict,fixedList,self.parmDict)
1522        except:
1523            # this really should not happen
1524            print ' *** ERROR - constraints are internally inconsistent ***'
1525            errmsg, warnmsg = G2mv.CheckConstraints(varyList,constDict,fixedList)
1526            print 'Errors',errmsg
1527            if warnmsg: print 'Warnings',warnmsg
1528            raise Exception(' *** CIF creation aborted ***')
1529        # add the constrained values to the parameter dictionary
1530        G2mv.Dict2Map(self.parmDict,varyList)
1531        # and add their uncertainties into the esd dictionary (sigDict)
1532        if covDict.get('covMatrix') is not None:
1533            self.sigDict.update(G2mv.ComputeDepESD(covDict['covMatrix'],covDict['varyList'],self.parmDict))
1534
1535    def loadTree(self):
1536        '''Load the contents of the data tree into a set of dicts
1537        (self.OverallParms, self.Phases and self.Histogram as well as self.powderDict
1538        & self.xtalDict)
1539       
1540        * The childrenless data tree items are overall parameters/controls for the
1541          entire project and are placed in self.OverallParms
1542        * Phase items are placed in self.Phases
1543        * Data items are placed in self.Histogram. The key for these data items
1544          begin with a keyword, such as PWDR, IMG, HKLF,... that identifies the data type.
1545        '''
1546        self.OverallParms = {}
1547        self.powderDict = {}
1548        self.xtalDict = {}
1549        self.Phases = {}
1550        self.Histograms = {}
1551        self.SeqRefdata = None
1552        self.SeqRefhist = None
1553        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
1554        histType = None       
1555        if self.currentExportType == 'phase':
1556            # if exporting phases load them here
1557            sub = G2gd.GetPatternTreeItemId(self.G2frame,self.G2frame.root,'Phases')
1558            if not sub:
1559                print 'no phases found'
1560                return True
1561            item, cookie = self.G2frame.PatternTree.GetFirstChild(sub)
1562            while item:
1563                phaseName = self.G2frame.PatternTree.GetItemText(item)
1564                self.Phases[phaseName] =  self.G2frame.PatternTree.GetItemPyData(item)
1565                item, cookie = self.G2frame.PatternTree.GetNextChild(sub, cookie)
1566            return
1567        elif self.currentExportType == 'single':
1568            histType = 'HKLF'
1569        elif self.currentExportType == 'powder':
1570            histType = 'PWDR'
1571        elif self.currentExportType == 'image':
1572            histType = 'IMG'
1573
1574        if histType: # Loading just one kind of tree entry
1575            item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
1576            while item:
1577                name = self.G2frame.PatternTree.GetItemText(item)
1578                if name.startswith(histType):
1579                    if self.Histograms.get(name): # there is already an item with this name
1580                        print('Histogram name '+str(name)+' is repeated. Renaming')
1581                        if name[-1] == '9':
1582                            name = name[:-1] + '10'
1583                        elif name[-1] in '012345678':
1584                            name = name[:-1] + str(int(name[-1])+1)
1585                        else:                           
1586                            name += '-1'
1587                    self.Histograms[name] = {}
1588                    # the main info goes into Data, but the 0th
1589                    # element contains refinement results, carry
1590                    # that over too now.
1591                    self.Histograms[name]['Data'] = self.G2frame.PatternTree.GetItemPyData(item)[1]
1592                    self.Histograms[name][0] = self.G2frame.PatternTree.GetItemPyData(item)[0]
1593                    item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
1594                    while item2: 
1595                        child = self.G2frame.PatternTree.GetItemText(item2)
1596                        self.Histograms[name][child] = self.G2frame.PatternTree.GetItemPyData(item2)
1597                        item2, cookie2 = self.G2frame.PatternTree.GetNextChild(item, cookie2)
1598                item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
1599            # index powder and single crystal histograms by number
1600            for hist in self.Histograms:
1601                if hist.startswith("PWDR"): 
1602                    d = self.powderDict
1603                elif hist.startswith("HKLF"): 
1604                    d = self.xtalDict
1605                else:
1606                    return                   
1607                i = self.Histograms[hist].get('hId')
1608                if i is None and not d.keys():
1609                    i = 0
1610                elif i is None or i in d.keys():
1611                    i = max(d.keys())+1
1612                d[i] = hist
1613            return
1614        # else standard load: using all interlinked phases and histograms
1615        self.Histograms,self.Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
1616        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
1617        while item:
1618            name = self.G2frame.PatternTree.GetItemText(item)
1619            item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
1620            if not item2: 
1621                self.OverallParms[name] = self.G2frame.PatternTree.GetItemPyData(item)
1622            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
1623        # index powder and single crystal histograms
1624        for hist in self.Histograms:
1625            i = self.Histograms[hist]['hId']
1626            if hist.startswith("PWDR"): 
1627                self.powderDict[i] = hist
1628            elif hist.startswith("HKLF"): 
1629                self.xtalDict[i] = hist
1630
1631    def dumpTree(self,mode='type'):
1632        '''Print out information on the data tree dicts loaded in loadTree.
1633        Used for testing only.
1634        '''
1635        if self.SeqRefdata and self.SeqRefhist:
1636            print('Note that dumpTree does not show sequential results')
1637        print '\nOverall'
1638        if mode == 'type':
1639            def Show(arg): return type(arg)
1640        else:
1641            def Show(arg): return arg
1642        for key in self.OverallParms:
1643            print '  ',key,Show(self.OverallParms[key])
1644        print 'Phases'
1645        for key1 in self.Phases:
1646            print '    ',key1,Show(self.Phases[key1])
1647        print 'Histogram'
1648        for key1 in self.Histograms:
1649            print '    ',key1,Show(self.Histograms[key1])
1650            for key2 in self.Histograms[key1]:
1651                print '      ',key2,Show(self.Histograms[key1][key2])
1652
1653    def defaultSaveFile(self):
1654        return os.path.abspath(
1655            os.path.splitext(self.G2frame.GSASprojectfile
1656                             )[0]+self.extension)
1657       
1658    def askSaveFile(self):
1659        '''Ask the user to supply a file name
1660
1661        :returns: a file name (str) or None if Cancel is pressed
1662        '''
1663       
1664        pth = G2G.GetExportPath(self.G2frame)
1665        defnam = os.path.splitext(
1666            os.path.split(self.G2frame.GSASprojectfile)[1]
1667            )[0]+self.extension
1668        dlg = wx.FileDialog(
1669            self.G2frame, 'Input name for file to write', pth, defnam,
1670            self.longFormatName+' (*'+self.extension+')|*'+self.extension,
1671            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1672        dlg.CenterOnParent()
1673        try:
1674            if dlg.ShowModal() == wx.ID_OK:
1675                filename = dlg.GetPath()
1676                self.G2frame.LastExportDir = os.path.split(filename)[0]
1677                filename = os.path.splitext(filename)[0]+self.extension # make sure extension is correct
1678            else:
1679                filename = None
1680        finally:
1681            dlg.Destroy()
1682        return filename
1683
1684    def askSaveDirectory(self):
1685        '''Ask the user to supply a directory name. Path name is used as the
1686        starting point for the next export path search.
1687
1688        :returns: a directory name (str) or None if Cancel is pressed
1689        '''
1690        pth = G2G.GetExportPath(self.G2frame)
1691        dlg = wx.DirDialog(
1692            self.G2frame, 'Input directory where file(s) will be written', pth,
1693            wx.DD_DEFAULT_STYLE)
1694        dlg.CenterOnParent()
1695        try:
1696            if dlg.ShowModal() == wx.ID_OK:
1697                filename = dlg.GetPath()
1698                self.G2frame.LastExportDir = filename
1699            else:
1700                filename = None
1701        finally:
1702            dlg.Destroy()
1703        return filename
1704
1705    # Tools for file writing.
1706    def OpenFile(self,fil=None,mode='w'):
1707        '''Open the output file
1708
1709        :param str fil: The name of the file to open. If None (default)
1710          the name defaults to self.dirname + self.filename.
1711          If an extension is supplied, it is not overridded,
1712          but if not, the default extension is used.
1713        :returns: the file object opened by the routine which is also
1714          saved as self.fp
1715        '''
1716        if mode == 'd': # debug mode
1717            self.fullpath = '(stdout)'
1718            self.fp = sys.stdout
1719            return
1720        if not fil:
1721            if not os.path.splitext(self.filename)[1]:
1722                self.filename += self.extension
1723            fil = os.path.join(self.dirname,self.filename)
1724        self.fullpath = os.path.abspath(fil)
1725        self.fp = open(self.fullpath,mode)
1726        return self.fp
1727
1728    def Write(self,line):
1729        '''write a line of output, attaching a line-end character
1730
1731        :param str line: the text to be written.
1732        '''
1733        self.fp.write(line+'\n')
1734       
1735    def CloseFile(self,fp=None):
1736        '''Close a file opened in OpenFile
1737
1738        :param file fp: the file object to be closed. If None (default)
1739          file object self.fp is closed.
1740        '''
1741        if self.fp == sys.stdout: return # debug mode
1742        if fp is None:
1743            fp = self.fp
1744            self.fp = None
1745        fp.close()
1746       
1747    def SetSeqRef(self,data,hist):
1748        '''Set the exporter to retrieve results from a sequential refinement
1749        rather than the main tree
1750        '''
1751        self.SeqRefdata = data
1752        self.SeqRefhist = hist
1753        data_name = data[hist]
1754        for i,val in zip(data_name['varyList'],data_name['sig']):
1755            self.sigDict[i] = val
1756            self.sigDict[striphist(i)] = val
1757        for i in data_name['parmDict']:
1758            self.parmDict[striphist(i)] = data_name['parmDict'][i]
1759            self.parmDict[i] = data_name['parmDict'][i]
1760            # zero out the dA[xyz] terms, they would only bring confusion
1761            key = i.split(':')
1762            if len(key) < 3: continue
1763            if key[2].startswith('dA'):
1764                self.parmDict[i] = 0.0
1765        for i,(val,sig) in data_name.get('depParmDict',{}).iteritems():
1766            self.parmDict[i] = val
1767            self.sigDict[i] = sig
1768        #GSASIIpath.IPyBreak()
1769               
1770    # Tools to pull information out of the data arrays
1771    def GetCell(self,phasenam):
1772        """Gets the unit cell parameters and their s.u.'s for a selected phase
1773
1774        :param str phasenam: the name for the selected phase
1775        :returns: `cellList,cellSig` where each is a 7 element list corresponding
1776          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
1777          cell values and `cellSig` has their uncertainties.
1778        """
1779        if self.SeqRefdata and self.SeqRefhist:
1780            return self.GetSeqCell(phasenam,self.SeqRefdata[self.SeqRefhist])
1781        phasedict = self.Phases[phasenam] # pointer to current phase info
1782        try:
1783            pfx = str(phasedict['pId'])+'::'
1784            A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict)
1785            cellSig = G2stIO.getCellEsd(pfx,phasedict['General']['SGData'],A,
1786                self.OverallParms['Covariance'])  # returns 7 vals, includes sigVol
1787            cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)
1788            return cellList,cellSig
1789        except KeyError:
1790            cell = phasedict['General']['Cell'][1:]
1791            return cell,7*[0]
1792           
1793    def GetSeqCell(self,phasenam,data_name):
1794        """Gets the unit cell parameters and their s.u.'s for a selected phase
1795        and histogram in a sequential fit
1796
1797        :param str phasenam: the name for the selected phase
1798        :param dict data_name: the sequential refinement parameters for the selected histogram
1799        :returns: `cellList,cellSig` where each is a 7 element list corresponding
1800          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
1801          cell values and `cellSig` has their uncertainties.
1802        """
1803        phasedict = self.Phases[phasenam]
1804        SGdata = phasedict['General']['SGData']
1805        pId = phasedict['pId']
1806        RecpCellTerms = G2lat.cell2A(phasedict['General']['Cell'][1:7])
1807        ESDlookup = {}
1808        Dlookup = {}
1809        varied = [striphist(i) for i in data_name['varyList']]
1810        for item,val in data_name['newCellDict'].iteritems():
1811            if item in varied:
1812                ESDlookup[val[0]] = item
1813                Dlookup[item] = val[0]
1814        A = RecpCellTerms[:]
1815        for i in range(6):
1816            var = str(pId)+'::A'+str(i)
1817            if var in ESDlookup:
1818                A[i] = data_name['newCellDict'][ESDlookup[var]][1] # override with refined value
1819        cellDict = dict(zip([str(pId)+'::A'+str(i) for i in range(6)],A))
1820        zeroDict = {i:0.0 for i in cellDict}
1821        A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata,cellDict,zeroDict)
1822        covData = {
1823            'varyList': [Dlookup.get(striphist(v),v) for v in data_name['varyList']],
1824            'covMatrix': data_name['covMatrix']
1825            }
1826        return list(G2lat.A2cell(A)) + [G2lat.calc_V(A)], G2stIO.getCellEsd(str(pId)+'::',SGdata,A,covData)
1827               
1828    def GetAtoms(self,phasenam):
1829        """Gets the atoms associated with a phase. Can be used with standard
1830        or macromolecular phases
1831
1832        :param str phasenam: the name for the selected phase
1833        :returns: a list of items for eac atom where each item is a list containing:
1834          label, typ, mult, xyz, and td, where
1835
1836          * label and typ are the atom label and the scattering factor type (str)
1837          * mult is the site multiplicity (int)
1838          * xyz is contains a list with four pairs of numbers:
1839            x, y, z and fractional occupancy and
1840            their standard uncertainty (or a negative value)
1841          * td is contains a list with either one or six pairs of numbers:
1842            if one number it is U\ :sub:`iso` and with six numbers it is
1843            U\ :sub:`11`, U\ :sub:`22`, U\ :sub:`33`, U\ :sub:`12`, U\ :sub:`13` & U\ :sub:`23`
1844            paired with their standard uncertainty (or a negative value)
1845        """
1846        phasedict = self.Phases[phasenam] # pointer to current phase info           
1847        cx,ct,cs,cia = phasedict['General']['AtomPtrs']
1848        cfrac = cx+3
1849        fpfx = str(phasedict['pId'])+'::Afrac:'       
1850        atomslist = []
1851        for i,at in enumerate(phasedict['Atoms']):
1852            if phasedict['General']['Type'] == 'macromolecular':
1853                label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2])
1854            else:
1855                label = at[ct-1]
1856            fval = self.parmDict.get(fpfx+str(i),at[cfrac])
1857            fsig = self.sigDict.get(fpfx+str(i),-0.009)
1858            mult = at[cs+1]
1859            typ = at[ct]
1860            xyz = []
1861            for j,v in enumerate(('x','y','z')):
1862                val = at[cx+j]
1863                pfx = str(phasedict['pId']) + '::A' + v + ':' + str(i)
1864                val = self.parmDict.get(pfx, val)
1865                dpfx = str(phasedict['pId'])+'::dA'+v+':'+str(i)
1866                sig = self.sigDict.get(dpfx,-0.000009)
1867                xyz.append((val,sig))
1868            xyz.append((fval,fsig))
1869            td = []
1870            if at[cia] == 'I':
1871                pfx = str(phasedict['pId'])+'::AUiso:'+str(i)
1872                val = self.parmDict.get(pfx,at[cia+1])
1873                sig = self.sigDict.get(pfx,-0.0009)
1874                td.append((val,sig))
1875            else:
1876                for i,var in enumerate(('AU11','AU22','AU33','AU12','AU13','AU23')):
1877                    pfx = str(phasedict['pId'])+'::'+var+':'+str(i)
1878                    val = self.parmDict.get(pfx,at[cia+2+i])
1879                    sig = self.sigDict.get(pfx,-0.0009)
1880                    td.append((val,sig))
1881            atomslist.append((label,typ,mult,xyz,td))
1882        return atomslist
1883######################################################################
1884def ExportPowderList(G2frame):
1885    '''Returns a list of extensions supported by :func:`GSASIIIO:ExportPowder`
1886    This is used in :meth:`GSASIIimgGUI.AutoIntFrame` only.
1887   
1888    :param wx.Frame G2frame: the GSAS-II main data tree window
1889    '''
1890    extList = []
1891    for obj in G2frame.exporterlist:
1892        if 'powder' in obj.exporttype:
1893            try:
1894                obj.Writer
1895                extList.append(obj.extension)
1896            except AttributeError:
1897                pass
1898    return extList
1899
1900def ExportPowder(G2frame,TreeName,fileroot,extension):
1901    '''Writes a single powder histogram using the Export routines.
1902    This is used in :meth:`GSASIIimgGUI.AutoIntFrame` only.
1903
1904    :param wx.Frame G2frame: the GSAS-II main data tree window
1905    :param str TreeName: the name of the histogram (PWDR ...) in the data tree
1906    :param str fileroot: name for file to be written, extension ignored
1907    :param str extension: extension for file to be written (start with '.'). Must
1908      match a powder export routine that has a Writer object.
1909    '''
1910    filename = os.path.abspath(os.path.splitext(fileroot)[0]+extension)
1911    for obj in G2frame.exporterlist:
1912        if obj.extension == extension and 'powder' in obj.exporttype:
1913            obj.currentExportType = 'powder'
1914            obj.InitExport(None)
1915            obj.loadTree() # load all histograms in tree into dicts
1916            if TreeName not in obj.Histograms:
1917                raise Exception('Histogram not found: '+str(TreeName))
1918            try:
1919                obj.Writer
1920            except AttributeError:
1921                continue
1922            try:
1923                obj.Writer(TreeName,filename)
1924                return
1925            except Exception,err:
1926                print('Export Routine for '+extension+' failed.')
1927                print err
1928    else:
1929        print('No Export routine supports extension '+extension)
1930
1931def ExportSequential(G2frame,data,obj,exporttype):
1932    '''
1933    Used to export from every phase/dataset in a sequential refinement using
1934    a .Writer method for either projects or phases. Prompts to select histograms
1935    and for phase exports, which phase(s).
1936
1937    :param wx.Frame G2frame: the GSAS-II main data tree window
1938    :param dict data: the sequential refinement data object
1939    :param str exporttype: indicates the type of export ('project' or 'phase')
1940    '''
1941    if len(data['histNames']) == 0:
1942        G2G.G2MessageBox(G2frame,'There are no sequential histograms','Warning')
1943    obj.InitExport(None)
1944    obj.loadTree()
1945    obj.loadParmDict()
1946    if len(data['histNames']) == 1:
1947        histlist = data['histNames']
1948    else:
1949        dlg = G2G.G2MultiChoiceDialog(G2frame,'Select histograms to export from list',
1950                                 'Select histograms',data['histNames'])
1951        if dlg.ShowModal() == wx.ID_OK:
1952            histlist = [data['histNames'][l] for l in dlg.GetSelections()]
1953            dlg.Destroy()
1954        else:
1955            dlg.Destroy()
1956            return
1957    if exporttype == 'Phase':
1958        phaselist = obj.Phases.keys()
1959        if len(obj.Phases) == 0:
1960            G2G.G2MessageBox(G2frame,'There are no phases in sequential ref.','Warning')
1961            return
1962        elif len(obj.Phases) > 1:
1963            dlg = G2G.G2MultiChoiceDialog(G2frame,'Select phases to export from list',
1964                                    'Select phases', phaselist)
1965            if dlg.ShowModal() == wx.ID_OK:
1966                phaselist = [phaselist[l] for l in dlg.GetSelections()]
1967                dlg.Destroy()
1968            else:
1969                dlg.Destroy()
1970                return
1971        filename = obj.askSaveFile()
1972        if not filename: return True
1973        obj.dirname,obj.filename = os.path.split(filename)
1974        print('Writing output to file '+str(obj.filename)+"...")
1975        mode = 'w'
1976        for p in phaselist:
1977            for h in histlist:
1978                obj.SetSeqRef(data,h)
1979                #GSASIIpath.IPyBreak()
1980                obj.Writer(h,phasenam=p,mode=mode)
1981                mode = 'a'
1982        print('...done')
1983    elif exporttype == 'Project':
1984        filename = obj.askSaveFile()
1985        if not filename: return True
1986        obj.dirname,obj.filename = os.path.split(filename)
1987        print('Writing output to file '+str(obj.filename)+"...")
1988        mode = 'w'
1989        for h in histlist:
1990            obj.SetSeqRef(data,h)
1991            obj.Writer(h,mode=mode)
1992            print('\t'+str(h)+' written')
1993            mode = 'a'
1994        print('...done')
1995
1996def ReadDIFFaX(DIFFaXfile):
1997    print 'read ',DIFFaXfile
1998    Layer = {'Laue':'-1','Cell':[False,1.,1.,1.,90.,90.,90,1.],'Width':[[10.,10.],[False,False]],
1999        'Layers':[],'Stacking':[],'Transitions':[],'Toler':0.01,'AtInfo':{}}
2000    df = open(DIFFaXfile,'r')
2001    lines = df.readlines()
2002    df.close()
2003    struct = False
2004    Struct = []
2005    stack = False
2006    Stack = []
2007    trans = False
2008    Trans = []
2009    for diff in lines:
2010        diff = diff[:-1].lower()
2011        if '!'  in diff:
2012            continue
2013        while '}' in diff: #strip comments
2014            iB = diff.index('{')
2015            iF = diff.index('}')+1
2016            if iB:
2017                diff = diff[:iB]
2018            else:
2019                diff = diff[iF:]
2020        if not diff:
2021            continue
2022        if diff.strip() == 'instrumental':
2023            continue
2024        if diff.strip() == 'structural':
2025            struct = True
2026            continue
2027        elif diff.strip() == 'stacking':
2028            struct = False
2029            stack = True
2030            continue
2031        elif diff.strip() == 'transitions':
2032            stack = False
2033            trans = True
2034            continue
2035        diff = diff.strip()
2036        if struct:
2037            if diff:
2038                Struct.append(diff)
2039        elif stack:
2040            if diff:
2041                Stack.append(diff)
2042        elif trans:
2043            if diff:
2044                Trans.append(diff)
2045   
2046#STRUCTURE records
2047    laueRec = Struct[1].split()
2048    Layer['Laue'] = laueRec[0]
2049    if Layer['Laue'] == 'unknown' and len(laueRec) > 1:
2050        Layer['Toler'] = float(laueRec[1])    #tolerance for 'unknown'?
2051    if Layer['Laue'] == '2/m(1)': Layer['Laue'] = '2/m(c)'
2052    if Layer['Laue'] == '2/m(2)': Layer['Laue'] = '2/m(ab)'
2053    cell = Struct[0].split()
2054    Layer['Cell'] = [False,float(cell[0]),float(cell[1]),float(cell[2]),90.,90.,float(cell[3]),1.0]
2055    nLayers = int(Struct[2])
2056    N = 3
2057    if 'layer' not in Struct[3]:
2058        N = 4
2059        if Struct[3] != 'infinite':
2060            width = Struct[3].split()
2061            Layer['Width'][0] = [float(width[0]),float(width[1])]
2062    for nL in range(nLayers):
2063        if '=' in Struct[N]:
2064            name = Struct[N].split('=')
2065            sameas = int(name[1])-1
2066            Layer['Layers'].append({'Name':name[0],'SameAs':Layer['Layers'][sameas]['Name'],'Symm':'None','Atoms':[]})
2067            N += 1
2068            continue
2069        Symm = 'None'
2070        if 'centro' in Struct[N+1]: Symm = '-1'
2071        Layer['Layers'].append({'Name':Struct[N],'SameAs':'','Symm':Symm,'Atoms':[]})
2072        N += 2
2073        while 'layer' not in Struct[N]:
2074            atom = Struct[N][4:].split()
2075            atomType = G2el.FixValence(Struct[N][:4].replace(' ','').strip().capitalize())
2076            if atomType not in Layer['AtInfo']:
2077                Layer['AtInfo'][atomType] = G2el.GetAtomInfo(atomType)
2078            atomName = '%s(%s)'%(atomType,atom[0])
2079            newVals = []
2080            for val in atom[1:6]:
2081                if '/' in val:
2082                    newVals.append(eval(val+'.'))
2083                else:
2084                    newVals.append(float(val))               
2085            atomRec = [atomName,atomType,newVals[0],newVals[1],newVals[2],newVals[4],newVals[3]/78.9568]
2086            Layer['Layers'][-1]['Atoms'].append(atomRec)
2087            N += 1
2088            if N > len(Struct)-1:
2089                break
2090#TRANSITIONS records
2091    transArray = []
2092    N = 0
2093    for i in range(nLayers):
2094        transArray.append([])
2095        for j in range(nLayers):
2096            vals = Trans[N].split()
2097            newVals = []
2098            for val in vals[:4]:
2099                if '/' in val:
2100                    newVals.append(eval(val+'.'))
2101                else:
2102                    newVals.append(float(val))
2103            transArray[-1].append(newVals+['',False])
2104            N += 1
2105    Layer['Transitions'] = transArray
2106#STACKING records
2107    Layer['Stacking'] = [Stack[0],'']
2108    if Stack[0] == 'recursive':
2109        Layer['Stacking'][1] = Stack[1]
2110    elif Stack[0] == 'explicit':
2111        if Stack[1] == 'random':
2112            Layer['Stacking'][1] = Stack[1]
2113        else:
2114            Layer['Stacking'][1] = 'list'
2115            Layer['Stacking'].append('')
2116            for stack in Stack[2:]:
2117                Layer['Stacking'][2] += ' '+stack
2118    return Layer
2119
2120if __name__ == '__main__':
2121    import GSASII
2122    application = GSASII.GSASIImain(0)
2123    G2frame = application.main
2124    #app = wx.PySimpleApp()
2125    #G2frame = wx.Frame(None) # create a frame
2126    #frm.Show(True)
2127    #filename = '/tmp/notzip.zip'
2128    #filename = '/tmp/all.zip'
2129    #filename = '/tmp/11bmb_7652.zip'
2130   
2131    #selection=None, confirmoverwrite=True, parent=None
2132    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
2133    #print ExtractFileFromZip(filename,multipleselect=True)
2134    #                         #confirmread=False, confirmoverwrite=False)
2135
2136    # choicelist=[ ('a','b','c'),
2137    #              ('test1','test2'),('no choice',)]
2138    # titles = [ 'a, b or c', 'tests', 'No option here']
2139    # dlg = MultipleChoicesDialog(
2140    #     choicelist,titles,
2141    #     parent=frm)
2142    # if dlg.ShowModal() == wx.ID_OK:
2143    #     print 'Got OK'
2144    imagefile = '/tmp/NDC5_00237_3.ge3'
2145    Comments, Data, Npix, Image = GetImageData(G2frame,imagefile,imageOnly=False,ImageTag=None)
2146
2147    print("\n\nResults loaded to Comments, Data, Npix and Image\n\n")
2148
2149    GSASIIpath.IPyBreak_base()
Note: See TracBrowser for help on using the repository browser.