Reading Time: 6 minutes

La difusión es una de las ecuaciones diferenciales parciales más intuitivas (PDES) que puede simular: un pico agudo se extiende, un paso empinado se suaviza en una transición suave y los gradientes desaparecen gradualmente. Si está aprendiendo Fipy, la difusión también es uno de los mejores puntos de partida porque se asigna limpiamente al flujo de trabajo principal de Fipy: Mesh → Variable → Ecuación → Time Loop → Visualización.

En esta guía, resolverá la ecuación de difusión en Fipy desde cero, ejecutará una simulación 1D completa que puede modificar de manera segura, aprenderá a interpretar la salida y luego verá cómo la misma configuración se extiende a 2D. El objetivo es la confianza práctica: debe poder cambiar la resolución, el paso de tiempo, la velocidad de difusión y las condiciones de los límites sin romper el modelo.

Qué significa la difusión (sin las matemáticas pesadas)

La difusión describe cómo algo se extiende debido a las diferencias de concentración (o temperatura). El calor se extiende a través de una varilla. Una gota de tinte se extiende en el agua. Matemáticamente, a menudo escribimos difusión de esta forma:

∂φ/∂t = ∇·(D ∇φ)

Aquí φ es el campo que te importa (temperatura, concentración, etc.). El coeficiente D controla la rapidez de la difusión. Más grande D significa que el perfil se suaviza más rápidamente.

Las condiciones de contorno son importantes porque las PDES necesitan reglas en los bordes del dominio. Para una primera ejecución de difusión, los límites de «sin flujo» son comunes: nada sale del dominio. Eso hace que la evolución sea fácil de interpretar porque el sistema no está siendo forzado por los límites.

Cómo Fipy representa la difusión

Fipy resuelve las PDE utilizando el método de volumen finito (FVM). Puede pensar en su dominio como dividido en celdas pequeñas. El campo desconocido vive en esas células (típicamente en los centros celulares). La difusión se implementa como flujo entre celdas vecinas: los valores altos empujan el flujo hacia valores bajos hasta que el perfil se vuelve más suave.

Los prácticos bloques de construcción Fipy son:

  • Mesh — La geometría y la resolución (cuadrícula 1D o 2D)
  • CellVariable — El campo φ que resuelves
  • TransientTerm() — La derivada de tiempo ∂φ/∂t
  • DiffusionTerm(coeff=D) — El operador de difusión
  • Un bucle de tiempo: resolver repetidamente con dt y visualizar instantáneas

Antes de comenzar: Lista de verificación de entorno mínimo

Necesita Python Plus Fipy y una biblioteca de trazado. Si está utilizando cuadernos, el mismo código funciona; Simplemente ejecute celdas en orden.

  • Python instalado (se recomienda una versión moderna)
  • Un entorno virtual (recomendado)
  • Fipy instalado (y sus dependencias numéricas)
  • matplotlib instalado para trazar

Primer ejemplo de trabajo: difusión 1D

Modelaremos la difusión en un dominio 1D de 0 a 1 usando una cuadrícula uniforme. La condición inicial será un paso:
φ = 1 en la mitad izquierda y φ = 0 en la mitad derecha. La difusión suavizará esa discontinuidad con el tiempo.

El siguiente código es un script completo que puede ejecutar tal cual.

# Solving Diffusion Equations with FiPy: 1D Example
# Save as: diffusion_1d_fipy.py

from fipy import Grid1D, CellVariable, TransientTerm, DiffusionTerm
import matplotlib.pyplot as plt

# --- 1) Mesh setup ---
nx = 200
dx = 1.0 / nx
mesh = Grid1D(nx=nx, dx=dx)

# --- 2) Variable (field) ---
phi = CellVariable(name="phi", mesh=mesh, value=0.0)

# Initial condition: step (left half = 1, right half = 0)
x = mesh.cellCenters[0]
phi.setValue(1.0, where=(x < 0.5))

