-
Notifications
You must be signed in to change notification settings - Fork 20
/
gray_scott_static.py
115 lines (86 loc) · 2.86 KB
/
gray_scott_static.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# import necessary libraries
import numpy as np
import matplotlib.pyplot as pl
# ============ define relevant functions =============
# an efficient function to compute a mean over neighboring cells
def apply_laplacian(mat):
"""This function applies a discretized Laplacian
in periodic boundary conditions to a matrix
For more information see
https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Implementation_via_operator_discretization
"""
# the cell appears 4 times in the formula to compute
# the total difference
neigh_mat = -4*mat.copy()
# Each direct neighbor on the lattice is counted in
# the discrete difference formula
neighbors = [
( 1.0, (-1, 0) ),
( 1.0, ( 0,-1) ),
( 1.0, ( 0, 1) ),
( 1.0, ( 1, 0) ),
]
# shift matrix according to demanded neighbors
# and add to this cell with corresponding weight
for weight, neigh in neighbors:
neigh_mat += weight * np.roll(mat, neigh, (0,1))
return neigh_mat
# Define the update formula for chemicals A and B
def update(A, B, DA, DB, f, k, delta_t):
"""Apply the Gray-Scott update formula"""
# compute the diffusion part of the update
diff_A = DA * apply_laplacian(A)
diff_B = DB * apply_laplacian(B)
# Apply chemical reaction
reaction = A*B**2
diff_A -= reaction
diff_B += reaction
# Apply birth/death
diff_A += f * (1-A)
diff_B -= (k+f) * B
A += diff_A * delta_t
B += diff_B * delta_t
return A, B
def get_initial_A_and_B(N, random_influence = 0.2):
"""get the initial chemical concentrations"""
# get initial homogeneous concentrations
A = (1-random_influence) * np.ones((N,N))
B = np.zeros((N,N))
# put some noise on there
A += random_influence * np.random.random((N,N))
B += random_influence * np.random.random((N,N))
# get center and radius for initial disturbance
N2, r = N//2, 50
# apply initial disturbance
A[N2-r:N2+r, N2-r:N2+r] = 0.50
B[N2-r:N2+r, N2-r:N2+r] = 0.25
return A, B
def draw(A, B):
"""return the matplotlib artists for animation"""
fig, ax = pl.subplots(1,2,figsize=(5.65,3))
imA = ax[0].imshow(A, animated=True,vmin=0,cmap='Greys')
imB = ax[1].imshow(B, animated=True,vmax=1,cmap='Greys')
ax[0].axis('off')
ax[1].axis('off')
ax[0].set_title('A')
ax[1].set_title('B')
return fig, imA, imB
# =========== define model parameters ==========
# update in time
delta_t = 1.0
# Diffusion coefficients
DA = 0.16
DB = 0.08
# define birth/death rates
f = 0.060
k = 0.062
# grid size
N = 200
# intialize the chemical concentrations
A, B = get_initial_A_and_B(N)
N_simulation_steps = 10000
for step in range(N_simulation_steps):
A, B = update(A, B, DA, DB, f, k, delta_t)
draw(A, B)
# show the result
pl.show()