Lektion 9: Gitter und Diffusion
Baue das Muster „Turing-Muster“ in Python und lerne dabei:
- 2D-Arrays als Gitter aus Zellen
- np.roll für Nachbarn, mit Rändern, die herumlaufen
- der Laplace-Operator: eine Zelle gegen ihre Nachbarn
- ein ganzes Gitter in einer Zeile aktualisieren
- ein Array mit plt.imshow zeigen
Erst ansehen
Läuft nach einem Klick von YouTube.
"""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
Kein Python auf diesem Computer? Das Notebook führt dasselbe Skript, die Übungen und die Lösungen in deinem Browser aus, in Google Colab. Das Notebook ist auf Englisch.
Zeile für Zeile
A, B = np.ones((size, size)), np.zeros((size, size))Zwei Gitter von 128 × 128: überall das Futter A, noch kein B.
B[y : y + 8, x : x + 8] = 1.0Ein Tropfen B: ein Quadrat von 8 × 8 Zellen des Gitters, auf einmal durch Slicing gesetzt.
def laplacian(Z):Wie sehr sich eine Zelle von ihren Nachbarn unterscheidet: positiv, wo die Nachbarn mehr haben, sodass die Diffusion sie auffüllt.
sides = np.roll(Z, 1, 0) + np.roll(Z, -1, 0) + np.roll(Z, 1, 1) + np.roll(Z, -1, 1)np.roll verschiebt das ganze Gitter um eine Zelle nach oben, unten, links oder rechts; die Ränder laufen herum, also hat die Schale keinen Rand.
reaction = A * B * BDie Reaktion, ein A und zwei B ergeben drei B, für jede Zelle auf einmal.
A += DA * laplacian(A) - reaction + f * (1 - A)Die Gray-Scott-Regel für A: Es breitet sich aus, wird verbraucht und wird mit der Rate f wieder in Richtung 1 aufgefüllt.
plt.imshow(B, cmap="magma", vmin=0, vmax=0.5)Das Gitter von B als Bild, ein Pixel pro Zelle.
Probier es selbst
Probier f, k = 0.034, 0.063.
Hinweis
Eine Zeile weit oben.
Lösung
Flecken: runde Stellen aus B, gleichmäßig verteilt, statt der gewundenen Linien der Koralle.
Lass B so schnell wie A diffundieren: DB = 1.0. Was passiert?
Hinweis
DA, DB = 1.0, 1.0.
Lösung
Gar kein Muster: Die Tropfen verblassen zu nichts. Ohne dass sich A schneller ausbreitet als B, hält nichts die Flecken auseinander. Das ist Turings Kernpunkt.
Nimm einen Tropfen in der Mitte statt sechs.
Hinweis
Ersetze die Schleife durch B[60:68, 60:68] = 1.0.
Lösung
Die Koralle wächst von dem einen Tropfen nach außen, mit einer vierzähligen Symmetrie, die den quadratischen Tropfen nachbildet: Ein Keim ergibt ein geordnetes Muster, sechs zufällige Tropfen ein natürlich aussehendes.
Quiz
Lernkarten
Lies die Vorderseite, sag dir die Rückseite vor, dann öffne die Karte.
np.roll(Z, shift, axis)
Verschiebt ein Array entlang einer Achse; was an einem Ende herausfällt, kommt am anderen wieder herein.
Laplace-Operator
Die Nachbarn einer Zelle minus die Zelle selbst: wohin die Diffusion sie bewegen wird.
Gray-Scott
A wird mit f zugeführt, B mit f + k entfernt, und A + 2B → 3B.
Turing-Instabilität
Diffusion zerlegt eine gleichmäßige Mischung in ein Muster, wenn sich ein Stoff schneller ausbreitet.
plt.imshow(grid)
Zeigt ein 2D-Array als Bild, ein Pixel pro Zelle.
Du hast alle neun gebaut. Wenn dir der Kurs geholfen hat, freut sich der Kanal, davon zu hören. Den Kanal unterstützen →