Lesson 9: Grids and diffusion
Build the turing patterns in Python, and learn on the way:
- 2-D arrays as a grid of cells
- np.roll for neighbours, with edges that wrap around
- the Laplacian: a cell against its neighbours
- updating a whole grid in one line
- showing an array with plt.imshow
Watch it first
Plays from YouTube after a click.
The script
Open in Colab: this lesson as a notebook"""Turing patterns: the Gray-Scott reaction-diffusion rule on a 128 x 128 grid.
Run: python turing-patterns.py (needs: pip install numpy matplotlib; takes a few seconds)
"""
import numpy as np
import matplotlib.pyplot as plt
plt.style.use("dark_background")
size, steps = 128, 6000
f, k = 0.0545, 0.062 # feed and kill rates: coral
DA, DB = 1.0, 0.5 # A spreads twice as fast as B
A, B = np.ones((size, size)), np.zeros((size, size))
rng = np.random.default_rng()
for y, x in rng.integers(10, size - 18, (6, 2)):
B[y : y + 8, x : x + 8] = 1.0 # six drops of B
def laplacian(Z):
"""Each cell against its neighbours: 0.2 for the four sides, 0.05 for the corners (Karl Sims)"""
sides = np.roll(Z, 1, 0) + np.roll(Z, -1, 0) + np.roll(Z, 1, 1) + np.roll(Z, -1, 1)
corners = (np.roll(np.roll(Z, 1, 0), 1, 1) + np.roll(np.roll(Z, 1, 0), -1, 1)
+ np.roll(np.roll(Z, -1, 0), 1, 1) + np.roll(np.roll(Z, -1, 0), -1, 1))
return 0.2 * sides + 0.05 * corners - Z
for _ in range(steps):
reaction = A * B * B # one A and two B make three B
A += DA * laplacian(A) - reaction + f * (1 - A)
B += DB * laplacian(B) + reaction - (f + k) * B
plt.figure(figsize=(6, 6))
plt.imshow(B, cmap="magma", vmin=0, vmax=0.5)
plt.axis("off")
plt.show()
# Try: f, k = 0.039, 0.058 (a cell net) or 0.034, 0.063 (spots) -> the same rule, another pattern
No Python on this computer? The notebook runs the same script, the exercises and the answers in your browser, on Google Colab.
Line by line
A, B = np.ones((size, size)), np.zeros((size, size))Two 128 × 128 grids: the food A everywhere, no B yet.
B[y : y + 8, x : x + 8] = 1.0A drop of B: an 8 × 8 square of the grid, set at once by slicing.
def laplacian(Z):How much a cell differs from its neighbours: positive where the neighbours have more, so diffusion fills it up.
sides = np.roll(Z, 1, 0) + np.roll(Z, -1, 0) + np.roll(Z, 1, 1) + np.roll(Z, -1, 1)np.roll shifts the whole grid by one cell up, down, left or right; the edges wrap around, so the dish has no border.
reaction = A * B * BThe reaction, one A and two B make three B, for every cell at once.
A += DA * laplacian(A) - reaction + f * (1 - A)The Gray–Scott rule for A: it spreads, is eaten, and is fed back towards 1 at the rate f.
plt.imshow(B, cmap="magma", vmin=0, vmax=0.5)The grid of B as a picture, one pixel per cell.
Try it yourself
Try f, k = 0.034, 0.063.
Hint
One line near the top.
Answer
Spots: round patches of B, evenly spaced, instead of the coral’s winding lines.
Make B spread as fast as A: DB = 1.0. What happens?
Hint
DA, DB = 1.0, 1.0.
Answer
No pattern at all: the drops fade away to nothing. Without A spreading faster than B, nothing holds the patches apart. This is Turing’s point.
Use one drop in the middle instead of six.
Hint
Replace the loop with B[60:68, 60:68] = 1.0.
Answer
The coral grows outwards from the one drop with a fourfold symmetry that copies the square drop: one seed gives an ordered pattern, six random drops a natural-looking one.
Quiz
Flashcards
Read the front, say the back to yourself, then open the card.
np.roll(Z, shift, axis)
Shifts an array along an axis; what falls off one end comes back at the other.
Laplacian
A cell’s neighbours minus the cell itself: where diffusion will move it.
Gray–Scott
A is fed in at f, B is removed at f + k, and A + 2B → 3B.
Turing instability
Diffusion breaks an even mixture into a pattern when one substance spreads faster.
plt.imshow(grid)
Shows a 2-D array as a picture, one pixel per cell.
You built all nine. If the course helped, the channel would love to hear it. Support the channel →