source: trunk/GSASIIIO.py @ 894

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

fix pixel size for MAR225

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