pyextal.superspace.scattering ============================= .. py:module:: pyextal.superspace.scattering .. autoapi-nested-parse:: 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 :func:`afact ` evaluates at [sfsub.f90:373-378], and the Mott-Bethe conversion below is the one at [sfsub.f90:49]. Functions --------- .. autoapisummary:: pyextal.superspace.scattering.form_factor_table pyextal.superspace.scattering.xray_form_factor pyextal.superspace.scattering.electron_form_factor Module Contents --------------- .. py:function:: form_factor_table(path=None, reload=False) Parse the Cromer-Mann table. :param path: Table file; located automatically when None. :type path: path-like, optional :param reload: Re-read even if already cached. :type reload: bool :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'``. :rtype: dict .. py:function:: xray_form_factor(element, s) X-ray atomic form factor. :param element: Element symbol. :type element: str :param s: ``|g| / 2`` in inverse Angstrom, i.e. sin(theta)/lambda. :type s: array-like :returns: ``f_x(s)`` in electrons, same shape as `s`. :rtype: np.ndarray .. py:function:: 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. :param element: Element symbol. :type element: str :param s: ``|g| / 2`` in inverse Angstrom. :type s: array-like :param s_floor: Lower clamp on `s`. :type s_floor: float :returns: ``f_e(s)`` in Angstrom, same shape as `s`. :rtype: np.ndarray