pyextal.superspace.structurefactor¶
The modulated structure factor.
This is item 2: the change to how sfact works. For an unmodulated crystal a
structure factor is a sum over atoms. For a modulated one each atom is smeared
over the internal coordinate, and the sum becomes a sum of integrals:
- F(H) = sum_mu f_mu(s) T_mu(s) Int_[0,1]^d dxbar P_mu(xbar)
exp{ 2 pi i [ h . r_mu + m . xbar + S(H) . u_mu(xbar) ] }
with h the integer main index, m the satellite index, S(H) the
effective, non-integral reciprocal index, and u_mu the displacement field.
Setting every u = 0 and m = 0 collapses it to the ordinary expression,
which is one of the tests.
Why quadrature rather than Bessel functions¶
For a single harmonic displacive modulation the integral has the closed form
J_-m(2 pi S.A), and textbooks present it that way. That form does not
survive several harmonics, or an occupational modulation multiplying a
displacive one, and the published 1T-TaS2 refinement used 21 harmonics on Ta.
The integrand is smooth and periodic, so the plain rectangle rule converges
exponentially in the number of points – there is no accuracy left on the
table, and it handles every case with one code path. bessel_reference()
provides the closed form so the quadrature can be checked against it.
The one thing that will silently go wrong is an under-resolved grid: the
integrand’s bandwidth grows with satellite order and with modulation amplitude,
and too few points aliases high harmonics onto low ones. auto_n_internal()
sizes the grid from both, and structure_factor() uses it by default.
Not implemented: modulated ADPs. B is a constant per atom. A modulated ADP would slot into the integrand next to P, but nothing here needs it yet and an untested implementation is worse than an honest gap.
Functions¶
|
Uniform sampling of the internal unit cell |
|
Choose a grid fine enough that the quadrature does not alias. |
|
Structure factors of a modulated structure. |
|
Closed-form structure factor for one atom with a single harmonic. |
Module Contents¶
- pyextal.superspace.structurefactor.internal_grid(d, n)¶
Uniform sampling of the internal unit cell
[0, 1)^d.- Parameters:
d (int) – Number of modulation dimensions.
n (int) – Points per dimension.
- Returns:
(n**d, d) internal coordinates.
- Return type:
np.ndarray
- pyextal.superspace.structurefactor.auto_n_internal(atoms, hkl, max_order, safety=4, lo=16, hi=256)¶
Choose a grid fine enough that the quadrature does not alias.
The integrand carries
exp(2 pi i m.xbar), contributing bandwidthmax|m|, andexp(2 pi i S.u(xbar)), whose Jacobi-Anger expansion has significant terms out to roughly|z| + 4in each harmonic present, wherez = 2 pi max|S.u|. The rectangle rule is exact belown/2, so the grid is sized at safety times the estimated bandwidth.- Parameters:
atoms (list[ModulatedAtom]) – Supplies the modulation amplitudes.
hkl (np.ndarray) – (n, 3) effective reciprocal indices.
max_order (int) – Largest satellite order in the reflection set.
safety (int) – Multiplier on the estimated bandwidth.
lo (int) – Floor on the returned value.
hi (int) – Ceiling, to keep
n**daffordable.
- Returns:
Points per internal dimension, rounded up to even.
- Return type:
int
- pyextal.superspace.structurefactor.structure_factor(lat, atoms, H, kind='electron', n_internal=None, max_points=4000000, s_floor=1e-05)¶
Structure factors of a modulated structure.
- Parameters:
lat (SuperspaceLattice) – Supplies the metric and the q-vectors.
atoms (list[ModulatedAtom]) – The structure, listed in P1 – every atom of the basic cell, not just the asymmetric unit.
H (array-like) – (n, 3+d) integer superspace indices.
kind (str) –
'electron'for Mott-Bethe scattering factors, matching the Bloch-wave engine, or'xray'for the Cromer-Mann values.n_internal (int, optional) – Points per internal dimension. Sized by
auto_n_internal()when None.max_points (int) – Reflections are processed in chunks so that
chunk * n_internal**dstays under this, bounding memory.s_floor (float) – Lower clamp on
s = |g|/2, as the engine uses.
- Returns:
(n,) complex structure factors, in the units of the chosen scattering factor.
- Return type:
np.ndarray
- Raises:
ValueError – If kind is not recognised, or H has the wrong width.
- pyextal.superspace.structurefactor.bessel_reference(lat, H, amplitude, element='TA', position=(0.0, 0.0, 0.0), kind='electron', s_floor=1e-05)¶
Closed-form structure factor for one atom with a single harmonic.
For
u(xbar) = A sin(2 pi xbar)in (3+1)D, Jacobi-Anger givesInt_0^1 exp{2 pi i [m xbar + S.A sin(2 pi xbar)]} dxbar = J_-m(2 pi S.A)
exactly. This is the analytic check on the quadrature in
structure_factor(); seetest_superspace.py.- Parameters:
lat (SuperspaceLattice) – Must be (3+1)-dimensional.
H (array-like) – (n, 4) superspace indices.
amplitude (array-like) – (3,) sine amplitude in fractional coordinates.
element (str) – Element symbol for the scattering factor.
position (array-like) – (3,) fractional position of the single atom.
kind (str) –
'electron'or'xray'.s_floor (float) – Lower clamp on
s.
- Returns:
(n,) complex structure factors.
- Return type:
np.ndarray
- Raises:
ValueError – If lat is not (3+1)-dimensional.