DiffractionVizzard · Interactive Physics Simulations
Source Code Documentation

2D Helmholtz Equation

Drag: pan · Scroll: zoom · Click on electron: remove
Ready
Helmholtz Controls

Beam

Scatterers

Electron Grid (Lattice)

Double-click the view to set grid origin. Drag handles to adjust lattice vectors.

Scatterers: 0

Visualization

Loading WASM module…

2D Helmholtz Scattering — Module Overview

What this module computes

This module visualises the elastic scattering of a monochromatic electromagnetic wave from a collection of point scatterers arranged in two dimensions. The simulation solves the scalar (time-harmonic) wave equation in 2D, commonly known as the Helmholtz equation:

(∇² + k²) ψ(r) = 0

where k = 2π/λ is the wavenumber and λ is the wavelength of the incident radiation. The total field is decomposed as ψ = ψinc + ψscat.

Incident field

The incident field is a plane wave (or, optionally, a Gaussian-envelope beam) propagating in the direction θ:

ψinc(r) = ei k·r    with   k = k (cosθ, sinθ)

When the Gaussian envelope is enabled the incident field is multiplied by exp(−|r|² / 2σ²), where r is the distance perpendicular to the propagation direction.

Scattering model — Born approximation

Each scatterer at position rj is treated as a point source that re-radiates in response to the incident field (first Born approximation). The scattered field is a superposition of outgoing cylindrical waves, each given by the 2D free-space Green’s function — the zeroth-order Hankel function of the first kind:

ψscat(r) = ∑j fj(q) · Gj · ¼ i H0(1)(k |rrj|) · ei k·rj

Here H0(1) is the fundamental solution of the 2D Helmholtz equation (outgoing cylindrical wave), fj(q) is the scattering form factor of scatterer j (see below), and Gj is a Gaussian beam weight that equals 1 for a plane wave.

Scatterer types

Electrons (f = 1)

The simplest scatterer model: a point with constant scattering amplitude f = 1 independent of scattering angle. This corresponds to Thomson scattering from a free electron.

Atoms (X-ray form factor)

When the “Atom” scatterer type is selected, each scatterer uses an atomic X-ray form factor f(q) that depends on the magnitude of the scattering vector q = koutkin. The form factor is parametrised with the Cromer–Mann four-Gaussian approximation:

f(|G|) = ∑i=14 ai exp(−bi (|G| / 4π)²) + c

The nine coefficients (a1–4, b1–4, c) for each neutral element (Z = 1–98) are taken from the International Tables for Crystallography, Vol. C, Table 6.1.1.4. At runtime a lookup table of 10 000 entries is computed for each selected element covering 0 ≤ q ≤ 4π/λmin, and linearly interpolated during rendering.

In the near-field region the scattering vector is computed per pixel–scatterer pair: q = |k·(&hat{r}) − kin|, where &hat{r} is the unit direction from the scatterer to the observation point. In the far-field region (see below) q depends only on the angular bin.

Near-field / far-field hybrid

Computing the exact Hankel function at every pixel is expensive. Beyond a user-adjustable far-field radius Rff (default 100 nm) the scattered field is approximated via Fraunhofer diffraction: the structure factor is pre-computed per angular bin,

F(θ) = ∑j fj(q(θ)) · Gj · ei (kinkout(θ)) · rj

and each far-field pixel simply looks up the nearest angular bin and modulates it by a single Hankel evaluation at the pixel’s distance from the origin. This reduces the cost of far-field pixels from O(N) per pixel to O(1).

Bragg condition indicators

When a 2D lattice of scatterers is placed, the module computes the reciprocal lattice vectors b1, b2 from the real-space lattice vectors a1, a2. For each reciprocal lattice point G = hb1 + lb2 (|h|, |l| ≤ 4), the Bragg condition

kout = kin + G,    |kout| = |kin| = k

is checked. When a solution exists within 2° of the current beam direction, the diffracted beam direction is drawn as a red line from the lattice origin. Bragg-satisfying wavelengths and beam directions are indicated as tick marks on the corresponding sliders.

Rendering

The displayed quantity is the logarithmic intensity of the total (or scattered-only) field: log(ε + |ψ|²), mapped to the viridis colourmap. The parameter ε (adjustable) prevents log-of-zero and controls the dynamic range.

Implementation

All field computation is performed in C compiled to WebAssembly via Emscripten. The Hankel function H0(1)(x) = J0(x) + iY0(x) is evaluated using a pre-built lookup table (40 000 entries) with linear interpolation, plus an asymptotic large-argument expansion for x > xmax. A coarse render (1/8 resolution) is computed on every parameter change for interactive feedback, followed by a full-resolution refinement after a short delay.

Key assumptions and limitations