package finitedifference;

import java.io.*;

/**
*
* @author BotRejectsInc@cronodon.com
*/

public class Diffusion
{
private double dt;
private double dx;
private double t;
private double x;
private PrintWriter pw;
private final int ROWS = 19;
private final int COLS = 19;

private double[][] matrix = new double[ROWS][COLS];

/** Creates a new instance of Diffusion */
public Diffusion()
{
dt = 0.1;
dx = 0.1;
t = 0;
x = 0;
}

public Diffusion(double t, double x)
{
dt = t;
dx = x;
t = 0;
x = 0;
}

/** computes results and populates results matrix */
public void iterate()
{
//Calculate stability criterion - s should be <= 0.5
double s = dt/(dx*dx);
System.out.println(s);

//matrix indices = nj, rows n, columns j
//Initial conditions (row 0)
matrix[0] = new double[] { 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0 };

//Compute solution matrix from row 1 onwards
for(int n = 1; n <= ROWS-1; n++) // n+1
{
   for(int j = 1; j <= COLS-2; j++)                                             
   {
       //matrix[n][j] = matrix[n-1][j+1] - matrix[n-1][j] + matrix[n-1][j-1];
       matrix[n][j] = s*(matrix[n-1][j+1] + matrix[n-1][j-1]) + (1-2*s)*matrix[n-1][j];
   }
}
displayData();
}

/** Outputs results to screen and text file
public void displayData()
{
//Prepare file for output
try
{
   pw = new PrintWriter("Output.txt");
}
catch(IOException e)
{
   System.out.println("Unable to open file for output: " + e.getMessage());
}

//Output data
for(int rows = 0; rows <= ROWS-1; rows++) // n
{
   System.out.println("n = " + rows + " : ");
   
   for(int col = 0; col <= COLS-1; col++) // j
   {
       System.out.print("  " + matrix[rows][col]);
       pw.print(matrix[rows][col] + ", ");
   }
   System.out.println("");
   pw.println("");
}
pw.close();
}

}
Transport Processes - Diffusion
Molecules are in constant motion. Molecules in solids vibrate back-and-forth as if attached to one another by springs,
whilst molecules in fluids (gases and liquids) are more-or-less free to move in any direction. This motion is due to thermal
energy - the hotter a substance is the faster its molecules move about. Attractive forces (the springs) between molecules
may restrict this motion, as in solids, until the molecules vibrate hard enough to break free and the solid melts into a
liquid or sublimes into a gas. In a gas the attractive forces between molecules are weak and transient and can usually be
ignored. The animated gif above was generated using a Java program to produce the animation. The molecules,
modeled as balls, are given random initial velocities (speeds and direction of motion) and bounce elastically off the walls
of their containing square. (In reality the molecules will also collide off one another and these collisions may change the
speed of the colliding molecules).

Diffusion is a fundamental physical process and one of the most important in chemical and biological systems. To
demonstrate diffusion, add a drop or two of food dye to a clear beaker of water (a spatula of purple potassium
permanganate crystals works quite well) and leave to stand and observe as the dye slowly disperses to colour the
beaker with an even hue - the molecules of dye have spread-out to fill the beaker. In effect the dye molecules have
moved from a region of high dye concentration (the region of the initial drop) to a region of low dye concentration (the
rest of the water in the beaker) until the concentration is even throughout. Molecules in solution diffuse, as do molecules
of gas - open a bottle of perfume in one corner of a room and the odour will slowly diffuse out to fill the room. Of course
advection, or bulk fluid movements such as wind and convection (movement of packets of warm fluid into cooler fluid)
currents, will help to mix the molecules, but diffusion will still take place in a sealed room with perfectly still air (in a
uniform temperature). As can be seen in the above animation, thermal motion of molecules results in diffusion - see how
the molecules spread out to fill the container from their initial cluster.

Advection and diffusion are the two fundamental fluid transport processes and organisms rely on both these processes.
your lungs pump air in and out, moving oxygen in by advection and venting off carbon dioxide produced by your cells as
they respire the oxygen. Obtaining oxygen is one of the most important fluid movements as far as many organisms are
concerned! In aerobic
respiration, oxygen 'burns' fuel, in the form of organic molecules like sugars, fats and amino acids,
inside cells to release energy as both heat and potential work. Carbon dioxide and water are byproducts of this process.
Advection requires external energy, such as is supplied by breathing movements, but it can be very rapid for moving
large amounts of fluid over large distances. However, diffusion takes over when the oxygen in your lungs diffuses across
the respiratory membrane - that is across the thin membranous lining of the air-sacs (alveoli) in your lungs and across
the thin walls of the capillaries (fine blood vessels) and across the cell membrane of red blood cells waiting in the
capillaries to take up oxygen which binds to the red pigment haemoglobin (an iron-containing pigment that gives
mammalian blood its red colour when oxygenated). (See section on
membranes for diffusion across membranes).
Advection then resumes prime importance as your heart pumps the blood and the oxygen it carries around your body.
What we see here is that whenever fluid has to be moved over very short distances then diffusion is the dominant
transport mechanism, whereas advection dominates over long distances. Why is this? What follows is a mathematical
analysis of diffusion, which can give us a better understanding of this vital process.
First of all, consider diffusion in one spatial dimension only, for simplicity, say along the x-axis (i.e. left and right).
Consider the concentration of molecules of some substance diffusing from a central position. The distribution of these
molecules is shown by the black curve in the plot below, for time t = 0, our starting point. Notice that as time passes, the
molecules become less concentrated at their original position and move out to the left and right of their initial position -
the curve or concentration distribution becomes progressively wider and flatter (eventually it would become a flat
horizontal line at some final concentration).
Following is an explanation of how these graphs were produced, which is only a brief outline and so requires certain
prior mathematical and computer programming knowledge, so those who do not wish to read these details may skip this
section and go straight to the 'Biological implications" at the bottom of the page!). Diffusion can be modeled very well
by the
diffusion equation. This equation is a partial differential equation (first-order in time derivative, second-order
in each spatial derivative) and one of the simplest PDEs to deal with. Solutions to this equation give us the distributions
plotted above. The method I have used to solve this equation is a
numerical method (that is a method that uses a
computer to calculate an approximate solution) called the
finite difference method. This method takes the continuous
derivatives and splits them into a number of points, or rather it calculates them at a certain number of points a certain
space apart, in this instance points given by the integer array j = { 0,1,2,3, ... } each separated from its neighbours by a
distance delta x. In two or three spatial dimensions we would have a grid of such points. There are then three principle
ways to approximate the derivative, or gradient of concentration in this case, by comparing neighbouring values (at the
previous time point). The backward difference calculates the value at each point j using the value at the preceding
point j-1. The forward difference calculates the value at point j+1 using the value at the proceeding point j. The central
difference method looks at values on both sides of the point j, before it at point j-1 and after it at point j-1. Now, clearly
we need some initial points to get us started. What we need is to specify the distribution of molecules at an arbitrary
starting time-point (t = 0). It is like conducting an experiment - we start off by releasing a certain number of the
molecules in a certain position and then the computer calculates their distribution at later time points. We can calculate
the distribution at a series of time-points given by integer array n = { 0,1,2,3, ... } where we supply the information for n
= 0 (t = 0). Thus we specify an initial value for n = 0 at each point j and then calculate the values at each later
time-point (n = 1,2,3, ...) for each j, using the values from the earlier time point, so we use the n = 0 values to calculate
each j at n = 1, and then the n = 1 values are used to find each j at n = 2, and so on, until we end-up with a matrix of
values.
Thus, we obtain results by a process of iteration - given the values at time n = 0 we calculate those at n = 1 (a time
delta t later) and then repeat the process using the values at n = 1 to calculate the values at n = 2 and so on. Clearly,
such a scheme is open to potential problems. The whole process is an approximation and supposing the results we
obtain for n = 1 contain errors that get larger when we calculate n = 2, and so on - the solution may blow-up out of
control and bear no resemblance to the true solution! This can happen, for example, if we set our points in space, j, or
our points in time, n, too far apart. Fortunately there are ways of checking for this and it can be calculated for which
values of delta x and delta t the solution goes wrong (diverges) and those for which it goes right (converges to the true
solution). This is represented by the stability condition, s, given below.
Now we have set-up the problem we can code a solution and let the computer do the rest of the work! Below
is a solution to this problem which I wrote in Java:
package finitedifference;

/**
*
* @author BotRejectsInc@cronodon.com
*/

public class Main
{

/** Creates a new instance of Main */
public Main()
{

}

/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
Diffusion dif1 = new Diffusion(0.00001,0.01);
dif1.iterate();
}

}
First of all, the above class sets up the variables and constants (fields) that we need and provides the
constructors needed to create a 'Diffusion' solution object. The first constructor assumes default values of
delta t (dt) and delta x (dx) - but be careful! These values might not satisfy the stability condition! Hence the
second constructor allows us to specify dt and dx and so is far more useful. In the function iterate() a matrix
is set-up, containing the initial conditions and from this the results are calculated and inserted into the matrix.
The function displayData() outputs the results to the screen and saves them in a text file.

