source: trunk/GSASIIIO.py @ 1156

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

Read 32-bit CHESS tiff files?

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