Turing pattern using FDM.
Script is based on this webpage: https://blogs.mathworks.com/graphics/2015/03/16/how-the-tiger-got-its-stripes/
[1]:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import animation
from IPython.display import HTML
import time
[2]:
# periodic boundary condition laplacian FD scheme
def my_laplacian(in_M):
out = -4*in_M + (np.roll(in_M,1,axis=1) + np.roll(in_M,-1,axis=1) + np.roll(in_M,1,axis=0) + np.roll(in_M,-1,axis=0))
return out
[3]:
# model parameters
da = 1/4.0 # diffusion A - there is factor four between the matlab script and standard FD Laplace implementation
db = .5/4.0 # diffusion B
f = .055 # feed rate
k = .062 # kill rate
[4]:
# Mesh and initial conditions
nx = 128
A = np.ones((nx,nx))
B = np.zeros((nx,nx))
B[np.ix_(np.arange(50,61),np.arange(50,71))] = 1
B[np.ix_(np.arange(60,81),np.arange(70,81))] = 1
Anew = A.copy()
Bnew = B.copy()
x = np.linspace(0, 127, nx)
y = np.linspace(0, 127, nx)
xv, yv = np.meshgrid(x, y)
[5]:
# time stepping
dt = .25
tottime = 4000
nt = int(tottime/dt)
t = 0
[6]:
# hide
# solver
def turing_solve(A, B):
Anew = A + (da*my_laplacian(A) - A*np.square(B) + f*(1-A))*dt
Bnew = B + (db*my_laplacian(B) + A*np.square(B) - (k+f)*B)*dt
return Anew,Bnew
[7]:
# solver
#def turing_solve(A, B):
# Anew =???
# Bnew = ???
# return Anew,Bnew
[8]:
# based on this solution: https://stackoverflow.com/questions/42386372/increase-the-speed-of-redrawing-contour-plot-in-matplotlib/42398244#42398244
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure(figsize=(10,5))
ax = plt.axes(xlim=(0, nx), ylim=(0, nx))
timeLabel=ax.text(0.02,0.98,'Time: ',transform=ax.transAxes,va='top')
ax.set_xlabel('X')
ax.set_ylabel('Y')
cmap=plt.cm.gist_yarg
p = [ax.contour(xv,yv,B, cmap=cmap ) ]
t = np.ones(nt)*time.time()
skipf = 20
# Animation function which updates figure data. This is called sequentially
def animate(i):
timeLabel._text='Time: %.1f'%((i*skipf)*dt)
# use global keyword to store the latest solution
global Anew, Bnew
for tp in p[0].collections:
tp.remove()
p[0] = ax.contourf(xv,yv,Bnew, cmap= cmap)
t[1:] = t[0:-1]
t[0] = time.time()
# the movie file gets too large if we save every time step, so we always skip 10
for it in range(0,skipf):
Anew,Bnew=turing_solve(Anew, Bnew)
return p[0].collections+[timeLabel]
# Call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate,
frames=int(nt/skipf), interval=30, repeat=False, blit=True)
plt.close(anim._fig)
# Call function to display the animation
#HTML(anim.to_html5_video()) # lower resolution
HTML(anim.to_jshtml()) # higher resolution
[8]: