# -*- coding: utf-8 -*-
########### SVN repository information ###################
# $Date: 2019-06-14 14:45:45 -0400 (Fri, 14 Jun 2019) $
# $Author: toby $
# $Revision: 4026 $
# $URL: https://subversion.xray.aps.anl.gov/pyGSAS/trunk/GSASIIfiles.py $
# $Id: GSASIIfiles.py 4026 2019-06-14 18:45:45Z toby $
########### SVN repository information ###################
'''
# Third-party code. No Schrodinger Copyright.
*GSASIIfiles: data (non-GUI) I/O routines*
==========================================
Module with miscellaneous routines for input and output from files.
This module should not contain any references to wxPython so that it
can be imported for scriptable use or potentially on clients where
wx is not installed.
Future refactoring: This module and GSASIIIO.py needs some work to
move non-wx routines here. It may will likely make sense to rename the module(s)
at that point.
'''
# flake8: noqa
import glob
import imp
import inspect
import os
import platform
import sys
import numpy as np
# N.B. This is duplicated in G2IO
[docs]def sfloat(S):
'Convert a string to float. An empty field or a unconvertable value is treated as zero'
if S.strip():
try:
return float(S)
except ValueError:
pass
return 0.0
G2printLevel = 'all'
'''This defines the level of output from calls to :func:`G2Print`,
which should be used in place of print() within this module.
Settings for this are 'all', 'warn', 'error' or 'none'. Also see:
:func:`G2Print` and :func:`G2SetPrintLevel`.
'''
[docs]def G2SetPrintLevel(level):
'''Set the level of output from calls to :func:`G2Print`, which should
be used in place of print() within GSASII. Settings for the mode are
'all', 'warn', 'error' or 'none'
:param str level: a string used to set the print level, which may be
'all', 'warn', 'error' or 'none'.
Note that capitalization and extra letters in level are ignored, so
'Warn', 'warnings', etc. will all set the mode to 'warn'
'''
global G2printLevel
for mode in 'all', 'warn', 'error', 'none':
if mode in level.lower():
G2printLevel = mode
return
else:
G2Print('G2SetPrintLevel Error: level={} cannot be interpreted.',
'Use all, warn, error or none.')
[docs]def G2Print(*args, **kwargs):
'''Print with filtering based level of output (see :func:`G2SetPrintLevel`).
Use G2Print() as replacement for print().
:param str mode: if specified, this should contain the mode for printing
('error', 'warn' or anything else). If not specified, the first argument
of the print command (args[0]) should contain the string 'error' for
error messages and 'warn' for warning messages
(capitalization and additional letters ignored.)
'''
if G2printLevel == 'none':
return
if kwargs.get('mode') is None:
testStr = str(args[0]).lower()
else:
testStr = kwargs['mode'][:].lower()
del kwargs['mode']
level = 2
for i, mode in enumerate(('error', 'warn')):
if mode in testStr:
level = i
break
if G2printLevel == 'error' and level > 0:
return
if G2printLevel == 'warn' and level > 1:
return
print(*args, **kwargs)
[docs]def get_python_versions(packagelist):
versions = [['Python', sys.version.split()[0]]]
for pack in packagelist:
try:
versions.append([pack.__name__, pack.__version__])
except:
pass
versions.append([
'Platform', sys.platform + ' ' + platform.architecture()[0] + ' ' +
platform.machine()
])
return versions
[docs]def makeInstDict(names, data, codes):
inst = dict(zip(names, zip(data, data, codes)))
for item in inst:
inst[item] = list(inst[item])
return inst
[docs]def SetPowderInstParms(Iparm, rd):
'''extracts values from instrument parameters in rd.instdict
or in array Iparm.
Create and return the contents of the instrument parameter tree entry.
'''
Irads = {
0: ' ',
1: 'CrKa',
2: 'FeKa',
3: 'CuKa',
4: 'MoKa',
5: 'AgKa',
6: 'TiKa',
7: 'CoKa'
}
DataType = Iparm['INS HTYPE '].strip()[:3] # take 1st 3 chars
# override inst values with values read from data file
Bank = rd.powderentry[2] #should be used in multibank iparm files
if rd.instdict.get('type'):
DataType = rd.instdict.get('type')
data = [
DataType,
]
instname = Iparm.get('INS 1INAME ')
irad = int(Iparm.get('INS 1 IRAD ', '0'))
if instname:
rd.Sample['InstrName'] = instname.strip()
if 'C' in DataType:
wave1 = None
wave2 = 0.0
if rd.instdict.get('wave'):
wl = rd.instdict.get('wave')
wave1 = wl[0]
if len(wl) > 1:
wave2 = wl[1]
s = Iparm['INS 1 ICONS']
if not wave1:
wave1 = sfloat(s[:10])
wave2 = sfloat(s[10:20])
v = (wave1, wave2, sfloat(s[20:30]) / 100., sfloat(s[55:65]),
sfloat(s[40:50])) #get lam1, lam2, zero, pola & ratio
if not v[1]:
names = [
'Type', 'Lam', 'Zero', 'Polariz.', 'U', 'V', 'W', 'X', 'Y', 'Z',
'SH/L', 'Azimuth'
]
v = (v[0], v[2], v[4])
codes = [0, 0, 0, 0, 0]
rd.Sample.update({
'Type': 'Debye-Scherrer',
'Absorption': [0., False],
'DisplaceX': [0., False],
'DisplaceY': [0., False]
})
else:
names = [
'Type', 'Lam1', 'Lam2', 'Zero', 'I(L2)/I(L1)', 'Polariz.', 'U',
'V', 'W', 'X', 'Y', 'Z', 'SH/L', 'Azimuth'
]
codes = [0, 0, 0, 0, 0, 0, 0]
rd.Sample.update({
'Type': 'Bragg-Brentano',
'Shift': [0., False],
'Transparency': [0., False],
'SurfRoughA': [0., False],
'SurfRoughB': [0., False]
})
data.extend(v)
if 'INS 1PRCF ' in Iparm:
v1 = Iparm['INS 1PRCF '].split()
v = Iparm['INS 1PRCF 1'].split()
data.extend([float(v[0]), float(v[1]),
float(v[2])]) #get GU, GV & GW - always here
azm = float(Iparm.get('INS 1DETAZM', '0.0'))
v = Iparm['INS 1PRCF 2'].split()
if v1[0] == 3:
data.extend([
float(v[0]),
float(v[1]), 0.0,
float(v[2]) + float(v[3], azm)
]) #get LX, LY, Z, S+H/L & azimuth
else:
data.extend([0.0, 0.0, 0.0, 0.002,
azm]) #OK defaults if fxn #3 not 1st in iprm file
else:
v1 = Iparm['INS 1PRCF1 '].split()
v = Iparm['INS 1PRCF11'].split()
data.extend([float(v[0]), float(v[1]),
float(v[2])]) #get GU, GV & GW - always here
azm = float(Iparm.get('INS 1DETAZM', '0.0'))
v = Iparm['INS 1PRCF12'].split()
if v1[0] == 3:
data.extend([
float(v[0]),
float(v[1]), 0.0,
float(v[2]) + float(v[3], azm)
]) #get LX, LY, Z, S+H/L & azimuth
else:
data.extend([0.0, 0.0, 0.0, 0.002,
azm]) #OK defaults if fxn #3 not 1st in iprm file
codes.extend([0, 0, 0, 0, 0, 0, 0])
Iparm1 = makeInstDict(names, data, codes)
Iparm1['Source'] = [Irads[irad], Irads[irad]]
Iparm1['Bank'] = [Bank, Bank, 0]
return [Iparm1, {}]
elif 'T' in DataType:
names = [
'Type',
'fltPath',
'2-theta',
'difC',
'difA',
'difB',
'Zero',
'alpha',
'beta-0',
'beta-1',
'beta-q',
'sig-0',
'sig-1',
'sig-2',
'sig-q',
'X',
'Y',
'Z',
'Azimuth',
]
codes = [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
]
azm = 0.
if 'INS 1DETAZM' in Iparm:
azm = float(Iparm['INS 1DETAZM'])
rd.Sample['Azimuth'] = azm
fltPath0 = 20. #arbitrary
if 'INS FPATH1' in Iparm:
s = Iparm['INS FPATH1'].split()
fltPath0 = sfloat(s[0])
if 'INS 1BNKPAR' not in Iparm: #bank missing from Iparm file
return []
s = Iparm['INS 1BNKPAR'].split()
fltPath1 = sfloat(s[0])
data.extend([
fltPath0 + fltPath1,
]) #Flight path source-sample-detector
data.extend([
sfloat(s[1]),
]) #2-theta for bank
s = Iparm['INS 1 ICONS'].split()
data.extend([sfloat(s[0]),
sfloat(s[1]), 0.0,
sfloat(s[2])]) #difC,difA,difB,Zero
if 'INS 1PRCF ' in Iparm:
s = Iparm['INS 1PRCF '].split()
pfType = int(s[0])
s = Iparm['INS 1PRCF 1'].split()
if abs(pfType) == 1:
data.extend([sfloat(s[1]),
sfloat(s[2]),
sfloat(s[3])]) #alpha, beta-0, beta-1
s = Iparm['INS 1PRCF 2'].split()
data.extend([
0.0, 0.0,
sfloat(s[1]),
sfloat(s[2]), 0.0, 0.0, 0.0, 0.0, azm
]) #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y, Z
elif abs(pfType) in [3, 4, 5]:
data.extend([sfloat(s[0]),
sfloat(s[1]),
sfloat(s[2])]) #alpha, beta-0, beta-1
if abs(pfType) == 4:
data.extend(
[0.0, 0.0,
sfloat(s[3]), 0.0, 0.0, 0.0, 0.0, 0.0,
azm]) #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y, Z
else:
s = Iparm['INS 1PRCF 2'].split()
data.extend([
0.0, 0.0,
sfloat(s[0]),
sfloat(s[1]), 0.0, 0.0, 0.0, 0.0, azm
]) #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y, Z
elif abs(pfType) == 2:
data.extend([sfloat(s[1]), 0.0,
1. / sfloat(s[3])]) #alpha, beta-0, beta-1
data.extend(
[0.0, 0.0,
sfloat(s[1]), 0.0, 0.0, 0.0, 0.0, 0.0,
azm]) #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y, Z
else:
s = Iparm['INS 1PRCF1 '].split()
pfType = int(s[0])
s = Iparm['INS 1PRCF11'].split()
if abs(pfType) == 1:
data.extend([sfloat(s[1]),
sfloat(s[2]),
sfloat(s[3])]) #alpha, beta-0, beta-1
s = Iparm['INS 1PRCF12'].split()
data.extend([
0.0, 0.0,
sfloat(s[1]),
sfloat(s[2]), 0.0, 0.0, 0.0, 0.0, 0.0, azm
]) #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y, Z
elif abs(pfType) in [3, 4, 5]:
data.extend([sfloat(s[0]),
sfloat(s[1]),
sfloat(s[2])]) #alpha, beta-0, beta-1
if abs(pfType) == 4:
data.extend(
[0.0, 0.0,
sfloat(s[3]), 0.0, 0.0, 0.0, 0.0, 0.0,
azm]) #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y, Z
else:
s = Iparm['INS 1PRCF12'].split()
data.extend([
0.0, 0.0,
sfloat(s[0]),
sfloat(s[1]), 0.0, 0.0, 0.0, 0.0, azm
]) #beta-q, sig-0, sig-1, sig-2, sig-q, X, Y, Z
Inst1 = makeInstDict(names, data, codes)
Inst1['Bank'] = [Bank, Bank, 0]
Inst2 = {}
if pfType < 0:
Ipab = 'INS 1PAB' + str(-pfType)
Npab = int(Iparm[Ipab + ' '].strip())
Inst2['Pdabc'] = []
for i in range(Npab):
k = Ipab + str(i + 1).rjust(2)
s = Iparm[k].split()
Inst2['Pdabc'].append([float(t) for t in s])
Inst2['Pdabc'] = np.array(Inst2['Pdabc'])
Inst2['Pdabc'].T[3] += Inst2['Pdabc'].T[0] * Inst1['difC'][
0] #turn 3rd col into TOF
if 'INS 1I ITYP' in Iparm:
s = Iparm['INS 1I ITYP'].split()
Ityp = int(s[0])
Tminmax = [float(s[1]) * 1000., float(s[2]) * 1000.]
Itypes = [
'Exponential', 'Maxwell/Exponential', '', 'Maxwell/Chebyschev',
''
]
if Ityp in [1, 2, 4]:
Inst2['Itype'] = Itypes[Ityp - 1]
Inst2['Tminmax'] = Tminmax
Icoeff = []
Iesd = []
Icovar = []
for i in range(3):
s = Iparm['INS 1ICOFF' + str(i + 1)].split()
Icoeff += [float(S) for S in s]
s = Iparm['INS 1IECOF' + str(i + 1)].split()
Iesd += [float(S) for S in s]
NT = 10
for i in range(8):
s = Iparm['INS 1IECOR' + str(i + 1)]
if i == 7:
NT = 8
Icovar += [float(s[6 * j:6 * j + 6]) for j in range(NT)]
Inst2['Icoeff'] = Icoeff
Inst2['Iesd'] = Iesd
Inst2['Icovar'] = Icovar
return [Inst1, Inst2]
[docs]def ReadPowderInstprm(instLines, bank, databanks, rd):
'''Read lines from a GSAS-II (new) instrument parameter file
similar to G2pwdGUI.OnLoad
If instprm file has multiple banks each with header #Bank n: ..., this
finds matching bank no. to load - problem with nonmatches?
Note that this routine performs a similar role to :meth:`GSASIIdataGUI.GSASII.ReadPowderInstprm`,
but that will call a GUI routine for selection when needed. This routine will raise exceptions
on errors and will select the first bank when a choice might be appropriate.
TODO: refactor to combine the two routines.
:param list instLines: strings from GSAS-II parameter file; can be concatenated with ';'
:param int bank: bank number to check when instprm file has '#BANK n:...' strings
when bank = n then use parameters; otherwise skip that set. Ignored if BANK n:
not present. NB: this kind of instprm file made by a Save all profile command in Instrument Par ameters
:return dict: Inst instrument parameter dict if OK, or
str: Error message if failed
(transliterated from GSASIIdataGUI.py:1235 (rev 3008), function of the same name)
'''
if 'GSAS-II' not in instLines[0]:
raise ValueError("Not a valid GSAS-II instprm file")
newItems = []
newVals = []
Found = False
il = 0
if bank is None:
banklist = set()
for S in instLines:
if S[0] == '#' and 'Bank' in S:
banklist.add(int(S.split(':')[0].split()[1]))
# Picks the first bank by default
if len(banklist) > 1:
bank = sorted(banklist)[0]
else:
bank = 1
rd.powderentry[2] = bank
while il < len(instLines):
S = instLines[il]
if S[0] == '#':
if Found:
break
if 'Bank' in S:
if bank == int(S.split(':')[0].split()[1]):
il += 1
S = instLines[il]
else:
il += 1
S = instLines[il]
while il < len(instLines) and '#Bank' not in S:
il += 1
if il == len(instLines):
raise ValueError(
"Bank {} not found in instprm file".format(
bank))
S = instLines[il]
continue
else:
il += 1
S = instLines[il]
Found = True
if '"""' in S:
delim = '"""'
elif "'''" in S:
delim = "'''"
else:
S = S.replace(' ', '')
SS = S.strip().split(';')
for s in SS:
item, val = s.split(':', 1)
newItems.append(item)
try:
newVals.append(float(val))
except ValueError:
newVals.append(val)
il += 1
continue
# read multiline values, delimited by ''' or """
item, val = S.strip().split(':', 1)
val = val.replace(delim, '').rstrip()
val += '\n'
while True:
il += 1
if il >= len(instLines):
break
S = instLines[il]
if delim in S:
val += S.replace(delim, '').rstrip()
val += '\n'
break
else:
val += S.rstrip()
val += '\n'
newItems.append(item)
newVals.append(val)
il += 1
if 'Lam1' in newItems:
rd.Sample.update({
'Type': 'Bragg-Brentano',
'Shift': [0., False],
'Transparency': [0., False],
'SurfRoughA': [0., False],
'SurfRoughB': [0., False]
})
else:
rd.Sample.update({
'Type': 'Debye-Scherrer',
'Absorption': [0., False],
'DisplaceX': [0., False],
'DisplaceY': [0., False]
})
return [makeInstDict(newItems, newVals, len(newVals) * [False]), {}]
[docs]def LoadImportRoutines(prefix, errprefix=None, traceback=False):
'''Routine to locate GSASII importers matching a prefix string
'''
if errprefix is None:
errprefix = prefix
readerlist = []
pathlist = sys.path[:]
if '.' not in pathlist:
pathlist.append('.')
potential_files = []
for path in pathlist:
for filename in glob.iglob(os.path.join(path, 'G2' + prefix + '*.py')):
potential_files.append(filename)
potential_files = sorted(list(set(potential_files)))
for filename in potential_files:
path, rootname = os.path.split(filename)
pkg = os.path.splitext(rootname)[0]
try:
fp = None
fp, fppath, desc = imp.find_module(pkg, [path])
pkg = imp.load_module(pkg, fp, fppath, desc)
for name, value in inspect.getmembers(pkg):
if name.startswith('_'):
continue
if inspect.isclass(value):
for method in 'Reader', 'ExtensionValidator', 'ContentsValidator':
if not hasattr(value, method):
break
if not callable(getattr(value, method)):
break
else:
reader = value()
if reader.UseReader:
readerlist.append(reader)
except AttributeError:
G2Print('Import_' + errprefix + ': Attribute Error ' + filename)
if traceback:
traceback.print_exc(file=sys.stdout)
except Exception as exc:
G2Print('\nImport_' + errprefix + ': Error importing file ' +
filename)
G2Print(u'Error message: {}\n'.format(exc))
if traceback:
traceback.print_exc(file=sys.stdout)
finally:
if fp:
fp.close()
return readerlist
[docs]def LoadExportRoutines(parent, traceback=False):
'''Routine to locate GSASII exporters
'''
exporterlist = []
pathlist = sys.path
filelist = []
for path in pathlist:
for filename in glob.iglob(os.path.join(path, "G2export*.py")):
filelist.append(filename)
filelist = sorted(list(set(filelist))) # remove duplicates
# go through the routines and import them, saving objects that
# have export routines (method Exporter)
for filename in filelist:
path, rootname = os.path.split(filename)
pkg = os.path.splitext(rootname)[0]
try:
fp = None
fp, fppath, desc = imp.find_module(pkg, [
path,
])
pkg = imp.load_module(pkg, fp, fppath, desc)
for clss in inspect.getmembers(
pkg): # find classes defined in package
if clss[0].startswith('_'):
continue
if not inspect.isclass(clss[1]):
continue
# check if we have the required methods
if not hasattr(clss[1], 'Exporter'):
continue
if not callable(getattr(clss[1], 'Exporter')):
continue
if parent is None:
if not hasattr(clss[1], 'Writer'):
continue
else:
if not hasattr(clss[1], 'loadParmDict'):
continue
if not callable(getattr(clss[1], 'loadParmDict')):
continue
try:
exporter = clss[1](parent) # create an export instance
except AttributeError:
pass
except Exception as exc:
G2Print('\nExport init: Error substantiating class ' +
clss[0])
G2Print(u'Error message: {}\n'.format(exc))
if traceback:
traceback.print_exc(file=sys.stdout)
continue
exporterlist.append(exporter)
except AttributeError:
G2Print('Export Attribute Error ' + filename)
if traceback:
traceback.print_exc(file=sys.stdout)
except Exception as exc:
G2Print('\nExport init: Error importing file ' + filename)
G2Print(u'Error message: {}\n'.format(exc))
if traceback:
traceback.print_exc(file=sys.stdout)
finally:
if fp:
fp.close()
return exporterlist
[docs]def LoadControls(Slines, data):
'Read values from a .imctrl (Image Controls) file'
cntlList = [
'color', 'wavelength', 'distance', 'tilt', 'invert_x', 'invert_y',
'type', 'Oblique', 'fullIntegrate', 'outChannels', 'outAzimuths',
'LRazimuth', 'IOtth', 'azmthOff', 'DetDepth', 'calibskip', 'pixLimit',
'cutoff', 'calibdmin', 'Flat Bkg', 'varyList', 'setdist', 'PolaVal',
'SampleAbs', 'dark image', 'background image', 'twoth'
]
save = {}
for S in Slines:
if S[0] == '#':
continue
[key, val] = S.strip().split(':', 1)
if key in [
'type',
'calibrant',
'binType',
'SampleShape',
'color',
]: #strings
save[key] = val
elif key in [
'varyList',
]:
save[key] = eval(val) #dictionary
elif key in ['rotation']:
save[key] = float(val)
elif key in [
'center',
]:
if ',' in val:
save[key] = eval(val)
else:
vals = val.strip('[] ').split()
save[key] = [float(vals[0]), float(vals[1])]
elif key in cntlList:
save[key] = eval(val)
data.update(save)
[docs]def WriteControls(filename, data):
'Write current values to a .imctrl (Image Controls) file'
File = open(filename, 'w')
keys = [
'type', 'color', 'wavelength', 'calibrant', 'distance', 'center',
'Oblique', 'tilt', 'rotation', 'azmthOff', 'fullIntegrate', 'LRazimuth',
'setdist', 'IOtth', 'outChannels', 'outAzimuths', 'invert_x',
'invert_y', 'DetDepth', 'calibskip', 'pixLimit', 'cutoff', 'calibdmin',
'Flat Bkg', 'varyList', 'binType', 'SampleShape', 'PolaVal',
'SampleAbs', 'dark image', 'background image', 'twoth'
]
for key in keys:
if key not in data: #uncalibrated!
continue
File.write(key + ':' + str(data[key]) + '\n')
File.close()
[docs]def RereadImageData(ImageReaderlist, imagefile, ImageTag=None, FormatName=''):
'''Read a single image with an image importer. This is called to
reread an image after it has already been imported, so it is not
necessary to reload metadata.
Based on :func:`GetImageData.GetImageData` which this can replace
where imageOnly=True
:param list ImageReaderlist: list of Reader objects for images
:param str imagefile: name of image file
:param int/str ImageTag: specifies a particular image to be read from a file.
First image is read if None (default).
:param str formatName: the image reader formatName
:returns: an image as a numpy array
'''
# determine which formats are compatible with this file
primaryReaders = []
secondaryReaders = []
for rd in ImageReaderlist:
flag = rd.ExtensionValidator(imagefile)
if flag is None:
secondaryReaders.append(rd)
elif flag:
if not FormatName:
primaryReaders.append(rd)
elif FormatName == rd.formatName:
primaryReaders.append(rd)
if len(secondaryReaders) + len(primaryReaders) == 0:
G2Print('Error: No matching format for file ' + imagefile)
raise Exception('No image read')
errorReport = ''
if not imagefile:
return
for rd in primaryReaders + secondaryReaders:
rd.ReInitialize() # purge anything from a previous read
rd.errors = "" # clear out any old errors
if not rd.ContentsValidator(imagefile): # rejected on cursory check
errorReport += "\n " + rd.formatName + ' validator error'
if rd.errors:
errorReport += ': ' + rd.errors
continue
flag = rd.Reader(imagefile, None, blocknum=ImageTag)
if flag: # this read succeeded
if rd.Image is None:
raise Exception('No image read. Strange!')
if GSASIIpath.GetConfigValue('Transpose'):
G2Print('Warning: Transposing Image!')
rd.Image = rd.Image.T
#rd.readfilename = imagefile
return rd.Image
else:
G2Print('Error reading file ' + imagefile)
G2Print('Error messages(s)\n' + errorReport)
raise Exception('No image read')
[docs]def readMasks(filename, masks, ignoreThreshold):
'''Read a GSAS-II masks file'''
File = open(filename, 'r')
save = {}
oldThreshold = masks['Thresholds'][0]
S = File.readline()
while S:
if S[0] == '#':
S = File.readline()
continue
[key, val] = S.strip().split(':', 1)
if key in [
'Points', 'Rings', 'Arcs', 'Polygons', 'Frames', 'Thresholds'
]:
if ignoreThreshold and key == 'Thresholds':
S = File.readline()
continue
save[key] = eval(val)
if key == 'Thresholds':
save[key][0] = oldThreshold
save[key][1][1] = min(oldThreshold[1], save[key][1][1])
S = File.readline()
File.close()
masks.update(save)
# CleanupMasks
for key in ['Points', 'Rings', 'Arcs', 'Polygons']:
masks[key] = masks.get(key, [])
masks[key] = [i for i in masks[key] if len(i)]
[docs]def PDFWrite(PDFentry, fileroot, PDFsaves, PDFControls, Inst={}, Limits=[]):
'''Write PDF-related data (G(r), S(Q),...) into files, as
selected.
:param str PDFentry: name of the PDF entry in the tree. This is
used for comments in the file specifying where it came from;
it can be arbitrary
:param str fileroot: name of file(s) to be written. The extension
will be ignored.
:param list PDFsaves: flags that determine what type of file will be
written:
PDFsaves[0], if True writes a I(Q) file with a .iq extension
PDFsaves[1], if True writes a S(Q) file with a .sq extension
PDFsaves[2], if True writes a F(Q) file with a .fq extension
PDFsaves[3], if True writes a G(r) file with a .gr extension
PDFsaves[4], if True writes G(r) in a pdfGUI input file with
a .gr extension. Note that if PDFsaves[3] and PDFsaves[4] are
both True, the pdfGUI overwrites the G(r) file.
:param dict PDFControls: The PDF parameters and computed results
:param dict Inst: Instrument parameters from the PDWR entry used
to compute the PDF. Needed only when PDFsaves[4] is True.
:param list Limits: Computation limits from the PDWR entry used
to compute the PDF. Needed only when PDFsaves[4] is True.
'''
import scipy.interpolate as scintp
fileroot = os.path.splitext(fileroot)[0]
if PDFsaves[0]: #I(Q)
iqfilename = fileroot + '.iq'
iqdata = PDFControls['I(Q)'][1]
iqfxn = scintp.interp1d(iqdata[0], iqdata[1], kind='linear')
iqfile = open(iqfilename, 'w')
iqfile.write('#T I(Q) %s\n' % (PDFentry))
iqfile.write('#L Q I(Q)\n')
qnew = np.arange(iqdata[0][0], iqdata[0][-1], 0.005)
iqnew = zip(qnew, iqfxn(qnew))
for q, iq in iqnew:
iqfile.write("%15.6g %15.6g\n" % (q, iq))
iqfile.close()
G2Print(' I(Q) saved to: ' + iqfilename)
if PDFsaves[1]: #S(Q)
sqfilename = fileroot + '.sq'
sqdata = PDFControls['S(Q)'][1]
sqfxn = scintp.interp1d(sqdata[0], sqdata[1], kind='linear')
sqfile = open(sqfilename, 'w')
sqfile.write('#T S(Q) %s\n' % (PDFentry))
sqfile.write('#L Q S(Q)\n')
qnew = np.arange(sqdata[0][0], sqdata[0][-1], 0.005)
sqnew = zip(qnew, sqfxn(qnew))
for q, sq in sqnew:
sqfile.write("%15.6g %15.6g\n" % (q, sq))
sqfile.close()
G2Print(' S(Q) saved to: ' + sqfilename)
if PDFsaves[2]: #F(Q)
fqfilename = fileroot + '.fq'
fqdata = PDFControls['F(Q)'][1]
fqfxn = scintp.interp1d(fqdata[0], fqdata[1], kind='linear')
fqfile = open(fqfilename, 'w')
fqfile.write('#T F(Q) %s\n' % (PDFentry))
fqfile.write('#L Q F(Q)\n')
qnew = np.arange(fqdata[0][0], fqdata[0][-1], 0.005)
fqnew = zip(qnew, fqfxn(qnew))
for q, fq in fqnew:
fqfile.write("%15.6g %15.6g\n" % (q, fq))
fqfile.close()
G2Print(' F(Q) saved to: ' + fqfilename)
if PDFsaves[3]: #G(R)
grfilename = fileroot + '.gr'
grdata = PDFControls['G(R)'][1]
grfxn = scintp.interp1d(grdata[0], grdata[1], kind='linear')
grfile = open(grfilename, 'w')
grfile.write('#T G(R) %s\n' % (PDFentry))
grfile.write('#L R G(R)\n')
rnew = np.arange(grdata[0][0], grdata[0][-1], 0.010)
grnew = zip(rnew, grfxn(rnew))
for r, gr in grnew:
grfile.write("%15.6g %15.6g\n" % (r, gr))
grfile.close()
G2Print(' G(R) saved to: ' + grfilename)
if PDFsaves[4]: #pdfGUI file for G(R)
import GSASIIlattice as G2lat
import GSASIImath as G2mth
grfilename = fileroot + '.gr'
grdata = PDFControls['G(R)'][1]
qdata = PDFControls['I(Q)'][1][0]
grfxn = scintp.interp1d(grdata[0], grdata[1], kind='linear')
grfile = open(grfilename, 'w')
rnew = np.arange(grdata[0][0], grdata[0][-1], 0.010)
grnew = zip(rnew, grfxn(rnew))
grfile.write('[DEFAULT]\n')
grfile.write('\n')
grfile.write('version = GSAS-II-v' +
str(GSASIIpath.GetVersionNumber()) + '\n')
grfile.write('\n')
grfile.write('# input and output specifications\n')
grfile.write('dataformat = Qnm\n')
grfile.write('inputfile = %s\n' % (PDFControls['Sample']['Name']))
grfile.write('backgroundfile = %s\n' %
(PDFControls['Sample Bkg.']['Name']))
grfile.write('outputtype = gr\n')
grfile.write('\n')
grfile.write('# PDF calculation setup\n')
if 'x' in Inst['Type']:
grfile.write('mode = %s\n' % ('xray'))
elif 'N' in Inst['Type']:
grfile.write('mode = %s\n' % ('neutron'))
wave = G2mth.getMeanWave(Inst)
grfile.write('wavelength = %.5f\n' % (wave))
formula = ''
for el in PDFControls['ElList']:
formula += el
num = PDFControls['ElList'][el]['FormulaNo']
if num == round(num):
formula += '%d' % (int(num))
else:
formula += '%.2f' % (num)
grfile.write('composition = %s\n' % (formula))
grfile.write('bgscale = %.3f\n' % (-PDFControls['Sample Bkg.']['Mult']))
highQ = 2. * np.pi / G2lat.Pos2dsp(Inst, Limits[1][1])
grfile.write('qmaxinst = %.2f\n' % (highQ))
grfile.write('qmin = %.5f\n' % (qdata[0]))
grfile.write('qmax = %.4f\n' % (qdata[-1]))
grfile.write('rmin = %.2f\n' % (PDFControls['Rmin']))
grfile.write('rmax = %.2f\n' % (PDFControls['Rmax']))
grfile.write('rstep = 0.01\n')
grfile.write('\n')
grfile.write('# End of config ' + 63 * '-')
grfile.write('\n')
grfile.write('#### start data\n')
grfile.write('#S 1\n')
grfile.write(r'#L r($\AA$) G($\AA^{-2}$)\n')
for r, gr in grnew:
grfile.write("%15.2F %15.6F\n" % (r, gr))
grfile.close()
G2Print(' G(R) saved to: ' + grfilename)