Coverage for larch/xafs/feffdat.py: 82%
457 statements
« prev ^ index » next coverage.py v7.6.0, created at 2024-10-16 21:04 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2024-10-16 21:04 +0000
1#!/usr/bin/env python
2"""
3feffdat provides the following function related to
4reading and dealing with Feff.data files in larch:
6 path1 = read_feffdat('feffNNNN.dat')
8returns a Feff Group -- a special variation of a Group -- for
9the path represented by the feffNNNN.dat
11 group = ff2chi(paths)
13creates a group that contains the chi(k) for the sum of paths.
14"""
15from pathlib import Path
16import numpy as np
17from copy import deepcopy
18from scipy.interpolate import UnivariateSpline
19from lmfit import Parameters, Parameter
21from xraydb import atomic_mass, atomic_symbol
23from larch import Group, isNamedClass
24from larch.utils.strutils import fix_varname, b32hash
25from larch.fitting import group2params, dict2params, isParameter, param_value
26from .xafsutils import ETOK, ktoe, set_xafsGroup, gfmt
27from .sigma2_models import add_sigma2funcs
29SMALL_ENERGY = 1.e-6
31PATH_PARS = ('degen', 's02', 'e0', 'ei', 'deltar', 'sigma2', 'third', 'fourth')
32FDAT_ARRS = ('real_phc', 'mag_feff', 'pha_feff', 'red_fact',
33 'lam', 'rep', 'pha', 'amp', 'k')
35# values that will be available in calculations of Path Parameter values
36FEFFDAT_VALUES = ('reff', 'nleg', 'degen', 'rmass', 'rnorman',
37 'gam_ch', 'rs_int', 'vint', 'vmu', 'vfermi')
39class FeffDatFile(Group):
40 def __init__(self, filename=None, **kws):
41 kwargs = dict(name='feff.dat: %s' % filename)
42 kwargs.update(kws)
43 Group.__init__(self, **kwargs)
44 if filename not in ('', None) and Path(filename).exists():
45 self._read(filename)
47 def __repr__(self):
48 if self.filename is not None:
49 return '<Feff.dat File Group: %s>' % self.filename
50 return '<Feff.dat File Group (empty)>'
52 def __copy__(self):
53 return FeffDatFile(filename=self.filename)
55 def __deepcopy__(self, memo):
56 return FeffDatFile(filename=self.filename)
58 @property
59 def reff(self): return self.__reff__
61 @reff.setter
62 def reff(self, val): pass
64 @property
65 def nleg(self): return self.__nleg__
67 @nleg.setter
68 def nleg(self, val): pass
70 @property
71 def rmass(self):
72 """reduced mass for a path"""
73 if self.__rmass is None:
74 rmass = 0
75 for atsym, iz, ipot, amass, x, y, z in self.geom:
76 rmass += 1.0/max(1., amass)
77 self.__rmass = 1./rmass
78 return self.__rmass
80 @rmass.setter
81 def rmass(self, val): pass
83 def _set_from_dict(self, **kws):
84 self.__rmass = None
85 for key, val in kws.items():
86 if key == 'rmass':
87 continue
88 elif key == 'reff':
89 key = '__reff__'
90 elif key == 'nleg':
91 key = '__nleg__'
92 elif key in FDAT_ARRS:
93 val = np.array(val)
94 setattr(self, key, val)
96 def __setstate__(self, state):
97 (self.filename, self.title, self.version, self.shell,
98 self.absorber, self.degen, self.__reff__, self.__nleg__,
99 self.rnorman, self.edge, self.gam_ch, self.exch, self.vmu, self.vfermi,
100 self.vint, self.rs_int, self.potentials, self.geom, self.__rmass,
101 self.k, self.real_phc, self.mag_feff, self.pha_feff,
102 self.red_fact, self.lam, self.rep, self.pha, self.amp) = state
104 self.k = np.array(self.k)
105 self.real_phc = np.array(self.real_phc)
106 self.mag_feff = np.array(self.mag_feff)
107 self.pha_feff = np.array(self.pha_feff)
108 self.red_fact = np.array(self.red_fact)
109 self.lam = np.array(self.lam)
110 self.rep = np.array(self.rep)
111 self.pha = np.array(self.pha)
112 self.amp = np.array(self.amp)
114 def __getstate__(self):
115 return (self.filename, self.title, self.version, self.shell,
116 self.absorber, self.degen, self.__reff__, self.__nleg__,
117 self.rnorman, self.edge, self.gam_ch, self.exch, self.vmu,
118 self.vfermi, self.vint, self.rs_int, self.potentials,
119 self.geom, self.__rmass, self.k.tolist(),
120 self.real_phc.tolist(), self.mag_feff.tolist(),
121 self.pha_feff.tolist(), self.red_fact.tolist(),
122 self.lam.tolist(), self.rep.tolist(), self.pha.tolist(),
123 self.amp.tolist())
126 def _read(self, filename):
127 try:
128 with open(filename, 'r') as fh:
129 lines = fh.readlines()
130 except:
131 print(f"Error reading Feff Data file '{filename}'")
132 return
133 self.filename = filename
134 mode = 'header'
135 self.potentials, self.geom = [], []
136 data = []
137 pcounter = 0
138 iline = 0
139 for line in lines:
140 iline += 1
141 line = line[:-1].strip()
142 if line.startswith('#'): line = line[1:]
143 line = line.strip()
144 if iline == 1:
145 self.title = line[:64].strip()
146 self.version = line[64:].strip()
147 continue
148 if line.startswith('k') and line.endswith('real[p]@#'):
149 mode = 'arrays'
150 continue
151 elif '----' in line[2:10]:
152 mode = 'path'
153 continue
154 #
155 if (mode == 'header' and
156 line.startswith('Abs') or line.startswith('Pot')):
157 words = line.replace('=', ' ').split()
158 ipot, z, rmt, rnm = (0, 0, 0, 0)
159 words.pop(0)
160 if line.startswith('Pot'):
161 ipot = int(words.pop(0))
162 iz = int(words[1])
163 rmt = float(words[3])
164 rnm = float(words[5])
165 if line.startswith('Abs'):
166 self.shell = words[6]
167 self.potentials.append((ipot, iz, rmt, rnm))
168 elif mode == 'header' and line.startswith('Gam_ch'):
169 words = line.replace('=', ' ').split(None, 2)
170 self.gam_ch = float(words[1])
171 self.exch = words[2]
172 elif mode == 'header' and line.startswith('Mu'):
173 words = line.replace('=', ' ').replace('eV', ' ').split()
174 self.vmu = float(words[1])
175 self.vfermi = ktoe(float(words[3]))
176 self.vint = float(words[5])
177 self.rs_int= float(words[7])
178 elif mode == 'path':
179 pcounter += 1
180 if pcounter == 1:
181 w = [float(x) for x in line.split()[:5]]
182 self.__nleg__ = int(w.pop(0))
183 self.degen, self.__reff__, self.rnorman, self.edge = w
184 elif pcounter > 2:
185 words = line.split()
186 xyz = ["%7.4f" % float(x) for x in words[:3]]
187 ipot = int(words[3])
188 iz = int(words[4])
189 if len(words) > 5:
190 lab = words[5]
191 else:
192 lab = atomic_symbol(iz)
193 amass = atomic_mass(iz)
194 geom = [lab, iz, ipot, amass] + xyz
195 if len(self.geom) == 0:
196 self.absorber = lab
197 self.geom.append(tuple(geom))
198 elif mode == 'arrays':
199 d = np.array([float(x) for x in line.split()])
200 if len(d) == 7:
201 data.append(d)
202 data = np.array(data).transpose()
203 self.k = data[0]
204 self.real_phc = data[1]
205 self.mag_feff = data[2]
206 self.pha_feff = data[3]
207 self.red_fact = data[4]
208 self.lam = data[5]
209 self.rep = data[6]
210 self.pha = data[1] + data[3]
211 self.amp = data[2] * data[4]
212 self.__rmass = None # reduced mass of path
215class FeffPathGroup(Group):
216 def __init__(self, filename=None, label='', feffrun='', s02=None, degen=None,
217 e0=None, ei=None, deltar=None, sigma2=None, third=None,
218 fourth=None, use=True, _feffdat=None, **kws):
219 kwargs = dict(filename=filename)
220 kwargs.update(kws)
221 Group.__init__(self, **kwargs)
223 self.filename = filename
224 self.feffrun = feffrun
225 self.label = label
226 self.use = use
227 self.params = None
228 self.spline_coefs = None
229 self.geom = []
230 self.shell = 'K'
231 self.absorber = None
232 self._feffdat = _feffdat
233 self.dataset = 'd001'
234 self.hashkey = 'p001'
235 self.k = None
236 self.chi = None
238 self.__def_degen = 1
240 if filename not in ('', None) and Path(filename).exists():
241 self._feffdat = FeffDatFile(filename=filename)
243 if self._feffdat is not None:
244 self.create_spline_coefs()
245 self.geom = self._feffdat.geom
246 self.shell = self._feffdat.shell
247 self.absorber = self._feffdat.absorber
248 self.__def_degen = self._feffdat.degen
250 self.hashkey = self.__geom2label()
251 if self.label in ('', None):
252 self.label = self.hashkey
254 if feffrun in ('', None):
255 try:
256 self.feffrun = Path(filename).parent.name
257 except:
258 pass
260 self.init_path_params(degen=degen, s02=s02, e0=e0, ei=ei,
261 deltar=deltar, sigma2=sigma2, third=third,
262 fourth=fourth)
265 def init_path_params(self, degen=None, s02=None, e0=None, ei=None,
266 deltar=None, sigma2=None, third=None, fourth=None):
267 """set inital values/expressions for path parameters for Feff Path"""
268 self.degen = self.__def_degen if degen is None else degen
269 self.s02 = 1.0 if s02 is None else s02
270 self.e0 = 0.0 if e0 is None else e0
271 self.ei = 0.0 if ei is None else ei
272 self.deltar = 0.0 if deltar is None else deltar
273 self.sigma2 = 0.0 if sigma2 is None else sigma2
274 self.third = 0.0 if third is None else third
275 self.fourth = 0.0 if fourth is None else fourth
277 def __repr__(self):
278 if self.filename is not None:
279 return 'feffpath((no_file)'
280 return f'feffpath({self.filename})'
282 def __getstate__(self):
283 _feffdat_state = self._feffdat.__getstate__()
284 return (self.filename, self.label, self.feffrun, self.degen,
285 self.s02, self.e0, self.ei, self.deltar, self.sigma2,
286 self.third, self.fourth, self.use, _feffdat_state)
289 def __setstate__(self, state):
290 self.params = self.spline_coefs = self.k = self.chi = None
291 self.use = True
292 if len(state) == 12: # "use" was added after paths states were being saved
293 (self.filename, self.label, self.feffrun, self.degen,
294 self.s02, self.e0, self.ei, self.deltar, self.sigma2,
295 self.third, self.fourth, _feffdat_state) = state
296 elif len(state) == 13:
297 (self.filename, self.label, self.feffrun, self.degen,
298 self.s02, self.e0, self.ei, self.deltar, self.sigma2,
299 self.third, self.fourth, self.use, _feffdat_state) = state
301 self._feffdat = FeffDatFile()
302 self._feffdat.__setstate__(_feffdat_state)
304 self.create_spline_coefs()
306 self.geom = self._feffdat.geom
307 self.shell = self._feffdat.shell
308 self.absorber = self._feffdat.absorber
309 def_degen = self._feffdat.degen
311 self.hashkey = self.__geom2label()
312 if self.label in ('', None):
313 self.label = self.hashkey
316 def __geom2label(self):
317 """generate label by hashing path geometry"""
318 rep = [self._feffdat.degen, self._feffdat.shell, self.feffrun]
319 for atom in self.geom:
320 rep.extend(atom)
321 rep.append("%7.4f" % self._feffdat.reff)
322 s = "|".join([str(i) for i in rep])
323 return "p%s" % (b32hash(s)[:8].lower())
325 def pathpar_name(self, parname):
326 """
327 get internal name of lmfit Parameter for a path paramter, using Path's hashkey
328 """
329 return f'{parname}_{self.dataset}_{self.hashkey}'
331 def __copy__(self):
332 newpath = FeffPathGroup()
333 newpath.__setstate__(self.__getstate__())
334 return newpath
336 def __deepcopy__(self, memo):
337 newpath = FeffPathGroup()
338 newpath.__setstate__(self.__getstate__())
339 return newpath
342 @property
343 def reff(self): return self._feffdat.reff
345 @reff.setter
346 def reff(self, val): pass
348 @property
349 def nleg(self): return self._feffdat.nleg
351 @nleg.setter
352 def nleg(self, val): pass
354 @property
355 def rmass(self): return self._feffdat.rmass
357 @rmass.setter
358 def rmass(self, val): pass
360 def __repr__(self):
361 return f'<FeffPath Group label={self.label:s}, filename={self.filename:s}, use={self.use}>'
363 def create_path_params(self, params=None, dataset=None):
364 """
365 create Path Parameters within the current lmfit.Parameters namespace
366 """
367 if isinstance(params, Group):
368 params = group2params(params)
369 if params is not None:
370 self.params = params
371 if self.params is None:
372 self.params = Parameters()
373 if dataset is not None:
374 self.dataset = dataset
375 if (not isinstance(self.params, Parameters) and
376 isinstance(self.params, dict)):
377 self.params = dict2params(self.params)
379 if self.params._asteval.symtable.get('sigma2_debye', None) is None:
380 add_sigma2funcs(self.params)
381 if self.label is None:
382 self.label = self.__geom2label()
383 self.store_feffdat()
384 for pname in PATH_PARS:
385 val = getattr(self, pname)
386 attr = 'value'
387 if isinstance(val, str):
388 attr = 'expr'
389 kws = {'vary': False, attr: val}
390 parname = self.pathpar_name(pname)
391 self.params.add(parname, **kws)
392 self.params[parname].is_pathparam = True
394 def create_spline_coefs(self):
395 """pre-calculate spline coefficients for feff data"""
396 self.spline_coefs = {}
397 fdat = self._feffdat
398 self.spline_coefs['pha'] = UnivariateSpline(fdat.k, fdat.pha, s=0)
399 self.spline_coefs['amp'] = UnivariateSpline(fdat.k, fdat.amp, s=0)
400 self.spline_coefs['rep'] = UnivariateSpline(fdat.k, fdat.rep, s=0)
401 self.spline_coefs['lam'] = UnivariateSpline(fdat.k, fdat.lam, s=0)
403 def store_feffdat(self):
404 """stores data about this Feff path in the Parameters
405 symbol table for use as `reff` and in sigma2 calcs
406 """
407 if self.params is None:
408 self.create_path_params()
409 if (not isinstance(self.params, Parameters) and
410 isinstance(self.params, dict)):
411 self.params = dict2params(self.params)
413 symtab = self.params._asteval.symtable
414 symtab['feffpath'] = self._feffdat
415 for attr in FEFFDAT_VALUES:
416 symtab[attr] = getattr(self._feffdat, attr)
419 def __path_params(self, **kws):
420 """evaluate path parameter value. Returns
421 (degen, s02, e0, ei, deltar, sigma2, third, fourth)
422 """
423 # put 'reff' and '_feffdat' into the symboltable so that
424 # they can be used in constraint expressions
425 self.store_feffdat()
426 if self.params is None:
427 self.create_path_params()
429 out = []
430 for pname in PATH_PARS:
431 val = kws.get(pname, None)
432 if val is None:
433 parname = self.pathpar_name(pname)
434 val = self.params[parname]._getval()
435 out.append(val)
436 return out
438 def path_paramvals(self, **kws):
439 (deg, s02, e0, ei, delr, ss2, c3, c4) = self.__path_params()
440 return dict(degen=deg, s02=s02, e0=e0, ei=ei, deltar=delr,
441 sigma2=ss2, third=c3, fourth=c4)
443 def report(self):
444 "return text report of parameters"
445 tmpvals = self.__path_params()
446 pathpars = {}
447 for pname in ('degen', 's02', 'e0', 'deltar',
448 'sigma2', 'third', 'fourth', 'ei'):
449 parname = self.pathpar_name(pname)
450 if parname in self.params:
451 pathpars[pname] = (self.params[parname].value,
452 self.params[parname].stderr)
454 out = [f" = Path '{self.label}' = {self.absorber} {self.shell} Edge",
455 f" feffdat file = {self.filename}, from feff run '{self.feffrun}'"]
456 geomlabel = ' geometry atom x y z ipot'
457 geomformat = ' %4s %s, %s, %s %d'
458 out.append(geomlabel)
460 for atsym, iz, ipot, amass, x, y, z in self.geom:
461 s = geomformat % (atsym, x, y, z, ipot)
462 if ipot == 0: s = "%s (absorber)" % s
463 out.append(s)
465 stderrs = {}
466 out.append(' {:7s}= {:s}'.format('reff',
467 gfmt(self._feffdat.reff)))
469 for pname in ('degen', 's02', 'e0', 'r',
470 'deltar', 'sigma2', 'third', 'fourth', 'ei'):
471 val = strval = getattr(self, pname, 0)
472 parname = self.pathpar_name(pname)
473 std = None
474 if pname == 'r':
475 parname = self.pathpar_name('deltar')
476 par = self.params.get(parname, None)
477 val = par.value + self._feffdat.reff
478 strval = 'reff + ' + getattr(self, 'deltar', 0)
479 std = par.stderr
480 else:
481 if pname in pathpars:
482 val, std = pathpars[pname]
483 else:
484 par = self.params.get(parname, None)
485 if par is not None:
486 val = par.value
487 std = par.stderr
489 if std is None or std <= 0:
490 svalue = gfmt(val)
491 else:
492 svalue = "{:s} +/-{:s}".format(gfmt(val), gfmt(std))
493 if pname == 's02':
494 pname = 'n*s02'
496 svalue = " {:7s}= {:s}".format(pname, svalue)
497 if isinstance(strval, str):
498 svalue = "{:s} := '{:s}'".format(svalue, strval)
500 if val == 0 and pname in ('third', 'fourth', 'ei'):
501 continue
502 out.append(svalue)
503 return '\n'.join(out)
505 def calc_chi_from_params(self, params, **kws):
506 "calculate chi(k) from Parameters, ParameterGroup, and/or kws for path parameters"
507 if isinstance(params, Parameters):
508 self.create_path_params(params=params)
509 else:
510 self.create_path_params(params=group2params(params))
511 self._calc_chi(**kws)
513 def _calc_chi(self, k=None, kmax=None, kstep=None, degen=None, s02=None,
514 e0=None, ei=None, deltar=None, sigma2=None,
515 third=None, fourth=None, debug=False, interp='cubic', **kws):
516 """calculate chi(k) with the provided parameters"""
517 fdat = self._feffdat
518 if fdat.reff < 0.05:
519 print('reff is too small to calculate chi(k)')
520 return
521 # make sure we have a k array
522 if k is None:
523 if kmax is None:
524 kmax = 30.0
525 kmax = min(max(fdat.k), kmax)
526 if kstep is None: kstep = 0.05
527 k = kstep * np.arange(int(1.01 + kmax/kstep), dtype='float64')
528 if not self.use:
529 self.k = k
530 self.p = k
531 self.chi = 0.0 * k
532 self.chi_imag = 0.0 * k
533 return
534 reff = fdat.reff
535 # get values for all the path parameters
536 (degen, s02, e0, ei, deltar, sigma2, third, fourth) = \
537 self.__path_params(degen=degen, s02=s02, e0=e0, ei=ei,
538 deltar=deltar, sigma2=sigma2,
539 third=third, fourth=fourth)
541 # create e0-shifted energy and k, careful to look for |e0| ~= 0.
542 en = k*k - e0*ETOK
543 if min(abs(en)) < SMALL_ENERGY:
544 try:
545 en[np.where(abs(en) < 1.5*SMALL_ENERGY)] = SMALL_ENERGY
546 except ValueError:
547 pass
548 # q is the e0-shifted wavenumber
549 q = np.sign(en)*np.sqrt(abs(en))
551 # lookup Feff.dat values (pha, amp, rep, lam)
552 if interp.startswith('lin'):
553 pha = np.interp(q, fdat.k, fdat.pha)
554 amp = np.interp(q, fdat.k, fdat.amp)
555 rep = np.interp(q, fdat.k, fdat.rep)
556 lam = np.interp(q, fdat.k, fdat.lam)
557 else:
558 pha = self.spline_coefs['pha'](q)
559 amp = self.spline_coefs['amp'](q)
560 rep = self.spline_coefs['rep'](q)
561 lam = self.spline_coefs['lam'](q)
563 if debug:
564 self.debug_k = q
565 self.debug_pha = pha
566 self.debug_amp = amp
567 self.debug_rep = rep
568 self.debug_lam = lam
570 # p = complex wavenumber, and its square:
571 pp = (rep + 1j/lam)**2 + 1j * ei * ETOK
572 p = np.sqrt(pp)
574 # the xafs equation:
575 cchi = np.exp(-2*reff*p.imag - 2*pp*(sigma2 - pp*fourth/3) +
576 1j*(2*q*reff + pha +
577 2*p*(deltar - 2*sigma2/reff - 2*pp*third/3) ))
579 cchi = degen * s02 * amp * cchi / (q*(reff + deltar)**2)
580 cchi[0] = 2*cchi[1] - cchi[2]
581 # outputs:
582 self.k = k
583 self.p = p
584 self.chi = cchi.imag
585 self.chi_imag = -cchi.real
589def path2chi(path, params=None, paramgroup=None, **kws):
590 """calculate chi(k) for a Feff Path,
591 optionally setting path parameter values
592 output chi array will be written to path group
594 Parameters:
595 ------------
596 path: a FeffPath Group
597 params: lmfit Parameters or larch ParameterGroup
598 kmax: maximum k value for chi calculation [20].
599 kstep: step in k value for chi calculation [0.05].
600 k: explicit array of k values to calculate chi.
602 Returns:
603 ---------
604 None - outputs are written to path group
606 """
607 if not isNamedClass(path, FeffPathGroup):
608 msg('%s is not a valid Feff Path' % path)
609 return
610 if params is None and paramgroup is not None:
611 params = group2params(paramgroup)
612 path.calc_chi_from_params(params=params, **kws)
615def ff2chi(paths, group=None, params=None, k=None, kmax=None, kstep=0.05,
616 paramgroup=None, **kws):
617 """sum chi(k) for a list of FeffPath Groups.
619 Parameters:
620 ------------
621 paths: a list of FeffPath Groups or dict of {label: FeffPathGroups}
622 params: lmfit.Parameters for calculating Path Parameters [None]
623 paramgroup: (old) Group of Parameters for calculating Path Parameters [None]
624 kmax: maximum k value for chi calculation [20].
625 kstep: step in k value for chi calculation [0.05].
626 k: explicit array of k values to calculate chi.
627 Returns:
628 ---------
629 group contain arrays for k and chi
631 This essentially calls path2chi() for each of the paths in the
632 `paths` and writes the resulting arrays to group.k and group.chi.
634 """
635 if params is None:
636 if isinstance(paramgroup, Parameters):
637 params = paramgroup
638 else:
639 params = group2params(paramgroup)
641 if isinstance(paths, (list, tuple)):
642 pathlist = paths
643 elif isinstance(paths, dict):
644 pathlist = list(paths.values())
645 else:
646 raise ValueErrror('paths must be list, tuple, or dict')
648 if len(pathlist) == 0:
649 return Group(k=np.linspace(0, 20, 401),
650 chi=np.zeros(401, dtype='float64'))
652 for path in pathlist:
653 if not isNamedClass(path, FeffPathGroup):
654 print(f"{path} is not a valid Feff Path")
655 return
656 path.create_path_params(params=params)
657 path._calc_chi(k=k, kstep=kstep, kmax=kmax)
658 k = pathlist[0].k[:]*1.0
659 out = np.zeros_like(k)
660 for path in pathlist:
661 out += path.chi
663 if group is None:
664 group = Group()
665 group.k = k
666 group.chi = out
667 return group
669def feffpath(filename='', label='', feffrun='', s02=None, degen=None,
670 e0=None,ei=None, deltar=None, sigma2=None, third=None,
671 fourth=None, use=True, **kws):
672 """create a Feff Path Group from a *feffNNNN.dat* file.
674 Parameters:
675 -----------
676 filename: name (full path of) *feffNNNN.dat* file
677 label: label for path [file name]
678 degen: path degeneracy, N [taken from file]
679 s02: S_0^2 value or parameter [1.0]
680 e0: E_0 value or parameter [0.0]
681 deltar: delta_R value or parameter [0.0]
682 sigma2: sigma^2 value or parameter [0.0]
683 third: c_3 value or parameter [0.0]
684 fourth: c_4 value or parameter [0.0]
685 ei: E_i value or parameter [0.0]
686 feffrun: label for Feff run [parent folder of Feff.dat file]
687 use : use in sum of paths [True]
689 For all the options described as **value or parameter** either a
690 numerical value or a Parameter (as created by param()) can be given.
692 Returns:
693 ---------
694 a FeffPath Group.
695 """
696 if filename != '' and not Path(filename).exists():
697 raise ValueError(f"Feff Path file '{filename:s}' not found")
698 return FeffPathGroup(filename=filename, label=label, feffrun=feffrun,
699 s02=s02, degen=degen, e0=e0, ei=ei, deltar=deltar,
700 sigma2=sigma2, third=third, fourth=fourth, use=use)
702def use_feffpath(pathcache, label, degen=None, s02=None, e0=None,ei=None,
703 deltar=None, sigma2=None, third=None, fourth=None, use=True):
704 """use a copy of a Feff Path from a cache of feff paths - a simply dictionary
705 keyed by the path label, and to support in-memory paths, not read from feff.dat files
707 Parameters:
708 -----------
709 pathcache: dictionary of feff paths
710 label: label for path -- the dictionary key
711 degen: path degeneracy, N [taken from file]
712 s02: S_0^2 value or parameter [1.0]
713 e0: E_0 value or parameter [0.0]
714 deltar: delta_R value or parameter [0.0]
715 sigma2: sigma^2 value or parameter [0.0]
716 third: c_3 value or parameter [0.0]
717 fourth: c_4 value or parameter [0.0]
718 ei: E_i value or parameter [0.0]
719 use: whether to use path in sum [True]
720 """
721 path = deepcopy(pathcache[label])
722 path.use = use
723 path.init_path_params(s02=s02, degen=degen, e0=e0, ei=ei,
724 deltar=deltar, sigma2=sigma2, third=third,
725 fourth=fourth)
726 return path