source: branch/2frame/GSASIIIO.py @ 2907

Last change on this file since 2907 was 2907, checked in by toby, 6 years ago

tabbed phase panel done. More to go...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 90.2 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2017-07-04 23:19:31 +0000 (Tue, 04 Jul 2017) $
4# $Author: toby $
5# $Revision: 2907 $
6# $URL: branch/2frame/GSASIIIO.py $
7# $Id: GSASIIIO.py 2907 2017-07-04 23:19:31Z toby $
8########### SVN repository information ###################
9'''
10*GSASIIIO: Misc I/O routines*
11=============================
12
13Module with miscellaneous routines for input and output. Many
14are GUI routines to interact with user.
15
16Includes support for image reading.
17
18Also includes base classes for data import routines.
19
20This module needs some work to separate wx from non-wx routines
21'''
22"""GSASIIIO: functions for IO of data
23   Copyright: 2008, Robert B. Von Dreele (Argonne National Laboratory)
24"""
25import wx
26import math
27import numpy as np
28import copy
29import cPickle
30import sys
31import re
32import random as ran
33import GSASIIpath
34GSASIIpath.SetVersionNumber("$Revision: 2907 $")
35import GSASIIdataGUI as G2gd
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 GSASIIctrlGUI 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.GPXtree.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.GPXtree.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.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(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.GPXtree.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.GPXtree.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,'File '+str(filename)+'\nImage size: '+str(h)+' x '+str(w)),
226        0,wx.ALIGN_LEFT|wx.ALL, 2)
227   
228    vsizer = wx.BoxSizer(wx.HORIZONTAL)
229    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Wavelength (\xC5) '),
230        0,wx.ALIGN_LEFT|wx.ALL, 2)
231    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'wavelength')
232    vsizer.Add(wdgt)
233    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
234
235    vsizer = wx.BoxSizer(wx.HORIZONTAL)
236    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Pixel size (\xb5m). Width '),
237        0,wx.ALIGN_LEFT|wx.ALL, 2)
238    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],0,
239                                 size=(50,-1))
240    vsizer.Add(wdgt)
241    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Height '),wx.ALIGN_LEFT|wx.ALL, 2)
242    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],1,size=(50,-1))
243    vsizer.Add(wdgt)
244    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
245
246    vsizer = wx.BoxSizer(wx.HORIZONTAL)
247    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Sample to detector (mm) '),
248        0,wx.ALIGN_LEFT|wx.ALL, 2)
249    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'distance')
250    vsizer.Add(wdgt)
251    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
252
253    vsizer = wx.BoxSizer(wx.HORIZONTAL)
254    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Beam center (pixels). X = '),
255        0,wx.ALIGN_LEFT|wx.ALL, 2)
256    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],0,size=(75,-1))
257    vsizer.Add(wdgt)
258    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Y = '),wx.ALIGN_LEFT|wx.ALL, 2)
259    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],1,size=(75,-1))
260    vsizer.Add(wdgt)
261    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
262
263    vsizer = wx.BoxSizer(wx.HORIZONTAL)
264    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Comments '),
265        0,wx.ALIGN_LEFT|wx.ALL, 2)
266    wdgt = G2G.ValidatedTxtCtrl(dlg,Comments,0,size=(250,-1))
267    vsizer.Add(wdgt)
268    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
269
270    btnsizer = wx.StdDialogButtonSizer()
271    OKbtn = wx.Button(dlg, wx.ID_OK, 'Continue')
272    OKbtn.SetDefault()
273    OKbtn.Bind(wx.EVT_BUTTON,onClose)
274    btnsizer.AddButton(OKbtn) # not sure why this is needed
275    btnsizer.Realize()
276    mainsizer.Add(btnsizer, 1, wx.ALIGN_CENTER|wx.ALL|wx.EXPAND, 5)
277    dlg.SetSizer(mainsizer)
278    dlg.CenterOnParent()
279    dlg.ShowModal()
280   
281def LoadImage2Tree(imagefile,G2frame,Comments,Data,Npix,Image):
282    '''Load an image into the tree. Saves the location of the image, as well as the
283    ImageTag (where there is more than one image in the file), if defined.
284    '''
285    ImgNames = G2gd.GetGPXtreeDataNames(G2frame,['IMG ',])
286    TreeLbl = 'IMG '+os.path.basename(imagefile)
287    ImageTag = Data.get('ImageTag')
288    if ImageTag:
289        TreeLbl += ' #'+'%04d'%(ImageTag)
290        imageInfo = (imagefile,ImageTag)
291    else:
292        imageInfo = imagefile
293    TreeName = G2obj.MakeUniqueLabel(TreeLbl,ImgNames)
294    Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=TreeName)
295    G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Comments'),Comments)
296    Imax = np.amax(Image)
297    if G2frame.imageDefault:
298        Data = copy.copy(G2frame.imageDefault)
299        Data['showLines'] = True
300        Data['ring'] = []
301        Data['rings'] = []
302        Data['cutoff'] = 10
303        Data['pixLimit'] = 20
304        Data['edgemin'] = 100000000
305        Data['calibdmin'] = 0.5
306        Data['calibskip'] = 0
307        Data['ellipses'] = []
308        Data['calibrant'] = ''
309        Data['GonioAngles'] = [0.,0.,0.]
310        Data['DetDepthRef'] = False
311    else:
312        Data['type'] = 'PWDR'
313        Data['color'] = GSASIIpath.GetConfigValue('Contour_color','Paired')
314        Data['tilt'] = 0.0
315        Data['rotation'] = 0.0
316        Data['showLines'] = False
317        Data['ring'] = []
318        Data['rings'] = []
319        Data['cutoff'] = 10
320        Data['pixLimit'] = 20
321        Data['calibdmin'] = 0.5
322        Data['calibskip'] = 0
323        Data['edgemin'] = 100000000
324        Data['ellipses'] = []
325        Data['GonioAngles'] = [0.,0.,0.]
326        Data['DetDepth'] = 0.
327        Data['DetDepthRef'] = False
328        Data['calibrant'] = ''
329        Data['IOtth'] = [2.0,5.0]
330        Data['LRazimuth'] = [0.,180.]
331        Data['azmthOff'] = 0.0
332        Data['outChannels'] = 2500
333        Data['outAzimuths'] = 1
334        Data['centerAzm'] = False
335        Data['fullIntegrate'] = False
336        Data['setRings'] = False
337        Data['background image'] = ['',-1.0]                           
338        Data['dark image'] = ['',-1.0]
339        Data['Flat Bkg'] = 0.0
340    Data['setDefault'] = False
341    Data['range'] = [(0,Imax),[0,Imax]]
342    G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Image Controls'),Data)
343    Masks = {'Points':[],'Rings':[],'Arcs':[],'Polygons':[],'Frames':[],'Thresholds':[(0,Imax),[0,Imax]]}
344    G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Masks'),Masks)
345    G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Stress/Strain'),
346        {'Type':'True','d-zero':[],'Sample phi':0.0,'Sample z':0.0,'Sample load':0.0})
347    G2frame.GPXtree.SetItemPyData(Id,[Npix,imageInfo])
348    G2frame.PickId = Id
349    G2frame.PickIdText = G2frame.GetTreeItemsList(G2frame.PickId)
350    G2frame.Image = Id
351
352def GetImageData(G2frame,imagefile,imageOnly=False,ImageTag=None,FormatName=''):
353    '''Read a single image with an image importer.
354
355    :param wx.Frame G2frame: main GSAS-II Frame and data object.
356    :param str imagefile: name of image file
357    :param bool imageOnly: If True return only the image,
358      otherwise  (default) return more (see below)
359    :param int/str ImageTag: specifies a particular image to be read from a file.
360      First image is read if None (default).
361    :param str formatName: the image reader formatName
362
363    :returns: an image as a numpy array or a list of four items:
364      Comments, Data, Npix and the Image, as selected by imageOnly
365
366    '''
367    # determine which formats are compatible with this file
368    primaryReaders = []
369    secondaryReaders = []
370    for rd in G2frame.ImportImageReaderlist:
371        flag = rd.ExtensionValidator(imagefile)
372        if flag is None: 
373            secondaryReaders.append(rd)
374        elif flag:
375            if not FormatName:
376                primaryReaders.append(rd)
377            elif FormatName == rd.formatName:
378                primaryReaders.append(rd)
379    if len(secondaryReaders) + len(primaryReaders) == 0:
380        print('Error: No matching format for file '+imagefile)
381        raise Exception('No image read')
382    fp = None
383    errorReport = ''
384    if not imagefile:
385        return
386    fp = open(imagefile,'Ur')
387    for rd in primaryReaders+secondaryReaders:
388        rd.ReInitialize() # purge anything from a previous read
389        fp.seek(0)  # rewind
390        rd.errors = "" # clear out any old errors
391        if not rd.ContentsValidator(fp): # rejected on cursory check
392            errorReport += "\n  "+rd.formatName + ' validator error'
393            if rd.errors: 
394                errorReport += ': '+rd.errors
395                continue
396        if imageOnly:
397            ParentFrame = None # prevent GUI access on reread
398        else:
399            ParentFrame = G2frame
400        if GSASIIpath.GetConfigValue('debug'):
401            flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=ImageTag)
402        else:
403            flag = False
404            try:
405                flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=ImageTag)
406            except rd.ImportException as detail:
407                rd.errors += "\n  Read exception: "+str(detail)
408            except Exception as detail:
409                import traceback
410                rd.errors += "\n  Unhandled read exception: "+str(detail)
411                rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
412        if flag: # this read succeeded
413            if rd.Image is None:
414                raise Exception('No image read. Strange!')
415            if GSASIIpath.GetConfigValue('Transpose'):
416                print 'Transposing Image!'
417                rd.Image = rd.Image.T
418            #rd.readfilename = imagefile
419            if imageOnly:
420                return rd.Image
421            else:
422                return rd.Comments,rd.Data,rd.Npix,rd.Image
423    else:
424        print('Error reading file '+imagefile)
425        print('Error messages(s)\n'+errorReport)
426        raise Exception('No image read')   
427
428def ReadImages(G2frame,imagefile):
429    '''Read one or more images from a file and put them into the Tree
430    using image importers. Called only in :meth:`AutoIntFrame.OnTimerLoop`.
431
432    :param wx.Frame G2frame: main GSAS-II Frame and data object.
433    :param str imagefile: name of image file
434
435    :returns: a list of the id's of the IMG tree items created
436    '''
437    # determine which formats are compatible with this file
438    primaryReaders = []
439    secondaryReaders = []
440    for rd in G2frame.ImportImageReaderlist:
441        flag = rd.ExtensionValidator(imagefile)
442        if flag is None:
443            secondaryReaders.append(rd)
444        elif flag:
445            primaryReaders.append(rd)
446    if len(secondaryReaders) + len(primaryReaders) == 0:
447        print('Error: No matching format for file '+imagefile)
448        raise Exception('No image read')
449    errorReport = ''
450    fp = open(imagefile,'Ur')
451    rdbuffer = {} # create temporary storage for file reader
452    for rd in primaryReaders+secondaryReaders:
453        rd.ReInitialize() # purge anything from a previous read
454        fp.seek(0)  # rewind
455        rd.errors = "" # clear out any old errors
456        if not rd.ContentsValidator(fp): # rejected on cursory check
457            errorReport += "\n  "+rd.formatName + ' validator error'
458            if rd.errors: 
459                errorReport += ': '+rd.errors
460                continue
461        ParentFrame = G2frame
462        block = 0
463        repeat = True
464        CreatedIMGitems = []
465        while repeat: # loop if the reader asks for another pass on the file
466            block += 1
467            repeat = False
468            if GSASIIpath.GetConfigValue('debug'):
469                flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=block,Buffer=rdbuffer)
470            else:
471                flag = False
472                try:
473                    flag = rd.Reader(imagefile,fp,ParentFrame,blocknum=block,Buffer=rdbuffer)
474                except rd.ImportException as detail:
475                    rd.errors += "\n  Read exception: "+str(detail)
476                except Exception as detail:
477                    import traceback
478                    rd.errors += "\n  Unhandled read exception: "+str(detail)
479                    rd.errors += "\n  Traceback info:\n"+str(traceback.format_exc())
480            if flag: # this read succeeded
481                if rd.Image is None:
482                    raise Exception('No image read. Strange!')
483                if GSASIIpath.GetConfigValue('Transpose'):
484                    print 'Transposing Image!'
485                    rd.Image = rd.Image.T
486                rd.Data['ImageTag'] = rd.repeatcount
487                LoadImage2Tree(imagefile,G2frame,rd.Comments,rd.Data,rd.Npix,rd.Image)
488                repeat = rd.repeat
489            CreatedIMGitems.append(G2frame.Image)
490        if CreatedIMGitems: return CreatedIMGitems
491    else:
492        print('Error reading file '+imagefile)
493        print('Error messages(s)\n'+errorReport)
494        return []
495        #raise Exception('No image read')   
496
497def SaveMultipleImg(G2frame):
498    if not G2frame.GPXtree.GetCount():
499        print 'no images!'
500        return
501    choices = G2gd.GetGPXtreeDataNames(G2frame,['IMG ',])
502    if len(choices) == 1:
503        names = choices
504    else:
505        dlg = G2G.G2MultiChoiceDialog(G2frame,'Stress/Strain fitting','Select images to fit:',choices)
506        dlg.SetSelections([])
507        names = []
508        if dlg.ShowModal() == wx.ID_OK:
509            names = [choices[sel] for sel in dlg.GetSelections()]
510        dlg.Destroy()
511    if not names: return
512    for name in names:
513        Id = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, name)
514        Npix,imagefile,imagetag = G2frame.GPXtree.GetImageLoc(Id)
515        imroot = os.path.splitext(imagefile)[0]
516        if imagetag:
517            imroot += '_' + str(imagetag)
518        Data = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id, 'Image Controls'))
519        print('Writing '+imroot+'.imctrl')
520        File = open(imroot+'.imctrl','w')
521        keys = ['type','wavelength','calibrant','distance','center',
522                    'tilt','rotation','azmthOff','fullIntegrate','LRazimuth',
523                    'IOtth','outChannels','outAzimuths','invert_x','invert_y','DetDepth',
524                    'calibskip','pixLimit','cutoff','calibdmin','chisq','Flat Bkg',
525                    'binType','SampleShape','PolaVal','SampleAbs','dark image','background image']
526        for key in keys:
527            if key not in Data: continue    #uncalibrated!
528            File.write(key+':'+str(Data[key])+'\n')
529        File.close()
530        mask = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id, 'Masks'))
531        G2imG.CleanupMasks(mask)
532        print('Writing '+imroot+'.immask')
533        File = open(imroot+'.immask','w')
534        for key in ['Points','Rings','Arcs','Polygons','Frames','Thresholds']:
535            File.write(key+':'+str(mask[key])+'\n')
536        File.close()
537       
538def PutG2Image(filename,Comments,Data,Npix,image):
539    'Write an image as a python pickle - might be better as an .edf file?'
540    File = open(filename,'wb')
541    cPickle.dump([Comments,Data,Npix,image],File,1)
542    File.close()
543    return
544   
545def ProjFileOpen(G2frame,showProvenance=True):
546    'Read a GSAS-II project file and load into the G2 data tree'
547    if not os.path.exists(G2frame.GSASprojectfile):
548        print ('\n*** Error attempt to open project file that does not exist:\n   '+
549               str(G2frame.GSASprojectfile))
550        return
551    LastSavedUsing = None
552    file = open(G2frame.GSASprojectfile,'rb')
553    if showProvenance: print 'loading from file: ',G2frame.GSASprojectfile
554    G2frame.SetTitle("GSAS-II data tree: "+
555                     os.path.split(G2frame.GSASprojectfile)[1])
556    wx.BeginBusyCursor()
557    try:
558        while True:
559            try:
560                data = cPickle.load(file)
561            except EOFError:
562                break
563            datum = data[0]
564           
565            Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=datum[0])
566            if datum[0].startswith('PWDR'):               
567                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
568                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
569                G2frame.GPXtree.SetItemPyData(Id,datum[1][:3])  #temp. trim off junk (patch?)
570            elif datum[0].startswith('HKLF'): 
571                if 'ranId' not in datum[1][0]: # patch: add random Id if not present
572                    datum[1][0]['ranId'] = ran.randint(0,sys.maxint)
573                G2frame.GPXtree.SetItemPyData(Id,datum[1])
574            else:
575                G2frame.GPXtree.SetItemPyData(Id,datum[1])             
576                if datum[0] == 'Controls' and 'LastSavedUsing' in datum[1]:
577                    LastSavedUsing = datum[1]['LastSavedUsing']
578                if datum[0] == 'Controls' and 'PythonVersions' in datum[1] and GSASIIpath.GetConfigValue('debug') and showProvenance:
579                    print('Packages used to create .GPX file:')
580                    if 'dict' in str(type(datum[1]['PythonVersions'])):  #patch
581                        for p in sorted(datum[1]['PythonVersions'],key=lambda s: s.lower()):
582                            print({:<14s}: {:s}".format(p[0],p[1]))
583                    else:
584                        for p in datum[1]['PythonVersions']:
585                            print({:<12s} {:s}".format(p[0]+':',p[1]))
586            oldPDF = False
587            for datus in data[1:]:
588#patch - 1/23/17 PDF cleanup
589                if datus[0][:4] in ['I(Q)','S(Q)','F(Q)','G(R)']:
590                    oldPDF = True
591                    data[1][1][datus[0][:4]] = copy.deepcopy(datus[1][:2])
592                    continue
593#end PDF cleanup
594                sub = G2frame.GPXtree.AppendItem(Id,datus[0])
595#patch
596                if datus[0] == 'Instrument Parameters' and len(datus[1]) == 1:
597                    if datum[0].startswith('PWDR'):
598                        datus[1] = [dict(zip(datus[1][3],zip(datus[1][0],datus[1][1],datus[1][2]))),{}]
599                    else:
600                        datus[1] = [dict(zip(datus[1][2],zip(datus[1][0],datus[1][1]))),{}]
601                    for item in datus[1][0]:               #zip makes tuples - now make lists!
602                        datus[1][0][item] = list(datus[1][0][item])
603#end patch
604                G2frame.GPXtree.SetItemPyData(sub,datus[1])
605            if 'PDF ' in datum[0][:4] and oldPDF:
606                sub = G2frame.GPXtree.AppendItem(Id,'PDF Peaks')
607                G2frame.GPXtree.SetItemPyData(sub,{'Limits':[1.,5.],'Background':[2,[0.,-0.2*np.pi],False],'Peaks':[]})
608            if datum[0].startswith('IMG'):                   #retrieve image default flag & data if set
609                Data = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id,'Image Controls'))
610                if Data['setDefault']:
611                    G2frame.imageDefault = Data               
612        file.close()
613        if LastSavedUsing:
614            print('GPX load successful. Last saved with GSAS-II revision '+LastSavedUsing)
615        else:
616            print('project load successful')
617        G2frame.NewPlot = True
618    except:
619        msg = wx.MessageDialog(G2frame,message="Error reading file "+
620            str(G2frame.GSASprojectfile)+". This is not a GSAS-II .gpx file",
621            caption="Load Error",style=wx.ICON_ERROR | wx.OK | wx.STAY_ON_TOP)
622        msg.ShowModal()
623    finally:
624        wx.EndBusyCursor()
625        G2frame.Status.SetStatusText('Mouse RB click item to refresh/raise; RB drag/drop to reorder')
626   
627def ProjFileSave(G2frame):
628    'Save a GSAS-II project file'
629    if not G2frame.GPXtree.IsEmpty():
630        file = open(G2frame.GSASprojectfile,'wb')
631        print 'save to file: ',G2frame.GSASprojectfile
632        # stick the file name into the tree and version info into tree so they are saved.
633        # (Controls should always be created at this point)
634        try:
635            Controls = G2frame.GPXtree.GetItemPyData(
636                G2gd.GetGPXtreeItemId(G2frame,G2frame.root, 'Controls'))
637            Controls['LastSavedAs'] = os.path.abspath(G2frame.GSASprojectfile)
638            Controls['LastSavedUsing'] = str(GSASIIpath.GetVersionNumber())
639            Controls['PythonVersions'] = G2frame.PackageVersions
640        except:
641            pass
642        wx.BeginBusyCursor()
643        try:
644            item, cookie = G2frame.GPXtree.GetFirstChild(G2frame.root)
645            while item:
646                data = []
647                name = G2frame.GPXtree.GetItemText(item)
648                data.append([name,G2frame.GPXtree.GetItemPyData(item)])
649                item2, cookie2 = G2frame.GPXtree.GetFirstChild(item)
650                while item2:
651                    name = G2frame.GPXtree.GetItemText(item2)
652                    data.append([name,G2frame.GPXtree.GetItemPyData(item2)])
653                    item2, cookie2 = G2frame.GPXtree.GetNextChild(item, cookie2)                           
654                item, cookie = G2frame.GPXtree.GetNextChild(G2frame.root, cookie)                           
655                cPickle.dump(data,file,1)
656            file.close()
657            pth = os.path.split(os.path.abspath(G2frame.GSASprojectfile))[0]
658            if GSASIIpath.GetConfigValue('Save_paths'): G2G.SaveGPXdirectory(pth)
659            G2frame.LastGPXdir = pth
660        finally:
661            wx.EndBusyCursor()
662        print('project save successful')
663
664def SaveIntegration(G2frame,PickId,data,Overwrite=False):
665    'Save image integration results as powder pattern(s)'
666    azms = G2frame.Integrate[1]
667    X = G2frame.Integrate[2][:-1]
668    N = len(X)
669    Id = G2frame.GPXtree.GetItemParent(PickId)
670    name = G2frame.GPXtree.GetItemText(Id)
671    name = name.replace('IMG ',data['type']+' ')
672    Comments = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame,Id, 'Comments'))
673    if 'PWDR' in name:
674        names = ['Type','Lam','Zero','Polariz.','U','V','W','X','Y','SH/L','Azimuth'] 
675        codes = [0 for i in range(11)]
676    elif 'SASD' in name:
677        names = ['Type','Lam','Zero','Azimuth'] 
678        codes = [0 for i in range(4)]
679        X = 4.*np.pi*npsind(X/2.)/data['wavelength']    #convert to q
680    Xminmax = [X[0],X[-1]]
681    Azms = []
682    dazm = 0.
683    if data['fullIntegrate'] and data['outAzimuths'] == 1:
684        Azms = [45.0,]                              #a poor man's average?
685    else:
686        for i,azm in enumerate(azms[:-1]):
687            if azm > 360. and azms[i+1] > 360.:
688                Azms.append(G2img.meanAzm(azm%360.,azms[i+1]%360.))
689            else:   
690                Azms.append(G2img.meanAzm(azm,azms[i+1]))
691        dazm = np.min(np.abs(np.diff(azms)))/2.
692    G2frame.IntgOutList = []
693    for i,azm in enumerate(azms[:-1]):
694        Aname = name+" Azm= %.2f"%((azm+dazm)%360.)
695        item, cookie = G2frame.GPXtree.GetFirstChild(G2frame.root)
696        # if Overwrite delete any duplicate
697        if Overwrite and G2gd.GetGPXtreeItemId(G2frame,G2frame.root,Aname):
698            print('Replacing '+Aname)
699            item = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,Aname)
700            G2frame.GPXtree.Delete(item)
701        else:
702            nOcc = 0
703            while item:
704                Name = G2frame.GPXtree.GetItemText(item)
705                if Aname in Name:
706                    nOcc += 1
707                item, cookie = G2frame.GPXtree.GetNextChild(G2frame.root, cookie)
708            if nOcc:
709                Aname += '(%d)'%(nOcc)
710        Sample = G2obj.SetDefaultSample()       #set as Debye-Scherrer
711        Sample['Gonio. radius'] = data['distance']
712        Sample['Omega'] = data['GonioAngles'][0]
713        Sample['Chi'] = data['GonioAngles'][1]
714        Sample['Phi'] = data['GonioAngles'][2]
715        Sample['Azimuth'] = (azm+dazm)%360.    #put here as bin center
716        polariz = 0.99    #set default polarization for synchrotron radiation!
717        for item in Comments:
718            if 'polariz' in item:
719                try:
720                    polariz = float(item.split('=')[1])
721                except:
722                    polariz = 0.99
723        if 'PWDR' in Aname:
724            parms = ['PXC',data['wavelength'],0.0,polariz,1.0,-0.10,0.4,0.30,1.0,0.0001,Azms[i]]
725        elif 'SASD' in Aname:
726            Sample['Trans'] = data['SampleAbs'][0]
727            parms = ['LXC',data['wavelength'],0.0,Azms[i]]
728        Y = G2frame.Integrate[0][i]
729        Ymin = np.min(Y)
730        Ymax = np.max(Y)
731        W = np.where(Y>0.,1./Y,1.e-6)                    #probably not true
732        Id = G2frame.GPXtree.AppendItem(parent=G2frame.root,text=Aname)
733        G2frame.IntgOutList.append(Id)
734        G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Comments'),Comments)                   
735        G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Limits'),[tuple(Xminmax),Xminmax])
736        if 'PWDR' in Aname:
737            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Background'),[['chebyschev',1,3,1.0,0.0,0.0],
738                {'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]}])
739        inst = [dict(zip(names,zip(parms,parms,codes))),{}]
740        for item in inst[0]:
741            inst[0][item] = list(inst[0][item])
742        G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Instrument Parameters'),inst)
743        if 'PWDR' in Aname:
744            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Sample Parameters'),Sample)
745            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Peak List'),{'sigDict':{},'peaks':[]})
746            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Index Peak List'),[[],[]])
747            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Unit Cells List'),[])
748            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Reflection Lists'),{})
749        elif 'SASD' in Aname:             
750            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Substances'),G2pdG.SetDefaultSubstances())
751            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Sample Parameters'),Sample)
752            G2frame.GPXtree.SetItemPyData(G2frame.GPXtree.AppendItem(Id,text='Models'),G2pdG.SetDefaultSASDModel())
753        valuesdict = {
754            'wtFactor':1.0,
755            'Dummy':False,
756            'ranId':ran.randint(0,sys.maxint),
757            'Offset':[0.0,0.0],'delOffset':0.02*Ymax,'refOffset':-0.1*Ymax,'refDelt':0.1*Ymax,
758            'qPlot':False,'dPlot':False,'sqrtPlot':False,'Yminmax':[Ymin,Ymax]
759            }
760        G2frame.GPXtree.SetItemPyData(
761            Id,[valuesdict,
762                [np.array(X),np.array(Y),np.array(W),np.zeros(N),np.zeros(N),np.zeros(N)]])
763    return Id       #last powder pattern generated
764   
765def XYsave(G2frame,XY,labelX='X',labelY='Y',names=None):
766    'Save XY table data'
767    pth = G2G.GetExportPath(G2frame)
768    dlg = wx.FileDialog(
769        G2frame, 'Enter csv filename for XY table', pth, '',
770        'XY table file (*.csv)|*.csv',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
771    try:
772        if dlg.ShowModal() == wx.ID_OK:
773            filename = dlg.GetPath()
774            filename = os.path.splitext(filename)[0]+'.csv'
775            File = open(filename,'w')
776        else:
777            filename = None
778    finally:
779        dlg.Destroy()
780    if not filename:
781        return
782    for i in range(len(XY)):
783        if names != None:
784            header = '%s,%s(%s)\n'%(labelX,labelY,names[i])
785        else:
786            header = '%s,%s(%d)\n'%(labelX,labelY,i)
787        File.write(header)
788        for x,y in XY[i].T:
789            File.write('%.3f,%.3f\n'%(x,y))   
790    File.close()
791    print ' XY data saved to: ',filename
792           
793def PDFSave(G2frame,exports,PDFsaves):
794    'Save a PDF I(Q), S(Q), F(Q) and G(r)  in column formats'
795    import scipy.interpolate as scintp
796    for export in exports:
797        PickId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, export)
798        PDFControls = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame, PickId,'PDF Controls'))
799        if PDFsaves[0]:     #I(Q)
800            iqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.iq')
801            iqdata = PDFControls['I(Q)'][0]
802            iqfxn = scintp.interp1d(iqdata[0],iqdata[1],kind='linear')
803            iqfile = open(iqfilename,'w')
804            iqfile.write('#T I(Q) %s\n'%(export))
805            iqfile.write('#L Q     I(Q)\n')
806            qnew = np.arange(iqdata[0][0],iqdata[0][-1],0.005)
807            iqnew = zip(qnew,iqfxn(qnew))
808            for q,iq in iqnew:
809                iqfile.write("%15.6g %15.6g\n" % (q,iq))
810            iqfile.close()
811            print ' I(Q) saved to: ',iqfilename
812           
813        if PDFsaves[1]:     #S(Q)
814            sqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.sq')
815            sqdata = PDFControls['S(Q)'][1]
816            sqfxn = scintp.interp1d(sqdata[0],sqdata[1],kind='linear')
817            sqfile = open(sqfilename,'w')
818            sqfile.write('#T S(Q) %s\n'%(export))
819            sqfile.write('#L Q     S(Q)\n')
820            qnew = np.arange(sqdata[0][0],sqdata[0][-1],0.005)
821            sqnew = zip(qnew,sqfxn(qnew))
822            for q,sq in sqnew:
823                sqfile.write("%15.6g %15.6g\n" % (q,sq))
824            sqfile.close()
825            print ' S(Q) saved to: ',sqfilename
826           
827        if PDFsaves[2]:     #F(Q)
828            fqfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.fq')
829            fqdata = PDFControls['F(Q)'][1]
830            fqfxn = scintp.interp1d(fqdata[0],fqdata[1],kind='linear')
831            fqfile = open(sqfilename,'w')
832            fqfile.write('#T F(Q) %s\n'%(export))
833            fqfile.write('#L Q     F(Q)\n')
834            qnew = np.arange(sqdata[0][0],sqdata[0][-1],0.005)
835            fqnew = zip(qnew,fqfxn(qnew))
836            for q,fq in fqnew:
837                fqfile.write("%15.6g %15.6g\n" % (q,fq))
838            fqfile.close()
839            print ' F(Q) saved to: ',fqfilename
840           
841        if PDFsaves[3]:     #G(R)
842            grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
843            grdata = PDFControls['G(R)'][1]
844            grfxn = scintp.interp1d(grdata[0],grdata[1],kind='linear')
845            grfile = open(grfilename,'w')
846            grfile.write('#T G(R) %s\n'%(export))
847            grfile.write('#L R     G(R)\n')
848            rnew = np.arange(grdata[0][0],grdata[0][-1],0.010)
849            grnew = zip(rnew,grfxn(rnew))
850            for r,gr in grnew:
851                grfile.write("%15.6g %15.6g\n" % (r,gr))
852            grfile.close()
853            print ' G(R) saved to: ',grfilename
854       
855        if PDFsaves[4]: #pdfGUI file for G(R)
856            pId = G2gd.GetGPXtreeItemId(G2frame, G2frame.root, 'PWDR'+export[4:])
857            Inst = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame, pId,'Instrument Parameters'))[0]
858            Limits = G2frame.GPXtree.GetItemPyData(G2gd.GetGPXtreeItemId(G2frame, pId,'Limits'))
859            grfilename = ospath.join(G2frame.dirname,export.replace(' ','_')[5:]+'.gr')
860            grdata = PDFControls['G(R)'][1]
861            qdata = PDFControls['I(Q)'][1][0]
862            grfxn = scintp.interp1d(grdata[0],grdata[1],kind='linear')
863            grfile = open(grfilename,'w')
864            rnew = np.arange(grdata[0][0],grdata[0][-1],0.010)
865            grnew = zip(rnew,grfxn(rnew))
866
867            grfile.write('[DEFAULT]\n')
868            grfile.write('\n')
869            grfile.write('version = GSAS-II-v'+str(GSASIIpath.GetVersionNumber())+'\n')
870            grfile.write('\n')
871            grfile.write('# input and output specifications\n')
872            grfile.write('dataformat = Qnm\n')
873            grfile.write('inputfile = %s\n'%(PDFControls['Sample']['Name']))
874            grfile.write('backgroundfile = %s\n'%(PDFControls['Sample Bkg.']['Name']))
875            grfile.write('outputtype = gr\n')
876            grfile.write('\n')
877            grfile.write('# PDF calculation setup\n')
878            if 'x' in Inst['Type']:
879                grfile.write('mode = %s\n'%('xray'))
880            elif 'N' in Inst['Type']:
881                grfile.write('mode = %s\n'%('neutron'))
882            wave = G2mth.getMeanWave(Inst)
883            grfile.write('wavelength = %.5f\n'%(wave))
884            formula = ''
885            for el in PDFControls['ElList']:
886                formula += el
887                num = PDFControls['ElList'][el]['FormulaNo']
888                if num == round(num):
889                    formula += '%d'%(int(num))
890                else:
891                    formula += '%.2f'%(num)
892            grfile.write('composition = %s\n'%(formula))
893            grfile.write('bgscale = %.3f\n'%(-PDFControls['Sample Bkg.']['Mult']))
894            highQ = 2.*np.pi/G2lat.Pos2dsp(Inst,Limits[1][1])
895            grfile.write('qmaxinst = %.2f\n'%(highQ))
896            grfile.write('qmin = %.5f\n'%(qdata[0]))
897            grfile.write('qmax = %.4f\n'%(qdata[-1]))
898            grfile.write('rmin = %.2f\n'%(PDFControls['Rmin']))
899            grfile.write('rmax = %.2f\n'%(PDFControls['Rmax']))
900            grfile.write('rstep = 0.01\n')
901           
902           
903            grfile.write('\n')
904            grfile.write('# End of config '+63*'-')
905            grfile.write('\n')
906            grfile.write('#### start data\n')
907            grfile.write('#S 1\n')
908            grfile.write('#L r($\AA$)  G($\AA^{-2}$)\n')           
909            for r,gr in grnew:
910                grfile.write("%15.2F %15.6F\n" % (r,gr))
911            grfile.close()
912            print ' G(R) saved to: ',grfilename
913   
914def PeakListSave(G2frame,file,peaks):
915    'Save powder peaks to a data file'
916    print 'save peak list to file: ',G2frame.peaklistfile
917    if not peaks:
918        dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
919        try:
920            dlg.ShowModal()
921        finally:
922            dlg.Destroy()
923        return
924    for peak in peaks:
925        file.write("%10.4f %12.2f %10.3f %10.3f \n" % \
926            (peak[0],peak[2],peak[4],peak[6]))
927    print 'peak list saved'
928             
929def IndexPeakListSave(G2frame,peaks):
930    'Save powder peaks from the indexing list'
931    file = open(G2frame.peaklistfile,'wa')
932    print 'save index peak list to file: ',G2frame.peaklistfile
933    wx.BeginBusyCursor()
934    try:
935        if not peaks:
936            dlg = wx.MessageDialog(G2frame, 'No peaks!', 'Nothing to save!', wx.OK)
937            try:
938                dlg.ShowModal()
939            finally:
940                dlg.Destroy()
941            return
942        for peak in peaks:
943            file.write("%12.6f\n" % (peak[7]))
944        file.close()
945    finally:
946        wx.EndBusyCursor()
947    print 'index peak list saved'
948   
949class MultipleChoicesDialog(wx.Dialog):
950    '''A dialog that offers a series of choices, each with a
951    title and a wx.Choice widget. Intended to be used Modally.
952    typical input:
953
954        *  choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
955        *  headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
956       
957    selections are placed in self.chosen when OK is pressed
958
959    Also see GSASIIctrlGUI
960    '''
961    def __init__(self,choicelist,headinglist,
962                 head='Select options',
963                 title='Please select from options below',
964                 parent=None):
965        self.chosen = []
966        wx.Dialog.__init__(
967            self,parent,wx.ID_ANY,head, 
968            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
969        panel = wx.Panel(self)
970        mainSizer = wx.BoxSizer(wx.VERTICAL)
971        mainSizer.Add((10,10),1)
972        topLabl = wx.StaticText(panel,wx.ID_ANY,title)
973        mainSizer.Add(topLabl,0,wx.ALIGN_CENTER_VERTICAL|wx.CENTER,10)
974        self.ChItems = []
975        for choice,lbl in zip(choicelist,headinglist):
976            mainSizer.Add((10,10),1)
977            self.chosen.append(0)
978            topLabl = wx.StaticText(panel,wx.ID_ANY,' '+lbl)
979            mainSizer.Add(topLabl,0,wx.ALIGN_LEFT,10)
980            self.ChItems.append(wx.Choice(self, wx.ID_ANY, (100, 50), choices = choice))
981            mainSizer.Add(self.ChItems[-1],0,wx.ALIGN_CENTER,10)
982
983        OkBtn = wx.Button(panel,-1,"Ok")
984        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
985        cancelBtn = wx.Button(panel,-1,"Cancel")
986        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
987        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
988        btnSizer.Add((20,20),1)
989        btnSizer.Add(OkBtn)
990        btnSizer.Add((20,20),1)
991        btnSizer.Add(cancelBtn)
992        btnSizer.Add((20,20),1)
993        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
994        panel.SetSizer(mainSizer)
995        panel.Fit()
996        self.Fit()
997       
998    def OnOk(self,event):
999        parent = self.GetParent()
1000        if parent is not None: parent.Raise()
1001        # save the results from the choice widgets
1002        self.chosen = []
1003        for w in self.ChItems:
1004            self.chosen.append(w.GetSelection())
1005        self.EndModal(wx.ID_OK)             
1006           
1007    def OnCancel(self,event):
1008        parent = self.GetParent()
1009        if parent is not None: parent.Raise()
1010        self.chosen = []
1011        self.EndModal(wx.ID_CANCEL)             
1012           
1013def ExtractFileFromZip(filename, selection=None, confirmread=True,
1014                       confirmoverwrite=True, parent=None,
1015                       multipleselect=False):
1016    '''If the filename is a zip file, extract a file from that
1017    archive.
1018
1019    :param list Selection: used to predefine the name of the file
1020      to be extracted. Filename case and zip directory name are
1021      ignored in selection; the first matching file is used.
1022
1023    :param bool confirmread: if True asks the user to confirm before expanding
1024      the only file in a zip
1025
1026    :param bool confirmoverwrite: if True asks the user to confirm
1027      before overwriting if the extracted file already exists
1028
1029    :param bool multipleselect: if True allows more than one zip
1030      file to be extracted, a list of file(s) is returned.
1031      If only one file is present, do not ask which one, otherwise
1032      offer a list of choices (unless selection is used).
1033   
1034    :returns: the name of the file that has been created or a
1035      list of files (see multipleselect)
1036
1037    If the file is not a zipfile, return the name of the input file.
1038    If the zipfile is empty or no file has been selected, return None
1039    '''
1040    import zipfile # do this now, since we can save startup time by doing this only on need
1041    import shutil
1042    zloc = os.path.split(filename)[0]
1043    if not zipfile.is_zipfile(filename):
1044        #print("not zip")
1045        return filename
1046
1047    z = zipfile.ZipFile(filename,'r')
1048    zinfo = z.infolist()
1049
1050    if len(zinfo) == 0:
1051        #print('Zip has no files!')
1052        zlist = [-1]
1053    if selection:
1054        choices = [os.path.split(i.filename)[1].lower() for i in zinfo]
1055        if selection.lower() in choices:
1056            zlist = [choices.index(selection.lower())]
1057        else:
1058            print('debug: file '+str(selection)+' was not found in '+str(filename))
1059            zlist = [-1]
1060    elif len(zinfo) == 1 and confirmread:
1061        result = wx.ID_NO
1062        dlg = wx.MessageDialog(
1063            parent,
1064            'Is file '+str(zinfo[0].filename)+
1065            ' what you want to extract from '+
1066            str(os.path.split(filename)[1])+'?',
1067            'Confirm file', 
1068            wx.YES_NO | wx.ICON_QUESTION)
1069        try:
1070            result = dlg.ShowModal()
1071        finally:
1072            dlg.Destroy()
1073        if result == wx.ID_NO:
1074            zlist = [-1]
1075        else:
1076            zlist = [0]
1077    elif len(zinfo) == 1:
1078        zlist = [0]
1079    elif multipleselect:
1080        # select one or more from a from list
1081        choices = [i.filename for i in zinfo]
1082        dlg = G2G.G2MultiChoiceDialog(parent,'Select file(s) to extract from zip file '+str(filename),
1083            'Choose file(s)',choices)
1084        if dlg.ShowModal() == wx.ID_OK:
1085            zlist = dlg.GetSelections()
1086        else:
1087            zlist = []
1088        dlg.Destroy()
1089    else:
1090        # select one from a from list
1091        choices = [i.filename for i in zinfo]
1092        dlg = wx.SingleChoiceDialog(parent,
1093            'Select file to extract from zip file'+str(filename),'Choose file',
1094            choices,)
1095        if dlg.ShowModal() == wx.ID_OK:
1096            zlist = [dlg.GetSelection()]
1097        else:
1098            zlist = [-1]
1099        dlg.Destroy()
1100       
1101    outlist = []
1102    for zindex in zlist:
1103        if zindex >= 0:
1104            efil = os.path.join(zloc, os.path.split(zinfo[zindex].filename)[1])
1105            if os.path.exists(efil) and confirmoverwrite:
1106                result = wx.ID_NO
1107                dlg = wx.MessageDialog(parent,
1108                    'File '+str(efil)+' already exists. OK to overwrite it?',
1109                    'Confirm overwrite',wx.YES_NO | wx.ICON_QUESTION)
1110                try:
1111                    result = dlg.ShowModal()
1112                finally:
1113                    dlg.Destroy()
1114                if result == wx.ID_NO:
1115                    zindex = -1
1116        if zindex >= 0:
1117            # extract the file to the current directory, regardless of it's original path
1118            #z.extract(zinfo[zindex],zloc)
1119            eloc,efil = os.path.split(zinfo[zindex].filename)
1120            outfile = os.path.join(zloc, efil)
1121            fpin = z.open(zinfo[zindex])
1122            fpout = file(outfile, "wb")
1123            shutil.copyfileobj(fpin, fpout)
1124            fpin.close()
1125            fpout.close()
1126            outlist.append(outfile)
1127    z.close()
1128    if multipleselect and len(outlist) >= 1:
1129        return outlist
1130    elif len(outlist) == 1:
1131        return outlist[0]
1132    else:
1133        return None
1134
1135######################################################################
1136# base classes for reading various types of data files
1137#   not used directly, only by subclassing
1138######################################################################
1139def BlockSelector(ChoiceList, ParentFrame=None,title='Select a block',
1140    size=None, header='Block Selector',useCancel=True):
1141    ''' Provide a wx dialog to select a block if the file contains more
1142    than one set of data and one must be selected
1143    '''
1144    if useCancel:
1145        dlg = wx.SingleChoiceDialog(
1146            ParentFrame,title, header,ChoiceList)
1147    else:
1148        dlg = wx.SingleChoiceDialog(
1149            ParentFrame,title, header,ChoiceList,
1150            style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK|wx.CENTRE)
1151    if size: dlg.SetSize(size)
1152    dlg.CenterOnParent()
1153    if dlg.ShowModal() == wx.ID_OK:
1154        sel = dlg.GetSelection()
1155        return sel
1156    else:
1157        return None
1158    dlg.Destroy()
1159
1160def MultipleBlockSelector(ChoiceList, ParentFrame=None,
1161    title='Select a block',size=None, header='Block Selector'):
1162    '''Provide a wx dialog to select a block of data if the
1163    file contains more than one set of data and one must be
1164    selected.
1165
1166    :returns: a list of the selected blocks
1167    '''
1168    dlg = wx.MultiChoiceDialog(ParentFrame,title, header,ChoiceList+['Select all'],
1169        wx.CHOICEDLG_STYLE)
1170    dlg.CenterOnScreen()
1171    if size: dlg.SetSize(size)
1172    if dlg.ShowModal() == wx.ID_OK:
1173        sel = dlg.GetSelections()
1174    else:
1175        return []
1176    dlg.Destroy()
1177    selected = []
1178    if len(ChoiceList) in sel:
1179        return range(len(ChoiceList))
1180    else:
1181        return sel
1182    return selected
1183
1184def MultipleChoicesSelector(choicelist, headinglist, ParentFrame=None, **kwargs):
1185    '''A modal dialog that offers a series of choices, each with a title and a wx.Choice
1186    widget. Typical input:
1187   
1188       * choicelist=[ ('a','b','c'), ('test1','test2'),('no choice',)]
1189       
1190       * headinglist = [ 'select a, b or c', 'select 1 of 2', 'No option here']
1191       
1192    optional keyword parameters are: head (window title) and title
1193    returns a list of selected indicies for each choice (or None)
1194    '''
1195    result = None
1196    dlg = MultipleChoicesDialog(choicelist,headinglist,
1197        parent=ParentFrame, **kwargs)         
1198    dlg.CenterOnParent()
1199    if dlg.ShowModal() == wx.ID_OK:
1200        result = dlg.chosen
1201    dlg.Destroy()
1202    return result
1203
1204def PhaseSelector(ChoiceList, ParentFrame=None,
1205    title='Select a phase', size=None,header='Phase Selector'):
1206    ''' Provide a wx dialog to select a phase if the file contains more
1207    than one phase
1208    '''
1209    return BlockSelector(ChoiceList,ParentFrame,title,
1210        size,header)
1211
1212######################################################################
1213def striphist(var,insChar=''):
1214    'strip a histogram number from a var name'
1215    sv = var.split(':')
1216    if len(sv) <= 1: return var
1217    if sv[1]:
1218        sv[1] = insChar
1219    return ':'.join(sv)
1220class ExportBaseclass(object):
1221    '''Defines a base class for the exporting of GSAS-II results.
1222
1223    This class is subclassed in the various exports/G2export_*.py files. Those files
1224    are imported in :meth:`GSASIIdataGUI.GSASII._init_Exports` which defines the
1225    appropriate menu items for each one and the .Exporter method is called
1226    directly from the menu item.
1227
1228    Routines may also define a .Writer method, which is used to write a single
1229    file without invoking any GUI objects.
1230    '''
1231    def __init__(self,G2frame,formatName,extension,longFormatName=None,):
1232        self.G2frame = G2frame
1233        self.formatName = formatName # short string naming file type
1234        self.extension = extension
1235        if longFormatName: # longer string naming file type
1236            self.longFormatName = longFormatName
1237        else:
1238            self.longFormatName = formatName
1239        self.OverallParms = {}
1240        self.Phases = {}
1241        self.Histograms = {}
1242        self.powderDict = {}
1243        self.xtalDict = {}
1244        self.parmDict = {}
1245        self.sigDict = {}
1246        # updated in InitExport:
1247        self.currentExportType = None # type of export that has been requested
1248        # updated in ExportSelect (when used):
1249        self.phasenam = None # a list of selected phases
1250        self.histnam = None # a list of selected histograms
1251        self.filename = None # name of file to be written (single export) or template (multiple files)
1252        self.dirname = '' # name of directory where file(s) will be written
1253        self.fullpath = '' # name of file being written -- full path
1254       
1255        # items that should be defined in a subclass of this class
1256        self.exporttype = []  # defines the type(s) of exports that the class can handle.
1257        # The following types are defined: 'project', "phase", "powder", "single"
1258        self.multiple = False # set as True if the class can export multiple phases or histograms
1259        # self.multiple is ignored for "project" exports
1260
1261    def InitExport(self,event):
1262        '''Determines the type of menu that called the Exporter and
1263        misc initialization.
1264        '''
1265        self.filename = None # name of file to be written (single export)
1266        self.dirname = '' # name of file to be written (multiple export)
1267        if event:
1268            self.currentExportType = self.G2frame.ExportLookup.get(event.Id)
1269
1270    def MakePWDRfilename(self,hist):
1271        '''Make a filename root (no extension) from a PWDR histogram name
1272
1273        :param str hist: the histogram name in data tree (starts with "PWDR ")
1274        '''
1275        file0 = ''
1276        file1 = hist[5:]
1277        # replace repeated blanks
1278        while file1 != file0:
1279            file0 = file1
1280            file1 = file0.replace('  ',' ').strip()
1281        file0 = file1.replace('Azm= ','A')
1282        # if angle has unneeded decimal places on aziumuth, remove them
1283        if file0[-3:] == '.00': file0 = file0[:-3]
1284        file0 = file0.replace('.','_')
1285        file0 = file0.replace(' ','_')
1286        return file0
1287
1288    def ExportSelect(self,AskFile='ask'):
1289        '''Selects histograms or phases when needed. Sets a default file name when
1290        requested into self.filename; always sets a default directory in self.dirname.
1291
1292        :param bool AskFile: Determines how this routine processes getting a
1293          location to store the current export(s).
1294         
1295          * if AskFile is 'ask' (default option), get the name of the file to be written;
1296            self.filename and self.dirname are always set. In the case where
1297            multiple files must be generated, the export routine should do this
1298            based on self.filename as a template.
1299          * if AskFile is 'dir', get the name of the directory to be used;
1300            self.filename is not used, but self.dirname is always set. The export routine
1301            will always generate the file name.
1302          * if AskFile is 'single', get only the name of the directory to be used when
1303            multiple items will be written (as multiple files) are used
1304            *or* a complete file name is requested when a single file
1305            name is selected. self.dirname is always set and self.filename used
1306            only when a single file is selected.
1307          * if AskFile is 'default', creates a name of the file to be used from
1308            the name of the project (.gpx) file. If the project has not been saved,
1309            then the name of file is requested.
1310            self.filename and self.dirname are always set. In the case where
1311            multiple file names must be generated, the export routine should do this
1312            based on self.filename.
1313          * if AskFile is 'default-dir', sets self.dirname from the project (.gpx)
1314            file. If the project has not been saved, then a directory is requested.
1315            self.filename is not used.
1316
1317        :returns: True in case of an error
1318        '''
1319       
1320        numselected = 1
1321        if self.currentExportType == 'phase':
1322            if len(self.Phases) == 0:
1323                self.G2frame.ErrorDialog(
1324                    'Empty project',
1325                    'Project does not contain any phases.')
1326                return True
1327            elif len(self.Phases) == 1:
1328                self.phasenam = self.Phases.keys()
1329            elif self.multiple: 
1330                choices = sorted(self.Phases.keys())
1331                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1332                if phasenum is None: return True
1333                self.phasenam = [choices[i] for i in phasenum]
1334                if not self.phasenam: return True
1335                numselected = len(self.phasenam)
1336            else:
1337                choices = sorted(self.Phases.keys())
1338                phasenum = G2G.ItemSelector(choices,self.G2frame)
1339                if phasenum is None: return True
1340                self.phasenam = [choices[phasenum]]
1341                numselected = len(self.phasenam)
1342        elif self.currentExportType == 'single':
1343            if len(self.xtalDict) == 0:
1344                self.G2frame.ErrorDialog(
1345                    'Empty project',
1346                    'Project does not contain any single crystal data.')
1347                return True
1348            elif len(self.xtalDict) == 1:
1349                self.histnam = self.xtalDict.values()
1350            elif self.multiple:
1351                choices = sorted(self.xtalDict.values())
1352                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1353                if not hnum: return True
1354                self.histnam = [choices[i] for i in hnum]
1355                numselected = len(self.histnam)
1356            else:
1357                choices = sorted(self.xtalDict.values())
1358                hnum = G2G.ItemSelector(choices,self.G2frame)
1359                if hnum is None: return True
1360                self.histnam = [choices[hnum]]
1361                numselected = len(self.histnam)
1362        elif self.currentExportType == 'powder':
1363            if len(self.powderDict) == 0:
1364                self.G2frame.ErrorDialog(
1365                    'Empty project',
1366                    'Project does not contain any powder data.')
1367                return True
1368            elif len(self.powderDict) == 1:
1369                self.histnam = self.powderDict.values()
1370            elif self.multiple:
1371                choices = sorted(self.powderDict.values())
1372                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=True)
1373                if not hnum: return True
1374                self.histnam = [choices[i] for i in hnum]
1375                numselected = len(self.histnam)
1376            else:
1377                choices = sorted(self.powderDict.values())
1378                hnum = G2G.ItemSelector(choices,self.G2frame)
1379                if hnum is None: return True
1380                self.histnam = [choices[hnum]]
1381                numselected = len(self.histnam)
1382        elif self.currentExportType == 'image':
1383            if len(self.Histograms) == 0:
1384                self.G2frame.ErrorDialog(
1385                    'Empty project',
1386                    'Project does not contain any images.')
1387                return True
1388            elif len(self.Histograms) == 1:
1389                self.histnam = self.Histograms.keys()
1390            else:
1391                choices = sorted(self.Histograms.keys())
1392                hnum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
1393                if self.multiple:
1394                    if not hnum: return True
1395                    self.histnam = [choices[i] for i in hnum]
1396                else:
1397                    if hnum is None: return True
1398                    self.histnam = [choices[hnum]]
1399                numselected = len(self.histnam)
1400        if self.currentExportType == 'map':
1401            # search for phases with maps
1402            mapPhases = []
1403            choices = []
1404            for phasenam in sorted(self.Phases):
1405                phasedict = self.Phases[phasenam] # pointer to current phase info           
1406                if len(phasedict['General']['Map'].get('rho',[])):
1407                    mapPhases.append(phasenam)
1408                    if phasedict['General']['Map'].get('Flip'):
1409                        choices.append('Charge flip map: '+str(phasenam))
1410                    elif phasedict['General']['Map'].get('MapType'):
1411                        choices.append(
1412                            str(phasedict['General']['Map'].get('MapType'))
1413                            + ' map: ' + str(phasenam))
1414                    else:
1415                        choices.append('unknown map: '+str(phasenam))
1416            # select a map if needed
1417            if len(mapPhases) == 0:
1418                self.G2frame.ErrorDialog(
1419                    'Empty project',
1420                    'Project does not contain any maps.')
1421                return True
1422            elif len(mapPhases) == 1:
1423                self.phasenam = mapPhases
1424            else: 
1425                phasenum = G2G.ItemSelector(choices,self.G2frame,multiple=self.multiple)
1426                if self.multiple:
1427                    if not phasenum: return True
1428                    self.phasenam = [mapPhases[i] for i in phasenum]
1429                else:
1430                    if phasenum is None: return True
1431                    self.phasenam = [mapPhases[phasenum]]
1432            numselected = len(self.phasenam)
1433
1434        # items selected, now set self.dirname and usually self.filename
1435        if AskFile == 'ask' or (AskFile == 'single' and numselected == 1) or (
1436            AskFile == 'default' and not self.G2frame.GSASprojectfile
1437            ):
1438            filename = self.askSaveFile()
1439            if not filename: return True
1440            self.dirname,self.filename = os.path.split(filename)
1441        elif AskFile == 'dir' or AskFile == 'single' or (
1442            AskFile == 'default-dir' and not self.G2frame.GSASprojectfile
1443            ):
1444            self.dirname = self.askSaveDirectory()
1445            if not self.dirname: return True
1446        elif AskFile == 'default-dir' or AskFile == 'default':
1447            self.dirname,self.filename = os.path.split(
1448                os.path.splitext(self.G2frame.GSASprojectfile)[0] + self.extension
1449                )
1450        else:
1451            raise Exception('This should not happen!')
1452
1453    def loadParmDict(self):
1454        '''Load the GSAS-II refinable parameters from the tree into a dict (self.parmDict). Update
1455        refined values to those from the last cycle and set the uncertainties for the
1456        refined parameters in another dict (self.sigDict).
1457
1458        Expands the parm & sig dicts to include values derived from constraints.
1459        '''
1460        self.parmDict = {}
1461        self.sigDict = {}
1462        rigidbodyDict = {}
1463        covDict = {}
1464        consDict = {}
1465        Histograms,Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
1466        if self.G2frame.GPXtree.IsEmpty(): return # nothing to do
1467        item, cookie = self.G2frame.GPXtree.GetFirstChild(self.G2frame.root)
1468        while item:
1469            name = self.G2frame.GPXtree.GetItemText(item)
1470            if name == 'Rigid bodies':
1471                 rigidbodyDict = self.G2frame.GPXtree.GetItemPyData(item)
1472            elif name == 'Covariance':
1473                 covDict = self.G2frame.GPXtree.GetItemPyData(item)
1474            elif name == 'Constraints':
1475                 consDict = self.G2frame.GPXtree.GetItemPyData(item)
1476            item, cookie = self.G2frame.GPXtree.GetNextChild(self.G2frame.root, cookie)
1477        rbVary,rbDict =  G2stIO.GetRigidBodyModels(rigidbodyDict,Print=False)
1478        self.parmDict.update(rbDict)
1479        rbIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})
1480        Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtables,BLtables,MFtables,maxSSwave =  G2stIO.GetPhaseData(
1481            Phases,RestraintDict=None,rbIds=rbIds,Print=False)
1482        self.parmDict.update(phaseDict)
1483        hapVary,hapDict,controlDict =  G2stIO.GetHistogramPhaseData(
1484            Phases,Histograms,Print=False,resetRefList=False)
1485        self.parmDict.update(hapDict)
1486        histVary,histDict,controlDict =  G2stIO.GetHistogramData(Histograms,Print=False)
1487        self.parmDict.update(histDict)
1488        self.parmDict.update(zip(
1489            covDict.get('varyList',[]),
1490            covDict.get('variables',[])))
1491        self.sigDict = dict(zip(
1492            covDict.get('varyList',[]),
1493            covDict.get('sig',[])))
1494        # expand to include constraints: first compile a list of constraints
1495        constList = []
1496        for item in consDict:
1497            if item.startswith('_'): continue
1498            constList += consDict[item]
1499        # now process the constraints
1500        G2mv.InitVars()
1501        constDict,fixedList,ignored = G2stIO.ProcessConstraints(constList)
1502        varyList = covDict.get('varyListStart')
1503        if varyList is None and len(constDict) == 0:
1504            # no constraints can use varyList
1505            varyList = covDict.get('varyList')
1506        elif varyList is None:
1507            # old GPX file from before pre-constraint varyList is saved
1508            print ' *** Old refinement: Please use Calculate/Refine to redo  ***'
1509            raise Exception(' *** Export aborted ***')
1510        else:
1511            varyList = list(varyList)
1512        try:
1513            groups,parmlist = G2mv.GroupConstraints(constDict)
1514            G2mv.GenerateConstraints(groups,parmlist,varyList,constDict,fixedList,self.parmDict)
1515        except:
1516            # this really should not happen
1517            print ' *** ERROR - constraints are internally inconsistent ***'
1518            errmsg, warnmsg = G2mv.CheckConstraints(varyList,constDict,fixedList)
1519            print 'Errors',errmsg
1520            if warnmsg: print 'Warnings',warnmsg
1521            raise Exception(' *** CIF creation aborted ***')
1522        # add the constrained values to the parameter dictionary
1523        G2mv.Dict2Map(self.parmDict,varyList)
1524        # and add their uncertainties into the esd dictionary (sigDict)
1525        if covDict.get('covMatrix') is not None:
1526            self.sigDict.update(G2mv.ComputeDepESD(covDict['covMatrix'],covDict['varyList'],self.parmDict))
1527
1528    def loadTree(self):
1529        '''Load the contents of the data tree into a set of dicts
1530        (self.OverallParms, self.Phases and self.Histogram as well as self.powderDict
1531        & self.xtalDict)
1532       
1533        * The childrenless data tree items are overall parameters/controls for the
1534          entire project and are placed in self.OverallParms
1535        * Phase items are placed in self.Phases
1536        * Data items are placed in self.Histogram. The key for these data items
1537          begin with a keyword, such as PWDR, IMG, HKLF,... that identifies the data type.
1538        '''
1539        self.OverallParms = {}
1540        self.powderDict = {}
1541        self.xtalDict = {}
1542        self.Phases = {}
1543        self.Histograms = {}
1544        self.SeqRefdata = None
1545        self.SeqRefhist = None
1546        if self.G2frame.GPXtree.IsEmpty(): return # nothing to do
1547        histType = None       
1548        if self.currentExportType == 'phase':
1549            # if exporting phases load them here
1550            sub = G2gd.GetGPXtreeItemId(self.G2frame,self.G2frame.root,'Phases')
1551            if not sub:
1552                print 'no phases found'
1553                return True
1554            item, cookie = self.G2frame.GPXtree.GetFirstChild(sub)
1555            while item:
1556                phaseName = self.G2frame.GPXtree.GetItemText(item)
1557                self.Phases[phaseName] =  self.G2frame.GPXtree.GetItemPyData(item)
1558                item, cookie = self.G2frame.GPXtree.GetNextChild(sub, cookie)
1559            return
1560        elif self.currentExportType == 'single':
1561            histType = 'HKLF'
1562        elif self.currentExportType == 'powder':
1563            histType = 'PWDR'
1564        elif self.currentExportType == 'image':
1565            histType = 'IMG'
1566
1567        if histType: # Loading just one kind of tree entry
1568            item, cookie = self.G2frame.GPXtree.GetFirstChild(self.G2frame.root)
1569            while item:
1570                name = self.G2frame.GPXtree.GetItemText(item)
1571                if name.startswith(histType):
1572                    if self.Histograms.get(name): # there is already an item with this name
1573                        print('Histogram name '+str(name)+' is repeated. Renaming')
1574                        if name[-1] == '9':
1575                            name = name[:-1] + '10'
1576                        elif name[-1] in '012345678':
1577                            name = name[:-1] + str(int(name[-1])+1)
1578                        else:                           
1579                            name += '-1'
1580                    self.Histograms[name] = {}
1581                    # the main info goes into Data, but the 0th
1582                    # element contains refinement results, carry
1583                    # that over too now.
1584                    self.Histograms[name]['Data'] = self.G2frame.GPXtree.GetItemPyData(item)[1]
1585                    self.Histograms[name][0] = self.G2frame.GPXtree.GetItemPyData(item)[0]
1586                    item2, cookie2 = self.G2frame.GPXtree.GetFirstChild(item)
1587                    while item2: 
1588                        child = self.G2frame.GPXtree.GetItemText(item2)
1589                        self.Histograms[name][child] = self.G2frame.GPXtree.GetItemPyData(item2)
1590                        item2, cookie2 = self.G2frame.GPXtree.GetNextChild(item, cookie2)
1591                item, cookie = self.G2frame.GPXtree.GetNextChild(self.G2frame.root, cookie)
1592            # index powder and single crystal histograms by number
1593            for hist in self.Histograms:
1594                if hist.startswith("PWDR"): 
1595                    d = self.powderDict
1596                elif hist.startswith("HKLF"): 
1597                    d = self.xtalDict
1598                else:
1599                    return                   
1600                i = self.Histograms[hist].get('hId')
1601                if i is None and not d.keys():
1602                    i = 0
1603                elif i is None or i in d.keys():
1604                    i = max(d.keys())+1
1605                d[i] = hist
1606            return
1607        # else standard load: using all interlinked phases and histograms
1608        self.Histograms,self.Phases = self.G2frame.GetUsedHistogramsAndPhasesfromTree()
1609        item, cookie = self.G2frame.GPXtree.GetFirstChild(self.G2frame.root)
1610        while item:
1611            name = self.G2frame.GPXtree.GetItemText(item)
1612            item2, cookie2 = self.G2frame.GPXtree.GetFirstChild(item)
1613            if not item2: 
1614                self.OverallParms[name] = self.G2frame.GPXtree.GetItemPyData(item)
1615            item, cookie = self.G2frame.GPXtree.GetNextChild(self.G2frame.root, cookie)
1616        # index powder and single crystal histograms
1617        for hist in self.Histograms:
1618            i = self.Histograms[hist]['hId']
1619            if hist.startswith("PWDR"): 
1620                self.powderDict[i] = hist
1621            elif hist.startswith("HKLF"): 
1622                self.xtalDict[i] = hist
1623
1624    def dumpTree(self,mode='type'):
1625        '''Print out information on the data tree dicts loaded in loadTree.
1626        Used for testing only.
1627        '''
1628        if self.SeqRefdata and self.SeqRefhist:
1629            print('Note that dumpTree does not show sequential results')
1630        print '\nOverall'
1631        if mode == 'type':
1632            def Show(arg): return type(arg)
1633        else:
1634            def Show(arg): return arg
1635        for key in self.OverallParms:
1636            print '  ',key,Show(self.OverallParms[key])
1637        print 'Phases'
1638        for key1 in self.Phases:
1639            print '    ',key1,Show(self.Phases[key1])
1640        print 'Histogram'
1641        for key1 in self.Histograms:
1642            print '    ',key1,Show(self.Histograms[key1])
1643            for key2 in self.Histograms[key1]:
1644                print '      ',key2,Show(self.Histograms[key1][key2])
1645
1646    def defaultSaveFile(self):
1647        return os.path.abspath(
1648            os.path.splitext(self.G2frame.GSASprojectfile
1649                             )[0]+self.extension)
1650       
1651    def askSaveFile(self):
1652        '''Ask the user to supply a file name
1653
1654        :returns: a file name (str) or None if Cancel is pressed
1655        '''
1656       
1657        pth = G2G.GetExportPath(self.G2frame)
1658        defnam = os.path.splitext(
1659            os.path.split(self.G2frame.GSASprojectfile)[1]
1660            )[0]+self.extension
1661        dlg = wx.FileDialog(
1662            self.G2frame, 'Input name for file to write', pth, defnam,
1663            self.longFormatName+' (*'+self.extension+')|*'+self.extension,
1664            wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1665        dlg.CenterOnParent()
1666        try:
1667            if dlg.ShowModal() == wx.ID_OK:
1668                filename = dlg.GetPath()
1669                self.G2frame.LastExportDir = os.path.split(filename)[0]
1670                filename = os.path.splitext(filename)[0]+self.extension # make sure extension is correct
1671            else:
1672                filename = None
1673        finally:
1674            dlg.Destroy()
1675        return filename
1676
1677    def askSaveDirectory(self):
1678        '''Ask the user to supply a directory name. Path name is used as the
1679        starting point for the next export path search.
1680
1681        :returns: a directory name (str) or None if Cancel is pressed
1682        '''
1683        pth = G2G.GetExportPath(self.G2frame)
1684        dlg = wx.DirDialog(
1685            self.G2frame, 'Input directory where file(s) will be written', pth,
1686            wx.DD_DEFAULT_STYLE)
1687        dlg.CenterOnParent()
1688        try:
1689            if dlg.ShowModal() == wx.ID_OK:
1690                filename = dlg.GetPath()
1691                self.G2frame.LastExportDir = filename
1692            else:
1693                filename = None
1694        finally:
1695            dlg.Destroy()
1696        return filename
1697
1698    # Tools for file writing.
1699    def OpenFile(self,fil=None,mode='w'):
1700        '''Open the output file
1701
1702        :param str fil: The name of the file to open. If None (default)
1703          the name defaults to self.dirname + self.filename.
1704          If an extension is supplied, it is not overridded,
1705          but if not, the default extension is used.
1706        :returns: the file object opened by the routine which is also
1707          saved as self.fp
1708        '''
1709        if mode == 'd': # debug mode
1710            self.fullpath = '(stdout)'
1711            self.fp = sys.stdout
1712            return
1713        if not fil:
1714            if not os.path.splitext(self.filename)[1]:
1715                self.filename += self.extension
1716            fil = os.path.join(self.dirname,self.filename)
1717        self.fullpath = os.path.abspath(fil)
1718        self.fp = open(self.fullpath,mode)
1719        return self.fp
1720
1721    def Write(self,line):
1722        '''write a line of output, attaching a line-end character
1723
1724        :param str line: the text to be written.
1725        '''
1726        self.fp.write(line+'\n')
1727       
1728    def CloseFile(self,fp=None):
1729        '''Close a file opened in OpenFile
1730
1731        :param file fp: the file object to be closed. If None (default)
1732          file object self.fp is closed.
1733        '''
1734        if self.fp == sys.stdout: return # debug mode
1735        if fp is None:
1736            fp = self.fp
1737            self.fp = None
1738        if fp is not None: fp.close()
1739       
1740    def SetSeqRef(self,data,hist):
1741        '''Set the exporter to retrieve results from a sequential refinement
1742        rather than the main tree
1743        '''
1744        self.SeqRefdata = data
1745        self.SeqRefhist = hist
1746        data_name = data[hist]
1747        for i,val in zip(data_name['varyList'],data_name['sig']):
1748            self.sigDict[i] = val
1749            self.sigDict[striphist(i)] = val
1750        for i in data_name['parmDict']:
1751            self.parmDict[striphist(i)] = data_name['parmDict'][i]
1752            self.parmDict[i] = data_name['parmDict'][i]
1753            # zero out the dA[xyz] terms, they would only bring confusion
1754            key = i.split(':')
1755            if len(key) < 3: continue
1756            if key[2].startswith('dA'):
1757                self.parmDict[i] = 0.0
1758        for i,(val,sig) in data_name.get('depParmDict',{}).iteritems():
1759            self.parmDict[i] = val
1760            self.sigDict[i] = sig
1761        #GSASIIpath.IPyBreak()
1762               
1763    # Tools to pull information out of the data arrays
1764    def GetCell(self,phasenam):
1765        """Gets the unit cell parameters and their s.u.'s for a selected phase
1766
1767        :param str phasenam: the name for the selected phase
1768        :returns: `cellList,cellSig` where each is a 7 element list corresponding
1769          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
1770          cell values and `cellSig` has their uncertainties.
1771        """
1772        if self.SeqRefdata and self.SeqRefhist:
1773            return self.GetSeqCell(phasenam,self.SeqRefdata[self.SeqRefhist])
1774        phasedict = self.Phases[phasenam] # pointer to current phase info
1775        try:
1776            pfx = str(phasedict['pId'])+'::'
1777            A,sigA = G2stIO.cellFill(pfx,phasedict['General']['SGData'],self.parmDict,self.sigDict)
1778            cellSig = G2stIO.getCellEsd(pfx,phasedict['General']['SGData'],A,
1779                self.OverallParms['Covariance'])  # returns 7 vals, includes sigVol
1780            cellList = G2lat.A2cell(A) + (G2lat.calc_V(A),)
1781            return cellList,cellSig
1782        except KeyError:
1783            cell = phasedict['General']['Cell'][1:]
1784            return cell,7*[0]
1785           
1786    def GetSeqCell(self,phasenam,data_name):
1787        """Gets the unit cell parameters and their s.u.'s for a selected phase
1788        and histogram in a sequential fit
1789
1790        :param str phasenam: the name for the selected phase
1791        :param dict data_name: the sequential refinement parameters for the selected histogram
1792        :returns: `cellList,cellSig` where each is a 7 element list corresponding
1793          to a, b, c, alpha, beta, gamma, volume where `cellList` has the
1794          cell values and `cellSig` has their uncertainties.
1795        """
1796        phasedict = self.Phases[phasenam]
1797        SGdata = phasedict['General']['SGData']
1798        pId = phasedict['pId']
1799        RecpCellTerms = G2lat.cell2A(phasedict['General']['Cell'][1:7])
1800        ESDlookup = {}
1801        Dlookup = {}
1802        varied = [striphist(i) for i in data_name['varyList']]
1803        for item,val in data_name['newCellDict'].iteritems():
1804            if item in varied:
1805                ESDlookup[val[0]] = item
1806                Dlookup[item] = val[0]
1807        A = RecpCellTerms[:]
1808        for i in range(6):
1809            var = str(pId)+'::A'+str(i)
1810            if var in ESDlookup:
1811                A[i] = data_name['newCellDict'][ESDlookup[var]][1] # override with refined value
1812        cellDict = dict(zip([str(pId)+'::A'+str(i) for i in range(6)],A))
1813        zeroDict = {i:0.0 for i in cellDict}
1814        A,zeros = G2stIO.cellFill(str(pId)+'::',SGdata,cellDict,zeroDict)
1815        covData = {
1816            'varyList': [Dlookup.get(striphist(v),v) for v in data_name['varyList']],
1817            'covMatrix': data_name['covMatrix']
1818            }
1819        return list(G2lat.A2cell(A)) + [G2lat.calc_V(A)], G2stIO.getCellEsd(str(pId)+'::',SGdata,A,covData)
1820               
1821    def GetAtoms(self,phasenam):
1822        """Gets the atoms associated with a phase. Can be used with standard
1823        or macromolecular phases
1824
1825        :param str phasenam: the name for the selected phase
1826        :returns: a list of items for eac atom where each item is a list containing:
1827          label, typ, mult, xyz, and td, where
1828
1829          * label and typ are the atom label and the scattering factor type (str)
1830          * mult is the site multiplicity (int)
1831          * xyz is contains a list with four pairs of numbers:
1832            x, y, z and fractional occupancy and
1833            their standard uncertainty (or a negative value)
1834          * td is contains a list with either one or six pairs of numbers:
1835            if one number it is U\ :sub:`iso` and with six numbers it is
1836            U\ :sub:`11`, U\ :sub:`22`, U\ :sub:`33`, U\ :sub:`12`, U\ :sub:`13` & U\ :sub:`23`
1837            paired with their standard uncertainty (or a negative value)
1838        """
1839        phasedict = self.Phases[phasenam] # pointer to current phase info           
1840        cx,ct,cs,cia = phasedict['General']['AtomPtrs']
1841        cfrac = cx+3
1842        fpfx = str(phasedict['pId'])+'::Afrac:'       
1843        atomslist = []
1844        for i,at in enumerate(phasedict['Atoms']):
1845            if phasedict['General']['Type'] == 'macromolecular':
1846                label = '%s_%s_%s_%s'%(at[ct-1],at[ct-3],at[ct-4],at[ct-2])
1847            else:
1848                label = at[ct-1]
1849            fval = self.parmDict.get(fpfx+str(i),at[cfrac])
1850            fsig = self.sigDict.get(fpfx+str(i),-0.009)
1851            mult = at[cs+1]
1852            typ = at[ct]
1853            xyz = []
1854            for j,v in enumerate(('x','y','z')):
1855                val = at[cx+j]
1856                pfx = str(phasedict['pId']) + '::A' + v + ':' + str(i)
1857                val = self.parmDict.get(pfx, val)
1858                dpfx = str(phasedict['pId'])+'::dA'+v+':'+str(i)
1859                sig = self.sigDict.get(dpfx,-0.000009)
1860                xyz.append((val,sig))
1861            xyz.append((fval,fsig))
1862            td = []
1863            if at[cia] == 'I':
1864                pfx = str(phasedict['pId'])+'::AUiso:'+str(i)
1865                val = self.parmDict.get(pfx,at[cia+1])
1866                sig = self.sigDict.get(pfx,-0.0009)
1867                td.append((val,sig))
1868            else:
1869                for i,var in enumerate(('AU11','AU22','AU33','AU12','AU13','AU23')):
1870                    pfx = str(phasedict['pId'])+'::'+var+':'+str(i)
1871                    val = self.parmDict.get(pfx,at[cia+2+i])
1872                    sig = self.sigDict.get(pfx,-0.0009)
1873                    td.append((val,sig))
1874            atomslist.append((label,typ,mult,xyz,td))
1875        return atomslist
1876######################################################################
1877def ExportPowderList(G2frame):
1878    '''Returns a list of extensions supported by :func:`GSASIIIO:ExportPowder`
1879    This is used in :meth:`GSASIIimgGUI.AutoIntFrame` only.
1880   
1881    :param wx.Frame G2frame: the GSAS-II main data tree window
1882    '''
1883    extList = []
1884    for obj in G2frame.exporterlist:
1885        if 'powder' in obj.exporttype:
1886            try:
1887                obj.Writer
1888                extList.append(obj.extension)
1889            except AttributeError:
1890                pass
1891    return extList
1892
1893def ExportPowder(G2frame,TreeName,fileroot,extension):
1894    '''Writes a single powder histogram using the Export routines.
1895    This is used in :meth:`GSASIIimgGUI.AutoIntFrame` only.
1896
1897    :param wx.Frame G2frame: the GSAS-II main data tree window
1898    :param str TreeName: the name of the histogram (PWDR ...) in the data tree
1899    :param str fileroot: name for file to be written, extension ignored
1900    :param str extension: extension for file to be written (start with '.'). Must
1901      match a powder export routine that has a Writer object.
1902    '''
1903    filename = os.path.abspath(os.path.splitext(fileroot)[0]+extension)
1904    for obj in G2frame.exporterlist:
1905        if obj.extension == extension and 'powder' in obj.exporttype:
1906            obj.currentExportType = 'powder'
1907            obj.InitExport(None)
1908            obj.loadTree() # load all histograms in tree into dicts
1909            if TreeName not in obj.Histograms:
1910                raise Exception('Histogram not found: '+str(TreeName))
1911            try:
1912                obj.Writer
1913            except AttributeError:
1914                continue
1915            try:
1916                obj.Writer(TreeName,filename)
1917                return
1918            except Exception,err:
1919                print('Export Routine for '+extension+' failed.')
1920                print err
1921    else:
1922        print('No Export routine supports extension '+extension)
1923
1924def ExportSequential(G2frame,data,obj,exporttype):
1925    '''
1926    Used to export from every phase/dataset in a sequential refinement using
1927    a .Writer method for either projects or phases. Prompts to select histograms
1928    and for phase exports, which phase(s).
1929
1930    :param wx.Frame G2frame: the GSAS-II main data tree window
1931    :param dict data: the sequential refinement data object
1932    :param str exporttype: indicates the type of export ('project' or 'phase')
1933    '''
1934    if len(data['histNames']) == 0:
1935        G2G.G2MessageBox(G2frame,'There are no sequential histograms','Warning')
1936    obj.InitExport(None)
1937    obj.loadTree()
1938    obj.loadParmDict()
1939    if len(data['histNames']) == 1:
1940        histlist = data['histNames']
1941    else:
1942        dlg = G2G.G2MultiChoiceDialog(G2frame,'Select histograms to export from list',
1943                                 'Select histograms',data['histNames'])
1944        if dlg.ShowModal() == wx.ID_OK:
1945            histlist = [data['histNames'][l] for l in dlg.GetSelections()]
1946            dlg.Destroy()
1947        else:
1948            dlg.Destroy()
1949            return
1950    if exporttype == 'Phase':
1951        phaselist = obj.Phases.keys()
1952        if len(obj.Phases) == 0:
1953            G2G.G2MessageBox(G2frame,'There are no phases in sequential ref.','Warning')
1954            return
1955        elif len(obj.Phases) > 1:
1956            dlg = G2G.G2MultiChoiceDialog(G2frame,'Select phases to export from list',
1957                                    'Select phases', phaselist)
1958            if dlg.ShowModal() == wx.ID_OK:
1959                phaselist = [phaselist[l] for l in dlg.GetSelections()]
1960                dlg.Destroy()
1961            else:
1962                dlg.Destroy()
1963                return
1964        filename = obj.askSaveFile()
1965        if not filename: return True
1966        obj.dirname,obj.filename = os.path.split(filename)
1967        print('Writing output to file '+str(obj.filename)+"...")
1968        mode = 'w'
1969        for p in phaselist:
1970            for h in histlist:
1971                obj.SetSeqRef(data,h)
1972                #GSASIIpath.IPyBreak()
1973                obj.Writer(h,phasenam=p,mode=mode)
1974                mode = 'a'
1975        print('...done')
1976    elif exporttype == 'Project':  # note that the CIF exporter is not yet ready for this
1977        filename = obj.askSaveFile()
1978        if not filename: return True
1979        obj.dirname,obj.filename = os.path.split(filename)
1980        print('Writing output to file '+str(obj.filename)+"...")
1981        mode = 'w'
1982        for h in histlist:
1983            obj.SetSeqRef(data,h)
1984            obj.Writer(h,mode=mode)
1985            print('\t'+str(h)+' written')
1986            mode = 'a'
1987        print('...done')
1988    elif exporttype == 'Powder':
1989        filename = obj.askSaveFile()
1990        if not filename: return True
1991        obj.dirname,obj.filename = os.path.split(filename)
1992        print('Writing output to file '+str(obj.filename)+"...")
1993        mode = 'w'
1994        for h in histlist:
1995            obj.SetSeqRef(data,h)
1996            obj.Writer(h,mode=mode)
1997            print('\t'+str(h)+' written')
1998            mode = 'a'
1999        print('...done')
2000
2001def ReadDIFFaX(DIFFaXfile):
2002    print 'read ',DIFFaXfile
2003    Layer = {'Laue':'-1','Cell':[False,1.,1.,1.,90.,90.,90,1.],'Width':[[10.,10.],[False,False]],
2004        'Layers':[],'Stacking':[],'Transitions':[],'Toler':0.01,'AtInfo':{}}
2005    df = open(DIFFaXfile,'r')
2006    lines = df.readlines()
2007    df.close()
2008    struct = False
2009    Struct = []
2010    stack = False
2011    Stack = []
2012    trans = False
2013    Trans = []
2014    for diff in lines:
2015        diff = diff[:-1].lower()
2016        if '!'  in diff:
2017            continue
2018        while '}' in diff: #strip comments
2019            iB = diff.index('{')
2020            iF = diff.index('}')+1
2021            if iB:
2022                diff = diff[:iB]
2023            else:
2024                diff = diff[iF:]
2025        if not diff:
2026            continue
2027        if diff.strip() == 'instrumental':
2028            continue
2029        if diff.strip() == 'structural':
2030            struct = True
2031            continue
2032        elif diff.strip() == 'stacking':
2033            struct = False
2034            stack = True
2035            continue
2036        elif diff.strip() == 'transitions':
2037            stack = False
2038            trans = True
2039            continue
2040        diff = diff.strip()
2041        if struct:
2042            if diff:
2043                Struct.append(diff)
2044        elif stack:
2045            if diff:
2046                Stack.append(diff)
2047        elif trans:
2048            if diff:
2049                Trans.append(diff)
2050   
2051#STRUCTURE records
2052    laueRec = Struct[1].split()
2053    Layer['Laue'] = laueRec[0]
2054    if Layer['Laue'] == 'unknown' and len(laueRec) > 1:
2055        Layer['Toler'] = float(laueRec[1])    #tolerance for 'unknown'?
2056    if Layer['Laue'] == '2/m(1)': Layer['Laue'] = '2/m(c)'
2057    if Layer['Laue'] == '2/m(2)': Layer['Laue'] = '2/m(ab)'
2058    cell = Struct[0].split()
2059    Layer['Cell'] = [False,float(cell[0]),float(cell[1]),float(cell[2]),90.,90.,float(cell[3]),1.0]
2060    nLayers = int(Struct[2])
2061    N = 3
2062    if 'layer' not in Struct[3]:
2063        N = 4
2064        if Struct[3] != 'infinite':
2065            width = Struct[3].split()
2066            Layer['Width'][0] = [float(width[0]),float(width[1])]
2067    for nL in range(nLayers):
2068        if '=' in Struct[N]:
2069            name = Struct[N].split('=')
2070            sameas = int(name[1])-1
2071            Layer['Layers'].append({'Name':name[0],'SameAs':Layer['Layers'][sameas]['Name'],'Symm':'None','Atoms':[]})
2072            N += 1
2073            continue
2074        Symm = 'None'
2075        if 'centro' in Struct[N+1]: Symm = '-1'
2076        Layer['Layers'].append({'Name':Struct[N],'SameAs':'','Symm':Symm,'Atoms':[]})
2077        N += 2
2078        while 'layer' not in Struct[N]:
2079            atom = Struct[N][4:].split()
2080            atomType = G2el.FixValence(Struct[N][:4].replace(' ','').strip().capitalize())
2081            if atomType not in Layer['AtInfo']:
2082                Layer['AtInfo'][atomType] = G2el.GetAtomInfo(atomType)
2083            atomName = '%s(%s)'%(atomType,atom[0])
2084            newVals = []
2085            for val in atom[1:6]:
2086                if '/' in val:
2087                    newVals.append(eval(val+'.'))
2088                else:
2089                    newVals.append(float(val))               
2090            atomRec = [atomName,atomType,newVals[0],newVals[1],newVals[2],newVals[4],newVals[3]/78.9568]
2091            Layer['Layers'][-1]['Atoms'].append(atomRec)
2092            N += 1
2093            if N > len(Struct)-1:
2094                break
2095#TRANSITIONS records
2096    transArray = []
2097    N = 0
2098    for i in range(nLayers):
2099        transArray.append([])
2100        for j in range(nLayers):
2101            vals = Trans[N].split()
2102            newVals = []
2103            for val in vals[:4]:
2104                if '/' in val:
2105                    newVals.append(eval(val+'.'))
2106                else:
2107                    newVals.append(float(val))
2108            transArray[-1].append(newVals+['',False])
2109            N += 1
2110    Layer['Transitions'] = transArray
2111#STACKING records
2112    Layer['Stacking'] = [Stack[0],'']
2113    if Stack[0] == 'recursive':
2114        Layer['Stacking'][1] = Stack[1]
2115    elif Stack[0] == 'explicit':
2116        if Stack[1] == 'random':
2117            Layer['Stacking'][1] = Stack[1]
2118        else:
2119            Layer['Stacking'][1] = 'list'
2120            Layer['Stacking'].append('')
2121            for stack in Stack[2:]:
2122                Layer['Stacking'][2] += ' '+stack
2123    return Layer
2124
2125if __name__ == '__main__':
2126    import GSASIIdataGUI
2127    application = GSASIIdataGUI.GSASIImain(0)
2128    G2frame = application.main
2129    #app = wx.PySimpleApp()
2130    #G2frame = wx.Frame(None) # create a frame
2131    #frm.Show(True)
2132    #filename = '/tmp/notzip.zip'
2133    #filename = '/tmp/all.zip'
2134    #filename = '/tmp/11bmb_7652.zip'
2135   
2136    #selection=None, confirmoverwrite=True, parent=None
2137    #print ExtractFileFromZip(filename, selection='11bmb_7652.fxye',parent=frm)
2138    #print ExtractFileFromZip(filename,multipleselect=True)
2139    #                         #confirmread=False, confirmoverwrite=False)
2140
2141    # choicelist=[ ('a','b','c'),
2142    #              ('test1','test2'),('no choice',)]
2143    # titles = [ 'a, b or c', 'tests', 'No option here']
2144    # dlg = MultipleChoicesDialog(
2145    #     choicelist,titles,
2146    #     parent=frm)
2147    # if dlg.ShowModal() == wx.ID_OK:
2148    #     print 'Got OK'
2149    imagefile = '/tmp/NDC5_00237_3.ge3'
2150    Comments, Data, Npix, Image = GetImageData(G2frame,imagefile,imageOnly=False,ImageTag=None)
2151
2152    print("\n\nResults loaded to Comments, Data, Npix and Image\n\n")
2153
2154    GSASIIpath.IPyBreak_base()
Note: See TracBrowser for help on using the repository browser.