Note
Go to the end to download the full example code.
Landau damping from first principles with particle-in-cell#
In 1946, Lev Landau solved the linearized Vlasov equation for a wave on a Maxwellian plasma and found something that seemed to violate reversible mechanics: the wave damps, exponentially, with no collisions or dissipation anywhere in the equations. Particles moving at very nearly the wave’s phase velocity “surf” it, and because a thermal distribution always has slightly more slightly slower particles being accelerated than slightly faster particles being decelerated, the net exchange drains the wave.
The system is a collisionless electron gas of distribution function \(f(x,v,t)\) against a fixed, uniform, charge-neutralizing ion background, coupled to its own self-consistent electric field \(E\) through Poisson’s equation:
A single density perturbation of wavenumber \(k\) is seeded on a Maxwellian background of thermal speed \(v_{th}\) in a periodic box of length \(L=2\pi/k\); linearizing this system predicts the wave’s field energy decays at the rate
valid for weak damping, \(k\lambda_D \lesssim 0.5\).
landau_damping_rate() evaluates the
analytic weak-damping formula above, and
pic_simulate() reproduces the decay
from first principles with a particle-in-cell solution of the same
Vlasov equation Landau linearized – no damping term appears anywhere
in pic_step(); the decay is a pure
consequence of the particle orbits.
import matplotlib.pyplot as plt
import numpy as np
import physicskit as pk
Classic benchmark: k * lambda_D = 0.5, one wavelength in the box#
Evolve the Vlasov-Poisson system with particles alone – no collision operator or damping term appears anywhere in pic_step.
Compare the simulated field-energy decay against Landau’s analytic rate (field energy ~ E^2, so it decays as exp(2*gamma*t)).
gamma = pk.plasma.landau_damping_rate(k=k_mode, v_th=v_th)
t, fe = result["t"], result["field_energy"]
fig, ax = pk.plasma.plot_field_energy_history(t, fe)
t0 = 50
ax.semilogy(t, fe[t0] * np.exp(2 * gamma * (t - t[t0])), "--", label=f"analytic $2\\gamma={2 * gamma:.3f}$")
ax.set_title("Landau damping: PIC simulation vs. analytic rate")
ax.legend()
fig.tight_layout()
plt.show()

Where the energy actually goes: phase-space flattening#
The exponentially decaying field energy above is only the field’s share of the story; the same mechanism that damps the wave is visible directly in the particle distribution. Comparing the initial and final phase-space density shows the resonant particles near the wave’s phase velocity being scattered into a flattened plateau, exactly the quasilinear signature of the particles absorbing the field energy the wave loses.
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
pk.plasma.plot_phase_space(x0, v0, ax=axes[0])
axes[0].set_title("t=0: seeded density ripple")
pk.plasma.plot_phase_space(result["x"], result["v"], ax=axes[1])
axes[1].set_title(f"t={t[-1]:.0f}: resonant plateau, wave damped")
fig.suptitle("Landau damping: phase-space flattening, not just field decay")
fig.tight_layout()
plt.show()

Total running time of the script: (0 minutes 0.152 seconds)