Skip to content
cfd-lab:~/en/posts/2026-05-25-lbm-equilibri…online
NOTE #054DAY MON CFD기법DATE 2026.05.25READ 5 min readWORDS 942#CFD#LBM#Lattice-Boltzmann#Kinetic-Theory#Hermite-Polynomial

Nine Arrows of Maxwell–Boltzmann — Why LBM's Equilibrium Is a Polynomial

A second-order Hermite truncation builds D2Q9, and the same truncation chains LBM to low-Mach flows

In 1986, Frisch, Hasslacher, and Pomeau dropped particles on a lattice and made them mimic Navier–Stokes. That was LGCA, the lattice gas cellular automaton. It died within five years — the integer occupancy of zero or one per direction generated noise that no amount of averaging could erase. In 1992, McNamara and Zanetti swapped integers for real numbers. They populated the lattice with particle distribution functions fif_i instead of bits. The noise vanished — but a new question rode in. How can nine real numbers stand in for the infinite-dimensional Maxwell–Boltzmann distribution? This post follows the answer: a second-order Hermite truncation gives LBM its polynomial equilibrium, and that same truncation locks it into low-Mach flow.

From integers to reals — LGCA died in 1986 and LBM was born#

LGCA was elegant. Square lattice, six particle directions, one collision rule. Average it macroscopically and Navier–Stokes returns. But boolean particles (zero or one) amplified statistical noise. You could kill the noise with long time averages, but then the transient you came for was gone too.

McNamara and Zanetti placed real-valued distributions fi(x,t)f_i(\mathbf{x}, t) on every node. fif_i is the expected count of particles at position x\mathbf{x} and time tt moving along lattice direction ci\mathbf{c}_i. The noise problem vanished by construction. One step splits into two halves — collision and streaming.

fi(x+ciΔt,t+Δt)=fi(x,t)fi(x,t)fieq(ρ,u)τf_i(\mathbf{x} + \mathbf{c}_i \Delta t, t + \Delta t) = f_i(\mathbf{x}, t) - \frac{f_i(\mathbf{x}, t) - f_i^{eq}(\rho, \mathbf{u})}{\tau}

τ\tau is the relaxation time and fieqf_i^{eq} is the equilibrium distribution. Collision shaves the non-equilibrium part on a τ\tau timescale, streaming shifts the shaved distribution one cell over. The deep question hides in fieqf_i^{eq} — what makes nine real numbers enough?

Maxwell–Boltzmann carries a time bomb#

In continuum kinetic theory, the equilibrium distribution is Maxwell–Boltzmann.

fMB(c)=ρ(2πRT)D/2exp ⁣((cu)22RT)f^{MB}(\mathbf{c}) = \rho \, (2\pi R T)^{-D/2} \exp\!\left( -\frac{(\mathbf{c} - \mathbf{u})^2}{2 R T} \right)

c\mathbf{c} is the microscopic particle velocity, u\mathbf{u} is the macroscopic flow speed, DD is the spatial dimension, TT the temperature, RR the gas constant. The bomb is that c\mathbf{c} is continuous. Reducing it to nine or nineteen discrete directions requires you to skim the distribution intelligently.

Naive attempt — replace the Gaussian integral with a midpoint rule on a fixed grid. It fails. The moments that Navier–Stokes needs — ρ\rho, ρu\rho \mathbf{u}, the momentum tensor ρuu\rho \mathbf{u}\mathbf{u}, energy — disagree with the lattice sum. Once conservation breaks, LBM is dead in the water.

The right answer is series expansion. Expand Maxwell–Boltzmann in orthogonal polynomials, keep the orders that carry the needed moments, drop the rest. Those polynomials are Hermite's.

Hermite polynomials chop the distribution into pieces#

The probabilist Hermite polynomials Hen(c)He_n(c) are orthogonal under the standard Gaussian weight w(c)=(2π)1/2ec2/2w(c) = (2\pi)^{-1/2} e^{-c^2/2}.

Hen(c)Hem(c)w(c)dc=n!δnm\int He_n(c)\, He_m(c)\, w(c)\, dc = n!\, \delta_{nm}

