source: trunk/GSASIIIO.py @ 1165

Last change on this file since 1165 was 1165, checked in by vondreele, 9 years ago

image calibration much better now - works on transposed data

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