[Android Apps and Games] 12er:
Ok, this isn't going to be easy. I can tell that you won't understand anything with just one answer. But I like this topic, so I am going to answer the question anyway. Hopefully I can get some of the users here into fluid dynamics :D Computational fluid dynamics is really cool, and learning some of the basics about it is not very easy for the start, but rewarding in my opinion.

A short overview about the simulation:

The physical Model:

I modelled the fluid as an inviscid incompressible fluid. Fluids are materials which do not resist deformation, such that shear forces are solely caused by friction. At the same time I assumed that the fluid is inviscid, therefore there is no friction between the fluid layers. The incompressibility entails that the fluid's density is equal everywhere.

The motion of such a fluid is governed by the Euler equations (inviscid Navier Stokes equations):

[IMG="latex"]http://latex.codecogs.com/gif.latex?%5Crho%20%5Ccdot%20%5Cleft%28%20%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20t%7D%20%5Cmathbf%7Bv%7D%20&plus;%20%28%5Cmathbf%7Bv%7D%20%5Ccdot%20%5Cnabla%29%20%5Cmathbf%7Bv%7D%20%5Cright%20%29%20%3D%20-%20%5Cnabla%20p%20&plus;%20%5Crho%20%5Ccdot%20%5Cmathbf%7Bf%7D%20%5Cquad%20%5Cquad%20%5Cquad%20%281%29[/IMG]

[IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cnabla%20%5Ccdot%20%5Cmathbf%7Bv%7D%20%3D%200%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%282%29[/IMG]

What do those equations mean?

Let's break down the first equation: v is a vector quantity mapping each point in space to the velocity of the particle sitting there. And [IMG="latex"]http://latex.codecogs.com/gif.latex?%5Crho[/IMG] is the density, in other words mass per unit volume. The lefthand side of formula (1) has two factors, density [IMG="latex"]http://latex.codecogs.com/gif.latex?%5Crho[/IMG] and the term in the brackets. The term in the brackets is equivalent to the acceleration of each particle from the particle's standpoint. So the lefthand side is analogous to "mass times acceleration", hence the equation means that the particles of the fluid change their momentum according to the forces on the right side of the equation.

So the right side of equation (1) is the sum of all forces working on the particles. According to equation (1) two forces are working on each particle: Some force [IMG="latex"]http://latex.codecogs.com/gif.latex?-%20%5Cnabla%20p[/IMG], where p is the pressure. [IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cnabla[/IMG] retrieves the gradient of a scalarquantity, pointing from lower to higher values. So [IMG="latex"]http://latex.codecogs.com/gif.latex?-%20%5Cnabla%20p[/IMG] is a force accelerating particles away from regions with high pressure. The last summand on the right side is the force caused by gravity, such that f is earth's acceleration.

According to the formula (2) the divergence of velocity v is zero, in other words the particles' trajectories aren't changing in density. So the fluid is incompressible.

Equation (1) is nothing more but a momentum conservation equation, and equation (2) is both an incompressibility constraint and a continuity equation stating that the total mass isn't changing.

The Simulation

For the simulation I implemented a grid based finite difference method. By gridbased I mean that the main datastructure used for the simulation is a twodimensional grid (in contrast particle based methods, where actually individual particles travel through space, are popular too, but for those finding the neighboring particles can get computationally quite expensive). Each gridcell contains all the information about the particle sitting in this cell at a particular moment, like pressure, velocity and color of the particle in the cell. The graphic below demonstrates the structure

[IMG="grid"]https://38.media.tumblr.com/3e24a36aa3002646d4dc938b58355606/tumblr_nbibqoV4KQ1tktekzo1_400.png[/IMG]

Such twodimensional grids can be represented by textures in OpenGl.

The simulation is done by approximating the solutions of equations (1) and (2) iteratively. The solution at a particular point of time is stored in a grid like described above. To calculate the state of the solution after a timeinterval [IMG="latex"]http://latex.codecogs.com/gif.latex?%5CDelta%20t[/IMG], we advance forward in time according to the equations above, and update the grid with the new solution. Let's rewrite equation (1) by shifting terms to the right side such that we can do something like forward-Euler in time to approximate solutions:

[IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20t%7D%20%5Cmathbf%7Bv%7D%20%3D%20-%28%5Cmathbf%7Bv%7D%20%5Ccdot%20%5Cnabla%29%20%5Cmathbf%7Bv%7D%20-%20%5Cfrac%7B1%7D%7B%5Crho%7D%5Cnabla%20p%20&plus;%20%5Cmathbf%7Bf%7D%20%5Cquad%20%5Cquad%20%5Cquad%20%283%29[/IMG]

By splitting this equation into three equations, and solving those in sequence, an approximation of the solution for each timestep can be obtained:

[IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20t%7D%20%5Cmathbf%7Bv%7D%20%3D%20-%28%5Cmathbf%7Bv%7D%20%5Ccdot%20%5Cnabla%29%20%5Cmathbf%7Bv%7D%20%5Cquad%20%5Cquad%20%5Cquad%20%284%29[/IMG]

[IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20t%7D%20%5Cmathbf%7Bv%7D%20%3D%20%5Cmathbf%7Bf%7D%20%5Cquad%20%5Cquad%20%5Cquad%20%285%29[/IMG]

[IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cfrac%7B%5Cpartial%7D%7B%5Cpartial%20t%7D%20%5Cmathbf%7Bv%7D%20%3D%20-%20%5Cfrac%7B1%7D%7B%5Crho%7D%5Cnabla%20p%20%5Cquad%20%5Cquad%20%5Cquad%20%286%29[/IMG]

Step 1: Advection - Solving equation (4)

Recall that the lefthand side of equation (1) describes the rate of change of momentum. So equation (4) states that the momentum isn't changing. As a result particles are moving along straight lines at velocity v according to equation (4). Due to the discrete nature of the grid, the actual movement can only be approximated. For more accurate solutions a higher order Runge Kutta method could be deployed, or the MacCormack scheme is very popular, but for simplicity I describe the Forward Euler method, which is closer to intuition: During a timestep [IMG="latex"]http://latex.codecogs.com/gif.latex?%5CDelta%20t[/IMG] each particle moves from its position p to position [IMG="delta"]http://latex.codecogs.com/gif.latex?p%20&plus;%20%5CDelta%20t%20%5Ccdot%20v[/IMG].

But how can straight movement be realized by particles described through a grid? Simply by doing the following for each gridcell: Lookup the velocity v, and copy the data of the particle there, which was at position [IMG="past"]http://latex.codecogs.com/gif.latex?p%20-%20%5CDelta%20t%20%5Ccdot%20v[/IMG] before timestep [IMG="latex"]http://latex.codecogs.com/gif.latex?%5CDelta%20t[/IMG].

[IMG="adv"]https://38.media.tumblr.com/034388c6f54cd86a9c0540aa5772df75/tumblr_nbicudj8pJ1tktekzo1_250.png[/IMG]

If position [IMG="past"]http://latex.codecogs.com/gif.latex?p%20-%20%5CDelta%20t%20%5Ccdot%20v[/IMG] isn't located exactly at the center of a cell (and this will almost always be the case), the data of the cells around this point have to be interpolated. OpenGl can do this for you by for instance bilinearly filtering the textures. Inside the shader it's enough to just lookup the fragmentdata at that particular position, as OpenGl does the interpolation for you, if it's activated.

Step 2: Gravity - Solving equation (5)

Advancing for a timestep [IMG="latex"]http://latex.codecogs.com/gif.latex?%5CDelta%20t[/IMG] according to equation (5) is actually pretty simple. After that timestep the velocity v changes by acceleration f times timeslot [IMG="latex"]http://latex.codecogs.com/gif.latex?%5CDelta%20t[/IMG]. So to obey equation (5) the velocity of each grid cell is updated using this formula: [IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cmathbf%7Bv%7D%5E%7Bt&plus;1%7D%20%3D%20%5Cmathbf%7Bv%7D%5E%7Bt%7D%20&plus;%20%5CDelta%20t%20%5Ccdot%20%5Cmathbf%7Bf%7D[/IMG]

Step 3: Pressure, and making the velocity divergence free - Solving equation (6)

This step is done by calculating the gradient of pressure p at each gridcell, and updating the velocities analogous to the gravity step. But this time it is done by adding the gradient of the pressure times [IMG="latex"]http://latex.codecogs.com/gif.latex?%5CDelta%20t[/IMG] to the velocity of each gridcell:

[IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cmathbf%7Bv%7D%5E%7Bt&plus;1%7D%20%3D%20%5Cmathbf%7Bv%7D%5E%7Bt%7D%20&plus;%20%5CDelta%20t%20%5Ccdot%20%5Cleft%28-%5Cfrac%7B1%7D%7B%5Crho%7D%20%5Ccdot%20%5Cnabla%20p%20%5Cright%29%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%286%29[/IMG]

But how do we obtain the pressure p? And up to here nothing has been done to keep velocity v divergence free. That's where equation (2) comes in: If we take the divergence of both sides of equation (6), and demand that the velocity [IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cmathbf%7Bv%7D%5E%7Bt&plus;1%7D[/IMG] is divergencefree ([IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cnabla%20%5Ccdot%20%5Cmathbf%7Bv%7D%20%3D%200[/IMG]) after the timestep, the lefthand side of equation (6) becomes zero. The equation obtained that way is called pressure Poisson equation:

[IMG="latex"]http://latex.codecogs.com/gif.latex?%5Cfrac%7B%5CDelta%20t%7D%7B%5Crho%7D%20%5Ccdot%20%5Cnabla%5E2%20p%20%3D%20%5Cnabla%20%5Ccdot%20%5Cmathbf%7Bv%7D%5E%7Bt%7D%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%287%29[/IMG]

Solving this equation gets us the pressure p, and the pressure has just the right amount to make the velocity divergence-free, if we update the velocity field according to equation (6). So the pressure acts as a quantity which makes the fluid incompressible. That's close to intuition: we try to compress the fluid -> pressure builds up, which makes the fluid resist being compressed.

Discretizing the problem turns equation (7) into large system of linear equations. Luckily the system matrix of those equations is sparse such that its solutions can be approximated efficiently by iterative approaches like Black & White Gauss-Seidel, or the Jacobi method. For simplicity I consider the Jacobi method. Let q be

[IMG="latex"]http://latex.codecogs.com/gif.latex?q%20%3D%20%5Cfrac%7B%5CDelta%20t%20%5Ccdot%20p%7D%7B%5Crho%7D%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%5Cquad%20%288%29[/IMG]

then q (and therefore pressure p) can be approximated iteratively by updating for q for each gridcell by using this formula:

[IMG="latex"]http://latex.codecogs.com/gif.latex?q%5E%7Bt&plus;1%7D%20%3D%20%5Cfrac%7Bq%5Et_%7B%5Ctext%7Babove%7D%7D%20&plus;%20q%5Et_%7B%5Ctext%7Bbelow%7D%7D%20&plus;%20q%5Et_%7B%5Ctext%7Bleft%7D%7D%20&plus;%20q%5Et_%7B%5Ctext%7Bright%7D%7D%20-%20%5Cleft%28%20v_%7B%28%5Ctext%7Bx%20%2C%20right%7D%29%7D%20-%20v_%7B%5Ctext%7B%28x%20%2C%20left%29%7D%7D%20&plus;%20v_%7B%5Ctext%7B%28y%20%2C%20above%29%7D%7D%20-%20v_%7B%5Ctext%7B%28y%20%2C%20below%29%7D%7D%20%5Cright%29%20%7D%7B2%20%5Ccdot%20n%7D%20%5Cquad%20%5Cquad%20%5Cquad%20%289%29%20%5C%5C%20n%20%3D%202[/IMG]

(To cover three dimensions, we would have to use n=3, and add q_front/behind and v_front/behind ...)

[IMG="jacobi"]https://33.media.tumblr.com/1e0e897ac950383af9ef48a31ae65760/tumblr_nbihkvsmpY1tktekzo1_500.png[/IMG]

Calculating q would require executing formula (9) repetively until q converges. A trick to spare time, since everything should run in real time: I am reusing q each frame, and running the Jacobi step from formula (9) only two times each frame, such that a very rough approximation of q accumulates over time.

Obviously this whole step is the computationally most expensive step: Calculating q by running the Jacobi step from formula (9) a few times, calculating the pressure p from q according to formula (8), and using the pressure to calculate the gradient to update the velocity according to formula (6) is what has to be done.

Putting it all together

For each frame steps 1 - 3 are run in sequence. That's the basic algorithm, which I used to approximate incomrpessible inviscid flows in my application. By using a threedimensional grid, the simulation could be done for three dimensions! That's where in my opinion it starts to get really exciting, because cloud formations with interesting dynamics, explosions and even the physically correct movement of water bodies could be simulated. It's a pitty that even on high end platforms such simulations require a lot of resources. So I had to stay in two dimensions in my Android app. But I think that a simulation in just two dimensions still demonstrates how wonderful fluid dynamics can be.

Still not convinced that fluid dynamics is an awesome topic? Some images might demonstrate the difference between 2D and 3D fluid dynamics. The first three images are from 2D fluid simulators (my app, magic fluids, fleya):

[IMG="myapp"]https://33.media.tumblr.com/c0a5c783ac8c79cb692bbc33bc684e27/tumblr_nbjh9njTIR1tktekzo1_400.png[/IMG] [IMG="magic fluids"]https://38.media.tumblr.com/d8addd93beba7e2a7e3c728f391206dd/tumblr_nbjhaaHmQF1tktekzo1_400.png[/IMG] [IMG="fleya"]https://33.media.tumblr.com/e4de8ab26f5eedac450691057eeeac1b/tumblr_nbjharUztv1tktekzo1_400.png[/IMG]

And the next three images are from 3D fluid simulators (Tall Cell Grid by Chentanez and Müller, vortex particle method by Selle et al., Wavelet Turbulence by Kim et al.):

[IMG="tallcellgrid"]https://38.media.tumblr.com/9a313ee9763de3a2ac69072464c0950a/tumblr_nbjhc0jioz1tktekzo1_400.png[/IMG] [IMG="smoke"]https://38.media.tumblr.com/4ed8d17dacba271763813bf9460e3a4a/tumblr_nbjhc9JzPz1tktekzo1_400.png[/IMG] [IMG="turbulence"]https://33.media.tumblr.com/50de4b4c65544dcef3d449e210dd8331/tumblr_nbjii5Xmcw1tktekzo1_400.png[/IMG]

For further reading I can recommend Nvidia GPU Gems "Fast Fluid Dynamics Simulation on the GPU", "FLUID SIMULATION SIGGRAPH 2007 Course Notes". Those two references cover the approach which I implemented. Those approaches are well enough for computergraphics, but don't provide the accuracy necessary for engineering applications. For "realworld" problems finite volume methods, finite element methods exist. You might have a look at the SIMPLE algorithm.