source: trunk/GSASIIIO.py @ 1131

Last change on this file since 1131 was 1131, checked in by vondreele, 8 years ago

fix to read Chess A2 tiff files
add polarization correction to SASD type patterns (show as PWDR for now)
fix to polygon & frame selection

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