Skip to content

scattering_factors

X-ray atomic scattering factors (form factors).

The atomic form factor f(s) describes how strongly an atom scatters X-rays as a function of s = sin(theta) / lambda. It is the Fourier transform of the atomic electron density: f(0) equals the number of electrons (~ the atomic number) and falls off with increasing scattering angle.

We use the Waasmaier-Kirfel five-Gaussian parameterisation

f(s) = sum_{i=1}^{5} a_i * exp(-b_i * s^2) + c

valid for s up to 6 A^-1.

Source: D. Waasmaier & A. Kirfel, Acta Cryst. (1995) A51, 416-431.

atomic_form_factor(atomic_numbers, sin_theta_over_lambda)

Evaluate atomic form factors f(s) (Waasmaier-Kirfel five-Gaussian fit).

Parameters:

Name Type Description Default
atomic_numbers

(N,) array of integer atomic numbers

required
sin_theta_over_lambda

(M,) array of s = sin(theta)/lambda values in A^-1

required

Returns:

Type Description
ndarray

(N, M) array where entry (i, j) is f of atom i at s value j.

Raises:

Type Description
ValueError

if an atomic number has no tabulated coefficients. The set of supported atomic numbers is available as AVAILABLE.

Source code in chmpy/crystal/scattering_factors.py
def atomic_form_factor(atomic_numbers, sin_theta_over_lambda) -> np.ndarray:
    """Evaluate atomic form factors f(s) (Waasmaier-Kirfel five-Gaussian fit).

    Args:
        atomic_numbers: (N,) array of integer atomic numbers
        sin_theta_over_lambda: (M,) array of s = sin(theta)/lambda values in A^-1

    Returns:
        (N, M) array where entry (i, j) is f of atom i at s value j.

    Raises:
        ValueError: if an atomic number has no tabulated coefficients. The set
            of supported atomic numbers is available as `AVAILABLE`.
    """
    atomic_numbers = np.atleast_1d(np.asarray(atomic_numbers, dtype=int))
    s = np.atleast_1d(np.asarray(sin_theta_over_lambda, dtype=np.float64))
    s2 = s * s

    result = np.empty((len(atomic_numbers), len(s)), dtype=np.float64)
    for i, z in enumerate(atomic_numbers):
        if int(z) not in _COEFFICIENTS_BY_NUMBER:
            raise ValueError(
                f"No tabulated X-ray scattering factor for "
                f"{Element.from_atomic_number(int(z))} (atomic number {int(z)})"
            )
        a_coeffs, b_coeffs, c = _COEFFICIENTS_BY_NUMBER[int(z)]
        f = np.full_like(s, c)
        for a_k, b_k in zip(a_coeffs, b_coeffs, strict=True):
            f += a_k * np.exp(-b_k * s2)
        result[i] = f
    return result