MS5033 · WORKED EXAMPLE · JULIA + NUMPY

The ink-drop experiment.

An ink drop spreads through molecular random walks.

The physical idea.

Think of the walkers as independent dye molecules released in a localized ink drop. This idealized model illustrates diffusion without fluid flow, convection or molecular interactions. Each molecule takes one independent step in one of four directions: left, right, up or down. The step length is a, measured in micrometers (µm), and the simulation time between steps is Δt = 1 second. After many steps, the predicted mean-square displacement is ⟨r²⟩ = 4Dt, where D = a²/(4Δt) is diffusivity (µm²/s), t is elapsed simulation time (s), and r is displacement from the starting point (µm). These illustrative values are not measured properties of a particular ink.

\[\langle r^2\rangle=4Dt,\qquad D=\frac{a^2}{4\Delta t}\]

This example is based on my teaching code, demo2_many_walkers_diffusion.jl. I wrote the original code to show how random molecular motion leads to diffusion. The version on this page lets you follow the molecules and compare their mean-square displacement with the diffusion equation.

LIVE SIMULATION · RUNS IN YOUR BROWSER

Try the simulation

Choose the number of molecules and the step length, then select Start. Each sweep moves every molecule once. Changing the number, step length or seed starts a new run. Playback speed changes how quickly you watch the simulation; it does not change the physical time between steps.

Elapsed simulation time0 s
Diffusivity D0.2500 µm²/s
Measured ⟨r²⟩0 µm²
Predicted 4Dt0 µm²
0 of 400

Where are the molecules?

The orange line follows the same molecule throughout the run. Darker blue means more molecules per bin. Density shading uses a small spatial smoothing kernel for display; positions and measurements are unchanged. The color scale is fixed across time, with square-root shading and saturation at 1% of molecules per bin.

Does the spreading agree with diffusion?

Solid green: measured ⟨r²⟩Dashed gray: predicted 4DtMean-square displacement is calculated by squaring each molecule's distance from its starting point and averaging over all molecules. Random fluctuations are expected; try increasing the number of molecules.
Try this: reset and double the step length from 1 to 2 µm. D increases from 0.25 to 1 µm²/s. Compare the slope of the measured curve at the same simulation time.

Recorded simulation

The original 100,000-molecule calculation and MP4 are retained here. The saved-state viewer advances in intervals of ten simulation steps; use the live simulation above to see every step and change parameters. The recorded calculation uses one unit of length and one unit of time per step.

Open the saved-state viewer and recorded movie

Precomputed NumPy results from the downloadable code; the browser scrubs saved states. Horizontal axis: x. Vertical axis: y. 100,000 walkers; 256 × 256 histogram bins from −128 to 128; color uses a square-root scale from probability 0 to 0.001 (values above 0.001 saturate).

Download high-resolution ink-drop movie ↓

Download measured diagnostics (CSV) ↗

Model and numerical choices.

This example moves every molecule once per sweep on an unbounded lattice. My original teaching demonstration selects molecules asynchronously in a periodic box. The displayed histogram window is not a boundary. Mean-square displacement uses unwrapped coordinates.

Questions explored in this example.

Use the live controls above to increase the number of molecules and compare fluctuations in mean-square displacement. Then double the step length and compare diffusivity. Download the source below to run larger calculations.

My Python calculation, explained in steps.

Both versions implement the same model. Python uses NumPy. The walker example in Julia uses standard-library packages only. Scripts write CSV snapshots and diagnostics into the output folder. The random-number generators differ, so walker paths differ while their ensemble statistics should agree.

Download the Python notebook ↓ · Read the code in steps → Download Julia version ↓

Run the notebook cells in order for the explained calculation. The commands and complete script below are an optional command-line route; the script is linked at the end of the notebook lesson.

python -m pip install numpy
python walkers.py results
Read the complete NumPy code
"""Random-walk diffusion example based on my teaching code demo2_many_walkers_diffusion.jl.
Purpose: show how random molecular steps produce diffusion.
Run: python walkers.py [output_directory]. Requires NumPy.
Each walker takes one unit cardinal step per sweep on an unbounded 2D lattice.
My original teaching code uses asynchronous moves in a periodic box.
This example moves every molecule once per sweep on an unbounded lattice.
MSD uses unwrapped coordinates; theoretical MSD=steps, D=1/4.
"""
import sys
from pathlib import Path
import numpy as np

def run(output='walkers_output'):
    out=Path(output);out.mkdir(parents=True,exist_ok=True)
    rng=np.random.default_rng(7);n=100000;pos=np.zeros((n,2),dtype=int)
    dirs=np.array([[1,0],[-1,0],[0,1],[0,-1]]);rows=[]
    for step in range(401):
        if step:
            pos+=dirs[rng.integers(0,4,n)]
        if step%10==0:
            msd=np.mean(np.sum(pos*pos,axis=1));rows.append([step,msd,step])
            hist,_,_=np.histogram2d(pos[:,0],pos[:,1],bins=256,range=[[-128,128],[-128,128]])
            np.savetxt(out/f'density_{step:04d}.csv',hist/n,delimiter=',')
    np.savetxt(out/'diagnostics.csv',rows,delimiter=',',header='steps,msd,theory',comments='')
    assert abs(rows[-1][1]/400-1)<.04
    print('Walker MSD at 400 steps',rows[-1][1],'theory 400')
if __name__=='__main__':run(*sys.argv[1:2])

About these calculations.

I use these examples to explain numerical methods. I provide the parameters, boundary conditions and numerical checks with the results. These are teaching calculations, not predictions calibrated for a particular material.

← All worked examples

How I develop my codes.

I start with a small calculation, check its result and then add the next part. These lessons follow the same sequence, with explanations and checks at each stage. Open the worked Python, Julia and C lessons →