source: trunk/GSASIIIO.py @ 792

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

change instrument parameters to dict from lists
chase down effects - got them all?
start on TOF; read TimeMap? style data - not complete

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 55.9 KB
Line 
1# -*- coding: utf-8 -*-
2"""GSASIIIO: functions for IO of data
3   Copyright: 2008, Robert B. Von Dreele (Argonne National Laboratory)
4"""
5########### SVN repository information ###################
6# $Date: 2012-10-24 13:54:20 +0000 (Wed, 24 Oct 2012) $
7# $Author: vondreele $
8# $Revision: 792 $
9# $URL: trunk/GSASIIIO.py $
10# $Id: GSASIIIO.py 792 2012-10-24 13:54:20Z vondreele $
11########### SVN repository information ###################
12import wx
13import math
14import numpy as np
15import cPickle
16import sys
17import random as ran
18import GSASIIpath
19GSASIIpath.SetVersionNumber("$Revision: 792 $")
20import GSASIIgrid as G2gd
21import GSASIIspc as G2spc
22import GSASIIlattice as G2lat
23import GSASIIpwdGUI as G2pdG
24import GSASIIElem as G2el
25import os
26import os.path as ospath
27
28def sfloat(S):
29    if S.strip():
30        return float(S)
31    else:
32        return 0.0
33
34def sint(S):
35    if S.strip():
36        return int(S)
37    else:
38        return 0
39
40def FileDlgFixExt(dlg,file):
41    #this is needed to fix a problem in linux wx.FileDialog
42    ext = dlg.GetWildcard().split('|')[2*dlg.GetFilterIndex()+1].strip('*')
43    if ext not in file:
44        file += ext
45    return file
46       
47def GetPowderPeaks(fileName):
48    sind = lambda x: math.sin(x*math.pi/180.)
49    asind = lambda x: 180.*math.asin(x)/math.pi
50    Cuka = 1.54052
51    File = open(fileName,'Ur')
52    Comments = []
53    peaks = []
54    S = File.readline()
55    while S:
56        if S[:1] == '#':
57            Comments.append(S[:-1])
58        else:
59            item = S.split()
60            if len(item) == 1:
61                peaks.append([float(item[0]),1.0])
62            elif len(item) > 1:
63                peaks.append([float(item[0]),float(item[0])])
64        S = File.readline()
65    File.close()
66    if Comments:
67       print 'Comments on file:'
68       for Comment in Comments: print Comment
69    Peaks = []
70    if peaks[0][0] > peaks[-1][0]:          # d-spacings - assume CuKa
71        for peak in peaks:
72            dsp = peak[0]
73            sth = Cuka/(2.0*dsp)
74            if sth < 1.0:
75                tth = 2.0*asind(sth)
76            else:
77                break
78            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
79    else:                                   #2-thetas - assume Cuka (for now)
80        for peak in peaks:
81            tth = peak[0]
82            dsp = Cuka/(2.0*sind(tth/2.0))
83            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
84    return Comments,Peaks
85
86def CheckImageFile(G2frame,imagefile):
87    if not ospath.exists(imagefile):
88        dlg = wx.FileDialog(G2frame, 'Bad image file name; choose name', '.', '',\
89        'Any image file (*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img)\
90        |*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img|\
91        Any detector tif (*.tif;*.tiff)|*.tif;*.tiff|\
92        MAR file (*.mar*)|*.mar*|\
93        GE Image (*.avg;*.sum)|*.avg;*.sum|\
94        ADSC Image (*.img)|*.img|\
95        All files (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
96        try:
97            dlg.SetFilename(''+ospath.split(imagefile)[1])
98            if dlg.ShowModal() == wx.ID_OK:
99                imagefile = dlg.GetPath()
100            else:
101                imagefile = False
102        finally:
103            dlg.Destroy()
104    return imagefile
105       
106def GetImageData(G2frame,imagefile,imageOnly=False):       
107    ext = ospath.splitext(imagefile)[1]
108    Comments = []
109    if ext == '.tif' or ext == '.tiff':
110        Comments,Data,Npix,Image = GetTifData(imagefile)
111    elif ext == '.img':
112        Comments,Data,Npix,Image = GetImgData(imagefile)
113        Image[0][0] = 0
114    elif ext == '.mar3450' or ext == '.mar2300':
115        Comments,Data,Npix,Image = GetMAR345Data(imagefile)
116    elif ext in ['.sum','.avg','']:
117        Comments,Data,Npix,Image = GetGEsumData(imagefile)
118    elif ext == '.G2img':
119        Comments,Data,Npix,Image = GetG2Image(imagefile)
120    if imageOnly:
121        return Image
122    else:
123        return Comments,Data,Npix,Image
124       
125def PutG2Image(filename,Comments,Data,Npix,image):
126    File = open(filename,'wb')
127    cPickle.dump([Comments,Data,Npix,image],File,1)
128    File.close()
129    return
130   
131def GetG2Image(filename):
132    File = open(filename,'rb')
133    Comments,Data,Npix,image = cPickle.load(File)
134    File.close()
135    return Comments,Data,Npix,image
136   
137def GetGEsumData(filename,imageOnly=False):
138    import struct as st
139    import array as ar
140    if not imageOnly:
141        print 'Read GE sum file: ',filename   
142    File = open(filename,'rb')
143    if '.sum' in filename:
144        head = ['GE detector sum data from APS 1-ID',]
145        sizexy = [2048,2048]
146    elif '.avg' in filename:
147        head = ['GE detector avg data from APS 1-ID',]
148        sizexy = [2048,2048]
149    else:
150        head = ['GE detector raw data from APS 1-ID',]
151        File.seek(18)
152        size,nframes = st.unpack('<ih',File.read(6))
153        sizexy = [2048,2048]
154        pos = 8192
155        File.seek(pos)
156    Npix = sizexy[0]*sizexy[1]
157    if '.sum' in filename:
158        image = np.array(ar.array('f',File.read(4*Npix)),dtype=np.int32)
159    elif '.avg' in filename:
160        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
161    else:
162        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
163        while nframes > 1:
164            image += np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
165            nframes -= 1
166    image = np.reshape(image,(sizexy[1],sizexy[0]))
167    data = {'pixelSize':(200,200),'wavelength':0.15,'distance':250.0,'center':[204.8,204.8],'size':sizexy} 
168    File.close()   
169    if imageOnly:
170        return image
171    else:
172        return head,data,Npix,image
173       
174def GetImgData(filename,imageOnly=False):
175    import struct as st
176    import array as ar
177    if not imageOnly:
178        print 'Read ADSC img file: ',filename
179    File = open(filename,'rb')
180    head = File.read(511)
181    lines = head.split('\n')
182    head = []
183    center = [0,0]
184    for line in lines[1:-2]:
185        line = line.strip()[:-1]
186        if line:
187            if 'SIZE1' in line:
188                size = int(line.split('=')[1])
189                Npix = size*size
190            elif 'WAVELENGTH' in line:
191                wave = float(line.split('=')[1])
192            elif 'BIN' in line:
193                if line.split('=')[1] == '2x2':
194                    pixel=(102,102)
195                else:
196                    pixel = (51,51)
197            elif 'DISTANCE' in line:
198                distance = float(line.split('=')[1])
199            elif 'CENTER_X' in line:
200                center[0] = float(line.split('=')[1])
201            elif 'CENTER_Y' in line:
202                center[1] = float(line.split('=')[1])
203            head.append(line)
204    data = {'pixelSize':pixel,'wavelength':wave,'distance':distance,'center':center,'size':[size,size]}
205    image = []
206    row = 0
207    pos = 512
208    File.seek(pos)
209    image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
210    image = np.reshape(image,(sizexy[1],sizexy[0]))
211#    image = np.zeros(shape=(size,size),dtype=np.int32)   
212#    while row < size:
213#        File.seek(pos)
214#        line = ar.array('H',File.read(2*size))
215#        image[row] = np.asarray(line)
216#        row += 1
217#        pos += 2*size
218    File.close()
219    if imageOnly:
220        return image
221    else:
222        return lines[1:-2],data,Npix,image
223       
224def GetMAR345Data(filename,imageOnly=False):
225    import array as ar
226    import struct as st
227    try:
228        import pack_f as pf
229    except:
230        msg = wx.MessageDialog(None, message="Unable to load the GSAS MAR image decompression, pack_f",
231                               caption="Import Error",
232                               style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
233        msg.ShowModal()
234        return None,None,None,None
235
236    if not imageOnly:
237        print 'Read Mar345 file: ',filename
238    File = open(filename,'rb')
239    head = File.read(4095)
240    numbers = st.unpack('<iiiiiiiiii',head[:40])
241    lines = head[128:].split('\n')
242    head = []
243    for line in lines:
244        line = line.strip()
245        if 'PIXEL' in line:
246            values = line.split()
247            pixel = (int(values[2]),int(values[4]))     #in microns
248        elif 'WAVELENGTH' in line:
249            wave = float(line.split()[1])
250        elif 'DISTANCE' in line:
251            distance = float(line.split()[1])           #in mm
252        elif 'CENTER' in line:
253            values = line.split()
254            center = [float(values[2])/10.,float(values[4])/10.]    #make in mm from pixels
255        if line: 
256            head.append(line)
257    data = {'pixelSize':pixel,'wavelength':wave,'distance':distance,'center':center}
258    for line in head:
259        if 'FORMAT' in line[0:6]:
260            items = line.split()
261            size = int(items[1])
262            Npix = size*size
263    pos = 4096
264    data['size'] = [size,size]
265    File.seek(pos)
266    line = File.read(8)
267    while 'CCP4' not in line:       #get past overflow list for now
268        line = File.read(8)
269        pos += 8
270    pos += 37
271    File.seek(pos)
272    raw = File.read()
273    File.close()
274    image = np.zeros(shape=(size,size),dtype=np.int32)
275    image = pf.pack_f(len(raw),raw,size,image)
276    if imageOnly:
277        return image.T              #transpose to get it right way around
278    else:
279        return head,data,Npix,image.T
280       
281def GetTifData(filename,imageOnly=False):
282    import struct as st
283    import array as ar
284    File = open(filename,'rb')
285    dataType = 5
286    try:
287        Meta = open(filename+'.metadata','Ur')
288        head = Meta.readlines()
289        for line in head:
290            line = line.strip()
291            if 'dataType=' in line:
292                dataType = int(line.split('=')[1])
293        Meta.close()
294    except IOError:
295        print 'no metadata file found - will try to read file anyway'
296        head = ['no metadata file found',]
297       
298    tag = File.read(2)
299    byteOrd = '<'
300    if tag == 'II' and int(st.unpack('<h',File.read(2))[0]) == 42:     #little endian
301        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])
302    elif tag == 'MM' and int(st.unpack('>h',File.read(2))[0]) == 42:   #big endian
303        byteOrd = '>'
304        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])       
305    else:
306        lines = ['not a detector tiff file',]
307        return lines,0,0,0
308    File.seek(IFD)                                                  #get number of directory entries
309    NED = int(st.unpack(byteOrd+'h',File.read(2))[0])
310    IFD = {}
311    for ied in range(NED):
312        Tag,Type = st.unpack(byteOrd+'Hh',File.read(4))
313        nVal = st.unpack(byteOrd+'i',File.read(4))[0]
314        if Type == 1:
315            Value = st.unpack(byteOrd+nVal*'b',File.read(nVal))
316        elif Type == 2:
317            Value = st.unpack(byteOrd+'i',File.read(4))
318        elif Type == 3:
319            Value = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
320            x = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
321        elif Type == 4:
322            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
323        elif Type == 5:
324            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
325        elif Type == 11:
326            Value = st.unpack(byteOrd+nVal*'f',File.read(nVal*4))
327        IFD[Tag] = [Type,nVal,Value]
328#        print Tag,IFD[Tag]
329    sizexy = [IFD[256][2][0],IFD[257][2][0]]
330    [nx,ny] = sizexy
331    Npix = nx*ny
332    if 272 in IFD:
333        ifd = IFD[272]
334        File.seek(ifd[2][0])
335        S = File.read(ifd[1])
336        if 'PILATUS' in S:
337            tifType = 'Pilatus'
338            dataType = 0
339            pixy = (172,172)
340            File.seek(4096)
341            if not imageOnly:
342                print 'Read Pilatus tiff file: ',filename
343            image = ar.array('L',File.read(4*Npix))
344            image = np.array(np.asarray(image),dtype=np.int32)
345    elif 262 in IFD and IFD[262][2][0] > 4:
346        tifType = 'DND'
347        pixy = (158,158)
348        File.seek(512)
349        if not imageOnly:
350            print 'Read DND SAX/WAX-detector tiff file: ',filename
351        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
352    elif sizexy == [1536,1536]:
353        tifType = 'APS Gold'
354        pixy = (150,150)
355        File.seek(64)
356        if not imageOnly:
357            print 'Read Gold tiff file:',filename
358        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
359    elif sizexy == [2048,2048] or sizexy == [1024,1024]:
360        if IFD[273][2][0] == 8:
361            if IFD[258][2][0] == 32:
362                tifType = 'PE'
363                pixy = (200,200)
364                File.seek(8)
365                if not imageOnly:
366                    print 'Read APS PE-detector tiff file: ',filename
367                if dataType == 5:
368                    image = np.array(ar.array('f',File.read(4*Npix)),dtype=np.float32)
369                else:
370                    image = np.array(ar.array('I',File.read(4*Npix)),dtype=np.int32)
371        elif IFD[273][2][0] == 4096:
372            tifType = 'MAR'
373            pixy = (158,158)
374            File.seek(4096)
375            if not imageOnly:
376                print 'Read MAR CCD tiff file: ',filename
377            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
378        elif IFD[273][2][0] == 512:
379            tiftype = '11-ID-C'
380            pixy = [200,200]
381            File.seek(512)
382            if not imageOnly:
383                print 'Read 11-ID-C tiff file: ',filename
384            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)           
385    elif sizexy == [4096,4096]:
386        if IFD[273][2][0] == 8:
387            if IFD[258][2][0] == 16:
388                tifType = 'scanCCD'
389                pixy = (9,9)
390                File.seek(8)
391                if not imageOnly:
392                    print 'Read APS scanCCD tiff file: ',filename
393                image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
394        elif IFD[273][2][0] == 4096:
395            tifType = 'Rayonix'
396            pixy = (73.242,73.242)
397            File.seek(4096)
398            if not imageOnly:
399                print 'Read Rayonix MX300HE tiff file: ',filename
400            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
401#    elif sizexy == [960,960]:
402#        tiftype = 'PE-BE'
403#        pixy = (200,200)
404#        File.seek(8)
405#        if not imageOnly:
406#            print 'Read Gold tiff file:',filename
407#        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
408           
409    else:
410        lines = ['not a known detector tiff file',]
411        return lines,0,0,0
412       
413    image = np.reshape(image,(sizexy[1],sizexy[0]))
414    center = [pixy[0]*sizexy[0]/2000,pixy[1]*sizexy[1]/2000]
415    data = {'pixelSize':pixy,'wavelength':0.10,'distance':100.0,'center':center,'size':sizexy}
416    File.close()   
417    if imageOnly:
418        return image
419    else:
420        return head,data,Npix,image
421   
422def ProjFileOpen(G2frame):
423    file = open(G2frame.GSASprojectfile,'rb')
424    print 'load from file: ',G2frame.GSASprojectfile
425    G2frame.SetTitle("GSAS-II data tree: "+
426                     os.path.split(G2frame.GSASprojectfile)[1])
427    wx.BeginBusyCursor()
428    try:
429        while True:
430            try:
431                data = cPickle.load(file)
432            except EOFError:
433                break
434            datum = data[0]
435           
436            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=datum[0])
437            if 'PWDR' in datum[0]:               
438                G2frame.PatternTree.SetItemPyData(Id,datum[1][:3])     #temp. trim off junk
439            else:
440                G2frame.PatternTree.SetItemPyData(Id,datum[1])
441            for datus in data[1:]:
442                sub = G2frame.PatternTree.AppendItem(Id,datus[0])
443#patch
444                if datus[0] == 'Instrument Parameters' and not isinstance(datus[1],dict):
445                    datus[1] = dict(zip(datus[1][3],zip(datus[1][0],datus[1][1],datus[1][2])))
446                    for item in datus[1]:               #zip makes tuples - now make lists!
447                        datus[1][item] = list(datus[1][item])
448#end patch
449                G2frame.PatternTree.SetItemPyData(sub,datus[1])
450            if 'IMG' in datum[0]:                   #retrieve image default flag & data if set
451                Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Image Controls'))
452                if Data['setDefault']:
453                    G2frame.imageDefault = Data               
454        file.close()
455        print 'project load successful'
456        G2frame.NewPlot = True
457    except:
458        msg = wx.MessageDialog(G2frame,message="Error reading file "+
459            str(G2frame.GSASprojectfile)+". This is not a GSAS-II .gpx file",
460            caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
461        msg.ShowModal()
462    finally:
463        wx.EndBusyCursor()
464   
465def ProjFileSave(G2frame):
466    if not G2frame.PatternTree.IsEmpty():
467        file = open(G2frame.GSASprojectfile,'wb')
468        print 'save to file: ',G2frame.GSASprojectfile
469        wx.BeginBusyCursor()
470        try:
471            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
472            while item:
473                data = []
474                name = G2frame.PatternTree.GetItemText(item)
475                data.append([name,G2frame.PatternTree.GetItemPyData(item)])
476                item2, cookie2 = G2frame.PatternTree.GetFirstChild(item)
477                while item2:
478                    name = G2frame.PatternTree.GetItemText(item2)
479                    data.append([name,G2frame.PatternTree.GetItemPyData(item2)])
480                    item2, cookie2 = G2frame.PatternTree.GetNextChild(item, cookie2)                           
481                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                           
482                cPickle.dump(data,file,1)
483            file.close()
484        finally:
485            wx.EndBusyCursor()
486        print 'project save successful'
487
488def SaveIntegration(G2frame,PickId,data):
489    azms = G2frame.Integrate[1]
490    X = G2frame.Integrate[2][:-1]
491    Xminmax = [X[0],X[-1]]
492    N = len(X)
493    Id = G2frame.PatternTree.GetItemParent(PickId)
494    name = G2frame.PatternTree.GetItemText(Id)
495    name = name.replace('IMG ','PWDR ')
496    Comments = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Comments'))
497    names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
498    codes = [0 for i in range(11)]
499    LRazm = data['LRazimuth']
500    Azms = []
501    if data['fullIntegrate'] and data['outAzimuths'] == 1:
502        Azms = [45.0,]                              #a poor man's average?
503    else:
504        for i,azm in enumerate(azms[:-1]):
505            Azms.append((azms[i+1]+azm)/2.)
506    for i,azm in enumerate(azms[:-1]):
507        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
508        Id = 0
509        while item:
510            Name = G2frame.PatternTree.GetItemText(item)
511            if name == Name:
512                Id = item
513            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
514        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!
515        Y = G2frame.Integrate[0][i]
516        W = 1./Y                    #probably not true
517        Sample = G2pdG.SetDefaultSample()
518        Sample['Gonio. radius'] = data['distance']
519        if Id:
520            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Comments'),Comments)                   
521            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Limits'),[tuple(Xminmax),Xminmax])
522            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Background'),[['chebyschev',1,3,1.0,0.0,0.0],
523                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
524            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'),dict(zip(names,zip(parms,parms,codes))))
525            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Peak List'),[])
526            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Index Peak List'),[])
527            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Unit Cells List'),[])             
528            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Reflection Lists'),{})             
529        else:
530            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=name+" Azm= %.2f"%(Azms[i]))
531            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
532            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
533            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0],
534                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
535            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),dict(zip(names,zip(parms,parms,codes))))
536            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
537            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Peak List'),[])
538            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Index Peak List'),[])
539            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Unit Cells List'),[])
540            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
541        G2frame.PatternTree.SetItemPyData(Id,[[''],[np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
542    G2frame.PatternTree.SelectItem(Id)
543    G2frame.PatternTree.Expand(Id)
544    G2frame.PatternId = Id
545           
546def powderFxyeSave(G2frame,exports,powderfile):
547    head,tail = ospath.split(powderfile)
548    name,ext = tail.split('.')
549    for i,export in enumerate(exports):
550        filename = ospath.join(head,name+'-%03d.'%(i)+ext)
551        prmname = filename.strip(ext)+'prm'
552        prm = open(prmname,'w')      #old style GSAS parm file
553        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
554        Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, \
555            PickId, 'Instrument Parameters'))
556        print Inst['Type']
557        prm.write( '            123456789012345678901234567890123456789012345678901234567890        '+'\n')
558        prm.write( 'INS   BANK      1                                                               '+'\n')
559        prm.write(('INS   HTYPE   %sR                                                              '+'\n')%(Inst['Type'][0]))
560        if 'Lam1' in Inst:              #Ka1 & Ka2
561            prm.write(('INS  1 ICONS%10.7f%10.7f    0.0000               0.990    0     0.500   '+'\n')%(Inst['Lam1'],Inst['Lam2'][0]))
562        elif 'Lam' in Inst:             #single wavelength
563            prm.write(('INS  1 ICONS%10.7f%10.7f    0.0000               0.990    0     0.500   '+'\n')%(Inst['Lam'][0],0.0))
564        prm.write( 'INS  1 IRAD     0                                                               '+'\n')
565        prm.write( 'INS  1I HEAD                                                                    '+'\n')
566        prm.write( 'INS  1I ITYP    0    0.0000  180.0000         1                                 '+'\n')
567        prm.write(('INS  1DETAZM%10.3f                                                          '+'\n')%(Inst['Azimuth'][0]))
568        prm.write( 'INS  1PRCF1     3    8   0.00100                                                '+'\n')
569        prm.write(('INS  1PRCF11     %15.6g%15.6g%15.6g%15.6g   '+'\n')%(Inst['U'][0],Inst['V'][0],Inst['W'][0],0.0))
570        prm.write(('INS  1PRCF12     %15.6g%15.6g%15.6g%15.6g   '+'\n')%(Inst['X'][0],Inst['Y'][0],Inst['SH/L'][0]/2.,Inst['SH/L'][0]/2.))
571        prm.close()
572        file = open(filename,'w')
573        print 'save powder pattern to file: ',filename
574        x,y,w,yc,yb,yd = G2frame.PatternTree.GetItemPyData(PickId)[1]
575        file.write(powderfile+'\n')
576        file.write('Instrument parameter file:'+ospath.split(prmname)[1]+'\n')
577        file.write('BANK 1 %d %d CONS %.2f %.2f 0 0 FXYE\n'%(len(x),len(x),\
578            100.*x[0],100.*(x[1]-x[0])))
579        s = list(np.sqrt(1./np.array(w)))       
580        XYW = zip(x,y,s)
581        for X,Y,S in XYW:
582            file.write("%15.6g %15.6g %15.6g\n" % (100.*X,Y,max(S,1.0)))
583        file.close()
584        print 'powder pattern file '+filename+' written'
585       
586def powderXyeSave(G2frame,exports,powderfile):
587    head,tail = ospath.split(powderfile)
588    name,ext = tail.split('.')
589    for i,export in enumerate(exports):
590        filename = ospath.join(head,name+'-%03d.'%(i)+ext)
591        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
592        file = open(filename,'w')
593        file.write('#%s\n'%(export))
594        print 'save powder pattern to file: ',filename
595        x,y,w,yc,yb,yd = G2frame.PatternTree.GetItemPyData(PickId)[1]
596        s = list(np.sqrt(1./np.array(w)))       
597        XYW = zip(x,y,s)
598        for X,Y,W in XYW:
599            file.write("%15.6g %15.6g %15.6g\n" % (X,Y,W))
600        file.close()
601        print 'powder pattern file '+filename+' written'
602       
603def PDFSave(G2frame,exports):   
604    for export in exports:
605        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
606        SQname = 'S(Q)'+export[4:]
607        GRname = 'G(R)'+export[4:]
608        sqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.sq')
609        grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
610        sqId = G2gd.GetPatternTreeItemId(G2frame, PickId, SQname)
611        grId = G2gd.GetPatternTreeItemId(G2frame, PickId, GRname)
612        sqdata = np.array(G2frame.PatternTree.GetItemPyData(sqId)[1][:2]).T
613        grdata = np.array(G2frame.PatternTree.GetItemPyData(grId)[1][:2]).T
614        sqfile = open(sqfilename,'w')
615        grfile = open(grfilename,'w')
616        sqfile.write('#T S(Q) %s\n'%(export))
617        grfile.write('#T G(R) %s\n'%(export))
618        sqfile.write('#L Q     S(Q)\n')
619        grfile.write('#L R     G(R)\n')
620        for q,sq in sqdata:
621            sqfile.write("%15.6g %15.6g\n" % (q,sq))
622        sqfile.close()
623        for r,gr in grdata:
624            grfile.write("%15.6g %15.6g\n" % (r,gr))
625        grfile.close()
626   
627def PeakListSave(G2frame,file,peaks):
628    print 'save peak list to file: ',G2frame.peaklistfile
629    if not peaks:
630        dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
631        try:
632            result = dlg.ShowModal()
633        finally:
634            dlg.Destroy()
635        return
636    for peak in peaks:
637        file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
638            (peak[0],peak[2],peak[4],peak[6]))
639    print 'peak list saved'
640             
641def IndexPeakListSave(G2frame,peaks):
642    file = open(G2frame.peaklistfile,'wa')
643    print 'save index peak list to file: ',G2frame.peaklistfile
644    wx.BeginBusyCursor()
645    try:
646        if not peaks:
647            dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
648            try:
649                result = dlg.ShowModal()
650            finally:
651                dlg.Destroy()
652            return
653        for peak in peaks:
654            file.write("%12.6f\n" % (peak[7]))
655        file.close()
656    finally:
657        wx.EndBusyCursor()
658    print 'index peak list saved'
659   
660def SetNewPhase(Name='New Phase',SGData=G2spc.SpcGroup('P 1')[1],cell=[1.0,1.0,1.0,90.,90,90.,1.]):
661    phaseData = {
662        'ranId':ran.randint(0,sys.maxint),
663        'General':{
664            'Name':Name,
665            'Type':'nuclear',
666            'SGData':SGData,
667            'Cell':[False,]+cell,
668            'Pawley dmin':1.0,
669            'Data plot type':'None',
670            'SH Texture':{
671                'Order':0,
672                'Model':'cylindrical',
673                'Sample omega':[False,0.0],
674                'Sample chi':[False,0.0],
675                'Sample phi':[False,0.0],
676                'SH Coeff':[False,{}],
677                'SHShow':False,
678                'PFhkl':[0,0,1],
679                'PFxyz':[0,0,1],
680                'PlotType':'Pole figure'}},
681        'Atoms':[],
682        'Drawing':{},
683        'Histograms':{},
684        'Pawley ref':[],
685        'Models':{},
686        }
687    return phaseData
688   
689def ReadEXPPhase(G2frame,filename):
690    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
691    textureData = {'Order':0,'Model':'cylindrical','Sample omega':[False,0.0],
692        'Sample chi':[False,0.0],'Sample phi':[False,0.0],'SH Coeff':[False,{}],
693        'SHShow':False,'PFhkl':[0,0,1],'PFxyz':[0,0,1],'PlotType':'Pole figure'}
694    shNcof = 0
695    file = open(filename, 'Ur')
696    S = 1
697    Expr = [{},{},{},{},{},{},{},{},{}]
698    while S:
699        S = file.readline()
700        if 'EXPR NPHAS' in S[:12]:
701            Num = S[12:-1].count('0')
702            NPhas = S[12:-1].split()
703        if 'CRS' in S[:3]:
704            N = int(S[3:4])-1
705            Expr[N][S[:12]] = S[12:-1]
706    file.close()
707    PNames = []
708    for n,N in enumerate(NPhas):
709        if N != '0':
710            result = n
711            key = 'CRS'+str(n+1)+'    PNAM'
712            PNames.append(Expr[n][key])
713    if Num < 8:
714        dlg = wx.SingleChoiceDialog(G2frame, 'Which phase to read?', 'Read phase data', PNames, wx.CHOICEDLG_STYLE)
715        try:
716            if dlg.ShowModal() == wx.ID_OK:
717                result = dlg.GetSelection()
718        finally:
719            dlg.Destroy()       
720    EXPphase = Expr[result]
721    keyList = EXPphase.keys()
722    keyList.sort()
723    SGData = {}
724    if NPhas[result] == '1':
725        Ptype = 'nuclear'
726    elif NPhas[result] in ['2','3']:
727        Ptype = 'magnetic'
728    elif NPhas[result] == '4':
729        Ptype = 'macromolecular'
730    elif NPhas[result] == '10':
731        Ptype = 'Pawley'
732    for key in keyList:
733        if 'PNAM' in key:
734           PhaseName = EXPphase[key].strip()
735        elif 'ABC   ' in key:
736            abc = [float(EXPphase[key][:10]),float(EXPphase[key][10:20]),float(EXPphase[key][20:30])]                       
737        elif 'ANGLES' in key:
738            angles = [float(EXPphase[key][:10]),float(EXPphase[key][10:20]),float(EXPphase[key][20:30])]                                               
739        elif 'SG SYM' in key:
740            SpGrp = EXPphase[key][:15].strip()
741            E,SGData = G2spc.SpcGroup(SpGrp)
742            if E:
743                E,SGData = G2spc.SpcGroup('P 1') # unlikely to need this
744        elif 'OD    ' in key:
745            SHdata = EXPphase[key].split() # may not have all 9 values
746            SHvals = 9*[0]
747            for i in range(9):
748                try:
749                    float(SHdata[i])
750                    SHvals[i] = SHdata[i]
751                except:
752                    pass
753            textureData['Order'] = int(SHvals[0])
754            textureData['Model'] = shModels[int(SHvals[2])]
755            textureData['Sample omega'] = [False,float(SHvals[6])]
756            textureData['Sample chi'] = [False,float(SHvals[7])]
757            textureData['Sample phi'] = [False,float(SHvals[8])]
758            shNcof = int(SHvals[1])
759    Atoms = []
760    if Ptype == 'nuclear':
761        for key in keyList:
762            if 'AT' in key:
763                if key[11:] == 'A':
764                    S = EXPphase[key]
765                elif key[11:] == 'B':
766                    S += EXPphase[key]
767                    Atom = [S[50:58].strip(),S[:10].strip(),'',
768                        float(S[10:20]),float(S[20:30]),float(S[30:40]),
769                        float(S[40:50]),'',int(S[60:62]),S[130:131]]
770                    if Atom[9] == 'I':
771                        Atom += [float(S[68:78]),0.,0.,0.,0.,0.,0.]
772                    elif Atom[9] == 'A':
773                        Atom += [0.0,float(S[68:78]),float(S[78:88]),
774                            float(S[88:98]),float(S[98:108]),
775                            float(S[108:118]),float(S[118:128])]
776                    XYZ = Atom[3:6]
777                    Atom[7],Atom[8] = G2spc.SytSym(XYZ,SGData)
778                    Atom.append(ran.randint(0,sys.maxint))
779                    Atoms.append(Atom)
780    elif Ptype == 'macromolecular':
781        for key in keyList:
782            if 'AT' in key[6:8]:
783                S = EXPphase[key]
784                Atom = [S[56:60],S[50:54].strip().upper(),S[54:56],
785                    S[46:51].strip(),S[:8].strip(),'',
786                    float(S[16:24]),float(S[24:32]),float(S[32:40]),
787                    float(S[8:16]),'1',1,'I',float(S[40:46]),0,0,0,0,0,0]
788                XYZ = Atom[6:9]
789                Atom[10],Atom[11] = G2spc.SytSym(XYZ,SGData)
790                Atom.append(ran.randint(0,sys.maxint))
791                Atoms.append(Atom)
792    Volume = G2lat.calc_V(G2lat.cell2A(abc+angles))
793    if shNcof:
794        shCoef = {}
795        nRec = [i+1 for i in range((shNcof-1)/6+1)]
796        for irec in nRec:
797            ODkey = keyList[0][:6]+'OD'+'%3dA'%(irec)
798            indx = EXPphase[ODkey].split()
799            ODkey = ODkey[:-1]+'B'
800            vals = EXPphase[ODkey].split()
801            for i,val in enumerate(vals):
802                key = 'C(%s,%s,%s)'%(indx[3*i],indx[3*i+1],indx[3*i+2])
803                shCoef[key] = float(val)
804        textureData['SH Coeff'] = [False,shCoef]
805       
806    Phase = SetNewPhase(Name=PhaseName,SGData=SGData,cell=abc+angles+[Volume,])
807    general = Phase['General']
808    general['Type'] = Ptype
809    general['SH Texture'] = textureData
810    Phase['Atoms'] = Atoms
811    return Phase
812       
813def ReadPDBPhase(filename):
814    EightPiSq = 8.*math.pi**2
815    file = open(filename, 'Ur')
816    Phase = {}
817    Title = ''
818    Compnd = ''
819    Atoms = []
820    A = np.zeros(shape=(3,3))
821    S = file.readline()
822    while S:
823        Atom = []
824        if 'TITLE' in S[:5]:
825            Title = S[10:72].strip()
826            S = file.readline()
827        elif 'COMPND    ' in S[:10]:
828            Compnd = S[10:72].strip()
829            S = file.readline()
830        elif 'CRYST' in S[:5]:
831            abc = S[7:34].split()
832            angles = S[34:55].split()
833            cell=[float(abc[0]),float(abc[1]),float(abc[2]),
834                float(angles[0]),float(angles[1]),float(angles[2])]
835            Volume = G2lat.calc_V(G2lat.cell2A(cell))
836            AA,AB = G2lat.cell2AB(cell)
837            SpGrp = S[55:65]
838            E,SGData = G2spc.SpcGroup(SpGrp)
839            # space group processing failed, try to look up name in table
840            if E:
841                SpGrpNorm = G2spc.StandardizeSpcName(SpGrp)
842                if SpGrpNorm:
843                    E,SGData = G2spc.SpcGroup(SpGrpNorm)
844            while E:
845                print G2spc.SGErrors(E)
846                dlg = wx.TextEntryDialog(None,
847                    SpGrp[:-1]+' is invalid \nN.B.: make sure spaces separate axial fields in symbol',
848                    'ERROR in space group symbol','',style=wx.OK)
849                if dlg.ShowModal() == wx.ID_OK:
850                    SpGrp = dlg.GetValue()
851                    E,SGData = G2spc.SpcGroup(SpGrp)
852                else:
853                    return None
854                dlg.Destroy()               
855            SGlines = G2spc.SGPrint(SGData)
856            for line in SGlines: print line
857            S = file.readline()
858        elif 'SCALE' in S[:5]:
859            V = (S[10:41].split())
860            A[int(S[5])-1] = [float(V[0]),float(V[1]),float(V[2])]
861            S = file.readline()
862        elif 'ATOM' in S[:4] or 'HETATM' in S[:6]:
863            XYZ = [float(S[31:39]),float(S[39:47]),float(S[47:55])]
864            XYZ = np.inner(AB,XYZ)
865            XYZ = np.where(abs(XYZ)<0.00001,0,XYZ)
866            SytSym,Mult = G2spc.SytSym(XYZ,SGData)
867            Uiso = float(S[61:67])/EightPiSq
868            Type = S[12:14].upper()
869            if Type[0] in '123456789':
870                Type = Type[1:]
871            Atom = [S[22:27].strip(),S[17:20].upper(),S[20:22],
872                S[12:17].strip(),Type.strip(),'',XYZ[0],XYZ[1],XYZ[2],
873                float(S[55:61]),SytSym,Mult,'I',Uiso,0,0,0,0,0,0]
874            S = file.readline()
875            if 'ANISOU' in S[:6]:
876                Uij = S[30:72].split()
877                Uij = [float(Uij[0])/10000.,float(Uij[1])/10000.,float(Uij[2])/10000.,
878                    float(Uij[3])/10000.,float(Uij[4])/10000.,float(Uij[5])/10000.]
879                Atom = Atom[:14]+Uij
880                Atom[12] = 'A'
881                S = file.readline()
882            Atom.append(ran.randint(0,sys.maxint))
883            Atoms.append(Atom)
884        else:           
885            S = file.readline()
886    file.close()
887    if Title:
888        PhaseName = Title
889    elif Compnd:
890        PhaseName = Compnd
891    else:
892        PhaseName = 'None'
893    Phase = SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell+[Volume,])
894    Phase['General']['Type'] = 'macromolecular'
895    Phase['Atoms'] = Atoms
896   
897    return Phase
898
899class MultipleChoicesDialog(wx.Dialog):
900    '''A dialog that offers a series of choices, each with a title and a wx.Choice
901    widget. Intended to be used Modally.
902    typical input:
903          choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
904          headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
905    selections are placed in self.chosen when OK is pressed
906    '''
907    def __init__(self,choicelist,headinglist,
908                 head='Select options',
909                 title='Please select from options below',
910                 parent=None):
911        self.chosen = []
912        wx.Dialog.__init__(
913            self,parent,wx.ID_ANY,head, 
914            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
915        panel = wx.Panel(self)
916        mainSizer = wx.BoxSizer(wx.VERTICAL)
917        mainSizer.Add((10,10),1)
918        topLabl = wx.StaticText(panel,wx.ID_ANY,title)
919        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.CENTER,10)
920        self.ChItems = []
921        for choice,lbl in zip(choicelist,headinglist):
922            mainSizer.Add((10,10),1)
923            self.chosen.append(0)
924            topLabl = wx.StaticText(panel,wx.ID_ANY,' '+lbl)
925            mainSizer.Add(topLabl,0,wx.ALIGN_LEFT,10)
926            self.ChItems.append(wx.Choice(self, wx.ID_ANY, (100, 50), choices = choice))
927            mainSizer.Add(self.ChItems[-1],0,wx.ALIGN_CENTER,10)
928
929        OkBtn = wx.Button(panel,-1,"Ok")
930        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
931        cancelBtn = wx.Button(panel,-1,"Cancel")
932        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
933        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
934        btnSizer.Add((20,20),1)
935        btnSizer.Add(OkBtn)
936        btnSizer.Add((20,20),1)
937        btnSizer.Add(cancelBtn)
938        btnSizer.Add((20,20),1)
939        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
940        panel.SetSizer(mainSizer)
941        panel.Fit()
942        self.Fit()
943       
944    def OnOk(self,event):
945        parent = self.GetParent()
946        if parent is not None: parent.Raise()
947        # save the results from the choice widgets
948        self.chosen = []
949        for w in self.ChItems:
950            self.chosen.append(w.GetSelection())
951        self.EndModal(wx.ID_OK)             
952           
953    def OnCancel(self,event):
954        parent = self.GetParent()
955        if parent is not None: parent.Raise()
956        self.chosen = []
957        self.EndModal(wx.ID_CANCEL)             
958           
959def ExtractFileFromZip(filename, selection=None, confirmread=True,
960                       confirmoverwrite=True, parent=None,
961                       multipleselect=False):
962    '''If the filename is a zip file, extract a file from that archive.
963      selection is used to predefine the name of the file to be extracted
964         filename case and zip directory name are ignored in selection;
965         the first matching file is used
966      confirmread if True asks the user to confirm before expanding
967         the only file in a zip
968      confirmoverwrite if True asks the user to confirm before
969        overwriting if the extracted file already exists
970      multipleselect if True allows more than one zip file to be extracted,
971        a list of file(s) is returned
972    If only one file is present, do not ask which one, otherwise offer a
973       list of choices (unless selection is used)
974    Return the name of the file that has been created or a list of files (see multipleselect)
975      If the file is not a zipfile, return the name of the input file.
976      If the zipfile is empty or no file has been selected, return None
977    '''
978    import zipfile # do this now, since we can save startup time by doing this only on need
979    import shutil
980    zloc = os.path.split(filename)[0]
981    if not zipfile.is_zipfile(filename):
982        #print("not zip")
983        return filename
984
985    z = zipfile.ZipFile(filename,'r')
986    zinfo = z.infolist()
987
988    if len(zinfo) == 0:
989        #print('Zip has no files!')
990        zlist = [-1]
991    if selection:
992        choices = [os.path.split(i.filename)[1].lower() for i in zinfo]
993        if selection.lower() in choices:
994            zlist = [choices.index(selection.lower())]
995        else:
996            print('debug: file '+str(selection)+' was not found in '+str(filename))
997            zlist = [-1]
998    elif len(zinfo) == 1 and confirmread:
999        result = wx.ID_NO
1000        dlg = wx.MessageDialog(
1001            parent,
1002            'Is file '+str(zinfo[0].filename)+
1003            ' what you want to extract from '+
1004            str(os.path.split(filename)[1])+'?',
1005            'Confirm file', 
1006            wx.YES_NO | wx.ICON_QUESTION)
1007        try:
1008            result = dlg.ShowModal()
1009        finally:
1010            dlg.Destroy()
1011        if result == wx.ID_NO:
1012            zlist = [-1]
1013        else:
1014            zlist = [0]
1015    elif len(zinfo) == 1:
1016        zlist = [0]
1017    elif multipleselect:
1018        # select one or more from a from list
1019        choices = [i.filename for i in zinfo]
1020        dlg = wx.MultiChoiceDialog(parent,'Select file(s) to extract from zip file'+str(filename),
1021            'Choose file(s)',choices,wx.CHOICEDLG_STYLE,)
1022        if dlg.ShowModal() == wx.ID_OK:
1023            zlist = dlg.GetSelections()
1024        else:
1025            zlist = []
1026        dlg.Destroy()
1027    else:
1028        # select one from a from list
1029        choices = [i.filename for i in zinfo]
1030        dlg = wx.SingleChoiceDialog(parent,
1031            'Select file to extract from zip file'+str(filename),'Choose file',
1032            choices,)
1033        if dlg.ShowModal() == wx.ID_OK:
1034            zlist = [dlg.GetSelection()]
1035        else:
1036            zlist = [-1]
1037        dlg.Destroy()
1038       
1039    outlist = []
1040    for zindex in zlist:
1041        if zindex >= 0:
1042            efil = os.path.join(zloc, os.path.split(zinfo[zindex].filename)[1])
1043            if os.path.exists(efil) and confirmoverwrite:
1044                result = wx.ID_NO
1045                dlg = wx.MessageDialog(parent,
1046                    'File '+str(efil)+' already exists. OK to overwrite it?',
1047                    'Confirm overwrite',wx.YES_NO | wx.ICON_QUESTION)
1048                try:
1049                    result = dlg.ShowModal()
1050                finally:
1051                    dlg.Destroy()
1052                if result == wx.ID_NO:
1053                    zindex = -1
1054        if zindex >= 0:
1055            # extract the file to the current directory, regardless of it's original path
1056            #z.extract(zinfo[zindex],zloc)
1057            eloc,efil = os.path.split(zinfo[zindex].filename)
1058            outfile = os.path.join(zloc, efil)
1059            fpin = z.open(zinfo[zindex])
1060            fpout = file(outfile, "wb")
1061            shutil.copyfileobj(fpin, fpout)
1062            fpin.close()
1063            fpout.close()
1064            outlist.append(outfile)
1065    z.close()
1066    if multipleselect and len(outlist) >= 1:
1067        return outlist
1068    elif len(outlist) == 1:
1069        return outlist[0]
1070    else:
1071        return None
1072
1073######################################################################
1074# base classes for reading various types of data files
1075#   not used directly, only by subclassing
1076######################################################################
1077E,SGData = G2spc.SpcGroup('P 1') # data structure for default space group
1078class ImportBaseclass(object):
1079    '''Defines a base class for the importing of data files (diffraction
1080    data, coordinates,...
1081    '''
1082    def __init__(self,
1083                 formatName,
1084                 longFormatName=None,
1085                 extensionlist=[],
1086                 strictExtension=False,
1087                 ):
1088        self.formatName = formatName # short string naming file type
1089        if longFormatName: # longer string naming file type
1090            self.longFormatName = longFormatName
1091        else:
1092            self.longFormatName = formatName
1093        # define extensions that are allowed for the file type
1094        # for windows, remove any extensions that are duplicate, as case is ignored
1095        if sys.platform == 'windows' and extensionlist:
1096            extensionlist = list(set([s.lower() for s in extensionlist]))
1097        self.extensionlist = extensionlist
1098        # If strictExtension is True, the file will not be read, unless
1099        # the extension matches one in the extensionlist
1100        self.strictExtension = strictExtension
1101        self.warnings = ''
1102        # used for readers that will use multiple passes to read
1103        # more than one data block
1104        self.repeat = False
1105        self.repeatcount = 0
1106        #print 'created',self.__class__
1107
1108    def BlockSelector(self, ChoiceList, ParentFrame=None,
1109                      title='Select a block',
1110                      size=None, header='Block Selector'):
1111        ''' Provide a wx dialog to select a block if the file contains more
1112        than one set of data and one must be selected
1113        '''
1114        dlg = wx.SingleChoiceDialog(ParentFrame,title, header,ChoiceList,)
1115        if size: dlg.SetSize(size)
1116        if dlg.ShowModal() == wx.ID_OK:
1117            sel = dlg.GetSelection()
1118            return sel
1119        else:
1120            return None
1121        dlg.Destroy()
1122
1123    def MultipleBlockSelector(self, ChoiceList, ParentFrame=None,
1124        title='Select a block',size=None, header='Block Selector'):
1125        ''' Provide a wx dialog to select a block of data if the file contains more
1126        than one set of data and one must be selected.
1127        Returns a list of the selected blocks
1128        '''
1129        dlg = wx.MultiChoiceDialog(ParentFrame,title, header,ChoiceList+['Select all'],
1130            wx.CHOICEDLG_STYLE)
1131        if size: dlg.SetSize(size)
1132        if dlg.ShowModal() == wx.ID_OK:
1133            sel = dlg.GetSelections()
1134        else:
1135            return []
1136        dlg.Destroy()
1137        selected = []
1138        if len(ChoiceList) in sel:
1139            return range(len(ChoiceList))
1140        else:
1141            return sel
1142        return selected
1143
1144    def MultipleChoicesDialog(self, choicelist, headinglist, ParentFrame=None, **kwargs):
1145        '''A modal dialog that offers a series of choices, each with a title and a wx.Choice
1146        widget.
1147        typical input:
1148           choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1149           headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1150        optional keyword parameters are: head (window title) and title
1151        returns a list of selected indicies for each choice (or None)
1152        '''
1153        result = None
1154        dlg = MultipleChoicesDialog(choicelist,headinglist,
1155            parent=ParentFrame, **kwargs)         
1156        if dlg.ShowModal() == wx.ID_OK:
1157            result = dlg.chosen
1158        dlg.Destroy()
1159        return result
1160
1161    def ShowBusy(self):
1162        wx.BeginBusyCursor()
1163
1164    def DoneBusy(self):
1165        wx.EndBusyCursor()
1166       
1167#    def Reader(self, filename, filepointer, ParentFrame=None, **unused):
1168#        '''This method must be supplied in the child class
1169#        it will read the file
1170#        '''
1171#        return True # if read OK
1172#        return False # if an error occurs
1173
1174    def ExtensionValidator(self, filename):
1175        '''This methods checks if the file has the correct extension
1176        Return False if this filename will not be supported by this reader
1177        Return True if the extension matches the list supplied by the reader
1178        Return None if the reader allows un-registered extensions
1179        '''
1180        if filename:
1181            ext = os.path.splitext(filename)[1]
1182            if sys.platform == 'windows': ext = ext.lower()
1183            if ext in self.extensionlist: return True
1184            if self.strictExtension: return False
1185        return None
1186
1187    def ContentsValidator(self, filepointer):
1188        '''This routine will attempt to determine if the file can be read
1189        with the current format.
1190        This will typically be overridden with a method that
1191        takes a quick scan of [some of]
1192        the file contents to do a "sanity" check if the file
1193        appears to match the selected format.
1194        Expected to be called via self.Validator()
1195        '''
1196        #filepointer.seek(0) # rewind the file pointer
1197        return True
1198
1199class ImportPhase(ImportBaseclass):
1200    '''Defines a base class for the reading of files with coordinates
1201    '''
1202    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1203        strictExtension=False,):
1204        # call parent __init__
1205        ImportBaseclass.__init__(self,formatName,longFormatName,
1206            extensionlist,strictExtension)
1207        # define a default Phase structure
1208        self.Phase = SetNewPhase(Name='new phase',SGData=SGData)
1209
1210    def PhaseSelector(self, ChoiceList, ParentFrame=None,
1211        title='Select a phase', size=None,header='Phase Selector'):
1212        ''' Provide a wx dialog to select a phase if the file contains more
1213        than one phase
1214        '''
1215        return self.BlockSelector(ChoiceList,ParentFrame,title,
1216            size,header)
1217
1218######################################################################
1219class ImportStructFactor(ImportBaseclass):
1220    '''Defines a base class for the reading of files with tables
1221    of structure factors
1222    '''
1223    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1224        strictExtension=False,):
1225        ImportBaseclass.__init__(self,formatName,longFormatName,
1226            extensionlist,strictExtension)
1227
1228        # define contents of Structure Factor entry
1229        self.Controls = { # dictionary with plotting controls
1230            'Type' : 'Fosq',
1231            'ifFc' : False,    #
1232            'HKLmax' : [None,None,None],
1233            'HKLmin' : [None,None,None],
1234            'FoMax' : None,   # maximum observed structure factor as Fo
1235            'Zone' : '001',
1236            'Layer' : 0,
1237            'Scale' : 1.0,
1238            'log-lin' : 'lin',
1239            }
1240        self.Parameters = [ # list with data collection parameters
1241            ('SXC',0.70926),
1242            ['SXC',0.70926],
1243            ['Type','Lam']
1244            ]
1245        self.RefList = []
1246
1247    def UpdateParameters(self,Type=None,Wave=None):
1248        HistType = self.Parameters[0][0]
1249        HistWave = self.Parameters[0][1]
1250        if Type is not None:
1251            HistType = Type
1252        if Wave is not None:
1253            HistWave = Wave
1254        self.Parameters = [(HistType,HistWave),[HistType,HistWave],  # overwrite entire list
1255            ['Type','Lam']]
1256           
1257    def UpdateControls(self,Type='Fosq',FcalcPresent=False):
1258        '''Scan through the reflections to update the Controls dictionary
1259        '''
1260        self.Controls['Type'] = Type
1261        self.Controls['ifFc'] = FcalcPresent
1262        HKLmax = [None,None,None]
1263        HKLmin = [None,None,None]
1264        Fo2max = None
1265        for refl in self.RefList:
1266            HKL = refl[:3]
1267            if Fo2max is None:
1268                Fo2max = refl[8]
1269            else:
1270                Fo2max = max(Fo2max,refl[8])
1271            for i,hkl in enumerate(HKL):
1272                if HKLmax[i] is None:
1273                    HKLmax[i] = hkl
1274                    HKLmin[i] = hkl
1275                else:
1276                    HKLmax[i] = max(HKLmax[i],hkl)
1277                    HKLmin[i] = min(HKLmin[i],hkl)
1278        self.Controls['HKLmax'] = HKLmax
1279        self.Controls['HKLmin'] = HKLmin
1280        if Type ==  'Fosq':
1281            self.Controls['FoMax'] = np.sqrt(Fo2max)
1282        elif Type ==  'Fo':
1283            self.Controls['FoMax'] = Fo2max
1284        else:
1285            print "Unsupported Struct Fact type in ImportStructFactor.UpdateControls"
1286            raise Exception,"Unsupported Struct Fact type in ImportStructFactor.UpdateControls"
1287
1288######################################################################
1289class ImportPowderData(ImportBaseclass):
1290    '''Defines a base class for the reading of files with powder data
1291    '''
1292    # define some default instrument parameter files
1293    # just like GSAS, sigh
1294    defaultIparm_lbl = []
1295    defaultIparms = []
1296    defaultIparm_lbl.append('CuKa lab data')
1297    defaultIparms.append({
1298        'INS   HTYPE ':'PXC ',
1299        'INS  1 ICONS':'  1.540500  1.544300       0.0         0       0.7    0       0.5   ',
1300        'INS  1PRCF1 ':'    3    8      0.01                                                ',
1301        'INS  1PRCF11':'   2.000000E+00  -2.000000E+00   5.000000E+00   0.000000E+00        ',
1302        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.150000E-01   0.150000E-01        ',
1303        })
1304    defaultIparm_lbl.append('0.6A synch')
1305    defaultIparms.append({
1306        'INS   HTYPE ':'PXC ',
1307        'INS  1 ICONS':'  0.600000  0.000000       0.0         0      0.99    0       0.5   ',
1308        'INS  1PRCF1 ':'    3    8      0.01                                                ',
1309        'INS  1PRCF11':'   1.000000E+00  -1.000000E+00   0.300000E+00   0.000000E+00        ',
1310        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.100000E-01   0.100000E-01        ',
1311        })
1312    defaultIparm_lbl.append('1.5A CW neutron data')
1313    defaultIparms.append({
1314        'INS   HTYPE ':'PNC',
1315        'INS  1 ICONS':'   1.54020   0.00000   0.04000         0',
1316        'INS  1PRCF1 ':'    3    8     0.005',
1317        'INS  1PRCF11':'   0.239700E+03  -0.298200E+03   0.180800E+03   0.000000E+00',
1318        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.400000E-01   0.300000E-01',
1319        })
1320    defaultIparm_lbl.append('10m TOF backscattering bank')
1321    defaultIparms.append({
1322        'INS  1 ICONS':'   5000.00      0.00      0.00',
1323        'INS  1BNKPAR':'    1.0000   150.000',       
1324        'INS  1PRCF1 ':'    1    8   0.01000',
1325        'INS  1PRCF11':'   0.000000E+00   5.000000E+00   3.000000E-02   1.000000E-03',
1326        'INS  1PRCF12':'   0.000000E+00   4.000000E+01   0.000000E+00   0.000000E+00',       
1327        })
1328    defaultIparm_lbl.append('10m TOF 90deg bank')
1329    defaultIparms.append({
1330        'INS  1 ICONS':'   3500.00      0.00      0.00',
1331        'INS  1BNKPAR':'    1.0000    90.000',       
1332        'INS  1PRCF1 ':'    1    8   0.01000',
1333        'INS  1PRCF11':'   0.000000E+00   5.000000E+00   3.000000E-02   4.000000E-03',
1334        'INS  1PRCF12':'   0.000000E+00   8.000000E+01   0.000000E+00   0.000000E+00',       
1335        })
1336    def __init__(self,
1337                 formatName,
1338                 longFormatName=None,
1339                 extensionlist=[],
1340                 strictExtension=False,
1341                 ):
1342        ImportBaseclass.__init__(self,formatName,
1343                                            longFormatName,
1344                                            extensionlist,
1345                                            strictExtension)
1346        self.powderentry = ['',None,None] #  (filename,Pos,Bank)
1347        self.powderdata = [] # Powder dataset
1348        '''A powder data set is a list with items [x,y,w,yc,yb,yd]:
1349                np.array(x), # x-axis values
1350                np.array(y), # powder pattern intensities
1351                np.array(w), # 1/sig(intensity)^2 values (weights)
1352                np.array(yc), # calc. intensities (zero)
1353                np.array(yb), # calc. background (zero)
1354                np.array(yd), # obs-calc profiles
1355        '''                           
1356        self.comments = []
1357        self.idstring = ''
1358        self.Sample = G2pdG.SetDefaultSample()
1359        self.instparm = None # name hint
1360        self.instfile = '' # full path name to instrument parameter file
1361        self.instbank = '' # inst parm bank number
1362        self.instmsg = ''  # a label that gets printed to show
1363                           # where instrument parameters are from
1364        self.numbanks = 1
1365        self.instdict = {} # place items here that will be transferred to the instrument parameters
1366
1367if __name__ == '__main__':
1368    app = wx.PySimpleApp()
1369    frm = wx.Frame(None) # create a frame
1370    frm.Show(True)
1371    filename = '/tmp/notzip.zip'
1372    filename = '/tmp/all.zip'
1373    #filename = '/tmp/11bmb_7652.zip'
1374   
1375    #selection=None, confirmoverwrite=True, parent=None
1376    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
1377    print ExtractFileFromZip(filename,multipleselect=True)
1378                             #confirmread=False, confirmoverwrite=False)
1379
1380    # choicelist=[ ('a','b','c'),
1381    #              ('test1','test2'),('no choice',)]
1382    # titles = [ 'a, b or c', 'tests', 'No option here']
1383    # dlg = MultipleChoicesDialog(
1384    #     choicelist,titles,
1385    #     parent=frm)
1386    # if dlg.ShowModal() == wx.ID_OK:
1387    #     print 'Got OK'
Note: See TracBrowser for help on using the repository browser.