The first few are He0=1He_0 = 1, He1=cHe_1 = c, He2=c21He_2 = c^2 - 1, He3=c33cHe_3 = c^3 - 3c. Set 1D Maxwell–Boltzmann to be isothermal (rescale to RT=1RT = 1). The exponential generating function gives this identity straight away.

fMB(c)=w(c)ρexp ⁣(ucu22)=w(c)ρn=0unn!Hen(c)f^{MB}(c) = w(c)\, \rho \exp\!\left( u c - \frac{u^2}{2} \right) = w(c)\, \rho \sum_{n=0}^{\infty} \frac{u^n}{n!} He_n(c)

Each term grabs a slice of the universe. n=0n=0 is the static Gaussian. n=1n=1 is a small drift. n=2n=2 is the mean-kinetic-energy correction. Higher nn are increasingly asymmetric tail effects. LBM's whole game is to cut this sum at a finite order.

Maxwell–Boltzmann과 그 Hermite 절단의 비교. 표의 세 모멘트(밀도·운동량·에너지)가 같아지는 차수가 바로 LBM이 멈추는 자리다.
N=2면 ρ·ρu·에너지 세 모멘트가 정확히 일치한다. u가 |u|/c_s ≈ 1을 넘어가면 절단오차가 폭주하며 격자가 깨진다 — LBM이 저속(낮은 마하수)에 묶이는 이유.

Play with the simulation above. Push the drift uu to 0.4 and pick truncation order N=2N=2 — the first three moments (density, momentum, energy) match Maxwell–Boltzmann exactly. Crank uu past 1.0 and the dashed curve peels off. That is exactly where LBM's Mach-number constraint u/cs0.3|\mathbf{u}|/c_s \lesssim 0.3 comes from, drawn in one panel.

What second-order truncation buys you#

Which moments do you need for first-order viscous Navier–Stokes? Three orders, no more — ρ\rho, ρu\rho \mathbf{u}, and the momentum flux Παβ=ρuαuβ+pδαβ\Pi_{\alpha\beta} = \rho u_\alpha u_\beta + p \delta_{\alpha\beta}. Because ρuu\rho \mathbf{u}\mathbf{u} is second-order in uu, the distribution function must carry a u2u^2 term.

So cut the Hermite series at N=2N=2.

feq(c)=w(c)ρ[1+uc+u22(c21)]f^{eq}(c) = w(c)\, \rho \left[ 1 + uc + \frac{u^2}{2}(c^2 - 1) \right]

This is the continuous form of the LBM equilibrium. N=3N=3 and beyond help with higher inviscid moments (heat flux) but are surplus to standard isothermal LBM. The dropped terms are responsible for LBM's two well-known limits — the isothermal assumption and the 0.3-Mach ceiling.

How D2Q9 was built#

Replacing the continuous integral feq(c)ϕ(c)dc\int f^{eq}(c) \phi(c)\, dc with a lattice sum iwifieqϕ(ci)\sum_i w_i f_i^{eq} \phi(\mathbf{c}_i) demands quadrature. The key fact — quadrature accurate to order NN requires only that it integrate polynomials of that order exactly.

In 2D, accuracy through the u2u^2 term means quadrature exact for polynomials up to fifth order under the Gaussian weight (the momentum tensor produces a c2×u2c^2 \times u^2 term). Three-point Gauss–Hermite does precisely that job.

In 1D, three nodes c{3,0,+3}c \in \{-\sqrt{3}, 0, +\sqrt{3}\} with weights {1/6,2/3,1/6}\{1/6, 2/3, 1/6\}. The tensor product in 2D gives 3×3=93 \times 3 = 9 nodes — that is D2Q9. Rescale to lattice units and you get cs=1/3c_s = 1/\sqrt{3} with lattice velocity vectors at integer coordinates (0,0),(±1,0),(0,±1),(±1,±1)(0,0), (\pm 1, 0), (0, \pm 1), (\pm 1, \pm 1). The lattice weights wiw_i absorb the Gaussian factor into the Gauss–Hermite weights.

