Visual Computing/Particle Simulation
5 / 67

01/2022Visual Computing

Particle Simulation

A fluid and particle simulator in C++: smoothed-particle hydrodynamics for the Navier-Stokes equations, with a spatial hash for neighbor search and collisions.

╌╌╌╌

A C++ simulator for fluids and particle systems. Fluids follow the Navier-Stokes equations, discretized with smoothed-particle hydrodynamics (SPH); a uniform spatial hash keeps neighbor search and collision detection near-linear as particle counts grow.

SPH represents a fluid as particles that each carry mass and sample the field around them. Any field quantity at a point is a kernel-weighted sum over nearby particles,

where is a smoothing kernel of support radius and the density at particle . Density is the same sum applied to mass, ; pressure and viscosity forces come from the gradient and Laplacian of .

Each particle obeys the momentum form of Navier-Stokes,

a balance of pressure, viscosity, and gravity. Pressure follows an equation of state from density, , which resists compression and keeps the fluid roughly incompressible.

Every kernel sum ranges only over particles within , but finding them naively is , and that search dominates the cost. Positional indexing hashes each particle into a grid of cell size ; then only the particle's own cell and the cells bordering it can hold interactions, so each query touches a constant number of cells:

A query particle (center) interacts only with particles inside its support radius , and those lie in its own grid cell or the eight bordering it, so a neighbor search touches nine cells, not the whole domain.
Algorithm:Neighbors(i)\textsc{Neighbors}(i) — spatial-hash query for particles within hh of ii
  1. 1
    input: particle ii, cell size hh, table GG mapping cell \to particles
  2. 2
    cri/hc \gets \lfloor \mathbf r_i / h \rfloor;  \ result \gets \varnothing
  3. 3
    for each cell cc' bordering cc, and cc itself, do
  4. 4
    for each particle jG[c]j \in G[c'] do
  5. 5
    if rirj<h\lVert \mathbf r_i - \mathbf r_j \rVert < h then add jj to result
  6. 6
    return result
The spatial-hash neighbor query, live over a real collision sim: particles bounce off each other through contacts found by the same hash — overlapping pairs separate and exchange an impulse along the contact normal. The query particle's 3-by-3 cell block is shaded and its kernel radius drawn; green particles are true neighbors inside the radius, yellow ones were scanned and rejected. The cell-size select shows the trade in how many candidates each query touches.
Spatial-hash neighbor query
querytrue neighborcandidatecolliding

The same grid detects particle collisions and propagates contact forces: particles that share or border a cell are the only ones close enough to touch, so contact resolution never compares far-apart pairs. A contact between two particles of radius is an overlap; resolution separates the pair and, if they are still approaching, reflects the normal component of their relative velocity with restitution :

Algorithm:ResolveContacts()\textsc{ResolveContacts}() — collisions through the same hash
  1. 1
    input: particles with radius rr, restitution ee, cell table GG
  2. 2
    rebuild GG: insert every particle into its cell
  3. 3
    for each particle ii do
  4. 4
    for each jNeighbors(i)j \in \textsc{Neighbors}(i) with j>ij > i do
  5. 5
    drirjd \gets \lVert \mathbf r_i - \mathbf r_j \rVert
  6. 6
    if d<2rd < 2r then
  7. 7
    n(rirj)/d\mathbf n \gets (\mathbf r_i - \mathbf r_j) / d
  8. 8
    move ii and jj apart by (2rd)/2(2r - d)/2 along ±n\pm\mathbf n
  9. 9
    vn(vivj)nv_n \gets (\mathbf v_i - \mathbf v_j) \cdot \mathbf n
  10. 10
    if vn<0v_n < 0 then
  11. 11
    apply impulse (1+e)vn/2-(1 + e)\,v_n / 2 along ±n\pm\mathbf n to ii and jj

References

  1. Project repository
  2. Reference notes: Spatial Data Structures
  3. Reference notes: Hash Tables

╌╌ END ╌╌