Avanzado · Patrones de Turing

Lección 9: Cuadrículas y difusión

Construye en Python el patrón «Patrones de Turing» y aprende por el camino:

  • arrays 2D como una cuadrícula de celdas
  • np.roll para los vecinos, con bordes que dan la vuelta
  • el laplaciano: una celda frente a sus vecinas
  • actualizar toda una cuadrícula en una línea
  • mostrar un array con plt.imshow

Míralo primero

Se reproduce desde YouTube tras hacer clic.

turing-patterns.py
"""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 tienes Python en este equipo? El cuaderno ejecuta el mismo script, los ejercicios y las respuestas en tu navegador, en Google Colab. El cuaderno está en inglés.

Línea a línea

  1. A, B = np.ones((size, size)), np.zeros((size, size))

    Dos cuadrículas de 128 × 128: el alimento A en todas partes, todavía nada de B.

  2. B[y : y + 8, x : x + 8] = 1.0

    Una gota de B: un cuadrado de 8 × 8 de la cuadrícula, asignado de una vez mediante slicing.

  3. def laplacian(Z):

    Cuánto se diferencia una celda de sus vecinas: positivo donde las vecinas tienen más, así que la difusión la rellena.

  4. sides = np.roll(Z, 1, 0) + np.roll(Z, -1, 0) + np.roll(Z, 1, 1) + np.roll(Z, -1, 1)

    np.roll desplaza toda la cuadrícula una celda hacia arriba, abajo, la izquierda o la derecha; los bordes dan la vuelta, así que la placa no tiene borde.

  5. reaction = A * B * B

    La reacción, una A y dos B dan tres B, para todas las celdas a la vez.

  6. A += DA * laplacian(A) - reaction + f * (1 - A)

    La regla de Gray-Scott para A: se extiende, se consume y se repone hacia 1 al ritmo f.

  7. plt.imshow(B, cmap="magma", vmin=0, vmax=0.5)

    La cuadrícula de B como imagen, un píxel por celda.

Pruébalo tú

  1. Prueba f, k = 0.034, 0.063.

    Pista

    Una línea cerca del principio.

    Respuesta

    Manchas: zonas redondas de B, separadas por igual, en lugar de las líneas sinuosas del coral.

  2. Haz que B se extienda tan deprisa como A: DB = 1.0. ¿Qué pasa?

    Pista

    DA, DB = 1.0, 1.0.

    Respuesta

    No aparece ningún patrón: las gotas se desvanecen hasta desaparecer. Si A no se extiende más deprisa que B, nada mantiene separadas las manchas. Esa es la idea de Turing.

  3. Usa una sola gota en el centro en lugar de seis.

    Pista

    Sustituye el bucle por B[60:68, 60:68] = 1.0.

    Respuesta

    El coral crece hacia fuera desde la única gota con una simetría cuádruple que copia la gota cuadrada: una sola semilla da un patrón ordenado; seis gotas al azar, uno de aspecto natural.

Cuestionario

1. ¿Qué hace np.roll(Z, 1, 0)?
2. ¿Qué mide el laplaciano de una celda?
3. ¿Por qué no hay ningún bucle sobre las celdas?
4. ¿Qué mostró Turing en 1952?
5. ¿Qué cambia del coral a las manchas?

Tarjetas de repaso

Lee el anverso, di el reverso para ti y luego abre la tarjeta.

  • np.roll(Z, shift, axis)

    Desplaza un array a lo largo de un eje; lo que sale por un extremo vuelve por el otro.

  • Laplaciano

    Las vecinas de una celda menos la propia celda: hacia dónde la moverá la difusión.

  • Gray-Scott

    A se añade a ritmo f, B se elimina a ritmo f + k, y A + 2B → 3B.

  • Inestabilidad de Turing

    La difusión rompe una mezcla uniforme en un patrón cuando una sustancia se extiende más deprisa.

  • plt.imshow(grid)

    Muestra un array 2D como una imagen, un píxel por celda.

Estas tarjetas en su propia página →

Has construido los nueve. Si el curso te ha servido, al canal le encantaría saberlo. Apoya el canal →