You are on page 1of 28

How to write an Eulerian Fluid Simulator

with 200 lines of JavaScript code


Matthias Müller, Ten Minute Physics
For the code and the demo see:

www.matthiasmueller.info/tenMinutePhysics
a few remarks…
Fluid =

or

liquid gas

Similar physical structures → same simulation method


Eulerian
𝑒𝑒 𝑖𝑖𝜋𝜋 = −1

Swiss Italian

Leonhard Euler (1707-1783) Joseph-Louis Lagrange (1736-1813)

grid-based grid-free (e. g. particles)


From 2d to 3d

straight forward - left as an exercise


Incompressible Fluid

• We assume incompressibility

• Water is very close to being incompressible


10,000 kg / cm2 → 3% compression!

• Reasonable assumption for free gas as well

→ compressible simulation in upcoming tutorial


Inviscid Fluid

• We assume zero viscosity

• Good approximation for gas and water

inviscid viscous
→ viscous simulation in upcoming tutorial
the method…
Fluid as a Velocity Field on a Grid
𝑢𝑢
• Velocity is a 2d vector 𝐯𝐯 = (vectors are written in boldface)
𝑣𝑣

𝐯𝐯𝑖𝑖,𝑗𝑗
𝑣𝑣𝑖𝑖,𝑗𝑗

𝑢𝑢𝑖𝑖,𝑗𝑗 𝑢𝑢𝑖𝑖,𝑗𝑗
𝑣𝑣𝑖𝑖,𝑗𝑗


collocated grid staggered grid
Fluid Simulation

Modify velocity values (e.g. add gravity)

Make the fluid incompressible (projection)

Move the velocity field (advection)


Update Velocity

for all 𝑖𝑖, 𝑗𝑗


𝑣𝑣𝑖𝑖,𝑗𝑗 ← 𝑣𝑣𝑖𝑖,𝑗𝑗 + ∆𝑡𝑡 � 𝑔𝑔

• Gravity 𝑔𝑔: −9.81 𝑚𝑚/𝑠𝑠 2


1
• Timestep ∆𝑡𝑡: ( e. g. 𝑠𝑠 )
30
Divergence (Total Outflow)
𝒅𝒅 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒗𝒗𝒊𝒊,𝒋𝒋

𝑣𝑣𝑖𝑖,𝑗𝑗+1

𝑢𝑢𝑖𝑖𝑖𝑖 𝑢𝑢𝑖𝑖+1,𝑗𝑗

𝑣𝑣𝑖𝑖𝑖𝑖

• Positive • Negative • Zero


• Too much outflow • Too much inflow • Incompressible
Forcing Incompressibility

Too much inflow Changing one velocity Push all velocities outward
A fluid cannot do that! by the same amount
Forcing Incompressibility
𝑣𝑣𝑖𝑖,𝑗𝑗+1
𝒅𝒅 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒗𝒗𝒊𝒊,𝒋𝒋

𝒖𝒖𝒊𝒊,𝒋𝒋 ← 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒅𝒅/𝟒𝟒


𝑢𝑢𝑖𝑖,𝑗𝑗 𝑢𝑢𝑖𝑖+1,𝑗𝑗
𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒅𝒅/𝟒𝟒
𝒗𝒗𝒊𝒊,𝒋𝒋 ← 𝒗𝒗𝒊𝒊,𝒋𝒋 + 𝒅𝒅/𝟒𝟒
𝑣𝑣𝑖𝑖,𝑗𝑗
𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 ← 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒅𝒅/𝟒𝟒
Obstacles / Walls
𝑣𝑣𝑖𝑖,𝑗𝑗+1
𝒅𝒅 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒗𝒗𝒊𝒊,𝒋𝒋

𝒖𝒖𝒊𝒊,𝒋𝒋 ← 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒅𝒅/𝟒𝟒


𝑢𝑢𝑖𝑖,𝑗𝑗 𝑢𝑢𝑖𝑖+1,𝑗𝑗 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒅𝒅/𝟑𝟑
𝒗𝒗𝒊𝒊,𝒋𝒋 ← 𝒗𝒗𝒊𝒊,𝒋𝒋 + 𝒅𝒅/𝟑𝟑
𝑣𝑣𝑖𝑖,𝑗𝑗 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 ← 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒅𝒅/𝟑𝟑

𝑢𝑢𝑖𝑖,𝑗𝑗 ≠ 0
• Moving object
• Turbine pushing fluid (e. g. wind tunnel)
General Case

𝒅𝒅 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒗𝒗𝒊𝒊,𝒋𝒋


