source: trunk/GSASIIIO.py @ 960

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

check in CIF dev snapshot

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