Indexci\mathbf{c}_iwiw_i
0(0,0)(0, 0)4/94/9
1–4(±1,0),(0,±1)(\pm 1, 0), (0, \pm 1)1/91/9
5–8(±1,±1)(\pm 1, \pm 1)1/361/36

Plugging cs2=1/3c_s^2 = 1/3 into the continuous form gives the on-lattice equilibrium.

fieq=wiρ[1+3(ciu)+92(ciu)232uu]f_i^{eq} = w_i\, \rho \left[ 1 + 3 (\mathbf{c}_i \cdot \mathbf{u}) + \frac{9}{2}(\mathbf{c}_i \cdot \mathbf{u})^2 - \frac{3}{2}\, \mathbf{u} \cdot \mathbf{u} \right]

That one line is the heart of every isothermal LBM code. A simple polynomial — but the first three moments of Maxwell–Boltzmann are sealed inside it.

Python — one BGK collision step#

Run a single collision step on one lattice node.

import numpy as np
 
cx = np.array([0, 1, 0, -1, 0, 1, -1, -1, 1])
cy = np.array([0, 0, 1, 0, -1, 1, 1, -1, -1])
w  = np.array([4/9, 1/9, 1/9, 1/9, 1/9, 1/36, 1/36, 1/36, 1/36])
 
def equilibrium(rho, ux, uy):
    """D2Q9 equilibrium — nine polynomials"""
    ciu = cx * ux + cy * uy            # dot product
    usq = ux * ux + uy * uy
    return w * rho * (1 + 3 * ciu + 4.5 * ciu**2 - 1.5 * usq)
 
def bgk_collision(f, tau):
    rho = f.sum()
    ux  = (cx * f).sum() / rho
    uy  = (cy * f).sum() / rho
    feq = equilibrium(rho, ux, uy)
    return f - (f - feq) / tau, rho, ux, uy
 
# off-equilibrium initial state
f = w * 1.0
f[1] += 0.05; f[3] -= 0.04          # slight eastward bias
 
for step in range(20):
    f, rho, ux, uy = bgk_collision(f, tau=0.8)
    err = np.linalg.norm(f - equilibrium(rho, ux, uy))
    print(f"step {step:2d}: rho={rho:.4f}, u=({ux:+.4f},{uy:+.4f}), ||delta||={err:.2e}")

About twenty steps and the residual drops below 10610^{-6} — the nine fif_i settle onto the equilibrium polynomial. What survives each step? Density ρ\rho and momentum ρu\rho \mathbf{u}. Collision only chips away non-equilibrium moments.

D2Q9 격자 위에서 9개 분포 함수가 BGK 충돌을 통해 평형으로 끌려가는 과정. 노란 화살표는 거시 속도 u, 가는 화살표는 각 격자 방향 c_i의 분포 크기.
τ→0.5에 가까울수록 한 스텝에 평형으로 끌려가지만, 점성 ν = c_s²(τ−1/2)도 작아져 안정성이 흔들린다.

Pull the τ\tau slider down toward 0.55 and the residual vanishes in one or two steps. Viscosity is ν=cs2(τ1/2)\nu = c_s^2 (\tau - 1/2) — as τ1/2\tau \to 1/2, viscosity disappears and the lattice goes unstable. Push τ\tau up and viscosity grows but relaxation slows. That trade-off is the dial every LBM practitioner spends time on.

Three lines to remember#

  • LBM's equilibrium fieqf_i^{eq} is Maxwell–Boltzmann expanded in Hermite polynomials and chopped at second order — that cut preserves the three moments ρ\rho, ρu\rho \mathbf{u}, and the momentum flux exactly.
  • D2Q9 is derived as the 2D tensor product of three-point Gauss–Hermite quadrature, the smallest rule that integrates the second-order equilibrium exactly. Nine is not an arbitrary number; it is an artifact of orthogonal integration.
  • The truncation order sets every limit. Isothermal assumption, u/cs0.3|\mathbf{u}|/c_s \lesssim 0.3 ceiling — both follow automatically from the single line "we cut the series at N=2N=2".

Share if you found it helpful.