𝒔𝒔 ← 𝒔𝒔𝒊𝒊+𝟏𝟏,𝒋𝒋 + 𝒔𝒔𝒊𝒊−𝟏𝟏,𝒋𝒋 + 𝒔𝒔𝒊𝒊,𝒋𝒋+𝟏𝟏 + 𝒔𝒔𝒊𝒊,𝒋𝒋−𝟏𝟏
𝑠𝑠𝑖𝑖−1,𝑗𝑗 = 0
𝑠𝑠𝑖𝑖,𝑗𝑗 = 1 𝒖𝒖𝒊𝒊,𝒋𝒋 ← 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒅𝒅 𝒔𝒔𝒊𝒊−𝟏𝟏,𝒋𝒋 /𝒔𝒔
𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒅𝒅 𝒔𝒔𝒊𝒊+𝟏𝟏,𝒋𝒋 /𝒔𝒔
𝒗𝒗𝒊𝒊,𝒋𝒋 ← 𝒗𝒗𝒊𝒊,𝒋𝒋 + 𝒅𝒅 𝒔𝒔𝒊𝒊,𝒋𝒋−𝟏𝟏 /𝒔𝒔
𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 ← 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒅𝒅 𝒔𝒔𝒊𝒊,𝒋𝒋+𝟏𝟏 /𝒔𝒔
Solving the Grid
for 𝒏𝒏 iterations • Gauss-Seidel method
for all 𝒊𝒊, 𝒋𝒋 • On the boundary we access
𝒅𝒅 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒗𝒗𝒊𝒊,𝒋𝒋 cells outside of the grid!

𝒔𝒔 ← 𝒔𝒔𝒊𝒊+𝟏𝟏,𝒋𝒋 + 𝒔𝒔𝒊𝒊−𝟏𝟏,𝒋𝒋 + 𝒔𝒔𝒊𝒊,𝒋𝒋+𝟏𝟏 + 𝒔𝒔𝒊𝒊,𝒋𝒋−𝟏𝟏 • Add border cells

𝒖𝒖𝒊𝒊,𝒋𝒋 ← 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒅𝒅 𝒔𝒔𝒊𝒊−𝟏𝟏,𝒋𝒋 /𝒔𝒔 • Set 𝑠𝑠𝑖𝑖,𝑗𝑗 = 0 for walls


𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒅𝒅 𝒔𝒔𝒊𝒊+𝟏𝟏,𝒋𝒋 /𝒔𝒔 • or copy neighbor values
𝒗𝒗𝒊𝒊,𝒋𝒋 ← 𝒗𝒗𝒊𝒊,𝒋𝒋 + 𝒅𝒅 𝒔𝒔𝒊𝒊,𝒋𝒋−𝟏𝟏 /𝒔𝒔
𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 ← 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒅𝒅 𝒔𝒔𝒊𝒊,𝒋𝒋+𝟏𝟏 /𝒔𝒔
Measuring Pressure
𝑝𝑝𝑖𝑖,𝑗𝑗 is physical pressure
for all 𝒊𝒊, 𝒋𝒋
𝒑𝒑𝒊𝒊,𝒋𝒋 ← 𝟎𝟎 𝝆𝝆 density
ℎ grid spacing
for 𝒏𝒏 iterations
for all 𝒊𝒊, 𝒋𝒋 ∆𝑡𝑡 time step
𝒅𝒅 ← 𝒖𝒖𝒊𝒊+𝟏𝟏,𝒋𝒋 − 𝒖𝒖𝒊𝒊,𝒋𝒋 + 𝒗𝒗𝒊𝒊,𝒋𝒋+𝟏𝟏 − 𝒗𝒗𝒊𝒊,𝒋𝒋 Not necessary for simulation
𝒔𝒔 ← 𝒔𝒔𝒊𝒊+𝟏𝟏,𝒋𝒋 + 𝒔𝒔𝒊𝒊−𝟏𝟏,𝒋𝒋 + 𝒔𝒔𝒊𝒊,𝒋𝒋+𝟏𝟏 + 𝒔𝒔𝒊𝒊,𝒋𝒋−𝟏𝟏

𝒅𝒅 𝝆𝝆 𝒉𝒉
𝒑𝒑𝒊𝒊,𝒋𝒋 ← 𝒑𝒑𝒊𝒊,𝒋𝒋 + �
𝒔𝒔 ∆𝒕𝒕
Overrelaxation
• Gauss-Seidel is very simple to implement
• Needs more iterations than global methods
• Acceleration: Overrelaxation – Magic!!

𝑑𝑑 ← 𝒐𝒐 𝑢𝑢𝑖𝑖+1,𝑗𝑗 − 𝑢𝑢𝑖𝑖,𝑗𝑗 + 𝑣𝑣𝑖𝑖,𝑗𝑗+1 − 𝑣𝑣𝑖𝑖,𝑗𝑗

