source: trunk/GSASIIIO.py @ 677

Last change on this file since 677 was 677, checked in by toby, 10 years ago

Provide error message on project import

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