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