• Multiply the divergence by a scalar 1 < 𝑜𝑜 < 2


• I use 𝑜𝑜 = 1.9 in the code
• Increases convergence dramatically
• The computed pressure value is still correct!
Last step: Advection

𝐯𝐯𝑡𝑡 𝐯𝐯𝑡𝑡+∆𝑡𝑡

𝑝𝑝𝑖𝑖 𝑢𝑢𝑖𝑖,𝑗𝑗
𝑝𝑝𝑖𝑖
moving particle
𝑣𝑣𝑖𝑖,𝑗𝑗

• In a fluid the velocity state is carried by the particles


• Particles move, grid cells are static
• We need to move the velocity values in the grid!
Semi-Lagrangian Advection

𝑢𝑢𝑡𝑡+∆𝑡𝑡 ← 𝑢𝑢𝑡𝑡

𝑢𝑢𝑡𝑡

• Which fluid “particle” moved to the location where 𝑢𝑢 is stored?


• Set the new velocity 𝑢𝑢𝑡𝑡+∆𝑡𝑡 to the velocity 𝑢𝑢𝑡𝑡 at the previous position
Semi-Lagrangian Advection
𝐯𝐯(𝐱𝐱)
𝐱𝐱

𝐱𝐱 − ∆𝑡𝑡 � 𝐯𝐯(𝐱𝐱)

• Compute 𝐯𝐯 at position 𝐱𝐱 where 𝑢𝑢 is stored


• The previous location can be approximated as 𝐱𝐱 − ∆𝑡𝑡 � 𝐯𝐯(𝐱𝐱)
• Assuming a straight path introduces viscosity!
Can be reduced with vorticity confinement
Get the 2d Velocity
𝑣𝑣𝑖𝑖−1,𝑗𝑗+1 𝑣𝑣𝑖𝑖,𝑗𝑗+1

𝑣𝑣̅ 𝐯𝐯 = [𝑢𝑢𝑖𝑖,𝑗𝑗 , 𝑣𝑣]̅


𝑢𝑢𝑖𝑖,𝑗𝑗

𝑣𝑣𝑖𝑖−1,𝑗𝑗 𝑣𝑣𝑖𝑖,𝑗𝑗

• Average surrounding vertical velocities


𝑣𝑣̅ = (𝑣𝑣𝑖𝑖,𝑗𝑗 + 𝑣𝑣𝑖𝑖,𝑗𝑗+1 + 𝑣𝑣𝑖𝑖−1,𝑗𝑗 + 𝑣𝑣𝑖𝑖−1,𝑗𝑗+1 )/4
General Grid Interpolation
𝑣𝑣𝑖𝑖,𝑗𝑗+1 𝑣𝑣𝑖𝑖+1,𝑗𝑗+1

𝑣𝑣̅ 𝑤𝑤00 = 1 − 𝑥𝑥/ℎ 𝑤𝑤01 = 𝑥𝑥/ℎ


𝑥𝑥
𝑤𝑤10 = 1 − 𝑦𝑦/ℎ 𝑤𝑤11 = 𝑦𝑦/ℎ
𝑦𝑦
𝑣𝑣𝑖𝑖,𝑗𝑗 𝑣𝑣𝑖𝑖+1,𝑗𝑗

𝑣𝑣̅ = 𝑤𝑤00 𝑤𝑤10 𝑣𝑣𝑖𝑖,𝑗𝑗 + 𝑤𝑤01 𝑤𝑤10 𝑣𝑣𝑖𝑖+1,𝑗𝑗 + 𝑤𝑤01 𝑤𝑤11 𝑣𝑣𝑖𝑖,𝑗𝑗+1 + 𝑤𝑤00 𝑤𝑤11 𝑣𝑣𝑖𝑖+1,𝑗𝑗+1
Smoke Advection

• Store density value at the center of each cell


• Advect it like the velocity components
Streamlines

𝐱𝐱 ← start position
𝑠𝑠 ← step size 𝑠𝑠 � 𝐯𝐯(𝐱𝐱 𝟐𝟐 )
𝐱𝐱 𝟑𝟑
𝐱𝐱 𝟐𝟐

for 𝒏𝒏 steps
𝑠𝑠 � 𝐯𝐯(𝐱𝐱 𝟏𝟏 )
𝐯𝐯 ← sampleV(𝐱𝐱)
𝐱𝐱 𝟏𝟏
𝐱𝐱 ← 𝐱𝐱 + 𝑠𝑠𝐯𝐯
Let’s look into the code…

You might also like