source: trunk/GSASIIIO.py @ 678

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

slight mod to message for bad gpx file

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