source: trunk/GSASIIIO.py @ 1160

Last change on this file since 1160 was 1160, checked in by toby, 9 years ago

finish ISODISPLACE fixes; improve show var window; improve help window; add refine checkbox for newvars in constraints display

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