Diffraction¶
Textbook guide to the static structure factor \(S(k)\) — \(g(r)\) seen in reciprocal space, the quantity scattering experiments measure.
Conventions
- Wavenumber \(k\) in Å⁻¹; \(S(k)\) dimensionless.
- Avoid \(k=0\); smallest meaningful \(k \approx 2\pi/L\).
1. Debye equation and \(g(r)\leftrightarrow S(k)\)¶
MolPy evaluates the Debye scattering equation directly from coordinates:
\[
S(k) = \frac{1}{N}\Big\langle\sum_i\sum_j
\frac{\sin(k\,r_{ij})}{k\,r_{ij}\Big\rangle.
\]
For an isotropic fluid,
\[
S(k) = 1 + 4\pi\rho\int_0^\infty r^2\,[g(r)-1]\,
\frac{\sin(kr)}{kr}\,\mathrm{d}r,
\]
so \(S(k)\) and \(g(r)\) carry the same pair information. Use \(S(k)\) to compare with X-ray/neutron diffraction, locate the first sharp diffraction peak, or read long-wavelength compressibility from \(S(k\to 0)\).
Cost is \(\mathcal{O}(N^2)\) per \(k\) per frame — fine for moderate \(N\); for huge boxes prefer a grid FFT route (not covered here).
2. Computing \(S(k)\)¶
import numpy as np
import molpy as mp
rng = np.random.default_rng(0)
xyz = rng.uniform(0.0, 20.0, size=(200, 3))
frame = mp.Frame()
frame["atoms"] = {"x": xyz[:, 0], "y": xyz[:, 1], "z": xyz[:, 2]}
frame.box = mp.Box.cubic(20.0)
import numpy as np
from molpy.compute import StaticStructureFactorDebye
k = np.linspace(0.2, 12.0, 300) # Å^-1
sk = StaticStructureFactorDebye(k)([frame])
3. Pitfalls¶
- Including \(k=0\) → division by zero.
- Over-dense \(k\)-grid on large \(N\) → wasteful \(\mathcal{O}(N^2)\) sums.
- Interpreting \(k < 2\pi/L\) as bulk thermodynamics.