source: trunk/GSASIIIO.py @ 3136

Last change on this file since 3136 was 3136, checked in by vondreele, 4 years ago

make GSAS-II python 3.6 compliant & preserve python 2.7 use;changes:
do from future import division, print_function for all GSAS-II py sources
all menu items revised to be py 2.7/3.6 compliant
all wx.OPEN --> wx.FD_OPEN in file dialogs
all integer divides (typically for image pixel math) made explicit with ; ambiguous ones made floats as appropriate
all print "stuff" --> print (stuff)
all print >> pFile,'stuff' --> pFile.writeCIFtemplate('stuff')
all read file opens made explicit 'r' or 'rb'
all cPickle imports made for py2.7 or 3.6 as cPickle or _pickle; test for '2' platform.version_tuple[0] for py 2.7
define cPickleload to select load(fp) or load(fp,encoding='latin-1') for loading gpx files; provides cross compatibility between py 2.7/3.6 gpx files
make dict.keys() as explicit list(dict.keys()) as needed (NB: possible source of remaining py3.6 bugs)
make zip(a,b) as explicit list(zip(a,b)) as needed (NB: possible source of remaining py3.6 bugs)
select unichr/chr according test for '2' platform.version_tuple[0] for py 2.7 (G2pwdGUI * G2plot) for special characters
select wg.EVT_GRID_CELL_CHANGE (classic) or wg.EVT_GRID_CELL_CHANGED (phoenix) in grid Bind
maxint --> maxsize; used in random number stuff
raise Exception,"stuff" --> raise Exception("stuff")
wx 'classic' sizer.DeleteWindows?() or 'phoenix' sizer.Clear(True)
wx 'classic' SetToolTipString?(text) or 'phoenix' SetToolTip?(wx.ToolTip?(text)); define SetToolTipString?(self,text) to handle the choice in plots
status.SetFields? --> status.SetStatusText?
'classic' AddSimpleTool? or 'phoenix' self.AddTool? for plot toolbar; Bind different as well
define GetItemPydata? as it doesn't exist in wx 'phoenix'
allow python versions 2.7 & 3.6 to run GSAS-II
Bind override commented out - no logging capability (NB: remove all logging code?)
all import ContentsValidator? open filename & test if valid then close; filepointer removed from Reader
binary importers (mostly images) test for 'byte' type & convert as needed to satisfy py 3.6 str/byte rules

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