source: trunk/GSASIIIO.py @ 2721

Last change on this file since 2721 was 2721, checked in by vondreele, 5 years ago

fix pseudo variable issues when some vals are None
fix problem of moved ge multi-image files

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 116.0 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2017-02-23 19:26:52 +0000 (Thu, 23 Feb 2017) $
4# $Author: vondreele $
5# $Revision: 2721 $
6# $URL: trunk/GSASIIIO.py $
7# $Id: GSASIIIO.py 2721 2017-02-23 19:26:52Z vondreele $
8########### SVN repository information ###################
9'''
10*GSASIIIO: Misc I/O routines*
11=============================
12
13Module with miscellaneous routines for input and output. Many
14are GUI routines to interact with user.
15
16Includes support for image reading.
17
18Also includes base classes for data import routines.
19
20'''
21"""GSASIIIO: functions for IO of data
22   Copyright: 2008, Robert B. Von Dreele (Argonne National Laboratory)
23"""
24import wx
25import math
26import numpy as np
27import copy
28import cPickle
29import sys
30import re
31import random as ran
32import GSASIIpath
33GSASIIpath.SetVersionNumber("$Revision: 2721 $")
34import GSASIIgrid as G2gd
35import GSASIIspc as G2spc
36import GSASIIobj as G2obj
37import GSASIIlattice as G2lat
38import GSASIImath as G2mth
39import GSASIIpwdGUI as G2pdG
40import GSASIIimgGUI as G2imG
41import GSASIIimage as G2img
42import GSASIIElem as G2el
43import GSASIIstrIO as G2stIO
44import GSASIImapvars as G2mv
45import GSASIIctrls as G2G
46import os
47import os.path as ospath
48
49DEBUG = False       #=True for various prints
50TRANSP = False      #=true to transpose images for testing
51if GSASIIpath.GetConfigValue('Transpose'): TRANSP = True
52npsind = lambda x: np.sin(x*np.pi/180.)
53
54def sfloat(S):
55    'Convert a string to float. An empty field or a unconvertable value is treated as zero'
56    if S.strip():
57        try:
58            return float(S)
59        except ValueError:
60            pass
61    return 0.0
62
63def sint(S):
64    'Convert a string to int. An empty field is treated as zero'
65    if S.strip():
66        return int(S)
67    else:
68        return 0
69
70def trim(val):
71    '''Simplify a string containing leading and trailing spaces
72    as well as newlines, tabs, repeated spaces etc. into a shorter and
73    more simple string, by replacing all ranges of whitespace
74    characters with a single space.
75
76    :param str val: the string to be simplified
77
78    :returns: the (usually) shortened version of the string
79    '''
80    return re.sub('\s+', ' ', val).strip()
81
82def makeInstDict(names,data,codes):
83    inst = dict(zip(names,zip(data,data,codes)))
84    for item in inst:
85        inst[item] = list(inst[item])
86    return inst
87
88def FileDlgFixExt(dlg,file):
89    'this is needed to fix a problem in linux wx.FileDialog'
90    ext = dlg.GetWildcard().split('|')[2*dlg.GetFilterIndex()+1].strip('*')
91    if ext not in file:
92        file += ext
93    return file
94       
95def GetPowderPeaks(fileName):
96    'Read powder peaks from a file'
97    sind = lambda x: math.sin(x*math.pi/180.)
98    asind = lambda x: 180.*math.asin(x)/math.pi
99    wave = 1.54052
100    File = open(fileName,'Ur')
101    Comments = []
102    peaks = []
103    S = File.readline()
104    while S:
105        if S[:1] == '#':
106            Comments.append(S[:-1])
107        else:
108            item = S.split()
109            if len(item) == 1:
110                peaks.append([float(item[0]),1.0])
111            elif len(item) > 1:
112                peaks.append([float(item[0]),float(item[0])])
113        S = File.readline()
114    File.close()
115    if Comments:
116       print 'Comments on file:'
117       for Comment in Comments: 
118            print Comment
119            if 'wavelength' in Comment:
120                wave = float(Comment.split('=')[1])
121    Peaks = []
122    if peaks[0][0] > peaks[-1][0]:          # d-spacings - assume CuKa
123        for peak in peaks:
124            dsp = peak[0]
125            sth = wave/(2.0*dsp)
126            if sth < 1.0:
127                tth = 2.0*asind(sth)
128            else:
129                break
130            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
131    else:                                   #2-thetas - assume Cuka (for now)
132        for peak in peaks:
133            tth = peak[0]
134            dsp = wave/(2.0*sind(tth/2.0))
135            Peaks.append([tth,peak[1],True,False,0,0,0,dsp,0.0])
136    limits = [1000.,0.]
137    for peak in Peaks:
138        limits[0] = min(limits[0],peak[0])
139        limits[1] = max(limits[1],peak[0])
140    limits[0] = max(1.,(int(limits[0]-1.)/5)*5.)
141    limits[1] = min(170.,(int(limits[1]+1.)/5)*5.)
142    return Comments,Peaks,limits,wave
143
144def GetCheckImageFile(G2frame,treeId):
145    '''Try to locate an image file if the project and image have been moved
146    together. If the image file cannot be found, request the location from
147    the user.
148
149    :param wx.Frame G2frame: main GSAS-II Frame and data object
150    :param wx.Id treeId: Id for the main tree item for the image
151    :returns: Npix,imagefile,imagetag with (Npix) number of pixels,
152       imagefile, if it exists, or the name of a file that does exist or False if the user presses Cancel
153       and (imagetag) an optional image number
154
155    '''
156    Npix,Imagefile,imagetag = G2frame.PatternTree.GetImageLoc(treeId)
157    if isinstance(Imagefile,list):
158        imagefile,imagetag = Imagefile
159    else:
160        imagefile = Imagefile
161    if not os.path.exists(imagefile):
162        print 'Image file '+imagefile+' not found'
163        fil = imagefile.replace('\\','/') # windows?!
164        # see if we can find a file with same name or in a similarly named sub-dir
165        pth,fil = os.path.split(fil)
166        prevpth = None
167        while pth and pth != prevpth:
168            prevpth = pth
169            if os.path.exists(os.path.join(G2frame.dirname,fil)):
170                print 'found image file '+os.path.join(G2frame.dirname,fil)
171                imagefile = os.path.join(G2frame.dirname,fil)
172                G2frame.PatternTree.UpdateImageLoc(treeId,imagefile)
173                return Npix,imagefile,imagetag
174            pth,enddir = os.path.split(pth)
175            fil = os.path.join(enddir,fil)
176        # not found as a subdirectory, drop common parts of path for last saved & image file names
177        #    if image was .../A/B/C/imgs/ima.ge
178        #      & GPX was  .../A/B/C/refs/fil.gpx but is now .../NEW/TEST/TEST1
179        #    will look for .../NEW/TEST/TEST1/imgs/ima.ge, .../NEW/TEST/imgs/ima.ge, .../NEW/imgs/ima.ge and so on
180        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
181        gpxPath = Controls.get('LastSavedAs','').replace('\\','/').split('/') # blank in older .GPX files
182        imgPath = imagefile.replace('\\','/').split('/')
183        for p1,p2 in zip(gpxPath,imgPath):
184            if p1 == p2:
185                gpxPath.pop(0),imgPath.pop(0)
186            else:
187                break
188        fil = os.path.join(*imgPath) # file with non-common prefix elements
189        prevpth = None
190        pth = os.path.abspath(G2frame.dirname)
191        while pth and pth != prevpth:
192            prevpth = pth
193            if os.path.exists(os.path.join(pth,fil)):
194                print 'found image file '+os.path.join(pth,fil)
195                imagefile = os.path.join(pth,fil)
196                G2frame.PatternTree.UpdateImageLoc(treeId,imagefile)
197                return Npix,imagefile,imagetag
198            pth,enddir = os.path.split(pth)
199        #GSASIIpath.IPyBreak()
200
201    if not os.path.exists(imagefile):
202        prevnam = os.path.split(imagefile)[1]
203        prevext = os.path.splitext(imagefile)[1]
204        wildcard = 'Image format (*'+prevext+')|*'+prevext
205        dlg = wx.FileDialog(G2frame, 'Previous image file ('+prevnam+') not found; open here', '.', prevnam,
206                            wildcard,wx.OPEN)
207        try:
208            dlg.SetFilename(''+ospath.split(imagefile)[1])
209            if dlg.ShowModal() == wx.ID_OK:
210                imagefile = dlg.GetPath()
211                G2frame.PatternTree.UpdateImageLoc(treeId,imagefile)
212            else:
213                imagefile = False
214        finally:
215            dlg.Destroy()
216    return Npix,imagefile,imagetag
217
218def EditImageParms(parent,Data,Comments,Image,filename):
219    dlg = wx.Dialog(parent, wx.ID_ANY, 'Edit image parameters',
220                    style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
221    def onClose(event):
222        dlg.EndModal(wx.ID_OK)
223    mainsizer = wx.BoxSizer(wx.VERTICAL)
224    h,w = Image.shape[:2]
225    mainsizer.Add(wx.StaticText(dlg,wx.ID_ANY,
226                                'File '+str(filename)+'\nImage size: '+str(h)+' x '+str(w)),
227                  0,wx.ALIGN_LEFT|wx.ALL, 2)
228   
229    vsizer = wx.BoxSizer(wx.HORIZONTAL)
230    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Wavelength (\xC5) '),
231               0,wx.ALIGN_LEFT|wx.ALL, 2)
232    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'wavelength')
233    vsizer.Add(wdgt)
234    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
235
236    vsizer = wx.BoxSizer(wx.HORIZONTAL)
237    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Pixel size (\xb5m). Width '),
238               0,wx.ALIGN_LEFT|wx.ALL, 2)
239    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],0,
240                                 size=(50,-1))
241    vsizer.Add(wdgt)
242    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Height '),
243               wx.ALIGN_LEFT|wx.ALL, 2)
244    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],1,
245                                 size=(50,-1))
246    vsizer.Add(wdgt)
247    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
248
249    vsizer = wx.BoxSizer(wx.HORIZONTAL)
250    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Sample to detector (mm) '),
251               0,wx.ALIGN_LEFT|wx.ALL, 2)
252    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'distance')
253    vsizer.Add(wdgt)
254    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
255
256    vsizer = wx.BoxSizer(wx.HORIZONTAL)
257    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Beam center (pixels). X = '),
258               0,wx.ALIGN_LEFT|wx.ALL, 2)
259    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],0,
260                                 size=(75,-1))
261    vsizer.Add(wdgt)
262    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Y = '),
263               wx.ALIGN_LEFT|wx.ALL, 2)
264    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],1,
265                                 size=(75,-1))
266    vsizer.Add(wdgt)
267    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
268
269    vsizer = wx.BoxSizer(wx.HORIZONTAL)
270    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Comments '),
271               0,wx.ALIGN_LEFT|wx.ALL, 2)
272    wdgt = G2G.ValidatedTxtCtrl(dlg,Comments,0,size=(250,-1))
273    vsizer.Add(wdgt)
274    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
275
276    btnsizer = wx.StdDialogButtonSizer()
277    OKbtn = wx.Button(dlg, wx.ID_OK, 'Continue')
278    OKbtn.SetDefault()
279    OKbtn.Bind(wx.EVT_BUTTON,onClose)
280    btnsizer.AddButton(OKbtn) # not sure why this is needed
281    btnsizer.Realize()
282    mainsizer.Add(btnsizer, 1, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 5)
283    dlg.SetSizer(mainsizer)
284    dlg.CenterOnParent()
285    dlg.ShowModal()
286   
287def LoadImage2Tree(imagefile,G2frame,Comments,Data,Npix,Image):
288    '''Load an image into the tree. Saves the location of the image, as well as the
289    ImageTag (where there is more than one image in the file), if defined.
290    '''
291    ImgNames = G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
292    TreeLbl = 'IMG '+os.path.basename(imagefile)
293    ImageTag = Data.get('ImageTag')
294    if ImageTag:
295        TreeLbl += ' #'+'%04d'%(ImageTag)
296        imageInfo = (imagefile,ImageTag)
297    else:
298        imageInfo = imagefile
299    TreeName = G2obj.MakeUniqueLabel(TreeLbl,ImgNames)
300    Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=TreeName)
301    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)
302    Imax = np.amax(Image)
303    if G2frame.imageDefault:
304        Data = copy.copy(G2frame.imageDefault)
305        Data['showLines'] = True
306        Data['ring'] = []
307        Data['rings'] = []
308        Data['cutoff'] = 10
309        Data['pixLimit'] = 20
310        Data['edgemin'] = 100000000
311        Data['calibdmin'] = 0.5
312        Data['calibskip'] = 0
313        Data['ellipses'] = []
314        Data['calibrant'] = ''
315        Data['GonioAngles'] = [0.,0.,0.]
316        Data['DetDepthRef'] = False
317    else:
318        Data['type'] = 'PWDR'
319        Data['color'] = 'Paired'
320        Data['tilt'] = 0.0
321        Data['rotation'] = 0.0
322        Data['showLines'] = False
323        Data['ring'] = []
324        Data['rings'] = []
325        Data['cutoff'] = 10
326        Data['pixLimit'] = 20
327        Data['calibdmin'] = 0.5
328        Data['calibskip'] = 0
329        Data['edgemin'] = 100000000
330        Data['ellipses'] = []
331        Data['GonioAngles'] = [0.,0.,0.]
332        Data['DetDepth'] = 0.
333        Data['DetDepthRef'] = False
334        Data['calibrant'] = ''
335        Data['IOtth'] = [2.0,5.0]
336        Data['LRazimuth'] = [0.,180.]
337        Data['azmthOff'] = 0.0
338        Data['outChannels'] = 2500
339        Data['outAzimuths'] = 1
340        Data['centerAzm'] = False
341        Data['fullIntegrate'] = False
342        Data['setRings'] = False
343        Data['background image'] = ['',-1.0]                           
344        Data['dark image'] = ['',-1.0]
345        Data['Flat Bkg'] = 0.0
346    Data['setDefault'] = False
347    Data['range'] = [(0,Imax),[0,Imax]]
348    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Image Controls'),Data)
349    Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(0,Imax),[0,Imax]]}
350    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Masks'),Masks)
351    G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Stress/Strain'),
352        {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
353    G2frame.PatternTree.SetItemPyData(Id,[Npix,imageInfo])
354    G2frame.PickId = Id
355    G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
356    G2frame.Image = Id
357
358def GetImageData(G2frame,imagefile,imageOnly=False,ImageTag=None,FormatName=''):
359    '''Read a single image with an image importer.
360
361    :param wx.Frame G2frame: main GSAS-II Frame and data object.
362    :param str imagefile: name of image file
363    :param bool imageOnly: If True return only the image,
364      otherwise  (default) return more (see below)
365    :param int/str ImageTag: specifies a particular image to be read from a file.
366      First image is read if None (default).
367    :param str formatName: the image reader formatName
368
369    :returns: an image as a numpy array or a list of four items:
370      Comments, Data, Npix and the Image, as selected by imageOnly
371
372    '''
373    # determine which formats are compatible with this file
374    primaryReaders = []
375    secondaryReaders = []
376    for rd in G2frame.ImportImageReaderlist:
377        flag = rd.ExtensionValidator(imagefile)
378        if flag is None: 
379            secondaryReaders.append(rd)
380        elif flag:
381            if not FormatName:
382                primaryReaders.append(rd)
383            elif FormatName == rd.formatName:
384                primaryReaders.append(rd)
385    if len(secondaryReaders) + len(primaryReaders) == 0:
386        print('Error: No matching format for file '+imagefile)
387        raise Exception('No image read')
388    fp = None
389    errorReport = ''
390    if not imagefile:
391        return
392    fp = open(imagefile,'Ur')
393    for rd in primaryReaders+secondaryReaders:
394        rd.ReInitialize() # purge anything from a previous read
395        fp.seek(0)  # rewind
396        rd.errors = "" # clear out any old errors
397        if not rd.ContentsValidator(fp): # rejected on cursory check
398            errorReport += "\n  "+rd.formatName + ' validator error'
399            if rd.errors: 
400                errorReport += ': '+rd.errors
401                continue
402        if imageOnly:
403            ParentFrame = None # prevent GUI access on reread
404        else:
405            ParentFrame = G2frame
406        if GSASIIpath.GetConfigValue('debug'):
407            flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=ImageTag)
408        else:
409            flag = False
410            try:
411                flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=ImageTag)
412            except rd.ImportException as detail:
413                rd.errors += "\n  Read exception: "+str(detail)
414            except Exception as detail:
415                import traceback
416                rd.errors += "\n  Unhandled read exception: "+str(detail)
417                rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
418        if flag: # this read succeeded
419            if rd.Image is None:
420                raise Exception('No image read. Strange!')
421            if GSASIIpath.GetConfigValue('Transpose'):
422                print 'Transposing Image!'
423                rd.Image = rd.Image.T
424            #rd.readfilename = imagefile
425            if imageOnly:
426                return rd.Image
427            else:
428                return rd.Comments,rd.Data,rd.Npix,rd.Image
429    else:
430        print('Error reading file '+imagefile)
431        print('Error messages(s)\n'+errorReport)
432        raise Exception('No image read')   
433
434def ReadImages(G2frame,imagefile):
435    '''Read one or more images from a file and put them into the Tree
436    using image importers. Called only in :meth:`AutoIntFrame.OnTimerLoop`.
437
438    :param wx.Frame G2frame: main GSAS-II Frame and data object.
439    :param str imagefile: name of image file
440
441    :returns: a list of the id's of the IMG tree items created
442    '''
443    # determine which formats are compatible with this file
444    primaryReaders = []
445    secondaryReaders = []
446    for rd in G2frame.ImportImageReaderlist:
447        flag = rd.ExtensionValidator(imagefile)
448        if flag is None:
449            secondaryReaders.append(rd)
450        elif flag:
451            primaryReaders.append(rd)
452    if len(secondaryReaders) + len(primaryReaders) == 0:
453        print('Error: No matching format for file '+imagefile)
454        raise Exception('No image read')
455    errorReport = ''
456    fp = open(imagefile,'Ur')
457    rdbuffer = {} # create temporary storage for file reader
458    for rd in primaryReaders+secondaryReaders:
459        rd.ReInitialize() # purge anything from a previous read
460        fp.seek(0)  # rewind
461        rd.errors = "" # clear out any old errors
462        if not rd.ContentsValidator(fp): # rejected on cursory check
463            errorReport += "\n  "+rd.formatName + ' validator error'
464            if rd.errors: 
465                errorReport += ': '+rd.errors
466                continue
467        ParentFrame = G2frame
468        block = 0
469        repeat = True
470        CreatedIMGitems = []
471        while repeat: # loop if the reader asks for another pass on the file
472            block += 1
473            repeat = False
474            if GSASIIpath.GetConfigValue('debug'):
475                flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=block,Buffer=rdbuffer)
476            else:
477                flag = False
478                try:
479                    flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=block,Buffer=rdbuffer)
480                except rd.ImportException as detail:
481                    rd.errors += "\n  Read exception: "+str(detail)
482                except Exception as detail:
483                    import traceback
484                    rd.errors += "\n  Unhandled read exception: "+str(detail)
485                    rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
486            if flag: # this read succeeded
487                if rd.Image is None:
488                    raise Exception('No image read. Strange!')
489                if GSASIIpath.GetConfigValue('Transpose'):
490                    print 'Transposing Image!'
491                    rd.Image = rd.Image.T
492                rd.Data['ImageTag'] = rd.repeatcount
493                LoadImage2Tree(imagefile,G2frame,rd.Comments,rd.Data,rd.Npix,rd.Image)
494                repeat = rd.repeat
495            CreatedIMGitems.append(G2frame.Image)
496        if CreatedIMGitems: return CreatedIMGitems
497    else:
498        print('Error reading file '+imagefile)
499        print('Error messages(s)\n'+errorReport)
500        return []
501        #raise Exception('No image read')   
502
503def SaveMultipleImg(G2frame):
504    if not G2frame.PatternTree.GetCount():
505        print 'no images!'
506        return
507    choices = G2gd.GetPatternTreeDataNames(G2frame,['IMG ',])
508    if len(choices) == 1:
509        names = choices
510    else:
511        dlg = G2G.G2MultiChoiceDialog(G2frame,'Stress/Strain fitting','Select images to fit:',choices)
512        dlg.SetSelections([])
513        names = []
514        if dlg.ShowModal() == wx.ID_OK:
515            names = [choices[sel] for sel in dlg.GetSelections()]
516        dlg.Destroy()
517    if not names: return
518    for name in names:
519        Id = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, name)
520        Npix,imagefile,imagetag = G2frame.PatternTree.GetImageLoc(Id)
521        imroot = os.path.splitext(imagefile)[0]
522        if imagetag:
523            imroot += '_' + str(imagetag)
524        Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Image Controls'))
525        print('Writing '+imroot+'.imctrl')
526        File = open(imroot+'.imctrl','w')
527        keys = ['type','wavelength','calibrant','distance','center',
528                    'tilt','rotation','azmthOff','fullIntegrate','LRazimuth',
529                    'IOtth','outChannels','outAzimuths','invert_x','invert_y','DetDepth',
530                    'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
531                    'binType','SampleShape','PolaVal','SampleAbs','dark image','background image']
532        for key in keys:
533            if key not in Data: continue    #uncalibrated!
534            File.write(key+':'+str(Data[key])+'\n')
535        File.close()
536        mask = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Masks'))
537        G2imG.CleanupMasks(mask)
538        print('Writing '+imroot+'.immask')
539        File = open(imroot+'.immask','w')
540        for key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']:
541            File.write(key+':'+str(mask[key])+'\n')
542        File.close()
543       
544def PutG2Image(filename,Comments,Data,Npix,image):
545    'Write an image as a python pickle - might be better as an .edf file?'
546    File = open(filename,'wb')
547    cPickle.dump([Comments,Data,Npix,image],File,1)
548    File.close()
549    return
550   
551# should get moved to importer when ready to test
552def GetEdfData(filename,imageOnly=False):   
553    'Read European detector data edf file'
554    if not imageOnly:
555        print 'Read European detector data edf file: ',filename
556    File = open(filename,'rb')
557    fileSize = os.stat(filename).st_size
558    head = File.read(3072)
559    lines = head.split('\n')
560    sizexy = [0,0]
561    pixSize = [154,154]     #Pixium4700?
562    cent = [0,0]
563    wave = 1.54187  #default <CuKa>
564    dist = 1000.
565    head = ['European detector data',]
566    for line in lines:
567        line = line.replace(';',' ').strip()
568        fields = line.split()
569        if 'Dim_1' in line:
570            sizexy[0] = int(fields[2])
571        elif 'Dim_2' in line:
572            sizexy[1] = int(fields[2])
573        elif 'DataType' in line:
574            dType = fields[2]
575        elif 'wavelength' in line:
576            wave = float(fields[2])
577        elif 'Size' in line:
578            imSize = int(fields[2])
579#        elif 'DataType' in lines:
580#            dType = fields[2]
581        elif 'pixel_size_x' in line:
582            pixSize[0] = float(fields[2])
583        elif 'pixel_size_y' in line:
584            pixSize[1] = float(fields[2])
585        elif 'beam_center_x' in line:
586            cent[0] = float(fields[2])
587        elif 'beam_center_y' in line:
588            cent[1] = float(fields[2])
589        elif 'refined_distance' in line:
590            dist = float(fields[2])
591        if line:
592            head.append(line)
593        else:   #blank line at end of header
594            break 
595    File.seek(fileSize-imSize)
596    if dType == 'UnsignedShort':       
597        image = np.array(np.frombuffer(File.read(imSize),dtype=np.int16),dtype=np.int32)
598    else:
599        image = np.array(np.frombuffer(File.read(imSize),dtype=np.int32),dtype=np.int32)
600    image = np.reshape(image,(sizexy[1],sizexy[0]))
601    data = {'pixelSize':pixSize,'wavelength':wave,'distance':dist,'center':cent,'size':sizexy}
602    Npix = sizexy[0]*sizexy[1]
603    File.close()   
604    if imageOnly:
605        return image
606    else:
607        return head,data,Npix,image
608       
609# should get moved to importer when ready to test
610def GetRigaku(filename,imageOnly=False):
611    'Read Rigaku R-Axis IV image file'
612    import array as ar
613    if not imageOnly:
614        print 'Read Rigaku R-Axis IV file: ',filename   
615    File = open(filename,'rb')
616    fileSize = os.stat(filename).st_size
617    Npix = (fileSize-6000)/2
618    File.read(6000)
619    head = ['Rigaku R-Axis IV detector data',]
620    image = np.array(ar.array('H',File.read(fileSize-6000)),dtype=np.int32)
621    print fileSize,image.shape
622    print head
623    if Npix == 9000000:
624        sizexy = [3000,3000]
625        pixSize = [100.,100.]       
626    elif Npix == 2250000:
627        sizexy = [1500,1500]
628        pixSize = [200.,200.]
629    else:
630        sizexy = [6000,6000]
631        pixSize = [50.,50.] 
632    image = np.reshape(image,(sizexy[1],sizexy[0]))       
633    data = {'pixelSize':pixSize,'wavelength':1.5428,'distance':250.0,'center':[150.,150.],'size':sizexy} 
634    File.close()   
635    if imageOnly:
636        return image
637    else:
638        return head,data,Npix,image
639   
640# should get moved to importer when ready to test       
641def GetImgData(filename,imageOnly=False):
642    'Read an ADSC image file'
643    import array as ar
644    if not imageOnly:
645        print 'Read ADSC img file: ',filename
646    File = open(filename,'rb')
647    head = File.read(511)
648    lines = head.split('\n')
649    head = []
650    center = [0,0]
651    for line in lines[1:-2]:
652        line = line.strip()[:-1]
653        if line:
654            if 'SIZE1' in line:
655                size = int(line.split('=')[1])
656                Npix = size*size
657            elif 'WAVELENGTH' in line:
658                wave = float(line.split('=')[1])
659            elif 'BIN' in line:
660                if line.split('=')[1] == '2x2':
661                    pixel=(102,102)
662                else:
663                    pixel = (51,51)
664            elif 'DISTANCE' in line:
665                distance = float(line.split('=')[1])
666            elif 'CENTER_X' in line:
667                center[0] = float(line.split('=')[1])
668            elif 'CENTER_Y' in line:
669                center[1] = float(line.split('=')[1])
670            head.append(line)
671    data = {'pixelSize':pixel,'wavelength':wave,'distance':distance,'center':center,'size':[size,size]}
672    image = []
673    pos = 512
674    File.seek(pos)
675    image = np.array(ar.array('H',File.read(2*Npix)),dtype=np.int32)
676    image = np.reshape(image,(size,size))
677#    image = np.zeros(shape=(size,size),dtype=np.int32)   
678#    while row < size:
679#        File.seek(pos)
680#        line = ar.array('H',File.read(2*size))
681#        image[row] = np.asarray(line)
682#        row += 1
683#        pos += 2*size
684    File.close()
685    if imageOnly:
686        return image
687    else:
688        return lines[1:-2],data,Npix,image
689       
690# should get moved to importer when ready to test
691def GetMAR345Data(filename,imageOnly=False):
692    'Read a MAR-345 image plate image'
693    try:
694        import pack_f as pf
695    except:
696        msg = wx.MessageDialog(None, message="Unable to load the GSAS MAR image decompression, pack_f",
697                               caption="Import Error",
698                               style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
699        msg.ShowModal()
700        return None,None,None,None
701
702    if not imageOnly:
703        print 'Read Mar345 file: ',filename
704    File = open(filename,'rb')
705    head = File.read(4095)
706    lines = head[128:].split('\n')
707    head = []
708    for line in lines:
709        line = line.strip()
710        if 'PIXEL' in line:
711            values = line.split()
712            pixel = (int(values[2]),int(values[4]))     #in microns
713        elif 'WAVELENGTH' in line:
714            wave = float(line.split()[1])
715        elif 'DISTANCE' in line:
716            distance = float(line.split()[1])           #in mm
717            if not distance:
718                distance = 500.
719        elif 'CENTER' in line:
720            values = line.split()
721            center = [float(values[2])/10.,float(values[4])/10.]    #make in mm from pixels
722        if line: 
723            head.append(line)
724    data = {'pixelSize':pixel,'wavelength':wave,'distance':distance,'center':center}
725    for line in head:
726        if 'FORMAT' in line[0:6]:
727            items = line.split()
728            sizex = int(items[1])
729            Npix = int(items[3])
730            sizey = int(Npix/sizex)
731    pos = 4096
732    data['size'] = [sizex,sizey]
733    File.seek(pos)
734    line = File.read(8)
735    while 'CCP4' not in line:       #get past overflow list for now
736        line = File.read(8)
737        pos += 8
738    pos += 37
739    File.seek(pos)
740    raw = File.read()
741    File.close()
742    image = np.zeros(shape=(sizex,sizey),dtype=np.int32)
743   
744    image = np.flipud(pf.pack_f(len(raw),raw,sizex,sizey,image).T)  #transpose to get it right way around & flip
745    if imageOnly:
746        return image
747    else:
748        return head,data,Npix,image
749       
750def ProjFileOpen(G2frame,showProvenance=True):
751    'Read a GSAS-II project file and load into the G2 data tree'
752    if not os.path.exists(G2frame.GSASprojectfile):
753        print ('\n*** Error attempt to open project file that does not exist:\n   '+
754               str(G2frame.GSASprojectfile))
755        return
756    LastSavedUsing = None
757    file = open(G2frame.GSASprojectfile,'rb')
758    if showProvenance: print 'loading from file: ',G2frame.GSASprojectfile
759    G2frame.SetTitle("GSAS-II data tree: "+
760                     os.path.split(G2frame.GSASprojectfile)[1])
761    wx.BeginBusyCursor()
762    try:
763        while True:
764            try:
765                data = cPickle.load(file)
766            except EOFError:
767                break
768            datum = data[0]
769           
770            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=datum[0])
771            if datum[0].startswith('PWDR'):               
772                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
773                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
774                G2frame.PatternTree.SetItemPyData(Id,datum[1][:3])  #temp. trim off junk (patch?)
775            elif datum[0].startswith('HKLF'): 
776                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
777                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
778                G2frame.PatternTree.SetItemPyData(Id,datum[1])
779            else:
780                G2frame.PatternTree.SetItemPyData(Id,datum[1])             
781                if datum[0] == 'Controls' and 'LastSavedUsing' in datum[1]:
782                    LastSavedUsing = datum[1]['LastSavedUsing']
783                if datum[0] == 'Controls' and 'PythonVersions' in datum[1] and GSASIIpath.GetConfigValue('debug') and showProvenance:
784                    print('Packages used to create .GPX file:')
785                    if 'dict' in str(type(datum[1]['PythonVersions'])):  #patch
786                        for p in sorted(datum[1]['PythonVersions'],key=lambda s: s.lower()):
787                            print({:<14s}: {:s}".format(p[0],p[1]))
788                    else:
789                        for p in datum[1]['PythonVersions']:
790                            print({:<12s} {:s}".format(p[0]+':',p[1]))
791            oldPDF = False
792            for datus in data[1:]:
793#patch - 1/23/17 PDF cleanup
794                if datus[0][:4] in ['I(Q)','S(Q)','F(Q)','G(R)']:
795                    oldPDF = True
796                    data[1][1][datus[0][:4]] = copy.deepcopy(datus[1][:2])
797                    continue
798#end PDF cleanup
799                sub = G2frame.PatternTree.AppendItem(Id,datus[0])
800#patch
801                if datus[0] == 'Instrument Parameters' and len(datus[1]) == 1:
802                    if datum[0].startswith('PWDR'):
803                        datus[1] = [dict(zip(datus[1][3],zip(datus[1][0],datus[1][1],datus[1][2]))),{}]
804                    else:
805                        datus[1] = [dict(zip(datus[1][2],zip(datus[1][0],datus[1][1]))),{}]
806                    for item in datus[1][0]:               #zip makes tuples - now make lists!
807                        datus[1][0][item] = list(datus[1][0][item])
808#end patch
809                G2frame.PatternTree.SetItemPyData(sub,datus[1])
810            if 'PDF ' in datum[0][:4] and oldPDF:
811                sub = G2frame.PatternTree.AppendItem(Id,'PDF Peaks')
812                G2frame.PatternTree.SetItemPyData(sub,{'Limits':[1.,5.],'Background':[2,[0.,-0.2*np.pi],False],'Peaks':[]})
813            if datum[0].startswith('IMG'):                   #retrieve image default flag & data if set
814                Data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Image Controls'))
815                if Data['setDefault']:
816                    G2frame.imageDefault = Data               
817        file.close()
818        if LastSavedUsing:
819            print('GPX load successful. Last saved with GSAS-II revision '+LastSavedUsing)
820        else:
821            print('project load successful')
822        G2frame.NewPlot = True
823    except:
824        msg = wx.MessageDialog(G2frame,message="Error reading file "+
825            str(G2frame.GSASprojectfile)+". This is not a GSAS-II .gpx file",
826            caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
827        msg.ShowModal()
828    finally:
829        wx.EndBusyCursor()
830        G2frame.Status.SetStatusText('Mouse RB click item to refresh/raise; RB drag/drop to reorder')
831   
832def ProjFileSave(G2frame):
833    'Save a GSAS-II project file'
834    if not G2frame.PatternTree.IsEmpty():
835        file = open(G2frame.GSASprojectfile,'wb')
836        print 'save to file: ',G2frame.GSASprojectfile
837        # stick the file name into the tree and version info into tree so they are saved.
838        # (Controls should always be created at this point)
839        try:
840            Controls = G2frame.PatternTree.GetItemPyData(
841                G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
842            Controls['LastSavedAs'] = os.path.abspath(G2frame.GSASprojectfile)
843            Controls['LastSavedUsing'] = str(GSASIIpath.GetVersionNumber())
844            Controls['PythonVersions'] = G2frame.PackageVersions
845        except:
846            pass
847        wx.BeginBusyCursor()
848        try:
849            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
850            while item:
851                data = []
852                name = G2frame.PatternTree.GetItemText(item)
853                data.append([name,G2frame.PatternTree.GetItemPyData(item)])
854                item2, cookie2 = G2frame.PatternTree.GetFirstChild(item)
855                while item2:
856                    name = G2frame.PatternTree.GetItemText(item2)
857                    data.append([name,G2frame.PatternTree.GetItemPyData(item2)])
858                    item2, cookie2 = G2frame.PatternTree.GetNextChild(item, cookie2)                           
859                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                           
860                cPickle.dump(data,file,1)
861            file.close()
862            pth = os.path.split(os.path.abspath(G2frame.GSASprojectfile))[0]
863            if GSASIIpath.GetConfigValue('Save_paths'): G2G.SaveGPXdirectory(pth)
864            G2frame.LastGPXdir = pth
865        finally:
866            wx.EndBusyCursor()
867        print('project save successful')
868
869def SaveIntegration(G2frame,PickId,data,Overwrite=False):
870    'Save image integration results as powder pattern(s)'
871    azms = G2frame.Integrate[1]
872    X = G2frame.Integrate[2][:-1]
873    N = len(X)
874    Id = G2frame.PatternTree.GetItemParent(PickId)
875    name = G2frame.PatternTree.GetItemText(Id)
876    name = name.replace('IMG ',data['type']+' ')
877    Comments = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Comments'))
878    if 'PWDR' in name:
879        names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
880        codes = [0 for i in range(11)]
881    elif 'SASD' in name:
882        names = ['Type','Lam','Zero','Azimuth'] 
883        codes = [0 for i in range(4)]
884        X = 4.*np.pi*npsind(X/2.)/data['wavelength']    #convert to q
885    Xminmax = [X[0],X[-1]]
886    Azms = []
887    dazm = 0.
888    if data['fullIntegrate'] and data['outAzimuths'] == 1:
889        Azms = [45.0,]                              #a poor man's average?
890    else:
891        for i,azm in enumerate(azms[:-1]):
892            if azm > 360. and azms[i+1] > 360.:
893                Azms.append(G2img.meanAzm(azm%360.,azms[i+1]%360.))
894            else:   
895                Azms.append(G2img.meanAzm(azm,azms[i+1]))
896        dazm = np.min(np.abs(np.diff(azms)))/2.
897    G2frame.IntgOutList = []
898    for i,azm in enumerate(azms[:-1]):
899        Aname = name+" Azm= %.2f"%((azm+dazm)%360.)
900        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
901        # if Overwrite delete any duplicate
902        if Overwrite and G2gd.GetPatternTreeItemId(G2frame,G2frame.root,Aname):
903            print('Replacing '+Aname)
904            item = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,Aname)
905            G2frame.PatternTree.Delete(item)
906        else:
907            nOcc = 0
908            while item:
909                Name = G2frame.PatternTree.GetItemText(item)
910                if Aname in Name:
911                    nOcc += 1
912                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
913            if nOcc:
914                Aname += '(%d)'%(nOcc)
915        Sample = G2pdG.SetDefaultSample()       #set as Debye-Scherrer
916        Sample['Gonio. radius'] = data['distance']
917        Sample['Omega'] = data['GonioAngles'][0]
918        Sample['Chi'] = data['GonioAngles'][1]
919        Sample['Phi'] = data['GonioAngles'][2]
920        Sample['Azimuth'] = (azm+dazm)%360.    #put here as bin center
921        polariz = 0.99    #set default polarization for synchrotron radiation!
922        for item in Comments:
923            if 'polariz' in item:
924                try:
925                    polariz = float(item.split('=')[1])
926                except:
927                    polariz = 0.99
928        if 'PWDR' in Aname:
929            parms = ['PXC',data['wavelength'],0.0,polariz,1.0,-0.10,0.4,0.30,1.0,0.0001,Azms[i]]
930        elif 'SASD' in Aname:
931            Sample['Trans'] = data['SampleAbs'][0]
932            parms = ['LXC',data['wavelength'],0.0,Azms[i]]
933        Y = G2frame.Integrate[0][i]
934        Ymin = np.min(Y)
935        Ymax = np.max(Y)
936        W = np.where(Y>0.,1./Y,1.e-6)                    #probably not true
937        Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text=Aname)
938        G2frame.IntgOutList.append(Id)
939        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Comments'),Comments)                   
940        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
941        if 'PWDR' in Aname:
942            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0],
943                {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
944        inst = [dict(zip(names,zip(parms,parms,codes))),{}]
945        for item in inst[0]:
946            inst[0][item] = list(inst[0][item])
947        G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Instrument Parameters'),inst)
948        if 'PWDR' in Aname:
949            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
950            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Peak List'),{'sigDict':{},'peaks':[]})
951            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Index Peak List'),[[],[]])
952            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Unit Cells List'),[])
953            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Reflection Lists'),{})
954        elif 'SASD' in Aname:             
955            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Substances'),G2pdG.SetDefaultSubstances())
956            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Sample Parameters'),Sample)
957            G2frame.PatternTree.SetItemPyData(G2frame.PatternTree.AppendItem(Id,text='Models'),G2pdG.SetDefaultSASDModel())
958        valuesdict = {
959            'wtFactor':1.0,
960            'Dummy':False,
961            'ranId':ran.randint(0,sys.maxint),
962            'Offset':[0.0,0.0],'delOffset':0.02*Ymax,'refOffset':-0.1*Ymax,'refDelt':0.1*Ymax,
963            'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
964            }
965        G2frame.PatternTree.SetItemPyData(
966            Id,[valuesdict,
967                [np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
968    return Id       #last powder pattern generated
969   
970def XYsave(G2frame,XY,labelX='X',labelY='Y',names=None):
971    'Save XY table data'
972    pth = G2G.GetExportPath(G2frame)
973    dlg = wx.FileDialog(
974        G2frame, 'Enter csv filename for XY table', pth, '',
975        'XY table file (*.csv)|*.csv',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
976    try:
977        if dlg.ShowModal() == wx.ID_OK:
978            filename = dlg.GetPath()
979            filename = os.path.splitext(filename)[0]+'.csv'
980            File = open(filename,'w')
981        else:
982            filename = None
983    finally:
984        dlg.Destroy()
985    if not filename:
986        return
987    for i in range(len(XY)):
988        if names != None:
989            header = '%s,%s(%s)\n'%(labelX,labelY,names[i])
990        else:
991            header = '%s,%s(%d)\n'%(labelX,labelY,i)
992        File.write(header)
993        for x,y in XY[i].T:
994            File.write('%.3f,%.3f\n'%(x,y))   
995    File.close()
996    print ' XY data saved to: ',filename
997           
998def PDFSave(G2frame,exports,PDFsaves):
999    'Save a PDF I(Q), S(Q), F(Q) and G(r)  in column formats'
1000    import scipy.interpolate as scintp
1001    for export in exports:
1002        PickId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, export)
1003        PDFControls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, PickId,'PDF Controls'))
1004        if PDFsaves[0]:     #I(Q)
1005            iqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.iq')
1006            iqdata = PDFControls['I(Q)'][0]
1007            iqfxn = scintp.interp1d(iqdata[0],iqdata[1],kind='linear')
1008            iqfile = open(iqfilename,'w')
1009            iqfile.write('#T I(Q) %s\n'%(export))
1010            iqfile.write('#L Q     I(Q)\n')
1011            qnew = np.arange(iqdata[0][0],iqdata[0][-1],0.005)
1012            iqnew = zip(qnew,iqfxn(qnew))
1013            for q,iq in iqnew:
1014                iqfile.write("%15.6g %15.6g\n" % (q,iq))
1015            iqfile.close()
1016            print ' I(Q) saved to: ',iqfilename
1017           
1018        if PDFsaves[1]:     #S(Q)
1019            sqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.sq')
1020            sqdata = PDFControls['S(Q)'][1]
1021            sqfxn = scintp.interp1d(sqdata[0],sqdata[1],kind='linear')
1022            sqfile = open(sqfilename,'w')
1023            sqfile.write('#T S(Q) %s\n'%(export))
1024            sqfile.write('#L Q     S(Q)\n')
1025            qnew = np.arange(sqdata[0][0],sqdata[0][-1],0.005)
1026            sqnew = zip(qnew,sqfxn(qnew))
1027            for q,sq in sqnew:
1028                sqfile.write("%15.6g %15.6g\n" % (q,sq))
1029            sqfile.close()
1030            print ' S(Q) saved to: ',sqfilename
1031           
1032        if PDFsaves[2]:     #F(Q)
1033            fqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.fq')
1034            fqdata = PDFControls['F(Q)'][1]
1035            fqfxn = scintp.interp1d(fqdata[0],fqdata[1],kind='linear')
1036            fqfile = open(sqfilename,'w')
1037            fqfile.write('#T F(Q) %s\n'%(export))
1038            fqfile.write('#L Q     F(Q)\n')
1039            qnew = np.arange(sqdata[0][0],sqdata[0][-1],0.005)
1040            fqnew = zip(qnew,fqfxn(qnew))
1041            for q,fq in fqnew:
1042                fqfile.write("%15.6g %15.6g\n" % (q,fq))
1043            fqfile.close()
1044            print ' F(Q) saved to: ',fqfilename
1045           
1046        if PDFsaves[3]:     #G(R)
1047            grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
1048            grdata = PDFControls['G(R)'][1]
1049            grfxn = scintp.interp1d(grdata[0],grdata[1],kind='linear')
1050            grfile = open(grfilename,'w')
1051            grfile.write('#T G(R) %s\n'%(export))
1052            grfile.write('#L R     G(R)\n')
1053            rnew = np.arange(grdata[0][0],grdata[0][-1],0.010)
1054            grnew = zip(rnew,grfxn(rnew))
1055            for r,gr in grnew:
1056                grfile.write("%15.6g %15.6g\n" % (r,gr))
1057            grfile.close()
1058            print ' G(R) saved to: ',grfilename
1059       
1060        if PDFsaves[4]: #pdfGUI file for G(R)
1061            pId = G2gd.GetPatternTreeItemId(G2frame, G2frame.root, 'PWDR'+export[4:])
1062            Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, pId,'Instrument Parameters'))[0]
1063            Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame, pId,'Limits'))
1064            grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
1065            grdata = PDFControls['G(R)'][1]
1066            qdata = PDFControls['I(Q)'][1][0]
1067            grfxn = scintp.interp1d(grdata[0],grdata[1],kind='linear')
1068            grfile = open(grfilename,'w')
1069            rnew = np.arange(grdata[0][0],grdata[0][-1],0.010)
1070            grnew = zip(rnew,grfxn(rnew))
1071
1072            grfile.write('[DEFAULT]\n')
1073            grfile.write('\n')
1074            grfile.write('version = GSAS-II-v'+str(GSASIIpath.GetVersionNumber())+'\n')
1075            grfile.write('\n')
1076            grfile.write('# input and output specifications\n')
1077            grfile.write('dataformat = Qnm\n')
1078            grfile.write('inputfile = %s\n'%(PDFControls['Sample']['Name']))
1079            grfile.write('backgroundfile = %s\n'%(PDFControls['Sample Bkg.']['Name']))
1080            grfile.write('outputtype = gr\n')
1081            grfile.write('\n')
1082            grfile.write('# PDF calculation setup\n')
1083            if 'x' in Inst['Type']:
1084                grfile.write('mode = %s\n'%('xray'))
1085            elif 'N' in Inst['Type']:
1086                grfile.write('mode = %s\n'%('neutron'))
1087            wave = G2mth.getMeanWave(Inst)
1088            grfile.write('wavelength = %.5f\n'%(wave))
1089            formula = ''
1090            for el in PDFControls['ElList']:
1091                formula += el
1092                num = PDFControls['ElList'][el]['FormulaNo']
1093                if num == round(num):
1094                    formula += '%d'%(int(num))
1095                else:
1096                    formula += '%.2f'%(num)
1097            grfile.write('composition = %s\n'%(formula))
1098            grfile.write('bgscale = %.3f\n'%(-PDFControls['Sample Bkg.']['Mult']))
1099            highQ = 2.*np.pi/G2lat.Pos2dsp(Inst,Limits[1][1])
1100            grfile.write('qmaxinst = %.2f\n'%(highQ))
1101            grfile.write('qmin = %.5f\n'%(qdata[0]))
1102            grfile.write('qmax = %.4f\n'%(qdata[-1]))
1103            grfile.write('rmin = %.2f\n'%(PDFControls['Rmin']))
1104            grfile.write('rmax = %.2f\n'%(PDFControls['Rmax']))
1105            grfile.write('rstep = 0.01\n')
1106           
1107           
1108            grfile.write('\n')
1109            grfile.write('# End of config '+63*'-')
1110            grfile.write('\n')
1111            grfile.write('#### start data\n')
1112            grfile.write('#S 1\n')
1113            grfile.write('#L r($\AA$)  G($\AA^{-2}$)\n')           
1114            for r,gr in grnew:
1115                grfile.write("%15.2F %15.6F\n" % (r,gr))
1116            grfile.close()
1117            print ' G(R) saved to: ',grfilename
1118           
1119           
1120           
1121   
1122def PeakListSave(G2frame,file,peaks):
1123    'Save powder peaks to a data file'
1124    print 'save peak list to file: ',G2frame.peaklistfile
1125    if not peaks:
1126        dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
1127        try:
1128            dlg.ShowModal()
1129        finally:
1130            dlg.Destroy()
1131        return
1132    for peak in peaks:
1133        file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
1134            (peak[0],peak[2],peak[4],peak[6]))
1135    print 'peak list saved'
1136             
1137def IndexPeakListSave(G2frame,peaks):
1138    'Save powder peaks from the indexing list'
1139    file = open(G2frame.peaklistfile,'wa')
1140    print 'save index peak list to file: ',G2frame.peaklistfile
1141    wx.BeginBusyCursor()
1142    try:
1143        if not peaks:
1144            dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
1145            try:
1146                dlg.ShowModal()
1147            finally:
1148                dlg.Destroy()
1149            return
1150        for peak in peaks:
1151            file.write("%12.6f\n" % (peak[7]))
1152        file.close()
1153    finally:
1154        wx.EndBusyCursor()
1155    print 'index peak list saved'
1156   
1157def SetNewPhase(Name='New Phase',SGData=None,cell=None,Super=None):
1158    '''Create a new phase dict with default values for various parameters
1159
1160    :param str Name: Name for new Phase
1161
1162    :param dict SGData: space group data from :func:`GSASIIspc:SpcGroup`;
1163      defaults to data for P 1
1164
1165    :param list cell: unit cell parameter list; defaults to
1166      [1.0,1.0,1.0,90.,90,90.,1.]
1167
1168    '''
1169    if SGData is None: SGData = G2spc.SpcGroup('P 1')[1]
1170    if cell is None: cell=[1.0,1.0,1.0,90.,90,90.,1.]
1171    phaseData = {
1172        'ranId':ran.randint(0,sys.maxint),
1173        'General':{
1174            'Name':Name,
1175            'Type':'nuclear',
1176            'Modulated':False,
1177            'AtomPtrs':[3,1,7,9],
1178            'SGData':SGData,
1179            'Cell':[False,]+cell,
1180            'Pawley dmin':1.0,
1181            'Data plot type':'None',
1182            'SH Texture':{
1183                'Order':0,
1184                'Model':'cylindrical',
1185                'Sample omega':[False,0.0],
1186                'Sample chi':[False,0.0],
1187                'Sample phi':[False,0.0],
1188                'SH Coeff':[False,{}],
1189                'SHShow':False,
1190                'PFhkl':[0,0,1],
1191                'PFxyz':[0,0,1],
1192                'PlotType':'Pole figure',
1193                'Penalty':[['',],0.1,False,1.0]}},
1194        'Atoms':[],
1195        'Drawing':{},
1196        'Histograms':{},
1197        'Pawley ref':[],
1198        'RBModels':{},
1199        }
1200    if Super and Super.get('Use',False):
1201        phaseData['General'].update({'Modulated':True,'Super':True,'SuperSg':Super['ssSymb']})
1202        phaseData['General']['SSGData'] = G2spc.SSpcGroup(SGData,Super['ssSymb'])
1203        phaseData['General']['SuperVec'] = [Super['ModVec'],False,Super['maxH']]
1204
1205    return phaseData
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    Also see GSASIIctrls
1218    '''
1219    def __init__(self,choicelist,headinglist,
1220                 head='Select options',
1221                 title='Please select from options below',
1222                 parent=None):
1223        self.chosen = []
1224        wx.Dialog.__init__(
1225            self,parent,wx.ID_ANY,head, 
1226            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
1227        panel = wx.Panel(self)
1228        mainSizer = wx.BoxSizer(wx.VERTICAL)
1229        mainSizer.Add((10,10),1)
1230        topLabl = wx.StaticText(panel,wx.ID_ANY,title)
1231        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.CENTER,10)
1232        self.ChItems = []
1233        for choice,lbl in zip(choicelist,headinglist):
1234            mainSizer.Add((10,10),1)
1235            self.chosen.append(0)
1236            topLabl = wx.StaticText(panel,wx.ID_ANY,' '+lbl)
1237            mainSizer.Add(topLabl,0,wx.ALIGN_LEFT,10)
1238            self.ChItems.append(wx.Choice(self, wx.ID_ANY, (100, 50), choices = choice))
1239            mainSizer.Add(self.ChItems[-1],0,wx.ALIGN_CENTER,10)
1240
1241        OkBtn = wx.Button(panel,-1,"Ok")
1242        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
1243        cancelBtn = wx.Button(panel,-1,"Cancel")
1244        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
1245        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
1246        btnSizer.Add((20,20),1)
1247        btnSizer.Add(OkBtn)
1248        btnSizer.Add((20,20),1)
1249        btnSizer.Add(cancelBtn)
1250        btnSizer.Add((20,20),1)
1251        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1252        panel.SetSizer(mainSizer)
1253        panel.Fit()
1254        self.Fit()
1255       
1256    def OnOk(self,event):
1257        parent = self.GetParent()
1258        if parent is not None: parent.Raise()
1259        # save the results from the choice widgets
1260        self.chosen = []
1261        for w in self.ChItems:
1262            self.chosen.append(w.GetSelection())
1263        self.EndModal(wx.ID_OK)             
1264           
1265    def OnCancel(self,event):
1266        parent = self.GetParent()
1267        if parent is not None: parent.Raise()
1268        self.chosen = []
1269        self.EndModal(wx.ID_CANCEL)             
1270           
1271def ExtractFileFromZip(filename, selection=None, confirmread=True,
1272                       confirmoverwrite=True, parent=None,
1273                       multipleselect=False):
1274    '''If the filename is a zip file, extract a file from that
1275    archive.
1276
1277    :param list Selection: used to predefine the name of the file
1278      to be extracted. Filename case and zip directory name are
1279      ignored in selection; the first matching file is used.
1280
1281    :param bool confirmread: if True asks the user to confirm before expanding
1282      the only file in a zip
1283
1284    :param bool confirmoverwrite: if True asks the user to confirm
1285      before overwriting if the extracted file already exists
1286
1287    :param bool multipleselect: if True allows more than one zip
1288      file to be extracted, a list of file(s) is returned.
1289      If only one file is present, do not ask which one, otherwise
1290      offer a list of choices (unless selection is used).
1291   
1292    :returns: the name of the file that has been created or a
1293      list of files (see multipleselect)
1294
1295    If the file is not a zipfile, return the name of the input file.
1296    If the zipfile is empty or no file has been selected, return None
1297    '''
1298    import zipfile # do this now, since we can save startup time by doing this only on need
1299    import shutil
1300    zloc = os.path.split(filename)[0]
1301    if not zipfile.is_zipfile(filename):
1302        #print("not zip")
1303        return filename
1304
1305    z = zipfile.ZipFile(filename,'r')
1306    zinfo = z.infolist()
1307
1308    if len(zinfo) == 0:
1309        #print('Zip has no files!')
1310        zlist = [-1]
1311    if selection:
1312        choices = [os.path.split(i.filename)[1].lower() for i in zinfo]
1313        if selection.lower() in choices:
1314            zlist = [choices.index(selection.lower())]
1315        else:
1316            print('debug: file '+str(selection)+' was not found in '+str(filename))
1317            zlist = [-1]
1318    elif len(zinfo) == 1 and confirmread:
1319        result = wx.ID_NO
1320        dlg = wx.MessageDialog(
1321            parent,
1322            'Is file '+str(zinfo[0].filename)+
1323            ' what you want to extract from '+
1324            str(os.path.split(filename)[1])+'?',
1325            'Confirm file', 
1326            wx.YES_NO | wx.ICON_QUESTION)
1327        try:
1328            result = dlg.ShowModal()
1329        finally:
1330            dlg.Destroy()
1331        if result == wx.ID_NO:
1332            zlist = [-1]
1333        else:
1334            zlist = [0]
1335    elif len(zinfo) == 1:
1336        zlist = [0]
1337    elif multipleselect:
1338        # select one or more from a from list
1339        choices = [i.filename for i in zinfo]
1340        dlg = G2G.G2MultiChoiceDialog(parent,'Select file(s) to extract from zip file '+str(filename),
1341            'Choose file(s)',choices)
1342        if dlg.ShowModal() == wx.ID_OK:
1343            zlist = dlg.GetSelections()
1344        else:
1345            zlist = []
1346        dlg.Destroy()
1347    else:
1348        # select one from a from list
1349        choices = [i.filename for i in zinfo]
1350        dlg = wx.SingleChoiceDialog(parent,
1351            'Select file to extract from zip file'+str(filename),'Choose file',
1352            choices,)
1353        if dlg.ShowModal() == wx.ID_OK:
1354            zlist = [dlg.GetSelection()]
1355        else:
1356            zlist = [-1]
1357        dlg.Destroy()
1358       
1359    outlist = []
1360    for zindex in zlist:
1361        if zindex >= 0:
1362            efil = os.path.join(zloc, os.path.split(zinfo[zindex].filename)[1])
1363            if os.path.exists(efil) and confirmoverwrite:
1364                result = wx.ID_NO
1365                dlg = wx.MessageDialog(parent,
1366                    'File '+str(efil)+' already exists. OK to overwrite it?',
1367                    'Confirm overwrite',wx.YES_NO | wx.ICON_QUESTION)
1368                try:
1369                    result = dlg.ShowModal()
1370                finally:
1371                    dlg.Destroy()
1372                if result == wx.ID_NO:
1373                    zindex = -1
1374        if zindex >= 0:
1375            # extract the file to the current directory, regardless of it's original path
1376            #z.extract(zinfo[zindex],zloc)
1377            eloc,efil = os.path.split(zinfo[zindex].filename)
1378            outfile = os.path.join(zloc, efil)
1379            fpin = z.open(zinfo[zindex])
1380            fpout = file(outfile, "wb")
1381            shutil.copyfileobj(fpin, fpout)
1382            fpin.close()
1383            fpout.close()
1384            outlist.append(outfile)
1385    z.close()
1386    if multipleselect and len(outlist) >= 1:
1387        return outlist
1388    elif len(outlist) == 1:
1389        return outlist[0]
1390    else:
1391        return None
1392
1393######################################################################
1394# base classes for reading various types of data files
1395#   not used directly, only by subclassing
1396######################################################################
1397try:
1398    E,SGData = G2spc.SpcGroup('P 1') # data structure for default space group
1399except: # errors on doc build
1400    SGData = None
1401P1SGData = SGData
1402######################################################################
1403class ImportBaseclass(object):
1404    '''Defines a base class for the reading of input files (diffraction
1405    data, coordinates,...). See :ref:`Writing a Import Routine<Import_routines>`
1406    for an explanation on how to use a subclass of this class.
1407    '''
1408    class ImportException(Exception):
1409        '''Defines an Exception that is used when an import routine hits an expected error,
1410        usually in .Reader.
1411
1412        Good practice is that the Reader should define a value in self.errors that
1413        tells the user some information about what is wrong with their file.         
1414        '''
1415        pass
1416   
1417    UseReader = True  # in __init__ set value of self.UseReader to False to skip use of current importer
1418    def __init__(self,formatName,longFormatName=None,
1419                 extensionlist=[],strictExtension=False,):
1420        self.formatName = formatName # short string naming file type
1421        if longFormatName: # longer string naming file type
1422            self.longFormatName = longFormatName
1423        else:
1424            self.longFormatName = formatName
1425        # define extensions that are allowed for the file type
1426        # for windows, remove any extensions that are duplicate, as case is ignored
1427        if sys.platform == 'windows' and extensionlist:
1428            extensionlist = list(set([s.lower() for s in extensionlist]))
1429        self.extensionlist = extensionlist
1430        # If strictExtension is True, the file will not be read, unless
1431        # the extension matches one in the extensionlist
1432        self.strictExtension = strictExtension
1433        self.errors = ''
1434        self.warnings = ''
1435        # used for readers that will use multiple passes to read
1436        # more than one data block
1437        self.repeat = False
1438        self.selections = []
1439        self.repeatcount = 0
1440        self.readfilename = '?'
1441        #print 'created',self.__class__
1442
1443    def ReInitialize(self):
1444        'Reinitialize the Reader to initial settings'
1445        self.errors = ''
1446        self.warnings = ''
1447        self.repeat = False
1448        self.repeatcount = 0
1449        self.readfilename = '?'
1450
1451    def BlockSelector(self, ChoiceList, ParentFrame=None,title='Select a block',
1452        size=None, header='Block Selector',useCancel=True):
1453        ''' Provide a wx dialog to select a block if the file contains more
1454        than one set of data and one must be selected
1455        '''
1456        if useCancel:
1457            dlg = wx.SingleChoiceDialog(
1458                ParentFrame,title, header,ChoiceList)
1459        else:
1460            dlg = wx.SingleChoiceDialog(
1461                ParentFrame,title, header,ChoiceList,
1462                style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK|wx.CENTRE)
1463        if size: dlg.SetSize(size)
1464        dlg.CenterOnParent()
1465        if dlg.ShowModal() == wx.ID_OK:
1466            sel = dlg.GetSelection()
1467            return sel
1468        else:
1469            return None
1470        dlg.Destroy()
1471
1472    def MultipleBlockSelector(self, ChoiceList, ParentFrame=None,
1473        title='Select a block',size=None, header='Block Selector'):
1474        '''Provide a wx dialog to select a block of data if the
1475        file contains more than one set of data and one must be
1476        selected.
1477
1478        :returns: a list of the selected blocks
1479        '''
1480        dlg = wx.MultiChoiceDialog(ParentFrame,title, header,ChoiceList+['Select all'],
1481            wx.CHOICEDLG_STYLE)
1482        dlg.CenterOnScreen()
1483        if size: dlg.SetSize(size)
1484        if dlg.ShowModal() == wx.ID_OK:
1485            sel = dlg.GetSelections()
1486        else:
1487            return []
1488        dlg.Destroy()
1489        selected = []
1490        if len(ChoiceList) in sel:
1491            return range(len(ChoiceList))
1492        else:
1493            return sel
1494        return selected
1495
1496    def MultipleChoicesDialog(self, choicelist, headinglist, ParentFrame=None, **kwargs):
1497        '''A modal dialog that offers a series of choices, each with a title and a wx.Choice
1498        widget. Typical input:
1499       
1500           * choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1501           
1502           * headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1503           
1504        optional keyword parameters are: head (window title) and title
1505        returns a list of selected indicies for each choice (or None)
1506        '''
1507        result = None
1508        dlg = MultipleChoicesDialog(choicelist,headinglist,
1509            parent=ParentFrame, **kwargs)         
1510        dlg.CenterOnParent()
1511        if dlg.ShowModal() == wx.ID_OK:
1512            result = dlg.chosen
1513        dlg.Destroy()
1514        return result
1515
1516    def ShowBusy(self):
1517        wx.BeginBusyCursor()
1518#        wx.Yield() # make it happen now!
1519
1520    def DoneBusy(self):
1521        wx.EndBusyCursor()
1522        wx.Yield() # make it happen now!
1523       
1524#    def Reader(self, filename, filepointer, ParentFrame=None, **unused):
1525#        '''This method must be supplied in the child class to read the file.
1526#        if the read fails either return False or raise an Exception
1527#        preferably of type ImportException.
1528#        '''
1529#        #start reading
1530#        raise ImportException("Error occurred while...")
1531#        self.errors += "Hint for user on why the error occur
1532#        return False # if an error occurs
1533#        return True # if read OK
1534
1535    def ExtensionValidator(self, filename):
1536        '''This methods checks if the file has the correct extension
1537        Return False if this filename will not be supported by this reader
1538        Return True if the extension matches the list supplied by the reader
1539        Return None if the reader allows un-registered extensions
1540        '''
1541        if filename:
1542            ext = os.path.splitext(filename)[1]
1543            if sys.platform == 'windows': ext = ext.lower()
1544            if ext in self.extensionlist: return True
1545            if self.strictExtension: return False
1546        return None
1547
1548    def ContentsValidator(self, filepointer):
1549        '''This routine will attempt to determine if the file can be read
1550        with the current format.
1551        This will typically be overridden with a method that
1552        takes a quick scan of [some of]
1553        the file contents to do a "sanity" check if the file
1554        appears to match the selected format.
1555        Expected to be called via self.Validator()
1556        '''
1557        #filepointer.seek(0) # rewind the file pointer
1558        return True
1559
1560    def CIFValidator(self, filepointer):
1561        '''A :meth:`ContentsValidator` for use to validate CIF files.
1562        '''
1563        for i,l in enumerate(filepointer):
1564            if i >= 1000: return True
1565            '''Encountered only blank lines or comments in first 1000
1566            lines. This is unlikely, but assume it is CIF anyway, since we are
1567            even less likely to find a file with nothing but hashes and
1568            blank lines'''
1569            line = l.strip()
1570            if len(line) == 0: # ignore blank lines
1571                continue 
1572            elif line.startswith('#'): # ignore comments
1573                continue 
1574            elif line.startswith('data_'): # on the right track, accept this file
1575                return True
1576            else: # found something invalid
1577                self.errors = 'line '+str(i+1)+' contains unexpected data:\n'
1578                if all([ord(c) < 128 and ord(c) != 0 for c in str(l)]): # show only if ASCII
1579                    self.errors += '  '+str(l)
1580                else: 
1581                    self.errors += '  (binary)'
1582                self.errors += '\n  Note: a CIF should only have blank lines or comments before'
1583                self.errors += '\n        a data_ statement begins a block.'
1584                return False 
1585
1586######################################################################
1587class ImportPhase(ImportBaseclass):
1588    '''Defines a base class for the reading of files with coordinates
1589
1590    Objects constructed that subclass this (in import/G2phase_*.py etc.) will be used
1591    in :meth:`GSASII.GSASII.OnImportPhase`.
1592    See :ref:`Writing a Import Routine<Import_Routines>`
1593    for an explanation on how to use this class.
1594
1595    '''
1596    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1597        strictExtension=False,):
1598        # call parent __init__
1599        ImportBaseclass.__init__(self,formatName,longFormatName,
1600            extensionlist,strictExtension)
1601        self.Phase = None # a phase must be created with G2IO.SetNewPhase in the Reader
1602        self.Constraints = None
1603
1604    def PhaseSelector(self, ChoiceList, ParentFrame=None,
1605        title='Select a phase', size=None,header='Phase Selector'):
1606        ''' Provide a wx dialog to select a phase if the file contains more
1607        than one phase
1608        '''
1609        return self.BlockSelector(ChoiceList,ParentFrame,title,
1610            size,header)
1611
1612######################################################################
1613class ImportStructFactor(ImportBaseclass):
1614    '''Defines a base class for the reading of files with tables
1615    of structure factors.
1616
1617    Structure factors are read with a call to :meth:`GSASII.GSASII.OnImportSfact`
1618    which in turn calls :meth:`GSASII.GSASII.OnImportGeneric`, which calls
1619    methods :meth:`ExtensionValidator`, :meth:`ContentsValidator` and
1620    :meth:`Reader`.
1621
1622    See :ref:`Writing a Import Routine<Import_Routines>`
1623    for an explanation on how to use import classes in general. The specifics
1624    for reading a structure factor histogram require that
1625    the ``Reader()`` routine in the import
1626    class need to do only a few things: It
1627    should load :attr:`RefDict` item ``'RefList'`` with the reflection list,
1628    and set :attr:`Parameters` with the instrument parameters
1629    (initialized with :meth:`InitParameters` and set with :meth:`UpdateParameters`).
1630    '''
1631    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1632        strictExtension=False,):
1633        ImportBaseclass.__init__(self,formatName,longFormatName,
1634            extensionlist,strictExtension)
1635
1636        # define contents of Structure Factor entry
1637        self.Parameters = []
1638        'self.Parameters is a list with two dicts for data parameter settings'
1639        self.InitParameters()
1640        self.RefDict = {'RefList':[],'FF':{},'Super':0}
1641        self.Banks = []             #for multi bank data (usually TOF)
1642        '''self.RefDict is a dict containing the reflection information, as read from the file.
1643        Item 'RefList' contains the reflection information. See the
1644        :ref:`Single Crystal Reflection Data Structure<XtalRefl_table>`
1645        for the contents of each row. Dict element 'FF'
1646        contains the form factor values for each element type; if this entry
1647        is left as initialized (an empty list) it will be initialized as needed later.
1648        '''
1649    def ReInitialize(self):
1650        'Reinitialize the Reader to initial settings'
1651        ImportBaseclass.ReInitialize(self)
1652        self.InitParameters()
1653        self.Banks = []             #for multi bank data (usually TOF)
1654        self.RefDict = {'RefList':[],'FF':{},'Super':0}
1655       
1656    def InitParameters(self):
1657        'initialize the instrument parameters structure'
1658        Lambda = 0.70926
1659        HistType = 'SXC'
1660        self.Parameters = [{'Type':[HistType,HistType], # create the structure
1661                            'Lam':[Lambda,Lambda]
1662                            }, {}]
1663        'Parameters is a list with two dicts for data parameter settings'
1664
1665    def UpdateParameters(self,Type=None,Wave=None):
1666        'Revise the instrument parameters'
1667        if Type is not None:
1668            self.Parameters[0]['Type'] = [Type,Type]
1669        if Wave is not None:
1670            self.Parameters[0]['Lam'] = [Wave,Wave]           
1671                       
1672######################################################################
1673class ImportPowderData(ImportBaseclass):
1674    '''Defines a base class for the reading of files with powder data.
1675
1676    Objects constructed that subclass this (in import/G2pwd_*.py etc.) will be used
1677    in :meth:`GSASII.GSASII.OnImportPowder`.
1678    See :ref:`Writing a Import Routine<Import_Routines>`
1679    for an explanation on how to use this class.
1680    '''
1681    def __init__(self,formatName,longFormatName=None,
1682        extensionlist=[],strictExtension=False,):
1683        ImportBaseclass.__init__(self,formatName,longFormatName,
1684            extensionlist,strictExtension)
1685        self.clockWd = None  # used in TOF
1686        self.ReInitialize()
1687       
1688    def ReInitialize(self):
1689        'Reinitialize the Reader to initial settings'
1690        ImportBaseclass.ReInitialize(self)
1691        self.powderentry = ['',None,None] #  (filename,Pos,Bank)
1692        self.powderdata = [] # Powder dataset
1693        '''A powder data set is a list with items [x,y,w,yc,yb,yd]:
1694                np.array(x), # x-axis values
1695                np.array(y), # powder pattern intensities
1696                np.array(w), # 1/sig(intensity)^2 values (weights)
1697                np.array(yc), # calc. intensities (zero)
1698                np.array(yb), # calc. background (zero)
1699                np.array(yd), # obs-calc profiles
1700        '''                           
1701        self.comments = []
1702        self.idstring = ''
1703        self.Sample = G2pdG.SetDefaultSample() # default sample parameters
1704        self.Controls = {}  # items to be placed in top-level Controls
1705        self.GSAS = None     # used in TOF
1706        self.repeat_instparm = True # Should a parm file be
1707        #                             used for multiple histograms?
1708        self.instparm = None # name hint from file of instparm to use
1709        self.instfile = '' # full path name to instrument parameter file
1710        self.instbank = '' # inst parm bank number
1711        self.instmsg = ''  # a label that gets printed to show
1712                           # where instrument parameters are from
1713        self.numbanks = 1
1714        self.instdict = {} # place items here that will be transferred to the instrument parameters
1715        self.pwdparms = {} # place parameters that are transferred directly to the tree
1716                           # here (typically from an existing GPX file)
1717######################################################################
1718class ImportSmallAngleData(ImportBaseclass):
1719    '''Defines a base class for the reading of files with small angle data.
1720    See :ref:`Writing a Import Routine<Import_Routines>`
1721    for an explanation on how to use this class.
1722    '''
1723    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1724        strictExtension=False,):
1725           
1726        ImportBaseclass.__init__(self,formatName,longFormatName,extensionlist,
1727            strictExtension)
1728        self.ReInitialize()
1729       
1730    def ReInitialize(self):
1731        'Reinitialize the Reader to initial settings'
1732        ImportBaseclass.ReInitialize(self)
1733        self.smallangleentry = ['',None,None] #  (filename,Pos,Bank)
1734        self.smallangledata = [] # SASD dataset
1735        '''A small angle data set is a list with items [x,y,w,yc,yd]:
1736                np.array(x), # x-axis values
1737                np.array(y), # powder pattern intensities
1738                np.array(w), # 1/sig(intensity)^2 values (weights)
1739                np.array(yc), # calc. intensities (zero)
1740                np.array(yd), # obs-calc profiles
1741                np.array(yb), # preset bkg
1742        '''                           
1743        self.comments = []
1744        self.idstring = ''
1745        self.Sample = G2pdG.SetDefaultSample()
1746        self.GSAS = None     # used in TOF
1747        self.clockWd = None  # used in TOF
1748        self.numbanks = 1
1749        self.instdict = {} # place items here that will be transferred to the instrument parameters
1750
1751######################################################################
1752class ImportImage(ImportBaseclass):
1753    '''Defines a base class for the reading of images
1754
1755    Images are read in only these places:
1756   
1757      * Initial reading is typically done from a menu item
1758        with a call to :meth:`GSASII.GSASII.OnImportImage`
1759        which in turn calls :meth:`GSASII.GSASII.OnImportGeneric`. That calls
1760        methods :meth:`ExtensionValidator`, :meth:`ContentsValidator` and
1761        :meth:`Reader`. This returns a list of reader objects for each read image.
1762
1763      * Images are read alternatively in :func:`GSASIIIO.ReadImages`, which puts image info
1764        directly into the data tree.
1765
1766      * Images are reloaded with :func:`GSASIIIO.GetImageData`.
1767
1768    .. _Image_import_routines:
1769
1770    When reading an image, the ``Reader()`` routine in the ImportImage class
1771    should set:
1772   
1773      * :attr:`Comments`: a list of strings (str),
1774      * :attr:`Npix`: the number of pixels in the image (int),
1775      * :attr:`Image`: the actual image as a numpy array (np.array)
1776      * :attr:`Data`: a dict defining image parameters (dict). Within this dict the following
1777        data items are needed:
1778       
1779         * 'pixelSize': size of each pixel in microns (such as ``[200,200]``.
1780         * 'wavelength': wavelength in Angstoms.
1781         * 'distance': distance of detector from sample in cm.
1782         * 'center': uncalibrated center of beam on detector (such as ``[204.8,204.8]``.
1783         * 'size': size of image (such as ``[2048,2048]``).
1784         * 'ImageTag': image number or other keyword used to retrieve image from
1785           a multi-image data file (defaults to ``1`` if not specified).
1786         * 'sumfile': holds sum image file name if a sum was produced from a multi image file
1787
1788    optional data items:
1789   
1790      * :attr:`repeat`: set to True if there are additional images to
1791        read in the file, False otherwise
1792      * :attr:`repeatcount`: set to the number of the image.
1793     
1794    Note that the above is initialized with :meth:`InitParameters`.
1795    (Also see :ref:`Writing a Import Routine<Import_Routines>`
1796    for an explanation on how to use import classes in general.)
1797    '''
1798    def __init__(self,formatName,longFormatName=None,extensionlist=[],
1799        strictExtension=False,):
1800        ImportBaseclass.__init__(self,formatName,longFormatName,
1801            extensionlist,strictExtension)
1802        self.InitParameters()
1803       
1804    def ReInitialize(self):
1805        'Reinitialize the Reader to initial settings -- not used at present'
1806        ImportBaseclass.ReInitialize(self)
1807        self.InitParameters()
1808       
1809    def InitParameters(self):
1810        'initialize the instrument parameters structure'
1811        self.Comments = ['No comments']
1812        self.Data = {}
1813        self.Npix = 0
1814        self.Image = None
1815        self.repeat = False
1816        self.repeatcount = 1
1817        self.sumfile = ''
1818
1819    def LoadImage(self,ParentFrame,imagefile,imagetag=None):
1820        '''Optionally, call this after reading in an image to load it into the tree.
1821        This saves time by preventing a reread of the same information.
1822        '''
1823        if ParentFrame:
1824            ParentFrame.ImageZ = self.Image   # store the image for plotting
1825            ParentFrame.oldImagefile = imagefile # save the name of the last image file read
1826            ParentFrame.oldImageTag = imagetag   # save the tag of the last image file read           
1827
1828######################################################################
1829def striphist(var,insChar=''):
1830    'strip a histogram number from a var name'
1831    sv = var.split(':')
1832    if len(sv) <= 1: return var
1833    if sv[1]:
1834        sv[1] = insChar
1835    return ':'.join(sv)
1836class ExportBaseclass(object):
1837    '''Defines a base class for the exporting of GSAS-II results.
1838
1839    This class is subclassed in the various exports/G2export_*.py files. Those files
1840    are imported in :meth:`GSASII.GSASII._init_Exports` which defines the
1841    appropriate menu items for each one and the .Exporter method is called
1842    directly from the menu item.
1843
1844    Routines may also define a .Writer method, which is used to write a single
1845    file without invoking any GUI objects.
1846    '''
1847    def __init__(self,G2frame,formatName,extension,longFormatName=None,):
1848        self.G2frame = G2frame
1849        self.formatName = formatName # short string naming file type
1850        self.extension = extension
1851        if longFormatName: # longer string naming file type
1852            self.longFormatName = longFormatName
1853        else:
1854            self.longFormatName = formatName
1855        self.OverallParms = {}
1856        self.Phases = {}
1857        self.Histograms = {}
1858        self.powderDict = {}
1859        self.xtalDict = {}
1860        self.parmDict = {}
1861        self.sigDict = {}
1862        # updated in InitExport:
1863        self.currentExportType = None # type of export that has been requested
1864        # updated in ExportSelect (when used):
1865        self.phasenam = None # a list of selected phases
1866        self.histnam = None # a list of selected histograms
1867        self.filename = None # name of file to be written (single export) or template (multiple files)
1868        self.dirname = '' # name of directory where file(s) will be written
1869        self.fullpath = '' # name of file being written -- full path
1870       
1871        # items that should be defined in a subclass of this class
1872        self.exporttype = []  # defines the type(s) of exports that the class can handle.
1873        # The following types are defined: 'project', "phase", "powder", "single"
1874        self.multiple = False # set as True if the class can export multiple phases or histograms
1875        # self.multiple is ignored for "project" exports
1876
1877    def InitExport(self,event):
1878        '''Determines the type of menu that called the Exporter and
1879        misc initialization.
1880        '''
1881        self.filename = None # name of file to be written (single export)
1882        self.dirname = '' # name of file to be written (multiple export)
1883        if event:
1884            self.currentExportType = self.G2frame.ExportLookup.get(event.Id)
1885
1886    def MakePWDRfilename(self,hist):
1887        '''Make a filename root (no extension) from a PWDR histogram name
1888
1889        :param str hist: the histogram name in data tree (starts with "PWDR ")
1890        '''
1891        file0 = ''
1892        file1 = hist[5:]
1893        # replace repeated blanks
1894        while file1 != file0:
1895            file0 = file1
1896            file1 = file0.replace('  ',' ').strip()
1897        file0 = file1.replace('Azm= ','A')
1898        # if angle has unneeded decimal places on aziumuth, remove them
1899        if file0[-3:] == '.00': file0 = file0[:-3]
1900        file0 = file0.replace('.','_')
1901        file0 = file0.replace(' ','_')
1902        return file0
1903
1904    def ExportSelect(self,AskFile='ask'):
1905        '''Selects histograms or phases when needed. Sets a default file name when
1906        requested into self.filename; always sets a default directory in self.dirname.
1907
1908        :param bool AskFile: Determines how this routine processes getting a
1909          location to store the current export(s).
1910         
1911          * if AskFile is 'ask' (default option), get the name of the file to be written;
1912            self.filename and self.dirname are always set. In the case where
1913            multiple files must be generated, the export routine should do this
1914            based on self.filename as a template.
1915          * if AskFile is 'dir', get the name of the directory to be used;
1916            self.filename is not used, but self.dirname is always set. The export routine
1917            will always generate the file name.
1918          * if AskFile is 'single', get only the name of the directory to be used when
1919            multiple items will be written (as multiple files) are used
1920            *or* a complete file name is requested when a single file
1921            name is selected. self.dirname is always set and self.filename used
1922            only when a single file is selected.
1923          * if AskFile is 'default', creates a name of the file to be used from
1924            the name of the project (.gpx) file. If the project has not been saved,
1925            then the name of file is requested.
1926            self.filename and self.dirname are always set. In the case where
1927            multiple file names must be generated, the export routine should do this
1928            based on self.filename.
1929          * if AskFile is 'default-dir', sets self.dirname from the project (.gpx)
1930            file. If the project has not been saved, then a directory is requested.
1931            self.filename is not used.
1932
1933        :returns: True in case of an error
1934        '''
1935       
1936        numselected = 1
1937        if self.currentExportType == 'phase':
1938            if len(self.Phases) == 0:
1939                self.G2frame.ErrorDialog(
1940                    'Empty project',
1941                    'Project does not contain any phases.')
1942                return True
1943            elif len(self.Phases) == 1:
1944                self.phasenam = self.Phases.keys()
1945            elif self.multiple: 
1946                choices = sorted(self.Phases.keys())
1947                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1948                if phasenum is None: return True
1949                self.phasenam = [choices[i] for i in phasenum]
1950                if not self.phasenam: return True
1951                numselected = len(self.phasenam)
1952            else:
1953                choices = sorted(self.Phases.keys())
1954                phasenum = G2G.ItemSelector(choices,self.G2frame)
1955                if phasenum is None: return True
1956                self.phasenam = [choices[phasenum]]
1957                numselected = len(self.phasenam)
1958        elif self.currentExportType == 'single':
1959            if len(self.xtalDict) == 0:
1960                self.G2frame.ErrorDialog(
1961                    'Empty project',
1962                    'Project does not contain any single crystal data.')
1963                return True
1964            elif len(self.xtalDict) == 1:
1965                self.histnam = self.xtalDict.values()
1966            elif self.multiple:
1967                choices = sorted(self.xtalDict.values())
1968                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1969                if not hnum: return True
1970                self.histnam = [choices[i] for i in hnum]
1971                numselected = len(self.histnam)
1972            else:
1973                choices = sorted(self.xtalDict.values())
1974                hnum = G2G.ItemSelector(choices,self.G2frame)
1975                if hnum is None: return True
1976                self.histnam = [choices[hnum]]
1977                numselected = len(self.histnam)
1978        elif self.currentExportType == 'powder':
1979            if len(self.powderDict) == 0:
1980                self.G2frame.ErrorDialog(
1981                    'Empty project',
1982                    'Project does not contain any powder data.')
1983                return True
1984            elif len(self.powderDict) == 1:
1985                self.histnam = self.powderDict.values()
1986            elif self.multiple:
1987                choices = sorted(self.powderDict.values())
1988                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1989                if not hnum: return True
1990                self.histnam = [choices[i] for i in hnum]
1991                numselected = len(self.histnam)
1992            else:
1993                choices = sorted(self.powderDict.values())
1994                hnum = G2G.ItemSelector(choices,self.G2frame)
1995                if hnum is None: return True
1996                self.histnam = [choices[hnum]]
1997                numselected = len(self.histnam)
1998        elif self.currentExportType == 'image':
1999            if len(self.Histograms) == 0:
2000                self.G2frame.ErrorDialog(
2001                    'Empty project',
2002                    'Project does not contain any images.')
2003                return True
2004            elif len(self.Histograms) == 1:
2005                self.histnam = self.Histograms.keys()
2006            else:
2007                choices = sorted(self.Histograms.keys())
2008                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
2009                if self.multiple:
2010                    if not hnum: return True
2011                    self.histnam = [choices[i] for i in hnum]
2012                else:
2013                    if hnum is None: return True
2014                    self.histnam = [choices[hnum]]
2015                numselected = len(self.histnam)
2016        if self.currentExportType == 'map':
2017            # search for phases with maps
2018            mapPhases = []
2019            choices = []
2020            for phasenam in sorted(self.Phases):
2021                phasedict = self.Phases[phasenam] # pointer to current phase info           
2022                if len(phasedict['General']['Map'].get('rho',[])):
2023                    mapPhases.append(phasenam)
2024                    if phasedict['General']['Map'].get('Flip'):
2025                        choices.append('Charge flip map: '+str(phasenam))
2026                    elif phasedict['General']['Map'].get('MapType'):
2027                        choices.append(
2028                            str(phasedict['General']['Map'].get('MapType'))
2029                            + ' map: ' + str(phasenam))
2030                    else:
2031                        choices.append('unknown map: '+str(phasenam))
2032            # select a map if needed
2033            if len(mapPhases) == 0:
2034                self.G2frame.ErrorDialog(
2035                    'Empty project',
2036                    'Project does not contain any maps.')
2037                return True
2038            elif len(mapPhases) == 1:
2039                self.phasenam = mapPhases
2040            else: 
2041                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
2042                if self.multiple:
2043                    if not phasenum: return True
2044                    self.phasenam = [mapPhases[i] for i in phasenum]
2045                else:
2046                    if phasenum is None: return True
2047                    self.phasenam = [mapPhases[phasenum]]
2048            numselected = len(self.phasenam)
2049
2050        # items selected, now set self.dirname and usually self.filename
2051        if AskFile == 'ask' or (AskFile == 'single' and numselected == 1) or (
2052            AskFile == 'default' and not self.G2frame.GSASprojectfile
2053            ):
2054            filename = self.askSaveFile()
2055            if not filename: return True
2056            self.dirname,self.filename = os.path.split(filename)
2057        elif AskFile == 'dir' or AskFile == 'single' or (
2058            AskFile == 'default-dir' and not self.G2frame.GSASprojectfile
2059            ):
2060            self.dirname = self.askSaveDirectory()
2061            if not self.dirname: return True
2062        elif AskFile == 'default-dir' or AskFile == 'default':
2063            self.dirname,self.filename = os.path.split(
2064                os.path.splitext(self.G2frame.GSASprojectfile)[0] + self.extension
2065                )
2066        else:
2067            raise Exception('This should not happen!')
2068
2069    def loadParmDict(self):
2070        '''Load the GSAS-II refinable parameters from the tree into a dict (self.parmDict). Update
2071        refined values to those from the last cycle and set the uncertainties for the
2072        refined parameters in another dict (self.sigDict).
2073
2074        Expands the parm & sig dicts to include values derived from constraints.
2075        '''
2076        self.parmDict = {}
2077        self.sigDict = {}
2078        rigidbodyDict = {}
2079        covDict = {}
2080        consDict = {}
2081        Histograms,Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
2082        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
2083        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
2084        while item:
2085            name = self.G2frame.PatternTree.GetItemText(item)
2086            if name == 'Rigid bodies':
2087                 rigidbodyDict = self.G2frame.PatternTree.GetItemPyData(item)
2088            elif name == 'Covariance':
2089                 covDict = self.G2frame.PatternTree.GetItemPyData(item)
2090            elif name == 'Constraints':
2091                 consDict = self.G2frame.PatternTree.GetItemPyData(item)
2092            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
2093        rbVary,rbDict =  G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
2094        self.parmDict.update(rbDict)
2095        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
2096        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtables,BLtables,MFtables,maxSSwave =  G2stIO.GetPhaseData(
2097            Phases,RestraintDict=None,rbIds=rbIds,Print=False)
2098        self.parmDict.update(phaseDict)
2099        hapVary,hapDict,controlDict =  G2stIO.GetHistogramPhaseData(
2100            Phases,Histograms,Print=False,resetRefList=False)
2101        self.parmDict.update(hapDict)
2102        histVary,histDict,controlDict =  G2stIO.GetHistogramData(Histograms,Print=False)
2103        self.parmDict.update(histDict)
2104        self.parmDict.update(zip(
2105            covDict.get('varyList',[]),
2106            covDict.get('variables',[])))
2107        self.sigDict = dict(zip(
2108            covDict.get('varyList',[]),
2109            covDict.get('sig',[])))
2110        # expand to include constraints: first compile a list of constraints
2111        constList = []
2112        for item in consDict:
2113            if item.startswith('_'): continue
2114            constList += consDict[item]
2115        # now process the constraints
2116        G2mv.InitVars()
2117        constDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
2118        varyList = covDict.get('varyListStart')
2119        if varyList is None and len(constDict) == 0:
2120            # no constraints can use varyList
2121            varyList = covDict.get('varyList')
2122        elif varyList is None:
2123            # old GPX file from before pre-constraint varyList is saved
2124            print ' *** Old refinement: Please use Calculate/Refine to redo  ***'
2125            raise Exception(' *** Export aborted ***')
2126        else:
2127            varyList = list(varyList)
2128        try:
2129            groups,parmlist = G2mv.GroupConstraints(constDict)
2130            G2mv.GenerateConstraints(groups,parmlist,varyList,constDict,fixedList,self.parmDict)
2131        except:
2132            # this really should not happen
2133            print ' *** ERROR - constraints are internally inconsistent ***'
2134            errmsg, warnmsg = G2mv.CheckConstraints(varyList,constDict,fixedList)
2135            print 'Errors',errmsg
2136            if warnmsg: print 'Warnings',warnmsg
2137            raise Exception(' *** CIF creation aborted ***')
2138        # add the constrained values to the parameter dictionary
2139        G2mv.Dict2Map(self.parmDict,varyList)
2140        # and add their uncertainties into the esd dictionary (sigDict)
2141        if covDict.get('covMatrix') is not None:
2142            self.sigDict.update(G2mv.ComputeDepESD(covDict['covMatrix'],covDict['varyList'],self.parmDict))
2143
2144    def loadTree(self):
2145        '''Load the contents of the data tree into a set of dicts
2146        (self.OverallParms, self.Phases and self.Histogram as well as self.powderDict
2147        & self.xtalDict)
2148       
2149        * The childrenless data tree items are overall parameters/controls for the
2150          entire project and are placed in self.OverallParms
2151        * Phase items are placed in self.Phases
2152        * Data items are placed in self.Histogram. The key for these data items
2153          begin with a keyword, such as PWDR, IMG, HKLF,... that identifies the data type.
2154        '''
2155        self.OverallParms = {}
2156        self.powderDict = {}
2157        self.xtalDict = {}
2158        self.Phases = {}
2159        self.Histograms = {}
2160        self.SeqRefdata = None
2161        self.SeqRefhist = None
2162        if self.G2frame.PatternTree.IsEmpty(): return # nothing to do
2163        histType = None       
2164        if self.currentExportType == 'phase':
2165            # if exporting phases load them here
2166            sub = G2gd.GetPatternTreeItemId(self.G2frame,self.G2frame.root,'Phases')
2167            if not sub:
2168                print 'no phases found'
2169                return True
2170            item, cookie = self.G2frame.PatternTree.GetFirstChild(sub)
2171            while item:
2172                phaseName = self.G2frame.PatternTree.GetItemText(item)
2173                self.Phases[phaseName] =  self.G2frame.PatternTree.GetItemPyData(item)
2174                item, cookie = self.G2frame.PatternTree.GetNextChild(sub, cookie)
2175            return
2176        elif self.currentExportType == 'single':
2177            histType = 'HKLF'
2178        elif self.currentExportType == 'powder':
2179            histType = 'PWDR'
2180        elif self.currentExportType == 'image':
2181            histType = 'IMG'
2182
2183        if histType: # Loading just one kind of tree entry
2184            item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
2185            while item:
2186                name = self.G2frame.PatternTree.GetItemText(item)
2187                if name.startswith(histType):
2188                    if self.Histograms.get(name): # there is already an item with this name
2189                        print('Histogram name '+str(name)+' is repeated. Renaming')
2190                        if name[-1] == '9':
2191                            name = name[:-1] + '10'
2192                        elif name[-1] in '012345678':
2193                            name = name[:-1] + str(int(name[-1])+1)
2194                        else:                           
2195                            name += '-1'
2196                    self.Histograms[name] = {}
2197                    # the main info goes into Data, but the 0th
2198                    # element contains refinement results, carry
2199                    # that over too now.
2200                    self.Histograms[name]['Data'] = self.G2frame.PatternTree.GetItemPyData(item)[1]
2201                    self.Histograms[name][0] = self.G2frame.PatternTree.GetItemPyData(item)[0]
2202                    item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
2203                    while item2: 
2204                        child = self.G2frame.PatternTree.GetItemText(item2)
2205                        self.Histograms[name][child] = self.G2frame.PatternTree.GetItemPyData(item2)
2206                        item2, cookie2 = self.G2frame.PatternTree.GetNextChild(item, cookie2)
2207                item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
2208            # index powder and single crystal histograms by number
2209            for hist in self.Histograms:
2210                if hist.startswith("PWDR"): 
2211                    d = self.powderDict
2212                elif hist.startswith("HKLF"): 
2213                    d = self.xtalDict
2214                else:
2215                    return                   
2216                i = self.Histograms[hist].get('hId')
2217                if i is None and not d.keys():
2218                    i = 0
2219                elif i is None or i in d.keys():
2220                    i = max(d.keys())+1
2221                d[i] = hist
2222            return
2223        # else standard load: using all interlinked phases and histograms
2224        self.Histograms,self.Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
2225        item, cookie = self.G2frame.PatternTree.GetFirstChild(self.G2frame.root)
2226        while item:
2227            name = self.G2frame.PatternTree.GetItemText(item)
2228            item2, cookie2 = self.G2frame.PatternTree.GetFirstChild(item)
2229            if not item2: 
2230                self.OverallParms[name] = self.G2frame.PatternTree.GetItemPyData(item)
2231            item, cookie = self.G2frame.PatternTree.GetNextChild(self.G2frame.root, cookie)
2232        # index powder and single crystal histograms
2233        for hist in self.Histograms:
2234            i = self.Histograms[hist]['hId']
2235            if hist.startswith("PWDR"): 
2236                self.powderDict[i] = hist
2237            elif hist.startswith("HKLF"): 
2238                self.xtalDict[i] = hist
2239
2240    def dumpTree(self,mode='type'):
2241        '''Print out information on the data tree dicts loaded in loadTree.
2242        Used for testing only.
2243        '''
2244        if self.SeqRefdata and self.SeqRefhist:
2245            print('Note that dumpTree does not show sequential results')
2246        print '\nOverall'
2247        if mode == 'type':
2248            def Show(arg): return type(arg)
2249        else:
2250            def Show(arg): return arg
2251        for key in self.OverallParms:
2252            print '  ',key,Show(self.OverallParms[key])
2253        print 'Phases'
2254        for key1 in self.Phases:
2255            print '    ',key1,Show(self.Phases[key1])
2256        print 'Histogram'
2257        for key1 in self.Histograms:
2258            print '    ',key1,Show(self.Histograms[key1])
2259            for key2 in self.Histograms[key1]:
2260                print '      ',key2,Show(self.Histograms[key1][key2])
2261
2262    def defaultSaveFile(self):
2263        return os.path.abspath(
2264            os.path.splitext(self.G2frame.GSASprojectfile
2265                             )[0]+self.extension)
2266       
2267    def askSaveFile(self):
2268        '''Ask the user to supply a file name
2269
2270        :returns: a file name (str) or None if Cancel is pressed
2271        '''
2272       
2273        pth = G2G.GetExportPath(self.G2frame)
2274        defnam = os.path.splitext(
2275            os.path.split(self.G2frame.GSASprojectfile)[1]
2276            )[0]+self.extension
2277        dlg = wx.FileDialog(
2278            self.G2frame, 'Input name for file to write', pth, defnam,
2279            self.longFormatName+' (*'+self.extension+')|*'+self.extension,
2280            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
2281        dlg.CenterOnParent()
2282        try:
2283            if dlg.ShowModal() == wx.ID_OK:
2284                filename = dlg.GetPath()
2285                self.G2frame.LastExportDir = os.path.split(filename)[0]
2286                filename = os.path.splitext(filename)[0]+self.extension # make sure extension is correct
2287            else:
2288                filename = None
2289        finally:
2290            dlg.Destroy()
2291        return filename
2292
2293    def askSaveDirectory(self):
2294        '''Ask the user to supply a directory name. Path name is used as the
2295        starting point for the next export path search.
2296
2297        :returns: a directory name (str) or None if Cancel is pressed
2298        '''
2299        pth = G2G.GetExportPath(self.G2frame)
2300        dlg = wx.DirDialog(
2301            self.G2frame, 'Input directory where file(s) will be written', pth,
2302            wx.DD_DEFAULT_STYLE)
2303        dlg.CenterOnParent()
2304        try:
2305            if dlg.ShowModal() == wx.ID_OK:
2306                filename = dlg.GetPath()
2307                self.G2frame.LastExportDir = filename
2308            else:
2309                filename = None
2310        finally:
2311            dlg.Destroy()
2312        return filename
2313
2314    # Tools for file writing.
2315    def OpenFile(self,fil=None,mode='w'):
2316        '''Open the output file
2317
2318        :param str fil: The name of the file to open. If None (default)
2319          the name defaults to self.dirname + self.filename.
2320          If an extension is supplied, it is not overridded,
2321          but if not, the default extension is used.
2322        :returns: the file object opened by the routine which is also
2323          saved as self.fp
2324        '''
2325        if mode == 'd': # debug mode
2326            self.fullpath = '(stdout)'
2327            self.fp = sys.stdout
2328            return
2329        if not fil:
2330            if not os.path.splitext(self.filename)[1]:
2331                self.filename += self.extension
2332            fil = os.path.join(self.dirname,self.filename)
2333        self.fullpath = os.path.abspath(fil)
2334        self.fp = open(self.fullpath,mode)
2335        return self.fp
2336
2337    def Write(self,line):
2338        '''write a line of output, attaching a line-end character
2339
2340        :param str line: the text to be written.
2341        '''
2342        self.fp.write(line+'\n')
2343       
2344    def CloseFile(self,fp=None):
2345        '''Close a file opened in OpenFile
2346
2347        :param file fp: the file object to be closed. If None (default)
2348          file object self.fp is closed.
2349        '''
2350        if self.fp == sys.stdout: return # debug mode
2351        if fp is None:
2352            fp = self.fp
2353            self.fp = None
2354        fp.close()
2355       
2356    def SetSeqRef(self,data,hist):
2357        '''Set the exporter to retrieve results from a sequential refinement
2358        rather than the main tree
2359        '''
2360        self.SeqRefdata = data
2361        self.SeqRefhist = hist
2362        data_name = data[hist]
2363        for i,val in zip(data_name['varyList'],data_name['sig']):
2364            self.sigDict[i] = val
2365            self.sigDict[striphist(i)] = val
2366        for i in data_name['parmDict']:
2367            self.parmDict[striphist(i)] = data_name['parmDict'][i]
2368            self.parmDict[i] = data_name['parmDict'][i]
2369            # zero out the dA[xyz] terms, they would only bring confusion
2370            key = i.split(':')
2371            if len(key) < 3: continue
2372            if key[2].startswith('dA'):
2373                self.parmDict[i] = 0.0
2374        for i,(val,sig) in data_name.get('depParmDict',{}).iteritems():
2375            self.parmDict[i] = val
2376            self.sigDict[i] = sig
2377        #GSASIIpath.IPyBreak()
2378               
2379    # Tools to pull information out of the data arrays
2380    def GetCell(self,phasenam):
2381        """Gets the unit cell parameters and their s.u.'s for a selected phase
2382
2383        :param str phasenam: the name for the selected phase
2384        :returns: `cellList,cellSig` where each is a 7 element list corresponding
2385          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
2386          cell values and `cellSig` has their uncertainties.
2387        """
2388        if self.SeqRefdata and self.SeqRefhist:
2389            return self.GetSeqCell(phasenam,self.SeqRefdata[self.SeqRefhist])
2390        phasedict = self.Phases[phasenam] # pointer to current phase info
2391        try:
2392            pfx = str(phasedict['pId'])+'::'
2393            A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict)
2394            cellSig = G2stIO.getCellEsd(pfx,phasedict['General']['SGData'],A,
2395                self.OverallParms['Covariance'])  # returns 7 vals, includes sigVol
2396            cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)
2397            return cellList,cellSig
2398        except KeyError:
2399            cell = phasedict['General']['Cell'][1:]
2400            return cell,7*[0]
2401           
2402    def GetSeqCell(self,phasenam,data_name):
2403        """Gets the unit cell parameters and their s.u.'s for a selected phase
2404        and histogram in a sequential fit
2405
2406        :param str phasenam: the name for the selected phase
2407        :param dict data_name: the sequential refinement parameters for the selected histogram
2408        :returns: `cellList,cellSig` where each is a 7 element list corresponding
2409          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
2410          cell values and `cellSig` has their uncertainties.
2411        """
2412        phasedict = self.Phases[phasenam]
2413        SGdata = phasedict['General']['SGData']
2414        pId = phasedict['pId']
2415        RecpCellTerms = G2lat.cell2A(phasedict['General']['Cell'][1:7])
2416        ESDlookup = {}
2417        Dlookup = {}
2418        varied = [striphist(i) for i in data_name['varyList']]
2419        for item,val in data_name['newCellDict'].iteritems():
2420            if item in varied:
2421                ESDlookup[val[0]] = item
2422                Dlookup[item] = val[0]
2423        A = RecpCellTerms[:]
2424        for i in range(6):
2425            var = str(pId)+'::A'+str(i)
2426            if var in ESDlookup:
2427                A[i] = data_name['newCellDict'][ESDlookup[var]][1] # override with refined value
2428        cellDict = dict(zip([str(pId)+'::A'+str(i) for i in range(6)],A))
2429        zeroDict = {i:0.0 for i in cellDict}
2430        A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata,cellDict,zeroDict)
2431        covData = {
2432            'varyList': [Dlookup.get(striphist(v),v) for v in data_name['varyList']],
2433            'covMatrix': data_name['covMatrix']
2434            }
2435        return list(G2lat.A2cell(A)) + [G2lat.calc_V(A)], G2stIO.getCellEsd(str(pId)+'::',SGdata,A,covData)
2436               
2437    def GetAtoms(self,phasenam):
2438        """Gets the atoms associated with a phase. Can be used with standard
2439        or macromolecular phases
2440
2441        :param str phasenam: the name for the selected phase
2442        :returns: a list of items for eac atom where each item is a list containing:
2443          label, typ, mult, xyz, and td, where
2444
2445          * label and typ are the atom label and the scattering factor type (str)
2446          * mult is the site multiplicity (int)
2447          * xyz is contains a list with four pairs of numbers:
2448            x, y, z and fractional occupancy and
2449            their standard uncertainty (or a negative value)
2450          * td is contains a list with either one or six pairs of numbers:
2451            if one number it is U\ :sub:`iso` and with six numbers it is
2452            U\ :sub:`11`, U\ :sub:`22`, U\ :sub:`33`, U\ :sub:`12`, U\ :sub:`13` & U\ :sub:`23`
2453            paired with their standard uncertainty (or a negative value)
2454        """
2455        phasedict = self.Phases[phasenam] # pointer to current phase info           
2456        cx,ct,cs,cia = phasedict['General']['AtomPtrs']
2457        cfrac = cx+3
2458        fpfx = str(phasedict['pId'])+'::Afrac:'       
2459        atomslist = []
2460        for i,at in enumerate(phasedict['Atoms']):
2461            if phasedict['General']['Type'] == 'macromolecular':
2462                label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2])
2463            else:
2464                label = at[ct-1]
2465            fval = self.parmDict.get(fpfx+str(i),at[cfrac])
2466            fsig = self.sigDict.get(fpfx+str(i),-0.009)
2467            mult = at[cs+1]
2468            typ = at[ct]
2469            xyz = []
2470            for j,v in enumerate(('x','y','z')):
2471                val = at[cx+j]
2472                pfx = str(phasedict['pId']) + '::A' + v + ':' + str(i)
2473                val = self.parmDict.get(pfx, val)
2474                dpfx = str(phasedict['pId'])+'::dA'+v+':'+str(i)
2475                sig = self.sigDict.get(dpfx,-0.000009)
2476                xyz.append((val,sig))
2477            xyz.append((fval,fsig))
2478            td = []
2479            if at[cia] == 'I':
2480                pfx = str(phasedict['pId'])+'::AUiso:'+str(i)
2481                val = self.parmDict.get(pfx,at[cia+1])
2482                sig = self.sigDict.get(pfx,-0.0009)
2483                td.append((val,sig))
2484            else:
2485                for i,var in enumerate(('AU11','AU22','AU33','AU12','AU13','AU23')):
2486                    pfx = str(phasedict['pId'])+'::'+var+':'+str(i)
2487                    val = self.parmDict.get(pfx,at[cia+2+i])
2488                    sig = self.sigDict.get(pfx,-0.0009)
2489                    td.append((val,sig))
2490            atomslist.append((label,typ,mult,xyz,td))
2491        return atomslist
2492######################################################################
2493def ExportPowderList(G2frame):
2494    '''Returns a list of extensions supported by :func:`GSASIIIO:ExportPowder`
2495    This is used in :meth:`GSASIIimgGUI.AutoIntFrame` only.
2496   
2497    :param wx.Frame G2frame: the GSAS-II main data tree window
2498    '''
2499    extList = []
2500    for obj in G2frame.exporterlist:
2501        if 'powder' in obj.exporttype:
2502            try:
2503                obj.Writer
2504                extList.append(obj.extension)
2505            except AttributeError:
2506                pass
2507    return extList
2508
2509def ExportPowder(G2frame,TreeName,fileroot,extension):
2510    '''Writes a single powder histogram using the Export routines.
2511    This is used in :meth:`GSASIIimgGUI.AutoIntFrame` only.
2512
2513    :param wx.Frame G2frame: the GSAS-II main data tree window
2514    :param str TreeName: the name of the histogram (PWDR ...) in the data tree
2515    :param str fileroot: name for file to be written, extension ignored
2516    :param str extension: extension for file to be written (start with '.'). Must
2517      match a powder export routine that has a Writer object.
2518    '''
2519    filename = os.path.abspath(os.path.splitext(fileroot)[0]+extension)
2520    for obj in G2frame.exporterlist:
2521        if obj.extension == extension and 'powder' in obj.exporttype:
2522            obj.currentExportType = 'powder'
2523            obj.InitExport(None)
2524            obj.loadTree() # load all histograms in tree into dicts
2525            if TreeName not in obj.Histograms:
2526                raise Exception('Histogram not found: '+str(TreeName))
2527            try:
2528                obj.Writer
2529            except AttributeError:
2530                continue
2531            try:
2532                obj.Writer(TreeName,filename)
2533                return
2534            except Exception,err:
2535                print('Export Routine for '+extension+' failed.')
2536                print err
2537    else:
2538        print('No Export routine supports extension '+extension)
2539
2540def ExportSequential(G2frame,data,obj,exporttype):
2541    '''
2542    Used to export from every phase/dataset in a sequential refinement using
2543    a .Writer method for either projects or phases. Prompts to select histograms
2544    and for phase exports, which phase(s).
2545
2546    :param wx.Frame G2frame: the GSAS-II main data tree window
2547    :param dict data: the sequential refinement data object
2548    :param str exporttype: indicates the type of export ('project' or 'phase')
2549    '''
2550    if len(data['histNames']) == 0:
2551        G2G.G2MessageBox(G2frame,'There are no sequential histograms','Warning')
2552    obj.InitExport(None)
2553    obj.loadTree()
2554    obj.loadParmDict()
2555    if len(data['histNames']) == 1:
2556        histlist = data['histNames']
2557    else:
2558        dlg = G2G.G2MultiChoiceDialog(G2frame,'Select histograms to export from list',
2559                                 'Select histograms',data['histNames'])
2560        if dlg.ShowModal() == wx.ID_OK:
2561            histlist = [data['histNames'][l] for l in dlg.GetSelections()]
2562            dlg.Destroy()
2563        else:
2564            dlg.Destroy()
2565            return
2566    if exporttype == 'Phase':
2567        phaselist = obj.Phases.keys()
2568        if len(obj.Phases) == 0:
2569            G2G.G2MessageBox(G2frame,'There are no phases in sequential ref.','Warning')
2570            return
2571        elif len(obj.Phases) > 1:
2572            dlg = G2G.G2MultiChoiceDialog(G2frame,'Select phases to export from list',
2573                                    'Select phases', phaselist)
2574            if dlg.ShowModal() == wx.ID_OK:
2575                phaselist = [phaselist[l] for l in dlg.GetSelections()]
2576                dlg.Destroy()
2577            else:
2578                dlg.Destroy()
2579                return
2580        filename = obj.askSaveFile()
2581        if not filename: return True
2582        obj.dirname,obj.filename = os.path.split(filename)
2583        print('Writing output to file '+str(obj.filename)+"...")
2584        mode = 'w'
2585        for p in phaselist:
2586            for h in histlist:
2587                obj.SetSeqRef(data,h)
2588                #GSASIIpath.IPyBreak()
2589                obj.Writer(h,phasenam=p,mode=mode)
2590                mode = 'a'
2591        print('...done')
2592    elif exporttype == 'Project':
2593        filename = obj.askSaveFile()
2594        if not filename: return True
2595        obj.dirname,obj.filename = os.path.split(filename)
2596        print('Writing output to file '+str(obj.filename)+"...")
2597        mode = 'w'
2598        for h in histlist:
2599            obj.SetSeqRef(data,h)
2600            obj.Writer(h,mode=mode)
2601            print('\t'+str(h)+' written')
2602            mode = 'a'
2603        print('...done')
2604
2605def ReadDIFFaX(DIFFaXfile):
2606    print 'read ',DIFFaXfile
2607    Layer = {'Laue':'-1','Cell':[False,1.,1.,1.,90.,90.,90,1.],'Width':[[10.,10.],[False,False]],
2608        'Layers':[],'Stacking':[],'Transitions':[],'Toler':0.01,'AtInfo':{}}
2609    df = open(DIFFaXfile,'r')
2610    lines = df.readlines()
2611    df.close()
2612    struct = False
2613    Struct = []
2614    stack = False
2615    Stack = []
2616    trans = False
2617    Trans = []
2618    for diff in lines:
2619        diff = diff[:-1].lower()
2620        if '!'  in diff:
2621            continue
2622        while '}' in diff: #strip comments
2623            iB = diff.index('{')
2624            iF = diff.index('}')+1
2625            if iB:
2626                diff = diff[:iB]
2627            else:
2628                diff = diff[iF:]
2629        if not diff:
2630            continue
2631        if diff.strip() == 'instrumental':
2632            continue
2633        if diff.strip() == 'structural':
2634            struct = True
2635            continue
2636        elif diff.strip() == 'stacking':
2637            struct = False
2638            stack = True
2639            continue
2640        elif diff.strip() == 'transitions':
2641            stack = False
2642            trans = True
2643            continue
2644        diff = diff.strip()
2645        if struct:
2646            if diff:
2647                Struct.append(diff)
2648        elif stack:
2649            if diff:
2650                Stack.append(diff)
2651        elif trans:
2652            if diff:
2653                Trans.append(diff)
2654   
2655#STRUCTURE records
2656    laueRec = Struct[1].split()
2657    Layer['Laue'] = laueRec[0]
2658    if Layer['Laue'] == 'unknown' and len(laueRec) > 1:
2659        Layer['Toler'] = float(laueRec[1])    #tolerance for 'unknown'?
2660    if Layer['Laue'] == '2/m(1)': Layer['Laue'] = '2/m(c)'
2661    if Layer['Laue'] == '2/m(2)': Layer['Laue'] = '2/m(ab)'
2662    cell = Struct[0].split()
2663    Layer['Cell'] = [False,float(cell[0]),float(cell[1]),float(cell[2]),90.,90.,float(cell[3]),1.0]
2664    nLayers = int(Struct[2])
2665    N = 3
2666    if 'layer' not in Struct[3]:
2667        N = 4
2668        if Struct[3] != 'infinite':
2669            width = Struct[3].split()
2670            Layer['Width'][0] = [float(width[0]),float(width[1])]
2671    for nL in range(nLayers):
2672        if '=' in Struct[N]:
2673            name = Struct[N].split('=')
2674            sameas = int(name[1])-1
2675            Layer['Layers'].append({'Name':name[0],'SameAs':Layer['Layers'][sameas]['Name'],'Symm':'None','Atoms':[]})
2676            N += 1
2677            continue
2678        Symm = 'None'
2679        if 'centro' in Struct[N+1]: Symm = '-1'
2680        Layer['Layers'].append({'Name':Struct[N],'SameAs':'','Symm':Symm,'Atoms':[]})
2681        N += 2
2682        while 'layer' not in Struct[N]:
2683            atom = Struct[N][4:].split()
2684            atomType = G2el.FixValence(Struct[N][:4].replace(' ','').strip().capitalize())
2685            if atomType not in Layer['AtInfo']:
2686                Layer['AtInfo'][atomType] = G2el.GetAtomInfo(atomType)
2687            atomName = '%s(%s)'%(atomType,atom[0])
2688            newVals = []
2689            for val in atom[1:6]:
2690                if '/' in val:
2691                    newVals.append(eval(val+'.'))
2692                else:
2693                    newVals.append(float(val))               
2694            atomRec = [atomName,atomType,newVals[0],newVals[1],newVals[2],newVals[4],newVals[3]/78.9568]
2695            Layer['Layers'][-1]['Atoms'].append(atomRec)
2696            N += 1
2697            if N > len(Struct)-1:
2698                break
2699#TRANSITIONS records
2700    transArray = []
2701    N = 0
2702    for i in range(nLayers):
2703        transArray.append([])
2704        for j in range(nLayers):
2705            vals = Trans[N].split()
2706            newVals = []
2707            for val in vals[:4]:
2708                if '/' in val:
2709                    newVals.append(eval(val+'.'))
2710                else:
2711                    newVals.append(float(val))
2712            transArray[-1].append(newVals+['',False])
2713            N += 1
2714    Layer['Transitions'] = transArray
2715#STACKING records
2716    Layer['Stacking'] = [Stack[0],'']
2717    if Stack[0] == 'recursive':
2718        Layer['Stacking'][1] = Stack[1]
2719    elif Stack[0] == 'explicit':
2720        if Stack[1] == 'random':
2721            Layer['Stacking'][1] = Stack[1]
2722        else:
2723            Layer['Stacking'][1] = 'list'
2724            Layer['Stacking'].append('')
2725            for stack in Stack[2:]:
2726                Layer['Stacking'][2] += ' '+stack
2727    return Layer
2728
2729def ReadCIF(URLorFile):
2730    '''Open a CIF, which may be specified as a file name or as a URL using PyCifRW
2731    (from James Hester).
2732    The open routine gets confused with DOS names that begin with a letter and colon
2733    "C:\dir\" so this routine will try to open the passed name as a file and if that
2734    fails, try it as a URL
2735
2736    :param str URLorFile: string containing a URL or a file name. Code will try first
2737      to open it as a file and then as a URL.
2738
2739    :returns: a PyCifRW CIF object.
2740    '''
2741    import CifFile as cif # PyCifRW from James Hester
2742
2743    # alternate approach:
2744    #import urllib
2745    #ciffile = 'file:'+urllib.pathname2url(filename)
2746   
2747    try:
2748        fp = open(URLorFile,'r')
2749        cf = cif.ReadCif(fp)
2750        fp.close()
2751        return cf
2752    except IOError:
2753        return cif.ReadCif(URLorFile)
2754
2755if __name__ == '__main__':
2756    import GSASII
2757    application = GSASII.GSASIImain(0)
2758    G2frame = application.main
2759    #app = wx.PySimpleApp()
2760    #G2frame = wx.Frame(None) # create a frame
2761    #frm.Show(True)
2762    #filename = '/tmp/notzip.zip'
2763    #filename = '/tmp/all.zip'
2764    #filename = '/tmp/11bmb_7652.zip'
2765   
2766    #selection=None, confirmoverwrite=True, parent=None
2767    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
2768    #print ExtractFileFromZip(filename,multipleselect=True)
2769    #                         #confirmread=False, confirmoverwrite=False)
2770
2771    # choicelist=[ ('a','b','c'),
2772    #              ('test1','test2'),('no choice',)]
2773    # titles = [ 'a, b or c', 'tests', 'No option here']
2774    # dlg = MultipleChoicesDialog(
2775    #     choicelist,titles,
2776    #     parent=frm)
2777    # if dlg.ShowModal() == wx.ID_OK:
2778    #     print 'Got OK'
2779    imagefile = '/tmp/NDC5_00237_3.ge3'
2780    Comments, Data, Npix, Image = GetImageData(G2frame,imagefile,imageOnly=False,ImageTag=None)
2781
2782    print("\n\nResults loaded to Comments, Data, Npix and Image\n\n")
2783
2784    GSASIIpath.IPyBreak_base()
Note: See TracBrowser for help on using the repository browser.