import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import expm, null_space
# Stochastic reaction simulation
# A +B <-> C
# Determine equilibrium via chemical master equation
# Set state vector x: [A; B; C]
Vol = 200
x = np.array([1, 5, 0]) * Vol
nmol = x[0]
# Set the reaction rate vector k
k = np.array([1 / Vol, 3])
extent = np.linspace(1, 0, nmol+1)
# Construct A of the chemical master equation
# dP/dt = A*P
A = np.zeros((nmol+1, nmol+1))
for i in range(nmol+1):
n = i
nu = nmol - n
a = n
b = x[1] - nu
c = nu
A[i, i] = -(k[0] * a * b + k[1] * c)
if i > 0:
A[i, i - 1] = k[1] * (c + 1)
if i < nmol:
A[i, i + 1] = k[0] * (a + 1) * (b + 1)
v = null_space(A)
v = v / np.sum(v)
plt.figure()
plt.plot(v)
# Set initial condition for p
p = np.zeros((nmol+1, 1))
p[-1] = 1 * nmol
deltat = 0.01
tfinal = 1
time = np.arange(0, tfinal + deltat, deltat)
Ad = expm(A * deltat)
p_all = np.zeros((nmol+1, len(time)))
p_all[:, 0] = p.flatten()
for i in range(1, len(time)):
p_all[:, i] = Ad @ p_all[:, i-1]
p_all[:, i] = p_all[:, i] / np.sum(p_all[:, i]) * nmol
# Decide on density of extents for plotting
elines = 50
eskip = int(np.ceil(nmol / elines))
eindex = np.arange(0, nmol+1, eskip)
tlines = 30
tskip = int(np.ceil((len(time) - 1) / tlines))
tstart = 2
tindex = np.arange(tstart, len(time), tskip) - 2
plt.figure()
X, Y = np.meshgrid(time[tindex], extent[eindex])
plt.pcolormesh(X, Y, p_all[eindex, :][:, tindex])
plt.colorbar()
plt.show(block=False)
# Save output for plotting in readable .dat format
with open('prob_dis_large.dat', 'w') as f:
for j in range(len(eindex)):
for i in range(len(tindex)):
output = [time[tindex[i]], extent[eindex[j]], p_all[eindex[j],tindex[i]]]
np.savetxt(f, [output], fmt='%g', newline='\n')
if j < len(eindex) - 1:
f.write('\n')