The Main class that drives the process is given below:
The results obtained have been imported and plotted in MS Excel to produce the graphs shown at the top of
the page.

The code for the Java animation at the top of the page is given below.
Diffusion animated gif
package diffusionanimation;

import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.imageio.*;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.*;
import java.io.*;

/**
*
* @author BotRejectsInc@cronodon.com
*/
public class DrawingApp extends JFrame
{
private final int FRAME_WIDTH = 500;
private final int FRAME_HEIGHT = 500;
private DrawingPanel drawingPanel;

private int frameCount = 0;

private boolean pauseAnim = false;

/** Creates a new instance of DrawingApp */
public DrawingApp()
{
}
public DrawingApp(String title)
{
super(title);
setSize(FRAME_WIDTH,FRAME_HEIGHT);
this.setResizable(false);
setLayout(new BorderLayout());

drawingPanel = new DrawingPanel();
add(drawingPanel);

//exiting on close
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

//event handlers
addKeyListener(new KeyHandler());
}

public void update()
{
while(!pauseAnim)
{
  //System.out.println("pauseAnim is :" + pauseAnim);
  drawingPanel.updatePictureState();
  repaint();
  try
  {
      Thread.sleep(50);
  }
  catch (InterruptedException e)
  {
      System.exit(0);
  }
}
//this involves updating the content of the drawingPanel
// by calling the panel's updatePictureState method

}

private class DrawingPanel extends JPanel // provided
{
private Picture myPicture;
// add further instance variables if required

public DrawingPanel() // given
{
  myPicture = new Picture(FRAME_WIDTH, FRAME_HEIGHT);
}

//this method is invoked automatically when repaint occurs in
//the outer container
public void paintComponent(Graphics g) // given
{
  super.paintComponent(g);
  myPicture.draw(g); //This does the redrawing based on current state
}

//Updates scene elements but does not redraw
public void updatePictureState()
{
  //System.out.println("DrawingApp.updatePictureState");
  //Change rest of picture
  myPicture.updatePictureState(500, 500);
  
  //Pause thread to allow drawing
  try
  {
      Thread.sleep(50);
  }
  catch (InterruptedException e)
  {
      System.exit(0);
  }
  //repaint();
  
  frameCount++;
  int interval = 10;
  if(frameCount % interval == 0) //Draws every 10th frame to file
  {
      //Save frame
      try
      {
          String fileName = new String("Screenshot" + frameCount + ".PNG");
          BufferedImage capture = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
          Graphics2D graphics2D = capture.createGraphics();
          myPicture.draw(graphics2D);
          ImageIO.write(capture, "PNG", new File(fileName));
          System.out.println("Image saved");
      }
      catch(IOException e)
      {
          System.out.println("Error saving image: " + e.getMessage());
      }
  }
  repaint();
}
}

private int getAvailableWidth()
{
return getWidth() - getInsets().left - getInsets().right;
}
private int getAvailableHeight()
{
return getHeight() - getInsets().top - getInsets().bottom;
}

private class KeyHandler extends KeyAdapter
{
@Override
      public void keyPressed(KeyEvent k)
{
  if(k.getKeyCode() == KeyEvent.VK_SPACE)
  {
      if(!pauseAnim)
      {
          //Pause animation
          pauseAnim = true;
      }
      if(pauseAnim)
      {
          //Unpause animation
          pauseAnim = false;
      }
  }
}
}
}
package diffusionanimation;

