source: trunk/GSASIIIO.py @ 1122

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

rename ASCIImap to just map
add export of ccp4 maps

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