source: trunk/GSASIIIO.py @ 2818

Last change on this file since 2818 was 2818, checked in by vondreele, 7 years ago

add GetPhaseNames?(fl) to G2obj - uses opened gpx file
fix PhaseSelector? & remove ShowBusy? & DoneBusy? from G2IO - not used ever

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