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¶
|
Parse the Cromer-Mann table. |
|
X-ray atomic form factor. |
|
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| / 2in 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 ass -> 0; the engine clampssto 1e-5 there ([sfsub.f90:27]) and so does this, so the direct beam gets a large finite value rather than an infinity.Z_effis the Cromer-Mann parameterisation’s own zero-angle value,sum(a) + c, not the integer nuclear charge – which is what the Fortran engine uses (ztcomes out as 72.95366 for Ta, against Z = 73). The difference is the fit’s residual ats = 0, and dividing it bys^2turns it into a spurious tail that grows without bound ass -> 0: 0.8% off_efor Ta already ats = 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| / 2in inverse Angstrom.s_floor (float) – Lower clamp on s.
- Returns:
f_e(s)in Angstrom, same shape as s.- Return type:
np.ndarray