pyextal.superspace.scattering

Atomic scattering factors, read from the engine’s own tables.

The kinematic half of this subpackage has to agree with the dynamical half, and the surest way to get that is to use the same numbers the Fortran does rather than a second parameterisation that is merely close. sftabl.sct ships in the pyextal package directory (CMake installs it there because the engine looks it up through $EMAPS), and holds Cromer-Mann coefficients:

LABEL  Z  a1 b1  a2 b2  a3 b3  a4 b4  c

so the X-ray form factor is f_x(s) = c + sum_i a_i exp(-b_i s^2) with s = |g| / 2 = sin(theta)/lambda. This is exactly what afact evaluates at [sfsub.f90:373-378], and the Mott-Bethe conversion below is the one at [sfsub.f90:49].

Functions

form_factor_table([path, reload])

Parse the Cromer-Mann table.

xray_form_factor(element, s)

X-ray atomic form factor.

electron_form_factor(element, s[, s_floor])

Electron scattering factor by the Mott-Bethe relation.

Module Contents

pyextal.superspace.scattering.form_factor_table(path=None, reload=False)

Parse the Cromer-Mann table.

Parameters:
  • path (path-like, optional) – Table file; located automatically when None.

  • reload (bool) – Re-read even if already cached.

Returns:

Upper-case label -> (Z, a, b, c) with a and b each (4,). Keys include ionic and valence entries as spelled in the file, e.g. 'TA', 'S', 'LI+1', 'CVAL'.

Return type:

dict

pyextal.superspace.scattering.xray_form_factor(element, s)

X-ray atomic form factor.

Parameters:
  • element (str) – Element symbol.

  • s (array-like) – |g| / 2 in inverse Angstrom, i.e. sin(theta)/lambda.

Returns:

f_x(s) in electrons, same shape as s.

Return type:

np.ndarray

pyextal.superspace.scattering.electron_form_factor(element, s, s_floor=1e-05)

Electron scattering factor by the Mott-Bethe relation.

f_e = MOTT * (Z_eff - f_x) / s^2, which diverges as s -> 0; the engine clamps s to 1e-5 there ([sfsub.f90:27]) and so does this, so the direct beam gets a large finite value rather than an infinity.

Z_eff is the Cromer-Mann parameterisation’s own zero-angle value, sum(a) + c, not the integer nuclear charge – which is what the Fortran engine uses (zt comes out as 72.95366 for Ta, against Z = 73). The difference is the fit’s residual at s = 0, and dividing it by s^2 turns it into a spurious tail that grows without bound as s -> 0: 0.8% of f_e for Ta already at s = 0.125. Since satellites sit close to their main reflections, that is exactly where they live. Using the integer Z here made the Python disagree with the engine by ~1e-3 across the board.

Parameters:
  • element (str) – Element symbol.

  • s (array-like) – |g| / 2 in inverse Angstrom.

  • s_floor (float) – Lower clamp on s.

Returns:

f_e(s) in Angstrom, same shape as s.

Return type:

np.ndarray