# --- 3) Diffusion equation ---
D = 1.0
eq = TransientTerm() == DiffusionTerm(coeff=D)

# --- 4) Time stepping ---
dt = 1e-4
steps = 2000

snapshots = []
times = []
capture_at = {0, 50, 200, 800, 2000}

for step in range(steps + 1):
    if step in capture_at:
        snapshots.append(phi.value.copy())
        times.append(step * dt)

    eq.solve(var=phi, dt=dt)

# --- 5) Plot ---
plt.figure()
for y, t in zip(snapshots, times):
    plt.plot(x.value, y, label=f"t = {t:.4f}")

plt.xlabel("x")
plt.ylabel("phi")
plt.title("1D Diffusion in FiPy")
plt.legend()
plt.show()

Qué hace cada bloque (para que puedas modificarlo de forma segura)

Mesh: su dominio y resolución

Grid1D(nx=nx, dx=dx) Crea una línea dividida en celdas nx. más pequeño dx (más grande nx) da más detalles pero cuesta más cálculo. La longitud de su dominio es aproximadamente nx * dx.

CellVariable: el campo que resuelves para

phi se almacena en los centros celulares. Comienza con una condición inicial usando setValue(). Con la difusión, esa forma inicial es lo que ves relajarte con el tiempo.

La ecuación: El cambio de tiempo es igual a difusión

Esta línea define el PDE de difusión en la sintaxis de término de Fipy:

TransientTerm() == DiffusionTerm(coeff=D)

D Controla la rapidez con que se suaviza el paso. Si aumentas D, deberías ver que la zona de transición se ensancha más rápido.

El bucle de tiempo: dar un paso adelante

Cada llamada a eq.solve(var=phi, dt=dt) avanza la solución en un solo paso de tiempo. Capturamos algunas instantáneas para que puedas ver la evolución sin trazar cada paso.

Cómo saber si su carrera de difusión se ve correcta

Con una condición inicial de paso, la difusión debe crear una región de transición suave que se ensanche gradualmente. El salto agudo debería suavizarse y la curva debería volverse menos pronunciada con el tiempo.

  • Si el perfil no cambia: es posible que su bucle no se esté ejecutando como se espera, o dt y steps producen muy poco tiempo total.
  • Si el perfil se vuelve ruidoso o «explota»: Reduzca dt, aumente la resolución o simplifique los límites.
  • Si todo parece cambiado o recortado: verifique su condición inicial y confirme que el eje x coincide con su dominio.

Elegir DT y DX: consejos prácticos de estabilidad y precisión

Incluso si el código se ejecuta, las opciones de parámetros afectan la calidad y el tiempo de ejecución. Tres ajustes cubren la mayoría de los problemas del «primer modelo»:

  • Reducir dt Si la evolución parece demasiado nerviosa, ruidosa o inconsistente entre ejecuciones. Una prueba rápida es reducir a la mitad dt y duplicar steps, por lo que el tiempo total simulado permanece similar.
  • Aumentar nx Si la curva parece irregular o la zona de transición está mal resuelta. Más celdas generalmente significa perfiles más suaves y mejores gradientes, a un mayor costo computacional.
  • Trate más grande D como un «sistema más rápido». Si la difusión es fuerte, por lo general necesita dt (o al menos para verificar que los resultados no cambien cuando refina el tiempo).

Un hábito simple que evita la confusión: siempre que cambie dt o nx, vuelva a ejecutar y compare dos ejecuciones (grueso vs refinado). Si las curvas son básicamente las mismas, estás en un buen régimen de aprendizaje e iteración.

