source: trunk/GSASIIIO.py @ 827

Last change on this file since 827 was 827, checked in by vondreele, 9 years ago

added gonio angles to image GUI for transfer to powder data sample GUI with integration

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