import javax.imageio.*;
import java.awt.*;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import java.awt.image.*;
import java.io.*;

/**
*
* @author BotRejectsInc@cronodon.com
*/
public class Picture
{
Random generator = new Random();
private int numBalls = 50;
private int ballDiam = 10;
private ArrayList<Particle> particles;
private int frameCount = 0;

/** Creates a new instance of Picture */
public Picture()
{
}
public  Picture  (int  frameWidth,  int  frameHeight)
{
particles  = new ArrayList<Particle>();
createBalls();
}

public void createBalls()
{
for (int i = 0; i < numBalls; i++)
{
   int randX = generator.nextInt(100) + 100;
   int randY = generator.nextInt(100) + 100;
   int randVx = generator.nextInt(10) - 5;
   int randVy = generator.nextInt(10) - 5;
   Particle aParticle = new Particle(randX, randY, randVx, randVy);
   particles.add(aParticle);
}
}

public void updatePictureState(int width, int height)
{
//System.out.println("Picture.updatePictureState");
moveBalls();
}

public void moveBalls()
{
//frameCount++;
//System.out.println("Picture.moveBalls()");
for(Particle p : particles)
{
   int initialX = p.getPosX();
   int initialY = p.getPosY();
   p.setPosX(initialX + p.getVelX());
   p.setPosY(initialY + p.getVelY());
}
collisionDetection();
}
public void collisionDetection()
{
for(Particle p : particles)
{
   int initialXPos = p.getPosX();
   if(initialXPos <= 15 + ballDiam || initialXPos >= 466 - ballDiam)
   {
       //Collision with vertical wall
       p.setVelX(-p.getVelX());
   }
   int initialYPos = p.getPosY();
   if(initialYPos <= 15 + ballDiam || initialYPos >= 414 - ballDiam)
   {
       //Collision with horizontal wall
       p.setVelY(-p.getVelY());
   }
}
}

public void draw(Graphics  g)
{
//System.out.println("Picture.draw()");
Color ballColour = Color.green;
Color backColour = Color.white;
Color boxColour = Color.black;

//Draw background box
g.setColor(backColour);
g.fillRect(0,0,500,500);

g.setColor(boxColour);
g.fillRect(20,20, 450,400);
       
//Draw particles
g.setColor(ballColour);
for(Particle p : particles)
{
   g.fillOval( p.getPosX(),  p.getPosY(),  ballDiam, ballDiam );
}
}

}
package diffusionanimation;

