In [1]:
from ecell4.core import *
from ecell4 import gillespie
m = NetworkModel()
m.add_reaction_rule(create_unimolecular_reaction_rule(Species("A"), Species("B"), 1.0))
m.add_reaction_rule(create_unimolecular_reaction_rule(Species("B"), Species("A"), 0.5))
w = gillespie.GillespieWorld(Real3(1, 1, 1))
w.add_molecules(Species("A"), 60)
s = gillespie.GillespieSimulator(m, w)
s.initialize()
Prepare observers. Not necessarily needed to be created here.
In [2]:
obs1 = FixedIntervalNumberObserver(1.0, ["A"])
obs2 = NumberObserver(["A", "B"])
obs3 = TimingNumberObserver([0, 1e-3, 1e-2, 1e-1, 1e+0, 1e+1], ["A"])
obs4 = FixedIntervalHDF5Observer(5.0, "test%02d.h5")
Run simulation with observers. Warning: HDF5 is not supported as a default. World::save
raises NotSupported error without the HDF5 feature.
In [3]:
s.run(16.0, [obs1, obs2, obs3])
# s.run(16.0, [obs1, obs2, obs3, obs4])
NumberObservers return data by calling the member function NumberObserver::data()
. NumberObserver::targets()
returns a list of species, which you specified as an argument of the constructor.
In [4]:
print(obs1.data())
print([sp.serial() for sp in obs1.targets()])
The normal NumberObserver
stores the numbers of given Species
just after every steps. It doesn't work properly with ODESimulator
because ODESimulator
has no internal dt
. FixedIntervalNumberObserver
logs them with the fixed step interval. TimingNumberObserver
allow you to give the times of logging as an argument of the constructor.
In [5]:
print(obs2.data()[: 5])
print(obs3.data())
FixedIntervalHDF5Observer
saves a World
in the HDF5 format. FixedIntervalHDF5Observer::filename()
returns the name of a file scheduled to be saved next. At most one format string like %02d
is allowed to use a step count in the file name. When you do not use the format string, it overwrites the latest data to the file.
In [6]:
print(obs4.filename())
viz.plot_number_observer
is the easiest way to plot a result in the NumberObserver
, FixedIntervalNumberObserver
and TimingNumberObserver
. For the detailed usage of viz.plot_number_observer
, see help(viz.plot_number_observer)
.
In [7]:
%matplotlib inline
from ecell4 import viz
viz.plot_number_observer(obs2)
Of course, you can analyze and plot the results by yourself.
In [8]:
%matplotlib inline
import numpy
import matplotlib.pylab as plt
labels = [sp.serial() for sp in obs2.targets()]
data = numpy.asarray(obs2.data()).T
plt.plot(data[0], data[2] / data[1], label="{1} / {0}".format(labels[0], labels[1]))
plt.plot([data[0][0], data[0][-1]], [2.0, 2.0], 'k--')
plt.xlabel("Time")
plt.ylabel("The ratio of numbers")
plt.legend(loc="best", shadow=True)
plt.show()
Warning: HDF5 is not supported as a default. Check HDF5 files.
In [9]:
# import glob
# print(glob.glob("test*.h5"))
# w.load('test03.h5')
# print(w.t(), w.num_molecules(Species("A")), w.num_molecules(Species("B")))
For logging positions of particles, FixedIntervalHDF5Observer
, FixedIntervalCSVObserver
and FixedIntervalTrajectoryObserver
are available. Here is an example with the lattice
module.
In [10]:
from ecell4 import lattice
m = NetworkModel()
m.add_species_attribute(Species("A", "0.005", "1"))
w = lattice.LatticeWorld(Real3(1, 1, 1), 0.005)
w.bind_to(m)
w.add_molecules(Species("A"), 3)
s = lattice.LatticeSimulator(w)
s.initialize()
The usage of FixedIntervalCSVObserver
is almost same with that of FixedIntervalHDF5Observer
. It saves positions (x, y, z) of particles with the radius (r) and serial number of Species
(sid). FixedIntervalTrajectoryObserver
keeps tracking of particles, which you specified with ParticleID
s. Once some ParticleID
is lost for the reaction, it just stop to trace the particle any more.
In [11]:
obs5 = FixedIntervalCSVObserver(0.3, "test%02d.csv")
obs6 = FixedIntervalTrajectoryObserver(1e-3, [pid for pid, p in w.list_particles()])
The way to run a simulation with these Observer
s is the same with the above for NumberObserver
s.
In [12]:
s.run(1.0, [obs5, obs6])
Chek CSV files.
In [13]:
import glob
print(glob.glob("test*.csv"))
print(open("test00.csv").read())
Generally, World
assumes a periodic boundary for each plane. To avoid the big jump of a particle at the edge because of the boundary condition, FixedIntervalTrajectoryObserver
tries to keep the shift of positions. Thus, the positions stored in the Observer
are not necessarily limited in the cuboid given for the World
. Of course, you can disable this option. See help(FixedIntervalTrajectoryObserver)
.
In [14]:
print([tuple(pos) for pos in obs6.data()[0][: 5]])
print([tuple(pos) for pos in obs6.data()[0][-5:]])
A user can easily plot the trajectory of particles by using viz.plot_trajectory
. For the detailed usage, see the Visualizer section and help(viz.plot_trajectory)
.
In [15]:
# viz.plot_trajectory(obs6)
In [ ]: