source: trunk/GSASIIIO.py @ 1148

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

major changes to 2-D detector calibration; now works for strongly tilted detectors & short sample to detector distances.
Distance is now defined as sample to detector plane. Previously it was sample to intercept of detector plane with incident beam (Bragg cone axis).
The "penetration" parameter is still suspect.

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