from dataclasses import dataclass
from mxlpy import Model, Simulator, fns, plot, unwrap
from mxlpy.types import InitialAssignment
def one_div(x: float) -> float:
return 1.0 / x
def minus_one_div(x: float) -> float:
return -1.0 / x
def times_frac(top: float, btm: float, x: float) -> float:
return top / btm * x
def ma_1s_1p_keq(s1: float, p1: float, kf: float, keq: float) -> float:
return kf * (s1 - p1 / keq)
--------------------------------------------------------------------------- ImportError Traceback (most recent call last) Cell In[1], line 3 1 from dataclasses import dataclass ----> 3 from mxlpy import Model, Simulator, fns, plot, unwrap 4 from mxlpy.types import InitialAssignment 7 def one_div(x: float) -> float: ImportError: cannot import name 'unwrap' from 'mxlpy' (/home/runner/work/MxlPy/MxlPy/src/mxlpy/__init__.py)
Compartmental models¶
We follow the recommendations by Hofmeyr (2020) (https://doi.org/10.1016/j.biosystems.2020.104203) when it comes to compartmentalisation. That is, describe compartmentalised variables in terms of amounts instead of concentration and scale kinetic constants by the compartment to yield rate factors.
Depending on your use case, your experimental data might be described as concentrations and communication is also prefered in concentrations.
mxlpy provides various ways of how you can automate that mapping
- use
Derivedvariables and parameters to obtain concentrations from the amounts. - use
InitialAssignments to calculate initial amounts in case your data is given in concentrations
Below we define convenience functions for exactly that, to reduce boilerplate code
@dataclass
class VarNames:
amount: str
conc: str
def add_cvar(
model: Model,
name: str,
compartment: str,
initial: float,
*,
initial_is_amount: bool = True,
amount_prefix: str = "n_",
conc_prefix: str = "c_",
) -> VarNames:
amount = f"{amount_prefix}{name}_{compartment}"
if not initial_is_amount:
# FIXME: rewrite initial assignment to take in float?
model.add_parameter(init_c := f"c_{name}_init", initial)
model.add_variable(
amount,
InitialAssignment(fn=fns.mul, args=[init_c, compartment]),
)
else:
model.add_variable(amount, initial)
model.add_derived(
conc := f"{conc_prefix}{name}_{compartment}",
fn=fns.div,
args=[amount, compartment],
)
return VarNames(amount, conc)
m = Model()
m.add_parameters({"c1": 2.0, "c2": 4.0})
# Add a compartmentalised variable with an initial amount
x_c1 = add_cvar(m, "x", compartment="c1", initial=1.5)
# Add a compartmentalised variable with an initial concentration
x_c2 = add_cvar(m, "x", compartment="c2", initial=1.5, initial_is_amount=False)
args = m.get_args()
print("Amounts", args.loc[[x_c1.amount, x_c2.amount]], sep="\n", end="\n\n")
print("Concentrations", args.loc[[x_c1.conc, x_c2.conc]], sep="\n", end="\n\n")
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[2], line 42 39 x_c1 = add_cvar(m, "x", compartment="c1", initial=1.5) 41 # Add a compartmentalised variable with an initial concentration ---> 42 x_c2 = add_cvar(m, "x", compartment="c2", initial=1.5, initial_is_amount=False) 44 args = m.get_args() 45 print("Amounts", args.loc[[x_c1.amount, x_c2.amount]], sep="\n", end="\n\n") Cell In[2], line 23, in add_cvar(model, name, compartment, initial, initial_is_amount, amount_prefix, conc_prefix) 18 if not initial_is_amount: 19 # FIXME: rewrite initial assignment to take in float? 20 model.add_parameter(init_c := f"c_{name}_init", initial) 21 model.add_variable( 22 amount, ---> 23 InitialAssignment(fn=fns.mul, args=[init_c, compartment]), 24 ) 25 else: 26 model.add_variable(amount, initial) NameError: name 'InitialAssignment' is not defined
Here is another quick conveniece function to quickly kinetic constants and their respective **rate factors **
def rate_factor(rxn_place: float, k: float, compartment: float) -> float:
return rxn_place * k / compartment
def add_rate_factor(
model: Model,
base: str,
value: float,
rxn_compartment: str,
cpd_compartment: str,
k_prefix: str = "k_",
f_prefix: str = "f_",
) -> str:
model.add_parameter(k := f"{k_prefix}{base}", value)
f = f"{f_prefix}{base}"
model.add_derived(
f,
fn=rate_factor,
args=[rxn_compartment, k, cpd_compartment],
)
return f
m = Model()
m.add_parameters({"c1": 2.0, "a1": 4.0})
rf = add_rate_factor(m, "r1", 1.0, rxn_compartment="a1", cpd_compartment="c1")
m.get_args().loc[rf]
np.float64(2.0)
Examples¶
Single compartment¶
In case all your reactions happen in the volume of the same compartment, you don't need to change anything.
Whether your variables describe an amount or a concentration does not matter, the equations are identical.
Here we use standard reversible mass-action kinetics, once formulated explicitly with forward and backward kinetic constants and once using the equilibrium constant.
$$\begin{align*} v &= k_f x - k_r y \\ &= k_f \left( x - \frac{y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"x": 2.0, "y": 1.0})
.add_parameters({"kf": 1.0, "keq": 2.0})
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["x", "y", "kf", "keq"],
stoichiometry={"x": -1, "y": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
_ = plot.lines(
c,
xlabel="Time",
ylabel="Amount or Concentration",
ax=plot.one_axes(figsize=(4, 3))[1],
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[4], line 7 1 m = ( 2 Model() 3 .add_variables({"x": 2.0, "y": 1.0}) 4 .add_parameters({"kf": 1.0, "keq": 2.0}) 5 .add_reaction( 6 "v1", ----> 7 ma_1s_1p_keq, 8 args=["x", "y", "kf", "keq"], 9 stoichiometry={"x": -1, "y": 1}, 10 ) 11 ) 13 c, v = unwrap(Simulator(m).simulate(10).get_result()) 14 _ = plot.lines( 15 c, 16 xlabel="Time", 17 ylabel="Amount or Concentration", 18 ax=plot.one_axes(figsize=(4, 3))[1], 19 ) NameError: name 'ma_1s_1p_keq' is not defined
Single compartment - at membrane¶
$$\begin{align*} v &= {\color{purple} A} \left( k_f \frac{n_x}{{\color{cyan}C_1} } - k_r \frac{n_y}{{\color{cyan}C_1}} \right) \\ &= f_f n_x - f_r n_y \\ &= f_f \left( n_x - \frac{n_y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"n_x": 2.0, "n_y": 1.0})
.add_parameters(
{
"kf": 1.0,
"keq": 2.0,
"c1": 1.5, # compartment volume
"a1": 1.0, # area of membrane
}
)
# Now compartmentalise
.add_derived("ff", rate_factor, args=["a1", "kf", "c1"])
.add_derived("x_c1", fns.div, args=["n_x", "c1"])
.add_derived("y_c1", fns.div, args=["n_y", "c1"])
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["n_x", "n_y", "ff", "keq"],
stoichiometry={"n_x": -1, "n_y": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3))
_ = plot.lines(
c.loc[:, ["n_x", "n_y"]],
ax=ax1,
xlabel="Time",
ylabel="Amount",
)
_ = plot.lines(
c.loc[:, ["x_c1", "y_c1"]],
ax=ax2,
xlabel="Time",
ylabel="Concentration",
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[5], line 18 1 m = ( 2 Model() 3 .add_variables({"n_x": 2.0, "n_y": 1.0}) 4 .add_parameters( 5 { 6 "kf": 1.0, 7 "keq": 2.0, 8 "c1": 1.5, # compartment volume 9 "a1": 1.0, # area of membrane 10 } 11 ) 12 # Now compartmentalise 13 .add_derived("ff", rate_factor, args=["a1", "kf", "c1"]) 14 .add_derived("x_c1", fns.div, args=["n_x", "c1"]) 15 .add_derived("y_c1", fns.div, args=["n_y", "c1"]) 16 .add_reaction( 17 "v1", ---> 18 ma_1s_1p_keq, 19 args=["n_x", "n_y", "ff", "keq"], 20 stoichiometry={"n_x": -1, "n_y": 1}, 21 ) 22 ) 24 c, v = unwrap(Simulator(m).simulate(10).get_result()) 25 fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3)) NameError: name 'ma_1s_1p_keq' is not defined
Single compartment - on membrane¶
This special case depends only on the area of the membrane, not on the volume of the compartment
$$\begin{align*} v &= {\color{purple} A} \left( k_f \frac{n_x}{{\color{purple} A} } - k_r \frac{n_y}{{\color{purple} A} } \right) \\ &= f_f n_x - f_r n_y \\ &= f_f \left( n_x - \frac{n_y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"n_x": 2.0, "n_y": 1.0})
.add_parameters(
{
"kf": 1.0,
"keq": 2.0,
}
)
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["n_x", "n_y", "kf", "keq"],
stoichiometry={"n_x": -1, "n_y": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
_ = plot.lines(
c.loc[:, ["n_x", "n_y"]],
xlabel="Time",
ylabel="Amount",
ax=plot.one_axes(figsize=(4, 3))[1],
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[6], line 12 1 m = ( 2 Model() 3 .add_variables({"n_x": 2.0, "n_y": 1.0}) 4 .add_parameters( 5 { 6 "kf": 1.0, 7 "keq": 2.0, 8 } 9 ) 10 .add_reaction( 11 "v1", ---> 12 ma_1s_1p_keq, 13 args=["n_x", "n_y", "kf", "keq"], 14 stoichiometry={"n_x": -1, "n_y": 1}, 15 ) 16 ) 18 c, v = unwrap(Simulator(m).simulate(10).get_result()) 19 _ = plot.lines( 20 c.loc[:, ["n_x", "n_y"]], 21 xlabel="Time", 22 ylabel="Amount", 23 ax=plot.one_axes(figsize=(4, 3))[1], 24 ) NameError: name 'ma_1s_1p_keq' is not defined
Two compartments - diffusion accross membrane¶
$$\begin{align*} v &= {\color{purple} A} \left( k_f \frac{n_x}{{\color{cyan} C_1}} - k_r \frac{n_y}{{\color{coral} C_2}} \right) \\ &= f_f n_x - f_r n_y \\ &= f_f \left( n_x - \frac{n_y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"nx_c1": 2.0, "ny_c2": 1.0})
.add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "c2": 0.5})
# Now compartmentalise
.add_derived("ff", fns.div, args=["kf", "c1"])
.add_derived("x_c1", fns.div, args=["nx_c1", "c1"])
.add_derived("x_c2", fns.div, args=["ny_c2", "c2"])
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["nx_c1", "ny_c2", "ff", "keq"],
stoichiometry={"nx_c1": -1, "ny_c2": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3))
_ = plot.lines(
c.loc[:, ["nx_c1", "ny_c2"]],
ax=ax1,
xlabel="Time",
ylabel="Amount",
)
_ = plot.lines(
c.loc[:, ["x_c1", "x_c2"]],
ax=ax2,
xlabel="Time",
ylabel="Concentration",
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[7], line 11 1 m = ( 2 Model() 3 .add_variables({"nx_c1": 2.0, "ny_c2": 1.0}) 4 .add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "c2": 0.5}) 5 # Now compartmentalise 6 .add_derived("ff", fns.div, args=["kf", "c1"]) 7 .add_derived("x_c1", fns.div, args=["nx_c1", "c1"]) 8 .add_derived("x_c2", fns.div, args=["ny_c2", "c2"]) 9 .add_reaction( 10 "v1", ---> 11 ma_1s_1p_keq, 12 args=["nx_c1", "ny_c2", "ff", "keq"], 13 stoichiometry={"nx_c1": -1, "ny_c2": 1}, 14 ) 15 ) 17 c, v = unwrap(Simulator(m).simulate(10).get_result()) 18 fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3)) NameError: name 'ma_1s_1p_keq' is not defined
Two compartments - inside¶
$$\begin{align*} v &= {\color{purple} A} \left( k_f \frac{n_x}{{\color{cyan} C_1}} - k_r \frac{n_y}{{\color{coral} C_2}} \right) \\ &= f_f n_x - f_r n_y \\ &= f_f \left( n_x - \frac{n_y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"nx_c1": 2.0, "ny_c2": 1.0})
.add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "c2": 0.5})
# Now compartmentalise
.add_derived("ff", fns.div, args=["kf", "c1"])
.add_derived("x_c1", fns.div, args=["nx_c1", "c1"])
.add_derived("x_c2", fns.div, args=["ny_c2", "c2"])
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["nx_c1", "ny_c2", "ff", "keq"],
stoichiometry={"nx_c1": -1, "ny_c2": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3))
_ = plot.lines(
c.loc[:, ["nx_c1", "ny_c2"]],
ax=ax1,
xlabel="Time",
ylabel="Amount",
)
_ = plot.lines(
c.loc[:, ["x_c1", "x_c2"]],
ax=ax2,
xlabel="Time",
ylabel="Concentration",
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[8], line 11 1 m = ( 2 Model() 3 .add_variables({"nx_c1": 2.0, "ny_c2": 1.0}) 4 .add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "c2": 0.5}) 5 # Now compartmentalise 6 .add_derived("ff", fns.div, args=["kf", "c1"]) 7 .add_derived("x_c1", fns.div, args=["nx_c1", "c1"]) 8 .add_derived("x_c2", fns.div, args=["ny_c2", "c2"]) 9 .add_reaction( 10 "v1", ---> 11 ma_1s_1p_keq, 12 args=["nx_c1", "ny_c2", "ff", "keq"], 13 stoichiometry={"nx_c1": -1, "ny_c2": 1}, 14 ) 15 ) 17 c, v = unwrap(Simulator(m).simulate(10).get_result()) 18 fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3)) NameError: name 'ma_1s_1p_keq' is not defined
Two compartments - at membrane¶
$$\begin{align*} v &= {\color{purple} A} \left( k_f \frac{n_x}{{\color{cyan} C_1}} - k_r \frac{n_y}{{\color{coral} C_2}} \right) \\ &= f_f n_x - f_r n_y \\ &= f_f \left( n_x - \frac{n_y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"nx_c1": 2.0, "ny_c2": 1.0})
.add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "c2": 0.5})
# Now compartmentalise
.add_derived("ff", fns.div, args=["kf", "c1"])
.add_derived("x_c1", fns.div, args=["nx_c1", "c1"])
.add_derived("x_c2", fns.div, args=["ny_c2", "c2"])
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["nx_c1", "ny_c2", "ff", "keq"],
stoichiometry={"nx_c1": -1, "ny_c2": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3))
_ = plot.lines(
c.loc[:, ["nx_c1", "ny_c2"]],
ax=ax1,
xlabel="Time",
ylabel="Amount",
)
_ = plot.lines(
c.loc[:, ["x_c1", "x_c2"]],
ax=ax2,
xlabel="Time",
ylabel="Concentration",
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[9], line 11 1 m = ( 2 Model() 3 .add_variables({"nx_c1": 2.0, "ny_c2": 1.0}) 4 .add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "c2": 0.5}) 5 # Now compartmentalise 6 .add_derived("ff", fns.div, args=["kf", "c1"]) 7 .add_derived("x_c1", fns.div, args=["nx_c1", "c1"]) 8 .add_derived("x_c2", fns.div, args=["ny_c2", "c2"]) 9 .add_reaction( 10 "v1", ---> 11 ma_1s_1p_keq, 12 args=["nx_c1", "ny_c2", "ff", "keq"], 13 stoichiometry={"nx_c1": -1, "ny_c2": 1}, 14 ) 15 ) 17 c, v = unwrap(Simulator(m).simulate(10).get_result()) 18 fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3)) NameError: name 'ma_1s_1p_keq' is not defined
Two compartments - on membrane¶
$$\begin{align*} v &= {\color{purple} A} \left( k_f \frac{n_x}{{\color{purple} A}} - k_r \frac{n_y}{{\color{purple} A}} \right) \\ &= f_f n_x - f_r n_y \\ &= f_f \left( n_x - \frac{n_y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"nx_c1": 2.0, "ny_c2": 1.0})
.add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "c2": 0.5})
# Now compartmentalise
.add_derived("ff", fns.div, args=["kf", "c1"])
.add_derived("x_c1", fns.div, args=["nx_c1", "c1"])
.add_derived("x_c2", fns.div, args=["ny_c2", "c2"])
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["nx_c1", "ny_c2", "ff", "keq"],
stoichiometry={"nx_c1": -1, "ny_c2": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3))
_ = plot.lines(
c.loc[:, ["nx_c1", "ny_c2"]],
ax=ax1,
xlabel="Time",
ylabel="Amount",
)
_ = plot.lines(
c.loc[:, ["x_c1", "x_c2"]],
ax=ax2,
xlabel="Time",
ylabel="Concentration",
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[10], line 11 1 m = ( 2 Model() 3 .add_variables({"nx_c1": 2.0, "ny_c2": 1.0}) 4 .add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "c2": 0.5}) 5 # Now compartmentalise 6 .add_derived("ff", fns.div, args=["kf", "c1"]) 7 .add_derived("x_c1", fns.div, args=["nx_c1", "c1"]) 8 .add_derived("x_c2", fns.div, args=["ny_c2", "c2"]) 9 .add_reaction( 10 "v1", ---> 11 ma_1s_1p_keq, 12 args=["nx_c1", "ny_c2", "ff", "keq"], 13 stoichiometry={"nx_c1": -1, "ny_c2": 1}, 14 ) 15 ) 17 c, v = unwrap(Simulator(m).simulate(10).get_result()) 18 fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3)) NameError: name 'ma_1s_1p_keq' is not defined
Two compartments - onto / off membrane¶
$$\begin{align*} v &= {\color{purple} A} \left( k_f \frac{n_x}{{\color{cyan} C_1}} - k_r \frac{n_y}{{\color{purple} A} } \right) \\ &= f_f n_x - f_r n_y \\ &= f_f \left( n_x - \frac{n_y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"nx_c1": 2.0, "ny_a": 1.0})
.add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "a": 0.5})
# Now compartmentalise
.add_derived("ff", rate_factor, args=["a", "kf", "c1"])
.add_derived("x_c1", fns.div, args=["nx_c1", "c1"])
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["nx_c1", "ny_a", "ff", "keq"],
stoichiometry={"nx_c1": -1, "ny_a": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3))
_ = plot.lines(
c.loc[:, ["nx_c1", "ny_a"]],
ax=ax1,
xlabel="Time",
ylabel="Amount",
)
_ = plot.lines(
c.loc[:, ["x_c1"]],
ax=ax2,
xlabel="Time",
ylabel="Concentration",
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[11], line 10 1 m = ( 2 Model() 3 .add_variables({"nx_c1": 2.0, "ny_a": 1.0}) 4 .add_parameters({"kf": 1.0, "keq": 2.0, "c1": 1.5, "a": 0.5}) 5 # Now compartmentalise 6 .add_derived("ff", rate_factor, args=["a", "kf", "c1"]) 7 .add_derived("x_c1", fns.div, args=["nx_c1", "c1"]) 8 .add_reaction( 9 "v1", ---> 10 ma_1s_1p_keq, 11 args=["nx_c1", "ny_a", "ff", "keq"], 12 stoichiometry={"nx_c1": -1, "ny_a": 1}, 13 ) 14 ) 16 c, v = unwrap(Simulator(m).simulate(10).get_result()) 17 fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3)) NameError: name 'ma_1s_1p_keq' is not defined
$$\begin{align*} v &= {\color{purple} A} \left( k_f \frac{n_x}{{\color{purple} A} } - k_r \frac{n_y}{{\color{coral} C_2}} \right) \\ &= f_f n_x - f_r n_y \\ &= f_f \left( n_x - \frac{n_y}{K_{eq}} \right)\\ \end{align*}$$
m = (
Model()
.add_variables({"nx_a": 2.0, "ny_c2": 1.0})
.add_parameters({"kf": 1.0, "keq": 2.0, "c2": 1.5, "a": 0.5})
# Now compartmentalise
.add_derived("ff", rate_factor, args=["a", "kf", "a"])
.add_derived("y_c2", fns.div, args=["nx_a", "c2"])
.add_reaction(
"v1",
ma_1s_1p_keq,
args=["nx_a", "ny_c2", "ff", "keq"],
stoichiometry={"nx_a": -1, "ny_c2": 1},
)
)
c, v = unwrap(Simulator(m).simulate(10).get_result())
fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3))
_ = plot.lines(
c.loc[:, ["nx_a", "ny_c2"]],
ax=ax1,
xlabel="Time",
ylabel="Amount",
)
_ = plot.lines(
c.loc[:, ["y_c2"]],
ax=ax2,
xlabel="Time",
ylabel="Concentration",
)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[12], line 10 1 m = ( 2 Model() 3 .add_variables({"nx_a": 2.0, "ny_c2": 1.0}) 4 .add_parameters({"kf": 1.0, "keq": 2.0, "c2": 1.5, "a": 0.5}) 5 # Now compartmentalise 6 .add_derived("ff", rate_factor, args=["a", "kf", "a"]) 7 .add_derived("y_c2", fns.div, args=["nx_a", "c2"]) 8 .add_reaction( 9 "v1", ---> 10 ma_1s_1p_keq, 11 args=["nx_a", "ny_c2", "ff", "keq"], 12 stoichiometry={"nx_a": -1, "ny_c2": 1}, 13 ) 14 ) 16 c, v = unwrap(Simulator(m).simulate(10).get_result()) 17 fig, (ax1, ax2) = plot.two_axes(figsize=(6, 3)) NameError: name 'ma_1s_1p_keq' is not defined
First finish line
With that you now know most of what you will need from a day-to-day basis about compartmentalisation in mxlpy.Congratulations!