basic fluids
TRANSCRIPT
FFLUIDLUID S SIMULATIONIMULATION
Robert Bridson, UBC
Matthias Müller-Fischer, AGEIA Inc.
Course Details
www.cs.ubc.ca/~rbridson/fluidsimulation
Schedule:
1:45 - 3:30 Basics [Bridson]
3:30 - 3:45 Break
3:45 - 4:45 Real-Time [M-F]
4:45 - 5:30 Extras [Bridson]
The Basic Equations
Symbols
: velocity with components (u,v,w)
: fluid density
p: pressure
: acceleration due to gravity or animator
: dynamic viscosity
u
g
The Equations
Incompressible Navier-Stokes:
“Momentum Equation”
“Incompressibility condition”
vu
t vugv
u 1
p v
g
gvu
gvu 0
The Momentum Equation
The Momentum Equation
Just a specialized version of F=ma
Let’s build it up intuitively
Imagine modeling a fluid with a bunch of particles(e.g. blobs of water)
A blob has a mass m, a volume V, velocity u
We’ll write the acceleration as Du/Dt(“material derivative”)
What forces act on the blob?m
Dvu
Dt
vF
Forces on Fluids
Gravity: mg
or other “body forces” designed by animator
And a blob of fluid also exerts contact forces on its neighbouring blobs…
m
Dvu
Dtm
vg K
Pressure
The “normal” contact force is pressure (force/area)
How blobs push against each other, and how they stick together
If pressure is equal in every direction, net force is zero…Important quantity is pressure gradient:
We integrate over the blob’s volume(equivalent to integrating -pn over blob’s surface)
What is the pressure? Coming soon…
m
Dvu
Dtm
vg Vp K
Viscosity
Think of it as frictional part of contact force:a sticky (viscous) fluid blob resists other blobs moving past it
For now, simple model is that we want velocity to be blurred/diffused/…
Blurring in PDE form comes from the Laplacian:
m
Dvu
Dtm
vg Vp Vgv
u
The Continuum Limit (1)
Model the world as a continuum:
# particles Mass and volume 0
We want F=ma to be more than 0=0:
Divide by mass
Dvu
Dtvg
V
mp
V
mgv
u
The Continuum Limit (2)
The fluid density is =m/V:
This is almost the same as the stanford eq’n(in fact, the form we mostly use!)
The only weird thing is Du/Dt…
Dvu
Dt
1
p v
g
gvu
Lagrangian vs. Eulerian
Lagrangian viewpoint:
Treat the world like a particle system
Label each speck of matter, track where it goes (how fast, acceleration, etc.)
Eulerian viewpoint:
Fix your point in space
Measure stuff as it flows past
Think of measuring the temperature:
Lagrangian: in a balloon, floating with the wind
Eulerian: on the ground, wind blows past
The Material Derivative (1)
We have fluid moving in a velocity field u
It possesses some quality q
At an instant in time t and a position in space x, the fluid at x has q(x,t)
q(x,t) is an Eulerian field
How fast is that blob of fluid’s q changing?
A Lagrangian question
Answer: the material derivative Dq/Dt
The Material Derivative (2)
It all boils down to the chain rule:
We usually rearrange it:
D
Dtq(x, t)
qt
qx
gdx
dt
qt
qgvu
Dq
Dt
qt
vugq
Turning Dq/Dt Around
For a thought experiment, turn it around:
That is, how fast q is changing at a fixed point in space (∂q/∂t) comes from two things:
How fast q is changing for the blob of fluid at x
How fast fluid with different values of q is flowing past
qt
Dq
Dt vugq
Writing D/Dt Out
We can explicitly write it out from components:
Dq
Dt
qt
vugq
qt
uqx
vqy
wqz
D/Dt For Vector Fields
Say our fluid has a colour variable (RGB vector) C
We still write
The dot-product and gradient confusing?
Just do it component-by-component:
DvC
Dt
vC
t vug
vC
DvC
Dt
DR Dt
DG Dt
DB Dt
R t vugR
G t vugG
B t vugB
Du/Dt
This holds even if the vector field is velocity itself:
Nothing different about this, just that the fluid blobs are moving at the velocity they’re carrying.
Dvu
Dt
vu
t vugv
u
Du Dt
Dv Dt
Dw Dt
u t vugu
v t vugv
w t vugw
The Incompressibility Condition
Compressibility
Real fluids are compressible
Shock waves, acoustic waves, pistons…
Note: liquids change their volume as well as gases, otherwise there would be no sound underwater
But this is nearly irrelevant for animation
Shocks move too fast to normally be seen(easier/better to hack in their effects)
Acoustic waves usually have little effect on visible fluid motion
Pistons are boring
Incompressibility
Rather than having to simulate acoustic and shock waves, eliminate them from our model:assume fluid is incompressible
Turn stiff system into a constraint, just like rigid bodies!
If you fix your eyes on any volume of space, volume of fluid in = volume of fluid out:
ugn
0
Divergence
Let’s use the divergence theorem:
So for any region, the integral of is zero
Thus it’s zero everywhere:
ugn
g
vu
gvu
gvu 0
Pressure
Pressure p:whatever it takes to make the velocity field divergence free
If you know constrained dynamics,is a constraint, and pressure is the matching Lagrange multiplier
Our simulator will follow this approach:
solve for a pressure that makes our fluid incompressible at each time step.
gvu 0
Alternative
To avoid having to solve linear systems, can turn this into a soft-constraint
Track density, make pressure proportional to density variation
Called “artificial compressibility”
However, easier to accelerate a linear solver… if the linear system is well-posed
Inviscid Fluids
Dropping Viscosity
In most scenarios, viscosity term is much smaller
Convenient to drop it from the equations:
Zero viscosity = “inviscid”
Inviscid Navier-Stokes = “Euler equations”
Numerical simulation typically makes errors that resemble physical viscosity, so we have the visual effect of it anyway
Called “numerical dissipation”
For animation: often numerical dissipation is larger than the true physical viscosity!
Aside: A Few Figures
Dynamic viscosity of air:
Density of air:
Dynamic viscosity of water:
Density of water:
The ratio, / (“kinematic viscosity”) is what’s important for the motion of the fluid…… air is 10 times more viscous than water!
air 1.3 kg m3
water 1000 kg m3water 1.110 3 Ns m2
air 1.8 10 5 Ns m2
The inviscid equations
A.k.a. the incompressible Euler equations:
vu
t vugv
u 1
p v
g
gvu 0
Boundary Conditions
Boundary Conditions
We know what’s going on inside the fluid: what about at the surface?
Three types of surface
Solid wall: fluid is adjacent to a solid body
Free surface: fluid is adjacent to nothing(e.g. water is so much denser than air, might as well forget about the air)
Other fluid: possibly discontinuous jump in quantities (density, …)
Solid Wall Boundaries
No fluid can enter or come out of a solid wall:
For common case of usolid=0:
Sometimes called the “no-stick” condition, since we let fluid slip past tangentially
For viscous fluids, can additionally impose “no-slip” condition:
ugn v
usolid gn
ugn 0
u v
usolid
Free Surface
Neglecting the other fluid, we model it simply as pressure=constant
Since only pressure gradient is important, we can choose the constant to be zero:
If surface tension is important (not covered today), pressure is instead related to mean curvature of surface
p 0
Multiple Fluids
At fluid-fluid boundaries, the trick is to determine “jump conditions”
For a fluid quantity q, [q]=q1-q2
Density jump [] is known
Normal velocity jump must be zero:
For inviscid flow, tangential velocities may be unrelated (jump is unknown)
With no surface tension, pressure jump [p]=0
[vugn] 0
Numerical Simulation Overview
Splitting
We have lots of terms in the momentum equation: a pain to handle them all simultaneously
Instead we split up the equation into its terms, and integrate them one after the other
Makes for easier software design too:a separate solution module for each term
First order accurate in time
Can be made more accurate, not covered today.
A Splitting Example
Say we have a differential equation
And we can solve the component parts:
SolveF(q,∆t) solves dq/dt=f(q) for time ∆t
SolveG(q,∆t) solves dq/dt=g(q) for time ∆t
Put them together to solve the full thing:
q* = SolveF(qn, ∆t)
qn+1 = SolveG(q*, ∆t)
dq
dt f (q) g(q)
Does it Work?
Up to O(∆t): dq
dtqn1 qn
t
qn1 q
tq* qn
tg(q) f (q)
Splitting Momentum
We have three terms:
First term: advection
Move the fluid through its velocity field (Du/Dt=0)
Second term: gravity
Final term: pressure update
How we’ll make the fluid incompressible:
vu
t v
ugvu v
g 1
p
vu
t v
ugvu
vu
tvg
vu
t
1
p
gvu 0
Space
That’s our general strategy in time; what about space?
We’ll begin with a fixed Eulerian grid
Trivial to set up
Easy to approximate spatial derivatives
Particularly good for the effect of pressure
Disadvantage: advection doesn’t work so well
Later: particle methods that fix this
A Simple Grid
We could put all our fluid variables at the nodes of a regular grid
But this causes some major problems
In 1D: incompressibility means
Approximate at a grid point:
Note the velocity at the grid point isn’t involved!
ux
0
ui1 ui 1
2x0
A Simple Grid Disaster
The only solutions to are u=constant
But our numerical version has other solutions:
ux
0
u
x
Staggered Grids
Problem is solved if we don’t skip over grid points
To make it unbiased, we stagger the grid:put velocities halfway between grid points
In 1D, we estimate divergence at a grid point as:
Problem solved!
ux
(xi ) ui 1
2 ui 1
2
x
The MAC Grid
From the Marker-and-Cell (MAC) method [Harlow&Welch’65]
A particular staggering of variables in 2D/3D that works well for incompressible fluids:
Grid cell (i,j,k) has pressure pi,j,k at its center
x-part of velocity ui+1/2,jk in middle of x-face between grid cells (i,j,k) and (i+1,j,k)
y-part of velocity vi,j+1/2,k in middle of y-face
z-part of velocity wi,j,k+1/2 in middle of z-face
ui 12, j ui 1
2, jvi, j 1
2
MAC Grid in 2D
pi, j pi1, j
pi, j 1
pi, j1
pi 1, j
vi, j 12
Array storage
Then for a nxnynz grid, we store them as3D arrays:
p[nx, ny, nz]
u[nx+1, ny, nz]
v[nx, ny+1, nz]
w[nx, ny, nz+1]
And translate indices in code, e.g.
ui 12, j ,k u[i 1, j,k]
The downside
Not having all quantities at the same spot makes some algorithms a pain
Even interpolation of velocities for pushing particles is annoying
One strategy: switch back and forth (colocated/staggered) by averaging
My philosophy: avoid averaging as much as possible!
Advection Algorithms
Advecting Quantities
The goal is to solve
“the advection equation” for any grid quantity q
in particular, the components of velocity
Rather than directly approximate spatial term, we’ll use the Lagrangian notion of advection directly
We’re on an Eulerian grid, though, so the result will be called “semi-Lagrangian”
Introduced to graphics by [Stam’99]
Dq
Dt0
Semi-Lagrangian Advection
Dq/Dt=0 says q doesn’t change as you follow the fluid.
So
We want to know q at each grid point at tnew
(that is, we’re interested in xnew=xijk)
So we just need to figure outxold (where fluid at xijk came from)
andq(xold) (what value of q was there before)
q(xnew , t new ) q(xold , t old )
Finding xold
We need to trace backwards through the velocity field.
Up to O(∆t) we can assume velocity field constant over the time step
The simplest estimate is then
I.e. tracing through the time-reversed flow with one step of Forward Euler
Other ODE methods can (and should) be used
xold xijk t v
u(xijk )
Aside: ODE methods
Chief interesting aspect of fluid motion is vortices: rotation
Any ODE integrator we use should handle rotation reasonably well
Forward Euler does not
Instability, obvious spiral artifacts Runge-Kutta 2 is simplest half-decent
method
x n1 v
x n t vu
vx n 1
2 t vu(
vx n )
Details of xold
We need for a quantity stored at (i,j,k)
For staggered quantities, say u, we need it at the staggered location: e.g.
We can get the velocity there by averaging the appropriate staggered components: e.g.
u(xijk )
u(xi 1
2, j ,k )
u(xi 1
2, j ,k )
ui 12, j ,k
14 vij 1
2k vi1 j 1
2k vij 1
2k vi1 j 1
2k 1
4 wijk 12wi1 jk 1
2wijk 1
2wi1 jk 1
2
Which u to Use?
Note that we only want to advect quantities in an incompressible velocity field
Otherwise the quantity gets compressed(often an obvious unphysical artifact)
For example, when we advect u, v, and w themselves, we use the old incompressible values stored in the grid
Do not update as you go!
Finding q(xold)
Odds are when we trace back from a grid point to xold we won’t land on a grid point
So we don’t have an old value of q there
Solution: interpolate from nearby grid points
Simplest method: bi/trilinear interpolation
Know your grid: be careful to get it right for staggered quantities!
Boundary Conditions
What if xold isn’t in the fluid? (or a nearest grid point we’re interpolating from is not in the fluid?)
Solution: extrapolate from boundary of fluid
Extrapolate before advection, to all grid points in the domain that aren’t fluid
ALSO: if fluid can move to a grid point that isn’t fluid now, make sure to do semi-Lagrangian advection there
Use the extrapolated velocity
Extrapolating u Into Solids
Note that the inviscid “no-stick” boundary condition just says
The tangential component of velocity doesn’t have to be equal!
So we need to extrapolate into solids,and can’t use the solid’s own velocity(result would be bad numerical viscosity)
ugn v
usolid gn
Extrapolation
One of the trickiest bits of code to get right
For sanity check, be careful about what’s known and unknown on the grid
Replace all unknowns with linear combinations of knowns
More on this later (level sets)
Body Forces
Integrating Body Forces
Gravity vector or volumetric animator forces:
Simplest scheme: at every grid point just add
vu
tvg
u* v
u advected t vg
Making Fluids Incompressible
The Continuous Version
We want to find a pressure p so that the updated velocity:
is divergence free:
while respecting the boundary conditions:
u n1 v
u* t
p
gvu n1 0
ugn v
usolid gn at solid walls
p 0 at the free surface
The Poisson Problem
Plug in the pressure update formula into incompressibility:
Turns into a “Poisson equation” for pressure:
g
vu*
t
p
0
gt
p
gvu*
t
pgn (vu v
usolid )gn at solid walls
p 0 at the free surface
Discrete Pressure Update
The discrete pressure update on the MAC grid:
ui 12 jk
n1 ui 12 jk
* t
pi1 jk pijk
x
vij 12k
n1 vij 12k
* t
pij1k pijk
x
wijk 12
n1 wijk 12
* t
pijk1 pijk
x
Discrete Divergence
The discretized incompressibility condition on the new velocity (estimated at i,j,k):
ux
vy
wz
0
ui 12 jk
n1 ui 12 jk
n1
xvij 1
2kn1 vij 1
2kn1
xL
0
Discrete Boundaries
For now, let’s voxelize the geometry:each grid cell is either fluid, solid, or empty
S
S
S
E
S
S FS S
E E
F
FFF
F
F
F
What’s Active?
Pressure: we’ll only solve for p in Fluid cells
Velocity: anything bordering a Fluid cell is good
Boundary conditions:
p=0 in Empty cells (free surface)
p=? whatever is needed in Solid cells so that the pressure update makes
(Note normal is to grid cell!)(Also note: different implied pressures for each active face of a solid cell - we don’t store p there…)
u n1gn v
usolid gn
Example Solid Wall
(i-1,j,k) is solid, (i,j,k) is fluid
Normal is n=(1,0,0)
Want
The pressure update formula is:
So the “ghost” solid pressure is:
S F
ui 12 jk
n1 usolid
ui 1
2 jkn1 ui 1
2 jk*
t
pijk %pi 1 jk
x
pi 1 jk pijk
xt
ui 12 jk
n1 ui 12 jk
*
Discrete Pressure Equations
Substitute in pressure update formula to discrete divergence
In each fluid cell (i,j,k) get an equation:
1
x
ui 12 jk
t
pi1 jk pijk
x
ui 12 jk
t
pijk pi 1 jk
x
vij 12k
t
pij1k pijk
x
vij 12k
t
pijk pij 1k
x
wijk 12
t
pijk1 pijk
x
wijk 12
t
pijk pijk 1
x
0
Simplified
Collecting terms:
Empty neighbors: drop zero pressures
Solid neighbors: e.g. ( i-1, j, k) is solid
Drop pi-1jk - reduce coeff of pijk by 1 (to 5…)
Replace ui-1/2jk in right-hand side with usolid
t
6pijk pi1 jk pi 1 jk K
x2
ui 1
2 jk* ui 1
2 jk*
xK
Linear Equations
End up with a sparse set of linear equations to solve for pressure
Matrix is symmetric positive (semi-)definite
In 3D on large grids, direct methods unsatisfactory
Instead use Preconditioned Conjugate Gradient, with Incomplete Cholesky preconditioner
See course notes for full details (pseudo-code)
Residual is how much divergence there is in un+1
Iterate until satisfied it’s small enough
Voxelization is Suboptimal
Free surface artifacts:
Waves less than a grid cell high aren’t “seen” by the fluid solver – thus they don’t behave right
Left with strangely textured surface
Solid wall artifacts:
If boundary not grid-aligned, O(1) error – it doesn’t even go away as you refine!
Slopes are turned into stairs,water will pool on artificial steps.
Smoke
As per [Fedkiw et al.’01]
Soot
Smoke is composed of soot particles suspended in air
For simulation, need to track concentration of soot on the grid: s(x,t)
Evolution equation:
Extra term is diffusion (if k≠0)
Simplest implementation: Gaussian blur
Boundary conditions:
At solid wall: ds/dn=0 (extrapolate from fluid)
At smoke source: s=ssource
Note: lots of particles may be better for rendering…
Ds
Dtksgs
Heat
Usually smoke is moving because the air is hot
Hot air is less dense; pressure vs. gravity ends up in buoyancy (hot air rising)
Need to track temperature T(x,t)
Evolution equation (neglecting conduction)
Boundary conditions: conduction of heat between solids and fluids
Extrapolate T from fluid, add source term…
DT
Dt fradiation (T ) fsource T Tsource (x)
Boussinesq and Buoyancy
Density variation due to temperature or soot concentration is very small
Use the “Boussinesq approximation”:fix density=constant, but replace gravity in momentum equation with a buoyancy force:
Constants and can be tuned
fbuoy 0, s T Tamb , 0
Open Boundaries
If open air extends beyond the grid, what boundary condition?
After making the Boussinesq approximation, simplest thing is to say the open air is a free surface (p=0)
We let air blow in or out as it wants
May want to explicitly zero velocity on far boundaries to avoid large currents developing
Water
Where is the Water?
Water is often modeled as a fluid with afree surface
The only thing we’re missing so far is how to track where the water is
Voxelized: which cells are fluid vs. empty?
Better: where does air/water interface cut through grid lines?
Marker Particles
Simplest approach is to use marker particles
Sample fluid volume with particles {xp}
At each time step, mark grid cells containing any marker particles as Fluid, rest as Empty or Solid
Move particles in incompressible grid velocity field (interpolating as needed):
dxp
dtvu(xp )
Rendering Marker Particles
Need to wrap a surface around the particles
E.g. blobbies, or Zhu & Bridson ‘05
Problem: rendered surface has bumpy detail that the fluid solver doesn’t have access to
The simulation can’t animate that detail properly if it can’t “see” it.
Result: looks fine for splashy, noisy surfaces, but fails on smooth, glassy surfaces.
Improvement
Sample implicit surface function on simulation grid
Even just union of spheres is reasonable if we smooth and render from the grid
Note: make sure that a single particle always shows up on grid (e.g. radius ≥ ∆x) or droplets can flicker in and out of existence…
If not: you must delete stray particles
But still not perfect for flat fluid surfaces.
Level Sets
Idea: drop the particles all together, and just sample the implicit surface function on the grid
In particular, best behaved type of implicit surface function is signed distance:
Surface is exactly where =0
See e.g. the book [Osher&Fedkiw’02]
(
vx)
dist(vx,surface) :
vx is outside
dist(vx,surface) :vx is inside
Surface Capturing
We need to evolve on the grid
The surface (=0) moves at the velocity of the fluid (any fluid particle with =0 should continue with =0)
We can use same equation for rest of volume(doesn’t really matter what we do as long as sign stays the same – at least in continuous variables!)
DDt
0
Reinitializing
One problem is that advecting this way doesn’t preserve signed distance property
Eventually gets badly distorted
Causes problems particularly for extrapolation, also for accuracy in general
Reinitialize: recompute distance to surface
Ideally shouldn’t change surface at all, just values in the volume
Computing Signed Distance
Many algorithms exist
Simplest and most robust (and accurate enough for animation) are geometric in nature
Our example algorithm is based on a Fast Sweeping method [Tsai’02]
Set Up
Start by identifying grid cells where old changes sign (where the surface is)
Determine points and/or mesh elements to approximate surface
Set nearby grid values to exact distance to closest surface element
Also store index of closest surface element
Every other grid point is reset to = ±Land index of closest surface element = UNKNOWN
We then propagate information out to these points
Fast Sweeping
One sweep: loop i,j,k through the grid:
Check neighbors for their closest surface element
If the closest of those is closer than |ijk| then update ijk and set its index to that point
Idea: keep sweeping in different directions
++i, ++j, ++k
--i, ++j, ++k
++i, --j, ++k
--i, --j, ++k
++i, ++j, --k
etc…
Extrapolation
We often need fluid values extrapolated outside of the fluid
e.g. velocity must be extrapolated out from free surface and into solid
With signed distance this is much simpler
Extrapolation (1)
Interpolate fluid quantities onto stored surface points (generated in redistancing)
Make sure to only use known quantities, not values outside the fluid that the physics doesn’t touch
Then use index-of-closest-element to copy values everywhere needed
Extrapolation (2)
Gradient of distance points parallel to ray to closest surface point
Phrase extrapolation as a PDE:
Then solve the PDE with finite differences
Careful “upwind” scheme needed(want to get information from points with smaller distance, not bigger)
qg 0