source: trunk/GSASIIIO.py @ 1199

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

1st import of small angle data, create SASD data from image.
Work on proper plotting of SASD data
work on image GUI stuff for small angle data

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