source: trunk/GSASIIIO.py @ 2011

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

fix image transpose error in ReadImageData?

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 113.8 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2015-10-16 17:33:33 +0000 (Fri, 16 Oct 2015) $
4# $Author: vondreele $
5# $Revision: 2011 $
6# $URL: trunk/GSASIIIO.py $
7# $Id: GSASIIIO.py 2011 2015-10-16 17:33:33Z 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 cPickle
28import sys
29import re
30import random as ran
31import GSASIIpath
32GSASIIpath.SetVersionNumber("$Revision: 2011 $")
33import GSASIIgrid as G2gd
34import GSASIIspc as G2spc
35import GSASIIobj as G2obj
36import GSASIIlattice as G2lat
37import GSASIIpwdGUI as G2pdG
38import GSASIIimage as G2img
39import GSASIIElem as G2el
40import GSASIIstrIO as G2stIO
41import GSASIImapvars as G2mv
42import GSASIIctrls as G2G
43import os
44import os.path as ospath
45
46DEBUG = False       #=True for various prints
47TRANSP = False      #=true to transpose images for testing
48if GSASIIpath.GetConfigValue('Transpose'): TRANSP = True
49npsind = lambda x: np.sin(x*np.pi/180.)
50
51def sfloat(S):
52    'Convert a string to float. An empty field or a unconvertable value is treated as zero'
53    if S.strip():
54        try:
55            return float(S)
56        except ValueError:
57            pass
58    return 0.0
59
60def sint(S):
61    'Convert a string to int. An empty field is treated as zero'
62    if S.strip():
63        return int(S)
64    else:
65        return 0
66
67def trim(val):
68    '''Simplify a string containing leading and trailing spaces
69    as well as newlines, tabs, repeated spaces etc. into a shorter and
70    more simple string, by replacing all ranges of whitespace
71    characters with a single space.
72
73    :param str val: the string to be simplified
74
75    :returns: the (usually) shortened version of the string
76    '''
77    return re.sub('\s+', ' ', val).strip()
78
79def makeInstDict(names,data,codes):
80    inst = dict(zip(names,zip(data,data,codes)))
81    for item in inst:
82        inst[item] = list(inst[item])
83    return inst
84
85def FileDlgFixExt(dlg,file):
86    'this is needed to fix a problem in linux wx.FileDialog'
87    ext = dlg.GetWildcard().split('|')[2*dlg.GetFilterIndex()+1].strip('*')
88    if ext not in file:
89        file += ext
90    return file
91       
92def GetPowderPeaks(fileName):
93    'Read powder peaks from a file'
94    sind = lambda x: math.sin(x*math.pi/180.)
95    asind = lambda x: 180.*math.asin(x)/math.pi
96    Cuka = 1.54052
97    File = open(fileName,'Ur')
98    Comments = []
99    peaks = []
100    S = File.readline()
101    while S:
102        if S[:1] == '#':
103            Comments.append(S[:-1])
104        else:
105            item = S.split()
106            if len(item) == 1:
107                peaks.append([float(item[0]),1.0])
108            elif len(item) > 1:
109                peaks.append([float(item[0]),float(item[0])])
110        S = File.readline()
111    File.close()
112    if Comments:
113       print 'Comments on file:'
114       for Comment in Comments: print Comment
115    Peaks = []
116    if peaks[0][0] > peaks[-1][0]:          # d-spacings - assume CuKa
117        for peak in peaks:
118            dsp = peak[0]
119            sth = Cuka/(2.0*dsp)
120            if sth < 1.0:
121                tth = 2.0*asind(sth)
122            else:
123                break
124            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
125    else:                                   #2-thetas - assume Cuka (for now)
126        for peak in peaks:
127            tth = peak[0]
128            dsp = Cuka/(2.0*sind(tth/2.0))
129            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
130    return Comments,Peaks
131
132def CheckImageFile(G2frame,imagefile):
133    '''Try to locate an image file if the project and image have been moved
134    together. If the image file cannot be found, request the location from
135    the user.
136
137    :param wx.Frame G2frame: main GSAS-II Frame and data object
138    :param str imagefile: name of image file
139    :returns: imagefile, if it exists, or the name of a file
140      that does exist or False if the user presses Cancel
141
142    '''
143    if not os.path.exists(imagefile):
144        print 'Image file '+imagefile+' not found'
145        fil = imagefile.replace('\\','/') # windows?!
146        # see if we can find a file with same name or in a similarly named sub-dir
147        pth,fil = os.path.split(fil)
148        prevpth = None
149        while pth and pth != prevpth:
150            prevpth = pth
151            if os.path.exists(os.path.join(G2frame.dirname,fil)):
152                print 'found image file '+os.path.join(G2frame.dirname,fil)
153                return os.path.join(G2frame.dirname,fil)
154            pth,enddir = os.path.split(pth)
155            fil = os.path.join(enddir,fil)
156        # not found as a subdirectory, drop common parts of path for last saved & image file names
157        #    if image was .../A/B/C/imgs/ima.ge
158        #      & GPX was  .../A/B/C/refs/fil.gpx but is now .../NEW/TEST/TEST1
159        #    will look for .../NEW/TEST/TEST1/imgs/ima.ge, .../NEW/TEST/imgs/ima.ge, .../NEW/imgs/ima.ge and so on
160        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
161        gpxPath = Controls.get('LastSavedAs','').replace('\\','/').split('/') # blank in older .GPX files
162        imgPath = imagefile.replace('\\','/').split('/')
163        for p1,p2 in zip(gpxPath,imgPath):
164            if p1 == p2:
165                gpxPath.pop(0),imgPath.pop(0)
166            else:
167                break
168        fil = os.path.join(*imgPath) # file with non-common prefix elements
169        prevpth = None
170        pth = os.path.abspath(G2frame.dirname)
171        while pth and pth != prevpth:
172            prevpth = pth
173            if os.path.exists(os.path.join(pth,fil)):
174                print 'found image file '+os.path.join(pth,fil)
175                return os.path.join(pth,fil)
176            pth,enddir = os.path.split(pth)
177        #GSASIIpath.IPyBreak()
178
179    if not os.path.exists(imagefile):
180        dlg = wx.FileDialog(G2frame, 'Previous image file not found; open here', '.', '',\
181        'Any image file (*.edf;*.tif;*.tiff;*.mar*;*.ge*;*.avg;*.sum;*.img;*.cor;*.stl)\
182        |*.edf;*.tif;*.tiff;*.mar*;*.ge*;*.avg;*.sum;*.img;*.cor;*.stl|\
183        European detector file (*.edf)|*.edf|\
184        Any detector tif (*.tif;*.tiff)|*.tif;*.tiff|\
185        MAR file (*.mar*)|*.mar*|\
186        GE Image (*.ge*;*.avg;*.sum;*.cor)|*.ge*;*.avg;*.sum;*.cor|\
187        ADSC Image (*.img)|*.img|\
188        Rigaku-Axis4 (*.stl)|*.stl|\
189        All files (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
190        try:
191            dlg.SetFilename(''+ospath.split(imagefile)[1])
192            if dlg.ShowModal() == wx.ID_OK:
193                imagefile = dlg.GetPath()
194            else:
195                imagefile = False
196        finally:
197            dlg.Destroy()
198    return imagefile
199
200def EditImageParms(parent,Data,Comments,Image,filename):
201    dlg = wx.Dialog(parent, wx.ID_ANY, 'Edit image parameters',
202                    style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
203    def onClose(event):
204        dlg.EndModal(wx.ID_OK)
205    mainsizer = wx.BoxSizer(wx.VERTICAL)
206    h,w = Image.shape[:2]
207    mainsizer.Add(wx.StaticText(dlg,wx.ID_ANY,
208                                'File '+str(filename)+'\nImage size: '+str(h)+' x '+str(w)),
209                  0,wx.ALIGN_LEFT|wx.ALL, 2)
210   
211    vsizer = wx.BoxSizer(wx.HORIZONTAL)
212    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Wavelength (\xC5) '),
213               0,wx.ALIGN_LEFT|wx.ALL, 2)
214    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'wavelength')
215    vsizer.Add(wdgt)
216    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
217
218    vsizer = wx.BoxSizer(wx.HORIZONTAL)
219    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Pixel size (\xb5m). Width '),
220               0,wx.ALIGN_LEFT|wx.ALL, 2)
221    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],0,
222                                 size=(50,-1))
223    vsizer.Add(wdgt)
224    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Height '),
225               wx.ALIGN_LEFT|wx.ALL, 2)
226    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],1,
227                                 size=(50,-1))
228    vsizer.Add(wdgt)
229    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
230
231    vsizer = wx.BoxSizer(wx.HORIZONTAL)
232    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Sample to detector (mm) '),
233               0,wx.ALIGN_LEFT|wx.ALL, 2)
234    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'distance')
235    vsizer.Add(wdgt)
236    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
237
238    vsizer = wx.BoxSizer(wx.HORIZONTAL)
239    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Beam center (pixels). X = '),
240               0,wx.ALIGN_LEFT|wx.ALL, 2)
241    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],0,
242                                 size=(75,-1))
243    vsizer.Add(wdgt)
244    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Y = '),
245               wx.ALIGN_LEFT|wx.ALL, 2)
246    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],1,
247                                 size=(75,-1))
248    vsizer.Add(wdgt)
249    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
250
251    vsizer = wx.BoxSizer(wx.HORIZONTAL)
252    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Comments '),
253               0,wx.ALIGN_LEFT|wx.ALL, 2)
254    wdgt = G2G.ValidatedTxtCtrl(dlg,Comments,0,size=(250,-1))
255    vsizer.Add(wdgt)
256    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
257
258    btnsizer = wx.StdDialogButtonSizer()
259    OKbtn = wx.Button(dlg, wx.ID_OK, 'Continue')
260    OKbtn.SetDefault()
261    OKbtn.Bind(wx.EVT_BUTTON,onClose)
262    btnsizer.AddButton(OKbtn) # not sure why this is needed
263    btnsizer.Realize()
264    mainsizer.Add(btnsizer, 1, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 5)
265    dlg.SetSizer(mainsizer)
266    dlg.CenterOnParent()
267    dlg.ShowModal()
268   
269def ReadLoadImage(imagefile,G2frame):
270    '''Read a GSAS-II image file and load it into the data tree
271    '''
272    # if a zip file, open and extract
273    if os.path.splitext(imagefile)[1].lower() == '.zip':
274        extractedfile = ExtractFileFromZip(imagefile,parent=G2frame)
275        if extractedfile is not None and extractedfile != imagefile:
276            imagefile = extractedfile
277    Comments,Data,Npix,Image = GetImageData(G2frame,imagefile)
278    if Comments:
279        LoadImage(imagefile,G2frame,Comments,Data,Npix,Image)
280   
281def LoadImage(imagefile,G2frame,Comments,Data,Npix,Image):
282    '''Load an image into the tree
283    '''
284   
285    ImgNames = []
286    if G2frame.PatternTree.GetCount(): # get a list of existing Image entries
287        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
288        while item:
289            name = G2frame.PatternTree.GetItemText(item)
290            if name.startswith('IMG'): ImgNames.append(name)       
291            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
292    TreeName = G2obj.MakeUniqueLabel('IMG '+os.path.basename(imagefile),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    Imin = max(0.0,np.amin(Image))          #force positive
297    if G2frame.imageDefault:
298        Data = copy.copy(G2frame.imageDefault)
299        Data['showLines'] = True
300        Data['ring'] = []
301        Data['rings'] = []
302        Data['cutoff'] = 10
303        Data['pixLimit'] = 20
304        Data['edgemin'] = 100000000
305        Data['calibdmin'] = 0.5
306        Data['calibskip'] = 0
307        Data['ellipses'] = []
308        Data['calibrant'] = ''
309        Data['GonioAngles'] = [0.,0.,0.]
310        Data['DetDepthRef'] = False
311    else:
312        Data['type'] = 'PWDR'
313        Data['color'] = 'Paired'
314        Data['tilt'] = 0.0
315        Data['rotation'] = 0.0
316        Data['showLines'] = False
317        Data['ring'] = []
318        Data['rings'] = []
319        Data['cutoff'] = 10
320        Data['pixLimit'] = 20
321        Data['calibdmin'] = 0.5
322        Data['calibskip'] = 0
323        Data['edgemin'] = 100000000
324        Data['ellipses'] = []
325        Data['GonioAngles'] = [0.,0.,0.]
326        Data['DetDepth'] = 0.
327        Data['DetDepthRef'] = False
328        Data['calibrant'] = ''
329        Data['IOtth'] = [2.0,5.0]
330        Data['LRazimuth'] = [135,225]
331        Data['azmthOff'] = 0.0
332        Data['outChannels'] = 2500
333        Data['outAzimuths'] = 1
334        Data['centerAzm'] = False
335        Data['fullIntegrate'] = False
336        Data['setRings'] = False
337        Data['background image'] = ['',-1.0]                           
338        Data['dark image'] = ['',-1.0]
339        Data['Flat Bkg'] = 0.0
340    Data['setDefault'] = False
341    Data['range'] = [(Imin,Imax),[Imin,Imax]]
342    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Image Controls'),Data)
343    Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(Imin,Imax),[Imin,Imax]]}
344    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Masks'),Masks)
345    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Stress/Strain'),
346        {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
347    G2frame.PatternTree.SetItemPyData(Id,[Npix,imagefile])
348    G2frame.PickId = Id
349    G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
350    G2frame.Image = Id
351   
352def ReadImageData(G2frame,imagefile,imageOnly=False):
353    '''Read a single image with an image importer. replacement for GetImageData
354
355    :param wx.Frame G2frame: main GSAS-II Frame and data object.
356    :param str imagefile: name of image file
357    :param bool imageOnly: If True return only the image,
358      otherwise  (default) return more (see below)
359
360    :returns: an image as a numpy array or a list of four items:
361      Comments, Data, Npix and the Image, as selected by imageOnly
362
363    '''
364    # determine which formats are compatible with this file
365    print 'Debug: using ReadImageData'
366    primaryReaders = []
367    secondaryReaders = []
368    for rd in G2frame.ImportImageReaderlist:
369        flag = rd.ExtensionValidator(imagefile)
370        if flag is None: 
371            secondaryReaders.append(rd)
372        elif flag:
373            primaryReaders.append(rd)
374    if len(secondaryReaders) + len(primaryReaders) == 0:
375        print('Error: No matching format for file '+filename)
376        raise Exception('No image read')
377    fp = None
378    errorReport = ''
379    fp = open(imagefile,'Ur')
380    for rd in primaryReaders+secondaryReaders:
381        rd.ReInitialize() # purge anything from a previous read
382        fp.seek(0)  # rewind
383        rd.errors = "" # clear out any old errors
384        if not rd.ContentsValidator(fp): # rejected on cursory check
385            errorReport += "\n  "+rd.formatName + ' validator error'
386            if rd.errors: 
387                errorReport += ': '+rd.errors
388                continue 
389        rdbuffer = {} # create temporary storage for file reader
390        if GSASIIpath.GetConfigValue('debug'):
391            flag = rd.Reader(imagefile,fp,G2frame)
392        else:
393            flag = False
394            try:
395                flag = rd.Reader(imagefile,fp,G2frame)
396            except rd.ImportException as detail:
397                rd.errors += "\n  Read exception: "+str(detail)
398            except Exception as detail:
399                import traceback
400                rd.errors += "\n  Unhandled read exception: "+str(detail)
401                rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
402        if flag: # this read succeeded
403            if rd.Image is None:
404                raise Exception('No image read. Strange!')
405            if GSASIIpath.GetConfigValue('Transpose'):
406                rd.Image = rd.Image.T
407            #rd.readfilename = imagefile
408            if imageOnly:
409                return rd.Image
410            else:
411                return rd.Comments,rd.Data,rd.Npix,rd.Image
412    else:
413        print('Error reading file '+filename)
414        print('Error messages(s)\n'+errorReport)
415        raise Exception('No image read')
416   
417def GetImageData(G2frame,imagefile,imageOnly=False):
418    '''Read an image with the file reader keyed by the
419    file extension
420
421    :param wx.Frame G2frame: main GSAS-II Frame and data object.
422
423    :param str imagefile: name of image file
424
425    :param bool imageOnly: If True return only the image,
426      otherwise  (default) return more (see below)
427
428    :returns: an image as a numpy array or a list of four items:
429      Comments, Data, Npix and the Image, as selected by imageOnly
430
431    '''
432    if GSASIIpath.GetConfigValue('debug'):  # test out using replacement routine
433        return ReadImageData(G2frame,imagefile,imageOnly)
434   
435    ext = ospath.splitext(imagefile)[1]
436    Comments = []
437    Image = None
438    if ext == '.tif' or ext == '.tiff':
439        Comments,Data,Npix,Image = GetTifData(imagefile)
440        if Npix == 0:
441            print("GetTifData failed to read "+str(imagefile)+" Trying PIL")
442            import scipy.misc
443            Image = scipy.misc.imread(imagefile,flatten=True)
444            Npix = Image.size
445            Comments = ['no metadata']
446            Data = {'wavelength': 0.1, 'pixelSize': [200, 200], 'distance': 100.0}
447            Data['size'] = list(Image.shape)
448            Data['center'] = [int(i/2) for i in Image.shape]
449            if not imageOnly:
450                EditImageParms(G2frame,Data,Comments,Image,imagefile)
451    elif ext == '.edf':
452        Comments,Data,Npix,Image = GetEdfData(imagefile)
453    elif ext == '.img':
454        Comments,Data,Npix,Image = GetImgData(imagefile)
455        Image[0][0] = 0
456    elif ext in ['.mar3450','.mar2300','.mar2560']:
457        Comments,Data,Npix,Image = GetMAR345Data(imagefile)
458    elif ext in ['.sum','.avg','.cor'] or 'ge' in ext:
459        Comments,Data,Npix,Image = GetGEsumData(imagefile)
460    elif ext == '.G2img':
461        Comments,Data,Npix,Image = GetG2Image(imagefile)
462    elif ext == '.png':
463        Comments,Data,Npix,Image = GetPNGData(imagefile)
464        if not imageOnly:
465            EditImageParms(G2frame,Data,Comments,Image,imagefile)
466    elif ext == '.stl':
467        Comments,Data,Npix,Image = GetRigaku(imagefile)
468#        if not imageOnly:
469#            EditImageParms(G2frame,Data,Comments,Image,imagefile)
470    else:
471        print 'Extension for file '+imagefile+' not recognized'
472    if Image is None:
473        raise Exception('No image read')
474    if imageOnly:
475        print 'transpose:',TRANSP
476        if TRANSP:
477            return Image.T
478        else:
479            return Image
480    else:
481        print 'transpose:',TRANSP
482        if TRANSP:
483            return Comments,Data,Npix,Image.T
484        else:
485            return Comments,Data,Npix,Image
486       
487def PutG2Image(filename,Comments,Data,Npix,image):
488    'Write an image as a python pickle - might be better as an .edf file?'
489    File = open(filename,'wb')
490    cPickle.dump([Comments,Data,Npix,image],File,1)
491    File.close()
492    return
493   
494def GetG2Image(filename):
495    'Read an image as a python pickle'
496    File = open(filename,'rb')
497    Comments,Data,Npix,image = cPickle.load(File)
498    File.close()
499    return Comments,Data,Npix,image
500   
501def GetEdfData(filename,imageOnly=False):   
502    'Read European detector data edf file'
503    import struct as st
504    import array as ar
505    if not imageOnly:
506        print 'Read European detector data edf file: ',filename
507    File = open(filename,'rb')
508    fileSize = os.stat(filename).st_size
509    head = File.read(3072)
510    lines = head.split('\n')
511    sizexy = [0,0]
512    pixSize = [154,154]     #Pixium4700?
513    cent = [0,0]
514    wave = 1.54187  #default <CuKa>
515    dist = 1000.
516    head = ['European detector data',]
517    for line in lines:
518        line = line.replace(';',' ').strip()
519        fields = line.split()
520        if 'Dim_1' in line:
521            sizexy[0] = int(fields[2])
522        elif 'Dim_2' in line:
523            sizexy[1] = int(fields[2])
524        elif 'DataType' in line:
525            dType = fields[2]
526        elif 'wavelength' in line:
527            wave = float(fields[2])
528        elif 'Size' in line:
529            imSize = int(fields[2])
530#        elif 'DataType' in lines:
531#            dType = fields[2]
532        elif 'pixel_size_x' in line:
533            pixSize[0] = float(fields[2])
534        elif 'pixel_size_y' in line:
535            pixSize[1] = float(fields[2])
536        elif 'beam_center_x' in line:
537            cent[0] = float(fields[2])
538        elif 'beam_center_y' in line:
539            cent[1] = float(fields[2])
540        elif 'refined_distance' in line:
541            dist = float(fields[2])
542        if line:
543            head.append(line)
544        else:   #blank line at end of header
545            break 
546    File.seek(fileSize-imSize)
547    if dType == 'UnsignedShort':       
548        image = np.array(ar.array('H',File.read(imSize)),dtype=np.int32)
549    elif dType == 'UnsignedInt':
550        image = np.array(ar.array('L',File.read(imSize)),dtype=np.int32)
551    elif dType == 'UnsignedLong':
552        image = np.array(ar.array('L',File.read(imSize)),dtype=np.int32)
553    elif dType == 'SignedInteger':
554        image = np.array(ar.array('l',File.read(imSize)),dtype=np.int32)
555    image = np.reshape(image,(sizexy[1],sizexy[0]))
556    data = {'pixelSize':pixSize,'wavelength':wave,'distance':dist,'center':cent,'size':sizexy}
557    Npix = sizexy[0]*sizexy[1]
558    File.close()   
559    if imageOnly:
560        return image
561    else:
562        return head,data,Npix,image
563       
564def GetRigaku(filename,imageOnly=False):
565    'Read Rigaku R-Axis IV image file'
566    import struct as st
567    import array as ar
568    if not imageOnly:
569        print 'Read Rigaku R-Axis IV file: ',filename   
570    File = open(filename,'rb')
571    fileSize = os.stat(filename).st_size
572    Npix = (fileSize-6000)/2
573    Head = File.read(6000)
574    head = ['Rigaku R-Axis IV detector data',]
575    image = np.array(ar.array('H',File.read(fileSize-6000)),dtype=np.int32)
576    print fileSize,image.shape
577    print head
578    if Npix == 9000000:
579        sizexy = [3000,3000]
580        pixSize = [100.,100.]       
581    elif Npix == 2250000:
582        sizexy = [1500,1500]
583        pixSize = [200.,200.]
584    else:
585        sizexy = [6000,6000]
586        pixSize = [50.,50.] 
587    image = np.reshape(image,(sizexy[1],sizexy[0]))       
588    data = {'pixelSize':pixSize,'wavelength':1.5428,'distance':250.0,'center':[150.,150.],'size':sizexy} 
589    File.close()   
590    if imageOnly:
591        return image
592    else:
593        return head,data,Npix,image
594   
595def GetGEsumData(filename,imageOnly=False):
596    'Read SUM file as produced at 1-ID from G.E. images'
597    import struct as st
598    import array as ar
599    if not imageOnly:
600        print 'Read GE sum file: ',filename   
601    File = open(filename,'rb')
602    if '.sum' in filename or '.cor' in filename:
603        head = ['GE detector sum or cor data from APS 1-ID',]
604        sizexy = [2048,2048]
605    elif '.avg' in filename or '.ge' in filename:
606        head = ['GE detector avg or ge* data from APS 1-ID',]
607        sizexy = [2048,2048]
608    else:
609        head = ['GE detector raw data from APS 1-ID',]
610        File.seek(18)
611        size,nframes = st.unpack('<ih',File.read(6))
612        sizexy = [2048,2048]
613        pos = 8192
614        File.seek(pos)
615    Npix = sizexy[0]*sizexy[1]
616    if '.sum' in filename or '.cor' in filename:
617        image = np.array(ar.array('f',File.read(4*Npix)),dtype=np.int32)
618    elif '.avg' in filename or '.ge' in filename:
619        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
620    else:
621        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
622        while nframes > 1:
623            image += np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
624            nframes -= 1
625    image = np.reshape(image,(sizexy[1],sizexy[0]))
626    data = {'pixelSize':[200,200],'wavelength':0.15,'distance':250.0,'center':[204.8,204.8],'size':sizexy} 
627    File.close()   
628    if imageOnly:
629        return image
630    else:
631        return head,data,Npix,image
632       
633def GetImgData(filename,imageOnly=False):
634    'Read an ADSC image file'
635    import struct as st
636    import array as ar
637    if not imageOnly:
638        print 'Read ADSC img file: ',filename
639    File = open(filename,'rb')
640    head = File.read(511)
641    lines = head.split('\n')
642    head = []
643    center = [0,0]
644    for line in lines[1:-2]:
645        line = line.strip()[:-1]
646        if line:
647            if 'SIZE1' in line:
648                size = int(line.split('=')[1])
649                Npix = size*size
650            elif 'WAVELENGTH' in line:
651                wave = float(line.split('=')[1])
652            elif 'BIN' in line:
653                if line.split('=')[1] == '2x2':
654                    pixel=(102,102)
655                else:
656                    pixel = (51,51)
657            elif 'DISTANCE' in line:
658                distance = float(line.split('=')[1])
659            elif 'CENTER_X' in line:
660                center[0] = float(line.split('=')[1])
661            elif 'CENTER_Y' in line:
662                center[1] = float(line.split('=')[1])
663            head.append(line)
664    data = {'pixelSize':pixel,'wavelength':wave,'distance':distance,'center':center,'size':[size,size]}
665    image = []
666    row = 0
667    pos = 512
668    File.seek(pos)
669    image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
670    image = np.reshape(image,(sizexy[1],sizexy[0]))
671#    image = np.zeros(shape=(size,size),dtype=np.int32)   
672#    while row < size:
673#        File.seek(pos)
674#        line = ar.array('H',File.read(2*size))
675#        image[row] = np.asarray(line)
676#        row += 1
677#        pos += 2*size
678    File.close()
679    if imageOnly:
680        return image
681    else:
682        return lines[1:-2],data,Npix,image
683       
684def GetMAR345Data(filename,imageOnly=False):
685    'Read a MAR-345 image plate image'
686    import array as ar
687    import struct as st
688    try:
689        import pack_f as pf
690    except:
691        msg = wx.MessageDialog(None, message="Unable to load the GSAS MAR image decompression, pack_f",
692                               caption="Import Error",
693                               style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
694        msg.ShowModal()
695        return None,None,None,None
696
697    if not imageOnly:
698        print 'Read Mar345 file: ',filename
699    File = open(filename,'rb')
700    head = File.read(4095)
701    numbers = st.unpack('<iiiiiiiiii',head[:40])
702    lines = head[128:].split('\n')
703    head = []
704    for line in lines:
705        line = line.strip()
706        if 'PIXEL' in line:
707            values = line.split()
708            pixel = (int(values[2]),int(values[4]))     #in microns
709        elif 'WAVELENGTH' in line:
710            wave = float(line.split()[1])
711        elif 'DISTANCE' in line:
712            distance = float(line.split()[1])           #in mm
713        elif 'CENTER' in line:
714            values = line.split()
715            center = [float(values[2])/10.,float(values[4])/10.]    #make in mm from pixels
716        if line: 
717            head.append(line)
718    data = {'pixelSize':pixel,'wavelength':wave,'distance':distance,'center':center}
719    for line in head:
720        if 'FORMAT' in line[0:6]:
721            items = line.split()
722            sizex = int(items[1])
723            Npix = int(items[3])
724            sizey = int(Npix/sizex)
725    pos = 4096
726    data['size'] = [sizex,sizey]
727    File.seek(pos)
728    line = File.read(8)
729    while 'CCP4' not in line:       #get past overflow list for now
730        line = File.read(8)
731        pos += 8
732    pos += 37
733    File.seek(pos)
734    raw = File.read()
735    File.close()
736    image = np.zeros(shape=(sizex,sizey),dtype=np.int32)
737   
738    image = np.flipud(pf.pack_f(len(raw),raw,sizex,sizey,image).T)  #transpose to get it right way around & flip
739    if imageOnly:
740        return image
741    else:
742        return head,data,Npix,image
743       
744def GetPNGData(filename,imageOnly=False):
745    '''Read an image in a png format, assumes image is converted from CheMin tif file
746    so default parameters are that machine.
747    '''
748    import scipy.misc
749    Image = scipy.misc.imread(filename,flatten=True)
750    Npix = Image.size
751    Comments = ['no metadata']
752    pixy = list(Image.shape)
753    sizexy = [40,40]
754    Data = {'wavelength': 1.78892, 'pixelSize': sizexy, 'distance': 18.0,'size':pixy}
755    Data['center'] = [pixy[0]*sizexy[0]/1000,pixy[1]*sizexy[1]/2000]
756    if imageOnly:
757        return Image.T
758    else:
759        return Comments,Data,Npix,Image.T
760
761def GetTifData(filename,imageOnly=False):
762    '''Read an image in a pseudo-tif format,
763    as produced by a wide variety of software, almost always
764    incorrectly in some way.
765    '''
766    import struct as st
767    try:
768        import Image as Im
769    except ImportError:
770        try:
771            from PIL import Image as Im
772        except ImportError:
773            print "PIL/pillow Image module not present. TIFs cannot be read without this"
774            raise Exception("PIL/pillow Image module not found")
775    import array as ar
776    import ReadMarCCDFrame as rmf
777    File = open(filename,'rb')
778    dataType = 5
779    center = [None,None]
780    wavelength = None
781    distance = None
782    try:
783        Meta = open(filename+'.metadata','Ur')
784        head = Meta.readlines()
785        for line in head:
786            line = line.strip()
787            if 'dataType=' in line:
788                dataType = int(line.split('=')[1])
789        Meta.close()
790    except IOError:
791        print 'no metadata file found - will try to read file anyway'
792        head = ['no metadata file found',]
793       
794    tag = File.read(2)
795    byteOrd = '<'
796    if tag == 'II' and int(st.unpack('<h',File.read(2))[0]) == 42:     #little endian
797        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])
798    elif tag == 'MM' and int(st.unpack('>h',File.read(2))[0]) == 42:   #big endian
799        byteOrd = '>'
800        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])       
801    else:
802        lines = ['not a detector tiff file',]
803        return lines,0,0,0
804    File.seek(IFD)                                                  #get number of directory entries
805    NED = int(st.unpack(byteOrd+'h',File.read(2))[0])
806    IFD = {}
807    nSlice = 1
808    for ied in range(NED):
809        Tag,Type = st.unpack(byteOrd+'Hh',File.read(4))
810        nVal = st.unpack(byteOrd+'i',File.read(4))[0]
811        if DEBUG: print 'Try:',Tag,Type,nVal
812        if Type == 1:
813            Value = st.unpack(byteOrd+nVal*'b',File.read(nVal))
814        elif Type == 2:
815            Value = st.unpack(byteOrd+'i',File.read(4))
816        elif Type == 3:
817            Value = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
818            x = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
819        elif Type == 4:
820            if Tag in [273,279]:
821                nSlice = nVal
822                nVal = 1
823            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
824        elif Type == 5:
825            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
826        elif Type == 11:
827            Value = st.unpack(byteOrd+nVal*'f',File.read(nVal*4))
828        IFD[Tag] = [Type,nVal,Value]
829        if DEBUG: print Tag,IFD[Tag]
830    sizexy = [IFD[256][2][0],IFD[257][2][0]]
831    [nx,ny] = sizexy
832    Npix = nx*ny
833    if 34710 in IFD:
834        if not imageOnly:
835            print 'Read MAR CCD tiff file: ',filename
836        marFrame = rmf.marFrame(File,byteOrd,IFD)
837        image = np.flipud(np.array(np.asarray(marFrame.image),dtype=np.int32))
838        tifType = marFrame.filetitle
839        pixy = [marFrame.pixelsizeX/1000.0,marFrame.pixelsizeY/1000.0]
840        head = marFrame.outputHead()
841# extract resonable wavelength from header
842        wavelength = marFrame.sourceWavelength*1e-5
843        wavelength = (marFrame.opticsWavelength > 0) and marFrame.opticsWavelength*1e-5 or wavelength
844        wavelength = (wavelength <= 0) and None or wavelength
845# extract resonable distance from header
846        distance = (marFrame.startXtalToDetector+marFrame.endXtalToDetector)*5e-4
847        distance = (distance <= 0) and marFrame.xtalToDetector*1e-3 or distance
848        distance = (distance <= 0) and None or distance
849# extract resonable center from header
850        center = [marFrame.beamX*marFrame.pixelsizeX*1e-9,marFrame.beamY*marFrame.pixelsizeY*1e-9]
851        center = (center[0] != 0 and center[1] != 0) and center or [None,None]
852#print head,tifType,pixy
853    elif nSlice > 1:    #CheMin multislice tif file!
854        tifType = 'CheMin'
855        pixy = [40,40]
856        image = np.flipud(np.array(Im.open(filename)))*10.
857        distance = 18.0
858        center = [pixy[0]*sizexy[0]/2000,0]     #the CheMin beam stop is here
859        wavelength = 1.78892
860    elif 272 in IFD:
861        ifd = IFD[272]
862        File.seek(ifd[2][0])
863        S = File.read(ifd[1])
864        if 'PILATUS' in S:
865            tifType = 'Pilatus'
866            dataType = 0
867            pixy = [172,172]
868            File.seek(4096)
869            if not imageOnly:
870                print 'Read Pilatus tiff file: ',filename
871            image = ar.array('L',File.read(4*Npix))
872            image = np.array(np.asarray(image),dtype=np.int32)
873        else:
874            if IFD[258][2][0] == 16:
875                tifType = 'GE'
876                pixy = [200,200]
877                File.seek(8)
878                if not imageOnly:
879                    print 'Read GE-detector tiff file: ',filename
880                image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
881            elif IFD[258][2][0] == 32:
882                tifType = 'CHESS'
883                pixy = [200,200]
884                File.seek(8)
885                if not imageOnly:
886                    print 'Read CHESS-detector tiff file: ',filename
887                image = np.array(ar.array('L',File.read(4*Npix)),dtype=np.int32)
888           
889    elif 262 in IFD and IFD[262][2][0] > 4:
890        tifType = 'DND'
891        pixy = [158,158]
892        File.seek(512)
893        if not imageOnly:
894            print 'Read DND SAX/WAX-detector tiff file: ',filename
895        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
896    elif sizexy == [1536,1536]:
897        tifType = 'APS Gold'
898        pixy = [150,150]
899        File.seek(64)
900        if not imageOnly:
901            print 'Read Gold tiff file:',filename
902        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
903    elif sizexy == [2048,2048] or sizexy == [1024,1024] or sizexy == [3072,3072]:
904        if IFD[273][2][0] == 8:
905            if IFD[258][2][0] == 32:
906                tifType = 'PE'
907                pixy = [200,200]
908                File.seek(8)
909                if not imageOnly:
910                    print 'Read APS PE-detector tiff file: ',filename
911                if dataType == 5:
912                    image = np.array(ar.array('f',File.read(4*Npix)),dtype=np.float32)
913                else:
914                    image = np.array(ar.array('I',File.read(4*Npix)),dtype=np.int32)
915            elif IFD[258][2][0] == 16: 
916                tifType = 'MedOptics D1'
917                pixy = [46.9,46.9]
918                File.seek(8)
919                if not imageOnly:
920                    print 'Read MedOptics D1 tiff file: ',filename
921                image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
922                 
923        elif IFD[273][2][0] == 4096:
924            if sizexy[0] == 3072:
925                pixy =  [73,73]
926                tifType = 'MAR225'           
927            else:
928                pixy = [158,158]
929                tifType = 'MAR325'           
930            File.seek(4096)
931            if not imageOnly:
932                print 'Read MAR CCD tiff file: ',filename
933            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
934        elif IFD[273][2][0] == 512:
935            tiftype = '11-ID-C'
936            pixy = [200,200]
937            File.seek(512)
938            if not imageOnly:
939                print 'Read 11-ID-C tiff file: ',filename
940            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)           
941    elif sizexy == [4096,4096]:
942        if IFD[273][2][0] == 8:
943            if IFD[258][2][0] == 16:
944                tifType = 'scanCCD'
945                pixy = [9,9]
946                File.seek(8)
947                if not imageOnly:
948                    print 'Read APS scanCCD tiff file: ',filename
949                image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
950        elif IFD[273][2][0] == 4096:
951            tifType = 'Rayonix'
952            pixy = [73.242,73.242]
953            File.seek(4096)
954            if not imageOnly:
955                print 'Read Rayonix MX300HE tiff file: ',filename
956            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
957#    elif sizexy == [960,960]:
958#        tiftype = 'PE-BE'
959#        pixy = (200,200)
960#        File.seek(8)
961#        if not imageOnly:
962#            print 'Read Gold tiff file:',filename
963#        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
964           
965    else:
966        lines = ['not a known detector tiff file',]
967        return lines,0,0,0
968       
969    image = np.reshape(image,(sizexy[1],sizexy[0]))
970    center = (not center[0]) and [pixy[0]*sizexy[0]/2000,pixy[1]*sizexy[1]/2000] or center
971    wavelength = (not wavelength) and 0.10 or wavelength
972    distance = (not distance) and 100.0 or distance
973    data = {'pixelSize':pixy,'wavelength':wavelength,'distance':distance,'center':center,'size':sizexy}
974    File.close()   
975    if imageOnly:
976        return image
977    else:
978        return head,data,Npix,image
979   
980#def GetTifData(filename,imageOnly=False):
981#    import struct as st
982#    import array as ar
983#    File = open(filename,'rb')
984#    dataType = 5
985#    try:
986#        Meta = open(filename+'.metadata','Ur')
987#        head = Meta.readlines()
988#        for line in head:
989#            line = line.strip()
990#            if 'dataType=' in line:
991#                dataType = int(line.split('=')[1])
992#        Meta.close()
993#    except IOError:
994#        print 'no metadata file found - will try to read file anyway'
995#        head = ['no metadata file found',]
996#       
997#    tag = File.read(2)
998#    byteOrd = '<'
999#    if tag == 'II' and int(st.unpack('<h',File.read(2))[0]) == 42:     #little endian
1000#        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])
1001#    elif tag == 'MM' and int(st.unpack('>h',File.read(2))[0]) == 42:   #big endian
1002#        byteOrd = '>'
1003#        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])       
1004#    else:
1005#        lines = ['not a detector tiff file',]
1006#        return lines,0,0,0
1007#    File.seek(IFD)                                                  #get number of directory entries
1008#    NED = int(st.unpack(byteOrd+'h',File.read(2))[0])
1009#    IFD = {}
1010#    for ied in range(NED):
1011#        Tag,Type = st.unpack(byteOrd+'Hh',File.read(4))
1012#        nVal = st.unpack(byteOrd+'i',File.read(4))[0]
1013#        if Type == 1:
1014#            Value = st.unpack(byteOrd+nVal*'b',File.read(nVal))
1015#        elif Type == 2:
1016#            Value = st.unpack(byteOrd+'i',File.read(4))
1017#        elif Type == 3:
1018#            Value = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
1019#            x = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
1020#        elif Type == 4:
1021#            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
1022#        elif Type == 5:
1023#            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
1024#        elif Type == 11:
1025#            Value = st.unpack(byteOrd+nVal*'f',File.read(nVal*4))
1026#        IFD[Tag] = [Type,nVal,Value]
1027##        print Tag,IFD[Tag]
1028#    sizexy = [IFD[256][2][0],IFD[257][2][0]]
1029#    [nx,ny] = sizexy
1030#    Npix = nx*ny
1031#    if 272 in IFD:
1032#        ifd = IFD[272]
1033#        File.seek(ifd[2][0])
1034#        S = File.read(ifd[1])
1035#        if 'PILATUS' in S:
1036#            tifType = 'Pilatus'
1037#            dataType = 0
1038#            pixy = (172,172)
1039#            File.seek(4096)
1040#            if not imageOnly:
1041#                print 'Read Pilatus tiff file: ',filename
1042#            image = ar.array('L',File.read(4*Npix))
1043#            image = np.array(np.asarray(image),dtype=np.int32)
1044#    elif 262 in IFD and IFD[262][2][0] > 4:
1045#        tifType = 'DND'
1046#        pixy = (158,158)
1047#        File.seek(512)
1048#        if not imageOnly:
1049#            print 'Read DND SAX/WAX-detector tiff file: ',filename
1050#        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
1051#    elif sizexy == [1536,1536]:
1052#        tifType = 'APS Gold'
1053#        pixy = (150,150)
1054#        File.seek(64)
1055#        if not imageOnly:
1056#            print 'Read Gold tiff file:',filename
1057#        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
1058#    elif sizexy == [2048,2048] or sizexy == [1024,1024] or sizexy == [3072,3072]:
1059#        if IFD[273][2][0] == 8:
1060#            if IFD[258][2][0] == 32:
1061#                tifType = 'PE'
1062#                pixy = (200,200)
1063#                File.seek(8)
1064#                if not imageOnly:
1065#                    print 'Read APS PE-detector tiff file: ',filename
1066#                if dataType == 5:
1067#                    image = np.array(ar.array('f',File.read(4*Npix)),dtype=np.float32)
1068#                else:
1069#                    image = np.array(ar.array('I',File.read(4*Npix)),dtype=np.int32)
1070#        elif IFD[273][2][0] == 4096:
1071#            if sizexy[0] == 3072:
1072#                pixy =  (73,73)
1073#                tifType = 'MAR225'           
1074#            else:
1075#                pixy = (158,158)
1076#                tifType = 'MAR325'           
1077#            File.seek(4096)
1078#            if not imageOnly:
1079#                print 'Read MAR CCD tiff file: ',filename
1080#            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
1081#        elif IFD[273][2][0] == 512:
1082#            tiftype = '11-ID-C'
1083#            pixy = [200,200]
1084#            File.seek(512)
1085#            if not imageOnly:
1086#                print 'Read 11-ID-C tiff file: ',filename
1087#            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)           
1088#    elif sizexy == [4096,4096]:
1089#        if IFD[273][2][0] == 8:
1090#            if IFD[258][2][0] == 16:
1091#                tifType = 'scanCCD'
1092#                pixy = (9,9)
1093#                File.seek(8)
1094#                if not imageOnly:
1095#                    print 'Read APS scanCCD tiff file: ',filename
1096#                image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
1097#        elif IFD[273][2][0] == 4096:
1098#            tifType = 'Rayonix'
1099#            pixy = (73.242,73.242)
1100#            File.seek(4096)
1101#            if not imageOnly:
1102#                print 'Read Rayonix MX300HE tiff file: ',filename
1103#            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
1104##    elif sizexy == [960,960]:
1105##        tiftype = 'PE-BE'
1106##        pixy = (200,200)
1107##        File.seek(8)
1108##        if not imageOnly:
1109##            print 'Read Gold tiff file:',filename
1110##        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
1111#           
1112#    else:
1113#        lines = ['not a known detector tiff file',]
1114#        return lines,0,0,0
1115#       
1116#    image = np.reshape(image,(sizexy[1],sizexy[0]))
1117#    center = [pixy[0]*sizexy[0]/2000,pixy[1]*sizexy[1]/2000]
1118#    data = {'pixelSize':pixy,'wavelength':0.10,'distance':100.0,'center':center,'size':sizexy}
1119#    File.close()   
1120#    if imageOnly:
1121#        return image
1122#    else:
1123#        return head,data,Npix,image
1124#   
1125def ProjFileOpen(G2frame):
1126    'Read a GSAS-II project file and load into the G2 data tree'
1127    if not os.path.exists(G2frame.GSASprojectfile):
1128        print ('\n*** Error attempt to open project file that does not exist:\n   '+
1129               str(G2frame.GSASprojectfile))
1130        return
1131    LastSavedUsing = None
1132    file = open(G2frame.GSASprojectfile,'rb')
1133    print 'load from file: ',G2frame.GSASprojectfile
1134    G2frame.SetTitle("GSAS-II data tree: "+
1135                     os.path.split(G2frame.GSASprojectfile)[1])
1136    wx.BeginBusyCursor()
1137    try:
1138        while True:
1139            try:
1140                data = cPickle.load(file)
1141            except EOFError:
1142                break
1143            datum = data[0]
1144           
1145            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=datum[0])
1146            if 'PWDR' in datum[0]:               
1147                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
1148                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
1149                G2frame.PatternTree.SetItemPyData(Id,datum[1][:3])  #temp. trim off junk (patch?)
1150            elif datum[0].startswith('HKLF'): 
1151                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
1152                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
1153                G2frame.PatternTree.SetItemPyData(Id,datum[1])
1154            else:
1155                G2frame.PatternTree.SetItemPyData(Id,datum[1])             
1156                if datum[0] == 'Controls' and 'LastSavedUsing' in datum[1]:
1157                    LastSavedUsing = datum[1]['LastSavedUsing']
1158                if datum[0] == 'Controls' and 'PythonVersions' in datum[1] and GSASIIpath.GetConfigValue('debug'):
1159                    print('Packages used to create .GPX file:')
1160                    if 'dict' in str(type(datum[1]['PythonVersions'])):  #patch
1161                        for p in sorted(datum[1]['PythonVersions'],key=lambda s: s.lower()):
1162                            print("{:>14s}: {:s}".format(p[0],p[1]))
1163                    else:
1164                        for p in datum[1]['PythonVersions']:
1165                            print("{:<12s} {:s}".format(p[0]+':',p[1]))
1166            for datus in data[1:]:
1167                sub = G2frame.PatternTree.AppendItem(Id,datus[0])
1168#patch
1169                if datus[0] == 'Instrument Parameters' and len(datus[1]) == 1:
1170                    if 'PWDR' in datum[0]:
1171                        datus[1] = [dict(zip(datus[1][3],zip(datus[1][0],datus[1][1],datus[1][2]))),{}]
1172                    else:
1173                        datus[1] = [dict(zip(datus[1][2],zip(datus[1][0],datus[1][1]))),{}]
1174                    for item in datus[1][0]:               #zip makes tuples - now make lists!
1175                        datus[1][0][item] = list(datus[1][0][item])
1176#end patch
1177                G2frame.PatternTree.SetItemPyData(sub,datus[1])
1178            if 'IMG' in datum[0]:                   #retrieve image default flag & data if set
1179                Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Image Controls'))
1180                if Data['setDefault']:
1181                    G2frame.imageDefault = Data               
1182        file.close()
1183        if LastSavedUsing:
1184            print('GPX load successful. Last saved with GSAS-II version '+LastSavedUsing)
1185        else:
1186            print('project load successful')
1187        G2frame.NewPlot = True
1188    except:
1189        msg = wx.MessageDialog(G2frame,message="Error reading file "+
1190            str(G2frame.GSASprojectfile)+". This is not a GSAS-II .gpx file",
1191            caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
1192        msg.ShowModal()
1193    finally:
1194        wx.EndBusyCursor()
1195        G2frame.Status.SetStatusText('To reorder tree items, use mouse RB to drag/drop them')
1196   
1197def ProjFileSave(G2frame):
1198    'Save a GSAS-II project file'
1199    if not G2frame.PatternTree.IsEmpty():
1200        file = open(G2frame.GSASprojectfile,'wb')
1201        print 'save to file: ',G2frame.GSASprojectfile
1202        # stick the file name into the tree and version info into tree so they are saved.
1203        # (Controls should always be created at this point)
1204        try:
1205            Controls = G2frame.PatternTree.GetItemPyData(
1206                G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
1207            Controls['LastSavedAs'] = os.path.abspath(G2frame.GSASprojectfile)
1208            Controls['LastSavedUsing'] = str(GSASIIpath.GetVersionNumber())
1209            Controls['PythonVersions'] = G2frame.PackageVersions
1210        except:
1211            pass
1212        wx.BeginBusyCursor()
1213        try:
1214            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1215            while item:
1216                data = []
1217                name = G2frame.PatternTree.GetItemText(item)
1218                data.append([name,G2frame.PatternTree.GetItemPyData(item)])
1219                item2, cookie2 = G2frame.PatternTree.GetFirstChild(item)
1220                while item2:
1221                    name = G2frame.PatternTree.GetItemText(item2)
1222                    data.append([name,G2frame.PatternTree.GetItemPyData(item2)])
1223                    item2, cookie2 = G2frame.PatternTree.GetNextChild(item, cookie2)                           
1224                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                           
1225                cPickle.dump(data,file,1)
1226            file.close()
1227        finally:
1228            wx.EndBusyCursor()
1229        print('project save successful')
1230
1231def SaveIntegration(G2frame,PickId,data):
1232    'Save image integration results as powder pattern(s)'
1233    azms = G2frame.Integrate[1]
1234    X = G2frame.Integrate[2][:-1]
1235    N = len(X)
1236    Id = G2frame.PatternTree.GetItemParent(PickId)
1237    name = G2frame.PatternTree.GetItemText(Id)
1238    name = name.replace('IMG ',data['type']+' ')
1239    Comments = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Comments'))
1240    if 'PWDR' in name:
1241        names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
1242        codes = [0 for i in range(11)]
1243    elif 'SASD' in name:
1244        names = ['Type','Lam','Zero','Azimuth'] 
1245        codes = [0 for i in range(4)]
1246        X = 4.*np.pi*npsind(X/2.)/data['wavelength']    #convert to q
1247    Xminmax = [X[0],X[-1]]
1248    LRazm = data['LRazimuth']
1249    Azms = []
1250    dazm = 0.
1251    if data['fullIntegrate'] and data['outAzimuths'] == 1:
1252        Azms = [45.0,]                              #a poor man's average?
1253    else:
1254        for i,azm in enumerate(azms[:-1]):
1255            if azm > 360. and azms[i+1] > 360.:
1256                Azms.append(G2img.meanAzm(azm%360.,azms[i+1]%360.))
1257            else:   
1258                Azms.append(G2img.meanAzm(azm,azms[i+1]))
1259        dazm = np.min(np.abs(np.diff(azms)))/2.
1260    for i,azm in enumerate(azms[:-1]):
1261        Aname = name+" Azm= %.2f"%((azm+dazm)%360.)
1262        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1263        nOcc = 0
1264        while item:
1265            Name = G2frame.PatternTree.GetItemText(item)
1266            if Aname in Name:
1267                nOcc += 1
1268            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1269        if nOcc:
1270            Aname += '(%d)'%(nOcc)
1271        Sample = G2pdG.SetDefaultSample()
1272        Sample['Gonio. radius'] = data['distance']
1273        Sample['Omega'] = data['GonioAngles'][0]
1274        Sample['Chi'] = data['GonioAngles'][1]
1275        Sample['Phi'] = data['GonioAngles'][2]
1276        Sample['Azimuth'] = (azm+dazm)%360.    #put here as bin center
1277        if 'PWDR' in Aname:
1278            parms = ['PXC',data['wavelength'],0.0,0.99,1.0,-0.10,0.4,0.30,1.0,0.0001,Azms[i]]    #set polarization for synchrotron radiation!
1279        elif 'SASD' in Aname:
1280            Sample['Trans'] = data['SampleAbs'][0]
1281            parms = ['LXC',data['wavelength'],0.0,Azms[i]]
1282        Y = G2frame.Integrate[0][i]
1283        W = np.where(Y>0.,1./Y,1.e-6)                    #probably not true
1284        Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=Aname)
1285        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
1286        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
1287        if 'PWDR' in Aname:
1288            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0],
1289                {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
1290        inst = [dict(zip(names,zip(parms,parms,codes))),{}]
1291        for item in inst[0]:
1292            inst[0][item] = list(inst[0][item])
1293        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
1294        if 'PWDR' in Aname:
1295            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
1296            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Peak List'),{'sigDict':{},'peaks':[]})
1297            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Index Peak List'),[[],[]])
1298            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Unit Cells List'),[])
1299            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Reflection Lists'),{})
1300        elif 'SASD' in Aname:             
1301            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Substances'),G2pdG.SetDefaultSubstances())
1302            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
1303            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Models'),G2pdG.SetDefaultSASDModel())
1304        valuesdict = {
1305            'wtFactor':1.0,
1306            'Dummy':False,
1307            'ranId':ran.randint(0,sys.maxint),
1308            'Offset':[0.0,0.0],'delOffset':0.02,'refOffset':-1.0,'refDelt':0.01,
1309            'qPlot':False,'dPlot':False,'sqrtPlot':False
1310            }
1311        G2frame.PatternTree.SetItemPyData(
1312            Id,[valuesdict,
1313                [np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
1314    return Id       #last powder pattern generated
1315           
1316# def powderFxyeSave(G2frame,exports,powderfile):
1317#     'Save a powder histogram as a GSAS FXYE file'
1318#     head,tail = ospath.split(powderfile)
1319#     name,ext = tail.split('.')
1320#     for i,export in enumerate(exports):
1321#         filename = ospath.join(head,name+'-%03d.'%(i)+ext)
1322#         prmname = filename.strip(ext)+'prm'
1323#         prm = open(prmname,'w')      #old style GSAS parm file
1324#         PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
1325#         Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, \
1326#             PickId, 'Instrument Parameters'))[0]
1327#         prm.write( '            123456789012345678901234567890123456789012345678901234567890        '+'\n')
1328#         prm.write( 'INS   BANK      1                                                               '+'\n')
1329#         prm.write(('INS   HTYPE   %sR                                                              '+'\n')%(Inst['Type'][0]))
1330#         if 'Lam1' in Inst:              #Ka1 & Ka2
1331#             prm.write(('INS  1 ICONS%10.7f%10.7f    0.0000               0.990    0     0.500   '+'\n')%(Inst['Lam1'][0],Inst['Lam2'][0]))
1332#         elif 'Lam' in Inst:             #single wavelength
1333#             prm.write(('INS  1 ICONS%10.7f%10.7f    0.0000               0.990    0     0.500   '+'\n')%(Inst['Lam'][1],0.0))
1334#         prm.write( 'INS  1 IRAD     0                                                               '+'\n')
1335#         prm.write( 'INS  1I HEAD                                                                    '+'\n')
1336#         prm.write( 'INS  1I ITYP    0    0.0000  180.0000         1                                 '+'\n')
1337#         prm.write(('INS  1DETAZM%10.3f                                                          '+'\n')%(Inst['Azimuth'][0]))
1338#         prm.write( 'INS  1PRCF1     3    8   0.00100                                                '+'\n')
1339#         prm.write(('INS  1PRCF11     %15.6g%15.6g%15.6g%15.6g   '+'\n')%(Inst['U'][1],Inst['V'][1],Inst['W'][1],0.0))
1340#         prm.write(('INS  1PRCF12     %15.6g%15.6g%15.6g%15.6g   '+'\n')%(Inst['X'][1],Inst['Y'][1],Inst['SH/L'][1]/2.,Inst['SH/L'][1]/2.))
1341#         prm.close()
1342#         file = open(filename,'w')
1343#         print 'save powder pattern to file: ',filename
1344#         x,y,w,yc,yb,yd = G2frame.PatternTree.GetItemPyData(PickId)[1]
1345#         file.write(powderfile+'\n')
1346#         file.write('Instrument parameter file:'+ospath.split(prmname)[1]+'\n')
1347#         file.write('BANK 1 %d %d CONS %.2f %.2f 0 0 FXYE\n'%(len(x),len(x),\
1348#             100.*x[0],100.*(x[1]-x[0])))
1349#         s = list(np.sqrt(1./np.array(w)))       
1350#         XYW = zip(x,y,s)
1351#         for X,Y,S in XYW:
1352#             file.write("%15.6g %15.6g %15.6g\n" % (100.*X,Y,max(S,1.0)))
1353#         file.close()
1354#         print 'powder pattern file '+filename+' written'
1355       
1356# def powderXyeSave(G2frame,exports,powderfile):
1357#     'Save a powder histogram as a Topas XYE file'
1358#     head,tail = ospath.split(powderfile)
1359#     name,ext = tail.split('.')
1360#     for i,export in enumerate(exports):
1361#         filename = ospath.join(head,name+'-%03d.'%(i)+ext)
1362#         PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
1363#         file = open(filename,'w')
1364#         file.write('#%s\n'%(export))
1365#         print 'save powder pattern to file: ',filename
1366#         x,y,w,yc,yb,yd = G2frame.PatternTree.GetItemPyData(PickId)[1]
1367#         s = list(np.sqrt(1./np.array(w)))       
1368#         XYW = zip(x,y,s)
1369#         for X,Y,W in XYW:
1370#             file.write("%15.6g %15.6g %15.6g\n" % (X,Y,W))
1371#         file.close()
1372#         print 'powder pattern file '+filename+' written'
1373       
1374def PDFSave(G2frame,exports):
1375    'Save a PDF G(r) and S(Q) in column formats'
1376    for export in exports:
1377        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
1378        SQname = 'S(Q)'+export[4:]
1379        GRname = 'G(R)'+export[4:]
1380        sqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.sq')
1381        grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
1382        sqId = G2gd.GetPatternTreeItemId(G2frame, PickId, SQname)
1383        grId = G2gd.GetPatternTreeItemId(G2frame, PickId, GRname)
1384        sqdata = np.array(G2frame.PatternTree.GetItemPyData(sqId)[1][:2]).T
1385        grdata = np.array(G2frame.PatternTree.GetItemPyData(grId)[1][:2]).T
1386        sqfile = open(sqfilename,'w')
1387        grfile = open(grfilename,'w')
1388        sqfile.write('#T S(Q) %s\n'%(export))
1389        grfile.write('#T G(R) %s\n'%(export))
1390        sqfile.write('#L Q     S(Q)\n')
1391        grfile.write('#L R     G(R)\n')
1392        for q,sq in sqdata:
1393            sqfile.write("%15.6g %15.6g\n" % (q,sq))
1394        sqfile.close()
1395        for r,gr in grdata:
1396            grfile.write("%15.6g %15.6g\n" % (r,gr))
1397        grfile.close()
1398   
1399def PeakListSave(G2frame,file,peaks):
1400    'Save powder peaks to a data file'
1401    print 'save peak list to file: ',G2frame.peaklistfile
1402    if not peaks:
1403        dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
1404        try:
1405            result = dlg.ShowModal()
1406        finally:
1407            dlg.Destroy()
1408        return
1409    for peak in peaks:
1410        file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
1411            (peak[0],peak[2],peak[4],peak[6]))
1412    print 'peak list saved'
1413             
1414def IndexPeakListSave(G2frame,peaks):
1415    'Save powder peaks from the indexing list'
1416    file = open(G2frame.peaklistfile,'wa')
1417    print 'save index peak list to file: ',G2frame.peaklistfile
1418    wx.BeginBusyCursor()
1419    try:
1420        if not peaks:
1421            dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
1422            try:
1423                result = dlg.ShowModal()
1424            finally:
1425                dlg.Destroy()
1426            return
1427        for peak in peaks:
1428            file.write("%12.6f\n" % (peak[7]))
1429        file.close()
1430    finally:
1431        wx.EndBusyCursor()
1432    print 'index peak list saved'
1433   
1434def SetNewPhase(Name='New Phase',SGData=None,cell=None,Super=None):
1435    '''Create a new phase dict with default values for various parameters
1436
1437    :param str Name: Name for new Phase
1438
1439    :param dict SGData: space group data from :func:`GSASIIspc:SpcGroup`;
1440      defaults to data for P 1
1441
1442    :param list cell: unit cell parameter list; defaults to
1443      [1.0,1.0,1.0,90.,90,90.,1.]
1444
1445    '''
1446    if SGData is None: SGData = G2spc.SpcGroup('P 1')[1]
1447    if cell is None: cell=[1.0,1.0,1.0,90.,90,90.,1.]
1448    phaseData = {
1449        'ranId':ran.randint(0,sys.maxint),
1450        'General':{
1451            'Name':Name,
1452            'Type':'nuclear',
1453            'AtomPtrs':[3,1,7,9],
1454            'SGData':SGData,
1455            'Cell':[False,]+cell,
1456            'Pawley dmin':1.0,
1457            'Data plot type':'None',
1458            'SH Texture':{
1459                'Order':0,
1460                'Model':'cylindrical',
1461                'Sample omega':[False,0.0],
1462                'Sample chi':[False,0.0],
1463                'Sample phi':[False,0.0],
1464                'SH Coeff':[False,{}],
1465                'SHShow':False,
1466                'PFhkl':[0,0,1],
1467                'PFxyz':[0,0,1],
1468                'PlotType':'Pole figure',
1469                'Penalty':[['',],0.1,False,1.0]}},
1470        'Atoms':[],
1471        'Drawing':{},
1472        'Histograms':{},
1473        'Pawley ref':[],
1474        'RBModels':{},
1475        }
1476    if Super and Super.get('Use',False):
1477        phaseData['General'].update({'Type':'modulated','Super':True,'SuperSg':Super['ssSymb']})
1478        phaseData['General']['SSGData'] = G2spc.SSpcGroup(SGData,Super['ssSymb'])
1479        phaseData['General']['SuperVec'] = [Super['ModVec'],False,Super['maxH']]
1480
1481    return phaseData
1482       
1483class MultipleChoicesDialog(wx.Dialog):
1484    '''A dialog that offers a series of choices, each with a
1485    title and a wx.Choice widget. Intended to be used Modally.
1486    typical input:
1487
1488        *  choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1489        *  headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1490       
1491    selections are placed in self.chosen when OK is pressed
1492    '''
1493    def __init__(self,choicelist,headinglist,
1494                 head='Select options',
1495                 title='Please select from options below',
1496                 parent=None):
1497        self.chosen = []
1498        wx.Dialog.__init__(
1499            self,parent,wx.ID_ANY,head, 
1500            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1501        panel = wx.Panel(self)
1502        mainSizer = wx.BoxSizer(wx.VERTICAL)
1503        mainSizer.Add((10,10),1)
1504        topLabl = wx.StaticText(panel,wx.ID_ANY,title)
1505        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.CENTER,10)
1506        self.ChItems = []
1507        for choice,lbl in zip(choicelist,headinglist):
1508            mainSizer.Add((10,10),1)
1509            self.chosen.append(0)
1510            topLabl = wx.StaticText(panel,wx.ID_ANY,' '+lbl)
1511            mainSizer.Add(topLabl,0,wx.ALIGN_LEFT,10)
1512            self.ChItems.append(wx.Choice(self, wx.ID_ANY, (100, 50), choices = choice))
1513            mainSizer.Add(self.ChItems[-1],0,wx.ALIGN_CENTER,10)
1514
1515        OkBtn = wx.Button(panel,-1,"Ok")
1516        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1517        cancelBtn = wx.Button(panel,-1,"Cancel")
1518        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1519        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1520        btnSizer.Add((20,20),1)
1521        btnSizer.Add(OkBtn)
1522        btnSizer.Add((20,20),1)
1523        btnSizer.Add(cancelBtn)
1524        btnSizer.Add((20,20),1)
1525        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1526        panel.SetSizer(mainSizer)
1527        panel.Fit()
1528        self.Fit()
1529       
1530    def OnOk(self,event):
1531        parent = self.GetParent()
1532        if parent is not None: parent.Raise()
1533        # save the results from the choice widgets
1534        self.chosen = []
1535        for w in self.ChItems:
1536            self.chosen.append(w.GetSelection())
1537        self.EndModal(wx.ID_OK)             
1538           
1539    def OnCancel(self,event):
1540        parent = self.GetParent()
1541        if parent is not None: parent.Raise()
1542        self.chosen = []
1543        self.EndModal(wx.ID_CANCEL)             
1544           
1545def ExtractFileFromZip(filename, selection=None, confirmread=True,
1546                       confirmoverwrite=True, parent=None,
1547                       multipleselect=False):
1548    '''If the filename is a zip file, extract a file from that
1549    archive.
1550
1551    :param list Selection: used to predefine the name of the file
1552      to be extracted. Filename case and zip directory name are
1553      ignored in selection; the first matching file is used.
1554
1555    :param bool confirmread: if True asks the user to confirm before expanding
1556      the only file in a zip
1557
1558    :param bool confirmoverwrite: if True asks the user to confirm
1559      before overwriting if the extracted file already exists
1560
1561    :param bool multipleselect: if True allows more than one zip
1562      file to be extracted, a list of file(s) is returned.
1563      If only one file is present, do not ask which one, otherwise
1564      offer a list of choices (unless selection is used).
1565   
1566    :returns: the name of the file that has been created or a
1567      list of files (see multipleselect)
1568
1569    If the file is not a zipfile, return the name of the input file.
1570    If the zipfile is empty or no file has been selected, return None
1571    '''
1572    import zipfile # do this now, since we can save startup time by doing this only on need
1573    import shutil
1574    zloc = os.path.split(filename)[0]
1575    if not zipfile.is_zipfile(filename):
1576        #print("not zip")
1577        return filename
1578
1579    z = zipfile.ZipFile(filename,'r')
1580    zinfo = z.infolist()
1581
1582    if len(zinfo) == 0:
1583        #print('Zip has no files!')
1584        zlist = [-1]
1585    if selection:
1586        choices = [os.path.split(i.filename)[1].lower() for i in zinfo]
1587        if selection.lower() in choices:
1588            zlist = [choices.index(selection.lower())]
1589        else:
1590            print('debug: file '+str(selection)+' was not found in '+str(filename))
1591            zlist = [-1]
1592    elif len(zinfo) == 1 and confirmread:
1593        result = wx.ID_NO
1594        dlg = wx.MessageDialog(
1595            parent,
1596            'Is file '+str(zinfo[0].filename)+
1597            ' what you want to extract from '+
1598            str(os.path.split(filename)[1])+'?',
1599            'Confirm file', 
1600            wx.YES_NO | wx.ICON_QUESTION)
1601        try:
1602            result = dlg.ShowModal()
1603        finally:
1604            dlg.Destroy()
1605        if result == wx.ID_NO:
1606            zlist = [-1]
1607        else:
1608            zlist = [0]
1609    elif len(zinfo) == 1:
1610        zlist = [0]
1611    elif multipleselect:
1612        # select one or more from a from list
1613        choices = [i.filename for i in zinfo]
1614        dlg = G2G.G2MultiChoiceDialog(parent,'Select file(s) to extract from zip file '+str(filename),
1615            'Choose file(s)',choices)
1616        if dlg.ShowModal() == wx.ID_OK:
1617            zlist = dlg.GetSelections()
1618        else:
1619            zlist = []
1620        dlg.Destroy()
1621    else:
1622        # select one from a from list
1623        choices = [i.filename for i in zinfo]
1624        dlg = wx.SingleChoiceDialog(parent,
1625            'Select file to extract from zip file'+str(filename),'Choose file',
1626            choices,)
1627        if dlg.ShowModal() == wx.ID_OK:
1628            zlist = [dlg.GetSelection()]
1629        else:
1630            zlist = [-1]
1631        dlg.Destroy()
1632       
1633    outlist = []
1634    for zindex in zlist:
1635        if zindex >= 0:
1636            efil = os.path.join(zloc, os.path.split(zinfo[zindex].filename)[1])
1637            if os.path.exists(efil) and confirmoverwrite:
1638                result = wx.ID_NO
1639                dlg = wx.MessageDialog(parent,
1640                    'File '+str(efil)+' already exists. OK to overwrite it?',
1641                    'Confirm overwrite',wx.YES_NO | wx.ICON_QUESTION)
1642                try:
1643                    result = dlg.ShowModal()
1644                finally:
1645                    dlg.Destroy()
1646                if result == wx.ID_NO:
1647                    zindex = -1
1648        if zindex >= 0:
1649            # extract the file to the current directory, regardless of it's original path
1650            #z.extract(zinfo[zindex],zloc)
1651            eloc,efil = os.path.split(zinfo[zindex].filename)
1652            outfile = os.path.join(zloc, efil)
1653            fpin = z.open(zinfo[zindex])
1654            fpout = file(outfile, "wb")
1655            shutil.copyfileobj(fpin, fpout)
1656            fpin.close()
1657            fpout.close()
1658            outlist.append(outfile)
1659    z.close()
1660    if multipleselect and len(outlist) >= 1:
1661        return outlist
1662    elif len(outlist) == 1:
1663        return outlist[0]
1664    else:
1665        return None
1666
1667######################################################################
1668# base classes for reading various types of data files
1669#   not used directly, only by subclassing
1670######################################################################
1671E,SGData = G2spc.SpcGroup('P 1') # data structure for default space group
1672P1SGData = SGData
1673class ImportBaseclass(object):
1674    '''Defines a base class for the reading of input files (diffraction
1675    data, coordinates,...). See :ref:`Writing a Import Routine<Import_routines>`
1676    for an explanation on how to use a subclass of this class.
1677    '''
1678    class ImportException(Exception):
1679        '''Defines an Exception that is used when an import routine hits an expected error,
1680        usually in .Reader.
1681
1682        Good practice is that the Reader should define a value in self.errors that
1683        tells the user some information about what is wrong with their file.         
1684        '''
1685        pass
1686
1687    def __init__(self,
1688                 formatName,
1689                 longFormatName=None,
1690                 extensionlist=[],
1691                 strictExtension=False,
1692                 ):
1693        self.formatName = formatName # short string naming file type
1694        if longFormatName: # longer string naming file type
1695            self.longFormatName = longFormatName
1696        else:
1697            self.longFormatName = formatName
1698        # define extensions that are allowed for the file type
1699        # for windows, remove any extensions that are duplicate, as case is ignored
1700        if sys.platform == 'windows' and extensionlist:
1701            extensionlist = list(set([s.lower() for s in extensionlist]))
1702        self.extensionlist = extensionlist
1703        # If strictExtension is True, the file will not be read, unless
1704        # the extension matches one in the extensionlist
1705        self.strictExtension = strictExtension
1706        self.errors = ''
1707        self.warnings = ''
1708        # used for readers that will use multiple passes to read
1709        # more than one data block
1710        self.repeat = False
1711        self.selections = []
1712        self.repeatcount = 0
1713        self.readfilename = '?'
1714        #print 'created',self.__class__
1715
1716    def ReInitialize(self):
1717        'Reinitialize the Reader to initial settings'
1718        self.errors = ''
1719        self.warnings = ''
1720        self.repeat = False
1721        self.repeatcount = 0
1722        self.readfilename = '?'
1723
1724    def BlockSelector(self, ChoiceList, ParentFrame=None,
1725                      title='Select a block',
1726                      size=None, header='Block Selector',
1727                      useCancel=True):
1728        ''' Provide a wx dialog to select a block if the file contains more
1729        than one set of data and one must be selected
1730        '''
1731        if useCancel:
1732            dlg = wx.SingleChoiceDialog(
1733                ParentFrame,title, header,ChoiceList)
1734        else:
1735            dlg = wx.SingleChoiceDialog(
1736                ParentFrame,title, header,ChoiceList,
1737                style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK|wx.CENTRE)
1738        if size: dlg.SetSize(size)
1739        dlg.CenterOnParent()
1740        if dlg.ShowModal() == wx.ID_OK:
1741            sel = dlg.GetSelection()
1742            return sel
1743        else:
1744            return None
1745        dlg.Destroy()
1746
1747    def MultipleBlockSelector(self, ChoiceList, ParentFrame=None,
1748        title='Select a block',size=None, header='Block Selector'):
1749        '''Provide a wx dialog to select a block of data if the
1750        file contains more than one set of data and one must be
1751        selected.
1752
1753        :returns: a list of the selected blocks
1754        '''
1755        dlg = wx.MultiChoiceDialog(ParentFrame,title, header,ChoiceList+['Select all'],
1756            wx.CHOICEDLG_STYLE)
1757        dlg.CenterOnParent()
1758        if size: dlg.SetSize(size)
1759        if dlg.ShowModal() == wx.ID_OK:
1760            sel = dlg.GetSelections()
1761        else:
1762            return []
1763        dlg.Destroy()
1764        selected = []
1765        if len(ChoiceList) in sel:
1766            return range(len(ChoiceList))
1767        else:
1768            return sel
1769        return selected
1770
1771    def MultipleChoicesDialog(self, choicelist, headinglist, ParentFrame=None, **kwargs):
1772        '''A modal dialog that offers a series of choices, each with a title and a wx.Choice
1773        widget. Typical input:
1774       
1775           * choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1776           
1777           * headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1778           
1779        optional keyword parameters are: head (window title) and title
1780        returns a list of selected indicies for each choice (or None)
1781        '''
1782        result = None
1783        dlg = MultipleChoicesDialog(choicelist,headinglist,
1784            parent=ParentFrame, **kwargs)         
1785        dlg.CenterOnParent()
1786        if dlg.ShowModal() == wx.ID_OK:
1787            result = dlg.chosen
1788        dlg.Destroy()
1789        return result
1790
1791    def ShowBusy(self):
1792        wx.BeginBusyCursor()
1793#        wx.Yield() # make it happen now!
1794
1795    def DoneBusy(self):
1796        wx.EndBusyCursor()
1797        wx.Yield() # make it happen now!
1798       
1799#    def Reader(self, filename, filepointer, ParentFrame=None, **unused):
1800#        '''This method must be supplied in the child class to read the file.
1801#        if the read fails either return False or raise an Exception
1802#        preferably of type ImportException.
1803#        '''
1804#        #start reading
1805#        raise ImportException("Error occurred while...")
1806#        self.errors += "Hint for user on why the error occur
1807#        return False # if an error occurs
1808#        return True # if read OK
1809
1810    def ExtensionValidator(self, filename):
1811        '''This methods checks if the file has the correct extension
1812        Return False if this filename will not be supported by this reader
1813        Return True if the extension matches the list supplied by the reader
1814        Return None if the reader allows un-registered extensions
1815        '''
1816        if filename:
1817            ext = os.path.splitext(filename)[1]
1818            if sys.platform == 'windows': ext = ext.lower()
1819            if ext in self.extensionlist: return True
1820            if self.strictExtension: return False
1821        return None
1822
1823    def ContentsValidator(self, filepointer):
1824        '''This routine will attempt to determine if the file can be read
1825        with the current format.
1826        This will typically be overridden with a method that
1827        takes a quick scan of [some of]
1828        the file contents to do a "sanity" check if the file
1829        appears to match the selected format.
1830        Expected to be called via self.Validator()
1831        '''
1832        #filepointer.seek(0) # rewind the file pointer
1833        return True
1834
1835    def CIFValidator(self, filepointer):
1836        '''A :meth:`ContentsValidator` for use to validate CIF files.
1837        '''
1838        for i,l in enumerate(filepointer):
1839            if i >= 1000: return True
1840            '''Encountered only blank lines or comments in first 1000
1841            lines. This is unlikely, but assume it is CIF anyway, since we are
1842            even less likely to find a file with nothing but hashes and
1843            blank lines'''
1844            line = l.strip()
1845            if len(line) == 0: # ignore blank lines
1846                continue 
1847            elif line.startswith('#'): # ignore comments
1848                continue 
1849            elif line.startswith('data_'): # on the right track, accept this file
1850                return True
1851            else: # found something invalid
1852                self.errors = 'line '+str(i+1)+' contains unexpected data:\n'
1853                self.errors += '  '+str(l)
1854                self.errors += '  Note: a CIF should only have blank lines or comments before'
1855                self.errors += '        a data_ statement begins a block.'
1856                return False 
1857
1858class ImportPhase(ImportBaseclass):
1859    '''Defines a base class for the reading of files with coordinates
1860
1861    Objects constructed that subclass this (in import/G2phase_*.py etc.) will be used
1862    in :meth:`GSASII.GSASII.OnImportPhase`.
1863    See :ref:`Writing a Import Routine<Import_Routines>`
1864    for an explanation on how to use this class.
1865
1866    '''
1867    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1868        strictExtension=False,):
1869        # call parent __init__
1870        ImportBaseclass.__init__(self,formatName,longFormatName,
1871            extensionlist,strictExtension)
1872        self.Phase = None # a phase must be created with G2IO.SetNewPhase in the Reader
1873        self.Constraints = None
1874
1875    def PhaseSelector(self, ChoiceList, ParentFrame=None,
1876        title='Select a phase', size=None,header='Phase Selector'):
1877        ''' Provide a wx dialog to select a phase if the file contains more
1878        than one phase
1879        '''
1880        return self.BlockSelector(ChoiceList,ParentFrame,title,
1881            size,header)
1882
1883class ImportStructFactor(ImportBaseclass):
1884    '''Defines a base class for the reading of files with tables
1885    of structure factors.
1886
1887    Structure factors are read with a call to :meth:`GSASII.GSASII.OnImportSfact`
1888    which in turn calls :meth:`GSASII.GSASII.OnImportGeneric`, which calls
1889    methods :meth:`ExtensionValidator`, :meth:`ContentsValidator` and
1890    :meth:`Reader`.
1891
1892    See :ref:`Writing a Import Routine<Import_Routines>`
1893    for an explanation on how to use import classes in general. The specifics
1894    for reading a structure factor histogram require that
1895    the ``Reader()`` routine in the import
1896    class need to do only a few things: It
1897    should load :attr:`RefDict` item ``'RefList'`` with the reflection list,
1898    and set :attr:`Parameters` with the instrument parameters
1899    (initialized with :meth:`InitParameters` and set with :meth:`UpdateParameters`).
1900    '''
1901    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1902        strictExtension=False,):
1903        ImportBaseclass.__init__(self,formatName,longFormatName,
1904            extensionlist,strictExtension)
1905
1906        # define contents of Structure Factor entry
1907        self.Parameters = []
1908        'self.Parameters is a list with two dicts for data parameter settings'
1909        self.InitParameters()
1910        self.RefDict = {'RefList':[],'FF':{},'Super':0}
1911        self.Banks = []             #for multi bank data (usually TOF)
1912        '''self.RefDict is a dict containing the reflection information, as read from the file.
1913        Item 'RefList' contains the reflection information. See the
1914        :ref:`Single Crystal Reflection Data Structure<XtalRefl_table>`
1915        for the contents of each row. Dict element 'FF'
1916        contains the form factor values for each element type; if this entry
1917        is left as initialized (an empty list) it will be initialized as needed later.
1918        '''
1919    def ReInitialize(self):
1920        'Reinitialize the Reader to initial settings'
1921        ImportBaseclass.ReInitialize(self)
1922        self.InitParameters()
1923        self.Banks = []             #for multi bank data (usually TOF)
1924        self.RefDict = {'RefList':[],'FF':{},'Super':0}
1925       
1926    def InitParameters(self):
1927        'initialize the instrument parameters structure'
1928        Lambda = 0.70926
1929        HistType = 'SXC'
1930        self.Parameters = [{'Type':[HistType,HistType], # create the structure
1931                            'Lam':[Lambda,Lambda]
1932                            }, {}]
1933        'Parameters is a list with two dicts for data parameter settings'
1934
1935    def UpdateParameters(self,Type=None,Wave=None):
1936        'Revise the instrument parameters'
1937        if Type is not None:
1938            self.Parameters[0]['Type'] = [Type,Type]
1939        if Wave is not None:
1940            self.Parameters[0]['Lam'] = [Wave,Wave]           
1941                       
1942######################################################################
1943class ImportPowderData(ImportBaseclass):
1944    '''Defines a base class for the reading of files with powder data.
1945
1946    Objects constructed that subclass this (in import/G2pwd_*.py etc.) will be used
1947    in :meth:`GSASII.GSASII.OnImportPowder`.
1948    See :ref:`Writing a Import Routine<Import_Routines>`
1949    for an explanation on how to use this class.
1950    '''
1951    def __init__(self,
1952                 formatName,
1953                 longFormatName=None,
1954                 extensionlist=[],
1955                 strictExtension=False,
1956                 ):
1957        ImportBaseclass.__init__(self,formatName,
1958                                            longFormatName,
1959                                            extensionlist,
1960                                            strictExtension)
1961        self.clockWd = None  # used in TOF
1962        self.ReInitialize()
1963       
1964    def ReInitialize(self):
1965        'Reinitialize the Reader to initial settings'
1966        ImportBaseclass.ReInitialize(self)
1967        self.powderentry = ['',None,None] #  (filename,Pos,Bank)
1968        self.powderdata = [] # Powder dataset
1969        '''A powder data set is a list with items [x,y,w,yc,yb,yd]:
1970                np.array(x), # x-axis values
1971                np.array(y), # powder pattern intensities
1972                np.array(w), # 1/sig(intensity)^2 values (weights)
1973                np.array(yc), # calc. intensities (zero)
1974                np.array(yb), # calc. background (zero)
1975                np.array(yd), # obs-calc profiles
1976        '''                           
1977        self.comments = []
1978        self.idstring = ''
1979        self.Sample = G2pdG.SetDefaultSample() # default sample parameters
1980        self.Controls = {}  # items to be placed in top-level Controls
1981        self.GSAS = None     # used in TOF
1982        self.repeat_instparm = True # Should a parm file be
1983        #                             used for multiple histograms?
1984        self.instparm = None # name hint from file of instparm to use
1985        self.instfile = '' # full path name to instrument parameter file
1986        self.instbank = '' # inst parm bank number
1987        self.instmsg = ''  # a label that gets printed to show
1988                           # where instrument parameters are from
1989        self.numbanks = 1
1990        self.instdict = {} # place items here that will be transferred to the instrument parameters
1991        self.pwdparms = {} # place parameters that are transferred directly to the tree
1992                           # here (typically from an existing GPX file)
1993######################################################################
1994class ImportSmallAngleData(ImportBaseclass):
1995    '''Defines a base class for the reading of files with small angle data.
1996    See :ref:`Writing a Import Routine<Import_Routines>`
1997    for an explanation on how to use this class.
1998    '''
1999    def __init__(self,formatName,longFormatName=None,extensionlist=[],
2000        strictExtension=False,):
2001           
2002        ImportBaseclass.__init__(self,formatName,longFormatName,extensionlist,
2003            strictExtension)
2004        self.ReInitialize()
2005       
2006    def ReInitialize(self):
2007        'Reinitialize the Reader to initial settings'
2008        ImportBaseclass.ReInitialize(self)
2009        self.smallangleentry = ['',None,None] #  (filename,Pos,Bank)
2010        self.smallangledata = [] # SASD dataset
2011        '''A small angle data set is a list with items [x,y,w,yc,yd]:
2012                np.array(x), # x-axis values
2013                np.array(y), # powder pattern intensities
2014                np.array(w), # 1/sig(intensity)^2 values (weights)
2015                np.array(yc), # calc. intensities (zero)
2016                np.array(yd), # obs-calc profiles
2017                np.array(yb), # preset bkg
2018        '''                           
2019        self.comments = []
2020        self.idstring = ''
2021        self.Sample = G2pdG.SetDefaultSample()
2022        self.GSAS = None     # used in TOF
2023        self.clockWd = None  # used in TOF
2024        self.numbanks = 1
2025        self.instdict = {} # place items here that will be transferred to the instrument parameters
2026
2027######################################################################
2028class ImportImage(ImportBaseclass):
2029    '''Defines a base class for the reading of images
2030
2031    Structure factors are read with a call to :meth:`GSASII.GSASII.OnImportImage`
2032    which in turn calls :meth:`GSASII.GSASII.OnImportGeneric`, which calls
2033    methods :meth:`ExtensionValidator`, :meth:`ContentsValidator` and
2034    :meth:`Reader`.
2035
2036    See :ref:`Writing a Import Routine<Import_Routines>`
2037    for an explanation on how to use import classes in general. The specifics
2038    for reading an image requires that the ``Reader()`` routine in the import
2039    class need to do only a few things:...
2040   
2041    (should load :attr:`RefDict` item ``'RefList'`` with the reflection list,
2042    (and set :attr:`Parameters` with the instrument parameters
2043    (initialized with :meth:`InitParameters` and set with :meth:`UpdateParameters`).
2044    '''
2045    def __init__(self,formatName,longFormatName=None,extensionlist=[],
2046        strictExtension=False,):
2047        ImportBaseclass.__init__(self,formatName,longFormatName,
2048            extensionlist,strictExtension)
2049        self.InitParameters()
2050       
2051    def ReInitialize(self):
2052        'Reinitialize the Reader to initial settings -- not used at present'
2053        ImportBaseclass.ReInitialize(self)
2054        self.InitParameters()
2055       
2056    def InitParameters(self):
2057        'initialize the instrument parameters structure'
2058        self.Comments = ['No comments']
2059        self.Data = {}
2060        self.Npix = 0
2061        self.Image = None
2062
2063######################################################################
2064class ExportBaseclass(object):
2065    '''Defines a base class for the exporting of GSAS-II results.
2066
2067    This class is subclassed in the various exports/G2export_*.py files. Those files
2068    are imported in :meth:`GSASII.GSASII._init_Exports` which defines the
2069    appropriate menu items for each one and the .Exporter method is called
2070    directly from the menu item.
2071
2072    Routines may also define a .Writer method, which is used to write a single
2073    file without invoking any GUI objects.
2074    '''
2075    def __init__(self,
2076                 G2frame,
2077                 formatName,
2078                 extension,
2079                 longFormatName=None,
2080                 ):
2081        self.G2frame = G2frame
2082        self.formatName = formatName # short string naming file type
2083        self.extension = extension
2084        if longFormatName: # longer string naming file type
2085            self.longFormatName = longFormatName
2086        else:
2087            self.longFormatName = formatName
2088        self.OverallParms = {}
2089        self.Phases = {}
2090        self.Histograms = {}
2091        self.powderDict = {}
2092        self.xtalDict = {}
2093        self.parmDict = {}
2094        self.sigDict = {}
2095        # updated in InitExport:
2096        self.currentExportType = None # type of export that has been requested
2097        # updated in ExportSelect (when used):
2098        self.phasenam = None # a list of selected phases
2099        self.histnam = None # a list of selected histograms
2100        self.filename = None # name of file to be written (single export) or template (multiple files)
2101        self.dirname = '' # name of directory where file(s) will be written
2102        self.fullpath = '' # name of file being written -- full path
2103       
2104        # items that should be defined in a subclass of this class
2105        self.exporttype = []  # defines the type(s) of exports that the class can handle.
2106        # The following types are defined: 'project', "phase", "powder", "single"
2107        self.multiple = False # set as True if the class can export multiple phases or histograms
2108        # self.multiple is ignored for "project" exports
2109
2110    def InitExport(self,event):
2111        '''Determines the type of menu that called the Exporter and
2112        misc initialization.
2113        '''
2114        self.filename = None # name of file to be written (single export)
2115        self.dirname = '' # name of file to be written (multiple export)
2116        if event:
2117            self.currentExportType = self.G2frame.ExportLookup.get(event.Id)
2118
2119    def MakePWDRfilename(self,hist):
2120        '''Make a filename root (no extension) from a PWDR histogram name
2121
2122        :param str hist: the histogram name in data tree (starts with "PWDR ")
2123        '''
2124        file0 = ''
2125        file1 = hist[5:]
2126        # replace repeated blanks
2127        while file1 != file0:
2128            file0 = file1
2129            file1 = file0.replace('  ',' ').strip()
2130        file0 = file1.replace('Azm= ','A')
2131        # if angle has unneeded decimal places on aziumuth, remove them
2132        if file0[-3:] == '.00': file0 = file0[:-3]
2133        file0 = file0.replace('.','_')
2134        file0 = file0.replace(' ','_')
2135        return file0
2136
2137    def ExportSelect(self,AskFile='ask'):
2138        '''Selects histograms or phases when needed. Sets a default file name when
2139        requested in self.filename; always sets a default directory in self.dirname.
2140
2141        :param bool AskFile: Determines how this routine processes getting a
2142          location to store the current export(s).
2143         
2144          * if AskFile is 'ask' (default option), get the name of the file to be written;
2145            self.filename and self.dirname are always set. In the case where
2146            multiple files must be generated, the export routine should do this
2147            based on self.filename as a template.
2148          * if AskFile is 'dir', get the name of the directory to be used;
2149            self.filename is not used, but self.dirname is always set. The export routine
2150            will always generate the file name.
2151          * if AskFile is 'single', get only the name of the directory to be used when
2152            multiple items will be written (as multiple files) are used
2153            *or* a complete file name is requested when a single file
2154            name is selected. self.dirname is always set and self.filename used
2155            only when a single file is selected.
2156          * if AskFile is 'default', creates a name of the file to be used from
2157            the name of the project (.gpx) file. If the project has not been saved,
2158            then the name of file is requested.
2159            self.filename and self.dirname are always set. In the case where
2160            multiple file names must be generated, the export routine should do this
2161            based on self.filename.
2162          * if AskFile is 'default-dir', sets self.dirname from the project (.gpx)
2163            file. If the project has not been saved, then a directory is requested.
2164            self.filename is not used.
2165
2166        :returns: True in case of an error
2167        '''
2168       
2169        numselected = 1
2170        if self.currentExportType == 'phase':
2171            if len(self.Phases) == 0:
2172                self.G2frame.ErrorDialog(
2173                    'Empty project',
2174                    'Project does not contain any phases.')
2175                return True
2176            elif len(self.Phases) == 1:
2177                self.phasenam = self.Phases.keys()
2178            elif self.multiple: 
2179                choices = sorted(self.Phases.keys())
2180                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
2181                if phasenum is None: return True
2182                self.phasenam = [choices[i] for i in phasenum]
2183                if not self.phasenam: return True
2184                numselected = len(self.phasenam)
2185            else:
2186                choices = sorted(self.Phases.keys())
2187                phasenum = G2G.ItemSelector(choices,self.G2frame)
2188                if phasenum is None: return True
2189                self.phasenam = [choices[phasenum]]
2190                numselected = len(self.phasenam)
2191        elif self.currentExportType == 'single':
2192            if len(self.xtalDict) == 0:
2193                self.G2frame.ErrorDialog(
2194                    'Empty project',
2195                    'Project does not contain any single crystal data.')
2196                return True
2197            elif len(self.xtalDict) == 1:
2198                self.histnam = self.xtalDict.values()
2199            elif self.multiple:
2200                choices = sorted(self.xtalDict.values())
2201                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
2202                if not hnum: return True
2203                self.histnam = [choices[i] for i in hnum]
2204                numselected = len(self.histnam)
2205            else:
2206                choices = sorted(self.xtalDict.values())
2207                hnum = G2G.ItemSelector(choices,self.G2frame)
2208                if hnum is None: return True
2209                self.histnam = [choices[hnum]]
2210                numselected = len(self.histnam)
2211        elif self.currentExportType == 'powder':
2212            if len(self.powderDict) == 0:
2213                self.G2frame.ErrorDialog(
2214                    'Empty project',
2215                    'Project does not contain any powder data.')
2216                return True
2217            elif len(self.powderDict) == 1:
2218                self.histnam = self.powderDict.values()
2219            elif self.multiple:
2220                choices = sorted(self.powderDict.values())
2221                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
2222                if not hnum: return True
2223                self.histnam = [choices[i] for i in hnum]
2224                numselected = len(self.histnam)
2225            else:
2226                choices = sorted(self.powderDict.values())
2227                hnum = G2G.ItemSelector(choices,self.G2frame)
2228                if hnum is None: return True
2229                self.histnam = [choices[hnum]]
2230                numselected = len(self.histnam)
2231        elif self.currentExportType == 'image':
2232            if len(self.Histograms) == 0:
2233                self.G2frame.ErrorDialog(
2234                    'Empty project',
2235                    'Project does not contain any images.')
2236                return True
2237            elif len(self.Histograms) == 1:
2238                self.histnam = self.Histograms.keys()
2239            else:
2240                choices = sorted(self.Histograms.keys())
2241                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
2242                if self.multiple:
2243                    if not hnum: return True
2244                    self.histnam = [choices[i] for i in hnum]
2245                else:
2246                    if hnum is None: return True
2247                    self.histnam = [choices[hnum]]
2248                numselected = len(self.histnam)
2249        if self.currentExportType == 'map':
2250            # search for phases with maps
2251            mapPhases = []
2252            choices = []
2253            for phasenam in sorted(self.Phases):
2254                phasedict = self.Phases[phasenam] # pointer to current phase info           
2255                if len(phasedict['General']['Map'].get('rho',[])):
2256                    mapPhases.append(phasenam)
2257                    if phasedict['General']['Map'].get('Flip'):
2258                        choices.append('Charge flip map: '+str(phasenam))
2259                    elif phasedict['General']['Map'].get('MapType'):
2260                        choices.append(
2261                            str(phasedict['General']['Map'].get('MapType'))
2262                            + ' map: ' + str(phasenam))
2263                    else:
2264                        choices.append('unknown map: '+str(phasenam))
2265            # select a map if needed
2266            if len(mapPhases) == 0:
2267                self.G2frame.ErrorDialog(
2268                    'Empty project',
2269                    'Project does not contain any maps.')
2270                return True
2271            elif len(mapPhases) == 1:
2272                self.phasenam = mapPhases
2273            else: 
2274                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
2275                if self.multiple:
2276                    if not phasenum: return True
2277                    self.phasenam = [mapPhases[i] for i in phasenum]
2278                else:
2279                    if phasenum is None: return True
2280                    self.phasenam = [mapPhases[phasenum]]
2281            numselected = len(self.phasenam)
2282
2283        # items selected, now set self.dirname and usually self.filename
2284        if AskFile == 'ask' or (AskFile == 'single' and numselected == 1) or (
2285            AskFile == 'default' and not self.G2frame.GSASprojectfile
2286            ):
2287            filename = self.askSaveFile()
2288            if not filename: return True
2289            self.dirname,self.filename = os.path.split(filename)
2290        elif AskFile == 'dir' or AskFile == 'single' or (
2291            AskFile == 'default-dir' and not self.G2frame.GSASprojectfile
2292            ):
2293            self.dirname = self.askSaveDirectory()
2294            if not self.dirname: return True
2295        elif AskFile == 'default-dir' or AskFile == 'default':
2296            self.dirname,self.filename = os.path.split(
2297                os.path.splitext(self.G2frame.GSASprojectfile)[0] + self.extension
2298                )
2299        else:
2300            raise Exception('This should not happen!')
2301       
2302    def loadParmDict(self):
2303        '''Load the GSAS-II refinable parameters from the tree into a dict (self.parmDict). Update
2304        refined values to those from the last cycle and set the uncertainties for the
2305        refined parameters in another dict (self.sigDict).
2306
2307        Expands the parm & sig dicts to include values derived from constraints.
2308        '''
2309        self.parmDict = {}
2310        self.sigDict = {}
2311        rigidbodyDict = {}
2312        covDict = {}
2313        consDict = {}
2314        Histograms,Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
2315        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
2316        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
2317        while item:
2318            name = self.G2frame.PatternTree.GetItemText(item)
2319            if name == 'Rigid bodies':
2320                 rigidbodyDict = self.G2frame.PatternTree.GetItemPyData(item)
2321            elif name == 'Covariance':
2322                 covDict = self.G2frame.PatternTree.GetItemPyData(item)
2323            elif name == 'Constraints':
2324                 consDict = self.G2frame.PatternTree.GetItemPyData(item)
2325            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
2326        rbVary,rbDict =  G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
2327        self.parmDict.update(rbDict)
2328        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
2329        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtables,BLtables,maxSSwave =  G2stIO.GetPhaseData(
2330            Phases,RestraintDict=None,rbIds=rbIds,Print=False)
2331        self.parmDict.update(phaseDict)
2332        hapVary,hapDict,controlDict =  G2stIO.GetHistogramPhaseData(
2333            Phases,Histograms,Print=False,resetRefList=False)
2334        self.parmDict.update(hapDict)
2335        histVary,histDict,controlDict =  G2stIO.GetHistogramData(Histograms,Print=False)
2336        self.parmDict.update(histDict)
2337        self.parmDict.update(zip(
2338            covDict.get('varyList',[]),
2339            covDict.get('variables',[])))
2340        self.sigDict = dict(zip(
2341            covDict.get('varyList',[]),
2342            covDict.get('sig',[])))
2343        # expand to include constraints: first compile a list of constraints
2344        constList = []
2345        for item in consDict:
2346            if item.startswith('_'): continue
2347            constList += consDict[item]
2348        # now process the constraints
2349        G2mv.InitVars()
2350        constDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
2351        varyList = covDict.get('varyListStart')
2352        if varyList is None and len(constDict) == 0:
2353            # no constraints can use varyList
2354            varyList = covDict.get('varyList')
2355        elif varyList is None:
2356            # old GPX file from before pre-constraint varyList is saved
2357            print ' *** Old refinement: Please use Calculate/Refine to redo  ***'
2358            raise Exception(' *** Export aborted ***')
2359        else:
2360            varyList = list(varyList)
2361        try:
2362            groups,parmlist = G2mv.GroupConstraints(constDict)
2363            G2mv.GenerateConstraints(groups,parmlist,varyList,constDict,fixedList,self.parmDict)
2364        except:
2365            # this really should not happen
2366            print ' *** ERROR - constraints are internally inconsistent ***'
2367            errmsg, warnmsg = G2mv.CheckConstraints(varyList,constDict,fixedList)
2368            print 'Errors',errmsg
2369            if warnmsg: print 'Warnings',warnmsg
2370            raise Exception(' *** CIF creation aborted ***')
2371        # add the constrained values to the parameter dictionary
2372        G2mv.Dict2Map(self.parmDict,varyList)
2373        # and add their uncertainties into the esd dictionary (sigDict)
2374        if covDict.get('covMatrix') is not None:
2375            self.sigDict.update(G2mv.ComputeDepESD(covDict['covMatrix'],covDict['varyList'],self.parmDict))
2376
2377    def loadTree(self):
2378        '''Load the contents of the data tree into a set of dicts
2379        (self.OverallParms, self.Phases and self.Histogram as well as self.powderDict
2380        & self.xtalDict)
2381       
2382        * The childrenless data tree items are overall parameters/controls for the
2383          entire project and are placed in self.OverallParms
2384        * Phase items are placed in self.Phases
2385        * Data items are placed in self.Histogram. The key for these data items
2386          begin with a keyword, such as PWDR, IMG, HKLF,... that identifies the data type.
2387        '''
2388        self.OverallParms = {}
2389        self.powderDict = {}
2390        self.xtalDict = {}
2391        self.Phases = {}
2392        self.Histograms = {}
2393        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
2394        histType = None       
2395        if self.currentExportType == 'phase':
2396            # if exporting phases load them here
2397            sub = G2gd.GetPatternTreeItemId(self.G2frame,self.G2frame.root,'Phases')
2398            if not sub:
2399                print 'no phases found'
2400                return True
2401            item, cookie = self.G2frame.PatternTree.GetFirstChild(sub)
2402            while item:
2403                phaseName = self.G2frame.PatternTree.GetItemText(item)
2404                self.Phases[phaseName] =  self.G2frame.PatternTree.GetItemPyData(item)
2405                item, cookie = self.G2frame.PatternTree.GetNextChild(sub, cookie)
2406            return
2407        elif self.currentExportType == 'single':
2408            histType = 'HKLF'
2409        elif self.currentExportType == 'powder':
2410            histType = 'PWDR'
2411        elif self.currentExportType == 'image':
2412            histType = 'IMG'
2413
2414        if histType: # Loading just one kind of tree entry
2415            item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
2416            while item:
2417                name = self.G2frame.PatternTree.GetItemText(item)
2418                if name.startswith(histType):
2419                    if self.Histograms.get(name): # there is already an item with this name
2420                        print('Histogram name '+str(name)+' is repeated. Renaming')
2421                        if name[-1] == '9':
2422                            name = name[:-1] + '10'
2423                        elif name[-1] in '012345678':
2424                            name = name[:-1] + str(int(name[-1])+1)
2425                        else:                           
2426                            name += '-1'
2427                    self.Histograms[name] = {}
2428                    # the main info goes into Data, but the 0th
2429                    # element contains refinement results, carry
2430                    # that over too now.
2431                    self.Histograms[name]['Data'] = self.G2frame.PatternTree.GetItemPyData(item)[1]
2432                    self.Histograms[name][0] = self.G2frame.PatternTree.GetItemPyData(item)[0]
2433                    item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
2434                    while item2: 
2435                        child = self.G2frame.PatternTree.GetItemText(item2)
2436                        self.Histograms[name][child] = self.G2frame.PatternTree.GetItemPyData(item2)
2437                        item2, cookie2 = self.G2frame.PatternTree.GetNextChild(item, cookie2)
2438                item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
2439            # index powder and single crystal histograms by number
2440            for hist in self.Histograms:
2441                if hist.startswith("PWDR"): 
2442                    d = self.powderDict
2443                elif hist.startswith("HKLF"): 
2444                    d = self.xtalDict
2445                else:
2446                    return                   
2447                i = self.Histograms[hist].get('hId')
2448                if i is None and not d.keys():
2449                    i = 0
2450                elif i is None or i in d.keys():
2451                    i = max(d.keys())+1
2452                d[i] = hist
2453            return
2454        # else standard load: using all interlinked phases and histograms
2455        self.Histograms,self.Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
2456        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
2457        while item:
2458            name = self.G2frame.PatternTree.GetItemText(item)
2459            item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
2460            if not item2: 
2461                self.OverallParms[name] = self.G2frame.PatternTree.GetItemPyData(item)
2462            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
2463        # index powder and single crystal histograms
2464        for hist in self.Histograms:
2465            i = self.Histograms[hist]['hId']
2466            if hist.startswith("PWDR"): 
2467                self.powderDict[i] = hist
2468            elif hist.startswith("HKLF"): 
2469                self.xtalDict[i] = hist
2470
2471    def dumpTree(self,mode='type'):
2472        '''Print out information on the data tree dicts loaded in loadTree
2473        '''
2474        print '\nOverall'
2475        if mode == 'type':
2476            def Show(arg): return type(arg)
2477        else:
2478            def Show(arg): return arg
2479        for key in self.OverallParms:
2480            print '  ',key,Show(self.OverallParms[key])
2481        print 'Phases'
2482        for key1 in self.Phases:
2483            print '    ',key1,Show(self.Phases[key1])
2484        print 'Histogram'
2485        for key1 in self.Histograms:
2486            print '    ',key1,Show(self.Histograms[key1])
2487            for key2 in self.Histograms[key1]:
2488                print '      ',key2,Show(self.Histograms[key1][key2])
2489
2490    def defaultSaveFile(self):
2491        return os.path.abspath(
2492            os.path.splitext(self.G2frame.GSASprojectfile
2493                             )[0]+self.extension)
2494       
2495    def askSaveFile(self):
2496        '''Ask the user to supply a file name
2497
2498        :returns: a file name (str) or None if Cancel is pressed
2499        '''
2500        defnam = os.path.splitext(
2501            os.path.split(self.G2frame.GSASprojectfile)[1]
2502            )[0]+self.extension
2503        dlg = wx.FileDialog(
2504            self.G2frame, 'Input name for file to write', '.', defnam,
2505            self.longFormatName+' (*'+self.extension+')|*'+self.extension,
2506            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
2507        dlg.CenterOnParent()
2508        try:
2509            if dlg.ShowModal() == wx.ID_OK:
2510                filename = dlg.GetPath()
2511                # make sure extension is correct
2512                filename = os.path.splitext(filename)[0]+self.extension
2513            else:
2514                filename = None
2515        finally:
2516            dlg.Destroy()
2517        return filename
2518
2519    def askSaveDirectory(self):
2520        '''Ask the user to supply a directory name. Path name is used as the
2521        starting point for the next export path search.
2522
2523        :returns: a directory name (str) or None if Cancel is pressed
2524        '''
2525        if self.G2frame.exportDir:
2526            startdir = self.G2frame.exportDir
2527        elif self.G2frame.GSASprojectfile:
2528            startdir = os.path.split(self.G2frame.GSASprojectfile)[0]
2529        elif self.G2frame.dirname:
2530            startdir = self.G2frame.dirname
2531        else:
2532            startdir = ''
2533        dlg = wx.DirDialog(
2534            self.G2frame, 'Input directory where file(s) will be written', startdir,
2535            wx.DD_DEFAULT_STYLE)
2536        dlg.CenterOnParent()
2537        try:
2538            if dlg.ShowModal() == wx.ID_OK:
2539                filename = dlg.GetPath()
2540                self.G2frame.exportDir = filename
2541            else:
2542                filename = None
2543        finally:
2544            dlg.Destroy()
2545        return filename
2546
2547    # Tools for file writing.
2548    def OpenFile(self,fil=None,mode='w'):
2549        '''Open the output file
2550
2551        :param str fil: The name of the file to open. If None (default)
2552          the name defaults to self.dirname + self.filename.
2553          If an extension is supplied, it is not overridded,
2554          but if not, the default extension is used.
2555        :returns: the file object opened by the routine which is also
2556          saved as self.fp
2557        '''
2558        if not fil:
2559            if not os.path.splitext(self.filename)[1]:
2560                self.filename += self.extension
2561            fil = os.path.join(self.dirname,self.filename)
2562        self.fullpath = os.path.abspath(fil)
2563        self.fp = open(fil,mode)
2564        return self.fp
2565
2566    def Write(self,line):
2567        '''write a line of output, attaching a line-end character
2568
2569        :param str line: the text to be written.
2570        '''
2571        self.fp.write(line+'\n')
2572    def CloseFile(self,fp=None):
2573        '''Close a file opened in OpenFile
2574
2575        :param file fp: the file object to be closed. If None (default)
2576          file object self.fp is closed.
2577        '''
2578        if fp is None:
2579            fp = self.fp
2580            self.fp = None
2581        fp.close()
2582    # Tools to pull information out of the data arrays
2583    def GetCell(self,phasenam):
2584        """Gets the unit cell parameters and their s.u.'s for a selected phase
2585
2586        :param str phasenam: the name for the selected phase
2587        :returns: `cellList,cellSig` where each is a 7 element list corresponding
2588          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
2589          cell values and `cellSig` has their uncertainties.
2590        """
2591        phasedict = self.Phases[phasenam] # pointer to current phase info
2592        try:
2593            pfx = str(phasedict['pId'])+'::'
2594            A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict)
2595            cellSig = G2stIO.getCellEsd(pfx,phasedict['General']['SGData'],A,
2596                self.OverallParms['Covariance'])  # returns 7 vals, includes sigVol
2597            cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)
2598            return cellList,cellSig
2599        except KeyError:
2600            cell = phasedict['General']['Cell'][1:]
2601            return cell,7*[0]
2602   
2603    def GetAtoms(self,phasenam):
2604        """Gets the atoms associated with a phase. Can be used with standard
2605        or macromolecular phases
2606
2607        :param str phasenam: the name for the selected phase
2608        :returns: a list of items for eac atom where each item is a list containing:
2609          label, typ, mult, xyz, and td, where
2610
2611          * label and typ are the atom label and the scattering factor type (str)
2612          * mult is the site multiplicity (int)
2613          * xyz is contains a list with four pairs of numbers:
2614            x, y, z and fractional occupancy and
2615            their standard uncertainty (or a negative value)
2616          * td is contains a list with either one or six pairs of numbers:
2617            if one number it is U\ :sub:`iso` and with six numbers it is
2618            U\ :sub:`11`, U\ :sub:`22`, U\ :sub:`33`, U\ :sub:`12`, U\ :sub:`13` & U\ :sub:`23`
2619            paired with their standard uncertainty (or a negative value)
2620        """
2621        phasedict = self.Phases[phasenam] # pointer to current phase info           
2622        cx,ct,cs,cia = phasedict['General']['AtomPtrs']
2623        cfrac = cx+3
2624        fpfx = str(phasedict['pId'])+'::Afrac:'       
2625        atomslist = []
2626        for i,at in enumerate(phasedict['Atoms']):
2627            if phasedict['General']['Type'] == 'macromolecular':
2628                label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2])
2629            else:
2630                label = at[ct-1]
2631            fval = self.parmDict.get(fpfx+str(i),at[cfrac])
2632            fsig = self.sigDict.get(fpfx+str(i),-0.009)
2633            mult = at[cs+1]
2634            typ = at[ct]
2635            xyz = []
2636            for j,v in enumerate(('x','y','z')):
2637                val = at[cx+j]
2638                pfx = str(phasedict['pId'])+'::dA'+v+':'+str(i)
2639                sig = self.sigDict.get(pfx,-0.000009)
2640                xyz.append((val,sig))
2641            xyz.append((fval,fsig))
2642            td = []
2643            if at[cia] == 'I':
2644                pfx = str(phasedict['pId'])+'::AUiso:'+str(i)
2645                val = self.parmDict.get(pfx,at[cia+1])
2646                sig = self.sigDict.get(pfx,-0.0009)
2647                td.append((val,sig))
2648            else:
2649                for i,var in enumerate(('AU11','AU22','AU33','AU12','AU13','AU23')):
2650                    pfx = str(phasedict['pId'])+'::'+var+':'+str(i)
2651                    val = self.parmDict.get(pfx,at[cia+2+i])
2652                    sig = self.sigDict.get(pfx,-0.0009)
2653                    td.append((val,sig))
2654            atomslist.append((label,typ,mult,xyz,td))
2655        return atomslist
2656######################################################################
2657def ExportPowderList(G2frame):
2658    '''Returns a list of extensions supported by :func:`GSASIIIO:ExportPowder`
2659   
2660    :param wx.Frame G2frame: the GSAS-II main data tree window
2661    '''
2662    extList = []
2663    for obj in G2frame.exporterlist:
2664        if 'powder' in obj.exporttype:
2665            try:
2666                obj.Writer
2667                extList.append(obj.extension)
2668            except AttributeError:
2669                pass
2670    return extList
2671
2672def ExportPowder(G2frame,TreeName,fileroot,extension):
2673    '''Writes a single powder histogram using the Export routines
2674
2675    :param wx.Frame G2frame: the GSAS-II main data tree window
2676    :param str TreeName: the name of the histogram (PWDR ...) in the data tree
2677    :param str fileroot: name for file to be written, extension ignored
2678    :param str extension: extension for file to be written (start with '.'). Must
2679      match a powder export routine that has a Writer object.
2680    '''
2681    filename = os.path.abspath(os.path.splitext(fileroot)[1]+extension)
2682    for obj in G2frame.exporterlist:
2683        if obj.extension == extension and 'powder' in obj.exporttype:
2684            obj.currentExportType = 'powder'
2685            obj.InitExport(None)
2686            obj.loadTree() # load all histograms in tree into dicts
2687            if TreeName not in obj.Histograms:
2688                raise Exception('Histogram not found: '+hst)
2689            try:
2690                obj.Writer(TreeName,filename)
2691                return
2692            except AttributeError:
2693                print('Export Routine for '+extension+' does not have a .Writer method')
2694    else:
2695        print('No Export routine supports extension '+extension)
2696
2697def ReadCIF(URLorFile):
2698    '''Open a CIF, which may be specified as a file name or as a URL using PyCifRW
2699    (from James Hester).
2700    The open routine gets confused with DOS names that begin with a letter and colon
2701    "C:\dir\" so this routine will try to open the passed name as a file and if that
2702    fails, try it as a URL
2703
2704    :param str URLorFile: string containing a URL or a file name. Code will try first
2705      to open it as a file and then as a URL.
2706
2707    :returns: a PyCifRW CIF object.
2708    '''
2709    import CifFile as cif # PyCifRW from James Hester
2710
2711    # alternate approach:
2712    #import urllib
2713    #ciffile = 'file:'+urllib.pathname2url(filename)
2714   
2715    try:
2716        fp = open(URLorFile,'r')
2717        cf = cif.ReadCif(fp)
2718        fp.close()
2719        return cf
2720    except IOError:
2721        return cif.ReadCif(URLorFile)
2722
2723if __name__ == '__main__':
2724    app = wx.PySimpleApp()
2725    frm = wx.Frame(None) # create a frame
2726    frm.Show(True)
2727    filename = '/tmp/notzip.zip'
2728    filename = '/tmp/all.zip'
2729    #filename = '/tmp/11bmb_7652.zip'
2730   
2731    #selection=None, confirmoverwrite=True, parent=None
2732    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
2733    print ExtractFileFromZip(filename,multipleselect=True)
2734                             #confirmread=False, confirmoverwrite=False)
2735
2736    # choicelist=[ ('a','b','c'),
2737    #              ('test1','test2'),('no choice',)]
2738    # titles = [ 'a, b or c', 'tests', 'No option here']
2739    # dlg = MultipleChoicesDialog(
2740    #     choicelist,titles,
2741    #     parent=frm)
2742    # if dlg.ShowModal() == wx.ID_OK:
2743    #     print 'Got OK'
Note: See TracBrowser for help on using the repository browser.