source: trunk/GSASIIIO.py @ 848

Last change on this file since 848 was 848, checked in by vondreele, 11 years ago

move all class stuff in GSAIIphsGUI to GSASIIgrid.py
move all DData GUI stuff to GSASIIddataGUI.py - new module
more rigid body work

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