In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy
from ecell4 import *
from ecell4_base.core import *
from ecell4_base import *
Making a model for all. A single species A
is defined. The radius is 5 nm, and the diffusion coefficient is 1um^2/s:
In [2]:
radius, D = 0.005, 1
m = NetworkModel()
m.add_species_attribute(Species("A", radius, D))
Create a random number generator, which is used through whole simulations below:
In [3]:
rng = GSLRandomNumberGenerator()
rng.seed(0)
In [4]:
def singlerun1(f, duration):
w = f.world(ones())
w.bind_to(m)
w.add_molecules(Species("A"), 60)
obs1 = FixedIntervalTrajectoryObserver(0.01)
sim = f.simulator(w)
sim.run(duration, obs1)
distances = []
for data in obs1.data():
distances.extend(tuple(data[-1] - data[0]))
return distances
def plot_displacements(N, f, duration):
distances = []
for _ in range(N):
distances.extend(singlerun1(f, duration))
_, bins, _ = plt.hist(distances, bins=30, normed=True, facecolor='green', alpha=0.5, label='Simulation')
xmax = max(abs(bins[0]), abs(bins[-1]))
x = numpy.linspace(-xmax, +xmax, 101)
gauss = lambda x, sigmasq: numpy.exp(-0.5 * x * x / sigmasq) / numpy.sqrt(2 * numpy.pi * sigmasq)
plt.plot(x, gauss(x, sum(numpy.array(distances) ** 2) / len(distances)), 'k--', label='Fitting')
plt.plot(x, gauss(x, 2 * D * duration), 'r-', label='Expected')
plt.xlim(x[0], x[-1])
plt.ylim(0, 1)
plt.xlabel('Displacement')
plt.ylabel('Frequenecy')
plt.legend(loc='best', shadow=True)
plt.show()
return distances
Simulating with egfrd
:
In [5]:
distances1 = plot_displacements(50, egfrd.Factory(Integer3(4, 4, 4)).rng(rng), 0.1)
Simulating with spatiocyte
:
In [6]:
distances2 = plot_displacements(50, spatiocyte.Factory(radius).rng(rng), 0.1)
In [7]:
def test_mean_square_displacement(N, func, *args):
t, mean = func(*args)
for _ in range(N - 1):
mean += func(*args)[1]
mean /= N
return t, mean
In [8]:
def singlerun2(f, duration):
w = f.world(ones())
w.bind_to(m)
w.add_molecules(Species("A"), 60)
obs1 = FixedIntervalTrajectoryObserver(0.01)
sim = f.simulator(w)
sim.run(duration, obs1)
t = numpy.array(obs1.t())
mean = sum(numpy.array([length_sq(pos - data[0]) for pos in data])
for data in obs1.data()) / obs1.num_tracers()
return t, mean
Simulating with egfrd
:
In [9]:
t, mean1 = test_mean_square_displacement(15, singlerun2, egfrd.Factory(Integer3(4, 4, 4)).rng(rng), 3)
Simulating with spatiocyte
:
In [10]:
t, mean2 = test_mean_square_displacement(15, singlerun2, spatiocyte.Factory(radius).rng(rng), 3)
In [11]:
plt.plot(t, 6 * D * t, 'k-', label="Expected")
plt.plot(t[::30], mean1[::30], 'go', label="eGFRD")
plt.plot(t[::30], mean2[::30], 'ro', label="Spatiocyte")
plt.xlim(t[0], t[-1])
plt.legend(loc="best", shadow=True)
plt.xlabel("Time")
plt.ylabel("Mean Square Displacement")
plt.show()
Here, we test a mean square diplacement in a cube. For the periodic boundaries, particles cannot escape from World, and thus the displacement for each axis is less than a half of the World size. In meso
simulations, unlike egfrd
and spatiocyte
, each molecule doesn't have its ParticleID
. meso
is just validated in this condition because FixedIntervalTrajectoryObserver
is only available with ParticleID
.
In [12]:
def singlerun3(f, duration):
w = f.world(ones())
L_11, L_2 = 1.0 / 11, 1.0 / 2
w.bind_to(m)
NA = 12
w.add_molecules(Species("A"), NA, AABB(Real3(5, 5, 5) * L_11, Real3(6, 6, 6) * L_11))
sim = f.simulator(w)
t, retval = [0.0], [sum(length_sq(p.position() - Real3(L_2, L_2, L_2)) for pid, p in w.list_particles_exact(Species("A"))) / NA]
for i in range(20):
sim.run(duration / 20)
mean = sum(length_sq(p.position() - Real3(L_2, L_2, L_2)) for pid, p in w.list_particles_exact(Species("A"))) / NA
t.append(sim.t())
retval.append(mean)
return numpy.array(t), numpy.array(retval)
Simulating with egfrd
:
In [13]:
t, mean1 = test_mean_square_displacement(50, singlerun3, egfrd.Factory(Integer3(4, 4, 4)).rng(rng), 0.15)
Simulating with spatiocyte
:
In [14]:
t, mean2 = test_mean_square_displacement(50, singlerun3, spatiocyte.Factory(radius).rng(rng), 0.15)
Simulating with meso
:
In [15]:
t, mean3 = test_mean_square_displacement(50, singlerun3, meso.Factory(Integer3(11, 11, 11)).rng(rng), 0.15)
Mean square displacement at the uniform distribution in a cube is calculated as follows:
$\int_0^1\int_0^1\int_0^1 dxdydz\ (x-0.5)^2+(y-0.5)^2+(z-0.5)^2=3\left[\frac{(x-0.5)^3}{3}\right]_0^1=0.25$
In [16]:
plt.plot(t, 6 * D * t, 'k-', label="Expected")
plt.plot((t[0], t[-1]), (0.25, 0.25), 'k--', label='Uniform distribution')
plt.plot(t, mean1, 'go', label="eGFRD")
plt.plot(t, mean2, 'ro', label="Spatiocyte")
plt.plot(t, mean3, 'bo', label="Meso")
plt.xlim(t[0], t[-1])
plt.ylim(0, 0.3)
plt.legend(loc="best", shadow=True)
plt.xlabel("Time")
plt.ylabel("Mean Square Displacement")
plt.show()
Spatial simulation with a structure is only supported by spatiocyte
and meso
now. Here, mean square displacement on a planar surface is tested for these algorithms.
First, a model is defined with a species A
which has the same attributes with above except for the location named M
.
In [17]:
radius, D = 0.005, 1
m = NetworkModel()
A = Species("A", radius, D, "M")
A.set_attribute("dimension", 2)
m.add_species_attribute(A)
M = Species("M", radius, 0)
M.set_attribute("dimension", 2)
m.add_species_attribute(M)
Mean square displacement of a 2D diffusion must follow 4Dt
. The diffusion on a planar surface parallel to yz-plane at the center is tested with spatiocyte
.
In [18]:
def singlerun4(f, duration):
w = f.world(ones())
w.bind_to(m)
w.add_structure(Species("M"), PlanarSurface(0.5 * ones(), unity(), unitz()))
w.add_molecules(Species("A"), 60)
obs1 = FixedIntervalTrajectoryObserver(0.01, [pid for pid, p in w.list_particles_exact(Species("A"))])
sim = f.simulator(w)
sim.run(duration, obs1)
t = numpy.array(obs1.t())
mean = sum(numpy.array([length_sq(pos - data[0]) for pos in data])
for data in obs1.data()) / obs1.num_tracers()
return t, mean
Simulating with spatiocyte
:
In [19]:
t, mean2 = test_mean_square_displacement(100, singlerun4, spatiocyte.Factory(radius).rng(rng), 10)
In [20]:
plt.plot(t, 4 * D * t, 'k-', label="Expected")
plt.plot(t[::50], mean2[::50], 'ro', label="Spatiocyte")
plt.xlim(t[0], t[-1])
plt.legend(loc="best", shadow=True)
plt.xlabel("Time")
plt.ylabel("Mean Square Displacement")
plt.show()
Mean square displacement on a planar surface restricted in a cube by periodic boundaries is compared between meso
and spatiocyte
.
In [21]:
def singlerun5(f, duration):
w = f.world(ones())
L_11, L_2 = 1.0 / 11, 1.0 / 2
w.bind_to(m)
NA = 12
w.add_structure(Species("M"), PlanarSurface(0.5 * ones(), unity(), unitz()))
w.add_molecules(Species("A"), NA, AABB(ones() * 5 * L_11, ones() * 6 * L_11))
sim = f.simulator(w)
t, retval = [0.0], [sum(length_sq(p.position() - Real3(L_2, L_2, L_2)) for pid, p in w.list_particles_exact(Species("A"))) / NA]
for i in range(20):
sim.run(duration / 20)
mean = sum(length_sq(p.position() - Real3(L_2, L_2, L_2)) for pid, p in w.list_particles_exact(Species("A"))) / NA
t.append(sim.t())
retval.append(mean)
return numpy.array(t), numpy.array(retval)
Simulating with spatiocyte
:
In [22]:
t, mean2 = test_mean_square_displacement(50, singlerun5, spatiocyte.Factory(radius).rng(rng), 0.15)
Simulating with meso
:
In [23]:
t, mean3 = test_mean_square_displacement(50, singlerun5, meso.Factory(Integer3(11, 11, 11)).rng(rng), 0.15)
Mean square displacement at the uniform distribution on a plane is calculated as follows:
$\int_0^1\int_0^1 dxdydz\ (0.5-0.5)^2+(y-0.5)^2+(z-0.5)^2=2\left[\frac{(x-0.5)^3}{3}\right]_0^1=\frac{1}{6}$
In [24]:
plt.plot(t, 4 * D * t, 'k-', label="Expected")
plt.plot((t[0], t[-1]), (0.5 / 3, 0.5 / 3), 'k--', label='Uniform distribution')
plt.plot(t, mean2, 'ro', label="Spatiocyte")
plt.plot(t, mean3, 'bo', label="Meso")
plt.xlim(t[0], t[-1])
plt.ylim(0, 0.2)
plt.legend(loc="best", shadow=True)
plt.xlabel("Time")
plt.ylabel("Mean Square Displacement")
plt.show()
Plottig the trajectory of particles on a surface with spatiocyte
:
In [25]:
obs = FixedIntervalTrajectoryObserver(0.01)
surface = PlanarSurface(0.5 * ones(), unity(), unitz())
run_simulation(5, model=m, y0={"A": 10}, structures={"M": surface}, observers=obs,
solver=spatiocyte.Factory(radius).rng(rng), return_type=None)
# viz.plot_trajectory(obs)
viz.plot_trajectory(obs, interactive=False)