See also
This page was generated from examples/example12.ipynb.
Download the Jupyter Notebook for this section: example12.ipynb
. View in nbviewer.
Important: The unit system is a feature under development. The following section might not work properly yet.
Here, we show some examples using the unit system in ecell4
. This feature requires Python library, pint
. Install pint
before running this example as follows: pip install pint
. See also the website https://pint.readthedocs.io/en/latest/.
[1]:
%matplotlib inline
from ecell4.prelude import *
First, imagine a very simple system only with binding and unbinding reactions like:
[2]:
with species_attributes():
A | B | C | {'D': 1, 'radius': 0.005}
with reaction_rules():
A + B == C | (0.01, 0.3)
m = get_model()
The species_attributes
section defines a diffusion constant and radius of Species
, A
, B
and C
. For example, the diffusion rate of A
is 1
, and its dimensionality is expected to be [length**2/time]
. However, what is the scale? Is it meter
? Or mile
?
Once the base units are determined, e.g. micrometer
as [length]
and second
as [time]
, all the units must be consistent within the model. The second order rate consant must have dimensionality [1/(substance/length**3)/time]
, which is micrometer**3/item/second
. Thus, when the parameter is given as 1/molar/min
in some literature, you have to translate it by yourself.
[3]:
show(m)
A | {'D': 1, 'radius': 0.005}
B | {'D': 1, 'radius': 0.005}
C | {'D': 1, 'radius': 0.005}
A + B > C | 0.01
C > A + B | 0.3
ecell4
provides the way to handle units in the modeling environment. Here is an example.
[4]:
from ecell4.extra.unit import getUnitRegistry
ureg = getUnitRegistry()
Q_ = ureg.Quantity
First, create your own unit system,ureg
, by using ecell4.extra.unit.getUnitRegistry
. With this UnitRegistry
, you can make a quantity with its unit as ureg.Quantity(value, unit)
. (Please be careful about the type of Quantity
. It looks same with Quantity
given by pint
, but is slightly changed in ecell4
though all the original functionality in pint
is availble even in ecell4
. Please not use ureg = pint.UnitRegistry()
.)
[5]:
with species_attributes():
A | B | C | {'D': Q_(1, 'um**2/s'), 'radius': Q_(0.005, 'um')}
with reaction_rules():
A + B == C | (Q_(0.01, '1/(item/um**3)/s'), Q_(0.3, '1/s'))
m = get_model()
The default base units are meter
for [length]
, second
for [time]
, and item
(which means the number of molecules) for [substance]
. When you change the default base unit, do like ureg = getUnitRegistry(length='micrometer')
.
[6]:
show(m)
A | {'D': Quantity_Real(1e-12, 'meter ** 2 / second'), 'radius': Quantity_Real(5e-09, 'meter')}
B | {'D': Quantity_Real(1e-12, 'meter ** 2 / second'), 'radius': Quantity_Real(5e-09, 'meter')}
C | {'D': Quantity_Real(1e-12, 'meter ** 2 / second'), 'radius': Quantity_Real(5e-09, 'meter')}
A + B > C | Quantity_Real(1e-20, 'meter ** 3 / item / second')
C > A + B | Quantity_Real(0.3, '1 / second')
Now you can provide quantities in any unit regardless of the base units.
[7]:
with species_attributes():
A | B | C | {'D': Q_(1e-8, 'cm**2/s'), 'radius': Q_(5, 'nm')}
with reaction_rules():
A + B == C | (Q_(6.02214129, '1/uM/s'), Q_(18, '1/min'))
m = get_model()
show(m)
A | {'D': Quantity_Real(1e-12, 'meter ** 2 / second'), 'radius': Quantity_Real(5e-09, 'meter')}
B | {'D': Quantity_Real(1e-12, 'meter ** 2 / second'), 'radius': Quantity_Real(5e-09, 'meter')}
C | {'D': Quantity_Real(1e-12, 'meter ** 2 / second'), 'radius': Quantity_Real(5e-09, 'meter')}
A + B > C | Quantity_Real(1e-20, 'meter ** 3 / item / second')
C > A + B | Quantity_Real(0.3, '1 / second')
You can operate quantities, and make a new quantity. See https://pint.readthedocs.io/en/latest/ for more details.
[8]:
volume = Q_(1, 'fL')
conc = Q_(100, 'nM')
print((volume * conc).to('item'))
60.221412900000004 item
In addition to the model creation, run_simulation
(and ensemble_simulations
) also supports the unit system.
[9]:
run_simulation(Q_(0.1, 'min'), y0={'C': Q_(60, 'item')}, volume=Q_(1, 'fL'), model=m, solver='ode')
Even if you change the base units, the behavior of simulations is kept consistent. In the following example, base units are rescaled to micrometer
and minute
with no change in the modeling section.
[10]:
ureg = getUnitRegistry(length='micrometer', time='minute')
Q_ = ureg.Quantity
with species_attributes():
A | B | C | {'D': Q_(1e-8, 'cm**2/s'), 'radius': Q_(5, 'nm')}
with reaction_rules():
A + B == C | (Q_(6.02214129, '1/uM/s'), Q_(18, '1/min'))
m = get_model()
show(m)
run_simulation(Q_(0.1, 'min'), y0={'C': Q_(60, 'item')}, volume=Q_(1, 'fL'), model=m, solver='ode')
A | {'D': Quantity_Real(60, 'micrometer ** 2 / minute'), 'radius': Quantity_Real(0.005, 'micrometer')}
B | {'D': Quantity_Real(60, 'micrometer ** 2 / minute'), 'radius': Quantity_Real(0.005, 'micrometer')}
C | {'D': Quantity_Real(60, 'micrometer ** 2 / minute'), 'radius': Quantity_Real(0.005, 'micrometer')}
A + B > C | Quantity_Real(0.6, 'micrometer ** 3 / item / minute')
C > A + B | Quantity_Real(18, '1 / minute')
This feature is still being developed. Please report issues when getting the wrong behavior.
You can check units in the model by ecell4.extra.unit.check_model
.
For example, the dimensionality of a diffusion constant must be [length**2/time]
. When you give a unit with a wrong dimensionality, an exception DimensionalityMismatchError
would be thrown as:
[11]:
from ecell4.extra.unit import check_model, DimensionalityMismatchError
ureg = getUnitRegistry()
Q_ = ureg.Quantity
[12]:
with species_attributes():
A | {'radius': Q_(0.005, 'um'), 'D': Q_(1.0, 'um/s')}
try:
check_model(get_model())
except DimensionalityMismatchError as e:
print('{}: {}'.format(e.__class__.__name__, e))
DimensionalityMismatchError: Attribute [D] in Species [A] has wrong dimensionality. [[length]**2/[time]] is expected.
When checking dimensionality of units in the model by check_model
, you can omit no unit.
[13]:
with species_attributes():
A | {'radius': 0.005, 'D': Q_(1.0, 'um**2/s')}
try:
check_model(get_model())
except DimensionalityMismatchError as e:
print('{}: {}'.format(e.__class__.__name__, e))
DimensionalityMismatchError: Attribute [radius] in Species [A] has wrong dimensionality. [[length]] is expected.
A kinetic rate constant of reactions is verified based on the order of the reaction. The first order reaction rate should have [1/time]
, and the second order should have [l/(substance/length**3)/time]
in volume.
[14]:
with reaction_rules():
A + B > C | Q_(0.3, '1/s')
try:
check_model(get_model())
except DimensionalityMismatchError as e:
print('{}: {}'.format(e.__class__.__name__, e))
DimensionalityMismatchError: ReactionRule [A+B>C|0.3] has wrong dimensionality [1 / [time]]. [[length]**3/[substance]/[time]] is expected.
The dimensionality of a synthetic reaction depends on the dimension which the products belongs to.
[15]:
with reaction_rules():
~A > A | Q_(0.3, '1/s')
try:
check_model(get_model())
except DimensionalityMismatchError as e:
print('{}: {}'.format(e.__class__.__name__, e))
DimensionalityMismatchError: ReactionRule [>A|0.3] has wrong dimensionality [1 / [time]]. [[substance]/[time]/[length]**3] is expected.
An unit of the reaction rate between a molecule and structure is also tested.
[16]:
with species_attributes():
B | {'location': 'M'}
M | {'dimension': 2}
with reaction_rules():
A + M > B | Q_(0.3, '1/s')
try:
check_model(get_model())
except DimensionalityMismatchError as e:
print('{}: {}'.format(e.__class__.__name__, e))
DimensionalityMismatchError: ReactionRule [A+M>B|0.3] has wrong dimensionality [1 / [time]]. [[length]**1/[time]] is expected.
Additionally, rate law representations accept quantities with a unit too. See the example below:
[17]:
with reaction_rules():
S > P | Q_(1.0, 'uM/s') * S / (Q_(100, 'nM') + S)
check_model(get_model())
Here, the reaction above has two quantities, Vmax = Q_(1.0, 'uM/s')
and Km = Q_(100, 'nM')
. First, Km
must have the same dimensionality with S
, which is [concentration]
.
[18]:
with reaction_rules():
S > P | Q_(1.0, 'uM/s') * S / (Q_(100, 'nM/s') + S)
try:
check_model(get_model())
except DimensionalityMismatchError as e:
print('{}: {}'.format(e.__class__.__name__, e))
DimensionalityMismatchError: Failed to evaluate [((Quantity_Real(6.02214129e+20, 'item / meter ** 3 / second') * S) / (Quantity_Real(6.02214129e+19, 'item / meter ** 3 / second') + S))] (1*S>1*P|0). Cannot convert from 'item / meter ** 3 / second' ([substance] / [length] ** 3 / [time]) to 'item / meter ** 3' ([substance] / [length] ** 3)
Secondly, the dimensionality of a rate equation must be [concentration/time]
. Therefore, the dimensionality of Vmax
should be [concentration/time]
too.
[19]:
with reaction_rules():
S > P | Q_(1.0, '1/s') * S / (Q_(100, 'nM') + S)
try:
check_model(get_model())
except DimensionalityMismatchError as e:
print('{}: {}'.format(e.__class__.__name__, e))
DimensionalityMismatchError: ReactionRule [1*S>1*P|0] has wrong dimensionality [1 / [time]]. [[substance]/[length]**3/[time]] is expected.
When you give a value with no unit, it is regarded as dimensionless
.
[20]:
with reaction_rules():
S > P | 10.0 * Q_(0.1, 'uM/s') * S**2 / (Q_(100, 'nM')**2 + S**2)
m = get_model()
show(m)
check_model(m)
S > P | ((Quantity_Real(6.02214129e+20, 'item / meter ** 3 / second') * pow(S, 2)) / (Quantity_Real(3.626618571672287e+39, 'item ** 2 / meter ** 6') + pow(S, 2)))