/**
*
* @author BotRejectsInc@cronodon.com
*/
public class Particle
{
private int X;
private int Y;
private int VelX;
private int VelY;

/** Creates a new instance of Particle */
public Particle()
{
X = 50;
Y = 50;
VelX = 0;
VelY = 0;
}
public Particle(int x, int Y)
{
this.X = X;
this.Y = Y;
VelX = 10;
VelY = 10;
}
public Particle(int X, int Y, int VelX, int VelY)
{
this.X = X;
this.Y = Y;
this.VelX = VelX;
this.VelY = VelY;
}

//Getters
public int getPosX()
{
return this.X;
}
public int getPosY()
{
return this.Y;
}
public int getVelX()
{
return this.VelX;
}
public int getVelY()
{
return this.VelY;
}

//Setters
public void setPosX(int X)
{
this.X  =  X;
}
public void setPosY(int Y)
{
this.Y = Y;
}
public void setVelX(int VelX)
{
this.VelX = VelX;
}
public void setVelY(int VelY)
{
this.VelY = VelY;
}

}
package diffusionanimation;

/**
*
* @author BotRejectsInc@cronodon.com
*/
public class Main
{

/** Creates a new instance of Main */
public Main()
{
}

/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
DrawingApp myDrawingApp = new DrawingApp("Diffusion animation");
myDrawingApp.setVisible(true);

myDrawingApp.update();
}

}
Random walks
The Main class drives the program by creating an instance of the DrawingApp class and calling its
update() method which sets up the application and creates a drawing panel which inserts the animation
generated by an instance of the Picture class (via the Picture.updatePictureState() method) and then
returns to DrawingApp which repaints the animation frame and then calls back to the Picture instance to
retrieve the next frame, and so on. The updatePictureState method of DrawingApp periodically saves a
frame to disc and the frequency with which it does this can be altered by changing the interval number
(each save does cause the animation to pause for a fraction of a second as it isn't run on a separate
thread).
The Stochastic Nature of Diffusion

