source: trunk/GSASIIIO.py @ 1215

Last change on this file since 1215 was 1215, checked in by toby, 8 years ago

add .png reading

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