Lesson 6.4 · 16 min

Van Hove functions

The Van Hove function G(r, t) extends g(r) to time: how likely is it to find an atom at distance r at time t from where an atom was at time 0? Its self part shows how individual atoms move (smoothly, or by hopping), its distinct part shows how neighbour shells break up, and its Fourier transform is what neutron scattering measures.

The idea

The radial distribution function g(r) (Lesson 6.1) is a snapshot. Léon Van Hove (1954) added time: G(r, t) is the density of atoms at distance r and time t from the place where an atom was at time 0. It splits into two parts.

Self part Gs(r, t): the same atom. 4πr²Gs(r, t) dr is the probability that an atom has moved a distance between r and r + dr in time t. Its second moment is the MSD (Lesson 6.2), but its shape carries more information:

Distinct part Gd(r, t): other atoms. At t = 0, Gd(r, 0)/ρ = g(r). As time goes on, the first-shell peak decays (the shell breaks up) and the hole near r = 0 fills as neighbours move into the space the atom has left (Part 2). Its decay time is a measure of how long a solvation or coordination shell survives. For ion pairs (Li⁺–anion), Gd tells you how long a pair stays together.

Scattering. The Fourier transform of Gs is the self-intermediate scattering function Fs(k, t), measured by incoherent quasi-elastic neutron scattering (QENS). Its decay at the first peak of S(k) defines the structural relaxation time τα (Part 4). The full G(r, t) transforms into the coherent F(k, t).

Key idea. Gs(r, t): how far single atoms have moved (Gaussian = smooth diffusion; extra peaks = hopping; α₂ = heterogeneity). Gd(r, t): how the neighbour shells relax. Their Fourier transforms connect MD to neutron scattering.

The algorithm

save UNWRAPPED positions every n steps
self part, lag k:
    for each origin t0 and atom i:  r = |u_i(t0 + k) - u_i(t0)|;  histogram r
    4πr² G_s(r) = hist / (n_samples · dr)               # normalized: integrates to 1
    MSD = ;  α2 = 3 / (5 ²) - 1
distinct part, lag k (fewer origins: costs N² per origin):
    for each origin t0, each i, each j ≠ i:
        d = minimum image of (x_j(t0 + k) - x_i(t0));  histogram |d|
    G_d(r)/ρ = hist / (n_origins · N · ρ · 4/3 π ((r+dr)³ - r³))
F_s(k, t) = < sin(k r) / (k r) >  over the same displacements (isotropic average)
  1. For mixtures, compute G_s per species and G_d per pair (Li–Li, Li–O, Li–anion). For distinct pairs A–B divide by N_A ρ_B.
  2. G_d needs positions consistently wrapped at t0 + t: use the wrapped position at t0 plus the unwrapped displacement, then the minimum image.
  3. Plot 4πr²G_s on a log scale of r (or log G_s vs r) to see small hopping populations.
  4. Tools: MDAnalysis (van_hove-style analyses), TRAVIS, LiquidLib, and your own NumPy code (as here); MDANSE computes F(k, t) for neutron comparisons.