source: trunk/GSASIIIO.py @ 762

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

update py files to use native line ends, add update from svn to help menu when svn or svn.exe is in path or ./svn/bin

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