source: trunk/GSASIIIO.py @ 1115

Last change on this file since 1115 was 1115, checked in by toby, 8 years ago

rework exports for new types

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 91.1 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2013-10-18 21:00:32 +0000 (Fri, 18 Oct 2013) $
4# $Author: toby $
5# $Revision: 1115 $
6# $URL: trunk/GSASIIIO.py $
7# $Id: GSASIIIO.py 1115 2013-10-18 21:00:32Z toby $
8########### SVN repository information ###################
9'''
10*GSASIIIO: Misc I/O routines*
11=============================
12
13Module with miscellaneous routines for input and output. Many
14are GUI routines to interact with user.
15
16Includes support for image reading.
17
18Also includes base classes for data import routines.
19
20'''
21"""GSASIIIO: functions for IO of data
22   Copyright: 2008, Robert B. Von Dreele (Argonne National Laboratory)
23"""
24import wx
25import math
26import numpy as np
27import cPickle
28import sys
29import re
30import random as ran
31import GSASIIpath
32GSASIIpath.SetVersionNumber("$Revision: 1115 $")
33import GSASIIgrid as G2gd
34import GSASIIspc as G2spc
35import GSASIIlattice as G2lat
36import GSASIIpwdGUI as G2pdG
37import GSASIIElem as G2el
38import GSASIIstrIO as G2stIO
39import GSASIImapvars as G2mv
40import os
41import os.path as ospath
42
43def sfloat(S):
44    'Convert a string to float. An empty field is treated as zero'
45    if S.strip():
46        return float(S)
47    else:
48        return 0.0
49
50def sint(S):
51    'Convert a string to int. An empty field is treated as zero'
52    if S.strip():
53        return int(S)
54    else:
55        return 0
56
57def trim(val):
58    '''Simplify a string containing leading and trailing spaces
59    as well as newlines, tabs, repeated spaces etc. into a shorter and
60    more simple string, by replacing all ranges of whitespace
61    characters with a single space.
62
63    :param str val: the string to be simplified
64
65    :returns: the (usually) shortened version of the string
66    '''
67    return re.sub('\s+', ' ', val).strip()
68
69def makeInstDict(names,data,codes):
70    inst = dict(zip(names,zip(data,data,codes)))
71    for item in inst:
72        inst[item] = list(inst[item])
73    return inst
74
75def FileDlgFixExt(dlg,file):
76    'this is needed to fix a problem in linux wx.FileDialog'
77    ext = dlg.GetWildcard().split('|')[2*dlg.GetFilterIndex()+1].strip('*')
78    if ext not in file:
79        file += ext
80    return file
81       
82def GetPowderPeaks(fileName):
83    'Read powder peaks from a file'
84    sind = lambda x: math.sin(x*math.pi/180.)
85    asind = lambda x: 180.*math.asin(x)/math.pi
86    Cuka = 1.54052
87    File = open(fileName,'Ur')
88    Comments = []
89    peaks = []
90    S = File.readline()
91    while S:
92        if S[:1] == '#':
93            Comments.append(S[:-1])
94        else:
95            item = S.split()
96            if len(item) == 1:
97                peaks.append([float(item[0]),1.0])
98            elif len(item) > 1:
99                peaks.append([float(item[0]),float(item[0])])
100        S = File.readline()
101    File.close()
102    if Comments:
103       print 'Comments on file:'
104       for Comment in Comments: print Comment
105    Peaks = []
106    if peaks[0][0] > peaks[-1][0]:          # d-spacings - assume CuKa
107        for peak in peaks:
108            dsp = peak[0]
109            sth = Cuka/(2.0*dsp)
110            if sth < 1.0:
111                tth = 2.0*asind(sth)
112            else:
113                break
114            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
115    else:                                   #2-thetas - assume Cuka (for now)
116        for peak in peaks:
117            tth = peak[0]
118            dsp = Cuka/(2.0*sind(tth/2.0))
119            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
120    return Comments,Peaks
121
122def CheckImageFile(G2frame,imagefile):
123    '''Get an new image file name if the specified one does not
124    exist
125
126    :param wx.Frame G2frame: main GSAS-II Frame and data object
127
128    :param str imagefile: name of image file
129
130    :returns: imagefile, if it exists, or the name of a file
131      that does exist or False if the user presses Cancel
132
133    '''
134    if not ospath.exists(imagefile):
135        dlg = wx.FileDialog(G2frame, 'Bad image file name; choose name', '.', '',\
136        'Any image file (*.edf;*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img)\
137        |*.edf;*.tif;*.tiff;*.mar*;*.avg;*.sum;*.img|\
138        European detector file (*.edf)|*.edf|\
139        Any detector tif (*.tif;*.tiff)|*.tif;*.tiff|\
140        MAR file (*.mar*)|*.mar*|\
141        GE Image (*.avg;*.sum)|*.avg;*.sum|\
142        ADSC Image (*.img)|*.img|\
143        All files (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
144        try:
145            dlg.SetFilename(''+ospath.split(imagefile)[1])
146            if dlg.ShowModal() == wx.ID_OK:
147                imagefile = dlg.GetPath()
148            else:
149                imagefile = False
150        finally:
151            dlg.Destroy()
152    return imagefile
153       
154def GetImageData(G2frame,imagefile,imageOnly=False):
155    '''Read an image with the file reader keyed by the
156    file extension
157
158    :param wx.Frame G2frame: main GSAS-II Frame and data object. Note: not used!
159
160    :param str imagefile: name of image file
161
162    :param bool imageOnly: If True return only the image,
163      otherwise  (default) return more (see below)
164
165    :returns: an image as a numpy array or a list of four items:
166      Comments, Data, Npix and the Image, as selected by imageOnly
167
168    '''
169    ext = ospath.splitext(imagefile)[1]
170    Comments = []
171    if ext == '.tif' or ext == '.tiff':
172        Comments,Data,Npix,Image = GetTifData(imagefile)
173    elif ext == '.edf':
174        Comments,Data,Npix,Image = GetEdfData(imagefile)
175    elif ext == '.img':
176        Comments,Data,Npix,Image = GetImgData(imagefile)
177        Image[0][0] = 0
178    elif ext == '.mar3450' or ext == '.mar2300':
179        Comments,Data,Npix,Image = GetMAR345Data(imagefile)
180    elif ext in ['.sum','.avg','']:
181        Comments,Data,Npix,Image = GetGEsumData(imagefile)
182    elif ext == '.G2img':
183        Comments,Data,Npix,Image = GetG2Image(imagefile)
184    if imageOnly:
185        return Image
186    else:
187        return Comments,Data,Npix,Image
188       
189def PutG2Image(filename,Comments,Data,Npix,image):
190    'Write an image as a python pickle'
191    File = open(filename,'wb')
192    cPickle.dump([Comments,Data,Npix,image],File,1)
193    File.close()
194    return
195   
196def GetG2Image(filename):
197    'Read an image as a python pickle'
198    File = open(filename,'rb')
199    Comments,Data,Npix,image = cPickle.load(File)
200    File.close()
201    return Comments,Data,Npix,image
202   
203def GetEdfData(filename,imageOnly=False):   
204    'Read European detector data edf file'
205    import struct as st
206    import array as ar
207    if not imageOnly:
208        print 'Read European detector data edf file: ',filename
209    File = open(filename,'rb')
210    fileSize = os.stat(filename).st_size
211    head = File.read(3072)
212    lines = head.split('\n')
213    sizexy = [0,0]
214    pixSize = [0,0]
215    cent = [0,0]
216    head = ['European detector data',]
217    for line in lines:
218        fields = line.split()
219        if 'Dim_1' in line:
220            sizexy[0] = int(fields[2])
221        elif 'Dim_2' in line:
222            sizexy[1] = int(fields[2])
223        elif 'DataType' in line:
224            dType = fields[2]
225        elif 'refined_wavelength' in line:
226            wave = float(fields[2])
227        elif 'Size' in line:
228            imSize = int(fields[2])
229        elif 'DataType' in lines:
230            dType = fields[2]
231        elif 'pixel_size_x' in line:
232            pixSize[0] = float(fields[2])
233        elif 'pixel_size_y' in line:
234            pixSize[1] = float(fields[2])
235        elif 'beam_center_x' in line:
236            cent[0] = float(fields[2])
237        elif 'beam_center_y' in line:
238            cent[1] = float(fields[2])
239        elif 'refined_distance' in line:
240            dist = float(fields[2])
241        if line:
242            head.append(line)
243    File.seek(fileSize-imSize)
244    if dType == 'UnsignedShort':       
245        image = np.array(ar.array('H',File.read(imSize)),dtype=np.int32)
246    image = np.reshape(image,(sizexy[1],sizexy[0]))
247    data = {'pixelSize':pixSize,'wavelength':wave,'distance':dist,'center':cent,'size':sizexy}
248    Npix = sizexy[0]*sizexy[1]
249    File.close()   
250    if imageOnly:
251        return image
252    else:
253        return head,data,Npix,image
254       
255def GetGEsumData(filename,imageOnly=False):
256    'Read SUM file as produced at 1-ID from G.E. images'
257    import struct as st
258    import array as ar
259    if not imageOnly:
260        print 'Read GE sum file: ',filename   
261    File = open(filename,'rb')
262    if '.sum' in filename:
263        head = ['GE detector sum data from APS 1-ID',]
264        sizexy = [2048,2048]
265    elif '.avg' in filename:
266        head = ['GE detector avg data from APS 1-ID',]
267        sizexy = [2048,2048]
268    else:
269        head = ['GE detector raw data from APS 1-ID',]
270        File.seek(18)
271        size,nframes = st.unpack('<ih',File.read(6))
272        sizexy = [2048,2048]
273        pos = 8192
274        File.seek(pos)
275    Npix = sizexy[0]*sizexy[1]
276    if '.sum' in filename:
277        image = np.array(ar.array('f',File.read(4*Npix)),dtype=np.int32)
278    elif '.avg' in filename:
279        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
280    else:
281        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
282        while nframes > 1:
283            image += np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
284            nframes -= 1
285    image = np.reshape(image,(sizexy[1],sizexy[0]))
286    data = {'pixelSize':(200,200),'wavelength':0.15,'distance':250.0,'center':[204.8,204.8],'size':sizexy} 
287    File.close()   
288    if imageOnly:
289        return image
290    else:
291        return head,data,Npix,image
292       
293def GetImgData(filename,imageOnly=False):
294    'Read an ADSC image file'
295    import struct as st
296    import array as ar
297    if not imageOnly:
298        print 'Read ADSC img file: ',filename
299    File = open(filename,'rb')
300    head = File.read(511)
301    lines = head.split('\n')
302    head = []
303    center = [0,0]
304    for line in lines[1:-2]:
305        line = line.strip()[:-1]
306        if line:
307            if 'SIZE1' in line:
308                size = int(line.split('=')[1])
309                Npix = size*size
310            elif 'WAVELENGTH' in line:
311                wave = float(line.split('=')[1])
312            elif 'BIN' in line:
313                if line.split('=')[1] == '2x2':
314                    pixel=(102,102)
315                else:
316                    pixel = (51,51)
317            elif 'DISTANCE' in line:
318                distance = float(line.split('=')[1])
319            elif 'CENTER_X' in line:
320                center[0] = float(line.split('=')[1])
321            elif 'CENTER_Y' in line:
322                center[1] = float(line.split('=')[1])
323            head.append(line)
324    data = {'pixelSize':pixel,'wavelength':wave,'distance':distance,'center':center,'size':[size,size]}
325    image = []
326    row = 0
327    pos = 512
328    File.seek(pos)
329    image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
330    image = np.reshape(image,(sizexy[1],sizexy[0]))
331#    image = np.zeros(shape=(size,size),dtype=np.int32)   
332#    while row < size:
333#        File.seek(pos)
334#        line = ar.array('H',File.read(2*size))
335#        image[row] = np.asarray(line)
336#        row += 1
337#        pos += 2*size
338    File.close()
339    if imageOnly:
340        return image
341    else:
342        return lines[1:-2],data,Npix,image
343       
344def GetMAR345Data(filename,imageOnly=False):
345    'Read a MAR-345 image plate image'
346    import array as ar
347    import struct as st
348    try:
349        import pack_f as pf
350    except:
351        msg = wx.MessageDialog(None, message="Unable to load the GSAS MAR image decompression, pack_f",
352                               caption="Import Error",
353                               style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
354        msg.ShowModal()
355        return None,None,None,None
356
357    if not imageOnly:
358        print 'Read Mar345 file: ',filename
359    File = open(filename,'rb')
360    head = File.read(4095)
361    numbers = st.unpack('<iiiiiiiiii',head[:40])
362    lines = head[128:].split('\n')
363    head = []
364    for line in lines:
365        line = line.strip()
366        if 'PIXEL' in line:
367            values = line.split()
368            pixel = (int(values[2]),int(values[4]))     #in microns
369        elif 'WAVELENGTH' in line:
370            wave = float(line.split()[1])
371        elif 'DISTANCE' in line:
372            distance = float(line.split()[1])           #in mm
373        elif 'CENTER' in line:
374            values = line.split()
375            center = [float(values[2])/10.,float(values[4])/10.]    #make in mm from pixels
376        if line: 
377            head.append(line)
378    data = {'pixelSize':pixel,'wavelength':wave,'distance':distance,'center':center}
379    for line in head:
380        if 'FORMAT' in line[0:6]:
381            items = line.split()
382            size = int(items[1])
383            Npix = size*size
384    pos = 4096
385    data['size'] = [size,size]
386    File.seek(pos)
387    line = File.read(8)
388    while 'CCP4' not in line:       #get past overflow list for now
389        line = File.read(8)
390        pos += 8
391    pos += 37
392    File.seek(pos)
393    raw = File.read()
394    File.close()
395    image = np.zeros(shape=(size,size),dtype=np.int32)
396    image = np.flipud(pf.pack_f(len(raw),raw,size,image).T)  #transpose to get it right way around & flip
397    if imageOnly:
398        return image
399    else:
400        return head,data,Npix,image
401
402def GetTifData(filename,imageOnly=False):
403    '''Read an image in a pseudo-tif format,
404    as produced by a wide variety of software, almost always
405    incorrectly in some way.
406    '''
407    import struct as st
408    import array as ar
409    import ReadMarCCDFrame as rmf
410    File = open(filename,'rb')
411    dataType = 5
412    try:
413        Meta = open(filename+'.metadata','Ur')
414        head = Meta.readlines()
415        for line in head:
416            line = line.strip()
417            if 'dataType=' in line:
418                dataType = int(line.split('=')[1])
419        Meta.close()
420    except IOError:
421        print 'no metadata file found - will try to read file anyway'
422        head = ['no metadata file found',]
423       
424    tag = File.read(2)
425    byteOrd = '<'
426    if tag == 'II' and int(st.unpack('<h',File.read(2))[0]) == 42:     #little endian
427        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])
428    elif tag == 'MM' and int(st.unpack('>h',File.read(2))[0]) == 42:   #big endian
429        byteOrd = '>'
430        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])       
431    else:
432        lines = ['not a detector tiff file',]
433        return lines,0,0,0
434    File.seek(IFD)                                                  #get number of directory entries
435    NED = int(st.unpack(byteOrd+'h',File.read(2))[0])
436    IFD = {}
437    for ied in range(NED):
438        Tag,Type = st.unpack(byteOrd+'Hh',File.read(4))
439        nVal = st.unpack(byteOrd+'i',File.read(4))[0]
440        if Type == 1:
441            Value = st.unpack(byteOrd+nVal*'b',File.read(nVal))
442        elif Type == 2:
443            Value = st.unpack(byteOrd+'i',File.read(4))
444        elif Type == 3:
445            Value = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
446            x = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
447        elif Type == 4:
448            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
449        elif Type == 5:
450            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
451        elif Type == 11:
452            Value = st.unpack(byteOrd+nVal*'f',File.read(nVal*4))
453        IFD[Tag] = [Type,nVal,Value]
454        #print Tag,IFD[Tag]
455    sizexy = [IFD[256][2][0],IFD[257][2][0]]
456    [nx,ny] = sizexy
457    Npix = nx*ny
458    if 34710 in IFD:
459        if not imageOnly:
460            print 'Read MAR CCD tiff file: ',filename
461        marFrame = rmf.marFrame(File,byteOrd,IFD)
462        image = np.flipud(np.array(np.asarray(marFrame.image),dtype=np.int32))
463        tifType = marFrame.filetitle
464        pixy = (marFrame.pixelsizeX/1000.0,marFrame.pixelsizeY/1000.0)
465        head = marFrame.outputHead()
466    elif 272 in IFD:
467        ifd = IFD[272]
468        File.seek(ifd[2][0])
469        S = File.read(ifd[1])
470        if 'PILATUS' in S:
471            tifType = 'Pilatus'
472            dataType = 0
473            pixy = (172,172)
474            File.seek(4096)
475            if not imageOnly:
476                print 'Read Pilatus tiff file: ',filename
477            image = ar.array('L',File.read(4*Npix))
478            image = np.array(np.asarray(image),dtype=np.int32)
479    elif 262 in IFD and IFD[262][2][0] > 4:
480        tifType = 'DND'
481        pixy = (158,158)
482        File.seek(512)
483        if not imageOnly:
484            print 'Read DND SAX/WAX-detector tiff file: ',filename
485        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
486    elif sizexy == [1536,1536]:
487        tifType = 'APS Gold'
488        pixy = (150,150)
489        File.seek(64)
490        if not imageOnly:
491            print 'Read Gold tiff file:',filename
492        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
493    elif sizexy == [2048,2048] or sizexy == [1024,1024] or sizexy == [3072,3072]:
494        if IFD[273][2][0] == 8:
495            if IFD[258][2][0] == 32:
496                tifType = 'PE'
497                pixy = (200,200)
498                File.seek(8)
499                if not imageOnly:
500                    print 'Read APS PE-detector tiff file: ',filename
501                if dataType == 5:
502                    image = np.array(ar.array('f',File.read(4*Npix)),dtype=np.float32)
503                else:
504                    image = np.array(ar.array('I',File.read(4*Npix)),dtype=np.int32)
505        elif IFD[273][2][0] == 4096:
506            if sizexy[0] == 3072:
507                pixy =  (73,73)
508                tifType = 'MAR225'           
509            else:
510                pixy = (158,158)
511                tifType = 'MAR325'           
512            File.seek(4096)
513            if not imageOnly:
514                print 'Read MAR CCD tiff file: ',filename
515            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
516        elif IFD[273][2][0] == 512:
517            tiftype = '11-ID-C'
518            pixy = [200,200]
519            File.seek(512)
520            if not imageOnly:
521                print 'Read 11-ID-C tiff file: ',filename
522            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)           
523    elif sizexy == [4096,4096]:
524        if IFD[273][2][0] == 8:
525            if IFD[258][2][0] == 16:
526                tifType = 'scanCCD'
527                pixy = (9,9)
528                File.seek(8)
529                if not imageOnly:
530                    print 'Read APS scanCCD tiff file: ',filename
531                image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
532        elif IFD[273][2][0] == 4096:
533            tifType = 'Rayonix'
534            pixy = (73.242,73.242)
535            File.seek(4096)
536            if not imageOnly:
537                print 'Read Rayonix MX300HE tiff file: ',filename
538            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
539#    elif sizexy == [960,960]:
540#        tiftype = 'PE-BE'
541#        pixy = (200,200)
542#        File.seek(8)
543#        if not imageOnly:
544#            print 'Read Gold tiff file:',filename
545#        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
546           
547    else:
548        lines = ['not a known detector tiff file',]
549        return lines,0,0,0
550       
551    image = np.reshape(image,(sizexy[1],sizexy[0]))
552    center = [pixy[0]*sizexy[0]/2000,pixy[1]*sizexy[1]/2000]
553    data = {'pixelSize':pixy,'wavelength':0.10,'distance':100.0,'center':center,'size':sizexy}
554    File.close()   
555    if imageOnly:
556        return image
557    else:
558        return head,data,Npix,image
559   
560#def GetTifData(filename,imageOnly=False):
561#    import struct as st
562#    import array as ar
563#    File = open(filename,'rb')
564#    dataType = 5
565#    try:
566#        Meta = open(filename+'.metadata','Ur')
567#        head = Meta.readlines()
568#        for line in head:
569#            line = line.strip()
570#            if 'dataType=' in line:
571#                dataType = int(line.split('=')[1])
572#        Meta.close()
573#    except IOError:
574#        print 'no metadata file found - will try to read file anyway'
575#        head = ['no metadata file found',]
576#       
577#    tag = File.read(2)
578#    byteOrd = '<'
579#    if tag == 'II' and int(st.unpack('<h',File.read(2))[0]) == 42:     #little endian
580#        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])
581#    elif tag == 'MM' and int(st.unpack('>h',File.read(2))[0]) == 42:   #big endian
582#        byteOrd = '>'
583#        IFD = int(st.unpack(byteOrd+'i',File.read(4))[0])       
584#    else:
585#        lines = ['not a detector tiff file',]
586#        return lines,0,0,0
587#    File.seek(IFD)                                                  #get number of directory entries
588#    NED = int(st.unpack(byteOrd+'h',File.read(2))[0])
589#    IFD = {}
590#    for ied in range(NED):
591#        Tag,Type = st.unpack(byteOrd+'Hh',File.read(4))
592#        nVal = st.unpack(byteOrd+'i',File.read(4))[0]
593#        if Type == 1:
594#            Value = st.unpack(byteOrd+nVal*'b',File.read(nVal))
595#        elif Type == 2:
596#            Value = st.unpack(byteOrd+'i',File.read(4))
597#        elif Type == 3:
598#            Value = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
599#            x = st.unpack(byteOrd+nVal*'h',File.read(nVal*2))
600#        elif Type == 4:
601#            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
602#        elif Type == 5:
603#            Value = st.unpack(byteOrd+nVal*'i',File.read(nVal*4))
604#        elif Type == 11:
605#            Value = st.unpack(byteOrd+nVal*'f',File.read(nVal*4))
606#        IFD[Tag] = [Type,nVal,Value]
607##        print Tag,IFD[Tag]
608#    sizexy = [IFD[256][2][0],IFD[257][2][0]]
609#    [nx,ny] = sizexy
610#    Npix = nx*ny
611#    if 272 in IFD:
612#        ifd = IFD[272]
613#        File.seek(ifd[2][0])
614#        S = File.read(ifd[1])
615#        if 'PILATUS' in S:
616#            tifType = 'Pilatus'
617#            dataType = 0
618#            pixy = (172,172)
619#            File.seek(4096)
620#            if not imageOnly:
621#                print 'Read Pilatus tiff file: ',filename
622#            image = ar.array('L',File.read(4*Npix))
623#            image = np.array(np.asarray(image),dtype=np.int32)
624#    elif 262 in IFD and IFD[262][2][0] > 4:
625#        tifType = 'DND'
626#        pixy = (158,158)
627#        File.seek(512)
628#        if not imageOnly:
629#            print 'Read DND SAX/WAX-detector tiff file: ',filename
630#        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
631#    elif sizexy == [1536,1536]:
632#        tifType = 'APS Gold'
633#        pixy = (150,150)
634#        File.seek(64)
635#        if not imageOnly:
636#            print 'Read Gold tiff file:',filename
637#        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
638#    elif sizexy == [2048,2048] or sizexy == [1024,1024] or sizexy == [3072,3072]:
639#        if IFD[273][2][0] == 8:
640#            if IFD[258][2][0] == 32:
641#                tifType = 'PE'
642#                pixy = (200,200)
643#                File.seek(8)
644#                if not imageOnly:
645#                    print 'Read APS PE-detector tiff file: ',filename
646#                if dataType == 5:
647#                    image = np.array(ar.array('f',File.read(4*Npix)),dtype=np.float32)
648#                else:
649#                    image = np.array(ar.array('I',File.read(4*Npix)),dtype=np.int32)
650#        elif IFD[273][2][0] == 4096:
651#            if sizexy[0] == 3072:
652#                pixy =  (73,73)
653#                tifType = 'MAR225'           
654#            else:
655#                pixy = (158,158)
656#                tifType = 'MAR325'           
657#            File.seek(4096)
658#            if not imageOnly:
659#                print 'Read MAR CCD tiff file: ',filename
660#            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
661#        elif IFD[273][2][0] == 512:
662#            tiftype = '11-ID-C'
663#            pixy = [200,200]
664#            File.seek(512)
665#            if not imageOnly:
666#                print 'Read 11-ID-C tiff file: ',filename
667#            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)           
668#    elif sizexy == [4096,4096]:
669#        if IFD[273][2][0] == 8:
670#            if IFD[258][2][0] == 16:
671#                tifType = 'scanCCD'
672#                pixy = (9,9)
673#                File.seek(8)
674#                if not imageOnly:
675#                    print 'Read APS scanCCD tiff file: ',filename
676#                image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
677#        elif IFD[273][2][0] == 4096:
678#            tifType = 'Rayonix'
679#            pixy = (73.242,73.242)
680#            File.seek(4096)
681#            if not imageOnly:
682#                print 'Read Rayonix MX300HE tiff file: ',filename
683#            image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
684##    elif sizexy == [960,960]:
685##        tiftype = 'PE-BE'
686##        pixy = (200,200)
687##        File.seek(8)
688##        if not imageOnly:
689##            print 'Read Gold tiff file:',filename
690##        image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
691#           
692#    else:
693#        lines = ['not a known detector tiff file',]
694#        return lines,0,0,0
695#       
696#    image = np.reshape(image,(sizexy[1],sizexy[0]))
697#    center = [pixy[0]*sizexy[0]/2000,pixy[1]*sizexy[1]/2000]
698#    data = {'pixelSize':pixy,'wavelength':0.10,'distance':100.0,'center':center,'size':sizexy}
699#    File.close()   
700#    if imageOnly:
701#        return image
702#    else:
703#        return head,data,Npix,image
704#   
705def ProjFileOpen(G2frame):
706    'Read a GSAS-II project file'
707    file = open(G2frame.GSASprojectfile,'rb')
708    print 'load from file: ',G2frame.GSASprojectfile
709    G2frame.SetTitle("GSAS-II data tree: "+
710                     os.path.split(G2frame.GSASprojectfile)[1])
711    wx.BeginBusyCursor()
712    try:
713        while True:
714            try:
715                data = cPickle.load(file)
716            except EOFError:
717                break
718            datum = data[0]
719           
720            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=datum[0])
721            if 'PWDR' in datum[0]:               
722                G2frame.PatternTree.SetItemPyData(Id,datum[1][:3])     #temp. trim off junk
723            else:
724                G2frame.PatternTree.SetItemPyData(Id,datum[1])
725            for datus in data[1:]:
726                sub = G2frame.PatternTree.AppendItem(Id,datus[0])
727#patch
728                if datus[0] == 'Instrument Parameters' and len(datus[1]) == 1:
729                    if 'PWDR' in datum[0]:
730                        datus[1] = [dict(zip(datus[1][3],zip(datus[1][0],datus[1][1],datus[1][2]))),{}]
731                    else:
732                        datus[1] = [dict(zip(datus[1][2],zip(datus[1][0],datus[1][1]))),{}]
733                    for item in datus[1][0]:               #zip makes tuples - now make lists!
734                        datus[1][0][item] = list(datus[1][0][item])
735#end patch
736                G2frame.PatternTree.SetItemPyData(sub,datus[1])
737            if 'IMG' in datum[0]:                   #retrieve image default flag & data if set
738                Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Image Controls'))
739                if Data['setDefault']:
740                    G2frame.imageDefault = Data               
741        file.close()
742        print 'project load successful'
743        G2frame.NewPlot = True
744    except:
745        msg = wx.MessageDialog(G2frame,message="Error reading file "+
746            str(G2frame.GSASprojectfile)+". This is not a GSAS-II .gpx file",
747            caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
748        msg.ShowModal()
749    finally:
750        wx.EndBusyCursor()
751   
752def ProjFileSave(G2frame):
753    'Save a GSAS-II project file'
754    if not G2frame.PatternTree.IsEmpty():
755        file = open(G2frame.GSASprojectfile,'wb')
756        print 'save to file: ',G2frame.GSASprojectfile
757        wx.BeginBusyCursor()
758        try:
759            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
760            while item:
761                data = []
762                name = G2frame.PatternTree.GetItemText(item)
763                data.append([name,G2frame.PatternTree.GetItemPyData(item)])
764                item2, cookie2 = G2frame.PatternTree.GetFirstChild(item)
765                while item2:
766                    name = G2frame.PatternTree.GetItemText(item2)
767                    data.append([name,G2frame.PatternTree.GetItemPyData(item2)])
768                    item2, cookie2 = G2frame.PatternTree.GetNextChild(item, cookie2)                           
769                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                           
770                cPickle.dump(data,file,1)
771            file.close()
772        finally:
773            wx.EndBusyCursor()
774        print 'project save successful'
775
776def SaveIntegration(G2frame,PickId,data):
777    'Save image integration results as powder pattern(s)'
778    azms = G2frame.Integrate[1]
779    X = G2frame.Integrate[2][:-1]
780    Xminmax = [X[0],X[-1]]
781    N = len(X)
782    Id = G2frame.PatternTree.GetItemParent(PickId)
783    name = G2frame.PatternTree.GetItemText(Id)
784    name = name.replace('IMG ','PWDR ')
785    Comments = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Comments'))
786    names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
787    codes = [0 for i in range(12)]
788    LRazm = data['LRazimuth']
789    Azms = []
790    if data['fullIntegrate'] and data['outAzimuths'] == 1:
791        Azms = [45.0,]                              #a poor man's average?
792    else:
793        for i,azm in enumerate(azms[:-1]):
794            Azms.append((azms[i+1]+azm)/2.)
795    for i,azm in enumerate(azms[:-1]):
796        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
797        Id = 0
798        while item:
799            Name = G2frame.PatternTree.GetItemText(item)
800            if name == Name:
801                Id = item
802            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
803        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!
804        Y = G2frame.Integrate[0][i]
805        W = 1./Y                    #probably not true
806        Sample = G2pdG.SetDefaultSample()
807        Sample['Gonio. radius'] = data['distance']
808        Sample['Omega'] = data['GonioAngles'][0]
809        Sample['Chi'] = data['GonioAngles'][1]
810        Sample['Phi'] = data['GonioAngles'][2]
811        if Id:
812            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Comments'),Comments)                   
813            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Limits'),[tuple(Xminmax),Xminmax])
814            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Background'),[['chebyschev',1,3,1.0,0.0,0.0],
815                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
816            inst = [dict(zip(names,zip(parms,parms,codes))),{}]
817            for item in inst[0]:
818                inst[0][item] = list(inst[0][item])
819            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'),inst)
820            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Peak List'),[])
821            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Index Peak List'),[])
822            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Unit Cells List'),[])             
823            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Reflection Lists'),{})             
824        else:
825            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=name+" Azm= %.2f"%(Azms[i]))
826            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
827            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
828            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0],
829                            {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
830            inst = [dict(zip(names,zip(parms,parms,codes))),{}]
831            for item in inst[0]:
832                inst[0][item] = list(inst[0][item])
833            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
834            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
835            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Peak List'),[])
836            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Index Peak List'),[])
837            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Unit Cells List'),[])
838            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Reflection Lists'),{})             
839        G2frame.PatternTree.SetItemPyData(Id,[[''],[np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
840    G2frame.PatternTree.SelectItem(Id)
841    G2frame.PatternTree.Expand(Id)
842    G2frame.PatternId = Id
843           
844def powderFxyeSave(G2frame,exports,powderfile):
845    'Save a powder histogram as a GSAS FXYE file'
846    head,tail = ospath.split(powderfile)
847    name,ext = tail.split('.')
848    for i,export in enumerate(exports):
849        filename = ospath.join(head,name+'-%03d.'%(i)+ext)
850        prmname = filename.strip(ext)+'prm'
851        prm = open(prmname,'w')      #old style GSAS parm file
852        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
853        Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, \
854            PickId, 'Instrument Parameters'))[0]
855        prm.write( '            123456789012345678901234567890123456789012345678901234567890        '+'\n')
856        prm.write( 'INS   BANK      1                                                               '+'\n')
857        prm.write(('INS   HTYPE   %sR                                                              '+'\n')%(Inst['Type'][0]))
858        if 'Lam1' in Inst:              #Ka1 & Ka2
859            prm.write(('INS  1 ICONS%10.7f%10.7f    0.0000               0.990    0     0.500   '+'\n')%(Inst['Lam1'][0],Inst['Lam2'][0]))
860        elif 'Lam' in Inst:             #single wavelength
861            prm.write(('INS  1 ICONS%10.7f%10.7f    0.0000               0.990    0     0.500   '+'\n')%(Inst['Lam'][1],0.0))
862        prm.write( 'INS  1 IRAD     0                                                               '+'\n')
863        prm.write( 'INS  1I HEAD                                                                    '+'\n')
864        prm.write( 'INS  1I ITYP    0    0.0000  180.0000         1                                 '+'\n')
865        prm.write(('INS  1DETAZM%10.3f                                                          '+'\n')%(Inst['Azimuth'][0]))
866        prm.write( 'INS  1PRCF1     3    8   0.00100                                                '+'\n')
867        prm.write(('INS  1PRCF11     %15.6g%15.6g%15.6g%15.6g   '+'\n')%(Inst['U'][1],Inst['V'][1],Inst['W'][1],0.0))
868        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.))
869        prm.close()
870        file = open(filename,'w')
871        print 'save powder pattern to file: ',filename
872        x,y,w,yc,yb,yd = G2frame.PatternTree.GetItemPyData(PickId)[1]
873        file.write(powderfile+'\n')
874        file.write('Instrument parameter file:'+ospath.split(prmname)[1]+'\n')
875        file.write('BANK 1 %d %d CONS %.2f %.2f 0 0 FXYE\n'%(len(x),len(x),\
876            100.*x[0],100.*(x[1]-x[0])))
877        s = list(np.sqrt(1./np.array(w)))       
878        XYW = zip(x,y,s)
879        for X,Y,S in XYW:
880            file.write("%15.6g %15.6g %15.6g\n" % (100.*X,Y,max(S,1.0)))
881        file.close()
882        print 'powder pattern file '+filename+' written'
883       
884def powderXyeSave(G2frame,exports,powderfile):
885    'Save a powder histogram as a Topas XYE file'
886    head,tail = ospath.split(powderfile)
887    name,ext = tail.split('.')
888    for i,export in enumerate(exports):
889        filename = ospath.join(head,name+'-%03d.'%(i)+ext)
890        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
891        file = open(filename,'w')
892        file.write('#%s\n'%(export))
893        print 'save powder pattern to file: ',filename
894        x,y,w,yc,yb,yd = G2frame.PatternTree.GetItemPyData(PickId)[1]
895        s = list(np.sqrt(1./np.array(w)))       
896        XYW = zip(x,y,s)
897        for X,Y,W in XYW:
898            file.write("%15.6g %15.6g %15.6g\n" % (X,Y,W))
899        file.close()
900        print 'powder pattern file '+filename+' written'
901       
902def PDFSave(G2frame,exports):
903    'Save a PDF G(r) and S(Q) in column formats'
904    for export in exports:
905        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
906        SQname = 'S(Q)'+export[4:]
907        GRname = 'G(R)'+export[4:]
908        sqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.sq')
909        grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
910        sqId = G2gd.GetPatternTreeItemId(G2frame, PickId, SQname)
911        grId = G2gd.GetPatternTreeItemId(G2frame, PickId, GRname)
912        sqdata = np.array(G2frame.PatternTree.GetItemPyData(sqId)[1][:2]).T
913        grdata = np.array(G2frame.PatternTree.GetItemPyData(grId)[1][:2]).T
914        sqfile = open(sqfilename,'w')
915        grfile = open(grfilename,'w')
916        sqfile.write('#T S(Q) %s\n'%(export))
917        grfile.write('#T G(R) %s\n'%(export))
918        sqfile.write('#L Q     S(Q)\n')
919        grfile.write('#L R     G(R)\n')
920        for q,sq in sqdata:
921            sqfile.write("%15.6g %15.6g\n" % (q,sq))
922        sqfile.close()
923        for r,gr in grdata:
924            grfile.write("%15.6g %15.6g\n" % (r,gr))
925        grfile.close()
926   
927def PeakListSave(G2frame,file,peaks):
928    'Save powder peaks to a data file'
929    print 'save peak list to file: ',G2frame.peaklistfile
930    if not peaks:
931        dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
932        try:
933            result = dlg.ShowModal()
934        finally:
935            dlg.Destroy()
936        return
937    for peak in peaks:
938        file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
939            (peak[0],peak[2],peak[4],peak[6]))
940    print 'peak list saved'
941             
942def IndexPeakListSave(G2frame,peaks):
943    'Save powder peaks from the indexing list'
944    file = open(G2frame.peaklistfile,'wa')
945    print 'save index peak list to file: ',G2frame.peaklistfile
946    wx.BeginBusyCursor()
947    try:
948        if not peaks:
949            dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
950            try:
951                result = dlg.ShowModal()
952            finally:
953                dlg.Destroy()
954            return
955        for peak in peaks:
956            file.write("%12.6f\n" % (peak[7]))
957        file.close()
958    finally:
959        wx.EndBusyCursor()
960    print 'index peak list saved'
961   
962def SetNewPhase(Name='New Phase',SGData=None,cell=None):
963    '''Create a new phase with default values for various parameters
964
965    :param str Name: Name for new Phase
966
967    :param dict SGData: space group data from :func:`GSASIIspc:SpcGroup`;
968      defaults to data for P 1
969
970    :param list cell: unit cell parameter list; defaults to
971      [1.0,1.0,1.0,90.,90,90.,1.]
972
973    '''
974    if SGData is None: SGData = G2spc.SpcGroup('P 1')[1]
975    if cell is None: cell=[1.0,1.0,1.0,90.,90,90.,1.]
976    phaseData = {
977        'ranId':ran.randint(0,sys.maxint),
978        'General':{
979            'Name':Name,
980            'Type':'nuclear',
981            'SGData':SGData,
982            'Cell':[False,]+cell,
983            'Pawley dmin':1.0,
984            'Data plot type':'None',
985            'SH Texture':{
986                'Order':0,
987                'Model':'cylindrical',
988                'Sample omega':[False,0.0],
989                'Sample chi':[False,0.0],
990                'Sample phi':[False,0.0],
991                'SH Coeff':[False,{}],
992                'SHShow':False,
993                'PFhkl':[0,0,1],
994                'PFxyz':[0,0,1],
995                'PlotType':'Pole figure'}},
996        'Atoms':[],
997        'Drawing':{},
998        'Histograms':{},
999        'Pawley ref':[],
1000        'RBModels':{},
1001        }
1002    return phaseData
1003   
1004def ReadEXPPhase(G2frame,filename):
1005    '''Read a phase from a GSAS .EXP file.
1006    Called in the GSAS phase import routine (see imports/G2phase.py)
1007    '''
1008    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
1009    textureData = {'Order':0,'Model':'cylindrical','Sample omega':[False,0.0],
1010        'Sample chi':[False,0.0],'Sample phi':[False,0.0],'SH Coeff':[False,{}],
1011        'SHShow':False,'PFhkl':[0,0,1],'PFxyz':[0,0,1],'PlotType':'Pole figure'}
1012    shNcof = 0
1013    file = open(filename, 'Ur')
1014    S = 1
1015    Expr = [{},{},{},{},{},{},{},{},{}]
1016    while S:
1017        S = file.readline()
1018        if 'EXPR NPHAS' in S[:12]:
1019            Num = S[12:-1].count('0')
1020            NPhas = S[12:-1].split()
1021        if 'CRS' in S[:3]:
1022            N = int(S[3:4])-1
1023            Expr[N][S[:12]] = S[12:-1]
1024    file.close()
1025    PNames = []
1026    for n,N in enumerate(NPhas):
1027        if N != '0':
1028            result = n
1029            key = 'CRS'+str(n+1)+'    PNAM'
1030            PNames.append(Expr[n][key])
1031    if Num < 8:
1032        dlg = wx.SingleChoiceDialog(G2frame, 'Which phase to read?', 'Read phase data', PNames, wx.CHOICEDLG_STYLE)
1033        try:
1034            if dlg.ShowModal() == wx.ID_OK:
1035                result = dlg.GetSelection()
1036        finally:
1037            dlg.Destroy()       
1038    EXPphase = Expr[result]
1039    keyList = EXPphase.keys()
1040    keyList.sort()
1041    SGData = {}
1042    if NPhas[result] == '1':
1043        Ptype = 'nuclear'
1044    elif NPhas[result] in ['2','3']:
1045        Ptype = 'magnetic'
1046    elif NPhas[result] == '4':
1047        Ptype = 'macromolecular'
1048    elif NPhas[result] == '10':
1049        Ptype = 'Pawley'
1050    for key in keyList:
1051        if 'PNAM' in key:
1052           PhaseName = EXPphase[key].strip()
1053        elif 'ABC   ' in key:
1054            abc = [float(EXPphase[key][:10]),float(EXPphase[key][10:20]),float(EXPphase[key][20:30])]                       
1055        elif 'ANGLES' in key:
1056            angles = [float(EXPphase[key][:10]),float(EXPphase[key][10:20]),float(EXPphase[key][20:30])]                                               
1057        elif 'SG SYM' in key:
1058            SpGrp = EXPphase[key][:15].strip()
1059            E,SGData = G2spc.SpcGroup(SpGrp)
1060            if E:
1061                E,SGData = G2spc.SpcGroup('P 1') # unlikely to need this
1062        elif 'OD    ' in key:
1063            SHdata = EXPphase[key].split() # may not have all 9 values
1064            SHvals = 9*[0]
1065            for i in range(9):
1066                try:
1067                    float(SHdata[i])
1068                    SHvals[i] = SHdata[i]
1069                except:
1070                    pass
1071            textureData['Order'] = int(SHvals[0])
1072            textureData['Model'] = shModels[int(SHvals[2])]
1073            textureData['Sample omega'] = [False,float(SHvals[6])]
1074            textureData['Sample chi'] = [False,float(SHvals[7])]
1075            textureData['Sample phi'] = [False,float(SHvals[8])]
1076            shNcof = int(SHvals[1])
1077    Atoms = []
1078    if Ptype == 'nuclear':
1079        for key in keyList:
1080            if 'AT' in key:
1081                if key[11:] == 'A':
1082                    S = EXPphase[key]
1083                elif key[11:] == 'B':
1084                    S += EXPphase[key]
1085                    Atom = [S[50:58].strip(),S[:10].strip().capitalize(),'',
1086                        float(S[10:20]),float(S[20:30]),float(S[30:40]),
1087                        float(S[40:50]),'',int(S[60:62]),S[130:131]]
1088                    if Atom[9] == 'I':
1089                        Atom += [float(S[68:78]),0.,0.,0.,0.,0.,0.]
1090                    elif Atom[9] == 'A':
1091                        Atom += [0.0,float(S[68:78]),float(S[78:88]),
1092                            float(S[88:98]),float(S[98:108]),
1093                            float(S[108:118]),float(S[118:128])]
1094                    XYZ = Atom[3:6]
1095                    Atom[7],Atom[8] = G2spc.SytSym(XYZ,SGData)
1096                    Atom.append(ran.randint(0,sys.maxint))
1097                    Atoms.append(Atom)
1098    elif Ptype == 'macromolecular':
1099        for key in keyList:
1100            if 'AT' in key[6:8]:
1101                S = EXPphase[key]
1102                Atom = [S[56:60],S[50:54].strip().upper(),S[54:56],
1103                    S[46:51].strip(),S[:8].strip().capitalize(),'',
1104                    float(S[16:24]),float(S[24:32]),float(S[32:40]),
1105                    float(S[8:16]),'1',1,'I',float(S[40:46]),0,0,0,0,0,0]
1106                XYZ = Atom[6:9]
1107                Atom[10],Atom[11] = G2spc.SytSym(XYZ,SGData)
1108                Atom.append(ran.randint(0,sys.maxint))
1109                Atoms.append(Atom)
1110    Volume = G2lat.calc_V(G2lat.cell2A(abc+angles))
1111    if shNcof:
1112        shCoef = {}
1113        nRec = [i+1 for i in range((shNcof-1)/6+1)]
1114        for irec in nRec:
1115            ODkey = keyList[0][:6]+'OD'+'%3dA'%(irec)
1116            indx = EXPphase[ODkey].split()
1117            ODkey = ODkey[:-1]+'B'
1118            vals = EXPphase[ODkey].split()
1119            for i,val in enumerate(vals):
1120                key = 'C(%s,%s,%s)'%(indx[3*i],indx[3*i+1],indx[3*i+2])
1121                shCoef[key] = float(val)
1122        textureData['SH Coeff'] = [False,shCoef]
1123       
1124    Phase = SetNewPhase(Name=PhaseName,SGData=SGData,cell=abc+angles+[Volume,])
1125    general = Phase['General']
1126    general['Type'] = Ptype
1127    general['SH Texture'] = textureData
1128    Phase['Atoms'] = Atoms
1129    return Phase
1130       
1131def ReadPDBPhase(filename):
1132    '''Read a phase from a PDB file.
1133    Called in the PDB phase import routine (see imports/G2phase.py)
1134    '''
1135    EightPiSq = 8.*math.pi**2
1136    file = open(filename, 'Ur')
1137    Phase = {}
1138    Title = ''
1139    Compnd = ''
1140    Atoms = []
1141    A = np.zeros(shape=(3,3))
1142    S = file.readline()
1143    while S:
1144        Atom = []
1145        if 'TITLE' in S[:5]:
1146            Title = S[10:72].strip()
1147            S = file.readline()
1148        elif 'COMPND    ' in S[:10]:
1149            Compnd = S[10:72].strip()
1150            S = file.readline()
1151        elif 'CRYST' in S[:5]:
1152            abc = S[7:34].split()
1153            angles = S[34:55].split()
1154            cell=[float(abc[0]),float(abc[1]),float(abc[2]),
1155                float(angles[0]),float(angles[1]),float(angles[2])]
1156            Volume = G2lat.calc_V(G2lat.cell2A(cell))
1157            AA,AB = G2lat.cell2AB(cell)
1158            SpGrp = S[55:65]
1159            E,SGData = G2spc.SpcGroup(SpGrp)
1160            # space group processing failed, try to look up name in table
1161            if E:
1162                SpGrpNorm = G2spc.StandardizeSpcName(SpGrp)
1163                if SpGrpNorm:
1164                    E,SGData = G2spc.SpcGroup(SpGrpNorm)
1165            while E:
1166                print G2spc.SGErrors(E)
1167                dlg = wx.TextEntryDialog(None,
1168                    SpGrp[:-1]+' is invalid \nN.B.: make sure spaces separate axial fields in symbol',
1169                    'ERROR in space group symbol','',style=wx.OK)
1170                if dlg.ShowModal() == wx.ID_OK:
1171                    SpGrp = dlg.GetValue()
1172                    E,SGData = G2spc.SpcGroup(SpGrp)
1173                else:
1174                    return None
1175                dlg.Destroy()               
1176            SGlines = G2spc.SGPrint(SGData)
1177            for line in SGlines: print line
1178            S = file.readline()
1179        elif 'SCALE' in S[:5]:
1180            V = (S[10:41].split())
1181            A[int(S[5])-1] = [float(V[0]),float(V[1]),float(V[2])]
1182            S = file.readline()
1183        elif 'ATOM' in S[:4] or 'HETATM' in S[:6]:
1184            XYZ = [float(S[31:39]),float(S[39:47]),float(S[47:55])]
1185            XYZ = np.inner(AB,XYZ)
1186            XYZ = np.where(abs(XYZ)<0.00001,0,XYZ)
1187            SytSym,Mult = G2spc.SytSym(XYZ,SGData)
1188            Uiso = float(S[61:67])/EightPiSq
1189            Type = S[12:14].lower()
1190            if Type[0] in '123456789':
1191                Type = Type[1:]
1192            Atom = [S[22:27].strip(),S[17:20].upper(),S[20:22],
1193                S[12:17].strip(),Type.strip().capitalize(),'',XYZ[0],XYZ[1],XYZ[2],
1194                float(S[55:61]),SytSym,Mult,'I',Uiso,0,0,0,0,0,0]
1195            S = file.readline()
1196            if 'ANISOU' in S[:6]:
1197                Uij = S[30:72].split()
1198                Uij = [float(Uij[0])/10000.,float(Uij[1])/10000.,float(Uij[2])/10000.,
1199                    float(Uij[3])/10000.,float(Uij[4])/10000.,float(Uij[5])/10000.]
1200                Atom = Atom[:14]+Uij
1201                Atom[12] = 'A'
1202                S = file.readline()
1203            Atom.append(ran.randint(0,sys.maxint))
1204            Atoms.append(Atom)
1205        else:           
1206            S = file.readline()
1207    file.close()
1208    if Title:
1209        PhaseName = Title
1210    elif Compnd:
1211        PhaseName = Compnd
1212    else:
1213        PhaseName = 'None'
1214    Phase = SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell+[Volume,])
1215    Phase['General']['Type'] = 'macromolecular'
1216    Phase['Atoms'] = Atoms
1217   
1218    return Phase
1219
1220class MultipleChoicesDialog(wx.Dialog):
1221    '''A dialog that offers a series of choices, each with a
1222    title and a wx.Choice widget. Intended to be used Modally.
1223    typical input:
1224
1225        *  choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1226        *  headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1227       
1228    selections are placed in self.chosen when OK is pressed
1229    '''
1230    def __init__(self,choicelist,headinglist,
1231                 head='Select options',
1232                 title='Please select from options below',
1233                 parent=None):
1234        self.chosen = []
1235        wx.Dialog.__init__(
1236            self,parent,wx.ID_ANY,head, 
1237            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1238        panel = wx.Panel(self)
1239        mainSizer = wx.BoxSizer(wx.VERTICAL)
1240        mainSizer.Add((10,10),1)
1241        topLabl = wx.StaticText(panel,wx.ID_ANY,title)
1242        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.CENTER,10)
1243        self.ChItems = []
1244        for choice,lbl in zip(choicelist,headinglist):
1245            mainSizer.Add((10,10),1)
1246            self.chosen.append(0)
1247            topLabl = wx.StaticText(panel,wx.ID_ANY,' '+lbl)
1248            mainSizer.Add(topLabl,0,wx.ALIGN_LEFT,10)
1249            self.ChItems.append(wx.Choice(self, wx.ID_ANY, (100, 50), choices = choice))
1250            mainSizer.Add(self.ChItems[-1],0,wx.ALIGN_CENTER,10)
1251
1252        OkBtn = wx.Button(panel,-1,"Ok")
1253        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1254        cancelBtn = wx.Button(panel,-1,"Cancel")
1255        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1256        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1257        btnSizer.Add((20,20),1)
1258        btnSizer.Add(OkBtn)
1259        btnSizer.Add((20,20),1)
1260        btnSizer.Add(cancelBtn)
1261        btnSizer.Add((20,20),1)
1262        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1263        panel.SetSizer(mainSizer)
1264        panel.Fit()
1265        self.Fit()
1266       
1267    def OnOk(self,event):
1268        parent = self.GetParent()
1269        if parent is not None: parent.Raise()
1270        # save the results from the choice widgets
1271        self.chosen = []
1272        for w in self.ChItems:
1273            self.chosen.append(w.GetSelection())
1274        self.EndModal(wx.ID_OK)             
1275           
1276    def OnCancel(self,event):
1277        parent = self.GetParent()
1278        if parent is not None: parent.Raise()
1279        self.chosen = []
1280        self.EndModal(wx.ID_CANCEL)             
1281           
1282def ExtractFileFromZip(filename, selection=None, confirmread=True,
1283                       confirmoverwrite=True, parent=None,
1284                       multipleselect=False):
1285    '''If the filename is a zip file, extract a file from that
1286    archive.
1287
1288    :param list Selection: used to predefine the name of the file
1289      to be extracted. Filename case and zip directory name are
1290      ignored in selection; the first matching file is used.
1291
1292    :param bool confirmread: if True asks the user to confirm before expanding
1293      the only file in a zip
1294
1295    :param bool confirmoverwrite: if True asks the user to confirm
1296      before overwriting if the extracted file already exists
1297
1298    :param bool multipleselect: if True allows more than one zip
1299      file to be extracted, a list of file(s) is returned.
1300      If only one file is present, do not ask which one, otherwise
1301      offer a list of choices (unless selection is used).
1302   
1303    :returns: the name of the file that has been created or a
1304      list of files (see multipleselect)
1305
1306    If the file is not a zipfile, return the name of the input file.
1307    If the zipfile is empty or no file has been selected, return None
1308    '''
1309    import zipfile # do this now, since we can save startup time by doing this only on need
1310    import shutil
1311    zloc = os.path.split(filename)[0]
1312    if not zipfile.is_zipfile(filename):
1313        #print("not zip")
1314        return filename
1315
1316    z = zipfile.ZipFile(filename,'r')
1317    zinfo = z.infolist()
1318
1319    if len(zinfo) == 0:
1320        #print('Zip has no files!')
1321        zlist = [-1]
1322    if selection:
1323        choices = [os.path.split(i.filename)[1].lower() for i in zinfo]
1324        if selection.lower() in choices:
1325            zlist = [choices.index(selection.lower())]
1326        else:
1327            print('debug: file '+str(selection)+' was not found in '+str(filename))
1328            zlist = [-1]
1329    elif len(zinfo) == 1 and confirmread:
1330        result = wx.ID_NO
1331        dlg = wx.MessageDialog(
1332            parent,
1333            'Is file '+str(zinfo[0].filename)+
1334            ' what you want to extract from '+
1335            str(os.path.split(filename)[1])+'?',
1336            'Confirm file', 
1337            wx.YES_NO | wx.ICON_QUESTION)
1338        try:
1339            result = dlg.ShowModal()
1340        finally:
1341            dlg.Destroy()
1342        if result == wx.ID_NO:
1343            zlist = [-1]
1344        else:
1345            zlist = [0]
1346    elif len(zinfo) == 1:
1347        zlist = [0]
1348    elif multipleselect:
1349        # select one or more from a from list
1350        choices = [i.filename for i in zinfo]
1351        dlg = wx.MultiChoiceDialog(parent,'Select file(s) to extract from zip file'+str(filename),
1352            'Choose file(s)',choices,wx.CHOICEDLG_STYLE,)
1353        if dlg.ShowModal() == wx.ID_OK:
1354            zlist = dlg.GetSelections()
1355        else:
1356            zlist = []
1357        dlg.Destroy()
1358    else:
1359        # select one from a from list
1360        choices = [i.filename for i in zinfo]
1361        dlg = wx.SingleChoiceDialog(parent,
1362            'Select file to extract from zip file'+str(filename),'Choose file',
1363            choices,)
1364        if dlg.ShowModal() == wx.ID_OK:
1365            zlist = [dlg.GetSelection()]
1366        else:
1367            zlist = [-1]
1368        dlg.Destroy()
1369       
1370    outlist = []
1371    for zindex in zlist:
1372        if zindex >= 0:
1373            efil = os.path.join(zloc, os.path.split(zinfo[zindex].filename)[1])
1374            if os.path.exists(efil) and confirmoverwrite:
1375                result = wx.ID_NO
1376                dlg = wx.MessageDialog(parent,
1377                    'File '+str(efil)+' already exists. OK to overwrite it?',
1378                    'Confirm overwrite',wx.YES_NO | wx.ICON_QUESTION)
1379                try:
1380                    result = dlg.ShowModal()
1381                finally:
1382                    dlg.Destroy()
1383                if result == wx.ID_NO:
1384                    zindex = -1
1385        if zindex >= 0:
1386            # extract the file to the current directory, regardless of it's original path
1387            #z.extract(zinfo[zindex],zloc)
1388            eloc,efil = os.path.split(zinfo[zindex].filename)
1389            outfile = os.path.join(zloc, efil)
1390            fpin = z.open(zinfo[zindex])
1391            fpout = file(outfile, "wb")
1392            shutil.copyfileobj(fpin, fpout)
1393            fpin.close()
1394            fpout.close()
1395            outlist.append(outfile)
1396    z.close()
1397    if multipleselect and len(outlist) >= 1:
1398        return outlist
1399    elif len(outlist) == 1:
1400        return outlist[0]
1401    else:
1402        return None
1403
1404######################################################################
1405# base classes for reading various types of data files
1406#   not used directly, only by subclassing
1407######################################################################
1408E,SGData = G2spc.SpcGroup('P 1') # data structure for default space group
1409class ImportBaseclass(object):
1410    '''Defines a base class for the reading of input files (diffraction
1411    data, coordinates,...
1412    '''
1413    def __init__(self,
1414                 formatName,
1415                 longFormatName=None,
1416                 extensionlist=[],
1417                 strictExtension=False,
1418                 ):
1419        self.formatName = formatName # short string naming file type
1420        if longFormatName: # longer string naming file type
1421            self.longFormatName = longFormatName
1422        else:
1423            self.longFormatName = formatName
1424        # define extensions that are allowed for the file type
1425        # for windows, remove any extensions that are duplicate, as case is ignored
1426        if sys.platform == 'windows' and extensionlist:
1427            extensionlist = list(set([s.lower() for s in extensionlist]))
1428        self.extensionlist = extensionlist
1429        # If strictExtension is True, the file will not be read, unless
1430        # the extension matches one in the extensionlist
1431        self.strictExtension = strictExtension
1432        self.warnings = ''
1433        # used for readers that will use multiple passes to read
1434        # more than one data block
1435        self.repeat = False
1436        self.repeatcount = 0
1437        #print 'created',self.__class__
1438
1439    def BlockSelector(self, ChoiceList, ParentFrame=None,
1440                      title='Select a block',
1441                      size=None, header='Block Selector',
1442                      useCancel=True):
1443        ''' Provide a wx dialog to select a block if the file contains more
1444        than one set of data and one must be selected
1445        '''
1446        if useCancel:
1447            dlg = wx.SingleChoiceDialog(
1448                ParentFrame,title, header,ChoiceList)
1449        else:
1450            dlg = wx.SingleChoiceDialog(
1451                ParentFrame,title, header,ChoiceList,
1452                style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK|wx.CENTRE)
1453        if size: dlg.SetSize(size)
1454        dlg.CenterOnParent()
1455        if dlg.ShowModal() == wx.ID_OK:
1456            sel = dlg.GetSelection()
1457            return sel
1458        else:
1459            return None
1460        dlg.Destroy()
1461
1462    def MultipleBlockSelector(self, ChoiceList, ParentFrame=None,
1463        title='Select a block',size=None, header='Block Selector'):
1464        '''Provide a wx dialog to select a block of data if the
1465        file contains more than one set of data and one must be
1466        selected.
1467
1468        :returns: a list of the selected blocks
1469        '''
1470        dlg = wx.MultiChoiceDialog(ParentFrame,title, header,ChoiceList+['Select all'],
1471            wx.CHOICEDLG_STYLE)
1472        dlg.CenterOnParent()
1473        if size: dlg.SetSize(size)
1474        if dlg.ShowModal() == wx.ID_OK:
1475            sel = dlg.GetSelections()
1476        else:
1477            return []
1478        dlg.Destroy()
1479        selected = []
1480        if len(ChoiceList) in sel:
1481            return range(len(ChoiceList))
1482        else:
1483            return sel
1484        return selected
1485
1486    def MultipleChoicesDialog(self, choicelist, headinglist, ParentFrame=None, **kwargs):
1487        '''A modal dialog that offers a series of choices, each with a title and a wx.Choice
1488        widget. Typical input:
1489       
1490           * choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1491           
1492           * headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1493           
1494        optional keyword parameters are: head (window title) and title
1495        returns a list of selected indicies for each choice (or None)
1496        '''
1497        result = None
1498        dlg = MultipleChoicesDialog(choicelist,headinglist,
1499            parent=ParentFrame, **kwargs)         
1500        dlg.CenterOnParent()
1501        if dlg.ShowModal() == wx.ID_OK:
1502            result = dlg.chosen
1503        dlg.Destroy()
1504        return result
1505
1506    def ShowBusy(self):
1507        wx.BeginBusyCursor()
1508
1509    def DoneBusy(self):
1510        wx.EndBusyCursor()
1511       
1512#    def Reader(self, filename, filepointer, ParentFrame=None, **unused):
1513#        '''This method must be supplied in the child class
1514#        it will read the file
1515#        '''
1516#        return True # if read OK
1517#        return False # if an error occurs
1518
1519    def ExtensionValidator(self, filename):
1520        '''This methods checks if the file has the correct extension
1521        Return False if this filename will not be supported by this reader
1522        Return True if the extension matches the list supplied by the reader
1523        Return None if the reader allows un-registered extensions
1524        '''
1525        if filename:
1526            ext = os.path.splitext(filename)[1]
1527            if sys.platform == 'windows': ext = ext.lower()
1528            if ext in self.extensionlist: return True
1529            if self.strictExtension: return False
1530        return None
1531
1532    def ContentsValidator(self, filepointer):
1533        '''This routine will attempt to determine if the file can be read
1534        with the current format.
1535        This will typically be overridden with a method that
1536        takes a quick scan of [some of]
1537        the file contents to do a "sanity" check if the file
1538        appears to match the selected format.
1539        Expected to be called via self.Validator()
1540        '''
1541        #filepointer.seek(0) # rewind the file pointer
1542        return True
1543
1544class ImportPhase(ImportBaseclass):
1545    '''Defines a base class for the reading of files with coordinates
1546    '''
1547    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1548        strictExtension=False,):
1549        # call parent __init__
1550        ImportBaseclass.__init__(self,formatName,longFormatName,
1551            extensionlist,strictExtension)
1552        # define a default Phase structure
1553        self.Phase = SetNewPhase(Name='new phase',SGData=SGData)
1554
1555    def PhaseSelector(self, ChoiceList, ParentFrame=None,
1556        title='Select a phase', size=None,header='Phase Selector'):
1557        ''' Provide a wx dialog to select a phase if the file contains more
1558        than one phase
1559        '''
1560        return self.BlockSelector(ChoiceList,ParentFrame,title,
1561            size,header)
1562
1563class ImportStructFactor(ImportBaseclass):
1564    '''Defines a base class for the reading of files with tables
1565    of structure factors
1566
1567    Note that the default controls are stored in self.Controls and the
1568    default instrument parameters are stored in self.Parameters.
1569    These can be changed, but any changes will be the defaults for all
1570    subsequent uses of the :class:`ImportStructFactor` derived classes
1571    until :meth:`InitControls` and :meth:`InitParameters` are
1572    called. Probably better to use :meth:`UpdateControls` and
1573    :meth:`UpdateControls` (adding new args if needed) to change
1574    values.
1575    '''
1576    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1577        strictExtension=False,):
1578        ImportBaseclass.__init__(self,formatName,longFormatName,
1579            extensionlist,strictExtension)
1580
1581        # define contents of Structure Factor entry
1582        self.InitParameters()
1583        self.InitControls()
1584        self.RefDict = {'RefList':[],'FF':[]}
1585       
1586    def InitControls(self):
1587        'initialize the controls structure'
1588        self.Controls = { # dictionary with plotting controls
1589            'Type' : 'Fosq',
1590            'ifFc' : False,    #
1591            'HKLmax' : [None,None,None],
1592            'HKLmin' : [None,None,None],
1593            'FoMax' : None,   # maximum observed structure factor as Fo
1594            'Zone' : '001',
1595            'Layer' : 0,
1596            'Scale' : 1.0,
1597            'log-lin' : 'lin',
1598            }
1599
1600    def InitParameters(self):
1601        'initialize the instrument parameters structure'
1602        Lambda = 0.70926
1603        HistType = 'SXC'
1604        self.Parameters = [{'Type':[HistType,HistType], # create the structure
1605                            'Lam':[Lambda,Lambda]
1606                            }, {}]
1607
1608    def UpdateParameters(self,Type=None,Wave=None):
1609        'Revise the instrument parameters'
1610        if Type is not None:
1611            self.Parameters[0]['Type'] = [Type,Type]
1612        if Wave is not None:
1613            self.Parameters[0]['Lam'] = [Wave,Wave]
1614           
1615    def UpdateControls(self,Type='Fosq',FcalcPresent=False):
1616        '''Scan through the reflections to update the Controls dictionary
1617        '''
1618        self.Controls['Type'] = Type
1619        self.Controls['ifFc'] = FcalcPresent
1620        HKLmax = [None,None,None]
1621        HKLmin = [None,None,None]
1622        Fo2max = None
1623        for refl in self.RefDict['RefList']:
1624            HKL = refl[:3]
1625            if Fo2max is None:
1626                Fo2max = refl[8]
1627            else:
1628                Fo2max = max(Fo2max,refl[8])
1629            for i,hkl in enumerate(HKL):
1630                if HKLmax[i] is None:
1631                    HKLmax[i] = hkl
1632                    HKLmin[i] = hkl
1633                else:
1634                    HKLmax[i] = max(HKLmax[i],hkl)
1635                    HKLmin[i] = min(HKLmin[i],hkl)
1636        self.Controls['HKLmax'] = HKLmax
1637        self.Controls['HKLmin'] = HKLmin
1638        if Type ==  'Fosq':
1639            self.Controls['FoMax'] = np.sqrt(Fo2max)
1640        elif Type ==  'Fo':
1641            self.Controls['FoMax'] = Fo2max
1642        else:
1643            print "Unsupported Struct Fact type in ImportStructFactor.UpdateControls"
1644            raise Exception,"Unsupported Struct Fact type in ImportStructFactor.UpdateControls"
1645
1646######################################################################
1647class ImportPowderData(ImportBaseclass):
1648    '''Defines a base class for the reading of files with powder data
1649    '''
1650    # define some default instrument parameter files
1651    # just like GSAS, sigh
1652    defaultIparm_lbl = []
1653    defaultIparms = []
1654    defaultIparm_lbl.append('CuKa lab data')
1655    defaultIparms.append({
1656        'INS   HTYPE ':'PXC ',
1657        'INS  1 ICONS':'  1.540500  1.544300       0.0         0       0.7    0       0.5   ',
1658        'INS  1PRCF1 ':'    3    8      0.01                                                ',
1659        'INS  1PRCF11':'   2.000000E+00  -2.000000E+00   5.000000E+00   0.000000E+00        ',
1660        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.150000E-01   0.150000E-01        ',
1661        })
1662    defaultIparm_lbl.append('0.6A synch')
1663    defaultIparms.append({
1664        'INS   HTYPE ':'PXC ',
1665        'INS  1 ICONS':'  0.600000  0.000000       0.0         0      0.99    0       0.5   ',
1666        'INS  1PRCF1 ':'    3    8      0.01                                                ',
1667        'INS  1PRCF11':'   1.000000E+00  -1.000000E+00   0.300000E+00   0.000000E+00        ',
1668        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.100000E-01   0.100000E-01        ',
1669        })
1670    defaultIparm_lbl.append('1.5A CW neutron data')
1671    defaultIparms.append({
1672        'INS   HTYPE ':'PNC',
1673        'INS  1 ICONS':'   1.54020   0.00000   0.04000         0',
1674        'INS  1PRCF1 ':'    3    8     0.005',
1675        'INS  1PRCF11':'   0.239700E+03  -0.298200E+03   0.180800E+03   0.000000E+00',
1676        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.400000E-01   0.300000E-01',
1677        })
1678    defaultIparm_lbl.append('10m TOF backscattering bank')
1679    defaultIparms.append({
1680        'INS   HTYPE ':'PNT',
1681        'INS  1 ICONS':'   5000.00      0.00      0.00',
1682        'INS  1BNKPAR':'    1.0000   150.000',       
1683        'INS  1PRCF1 ':'    1    8   0.01000',
1684        'INS  1PRCF11':'   0.000000E+00   5.000000E+00   3.000000E-02   1.000000E-03',
1685        'INS  1PRCF12':'   0.000000E+00   4.000000E+01   0.000000E+00   0.000000E+00',       
1686        })
1687    defaultIparm_lbl.append('10m TOF 90deg bank')
1688    defaultIparms.append({
1689        'INS   HTYPE ':'PNT',
1690        'INS  1 ICONS':'   3500.00      0.00      0.00',
1691        'INS  1BNKPAR':'    1.0000    90.000',       
1692        'INS  1PRCF1 ':'    1    8   0.01000',
1693        'INS  1PRCF11':'   0.000000E+00   5.000000E+00   3.000000E-02   4.000000E-03',
1694        'INS  1PRCF12':'   0.000000E+00   8.000000E+01   0.000000E+00   0.000000E+00',       
1695        })
1696    defaultIparm_lbl.append('63m POWGEN 90deg bank')
1697    defaultIparms.append({
1698        'INS   HTYPE ':'PNT',
1699        'INS  1 ICONS':'  22585.80      0.00      0.00',
1700        'INS  1BNKPAR':'    1.0000    90.000',       
1701        'INS  1PRCF1 ':'    1    8   0.01000',
1702        'INS  1PRCF11':'   0.000000E+00   1.000000E+00   3.000000E-02   4.000000E-03',
1703        'INS  1PRCF12':'   0.000000E+00   8.000000E+01   0.000000E+00   0.000000E+00',       
1704        })
1705    def __init__(self,
1706                 formatName,
1707                 longFormatName=None,
1708                 extensionlist=[],
1709                 strictExtension=False,
1710                 ):
1711        ImportBaseclass.__init__(self,formatName,
1712                                            longFormatName,
1713                                            extensionlist,
1714                                            strictExtension)
1715        self.powderentry = ['',None,None] #  (filename,Pos,Bank)
1716        self.powderdata = [] # Powder dataset
1717        '''A powder data set is a list with items [x,y,w,yc,yb,yd]:
1718                np.array(x), # x-axis values
1719                np.array(y), # powder pattern intensities
1720                np.array(w), # 1/sig(intensity)^2 values (weights)
1721                np.array(yc), # calc. intensities (zero)
1722                np.array(yb), # calc. background (zero)
1723                np.array(yd), # obs-calc profiles
1724        '''                           
1725        self.comments = []
1726        self.idstring = ''
1727        self.Sample = G2pdG.SetDefaultSample()
1728        self.GSAS = None     # used in TOF
1729        self.clockWd = None  # used in TOF
1730        self.repeat_instparm = True # Should a parm file be
1731        #                             used for multiple histograms?
1732        self.instparm = None # name hint
1733        self.instfile = '' # full path name to instrument parameter file
1734        self.instbank = '' # inst parm bank number
1735        self.instmsg = ''  # a label that gets printed to show
1736                           # where instrument parameters are from
1737        self.numbanks = 1
1738        self.instdict = {} # place items here that will be transferred to the instrument parameters
1739######################################################################
1740class ExportBaseclass(object):
1741    '''Defines a base class for the exporting of GSAS-II results
1742    '''
1743    def __init__(self,
1744                 G2frame,
1745                 formatName,
1746                 extension,
1747                 longFormatName=None,
1748                 ):
1749        self.G2frame = G2frame
1750        self.formatName = formatName # short string naming file type
1751        self.extension = extension
1752        if longFormatName: # longer string naming file type
1753            self.longFormatName = longFormatName
1754        else:
1755            self.longFormatName = formatName
1756        self.OverallParms = {}
1757        self.Phases = {}
1758        self.Histograms = {}
1759        self.powderDict = {}
1760        self.xtalDict = {}
1761        # updated in InitExport:
1762        self.currentExportType = None # type of export that has been requested
1763        # updated in ExportSelect (when used):
1764        self.phasenam = None # a list of selected phases
1765        self.histnam = None # a list of selected histograms
1766        self.filename = None # name of file to be written
1767       
1768        # items that should be defined in a subclass of this class
1769        self.exporttype = []  # defines the type(s) of exports that the class can handle.
1770        # The following types are defined: 'project', "phase", "powder", "single"
1771        self.multiple = False # set as True if the class can export multiple phases or histograms
1772        # self.multiple is ignored for "project" exports
1773
1774    def InitExport(self,event):
1775        '''Determines the type of menu that called the Exporter.
1776        '''
1777        if event:
1778            self.currentExportType = self.G2frame.ExportLookup.get(event.Id)
1779
1780    def ExportSelect(self,AskFile=True):
1781        '''Selects histograms or phases when needed. Sets a default file name.
1782
1783        :param bool AskFile: if AskFile is True (default) get the name of the file
1784          in a dialog
1785        :returns: True in case of an error
1786        '''
1787       
1788        if self.currentExportType == 'phase':
1789            if len(self.Phases) == 0:
1790                self.G2frame.ErrorDialog(
1791                    'Empty project',
1792                    'Project does not contain any phases.')
1793                return True
1794            elif self.multiple: 
1795                if len(self.Phases) == 1:
1796                    self.phasenam = self.Phases.keys()
1797                else:
1798                    choices = sorted(self.Phases.keys())
1799                    phasenum = G2gd.ItemSelector(choices,self.G2frame,multiple=True)
1800                    if phasenum is None: return True
1801                    self.phasenam = [choices[i] for i in phasenum]
1802            else:
1803                if len(self.Phases) == 1:
1804                    self.phasenam = self.Phases.keys()
1805                else:
1806                    choices = sorted(self.Phases.keys())
1807                    phasenum = G2gd.ItemSelector(choices,self.G2frame)
1808                    if phasenum is None: return True
1809                    self.phasenam = [choices[phasenum]]
1810        elif self.currentExportType == 'single':
1811            if len(self.xtalDict) == 0:
1812                self.G2frame.ErrorDialog(
1813                    'Empty project',
1814                    'Project does not contain any single crystal data.')
1815                return True
1816            elif self.multiple:
1817                if len(self.xtalDict) == 1:
1818                    self.histnam = self.xtalDict.values()
1819                else:
1820                    choices = sorted(self.xtalDict.values())
1821                    hnum = G2gd.ItemSelector(choices,self.G2frame,multiple=True)
1822                    if hnum is None: return True
1823                    self.histnam = [choices[i] for i in hnum]
1824            else:
1825                if len(self.xtalDict) == 1:
1826                    self.histnam = self.xtalDict.values()
1827                else:
1828                    choices = sorted(self.xtalDict.values())
1829                    hnum = G2gd.ItemSelector(choices,self.G2frame)
1830                    if hnum is None: return True
1831                    self.histnam = [choices[hnum]]
1832        elif self.currentExportType == 'powder':
1833            if len(self.powderDict) == 0:
1834                self.G2frame.ErrorDialog(
1835                    'Empty project',
1836                    'Project does not contain any powder data.')
1837                return True
1838            elif self.multiple:
1839                if len(self.powderDict) == 1:
1840                    self.histnam = self.powderDict.values()
1841                else:
1842                    choices = sorted(self.powderDict.values())
1843                    hnum = G2gd.ItemSelector(choices,self.G2frame,multiple=True)
1844                    if hnum is None: return True
1845                    self.histnam = [choices[i] for i in hnum]
1846            else:
1847                if len(self.powderDict) == 1:
1848                    self.histnam = self.powderDict.values()
1849                else:
1850                    choices = sorted(self.powderDict.values())
1851                    hnum = G2gd.ItemSelector(choices,self.G2frame)
1852                    if hnum is None: return True
1853                    self.histnam = [choices[hnum]]
1854        elif self.currentExportType == 'image':
1855            if len(self.Histograms) == 0:
1856                self.G2frame.ErrorDialog(
1857                    'Empty project',
1858                    'Project does not contain any images.')
1859                return True
1860            elif len(self.Histograms) == 1:
1861                self.histnam = self.Histograms.keys()
1862            else:
1863                choices = sorted(self.Histograms.keys())
1864                hnum = G2gd.ItemSelector(choices,self.G2frame,multiple=self.multiple)
1865                if hnum is None: return True
1866                if self.multiple:
1867                    self.histnam = [choices[i] for i in hnum]
1868                else:
1869                    self.histnam = [choices[hnum]]
1870        if AskFile:
1871            self.filename = self.askSaveFile()
1872        else:
1873            self.filename = self.defaultSaveFile()
1874        if not self.filename: return True
1875       
1876    # def SetupExport(self,event,AskFile=True):
1877    #     '''Determines the type of menu that called the Exporter. Selects histograms
1878    #     or phases when needed. Better to replace with individual calls to
1879    #     self.InitExport() and self.ExportSelect() so that the former can be called prior
1880    #     to self.LoadTree()
1881
1882    #     :param bool AskFile: if AskFile is True (default) get the name of the file
1883    #       in a dialog
1884    #     :returns: True in case of an error
1885    #     '''
1886    #     self.ExportInit(event)
1887    #     return self.ExportSelect(AskFile)
1888                   
1889    def loadParmDict(self):
1890        '''Load the GSAS-II refinable parameters from the tree into a dict (self.parmDict). Update
1891        refined values to those from the last cycle and set the uncertainties for the
1892        refined parameters in another dict (self.sigDict).
1893
1894        Expands the parm & sig dicts to include values derived from constraints.
1895        '''
1896        self.parmDict = {}
1897        self.sigDict = {}
1898        rigidbodyDict = {}
1899        covDict = {}
1900        consDict = {}
1901        Histograms,Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
1902        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
1903        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
1904        while item:
1905            name = self.G2frame.PatternTree.GetItemText(item)
1906            if name == 'Rigid bodies':
1907                 rigidbodyDict = self.G2frame.PatternTree.GetItemPyData(item)
1908            elif name == 'Covariance':
1909                 covDict = self.G2frame.PatternTree.GetItemPyData(item)
1910            elif name == 'Constraints':
1911                 consDict = self.G2frame.PatternTree.GetItemPyData(item)
1912            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
1913        rbVary,rbDict =  G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
1914        self.parmDict.update(rbDict)
1915        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
1916        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtables,BLtables =  G2stIO.GetPhaseData(
1917            Phases,RestraintDict=None,rbIds=rbIds,Print=False)
1918        self.parmDict.update(phaseDict)
1919        hapVary,hapDict,controlDict =  G2stIO.GetHistogramPhaseData(
1920            Phases,Histograms,Print=False,resetRefList=False)
1921        self.parmDict.update(hapDict)
1922        histVary,histDict,controlDict =  G2stIO.GetHistogramData(Histograms,Print=False)
1923        self.parmDict.update(histDict)
1924        self.parmDict.update(zip(
1925            covDict.get('varyList',[]),
1926            covDict.get('variables',[])))
1927        self.sigDict = dict(zip(
1928            covDict.get('varyList',[]),
1929            covDict.get('sig',[])))
1930        # expand to include constraints: first compile a list of constraints
1931        constList = []
1932        for item in consDict:
1933            constList += consDict[item]
1934        # now process the constraints
1935        G2mv.InitVars()
1936        constDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
1937        varyList = covDict.get('varyListStart')
1938        if varyList is None and len(constDict) == 0:
1939            # no constraints can use varyList
1940            varyList = covDict.get('varyList')
1941        elif varyList is None:
1942            # old GPX file from before pre-constraint varyList is saved
1943            print ' *** Old refinement: Please use Calculate/Refine to redo  ***'
1944            raise Exception(' *** CIF creation aborted ***')
1945        else:
1946            varyList = list(varyList)
1947        try:
1948            groups,parmlist = G2mv.GroupConstraints(constDict)
1949            G2mv.GenerateConstraints(groups,parmlist,varyList,constDict,fixedList)
1950        except:
1951            # this really should not happen
1952            print ' *** ERROR - constraints are internally inconsistent ***'
1953            errmsg, warnmsg = G2mv.CheckConstraints(varyList,constDict,fixedList)
1954            print 'Errors',errmsg
1955            if warnmsg: print 'Warnings',warnmsg
1956            raise Exception(' *** CIF creation aborted ***')
1957        # add the constrained values to the parameter dictionary
1958        G2mv.Dict2Map(self.parmDict,varyList)
1959        # and add their uncertainties into the esd dictionary (sigDict)
1960        if covDict.get('covMatrix') is not None:
1961            self.sigDict.update(G2mv.ComputeDepESD(covDict['covMatrix'],covDict['varyList'],self.parmDict))
1962
1963    def loadTree(self):
1964        '''Load the contents of the data tree into a set of dicts
1965        (self.OverallParms, self.Phases and self.Histogram as well as self.powderDict
1966        & self.xtalDict)
1967       
1968        * The childrenless data tree items are overall parameters/controls for the
1969          entire project and are placed in self.OverallParms
1970        * Phase items are placed in self.Phases
1971        * Data items are placed in self.Histogram. The key for these data items
1972          begin with a keyword, such as PWDR, IMG, HKLF,... that identifies the data type.
1973        '''
1974        self.OverallParms = {}
1975        self.powderDict = {}
1976        self.xtalDict = {}
1977        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
1978        histType = None       
1979        if self.currentExportType == 'phase':
1980            # if exporting phases load them here
1981            sub = G2gd.GetPatternTreeItemId(self.G2frame,self.G2frame.root,'Phases')
1982            if not sub:
1983                print 'no phases found'
1984                return True
1985            item, cookie = self.G2frame.PatternTree.GetFirstChild(sub)
1986            while item:
1987                phaseName = self.G2frame.PatternTree.GetItemText(item)
1988                self.Phases[phaseName] =  self.G2frame.PatternTree.GetItemPyData(item)
1989                item, cookie = self.G2frame.PatternTree.GetNextChild(sub, cookie)
1990            return
1991        elif self.currentExportType == 'single':
1992            histType = 'HKLF'
1993        elif self.currentExportType == 'powder':
1994            histType = 'PWDR'
1995        elif self.currentExportType == 'image':
1996            histType = 'IMG'
1997
1998        if histType: # Loading just one kind of tree entry
1999            item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
2000            while item:
2001                name = self.G2frame.PatternTree.GetItemText(item)
2002                if name.startswith(histType):
2003                    if self.Histograms.get(name): # there is already an item with this name
2004                        if name[-1] == '9':
2005                            name = name[:-1] + '10'
2006                        elif name[-1] in '012345678':
2007                            name = name[:-1] + str(int(name[:-1])+1)
2008                        else:                           
2009                            name += '-1'
2010                    self.Histograms[name] = {}
2011                    self.Histograms[name]['Data'] = self.G2frame.PatternTree.GetItemPyData(item)[1]
2012                    item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
2013                    while item2: 
2014                        child = self.G2frame.PatternTree.GetItemText(item2)
2015                        self.Histograms[name][child] = self.G2frame.PatternTree.GetItemPyData(item2)
2016                        item2, cookie2 = self.G2frame.PatternTree.GetNextChild(item, cookie2)
2017                item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
2018            # index powder and single crystal histograms by number
2019            for hist in self.Histograms:
2020                if hist.startswith("PWDR"): 
2021                    d = self.powderDict
2022                elif hist.startswith("HKLF"): 
2023                    d = self.xtalDict
2024                else:
2025                    return                   
2026                i = self.Histograms[hist].get('hId')
2027                if i is None and not d.keys():
2028                    i = 0
2029                elif i is None or i in d.keys():
2030                    i = max(d.keys())+1
2031                d[i] = hist
2032            return
2033        # else standard load: using all interlinked phases and histograms
2034        self.Histograms,self.Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
2035        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
2036        while item:
2037            name = self.G2frame.PatternTree.GetItemText(item)
2038            item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
2039            if not item2: 
2040                self.OverallParms[name] = self.G2frame.PatternTree.GetItemPyData(item)
2041            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
2042        # index powder and single crystal histograms
2043        for hist in self.Histograms:
2044            i = self.Histograms[hist]['hId']
2045            if hist.startswith("PWDR"): 
2046                self.powderDict[i] = hist
2047            elif hist.startswith("HKLF"): 
2048                self.xtalDict[i] = hist
2049
2050    def dumpTree(self,mode='type'):
2051        '''Print out information on the data tree dicts loaded in loadTree
2052        '''
2053        print '\nOverall'
2054        if mode == 'type':
2055            def Show(arg): return type(arg)
2056        else:
2057            def Show(arg): return arg
2058        for key in self.OverallParms:
2059            print '  ',key,Show(self.OverallParms[key])
2060        print 'Phases'
2061        for key1 in self.Phases:
2062            print '    ',key1,Show(self.Phases[key1])
2063        print 'Histogram'
2064        for key1 in self.Histograms:
2065            print '    ',key1,Show(self.Histograms[key1])
2066            for key2 in self.Histograms[key1]:
2067                print '      ',key2,Show(self.Histograms[key1][key2])
2068
2069    def defaultSaveFile(self):
2070        return os.path.abspath(
2071            os.path.splitext(self.G2frame.GSASprojectfile
2072                             )[0]+self.extension)
2073       
2074    def askSaveFile(self):
2075        '''Ask the user to supply a file name
2076
2077        :returns: a file name (str)
2078        '''
2079        defnam = os.path.splitext(
2080            os.path.split(self.G2frame.GSASprojectfile)[1]
2081            )[0]+self.extension
2082        dlg = wx.FileDialog(
2083            self.G2frame, 'Input name for file to write', '.', defnam,
2084            self.longFormatName+' (*'+self.extension+')|*'+self.extension,
2085            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
2086        dlg.CenterOnParent()
2087        try:
2088            if dlg.ShowModal() == wx.ID_OK:
2089                filename = dlg.GetPath()
2090                # make sure extension is correct
2091                filename = os.path.splitext(filename)[0]+self.extension
2092            else:
2093                filename = None
2094        finally:
2095            dlg.Destroy()
2096        return filename
2097
2098    # Tools for file writing.
2099    def OpenFile(self,fil=None):
2100        '''Open the output file
2101
2102        :param str fil: The name of the file to open. If None (default)
2103          the name defaults to self.filename.
2104        :returns: the file object opened by the routine which is also
2105          saved as self.fp
2106        '''
2107        if not fil:
2108            fil = self.filename
2109        self.fp = open(fil,'w')
2110        return self.fp
2111    def Write(self,line):
2112        '''write a line of output, attaching a line-end character
2113
2114        :param str line: the text to be written.
2115        '''
2116        self.fp.write(line+'\n')
2117    def CloseFile(self,fp=None):
2118        '''Close a file opened in OpenFile
2119
2120        :param file fp: the file object to be closed. If None (default)
2121          file object self.fp is closed.
2122        '''
2123        if fp is None:
2124            fp = self.fp
2125            self.fp = None
2126        fp.close()
2127    # Tools to pull information out of the data arrays
2128    def GetCell(self,phasenam):
2129        """Gets the unit cell parameters and their s.u.'s for a selected phase
2130
2131        :param str phasenam: the name for the selected phase
2132        :returns: `cellList,cellSig` where each is a 7 element list corresponding
2133          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
2134          cell values and `cellSig` has their uncertainties.
2135        """
2136        phasedict = self.Phases[phasenam] # pointer to current phase info
2137        try:
2138            pfx = str(phasedict['pId'])+'::'
2139            A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict)
2140            cellSig = G2stIO.getCellEsd(pfx,
2141                                        phasedict['General']['SGData'],A,
2142                                        self.OverallParms['Covariance'])  # returns 7 vals, includes sigVol
2143            cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)
2144            return cellList,cellSig
2145        except KeyError:
2146            cell = phasedict['General']['Cell'][1:]
2147            return cell,7*[0]
2148   
2149    def GetAtoms(self,phasenam):
2150        """Gets the atoms associated with a phase. Can be used with standard
2151        or macromolecular phases
2152
2153        :param str phasenam: the name for the selected phase
2154        :returns: a list of items for eac atom where each item is a list containing:
2155          label, typ, mult, xyz, and td, where
2156
2157          * label and typ are the atom label and the scattering factor type (str)
2158          * mult is the site multiplicity (int)
2159          * xyz is contains a list with four pairs of numbers:
2160            x, y, z and fractional occupancy and
2161            their standard uncertainty (or a negative value)
2162          * td is contains a list with either one or six pairs of numbers:
2163            if one number it is U\ :sub:`iso` and with six numbers it is
2164            U\ :sub:`11`, U\ :sub:`22`, U\ :sub:`33`, U\ :sub:`12`, U\ :sub:`13` & U\ :sub:`23`
2165            paired with their standard uncertainty (or a negative value)
2166        """
2167        phasedict = self.Phases[phasenam] # pointer to current phase info           
2168        cx,ct,cs,cia = phasedict['General']['AtomPtrs']
2169        cfrac = cx+3
2170        fpfx = str(phasedict['pId'])+'::Afrac:'       
2171        atomslist = []
2172        for i,at in enumerate(phasedict['Atoms']):
2173            if phasedict['General']['Type'] == 'macromolecular':
2174                label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2])
2175            else:
2176                label = at[ct-1]
2177            fval = self.parmDict.get(fpfx+str(i),at[cfrac])
2178            fsig = self.sigDict.get(fpfx+str(i),-0.009)
2179            mult = at[cs+1]
2180            typ = at[ct]
2181            xyz = []
2182            for j,v in enumerate(('x','y','z')):
2183                val = at[cx+j]
2184                pfx = str(phasedict['pId'])+'::dA'+v+':'+str(i)
2185                sig = self.sigDict.get(pfx,-0.000009)
2186                xyz.append((val,sig))
2187            xyz.append((fval,fsig))
2188            td = []
2189            if at[cia] == 'I':
2190                pfx = str(phasedict['pId'])+'::AUiso:'+str(i)
2191                val = self.parmDict.get(pfx,at[cia+1])
2192                sig = self.sigDict.get(pfx,-0.0009)
2193                td.append((val,sig))
2194            else:
2195                for i,var in enumerate(('AU11','AU22','AU33','AU12','AU13','AU23')):
2196                    pfx = str(phasedict['pId'])+'::'+var+':'+str(i)
2197                    val = self.parmDict.get(pfx,at[cia+2+i])
2198                    sig = self.sigDict.get(pfx,-0.0009)
2199                    td.append((val,sig))
2200            atomslist.append((label,typ,mult,xyz,td))
2201        return atomslist
2202######################################################################
2203
2204def ReadCIF(URLorFile):
2205    '''Open a CIF, which may be specified as a file name or as a URL using PyCifRW
2206    (from James Hester).
2207    The open routine gets confused with DOS names that begin with a letter and colon
2208    "C:\dir\" so this routine will try to open the passed name as a file and if that
2209    fails, try it as a URL
2210
2211    :param str URLorFile: string containing a URL or a file name. Code will try first
2212      to open it as a file and then as a URL.
2213
2214    :returns: a PyCifRW CIF object.
2215    '''
2216    import CifFile as cif # PyCifRW from James Hester
2217
2218    # alternate approach:
2219    #import urllib
2220    #ciffile = 'file:'+urllib.pathname2url(filename)
2221   
2222    try:
2223        fp = open(URLorFile,'r')
2224        cf = cif.ReadCif(fp)
2225        fp.close()
2226        return cf
2227    except IOError:
2228        return cif.ReadCif(URLorFile)
2229
2230if __name__ == '__main__':
2231    app = wx.PySimpleApp()
2232    frm = wx.Frame(None) # create a frame
2233    frm.Show(True)
2234    filename = '/tmp/notzip.zip'
2235    filename = '/tmp/all.zip'
2236    #filename = '/tmp/11bmb_7652.zip'
2237   
2238    #selection=None, confirmoverwrite=True, parent=None
2239    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
2240    print ExtractFileFromZip(filename,multipleselect=True)
2241                             #confirmread=False, confirmoverwrite=False)
2242
2243    # choicelist=[ ('a','b','c'),
2244    #              ('test1','test2'),('no choice',)]
2245    # titles = [ 'a, b or c', 'tests', 'No option here']
2246    # dlg = MultipleChoicesDialog(
2247    #     choicelist,titles,
2248    #     parent=frm)
2249    # if dlg.ShowModal() == wx.ID_OK:
2250    #     print 'Got OK'
Note: See TracBrowser for help on using the repository browser.