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.