Seis experimentos rápidos que te enseñan difusión rápido

  1. Cambie la velocidad de difusión: intente D = 0.1 y D = 5.0 y compare la rapidez con la que se relaja el paso.
  2. Aumente la resolución: cambie nx de 200 a 400 y vea cómo se ve la región de transición.
  3. Pruebe un golpe en lugar de un paso: establezca phi = 1 solo en una región estrecha y observe cómo se extiende simétricamente.
  4. Capture más instantáneas: agregue más índices a capture_at para ver la evolución con más detalles.
  5. Ejecutar más tiempo: Aumente steps y confirme que el perfil se vuelve más uniforme con el tiempo.
  6. Guardar salida: Agregar plt.savefig("diffusion_1d.png", dpi=200) antes de plt.show().

Actualización a difusión 2D (cambio mínimo, gran recompensa)

Una vez que 1D se siente cómodo, moverse a 2D se trata principalmente de cambiar la malla y la visualización. La estructura de la ecuación sigue siendo la misma. En 2D, normalmente comenzarás con un «punto» (valor alto en una región pequeña) y verás cómo se extiende en una mancha suave.

# 2D Diffusion sketch (core ideas)
from fipy import Grid2D, CellVariable, TransientTerm, DiffusionTerm
import matplotlib.pyplot as plt

nx = ny = 100
dx = dy = 1.0 / nx
mesh = Grid2D(nx=nx, ny=ny, dx=dx, dy=dy)

phi = CellVariable(name="phi", mesh=mesh, value=0.0)

x, y = mesh.cellCenters
phi.setValue(1.0, where=((x - 0.5)**2 + (y - 0.5)**2 < 0.05**2))

D = 1.0
eq = TransientTerm() == DiffusionTerm(coeff=D)

dt = 1e-4
for _ in range(500):
    eq.solve(var=phi, dt=dt)

# Visualize as an image
plt.figure()
plt.imshow(phi.value.reshape((ny, nx)), origin="lower")
plt.colorbar(label="phi")
plt.title("2D Diffusion in FiPy")
plt.show()

Dos notas prácticas para 2D: primero, puede ser significativamente más lento que 1D porque el número de células crece como nx * ny. En segundo lugar, los gráficos de imágenes dependen de la remodelación; Mantenga su (ny, nx) consistente.

Solución de problemas: problemas comunes por primera vez

Errores de importación o paquetes faltantes

  • Confirme que Fipy está instalado en el mismo entorno donde ejecuta el script.
  • En cuadernos, verifique que el kernel apunte al intérprete correcto.
  • Compruebe que matplotlib importa limpiamente.

La curva no cambia

  • Aumente el tiempo total simulado: eleve steps o dt ligeramente (con cuidado).
  • Asegúrese de que las instantáneas incluyan pasos posteriores, no solo el comienzo.
  • Confirme que en realidad está llamando a eq.solve() dentro del bucle.

La solución parece inestable o ruidosa

  • Reduzca dt (por ejemplo, de 1e-4 a 5e-5).
  • Aumente la resolución (nx) para resolver mejor los gradientes.
  • Pruebe un D más pequeño para reducir la velocidad de evolución mientras aprende.

es demasiado lento

  • Comience con menos celdas, luego aumente gradualmente una vez que el flujo de trabajo esté claro.
  • Capture menos instantáneas y trace con menos frecuencia.
  • En 2D, reduzca nx y ny mientras experimenta con la configuración.

Conclusión: el patrón de difusión que reutilizarás en todas partes

Resolver la difusión en Fipy enseña una estructura repetible que usará para muchos modelos PDE. Una vez que te sientas cómodo con cómo conectar Grid1D/Grid2D, CellVariable, TransientTerm y DiffusionTerm, puedes extender el mismo flujo de trabajo a convección-difusión, reacción-difusión, fuentes y sumideros, parámetro barridos y comprobaciones de validación.

Si desea el ciclo de aprendizaje más rápido, realice un cambio a la vez:D, nx, dt o la condición inicial: vuelva a ejecutar y explique qué cambió y por qué. Ese hábito es lo que convierte a la difusión de una demostración en una herramienta en la que puedes confiar.