Arrows in the Fluid Mind
A 2D Fluid Dynamics Model for Animation
Based on Intuitive Physics
Jeffrey Ventrella
1997
Download a free Windows simulation now! (it's small - 167 kb)
NOTE - in this simulation, you can stir the fluid around in real time.
If you have a fast PC, it's really smooth
Introduction
The nature of flowing water is something that is familiar to all of us.
We see fluid motion in rushing creeks and on rocky seashores. We see
it as we swish in a bath tub or pour cream into coffee. As chaotic
and complex as moving fluid can be, the patterns and motions are
very familiar to us, owing perhaps to the fact that we live on a
planet in which water is one of the basic necessities of all life.
Most of us have grown to understand the general behaviors of water,
although our cognitive models may differ from one individual to the next.
Another thing which is familiar to most of us is the visual
symbol known as the arrow. The arrow is used both as an annotation
device and as a symbol of motion. In either case it implies
direction (of attention and energy respectively). The arrow is
often used in scientific data visualizations of computer simulations
of fluids to depict velocity and angle of flow in a field.
These visualizations often show a vast array of arrows of differing
lengths and angles. I was inspired originally by images of this
sort, and had begun to imagine a large population of arrows
constantly changing lengths and angles, and relaying information
to and from each other. This is the visual output of many fluid
dynamics simulations. But for me it served as an input to my thinking
about the logic behind the dynamics.
In my mind there was also something beautiful and universal
about the high-resolution color animations of turbulence produced in
such centers as the National Center for Supercomputer Applications, in
Champagne, Illinois, and at Los Alamos, New Mexico. Though I had
virtually no understanding of the mathematics behind these beautiful
scientific animations, I did have a sense that something essential
and maybe even simple was behind the natural phenomena being studied,
and that effects such as vortices and pressure waves could emerge from
simple rules that can be implemented without the use of large equations.
Since I think more often on a geometric level than on a
numerical level, I found the arrow as a useful tool to think with,
as I set out to generate theories and construct a model. In a way,
I have viewed the many little arrows as agents, which "give" and
"take" information among themselves on a local level, resulting in
the effect of fluid flow on a global level. So, equipped with my
arrow agent, as a tool to think with, I set out to try my own fluid
dynamics model.
This paper is written by a person initially trained in visual art,
communication design, animation, and art education, and then later, software programming.
The thinking styles based in my training in the arts have always informed my programming.
Thus, the Navier-Stokes
equation, and such mathematical descriptions of fluid flow have not
been used in the building of my model. I am more interested in a naive,
constructionist approach to modeling a natural phenomenon. That
one can use a naive physics to build theories and procedures which
result in beautiful and realistic animations is as interesting to
me as building scientifically valid simulations.
And so I would like to share with you some of the fruits of my explorations. These
exist in four forms: 1) as a computer program, 2) as set of
computer animations on videotape, 3) as a downloadable, realtime interactive animation, and
4) as documentation, which you are
reading. No mathematics is used in this paper to describe my model,
and this is consistent with the way in which I built the model, with
many diagrams of arrows, and many long moments at puddles in the road.
The Grid
Imagine a grid overlaid onto the surface of a region of liquid, such as
a shallow pool of water. Looking at the liquid through the grid, each
grid cell is like a window onto a small region of the liquid. Thus,
each cell can have information about the fluid behavior pertaining to
that region of the grid. As water flows across the actual pool, information
likewise flows across the grid.
In this model, the computational domain is a two-dimensional
grid of cells. It is a cellular automaton - in the running of the
animation, the entire grid of cells is updated in discrete time steps.
At each time step, information from each cell is propagated
to the neighboring cells surrounding it.
As the grid of cells is scanned, cell by cell, each cell
takes turns spreading information out to its neighbor cells.
This propagation of information from cell to cell across the
grid over many time steps gives rise to effects such as fluid
flow and pressure waves. The manner in which the information
is exchanged from cell to cell is determined by a set of rules
which I designed according to a general understanding of how
fluids behave. These rules comprise the physics of the simulation.
On the microscopic level of the cell and its neighborhood,
this cell-wise transfer of information may seem unrealistic, in
terms of the way real fluids behave. But as one brings the view
back to see the effect over a patch of many cells, the discrete
nature of these interactions blurs and the result is more continuous
flow. Consequently, the more cells I use in the model, and the
smaller the cells, the more realistic the animation.
Forms of Energy
The information in each cell of the grid has two parts, representing
two forms of energy: actual and potential. Actual energy consists
of fluid motion and is represented in this paper as a vector with a
velocity (length) and a direction (angle).
Potential energy consists of a pressure differential
(energy that will be released as radial motion) and is expressed
as a pressure value which can be either positive or negative.
In this paper, pressure is represented graphically as a dot.
The size of the dot shows the amount of pressure. If pressure
is positive it is shown as white, if negative, it is shown as
black.
These two forms of energy, which I call flow and
pressure, comprise the main elements of the fluid dynamics model, and they
are constantly exchanged throughout the simulation. From one time step
to the next, the flow energy of a cell can be partially or fully
converted into pressure, as it is passed to its neighbors, depending
on the conditions within those neighbors, and its relation to them.
Imagine a tide of water gushing onto a vertical wall, like the edge
of a dock: the motion energy of the water as it flows toward the wall
is partially converted to pressure energy at the region where it hits
the wall.
Pressure can also be converted into flow from one time
step to the next. Imagine, for example, an underwater explosion.
The pressure from the explosion propels water in all directions away
from the explosion: pressure is converted into flow as a sphere of
outward-radiating motion (in the immediate vicinity around the center
of the explosion.)
The conversion between the two forms of
energy often oscillates. For instance, where regions of opposing
flow are coming against each other, a high pressure region results.
This pressure region then causes a backlash of flow away from itself,
as illustrated:
Conservation of Energy
In any physics model such
as this, all these conversions from one form of energy to another
should be precise, and no energy should be lost or gained in the
process - only shuffled around within the system. If any energy
is lost in the process, the accumulation of these losses over a
number of time steps, can have exaggerated effects, and the energy
will quickly drain. Likewise, any slight addition of energy due to
imprecise computations can cause an exponential increase of energy
over a short period of time.
The idea of conservation of energy was
important to keep in mind in the design of the model. This principle was,
in fact, not too difficult to manifest in terms of computation.
What was difficult, on the other hand, was designing the nature
in which energy is converted from one form to the next, and devising
the rules which determine these conversions. It is easy to say:
"all the energy of every cell is to be divided up and distributed
to its eight
neighbors at every time step", but it is not easy to say which
neighbor cells get the most energy, and in what form it should
be given. The rules which I describe below are my solution to
this problem.
The Rules
1 The Flow Offspring Rule
2 The Pressure Offspring Rule
3 The Vector Conflict Rule
4 The Offspring Merge Rule
1) The Flow Offspring Rule
At each step in the simulation, the cells in front of and in back
of a flow vector receive the most energy, while the cells perpendicular
to the axis if the vector receive the least energy. Stated in another
way - each vector pushes at the region in front and pulls from the
region behind. Fluid lying where the flow is directed will be affected,
and fluid lying where the flow is coming from will also be affected.
According to the vector-offspring rule, each vector (as parent) is
subdivided into eight smaller vectors (as offspring) and distributed among
the neighbor cells in varying amounts. The relative amounts of energy in
the offspring vectors are determined by the relation of the parent's
direction to the positions of the neighbor cells. For instance, if the
parent vector is pointed upward, its offspring will be stronger in the
cells above and below the parent cell, corresponding to this pushing and
pulling effect. The offspring diagonal to the parent cell will receive a
smaller amount of energy, and the offspring to the left and right will
receive none, as shown in this illustration.
Stated in slightly more precise terms, if the parent vector's velocity
equals exactly 1, and its direction is exactly 90 degrees (upward in this coordinate
system), the offspring above and below will receive exactly one fourth the parent's
energy (0.25), and the diagonal offspring will receive exactly one eighth (0.125).
These add up to equal 1 - the velocity of the original parent vector.
If the parent vector is pointing in the direction of the upper right cell
(45 degrees), that cell's offspring will receive one fourth of the parent's
energy (0.25), as well as the lower left cell; the cells above, below, to
the left, and to the right will receive one eighth (0.125); and the two
remaining cells will receive none, as illustrated:
All offspring vectors receive energy according to their perpendicularity
to the parent, no matter what the direction the parent vector is heading.
For instance, in the following diagram, the parent vector (of value 1) is
pointing in the direction exactly between the lower-right and bottom cells
(62.5 degrees). Thus, the top-left, top, bottom-right, and bottom offspring
receive 0.1875, while the rest receive 0.0625, corresponding to the
perpendicularity of the offspring cell's relation to the parent's axis.
Again, these values add up to 1, the original parent's value.
In every case, the sum of the lengths of the offspring vectors
always equals the length of the parent vector, meaning that no energy
is lost or gained in the process, only distributed in uneven amounts
to the neighborhood. The mapping of perpendicularity to offspring
amount is linear. I have experimented with other mappings, such as
taking the cosine of the perpendicularity - which results in a
slightly different distribution of offspring amounts. Different
mappings cause different degrees to which fluid alongside a parent
vector's axis is dragged along with the flow. I don't have an
intuition as to what this may correspond to in the world of real
fluids (perhaps viscosity?), or whether it has any correspondence
at all. I hope to discover this some day, or perhaps the answer is
not discoverable, but must be explained to me, in a way that would
require me to re-work the push-pull theory behind this rule.
2) The Pressure Offspring Rule
Every cell in the grid has, in addition to a vector of flow,
a pressure value. The cell's pressure value can be positive or
negative, or it can be zero. If it is positive, it has a build-up
of energy and wants to push outward in the next time step.
If it is negative, it experiences a partial vacuum and wants
to pull energy from its neighborhood in the next time step.
At the next time step, the pressure value in each cell (if it
is non-zero) is converted into a radial collection of offspring
vectors among the eight neighbors. This radial collection of
offspring vectors is like a tiny explosion or implosion. The
energy of the explosion/implosion is directly proportional to
the amount of pressure.
Unlike the flow offspring rule, in this case every neighbor
cell receives the same amount of energy from the parent cell.
3) The Vector Conflict Rule
This rule is more complicated than the first two. This rule
operates on the fact that flow in one area of the fluid may come in
conflict with flow in another area. In a relatively calm region of
the fluid, vectors will often have very small lengths (very little
motion in the fluid), or no length at all:
-or they may all lie in the same direction and have the same length:
In both of these cases, all the vectors in the region are in agreement with
each other. They are at an equilibrium, as in a stagnant pond or the middle of a
large evenly-flowing river. If there is a difference-gradient among vector angles
and magnitudes, as shown in these three examples...
...the flow will be interrupted to some degree - energy passed between the
cells these vectors occupy will be partially converted to pressure values. For
instance, in the case of figure (a) above, the border between the two differing
regions of flow will experience a pull from the bordering vectors on the right.
Thus, in the next time step, offspring vectors lying at this border will be partially
converted to negative pressure values - a negative pressure front will appear at
this region. In the case of figure (b), the border between the two incoming
regions will experience a high pressure front - the energy from these clashing
vectors will be partially converted into positive pressure values.
In the case of figure (c), offspring vectors would be converted into a
slight mixture of both negative and positive pressure values, with a bit
of positive pressure appearing at the top, due to compression, and some
negative pressure at the right, due to expansion.
The vector conflict rule determines the degree in which the offspring
vectors are converted - wholly, or partially - into pressure, at the next time
step. This is done by considering the states of the other vectors in the
neighborhood and determining the degree of conflict in each, before the
offspring vectors are created. If the vectors in all the neighbor cells
are identical to the parent cell, for instance, it will have no conflict
and will give birth to healthy flow offspring in the next time step.
If there is a conflict, meaning that some vectors are aimed in different
directions or that the rate of flow is different, then the offspring will
be born with some of their flow energy converted to pressure energy.
In the following illustration, the parent encounters conflict with one
of its neighbor vectors, and so one of its offspring vectors is converted from
flow energy to pressure energy.
In the case of the top example, conflict in the upper-right cell causes
the associated offspring vector to be converted into positive pressure. In the
bottom example, conflict in the cell below causes the associated offspring to be
converted into negative pressure. Since the parent vector is pushing fluid ahead
of itself or pulling fluid from behind, if the neighbor cell is moving fluid in
the same direction and at the same rate as the parent vector, the fluid is pushed
or pulled along without any resistance, but if there is a difference in flow among
the cells, the fluid being pushed or pulled by the parent vector cannot move
along evenly, so this resistance shows up as positive or negative pressure values.
The following diagrams illustrate how the vector conflict rule is used
to determine the amount of conflict in neighboring cells. In this illustration,
the vectors in the white boxes represent a parent vector with an upright direction.
The vector in the darker box poses a potential conflict for the offspring vector
about to be born. In general, the more similarity among the two vectors, the
less the conflict.
The Mushroom Effect
Due to the vector conflict rule, A region of fluid moving in a specific
direction within an otherwise stagnant field will cause a billowing effect in
the direction of the flow. Just as in the case of real water, if you place a
hose underwater, and turn on the faucet, you will see that the water gushing
out of the hose doesn't just move straight out indefinitely - it encounters
resistance from the rest of the water around it, so it mushrooms, pushing some
water away in other directions - not just in the direction of the initial flow.
The diagram below illustrates how the vector conflict rule causes an initial set
of four vectors to spread flow outward, due to the radial effects of resulting
pressure. Notice that the negative pressure effects at the bottom cause the
fluid to be pulled in a similar manner.
4) The Offspring Merge Rule
Like I said, each cell delivers energy to its eight neighbors at every
time step, and since each cell is also a neighbor to eight other cells, it
receives energy from eight other neighbors. The vectors and pressures
received are piled onto the cell, as the grid is scanned and neighbors have
their turn at delivering their energy. These pieces of flow and pressure
must be merged together as they accumulate in the cell, in order to determine
the final flow and pressure values in next time step.
Adding vectors and pressures is not as easy as just adding up numbers,
like 4.5 and -56.0, as I soon found out while designing this model. In special
cases, it is a simple matter: if the two vectors being added have identical
directions, as shown:
-then the resulting vector should have the same direction and be
twice as long. But, if you add the following two vectors together:
A logical solution is to have them cancel each other out. But to do
this would imply that the energy is lost, and this would not fit with the
law of conservation of energy. The energy has to go somewhere - so in this
model it is converted into pressure, as in the case of the Flow Offspring
Rule, when neighboring flows conflict.
These two vectors add up to form a combination of both flow and pressure:
Adding pressures is done in a similar way. For instance, adding a pressure
value of -0.8 to a pressure value of 0.8 will result in a value of 0.0, with
some leftover energy equaling 0.16. This remaining energy is added to the
velocity of the flow vector.
After all the neighbors have contributed all
their energy, and leftover energy is shuffled between flow and pressure,
there remains in the end a vector with a direction and a velocity, and
a pressure value, which can be either negative or positive. The purpose
of all these conversions is to conserve energy - and in a realistic way.
The remaining flow and pressure values contain all the energy which has
been gathered from the neighbors, and the direction of the vector
inherits some average of the directions of neighboring cells whose
vectors have contributed the most energy. The amount of pressure
energy corresponds to the degree in which accumulated vectors clash.
Visualization
Thousands of Floating Bits
My favorite way to animate this fluid dynamics system is with a
technique analogous to placing many little bits of leaves into a stream
and watching them swirl around, carried away by the flow of the water.
I initialize a large array of many thousands of little bits to be
scattered randomly in the field at the start of the animation.
Depending on the direction of flow and the velocity at each bit's
location, it moves along the field, driven by the fluid dynamics.
Also, the velocity and direction of each bit are visualized by
rendering the bit as a dash, rather than a point, with the dash's
length and angle corresponding to the velocity and direction of the
fluid driving it. In just a few time steps of the animation,
patterns emerge among the bits indicating areas of rapid flow,
vortices, eddies, and pressure effects.
The following diagram illustrates how the floating bits
layer is overlaid onto the fluid dynamics layer.
The illustration below demonstrates a typical frame from an animation
showing the patterns which emerge among the bits, moved around by the
fluid dynamics.
Effects
The Walls of the Aquarium
All cellular automata models which people build to simulate
natural phenomena must have boundaries, even if the model represents
an ideally infinite domain. Boundaries exist simply because one must
have a limit on the size of the array of cells held in computer memory.
Boundary effects due to computational limits often get in the way of
models which attempt to simulate phenomena without any explicit
hard-edge boundaries.
One common technique used in cellular automata to get around
the problem of boundary effects is to let the left and right boundaries,
and bottom and top boundaries "wrap-around". This way, information
"falling off the edge" of the domain can reappear on the opposite
edge, like a ship sailing around the world (a torus-shaped world,
that is). As far as the ship is concerned, there are no
interruptions in its voyage.
I decided not to do this. I decided that the way to deal
with the boundary effect is to treat the boundary exactly like a
boundary, as if the fluid were existing within a rectangular tub.
In a college painting class, I learned how to treat the edges of
the canvas an aspect of the painting itself - as something which
can lend integrity to the composition. Likewise, I wanted my work
of fluid art to express the cellular array that it occupies,
complete with its boundaries. Besides, it is at the sides and
corners of my virtual aquarium that the most interesting patterns
emerge, such as swirling eddies, and lapping waves - things with
tend to bring out the characteristics of my fluid.
The technique for simulating the walls of my virtual tub of
water is analogous to folding the edge of a piece of paper back onto
itself. This causes the propagation of energy to neighbor cells
at the edge of the grid to reflect back onto the original cells,
as indicated by this diagram:
Since all edges are folded like this, the four corner cells are
thus reflected doubly:
With this technique, vectors which are pushing against the
edge of the walls encounter some opposing vectors, in the form of
their own offspring. The result is a buildup of pressure, as
would result in a natural boundary where fluid is flowing toward
the edge. Likewise, vectors pulling from the edge will
encounter opposing vectors, in the form of their own offspring,
which pull back, causing negative pressure. Vectors near the
edge which are flowing parallel to the walls are not as affected
by the walls, since their offspring are strongest in front and
in back, not so much at their sides.
The Swisher
I created an object which swishes through the fluid, much the same
way as one might run a hand through a tub to create flow. The swisher
is a disk which moves around in the fluid, appearing and disappearing as
if to be dipping into the water to momentarily push the water this way
and that. The swisher helps me to see how things are working as I
develop the model.
It works like this: the swisher swoops around according to some
motion function, such as a set of sine waves. The dipping in and out of
the water (appearing and disappearing) is calculated in a similar way.
I scan the grid, and identify which cells are in the same location as
the swisher at each time step. The cells which the swisher is
covering are given vectors of flow which correspond exactly to the
speed and direction of the swisher's motion. No pressure values are
given to the cells. As the swisher moves, it propagates flow. Also,
high pressure builds up immediately in front of it, and it leaves a
trail of low pressure behind, and fluid rushes in to fill the low
pressure trail. When the swisher disappears, the fluid still moves
on its own, and eventually comes to rest. At times, the moving fluid
pushes against the walls, causing eddies and pressure effects at the
boundary. Sometimes the swisher comes back and creates a flow that
interrupts with a flow that it had previously caused - this
generates interesting turbulent effects as the conflicting flows clash.
The swisher is fun!
Conclusion
There is a fluid dynamics which is
activated in my mind when I see and feel water swirling under my hand.
My mind's fluid dynamics is manifest in the model I have built. It is
not accurate by the standards of sophisticated simulations rendered so
beautifully on supercomputers for scientific purposes. But I have spent
many years trying to focus as closely on my inner fluid dynamics as
possible, and also to adjust my model as I learn through experiences.
This has been a psychological inquiry as much as an artistic or scientific
one. And the fact that my animations bear a resemblance to real fluid,
and evoke a similar aesthetic response is an added cause for celebration.
I hope this paper helps you to share with me an appreciation
for the beauty and complexity of flowing water.
A Few Technical Notes
The computer program for this model was first written in Pascal,
and then in C language. It is still being enhanced at this time.
One version runs on a Silicon Graphics IRIS computer. A more recent
version, which is unfinished, runs on a PC over Windows. You can
download it from this page. This version is not yet complete in that pressure
effects are not working. I intend to make this revision whenever I get a chance.
I run the program
at varying resolutions depending on what aspect I am working on,
and whether I am testing something in the model or rendering a
complete animation. The higher the resolution, the longer it
takes, but the more realistic the effect. A single frame of
animation can take minutes at high resolutions. When I record each
frame onto videotape, I can later play the videotape to see my
animations at 30 frames per second.
The program was originally developed in the Advanced
Graphics Research Lab of Syracuse University, and later re-worked
at Cinergi Inc. in Lenox, MA. It was later developed further
at the Media Lab at MIT, and I have been developing it recently.