source: trunk/GSASIIIO.py @ 794

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

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 56.1 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 16:46:26 +0000 (Wed, 24 Oct 2012) $
7# $Author: vondreele $
8# $Revision: 794 $
9# $URL: trunk/GSASIIIO.py $
10# $Id: GSASIIIO.py 794 2012-10-24 16:46:26Z 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: 794 $")
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(12)]
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            inst = dict(zip(names,zip(parms,parms,codes)))
525            for item in inst:
526                inst[item] = list(inst[item])
527            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'),inst)
528            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Peak List'),[])
529            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Index Peak List'),[])
530            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Unit Cells List'),[])             
531            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Reflection Lists'),{})             
532        else:
533            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=name+" Azm= %.2f"%(Azms[i]))
534            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
535            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
536            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0],
537                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
538            inst = dict(zip(names,zip(parms,parms,codes)))
539            for item in inst:
540                inst[item] = list(inst[item])
541            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
542            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
543            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Peak List'),[])
544            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Index Peak List'),[])
545            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Unit Cells List'),[])
546            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
547        G2frame.PatternTree.SetItemPyData(Id,[[''],[np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
548    G2frame.PatternTree.SelectItem(Id)
549    G2frame.PatternTree.Expand(Id)
550    G2frame.PatternId = Id
551           
552def powderFxyeSave(G2frame,exports,powderfile):
553    head,tail = ospath.split(powderfile)
554    name,ext = tail.split('.')
555    for i,export in enumerate(exports):
556        filename = ospath.join(head,name+'-%03d.'%(i)+ext)
557        prmname = filename.strip(ext)+'prm'
558        prm = open(prmname,'w')      #old style GSAS parm file
559        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
560        Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, \
561            PickId, 'Instrument Parameters'))
562        prm.write( '            123456789012345678901234567890123456789012345678901234567890        '+'\n')
563        prm.write( 'INS   BANK      1                                                               '+'\n')
564        prm.write(('INS   HTYPE   %sR                                                              '+'\n')%(Inst['Type'][0]))
565        if 'Lam1' in Inst:              #Ka1 & Ka2
566            prm.write(('INS  1 ICONS%10.7f%10.7f    0.0000               0.990    0     0.500   '+'\n')%(Inst['Lam1'][0],Inst['Lam2'][0]))
567        elif 'Lam' in Inst:             #single wavelength
568            prm.write(('INS  1 ICONS%10.7f%10.7f    0.0000               0.990    0     0.500   '+'\n')%(Inst['Lam'][1],0.0))
569        prm.write( 'INS  1 IRAD     0                                                               '+'\n')
570        prm.write( 'INS  1I HEAD                                                                    '+'\n')
571        prm.write( 'INS  1I ITYP    0    0.0000  180.0000         1                                 '+'\n')
572        prm.write(('INS  1DETAZM%10.3f                                                          '+'\n')%(Inst['Azimuth'][0]))
573        prm.write( 'INS  1PRCF1     3    8   0.00100                                                '+'\n')
574        prm.write(('INS  1PRCF11     %15.6g%15.6g%15.6g%15.6g   '+'\n')%(Inst['U'][1],Inst['V'][1],Inst['W'][1],0.0))
575        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.))
576        prm.close()
577        file = open(filename,'w')
578        print 'save powder pattern to file: ',filename
579        x,y,w,yc,yb,yd = G2frame.PatternTree.GetItemPyData(PickId)[1]
580        file.write(powderfile+'\n')
581        file.write('Instrument parameter file:'+ospath.split(prmname)[1]+'\n')
582        file.write('BANK 1 %d %d CONS %.2f %.2f 0 0 FXYE\n'%(len(x),len(x),\
583            100.*x[0],100.*(x[1]-x[0])))
584        s = list(np.sqrt(1./np.array(w)))       
585        XYW = zip(x,y,s)
586        for X,Y,S in XYW:
587            file.write("%15.6g %15.6g %15.6g\n" % (100.*X,Y,max(S,1.0)))
588        file.close()
589        print 'powder pattern file '+filename+' written'
590       
591def powderXyeSave(G2frame,exports,powderfile):
592    head,tail = ospath.split(powderfile)
593    name,ext = tail.split('.')
594    for i,export in enumerate(exports):
595        filename = ospath.join(head,name+'-%03d.'%(i)+ext)
596        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
597        file = open(filename,'w')
598        file.write('#%s\n'%(export))
599        print 'save powder pattern to file: ',filename
600        x,y,w,yc,yb,yd = G2frame.PatternTree.GetItemPyData(PickId)[1]
601        s = list(np.sqrt(1./np.array(w)))       
602        XYW = zip(x,y,s)
603        for X,Y,W in XYW:
604            file.write("%15.6g %15.6g %15.6g\n" % (X,Y,W))
605        file.close()
606        print 'powder pattern file '+filename+' written'
607       
608def PDFSave(G2frame,exports):   
609    for export in exports:
610        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
611        SQname = 'S(Q)'+export[4:]
612        GRname = 'G(R)'+export[4:]
613        sqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.sq')
614        grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
615        sqId = G2gd.GetPatternTreeItemId(G2frame, PickId, SQname)
616        grId = G2gd.GetPatternTreeItemId(G2frame, PickId, GRname)
617        sqdata = np.array(G2frame.PatternTree.GetItemPyData(sqId)[1][:2]).T
618        grdata = np.array(G2frame.PatternTree.GetItemPyData(grId)[1][:2]).T
619        sqfile = open(sqfilename,'w')
620        grfile = open(grfilename,'w')
621        sqfile.write('#T S(Q) %s\n'%(export))
622        grfile.write('#T G(R) %s\n'%(export))
623        sqfile.write('#L Q     S(Q)\n')
624        grfile.write('#L R     G(R)\n')
625        for q,sq in sqdata:
626            sqfile.write("%15.6g %15.6g\n" % (q,sq))
627        sqfile.close()
628        for r,gr in grdata:
629            grfile.write("%15.6g %15.6g\n" % (r,gr))
630        grfile.close()
631   
632def PeakListSave(G2frame,file,peaks):
633    print 'save peak list to file: ',G2frame.peaklistfile
634    if not peaks:
635        dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
636        try:
637            result = dlg.ShowModal()
638        finally:
639            dlg.Destroy()
640        return
641    for peak in peaks:
642        file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
643            (peak[0],peak[2],peak[4],peak[6]))
644    print 'peak list saved'
645             
646def IndexPeakListSave(G2frame,peaks):
647    file = open(G2frame.peaklistfile,'wa')
648    print 'save index peak list to file: ',G2frame.peaklistfile
649    wx.BeginBusyCursor()
650    try:
651        if not peaks:
652            dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
653            try:
654                result = dlg.ShowModal()
655            finally:
656                dlg.Destroy()
657            return
658        for peak in peaks:
659            file.write("%12.6f\n" % (peak[7]))
660        file.close()
661    finally:
662        wx.EndBusyCursor()
663    print 'index peak list saved'
664   
665def SetNewPhase(Name='New Phase',SGData=G2spc.SpcGroup('P 1')[1],cell=[1.0,1.0,1.0,90.,90,90.,1.]):
666    phaseData = {
667        'ranId':ran.randint(0,sys.maxint),
668        'General':{
669            'Name':Name,
670            'Type':'nuclear',
671            'SGData':SGData,
672            'Cell':[False,]+cell,
673            'Pawley dmin':1.0,
674            'Data plot type':'None',
675            'SH Texture':{
676                'Order':0,
677                'Model':'cylindrical',
678                'Sample omega':[False,0.0],
679                'Sample chi':[False,0.0],
680                'Sample phi':[False,0.0],
681                'SH Coeff':[False,{}],
682                'SHShow':False,
683                'PFhkl':[0,0,1],
684                'PFxyz':[0,0,1],
685                'PlotType':'Pole figure'}},
686        'Atoms':[],
687        'Drawing':{},
688        'Histograms':{},
689        'Pawley ref':[],
690        'Models':{},
691        }
692    return phaseData
693   
694def ReadEXPPhase(G2frame,filename):
695    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
696    textureData = {'Order':0,'Model':'cylindrical','Sample omega':[False,0.0],
697        'Sample chi':[False,0.0],'Sample phi':[False,0.0],'SH Coeff':[False,{}],
698        'SHShow':False,'PFhkl':[0,0,1],'PFxyz':[0,0,1],'PlotType':'Pole figure'}
699    shNcof = 0
700    file = open(filename, 'Ur')
701    S = 1
702    Expr = [{},{},{},{},{},{},{},{},{}]
703    while S:
704        S = file.readline()
705        if 'EXPR NPHAS' in S[:12]:
706            Num = S[12:-1].count('0')
707            NPhas = S[12:-1].split()
708        if 'CRS' in S[:3]:
709            N = int(S[3:4])-1
710            Expr[N][S[:12]] = S[12:-1]
711    file.close()
712    PNames = []
713    for n,N in enumerate(NPhas):
714        if N != '0':
715            result = n
716            key = 'CRS'+str(n+1)+'    PNAM'
717            PNames.append(Expr[n][key])
718    if Num < 8:
719        dlg = wx.SingleChoiceDialog(G2frame, 'Which phase to read?', 'Read phase data', PNames, wx.CHOICEDLG_STYLE)
720        try:
721            if dlg.ShowModal() == wx.ID_OK:
722                result = dlg.GetSelection()
723        finally:
724            dlg.Destroy()       
725    EXPphase = Expr[result]
726    keyList = EXPphase.keys()
727    keyList.sort()
728    SGData = {}
729    if NPhas[result] == '1':
730        Ptype = 'nuclear'
731    elif NPhas[result] in ['2','3']:
732        Ptype = 'magnetic'
733    elif NPhas[result] == '4':
734        Ptype = 'macromolecular'
735    elif NPhas[result] == '10':
736        Ptype = 'Pawley'
737    for key in keyList:
738        if 'PNAM' in key:
739           PhaseName = EXPphase[key].strip()
740        elif 'ABC   ' in key:
741            abc = [float(EXPphase[key][:10]),float(EXPphase[key][10:20]),float(EXPphase[key][20:30])]                       
742        elif 'ANGLES' in key:
743            angles = [float(EXPphase[key][:10]),float(EXPphase[key][10:20]),float(EXPphase[key][20:30])]                                               
744        elif 'SG SYM' in key:
745            SpGrp = EXPphase[key][:15].strip()
746            E,SGData = G2spc.SpcGroup(SpGrp)
747            if E:
748                E,SGData = G2spc.SpcGroup('P 1') # unlikely to need this
749        elif 'OD    ' in key:
750            SHdata = EXPphase[key].split() # may not have all 9 values
751            SHvals = 9*[0]
752            for i in range(9):
753                try:
754                    float(SHdata[i])
755                    SHvals[i] = SHdata[i]
756                except:
757                    pass
758            textureData['Order'] = int(SHvals[0])
759            textureData['Model'] = shModels[int(SHvals[2])]
760            textureData['Sample omega'] = [False,float(SHvals[6])]
761            textureData['Sample chi'] = [False,float(SHvals[7])]
762            textureData['Sample phi'] = [False,float(SHvals[8])]
763            shNcof = int(SHvals[1])
764    Atoms = []
765    if Ptype == 'nuclear':
766        for key in keyList:
767            if 'AT' in key:
768                if key[11:] == 'A':
769                    S = EXPphase[key]
770                elif key[11:] == 'B':
771                    S += EXPphase[key]
772                    Atom = [S[50:58].strip(),S[:10].strip(),'',
773                        float(S[10:20]),float(S[20:30]),float(S[30:40]),
774                        float(S[40:50]),'',int(S[60:62]),S[130:131]]
775                    if Atom[9] == 'I':
776                        Atom += [float(S[68:78]),0.,0.,0.,0.,0.,0.]
777                    elif Atom[9] == 'A':
778                        Atom += [0.0,float(S[68:78]),float(S[78:88]),
779                            float(S[88:98]),float(S[98:108]),
780                            float(S[108:118]),float(S[118:128])]
781                    XYZ = Atom[3:6]
782                    Atom[7],Atom[8] = G2spc.SytSym(XYZ,SGData)
783                    Atom.append(ran.randint(0,sys.maxint))
784                    Atoms.append(Atom)
785    elif Ptype == 'macromolecular':
786        for key in keyList:
787            if 'AT' in key[6:8]:
788                S = EXPphase[key]
789                Atom = [S[56:60],S[50:54].strip().upper(),S[54:56],
790                    S[46:51].strip(),S[:8].strip(),'',
791                    float(S[16:24]),float(S[24:32]),float(S[32:40]),
792                    float(S[8:16]),'1',1,'I',float(S[40:46]),0,0,0,0,0,0]
793                XYZ = Atom[6:9]
794                Atom[10],Atom[11] = G2spc.SytSym(XYZ,SGData)
795                Atom.append(ran.randint(0,sys.maxint))
796                Atoms.append(Atom)
797    Volume = G2lat.calc_V(G2lat.cell2A(abc+angles))
798    if shNcof:
799        shCoef = {}
800        nRec = [i+1 for i in range((shNcof-1)/6+1)]
801        for irec in nRec:
802            ODkey = keyList[0][:6]+'OD'+'%3dA'%(irec)
803            indx = EXPphase[ODkey].split()
804            ODkey = ODkey[:-1]+'B'
805            vals = EXPphase[ODkey].split()
806            for i,val in enumerate(vals):
807                key = 'C(%s,%s,%s)'%(indx[3*i],indx[3*i+1],indx[3*i+2])
808                shCoef[key] = float(val)
809        textureData['SH Coeff'] = [False,shCoef]
810       
811    Phase = SetNewPhase(Name=PhaseName,SGData=SGData,cell=abc+angles+[Volume,])
812    general = Phase['General']
813    general['Type'] = Ptype
814    general['SH Texture'] = textureData
815    Phase['Atoms'] = Atoms
816    return Phase
817       
818def ReadPDBPhase(filename):
819    EightPiSq = 8.*math.pi**2
820    file = open(filename, 'Ur')
821    Phase = {}
822    Title = ''
823    Compnd = ''
824    Atoms = []
825    A = np.zeros(shape=(3,3))
826    S = file.readline()
827    while S:
828        Atom = []
829        if 'TITLE' in S[:5]:
830            Title = S[10:72].strip()
831            S = file.readline()
832        elif 'COMPND    ' in S[:10]:
833            Compnd = S[10:72].strip()
834            S = file.readline()
835        elif 'CRYST' in S[:5]:
836            abc = S[7:34].split()
837            angles = S[34:55].split()
838            cell=[float(abc[0]),float(abc[1]),float(abc[2]),
839                float(angles[0]),float(angles[1]),float(angles[2])]
840            Volume = G2lat.calc_V(G2lat.cell2A(cell))
841            AA,AB = G2lat.cell2AB(cell)
842            SpGrp = S[55:65]
843            E,SGData = G2spc.SpcGroup(SpGrp)
844            # space group processing failed, try to look up name in table
845            if E:
846                SpGrpNorm = G2spc.StandardizeSpcName(SpGrp)
847                if SpGrpNorm:
848                    E,SGData = G2spc.SpcGroup(SpGrpNorm)
849            while E:
850                print G2spc.SGErrors(E)
851                dlg = wx.TextEntryDialog(None,
852                    SpGrp[:-1]+' is invalid \nN.B.: make sure spaces separate axial fields in symbol',
853                    'ERROR in space group symbol','',style=wx.OK)
854                if dlg.ShowModal() == wx.ID_OK:
855                    SpGrp = dlg.GetValue()
856                    E,SGData = G2spc.SpcGroup(SpGrp)
857                else:
858                    return None
859                dlg.Destroy()               
860            SGlines = G2spc.SGPrint(SGData)
861            for line in SGlines: print line
862            S = file.readline()
863        elif 'SCALE' in S[:5]:
864            V = (S[10:41].split())
865            A[int(S[5])-1] = [float(V[0]),float(V[1]),float(V[2])]
866            S = file.readline()
867        elif 'ATOM' in S[:4] or 'HETATM' in S[:6]:
868            XYZ = [float(S[31:39]),float(S[39:47]),float(S[47:55])]
869            XYZ = np.inner(AB,XYZ)
870            XYZ = np.where(abs(XYZ)<0.00001,0,XYZ)
871            SytSym,Mult = G2spc.SytSym(XYZ,SGData)
872            Uiso = float(S[61:67])/EightPiSq
873            Type = S[12:14].upper()
874            if Type[0] in '123456789':
875                Type = Type[1:]
876            Atom = [S[22:27].strip(),S[17:20].upper(),S[20:22],
877                S[12:17].strip(),Type.strip(),'',XYZ[0],XYZ[1],XYZ[2],
878                float(S[55:61]),SytSym,Mult,'I',Uiso,0,0,0,0,0,0]
879            S = file.readline()
880            if 'ANISOU' in S[:6]:
881                Uij = S[30:72].split()
882                Uij = [float(Uij[0])/10000.,float(Uij[1])/10000.,float(Uij[2])/10000.,
883                    float(Uij[3])/10000.,float(Uij[4])/10000.,float(Uij[5])/10000.]
884                Atom = Atom[:14]+Uij
885                Atom[12] = 'A'
886                S = file.readline()
887            Atom.append(ran.randint(0,sys.maxint))
888            Atoms.append(Atom)
889        else:           
890            S = file.readline()
891    file.close()
892    if Title:
893        PhaseName = Title
894    elif Compnd:
895        PhaseName = Compnd
896    else:
897        PhaseName = 'None'
898    Phase = SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell+[Volume,])
899    Phase['General']['Type'] = 'macromolecular'
900    Phase['Atoms'] = Atoms
901   
902    return Phase
903
904class MultipleChoicesDialog(wx.Dialog):
905    '''A dialog that offers a series of choices, each with a title and a wx.Choice
906    widget. Intended to be used Modally.
907    typical input:
908          choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
909          headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
910    selections are placed in self.chosen when OK is pressed
911    '''
912    def __init__(self,choicelist,headinglist,
913                 head='Select options',
914                 title='Please select from options below',
915                 parent=None):
916        self.chosen = []
917        wx.Dialog.__init__(
918            self,parent,wx.ID_ANY,head, 
919            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
920        panel = wx.Panel(self)
921        mainSizer = wx.BoxSizer(wx.VERTICAL)
922        mainSizer.Add((10,10),1)
923        topLabl = wx.StaticText(panel,wx.ID_ANY,title)
924        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.CENTER,10)
925        self.ChItems = []
926        for choice,lbl in zip(choicelist,headinglist):
927            mainSizer.Add((10,10),1)
928            self.chosen.append(0)
929            topLabl = wx.StaticText(panel,wx.ID_ANY,' '+lbl)
930            mainSizer.Add(topLabl,0,wx.ALIGN_LEFT,10)
931            self.ChItems.append(wx.Choice(self, wx.ID_ANY, (100, 50), choices = choice))
932            mainSizer.Add(self.ChItems[-1],0,wx.ALIGN_CENTER,10)
933
934        OkBtn = wx.Button(panel,-1,"Ok")
935        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
936        cancelBtn = wx.Button(panel,-1,"Cancel")
937        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
938        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
939        btnSizer.Add((20,20),1)
940        btnSizer.Add(OkBtn)
941        btnSizer.Add((20,20),1)
942        btnSizer.Add(cancelBtn)
943        btnSizer.Add((20,20),1)
944        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
945        panel.SetSizer(mainSizer)
946        panel.Fit()
947        self.Fit()
948       
949    def OnOk(self,event):
950        parent = self.GetParent()
951        if parent is not None: parent.Raise()
952        # save the results from the choice widgets
953        self.chosen = []
954        for w in self.ChItems:
955            self.chosen.append(w.GetSelection())
956        self.EndModal(wx.ID_OK)             
957           
958    def OnCancel(self,event):
959        parent = self.GetParent()
960        if parent is not None: parent.Raise()
961        self.chosen = []
962        self.EndModal(wx.ID_CANCEL)             
963           
964def ExtractFileFromZip(filename, selection=None, confirmread=True,
965                       confirmoverwrite=True, parent=None,
966                       multipleselect=False):
967    '''If the filename is a zip file, extract a file from that archive.
968      selection is used to predefine the name of the file to be extracted
969         filename case and zip directory name are ignored in selection;
970         the first matching file is used
971      confirmread if True asks the user to confirm before expanding
972         the only file in a zip
973      confirmoverwrite if True asks the user to confirm before
974        overwriting if the extracted file already exists
975      multipleselect if True allows more than one zip file to be extracted,
976        a list of file(s) is returned
977    If only one file is present, do not ask which one, otherwise offer a
978       list of choices (unless selection is used)
979    Return the name of the file that has been created or a list of files (see multipleselect)
980      If the file is not a zipfile, return the name of the input file.
981      If the zipfile is empty or no file has been selected, return None
982    '''
983    import zipfile # do this now, since we can save startup time by doing this only on need
984    import shutil
985    zloc = os.path.split(filename)[0]
986    if not zipfile.is_zipfile(filename):
987        #print("not zip")
988        return filename
989
990    z = zipfile.ZipFile(filename,'r')
991    zinfo = z.infolist()
992
993    if len(zinfo) == 0:
994        #print('Zip has no files!')
995        zlist = [-1]
996    if selection:
997        choices = [os.path.split(i.filename)[1].lower() for i in zinfo]
998        if selection.lower() in choices:
999            zlist = [choices.index(selection.lower())]
1000        else:
1001            print('debug: file '+str(selection)+' was not found in '+str(filename))
1002            zlist = [-1]
1003    elif len(zinfo) == 1 and confirmread:
1004        result = wx.ID_NO
1005        dlg = wx.MessageDialog(
1006            parent,
1007            'Is file '+str(zinfo[0].filename)+
1008            ' what you want to extract from '+
1009            str(os.path.split(filename)[1])+'?',
1010            'Confirm file', 
1011            wx.YES_NO | wx.ICON_QUESTION)
1012        try:
1013            result = dlg.ShowModal()
1014        finally:
1015            dlg.Destroy()
1016        if result == wx.ID_NO:
1017            zlist = [-1]
1018        else:
1019            zlist = [0]
1020    elif len(zinfo) == 1:
1021        zlist = [0]
1022    elif multipleselect:
1023        # select one or more from a from list
1024        choices = [i.filename for i in zinfo]
1025        dlg = wx.MultiChoiceDialog(parent,'Select file(s) to extract from zip file'+str(filename),
1026            'Choose file(s)',choices,wx.CHOICEDLG_STYLE,)
1027        if dlg.ShowModal() == wx.ID_OK:
1028            zlist = dlg.GetSelections()
1029        else:
1030            zlist = []
1031        dlg.Destroy()
1032    else:
1033        # select one from a from list
1034        choices = [i.filename for i in zinfo]
1035        dlg = wx.SingleChoiceDialog(parent,
1036            'Select file to extract from zip file'+str(filename),'Choose file',
1037            choices,)
1038        if dlg.ShowModal() == wx.ID_OK:
1039            zlist = [dlg.GetSelection()]
1040        else:
1041            zlist = [-1]
1042        dlg.Destroy()
1043       
1044    outlist = []
1045    for zindex in zlist:
1046        if zindex >= 0:
1047            efil = os.path.join(zloc, os.path.split(zinfo[zindex].filename)[1])
1048            if os.path.exists(efil) and confirmoverwrite:
1049                result = wx.ID_NO
1050                dlg = wx.MessageDialog(parent,
1051                    'File '+str(efil)+' already exists. OK to overwrite it?',
1052                    'Confirm overwrite',wx.YES_NO | wx.ICON_QUESTION)
1053                try:
1054                    result = dlg.ShowModal()
1055                finally:
1056                    dlg.Destroy()
1057                if result == wx.ID_NO:
1058                    zindex = -1
1059        if zindex >= 0:
1060            # extract the file to the current directory, regardless of it's original path
1061            #z.extract(zinfo[zindex],zloc)
1062            eloc,efil = os.path.split(zinfo[zindex].filename)
1063            outfile = os.path.join(zloc, efil)
1064            fpin = z.open(zinfo[zindex])
1065            fpout = file(outfile, "wb")
1066            shutil.copyfileobj(fpin, fpout)
1067            fpin.close()
1068            fpout.close()
1069            outlist.append(outfile)
1070    z.close()
1071    if multipleselect and len(outlist) >= 1:
1072        return outlist
1073    elif len(outlist) == 1:
1074        return outlist[0]
1075    else:
1076        return None
1077
1078######################################################################
1079# base classes for reading various types of data files
1080#   not used directly, only by subclassing
1081######################################################################
1082E,SGData = G2spc.SpcGroup('P 1') # data structure for default space group
1083class ImportBaseclass(object):
1084    '''Defines a base class for the importing of data files (diffraction
1085    data, coordinates,...
1086    '''
1087    def __init__(self,
1088                 formatName,
1089                 longFormatName=None,
1090                 extensionlist=[],
1091                 strictExtension=False,
1092                 ):
1093        self.formatName = formatName # short string naming file type
1094        if longFormatName: # longer string naming file type
1095            self.longFormatName = longFormatName
1096        else:
1097            self.longFormatName = formatName
1098        # define extensions that are allowed for the file type
1099        # for windows, remove any extensions that are duplicate, as case is ignored
1100        if sys.platform == 'windows' and extensionlist:
1101            extensionlist = list(set([s.lower() for s in extensionlist]))
1102        self.extensionlist = extensionlist
1103        # If strictExtension is True, the file will not be read, unless
1104        # the extension matches one in the extensionlist
1105        self.strictExtension = strictExtension
1106        self.warnings = ''
1107        # used for readers that will use multiple passes to read
1108        # more than one data block
1109        self.repeat = False
1110        self.repeatcount = 0
1111        #print 'created',self.__class__
1112
1113    def BlockSelector(self, ChoiceList, ParentFrame=None,
1114                      title='Select a block',
1115                      size=None, header='Block Selector'):
1116        ''' Provide a wx dialog to select a block if the file contains more
1117        than one set of data and one must be selected
1118        '''
1119        dlg = wx.SingleChoiceDialog(ParentFrame,title, header,ChoiceList,)
1120        if size: dlg.SetSize(size)
1121        if dlg.ShowModal() == wx.ID_OK:
1122            sel = dlg.GetSelection()
1123            return sel
1124        else:
1125            return None
1126        dlg.Destroy()
1127
1128    def MultipleBlockSelector(self, ChoiceList, ParentFrame=None,
1129        title='Select a block',size=None, header='Block Selector'):
1130        ''' Provide a wx dialog to select a block of data if the file contains more
1131        than one set of data and one must be selected.
1132        Returns a list of the selected blocks
1133        '''
1134        dlg = wx.MultiChoiceDialog(ParentFrame,title, header,ChoiceList+['Select all'],
1135            wx.CHOICEDLG_STYLE)
1136        if size: dlg.SetSize(size)
1137        if dlg.ShowModal() == wx.ID_OK:
1138            sel = dlg.GetSelections()
1139        else:
1140            return []
1141        dlg.Destroy()
1142        selected = []
1143        if len(ChoiceList) in sel:
1144            return range(len(ChoiceList))
1145        else:
1146            return sel
1147        return selected
1148
1149    def MultipleChoicesDialog(self, choicelist, headinglist, ParentFrame=None, **kwargs):
1150        '''A modal dialog that offers a series of choices, each with a title and a wx.Choice
1151        widget.
1152        typical input:
1153           choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1154           headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1155        optional keyword parameters are: head (window title) and title
1156        returns a list of selected indicies for each choice (or None)
1157        '''
1158        result = None
1159        dlg = MultipleChoicesDialog(choicelist,headinglist,
1160            parent=ParentFrame, **kwargs)         
1161        if dlg.ShowModal() == wx.ID_OK:
1162            result = dlg.chosen
1163        dlg.Destroy()
1164        return result
1165
1166    def ShowBusy(self):
1167        wx.BeginBusyCursor()
1168
1169    def DoneBusy(self):
1170        wx.EndBusyCursor()
1171       
1172#    def Reader(self, filename, filepointer, ParentFrame=None, **unused):
1173#        '''This method must be supplied in the child class
1174#        it will read the file
1175#        '''
1176#        return True # if read OK
1177#        return False # if an error occurs
1178
1179    def ExtensionValidator(self, filename):
1180        '''This methods checks if the file has the correct extension
1181        Return False if this filename will not be supported by this reader
1182        Return True if the extension matches the list supplied by the reader
1183        Return None if the reader allows un-registered extensions
1184        '''
1185        if filename:
1186            ext = os.path.splitext(filename)[1]
1187            if sys.platform == 'windows': ext = ext.lower()
1188            if ext in self.extensionlist: return True
1189            if self.strictExtension: return False
1190        return None
1191
1192    def ContentsValidator(self, filepointer):
1193        '''This routine will attempt to determine if the file can be read
1194        with the current format.
1195        This will typically be overridden with a method that
1196        takes a quick scan of [some of]
1197        the file contents to do a "sanity" check if the file
1198        appears to match the selected format.
1199        Expected to be called via self.Validator()
1200        '''
1201        #filepointer.seek(0) # rewind the file pointer
1202        return True
1203
1204class ImportPhase(ImportBaseclass):
1205    '''Defines a base class for the reading of files with coordinates
1206    '''
1207    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1208        strictExtension=False,):
1209        # call parent __init__
1210        ImportBaseclass.__init__(self,formatName,longFormatName,
1211            extensionlist,strictExtension)
1212        # define a default Phase structure
1213        self.Phase = SetNewPhase(Name='new phase',SGData=SGData)
1214
1215    def PhaseSelector(self, ChoiceList, ParentFrame=None,
1216        title='Select a phase', size=None,header='Phase Selector'):
1217        ''' Provide a wx dialog to select a phase if the file contains more
1218        than one phase
1219        '''
1220        return self.BlockSelector(ChoiceList,ParentFrame,title,
1221            size,header)
1222
1223######################################################################
1224class ImportStructFactor(ImportBaseclass):
1225    '''Defines a base class for the reading of files with tables
1226    of structure factors
1227    '''
1228    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1229        strictExtension=False,):
1230        ImportBaseclass.__init__(self,formatName,longFormatName,
1231            extensionlist,strictExtension)
1232
1233        # define contents of Structure Factor entry
1234        self.Controls = { # dictionary with plotting controls
1235            'Type' : 'Fosq',
1236            'ifFc' : False,    #
1237            'HKLmax' : [None,None,None],
1238            'HKLmin' : [None,None,None],
1239            'FoMax' : None,   # maximum observed structure factor as Fo
1240            'Zone' : '001',
1241            'Layer' : 0,
1242            'Scale' : 1.0,
1243            'log-lin' : 'lin',
1244            }
1245        self.Parameters = [ # list with data collection parameters
1246            ('SXC',0.70926),
1247            ['SXC',0.70926],
1248            ['Type','Lam']
1249            ]
1250        self.RefList = []
1251
1252    def UpdateParameters(self,Type=None,Wave=None):
1253        HistType = self.Parameters[0][0]
1254        HistWave = self.Parameters[0][1]
1255        if Type is not None:
1256            HistType = Type
1257        if Wave is not None:
1258            HistWave = Wave
1259        self.Parameters = [(HistType,HistWave),[HistType,HistWave],  # overwrite entire list
1260            ['Type','Lam']]
1261           
1262    def UpdateControls(self,Type='Fosq',FcalcPresent=False):
1263        '''Scan through the reflections to update the Controls dictionary
1264        '''
1265        self.Controls['Type'] = Type
1266        self.Controls['ifFc'] = FcalcPresent
1267        HKLmax = [None,None,None]
1268        HKLmin = [None,None,None]
1269        Fo2max = None
1270        for refl in self.RefList:
1271            HKL = refl[:3]
1272            if Fo2max is None:
1273                Fo2max = refl[8]
1274            else:
1275                Fo2max = max(Fo2max,refl[8])
1276            for i,hkl in enumerate(HKL):
1277                if HKLmax[i] is None:
1278                    HKLmax[i] = hkl
1279                    HKLmin[i] = hkl
1280                else:
1281                    HKLmax[i] = max(HKLmax[i],hkl)
1282                    HKLmin[i] = min(HKLmin[i],hkl)
1283        self.Controls['HKLmax'] = HKLmax
1284        self.Controls['HKLmin'] = HKLmin
1285        if Type ==  'Fosq':
1286            self.Controls['FoMax'] = np.sqrt(Fo2max)
1287        elif Type ==  'Fo':
1288            self.Controls['FoMax'] = Fo2max
1289        else:
1290            print "Unsupported Struct Fact type in ImportStructFactor.UpdateControls"
1291            raise Exception,"Unsupported Struct Fact type in ImportStructFactor.UpdateControls"
1292
1293######################################################################
1294class ImportPowderData(ImportBaseclass):
1295    '''Defines a base class for the reading of files with powder data
1296    '''
1297    # define some default instrument parameter files
1298    # just like GSAS, sigh
1299    defaultIparm_lbl = []
1300    defaultIparms = []
1301    defaultIparm_lbl.append('CuKa lab data')
1302    defaultIparms.append({
1303        'INS   HTYPE ':'PXC ',
1304        'INS  1 ICONS':'  1.540500  1.544300       0.0         0       0.7    0       0.5   ',
1305        'INS  1PRCF1 ':'    3    8      0.01                                                ',
1306        'INS  1PRCF11':'   2.000000E+00  -2.000000E+00   5.000000E+00   0.000000E+00        ',
1307        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.150000E-01   0.150000E-01        ',
1308        })
1309    defaultIparm_lbl.append('0.6A synch')
1310    defaultIparms.append({
1311        'INS   HTYPE ':'PXC ',
1312        'INS  1 ICONS':'  0.600000  0.000000       0.0         0      0.99    0       0.5   ',
1313        'INS  1PRCF1 ':'    3    8      0.01                                                ',
1314        'INS  1PRCF11':'   1.000000E+00  -1.000000E+00   0.300000E+00   0.000000E+00        ',
1315        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.100000E-01   0.100000E-01        ',
1316        })
1317    defaultIparm_lbl.append('1.5A CW neutron data')
1318    defaultIparms.append({
1319        'INS   HTYPE ':'PNC',
1320        'INS  1 ICONS':'   1.54020   0.00000   0.04000         0',
1321        'INS  1PRCF1 ':'    3    8     0.005',
1322        'INS  1PRCF11':'   0.239700E+03  -0.298200E+03   0.180800E+03   0.000000E+00',
1323        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.400000E-01   0.300000E-01',
1324        })
1325    defaultIparm_lbl.append('10m TOF backscattering bank')
1326    defaultIparms.append({
1327        'INS  1 ICONS':'   5000.00      0.00      0.00',
1328        'INS  1BNKPAR':'    1.0000   150.000',       
1329        'INS  1PRCF1 ':'    1    8   0.01000',
1330        'INS  1PRCF11':'   0.000000E+00   5.000000E+00   3.000000E-02   1.000000E-03',
1331        'INS  1PRCF12':'   0.000000E+00   4.000000E+01   0.000000E+00   0.000000E+00',       
1332        })
1333    defaultIparm_lbl.append('10m TOF 90deg bank')
1334    defaultIparms.append({
1335        'INS  1 ICONS':'   3500.00      0.00      0.00',
1336        'INS  1BNKPAR':'    1.0000    90.000',       
1337        'INS  1PRCF1 ':'    1    8   0.01000',
1338        'INS  1PRCF11':'   0.000000E+00   5.000000E+00   3.000000E-02   4.000000E-03',
1339        'INS  1PRCF12':'   0.000000E+00   8.000000E+01   0.000000E+00   0.000000E+00',       
1340        })
1341    def __init__(self,
1342                 formatName,
1343                 longFormatName=None,
1344                 extensionlist=[],
1345                 strictExtension=False,
1346                 ):
1347        ImportBaseclass.__init__(self,formatName,
1348                                            longFormatName,
1349                                            extensionlist,
1350                                            strictExtension)
1351        self.powderentry = ['',None,None] #  (filename,Pos,Bank)
1352        self.powderdata = [] # Powder dataset
1353        '''A powder data set is a list with items [x,y,w,yc,yb,yd]:
1354                np.array(x), # x-axis values
1355                np.array(y), # powder pattern intensities
1356                np.array(w), # 1/sig(intensity)^2 values (weights)
1357                np.array(yc), # calc. intensities (zero)
1358                np.array(yb), # calc. background (zero)
1359                np.array(yd), # obs-calc profiles
1360        '''                           
1361        self.comments = []
1362        self.idstring = ''
1363        self.Sample = G2pdG.SetDefaultSample()
1364        self.instparm = None # name hint
1365        self.instfile = '' # full path name to instrument parameter file
1366        self.instbank = '' # inst parm bank number
1367        self.instmsg = ''  # a label that gets printed to show
1368                           # where instrument parameters are from
1369        self.numbanks = 1
1370        self.instdict = {} # place items here that will be transferred to the instrument parameters
1371
1372if __name__ == '__main__':
1373    app = wx.PySimpleApp()
1374    frm = wx.Frame(None) # create a frame
1375    frm.Show(True)
1376    filename = '/tmp/notzip.zip'
1377    filename = '/tmp/all.zip'
1378    #filename = '/tmp/11bmb_7652.zip'
1379   
1380    #selection=None, confirmoverwrite=True, parent=None
1381    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
1382    print ExtractFileFromZip(filename,multipleselect=True)
1383                             #confirmread=False, confirmoverwrite=False)
1384
1385    # choicelist=[ ('a','b','c'),
1386    #              ('test1','test2'),('no choice',)]
1387    # titles = [ 'a, b or c', 'tests', 'No option here']
1388    # dlg = MultipleChoicesDialog(
1389    #     choicelist,titles,
1390    #     parent=frm)
1391    # if dlg.ShowModal() == wx.ID_OK:
1392    #     print 'Got OK'
Note: See TracBrowser for help on using the repository browser.