Diffusion is a stochastic or probabilistic process. Each particle moves at random, but collectively the
particles can exhibit definite behaviour. The diagram below gives four examples of computer-generated
random walks (generated using a C# Winform application). Left to its own devices, in a vacuum, a
particle that is moving will continue to do so in a straight line at constant velocity. In the animation above
the particle velocity changes when the particles bounce off the walls of their container (the direction but
not the speed changes in this simulation). In reality, particles may also collide with one-another (and I aim
to modify the simulation to incorporate this in the near future). This causes particles to change their
speed and direction of motion. (Collisions with the walls of the container can also change particle speed).
In effect a particle undergoes what is called a
random walk. The particle moves in a short straight step
until it collides with another particle and then changes direction. In the simulation below each particle is
confines in a circular arena (100 units radius) and moves with a speed of 2 units each time before the
computer computes whether or not a collision has occurred (using a collision probability of 0.4 per 2 units
moved in this example) and then the particle sets off in a random direction. Each simulation computed
100 such steps with the particle starting in the small central circle each time and then plotting the paths
to produce the plots shown below:
Notice that if the particle moved in a straight line then it would reach the edge of the arena in 50 moves,
but in 100 moves the particles often don't get that far as they often double back on themselves, as in the
particle on the bottom left.

So, how far would it take a particle to diffuse say 1 cm or 1 m, on average?

The time taken for the concentration of a substance (the height of the spike in the graph at the top of the
page) originally in a concentrated spike to reach 1/e (or to about 37% of its original height) at a distance,
d, from the starting position is given by the equation:

                                        t = d^2 / 4D, where D is the diffusion coefficient.

The diffusion coefficient reflects how fast a given particle type diffuses and depends on such things as
the particle's mass - heavier particles require more thermal energy to reach a given speed and so diffuse
more slowly. D also depends on temperature - the hotter it is, the more thermal kinetic energy the
particles have - the faster they move around and the faster they diffuse. Values for D can be obtained
from tables. For example, in water at 25C, D for molecules of carbon dioxide equals 1.7E-09, whilst for
carbon dioxide in air at 20C D = 1.51E-05. Diffusion is much more rapid in gases than in aqueous
solutions.

Considering aqueous solutions and taking a 'typical' value of D = 1E-09, the characteristic times to
diffuse a given distance is as follows:

  •        0.25 ms to diffuse 1 micrometre (the width of a typical bacterial cell)
  •        25 ms to diffuse 10 micrometres (the diameter of a typical animal cell)
  •        0.6 s to diffuse 50 micrometres (the diameter of a typical plant cell)
  •        4 minutes to diffuse 1 mm
  •        7 hours to diffuse 1 cm
  •        8 years to diffuse 1 m !!

In air diffusion is much faster, e.g. with D = 1E-05, it takes 2.5 s to diffuse 1 cm.

Biological Implications

We have seen that diffusion is extremely rapid over very short distances, but becomes ridiculously slow
over large distances. Diffusion is also more rapid in air than in water. What are the implications of these
facts on living things?

Bacteria
. Bacterial cells are tiny and so they are easily able to absorb nutrients and oxygen from their
surroundings by diffusion. They require no special machinery to circulate their cytoplasm by advection
and can achieve the highest growth rates f any known organism on Earth. Bacterial cells can be quite
long, but they are almost always about 1 micrometre or less in diameter, so that nutrients never have far
to diffuse. Some bacteria can double their numbers every ten minutes in optimum conditions and if they
had limitless food then their population would weigh more than the Earth after a day or two!

Plants. Plant cells are generally large and so diffusion alone would be insufficient to supply their needs.
Nutrients enter the cells by diffusion but are then transported rapidly, by advection, throughout the cell by
rapid cytoplasmic streaming (brought about by the cytoskeleton). Plant tissues, such as leaves, need
gases, such as carbon dioxide for photosynthesis, and the plant body contains microscopic air channels
that connect to the outside via minute pores (stomata and lenticels). Since diffusion is more rapid in air
than in water this gaseous system provides sufficient gases for the needs of the plant cells.

Animals. Animals are very active and so need to deliver nutrients and oxygen to their cells rapidly. In land-
dwelling vertebrates, like humans, diffusion carries oxygen across the lungs and into the blood stream,
but energetic advection is used to ventilate the lungs and the heart pumps blood around the body
(advection). Diffusion again carries nutrients across cell membranes, thus diffusion is only used to
transport materials over very short distances, advection is the necessary long-distance transport system.
Arthropods, like insects, tend to rely more heavily on diffusion. In
insects, a series of tubes (tracheae and
tracheoles) carry oxygen from the outside air deep into the tissues. This limits the size of insects and
most are 1-2 cm or less in diameter. Larger and more active insects will also use active pumping (such as
the throbbing abdomen in a wasp) to move air through the tracheae more rapidly by advection. At times
in the Earth's history, the atmosphere has contained more oxygen (as much as 35% compared with 21%
today) and this made it easier for arthropods (then the dominant animals on land) to obtain oxygen by
diffusion and this is likely one reason why these ancient arthropods reached much larger proportions
(dragonflies with wingspans of 1 m and millipedes larger than a man!).

Other life-forms. Plasmodial slime moulds are among the largest motile cells found on land, reaching up
to 1 m in length. Being single-celled organisms they rely on diffusion across their cell membrane to obtain
oxygen. Cytoplasm is actively moved around the cell, sometimes in a pulsating fashion, which must help
move oxygen and nutrients around inside the cell, but these cells remain flat when actively moving, being
at most some 3 mm in thickness, so that gases do not have far to diffuse. they are also slow-moving and
not very active and so require less oxygen than more active organisms.
Comment on this article!