Madelung constants via Ewald summation¶
The classical Madelung sum for an ionic crystal converges only conditionally in 3D — different truncation shapes give different answers. vibe-qc’s 3D Ewald implementation computes the infinite sum unconditionally.
NaCl rocksalt¶
import numpy as np
from vibeqc import EwaldOptions, ewald_point_charge_energy
# NaCl primitive cell: 2 ions (Na⁺, Cl⁻) on a face-centered-cubic
# lattice with conventional constant a = 5.64 Å.
A_TO_BOHR = 1.0 / 0.529177210903
a = 5.64 * A_TO_BOHR
# Primitive FCC lattice vectors (columns)
lattice = 0.5 * a * np.array([[0, 1, 1],
[1, 0, 1],
[1, 1, 0]], dtype=float).T
# One ion of each sign in the primitive cell
positions = np.column_stack([[0, 0, 0], # Na⁺ at origin
[0.5 * a, 0, 0]]) # Cl⁻ at (a/2, 0, 0)
charges = np.array([+1.0, -1.0])
opts = EwaldOptions()
opts.real_cutoff_bohr = 30.0 # α and k-space cutoff auto-derived
energy = ewald_point_charge_energy(lattice, positions, charges, opts)
# Extract the Madelung constant: E = −M / r_nn, where r_nn = a/2 is the
# nearest Na-Cl distance.
r_nn = 0.5 * a
M = -energy * r_nn
print(f"NaCl Madelung constant: {M:.10f}")
print(f"Literature value: 1.7475645946")
Output:
NaCl Madelung constant: 1.7475645946
Literature value: 1.7475645946
Matches to every printed digit.
Why α doesn’t matter¶
Ewald’s power lies in splitting 1/r into a short-range plus a long-range piece so that both converge fast. The width of the split — the Ewald parameter α — can be tuned to balance work between the two sums, but the total energy must be independent of α. Let’s verify:
for alpha in (0.2, 0.3, 0.5, 1.0):
opts = EwaldOptions()
opts.alpha = alpha
opts.real_cutoff_bohr = 40.0
opts.recip_cutoff_bohr_inv = 12.0
E = ewald_point_charge_energy(lattice, positions, charges, opts)
print(f"α = {alpha:.2f}: E = {E:.12f}")
All four lines agree to 1e-9 — the hallmark of a correct Ewald implementation.
NaCl Madelung constant computed at ten α values across more than a decade.
Blue: with a converged real-space cutoff (\(r_{\rm cut}=40\) bohr), every
α reproduces the literature constant to better than \(10^{-6}\) — a
quantitative α-invariance test that any correct Ewald implementation
must pass. Red: dropping the real-space cutoff to 8 bohr breaks the
short-range / long-range balance and the curve fans out by ~1 unit in
\(M\) — exactly the sort of conditional-convergence failure Ewald is
designed to eliminate. Regenerated by
examples/plots/nacl-ewald-alpha-invariance.py.¶
Dispatching through the SCF driver¶
For an actual periodic HF/DFT calculation, you don’t need to call
ewald_point_charge_energy yourself. Set the Coulomb method on the
LatticeSumOptions and the driver handles the rest:
from vibeqc import (
Atom, PeriodicSystem,
LatticeSumOptions, CoulombMethod,
PeriodicSCFOptions,
run_rhf_periodic_scf, run_rhf_periodic_gamma_scf,
)
opts = PeriodicSCFOptions()
opts.lattice_opts.coulomb_method = CoulombMethod.EWALD_3D
opts.lattice_opts.nuclear_cutoff_bohr = 30.0
# Pass opts to the dispatcher; it routes to the Ewald backend
# automatically. Multi-k: run_rhf_periodic_scf(sysp, basis, kmesh, opts)
# Γ-only: run_rhf_periodic_gamma_scf(sysp, basis, opts)
The full EWALD_3D path — nuclear repulsion + nuclear attraction
\(V(g)\) + electron-repulsion Coulomb \(J(\mu\nu)\) — is now wired
end-to-end into the RHF dispatcher (validated to ω-invariance to
\(10^{-8}\) Ha across H₂ / LiH / MgO / Ne). See
user_guide/ewald.md for the dispatcher API,
the ω-invariance correctness check, and the orthorhombic-cell
constraint on the FFT-based long-range solver.
Theory¶
Why the direct sum is wrong¶
The electrostatic energy per cell of a 3D crystal of point charges is
where \(\mathbf{T}\) runs over direct-lattice translations and the prime excludes the trivial \(A = B, \mathbf{T} = 0\) term. The summand decays as \(1/R\) but the shell volume grows as \(R^2 \, \mathrm{d}R\) — so the series is only conditionally convergent: the limit depends on the shape in which you truncate. Spherical, cubic, and rhombohedral truncations give different finite “answers.” For neutral cells the true infinite sum is well-defined, but finite-cutoff artefacts linger as \(1/R\).
The Ewald trick¶
Ewald (1921) decomposed the \(1/r\) kernel into two absolutely convergent pieces by adding and subtracting a Gaussian-charge distribution of width \(1/\alpha\) at each site:
The short-range part decays as a Gaussian — sum it in real space; convergence is exponential. The long-range part is smooth and extends to infinity but is periodic, so its Fourier transform is a discrete sum over reciprocal-lattice vectors \(\mathbf{G}\) that also converges exponentially because the Gaussian kills high-\(G\) contributions. Together the Ewald-summed energy is
where \(V\) is the unit-cell volume and \(S(\mathbf{G}) = \sum_A q_A e^{i \mathbf{G} \cdot \mathbf{r}_A}\) is the structure factor. A fourth term — a uniform background charge to neutralise a non-zero cell charge — appears for non-neutral cells (the “jellium” convention). Both series converge geometrically.
α-invariance: the rigorous correctness test¶
The decomposition parameter \(\alpha\) controls how work is partitioned between real and reciprocal space — large \(\alpha\) makes the real sum cheap and the reciprocal sum expensive; small \(\alpha\) the reverse. The total energy is independent of \(\alpha\). If your implementation returns different energies for different \(\alpha\)’s, something is wrong.
vibe-qc’s test suite exploits this: the same NaCl Madelung energy is computed with four different \(\alpha\) values, each with real and reciprocal cutoffs auto-selected to give a converged series, and all four must agree to \(10^{-9}\) Ha. The four-line script at the top of this tutorial replicates the check.
The Madelung constant¶
For an ionic crystal with two charges \(\pm q\) at a shortest interionic distance \(r_\text{nn}\), the Ewald energy per ion pair takes the form
defining the Madelung constant \(M\) — a pure geometric lattice sum, independent of \(r_\text{nn}\) or \(q\).
Crystal |
\(M\) |
\(r_\text{nn}\) |
|---|---|---|
NaCl (rocksalt) |
1.7475645946… |
\(a/2\) |
CsCl |
1.76267477… |
\(\sqrt{3}\, a/2\) |
ZnS (zincblende) |
1.6380… |
\(\sqrt{3}\, a/4\) |
Fluorite (CaF₂) |
2.51939… |
\(\sqrt{3}\, a/4\) |
These are textbook values with a long history of high-precision calculation (Sherman 1932, Nijboer-De Wette 1957). The vibe-qc Ewald summer reproduces all of them to \(\leq 10^{-8}\) relative precision at a 40-bohr real-space cutoff.
Resources¶
<50 MB peak RAM, <0.05 s on one core (Apple M2 baseline) for the
NaCl Madelung-constant point-charge calculation. The Ewald cost
scales as \(\mathcal{O}(N_\text{atom}^2 \cdot N_\text{cells}^2)\) in
the real-space part and as \(\mathcal{O}(N_G \cdot N_\text{atom})\) in
the reciprocal-space part — both are negligible at point-charge
scale. Real periodic SCFs that route through EWALD_3D add the
SCF cost on top (see tutorial 4).
References¶
Original Ewald summation. P. P. Ewald, “Die Berechnung optischer und elektrostatischer Gitterpotentiale,” Ann. Phys. 369, 253 (1921).
Modern practical implementation. M. P. Allen and D. J. Tildesley, Computer Simulation of Liquids, 2nd ed., Oxford University Press (2017), chapter 6. Clearest walk-through of real-space / reciprocal-space cutoffs and the \(\alpha\) trade-off.
Madelung constants, original tables. J. Sherman, “Crystal energies of ionic compounds and thermochemical applications,” Chem. Rev. 11, 93 (1932).
Madelung constants, high-precision computation. B. R. A. Nijboer and F. W. De Wette, “On the calculation of lattice sums,” Physica 23, 309 (1957).
Textbook, solid-state. N. W. Ashcroft and N. D. Mermin, Solid State Physics, Cengage Learning reprint (1976), chapters 19–20 for electrostatics of ionic crystals.