The Problem with Simulating Fluids
Fluid behaviour is governed by the Navier-Stokes equations — a set of partial differential equations relating velocity, pressure, density, and viscosity across a continuous medium. The problem is the word continuous. Real water contains roughly 3 × 1025 molecules per litre. Simulating each one is impossible.
Two broad strategies exist for handling this. Grid-based methods (Eulerian approaches) divide space into fixed cells and track how fluid flows between them. Particle-based methods (Lagrangian approaches) move with the fluid, tracking parcels of mass as they travel through space.
Smoothed Particle Hydrodynamics (SPH) is the most widely used particle method. It was originally invented in 1977 by Lucy and Gingold & Monaghan for astrophysics simulations, and later adapted for fluid dynamics. Its key advantage is the natural handling of free surfaces — boundaries between fluid and empty space — which are notoriously difficult for grid-based methods.
The SPH Kernel: Spreading Point Masses into Volumes
The core mathematical trick in SPH is the kernel function W(r, h), also called the smoothing kernel. Every particle has a smoothing length h — a radius of influence. The kernel determines how a property carried at a point is distributed over the surrounding volume.
A kernel must satisfy several properties:
- Normalisation: it integrates to 1 over all space.
- Compact support: it is zero outside the radius 2h, so distant particles contribute nothing (crucial for performance).
- Symmetry: W(r, h) depends only on distance |r|, not direction.
- Delta convergence: as h → 0, W approaches a Dirac delta function.
The cubic spline kernel, introduced by Monaghan, is the most common choice. It is smooth, computationally cheap, and well-behaved numerically. The Poly6 and Spiky kernels, introduced by Müller et al. in their landmark 2003 paper on interactive SPH, are used specifically for density and pressure calculations respectively — a key insight that dramatically improves simulation stability.
Estimating Quantities from Particles
Once you have a kernel, you can estimate any scalar or vector quantity A at a point r by summing contributions from all nearby particles j:
A(r) = Σⱼ mⱼ (Aⱼ / ρⱼ) W(r − rⱼ, h)
Where mⱼ is the mass of particle j, Aⱼ is the value of A carried by that particle, ρⱼ is its density, and W is the kernel. The density itself is estimated the same way:
ρ(r) = Σⱼ mⱼ W(r − rⱼ, h)
Derivatives are computed analytically by differentiating the kernel — no finite differences needed. The gradient of A at particle i is:
∇A(rᵢ) = Σⱼ mⱼ (Aⱼ / ρⱼ) ∇W(rᵢ − rⱼ, h)
This is the mathematical machinery that translates the continuous Navier-Stokes equations into a discrete particle system.
Pressure Force
Fluid resists compression. When particles get too close together, density rises above a rest value ρ₀, and a restoring pressure force pushes them apart. This is computed via the equation of state — the simplest being the ideal gas law:
p = k(ρ − ρ₀)
Where k is a stiffness constant. Higher k makes the fluid more incompressible but can cause numerical instability (particles bouncing violently). Real incompressible SPH uses more sophisticated pressure solvers (PCISPH or DFSPH) that iteratively enforce zero divergence, at higher computational cost.
The pressure force on particle i from its neighbours j is:
fᵢ_pressure = −mᵢ Σⱼ mⱼ ((pᵢ + pⱼ) / (2ρⱼ)) ∇W(rᵢ − rⱼ, h)
The symmetrised pressure term (pᵢ + pⱼ)/2 is important — it ensures Newton's third law holds and the total momentum of the system is conserved.
Viscosity Force
Real fluids resist shearing — this is viscosity. Without it, fluid particles that pass near each other transfer no energy, and the simulation looks like bubbles rather than water. The SPH viscosity term adds a damping force proportional to the velocity difference between neighbouring particles:
fᵢ_viscosity = μ Σⱼ mⱼ ((vⱼ − vᵢ) / ρⱼ) ∇²W(rᵢ − rⱼ, h)
Where μ is the dynamic viscosity coefficient and ∇²W is the Laplacian of the kernel. Müller et al. proposed a special kernel for this term whose Laplacian is always positive — avoiding the sign-change instabilities that plagued earlier implementations.
Surface Tension
Water forms droplets because interior molecules are attracted equally in all directions, while surface molecules feel a net inward pull. In SPH this is modelled with a colour field — a scalar that is 1 inside the fluid and 0 outside. The gradient of this field points toward the fluid surface; its curvature determines the surface tension force.
Surface tension is what makes SPH fluid simulations beautiful: the water beads up, droplets merge, and thin sheets naturally break. Without it, fluid particles disperse into a featureless cloud.
Why SPH Is Good for Free-Surface Flows
Grid-based methods track which grid cells contain fluid and which are empty. As the surface moves, cells must be classified, filled, and emptied — a bookkeeping challenge that requires special methods like the Volume of Fluid (VOF) or Level Set approaches.
SPH has no grid. The particles are the fluid. Wherever particles go, the fluid surface naturally follows. Splashing, merging, breakup, droplet formation — all emerge automatically from the particle dynamics without any explicit surface tracking.
This makes SPH the method of choice for:
- Dam break simulations — a classic benchmark where a column of water collapses and floods a basin.
- Ocean spray and breaking waves — where grid methods struggle with small-scale droplet dynamics.
- Fluid-structure interaction — particles naturally interact with rigid bodies and deformable solids.
- Industrial manufacturing — injection moulding, casting, coating flows.
See SPH in action in the browser — the interactive simulation at /fluid/ runs thousands of particles in real time. Try pouring fluid from different angles, or adding obstacles to see the flow split and reform.
The Performance Challenge
The naive SPH algorithm checks every particle against every other particle to find neighbours within radius 2h. That is O(n²) work — doubling the particle count quadruples the computation.
In practice, all real-time SPH implementations use a spatial hash: divide space into cells of size 2h and assign each particle to a cell. Neighbour queries only need to check the 27 surrounding cells (in 3D). This reduces complexity to O(n) on average for uniformly distributed particles.
Even so, thousands of particles per frame is close to the CPU limit for real-time simulation. Modern high-fidelity SPH uses GPU compute shaders to run the neighbour search and force calculation in parallel across thousands of GPU threads simultaneously, enabling millions of particles at interactive rates.