source: trunk/GSASIIIO.py @ 4619

Last change on this file since 4619 was 4619, checked in by vondreele, 2 years ago

Add pink beam check box to image data GUI
When selected, integration will set inst parms to pink beam defaults based on Sector 35 LSS data

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