source: trunk/GSASIIIO.py @ 981

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

introduce regress option; fix esd printing; more docs; new Mac app with drag & drop for open; control reset of ref list on load

  • 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-07-07 14:58:08 +0000 (Sun, 07 Jul 2013) $
4# $Author: toby $
5# $Revision: 981 $
6# $URL: trunk/GSASIIIO.py $
7# $Id: GSASIIIO.py 981 2013-07-07 14:58:08Z 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: 981 $")
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(
1597            Phases,Histograms,Print=False,resetRefList=False)
1598        self.parmDict.update(hapDict)
1599        histVary,histDict,controlDict =  G2stIO.GetHistogramData(Histograms,Print=False)
1600        self.parmDict.update(histDict)
1601        self.parmDict.update(zip(
1602            covDict.get('varyList',[]),
1603            covDict.get('variables',[])))
1604        self.sigDict = dict(zip(
1605            covDict.get('varyList',[]),
1606            covDict.get('sig',[])))
1607        # expand to include constraints: first compile a list of constraints
1608        constList = []
1609        for item in consDict:
1610            constList += consDict[item]
1611        # now process the constraints
1612        G2mv.InitVars()
1613        constDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
1614        varyList = covDict.get('varyListStart')
1615        if varyList is None and len(constDict) == 0:
1616            # no constraints can use varyList
1617            varyList = covDict.get('varyList')
1618        elif varyList is None:
1619            # old GPX file from before pre-constraint varyList is saved
1620            print ' *** Old refinement: Please use Calculate/Refine to redo  ***'
1621            raise Exception(' *** CIF creation aborted ***')
1622        else:
1623            varyList = list(varyList)
1624        try:
1625            groups,parmlist = G2mv.GroupConstraints(constDict)
1626            G2mv.GenerateConstraints(groups,parmlist,varyList,constDict,fixedList)
1627        except:
1628            # this really should not happen
1629            print ' *** ERROR - constraints are internally inconsistent ***'
1630            errmsg, warnmsg = G2mv.CheckConstraints(varyList,constDict,fixedList)
1631            print 'Errors',errmsg
1632            if warnmsg: print 'Warnings',warnmsg
1633            raise Exception(' *** CIF creation aborted ***')
1634        # add the constrained values to the parameter dictionary
1635        G2mv.Dict2Map(self.parmDict,varyList)
1636        # and add their uncertainties into the esd dictionary (sigDict)
1637        if covDict.get('covMatrix') is not None:
1638            self.sigDict.update(G2mv.ComputeDepESD(covDict['covMatrix'],covDict['varyList'],self.parmDict))
1639
1640    def loadTree(self):
1641        '''Load the contents of the data tree into a set of dicts
1642        (self.OverallParms, self.Phases and self.Histogram)
1643       
1644        * The childrenless data tree items are overall parameters/controls for the
1645          entire project and are placed in self.OverallParms
1646        * Phase items are placed in self.Phases
1647        * Data items are placed in self.Histogram. The key for these data items
1648          begin with a keyword, such as PWDR, IMG, HKLF,... that identifies the data type.
1649        '''
1650        self.OverallParms = {}
1651        self.Histograms,self.Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
1652        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
1653        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
1654        while item:
1655            name = self.G2frame.PatternTree.GetItemText(item)
1656            item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
1657            if not item2: 
1658                self.OverallParms[name] = self.G2frame.PatternTree.GetItemPyData(item)
1659            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
1660
1661    def dumpTree(self,mode='type'):
1662        '''Print out information on the data tree dicts loaded in loadTree
1663        '''
1664        print '\nOverall'
1665        if mode == 'type':
1666            def Show(arg): return type(arg)
1667        else:
1668            def Show(arg): return arg
1669        for key in self.OverallParms:
1670            print '  ',key,Show(self.OverallParms[key])
1671        print 'Phases'
1672        for key1 in self.Phases:
1673            print '    ',key1,Show(self.Phases[key1])
1674        print 'Histogram'
1675        for key1 in self.Histograms:
1676            print '    ',key1,Show(self.Histograms[key1])
1677            for key2 in self.Histograms[key1]:
1678                print '      ',key2,Show(self.Histograms[key1][key2])
1679                   
1680######################################################################
1681class ImportStructFactor(ImportBaseclass):
1682    '''Defines a base class for the reading of files with tables
1683    of structure factors
1684    '''
1685    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1686        strictExtension=False,):
1687        ImportBaseclass.__init__(self,formatName,longFormatName,
1688            extensionlist,strictExtension)
1689
1690        # define contents of Structure Factor entry
1691        self.Controls = { # dictionary with plotting controls
1692            'Type' : 'Fosq',
1693            'ifFc' : False,    #
1694            'HKLmax' : [None,None,None],
1695            'HKLmin' : [None,None,None],
1696            'FoMax' : None,   # maximum observed structure factor as Fo
1697            'Zone' : '001',
1698            'Layer' : 0,
1699            'Scale' : 1.0,
1700            'log-lin' : 'lin',
1701            }
1702        self.Parameters = [ # list with data collection parameters
1703            ('SXC',0.70926),
1704            ['SXC',0.70926],
1705            ['Type','Lam']
1706            ]
1707        self.RefList = []
1708
1709    def UpdateParameters(self,Type=None,Wave=None):
1710        HistType = self.Parameters[0][0]
1711        HistWave = self.Parameters[0][1]
1712        if Type is not None:
1713            HistType = Type
1714        if Wave is not None:
1715            HistWave = Wave
1716        self.Parameters = [{'Type':[HistType,HistType],'Lam':[HistWave,HistWave]},{}]  # overwrite entire list
1717           
1718    def UpdateControls(self,Type='Fosq',FcalcPresent=False):
1719        '''Scan through the reflections to update the Controls dictionary
1720        '''
1721        self.Controls['Type'] = Type
1722        self.Controls['ifFc'] = FcalcPresent
1723        HKLmax = [None,None,None]
1724        HKLmin = [None,None,None]
1725        Fo2max = None
1726        for refl in self.RefList:
1727            HKL = refl[:3]
1728            if Fo2max is None:
1729                Fo2max = refl[8]
1730            else:
1731                Fo2max = max(Fo2max,refl[8])
1732            for i,hkl in enumerate(HKL):
1733                if HKLmax[i] is None:
1734                    HKLmax[i] = hkl
1735                    HKLmin[i] = hkl
1736                else:
1737                    HKLmax[i] = max(HKLmax[i],hkl)
1738                    HKLmin[i] = min(HKLmin[i],hkl)
1739        self.Controls['HKLmax'] = HKLmax
1740        self.Controls['HKLmin'] = HKLmin
1741        if Type ==  'Fosq':
1742            self.Controls['FoMax'] = np.sqrt(Fo2max)
1743        elif Type ==  'Fo':
1744            self.Controls['FoMax'] = Fo2max
1745        else:
1746            print "Unsupported Struct Fact type in ImportStructFactor.UpdateControls"
1747            raise Exception,"Unsupported Struct Fact type in ImportStructFactor.UpdateControls"
1748
1749######################################################################
1750class ImportPowderData(ImportBaseclass):
1751    '''Defines a base class for the reading of files with powder data
1752    '''
1753    # define some default instrument parameter files
1754    # just like GSAS, sigh
1755    defaultIparm_lbl = []
1756    defaultIparms = []
1757    defaultIparm_lbl.append('CuKa lab data')
1758    defaultIparms.append({
1759        'INS   HTYPE ':'PXC ',
1760        'INS  1 ICONS':'  1.540500  1.544300       0.0         0       0.7    0       0.5   ',
1761        'INS  1PRCF1 ':'    3    8      0.01                                                ',
1762        'INS  1PRCF11':'   2.000000E+00  -2.000000E+00   5.000000E+00   0.000000E+00        ',
1763        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.150000E-01   0.150000E-01        ',
1764        })
1765    defaultIparm_lbl.append('0.6A synch')
1766    defaultIparms.append({
1767        'INS   HTYPE ':'PXC ',
1768        'INS  1 ICONS':'  0.600000  0.000000       0.0         0      0.99    0       0.5   ',
1769        'INS  1PRCF1 ':'    3    8      0.01                                                ',
1770        'INS  1PRCF11':'   1.000000E+00  -1.000000E+00   0.300000E+00   0.000000E+00        ',
1771        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.100000E-01   0.100000E-01        ',
1772        })
1773    defaultIparm_lbl.append('1.5A CW neutron data')
1774    defaultIparms.append({
1775        'INS   HTYPE ':'PNC',
1776        'INS  1 ICONS':'   1.54020   0.00000   0.04000         0',
1777        'INS  1PRCF1 ':'    3    8     0.005',
1778        'INS  1PRCF11':'   0.239700E+03  -0.298200E+03   0.180800E+03   0.000000E+00',
1779        'INS  1PRCF12':'   0.000000E+00   0.000000E+00   0.400000E-01   0.300000E-01',
1780        })
1781    defaultIparm_lbl.append('10m TOF backscattering bank')
1782    defaultIparms.append({
1783        'INS   HTYPE ':'PNT',
1784        'INS  1 ICONS':'   5000.00      0.00      0.00',
1785        'INS  1BNKPAR':'    1.0000   150.000',       
1786        'INS  1PRCF1 ':'    1    8   0.01000',
1787        'INS  1PRCF11':'   0.000000E+00   5.000000E+00   3.000000E-02   1.000000E-03',
1788        'INS  1PRCF12':'   0.000000E+00   4.000000E+01   0.000000E+00   0.000000E+00',       
1789        })
1790    defaultIparm_lbl.append('10m TOF 90deg bank')
1791    defaultIparms.append({
1792        'INS   HTYPE ':'PNT',
1793        'INS  1 ICONS':'   3500.00      0.00      0.00',
1794        'INS  1BNKPAR':'    1.0000    90.000',       
1795        'INS  1PRCF1 ':'    1    8   0.01000',
1796        'INS  1PRCF11':'   0.000000E+00   5.000000E+00   3.000000E-02   4.000000E-03',
1797        'INS  1PRCF12':'   0.000000E+00   8.000000E+01   0.000000E+00   0.000000E+00',       
1798        })
1799    defaultIparm_lbl.append('63m POWGEN 90deg bank')
1800    defaultIparms.append({
1801        'INS   HTYPE ':'PNT',
1802        'INS  1 ICONS':'  22585.80      0.00      0.00',
1803        'INS  1BNKPAR':'    1.0000    90.000',       
1804        'INS  1PRCF1 ':'    1    8   0.01000',
1805        'INS  1PRCF11':'   0.000000E+00   1.000000E+00   3.000000E-02   4.000000E-03',
1806        'INS  1PRCF12':'   0.000000E+00   8.000000E+01   0.000000E+00   0.000000E+00',       
1807        })
1808    def __init__(self,
1809                 formatName,
1810                 longFormatName=None,
1811                 extensionlist=[],
1812                 strictExtension=False,
1813                 ):
1814        ImportBaseclass.__init__(self,formatName,
1815                                            longFormatName,
1816                                            extensionlist,
1817                                            strictExtension)
1818        self.powderentry = ['',None,None] #  (filename,Pos,Bank)
1819        self.powderdata = [] # Powder dataset
1820        '''A powder data set is a list with items [x,y,w,yc,yb,yd]:
1821                np.array(x), # x-axis values
1822                np.array(y), # powder pattern intensities
1823                np.array(w), # 1/sig(intensity)^2 values (weights)
1824                np.array(yc), # calc. intensities (zero)
1825                np.array(yb), # calc. background (zero)
1826                np.array(yd), # obs-calc profiles
1827        '''                           
1828        self.comments = []
1829        self.idstring = ''
1830        self.Sample = G2pdG.SetDefaultSample()
1831        self.GSAS = None     # used in TOF
1832        self.clockWd = None  # used in TOF
1833        self.repeat_instparm = True # Should a parm file be
1834        #                             used for multiple histograms?
1835        self.instparm = None # name hint
1836        self.instfile = '' # full path name to instrument parameter file
1837        self.instbank = '' # inst parm bank number
1838        self.instmsg = ''  # a label that gets printed to show
1839                           # where instrument parameters are from
1840        self.numbanks = 1
1841        self.instdict = {} # place items here that will be transferred to the instrument parameters
1842
1843if __name__ == '__main__':
1844    app = wx.PySimpleApp()
1845    frm = wx.Frame(None) # create a frame
1846    frm.Show(True)
1847    filename = '/tmp/notzip.zip'
1848    filename = '/tmp/all.zip'
1849    #filename = '/tmp/11bmb_7652.zip'
1850   
1851    #selection=None, confirmoverwrite=True, parent=None
1852    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
1853    print ExtractFileFromZip(filename,multipleselect=True)
1854                             #confirmread=False, confirmoverwrite=False)
1855
1856    # choicelist=[ ('a','b','c'),
1857    #              ('test1','test2'),('no choice',)]
1858    # titles = [ 'a, b or c', 'tests', 'No option here']
1859    # dlg = MultipleChoicesDialog(
1860    #     choicelist,titles,
1861    #     parent=frm)
1862    # if dlg.ShowModal() == wx.ID_OK:
1863    #     print 'Got OK'
Note: See TracBrowser for help on using the repository browser.