source: trunk/GSASIIIO.py @ 796

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

revise instrument parameters (again); now two dictionaries
revise key stroke options on plots

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