diff --git a/mira/metamodel/template_model.py b/mira/metamodel/template_model.py
index 91aeccf9..40ff4f3f 100644
--- a/mira/metamodel/template_model.py
+++ b/mira/metamodel/template_model.py
@@ -12,7 +12,7 @@
import datetime
import sys
-from typing import List, Dict, Set, Optional, Mapping, Tuple, Any
+from typing import List, Dict, Set, Optional, Mapping, Tuple, Any, Union
import networkx as nx
import sympy
@@ -603,6 +603,14 @@ def generate_model_graph(self, use_display_name: bool = False) -> nx.DiGraph:
return graph
+ def set_rate_law(self, template_name: str,
+ rate_law: Union[str, sympy.Expr, SympyExprStr],
+ local_dict=None):
+ """Set the rate law of a template with a given name."""
+ for template in self.templates:
+ if template.name == template_name:
+ template.set_rate_law(rate_law, local_dict=local_dict)
+
def draw_graph(
self,
path: str,
diff --git a/mira/metamodel/templates.py b/mira/metamodel/templates.py
index 4c987805..3d14c740 100644
--- a/mira/metamodel/templates.py
+++ b/mira/metamodel/templates.py
@@ -739,6 +739,30 @@ def with_mass_action_rate_law(self, parameter, independent=False) -> "Template":
template.set_mass_action_rate_law(parameter, independent=independent)
return template
+ def set_rate_law(self, rate_law: Union[str, sympy.Expr, SympyExprStr],
+ local_dict=None):
+ """Set the rate law of this template to the given rate law."""
+ if isinstance(rate_law, SympyExprStr):
+ self.rate_law = rate_law
+ elif isinstance(rate_law, sympy.Expr):
+ self.rate_law = SympyExprStr(rate_law)
+ elif isinstance(rate_law, str):
+ try:
+ rate = SympyExprStr(safe_parse_expr(rate_law,
+ local_dict=local_dict))
+ except Exception as e:
+ logger.warning(f"Could not parse rate law into "
+ f"symbolic expression: {rate_law}. "
+ f"Not setting rate law.")
+ return
+ self.rate_law = rate
+
+ def with_rate_law(self, rate_law: Union[str, sympy.Expr, SympyExprStr],
+ local_dict=None) -> "Template":
+ template = self.copy(deep=True)
+ template.set_rate_law(rate_law, local_dict=local_dict)
+ return template
+
def get_parameter_names(self) -> Set[str]:
"""Get the set of parameter names.
diff --git a/mira/modeling/ode.py b/mira/modeling/ode.py
index 5f632b2e..ce505ca3 100644
--- a/mira/modeling/ode.py
+++ b/mira/modeling/ode.py
@@ -17,6 +17,8 @@ def __init__(self, model: Model, initialized: bool):
self.y = sympy.MatrixSymbol('y', len(model.variables), 1)
self.vmap = {variable.key: idx for idx, variable
in enumerate(model.variables.values())}
+ self.observable_map = {obs_key: idx for idx, obs_key
+ in enumerate(model.observables)}
real_params = {k: v for k, v in model.parameters.items()
if not v.placeholder}
self.p = sympy.MatrixSymbol('p', len(real_params), 1)
@@ -27,9 +29,9 @@ def __init__(self, model: Model, initialized: bool):
parameter_map = {parameter.concept.name: parameter.key
for parameter in real_params.values()}
- '''
- Following code block is agnostic towards the case if the ODE model was created with parameter and agent
- values initialized when creating parameters or when calling the simulate_ode method.'''
+ """Following code block is agnostic towards the case if the ODE model
+ was created with parameter and initial values initialized when
+ creating parameters or when calling the simulate_ode method."""
if initialized:
self.parameter_values = []
self.variable_values = []
@@ -73,11 +75,42 @@ def __init__(self, model: Model, initialized: bool):
self.kinetics = sympy.Matrix(self.kinetics)
self.kinetics_lmbd = sympy.lambdify([self.y], self.kinetics)
+ observables = []
+ for obs_name, model_obs in model.observables.items():
+ expr = deepcopy(model_obs.observable.expression).args[0]
+ for symbol in expr.free_symbols:
+ sym_str = str(symbol)
+ if sym_str in concept_map:
+ expr = expr.subs(symbol,
+ self.y[self.vmap[concept_map[sym_str]]])
+ elif sym_str in self.pmap:
+ expr = expr.subs(symbol,
+ self.p[self.pmap[parameter_map[sym_str]]])
+ elif model.template_model.time and \
+ sym_str == model.template_model.time.name:
+ expr = expr.subs(symbol, 't')
+ else:
+ assert False, sym_str
+ observables.append(expr)
+ self.observables = sympy.Matrix(observables)
+ self.observables_lmbd = sympy.lambdify([self.y], self.observables)
+
+ def get_interpretable_kinetics(self):
+ # Return kinetics but with y and p substituted
+ # based on vmap and pmap
+ subs = {self.y[v]: sympy.Symbol(k) for k, v in self.vmap.items()}
+ subs.update({self.p[p]: sympy.Symbol(k) for k, p in self.pmap.items()})
+ return sympy.Matrix([
+ k.subs(subs) for k in self.kinetics
+ ])
+
def set_parameters(self, params):
"""Set the parameters of the model."""
for p, v in params.items():
self.kinetics = self.kinetics.subs(self.p[self.pmap[p]], v)
+ self.observables = self.observables.subs(self.p[self.pmap[p]], v)
self.kinetics_lmbd = sympy.lambdify([self.y], self.kinetics)
+ self.observables_lmbd = sympy.lambdify([self.y], self.observables)
def get_rhs(self):
"""Return the right-hand side of the ODE system."""
@@ -96,7 +129,7 @@ def rhs(t, y):
# ode_model: OdeModel, times, initials=None,
# parameters=None
def simulate_ode_model(ode_model: OdeModel, times, initials=None,
- parameters=None):
+ parameters=None, with_observables=False):
"""Simulate an ODE model given initial conditions, parameters and a
time span.
@@ -112,6 +145,9 @@ def simulate_ode_model(ode_model: OdeModel, times, initials=None,
times:
A one-dimensional array of time values, typically from
a linear space like ``numpy.linspace(0, 25, 100)``
+ with_observables:
+ A boolean indicating whether to return the observables
+ as well as the variables.
Returns
-------
@@ -130,14 +166,27 @@ def simulate_ode_model(ode_model: OdeModel, times, initials=None,
initials = ode_model.variable_values
for index, expression in enumerate(initials):
- initials[index] = float(expression.subs(parameters).args[0])
+ # Only substitute if this is an expression. Once the model has been
+ # simulated, this is actually a float.
+ if isinstance(expression, sympy.Expr):
+ initials[index] = float(expression.subs(parameters).args[0])
ode_model.set_parameters(parameters)
solver = scipy.integrate.ode(f=rhs)
solver.set_initial_value(initials)
- res = numpy.zeros((len(times), ode_model.y.shape[0]))
- res[0, :] = initials
+ num_vars = ode_model.y.shape[0]
+ num_obs = len(ode_model.observable_map)
+ num_cols = num_vars + (num_obs if with_observables else 0)
+ res = numpy.zeros((len(times), num_cols))
+ res[0, :num_vars] = initials
for idx, time in enumerate(times[1:]):
- res[idx + 1, :] = solver.integrate(time)
+ res[idx + 1, :num_vars] = solver.integrate(time)
+
+ if with_observables:
+ for tidx, t in enumerate(times):
+ obs_res = \
+ ode_model.observables_lmbd(res[tidx, :num_vars][:, None])
+ for idx, val in enumerate(obs_res):
+ res[tidx, num_vars + idx] = obs_res[idx]
return res
diff --git a/notebooks/evaluation_2024.03/climate_scenario4/climate_scenario5_petri.json b/notebooks/evaluation_2024.03/climate_scenario4/climate_scenario5_petri.json
new file mode 100644
index 00000000..a1183d74
--- /dev/null
+++ b/notebooks/evaluation_2024.03/climate_scenario4/climate_scenario5_petri.json
@@ -0,0 +1,344 @@
+{
+ "header": {
+ "name": "Model",
+ "schema": "https://raw.githubusercontent.com/DARPA-ASKEM/Model-Representations/petrinet_v0.6/petrinet/petrinet_schema.json",
+ "schema_name": "petrinet",
+ "description": "Model",
+ "model_version": "0.1"
+ },
+ "properties": {},
+ "model": {
+ "states": [
+ {
+ "id": "E_PSII",
+ "name": "E_PSII",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ }
+ },
+ {
+ "id": "NADPp",
+ "name": "NADPp",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ }
+ },
+ {
+ "id": "P_NPQ",
+ "name": "P_NPQ",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ }
+ },
+ {
+ "id": "Q",
+ "name": "Q",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ }
+ },
+ {
+ "id": "NADPH",
+ "name": "NADPH",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ }
+ },
+ {
+ "id": "R",
+ "name": "R",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ }
+ }
+ ],
+ "transitions": [
+ {
+ "id": "t1",
+ "input": [],
+ "output": [
+ "E_PSII"
+ ],
+ "properties": {
+ "name": "t1"
+ }
+ },
+ {
+ "id": "t2",
+ "input": [
+ "NADPp",
+ "E_PSII"
+ ],
+ "output": [
+ "NADPp"
+ ],
+ "properties": {
+ "name": "t2"
+ }
+ },
+ {
+ "id": "t3",
+ "input": [
+ "P_NPQ",
+ "Q",
+ "E_PSII"
+ ],
+ "output": [
+ "P_NPQ",
+ "Q"
+ ],
+ "properties": {
+ "name": "t3"
+ }
+ },
+ {
+ "id": "t4",
+ "input": [
+ "P_NPQ",
+ "E_PSII"
+ ],
+ "output": [
+ "P_NPQ",
+ "E_PSII",
+ "Q"
+ ],
+ "properties": {
+ "name": "t4"
+ }
+ },
+ {
+ "id": "t5",
+ "input": [
+ "Q"
+ ],
+ "output": [],
+ "properties": {
+ "name": "t5"
+ }
+ },
+ {
+ "id": "t6",
+ "input": [],
+ "output": [
+ "P_NPQ"
+ ],
+ "properties": {
+ "name": "t6"
+ }
+ },
+ {
+ "id": "t7",
+ "input": [
+ "NADPp"
+ ],
+ "output": [
+ "NADPH"
+ ],
+ "properties": {
+ "name": "t7"
+ }
+ },
+ {
+ "id": "t8",
+ "input": [
+ "R",
+ "NADPH"
+ ],
+ "output": [
+ "R",
+ "NADPp"
+ ],
+ "properties": {
+ "name": "t8"
+ }
+ },
+ {
+ "id": "t9",
+ "input": [],
+ "output": [
+ "R"
+ ],
+ "properties": {
+ "name": "t9"
+ }
+ }
+ ]
+ },
+ "semantics": {
+ "ode": {
+ "rates": [
+ {
+ "target": "t1",
+ "expression": "PAR*alpha*c_in*(-E_PSII/E_PSII_star + 1)",
+ "expression_mathml": "PARalphac_in1E_PSIIE_PSII_star"
+ },
+ {
+ "target": "t2",
+ "expression": "E_PSII*NADPp*v_ETR",
+ "expression_mathml": "E_PSIINADPpv_ETR"
+ },
+ {
+ "target": "t3",
+ "expression": "E_PSII*P_NPQ*v_d*(-Q/Q_star + 1)",
+ "expression_mathml": "E_PSIIP_NPQv_d1QQ_star"
+ },
+ {
+ "target": "t4",
+ "expression": "E_PSII*P_NPQ*v_d*(-Q/Q_star + 1)",
+ "expression_mathml": "E_PSIIP_NPQv_d1QQ_star"
+ },
+ {
+ "target": "t5",
+ "expression": "Q*v_NPQ",
+ "expression_mathml": "Qv_NPQ"
+ },
+ {
+ "target": "t6",
+ "expression": "Piecewise((v_p*(1 - P_NPQ), c_y < -E_PSII*NADPp*v_ETR + PAR*alpha*c_in*(-E_PSII/E_PSII_star + 1)), (0, True))",
+ "expression_mathml": "v_p1P_NPQc_yE_PSIINADPpv_ETRPARalphac_in1E_PSIIE_PSII_star0"
+ },
+ {
+ "target": "t7",
+ "expression": "E_PSII*NADPp*eta_NADPp*v_ETR",
+ "expression_mathml": "E_PSIINADPpeta_NADPpv_ETR"
+ },
+ {
+ "target": "t8",
+ "expression": "NADPH*R*eta_NADPH*v_C",
+ "expression_mathml": "NADPHReta_NADPHv_C"
+ },
+ {
+ "target": "t9",
+ "expression": "v_R*(1 - R)*Min(d, NADPH/NADPp)",
+ "expression_mathml": "v_R1RdNADPHNADPp"
+ }
+ ],
+ "initials": [
+ {
+ "target": "E_PSII",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "NADPp",
+ "expression": "5.0",
+ "expression_mathml": "5.0"
+ },
+ {
+ "target": "P_NPQ",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "Q",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "NADPH",
+ "expression": "5.0",
+ "expression_mathml": "5.0"
+ },
+ {
+ "target": "R",
+ "expression": "0.001",
+ "expression_mathml": "0.001"
+ }
+ ],
+ "parameters": [
+ {
+ "id": "v_ETR",
+ "value": 0.78
+ },
+ {
+ "id": "v_NPQ",
+ "value": 70.58
+ },
+ {
+ "id": "v_C",
+ "value": 11.75
+ },
+ {
+ "id": "E_PSII_star",
+ "value": 157.56
+ },
+ {
+ "id": "PAR",
+ "value": 520.0
+ },
+ {
+ "id": "alpha",
+ "value": 0.78
+ },
+ {
+ "id": "c_in",
+ "value": 0.23
+ },
+ {
+ "id": "Q_star",
+ "value": 0.07
+ },
+ {
+ "id": "v_d",
+ "value": 0.08
+ },
+ {
+ "id": "c_y",
+ "value": -4.0
+ },
+ {
+ "id": "v_p",
+ "value": 0.07
+ },
+ {
+ "id": "eta_NADPp",
+ "value": 0.89
+ },
+ {
+ "id": "eta_NADPH",
+ "value": 5.07
+ },
+ {
+ "id": "d",
+ "value": 8.4
+ },
+ {
+ "id": "v_R",
+ "value": 0.00089
+ }
+ ],
+ "observables": [
+ {
+ "id": "ETR",
+ "name": "ETR",
+ "expression": "E_PSII*NADPp*v_ETR",
+ "expression_mathml": "E_PSIINADPpv_ETR"
+ },
+ {
+ "id": "NPQ",
+ "name": "NPQ",
+ "expression": "Q*v_NPQ",
+ "expression_mathml": "Qv_NPQ"
+ },
+ {
+ "id": "A",
+ "name": "A",
+ "expression": "NADPH*R*v_C",
+ "expression_mathml": "NADPHRv_C"
+ }
+ ],
+ "time": {
+ "id": "t"
+ }
+ }
+ },
+ "metadata": {
+ "annotations": {}
+ }
+}
\ No newline at end of file
diff --git a/notebooks/evaluation_2024.03/climate_scenario4/photosynthesis.ipynb b/notebooks/evaluation_2024.03/climate_scenario4/photosynthesis.ipynb
new file mode 100644
index 00000000..8df674c3
--- /dev/null
+++ b/notebooks/evaluation_2024.03/climate_scenario4/photosynthesis.ipynb
@@ -0,0 +1,337 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "8223e482",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import json\n",
+ "import sympy\n",
+ "import numpy\n",
+ "from mira.metamodel import *\n",
+ "from mira.modeling.amr.petrinet import template_model_to_petrinet_json\n",
+ "from mira.modeling import Model\n",
+ "from mira.modeling.ode import OdeModel, simulate_ode_model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "e4c5e2dd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "E_PSII = Concept(name='E_PSII')\n",
+ "Q = Concept(name='Q')\n",
+ "P_NPQ = Concept(name='P_NPQ')\n",
+ "NADPp = Concept(name='NADPp')\n",
+ "NADPH = Concept(name='NADPH')\n",
+ "R = Concept(name='R')\n",
+ "\n",
+ "concepts = [E_PSII, Q, P_NPQ, NADPp, NADPH, R]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "2a4b5195",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "inits = {\n",
+ " 'E_PSII': 0.0,\n",
+ " 'Q': 0.0,\n",
+ " 'P_NPQ': 0.0,\n",
+ " 'NADPp': 5.0,\n",
+ " 'NADPH': 5.0,\n",
+ " 'R': 0.001,\n",
+ "}\n",
+ "\n",
+ "params = {\n",
+ " 'PAR': 520,\n",
+ " 'alpha': 0.78,\n",
+ " 'c_in': 0.23,\n",
+ " 'E_PSII_star': 157.56,\n",
+ " 'v_ETR': 0.78,\n",
+ " 'v_d': 0.08,\n",
+ " 'Q_star': 0.07,\n",
+ " 'v_NPQ': 70.58,\n",
+ " 'v_p': 0.07,\n",
+ " 'v_C': 11.75,\n",
+ " 'eta_NADPH': 5.07,\n",
+ " 'eta_NADPp': 0.89,\n",
+ " 'v_R': 8.9e-4,\n",
+ " 'd': 8.40,\n",
+ " 'c_y': -4\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "03bbe6b8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "symbols = {c.name: sympy.Symbol(c.name) for c in concepts}\n",
+ "symbols.update({k: sympy.Symbol(k) for k in params})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "eeace5b6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "energy_input = safe_parse_expr('alpha*c_in*PAR*(1-E_PSII/E_PSII_star)', local_dict=symbols)\n",
+ "ETR = safe_parse_expr('v_ETR*E_PSII*NADPp', local_dict=symbols)\n",
+ "CEF = energy_input - ETR\n",
+ "energy_dissipation = safe_parse_expr('v_d*E_PSII*P_NPQ*(1-Q/Q_star)', local_dict=symbols)\n",
+ "\n",
+ "templates = [\n",
+ " NaturalProduction(\n",
+ " outcome=E_PSII,\n",
+ " rate_law=energy_input),\n",
+ " ControlledDegradation(\n",
+ " subject=E_PSII,\n",
+ " controller=NADPp).with_mass_action_rate_law('v_ETR'),\n",
+ " GroupedControlledDegradation(\n",
+ " subject=E_PSII,\n",
+ " controllers=[P_NPQ, Q],\n",
+ " rate_law=energy_dissipation),\n",
+ " GroupedControlledProduction(\n",
+ " outcome=Q,\n",
+ " controllers=[P_NPQ, E_PSII],\n",
+ " rate_law=energy_dissipation),\n",
+ " NaturalDegradation(\n",
+ " subject=Q).with_mass_action_rate_law('v_NPQ'),\n",
+ " NaturalProduction(\n",
+ " outcome=P_NPQ,\n",
+ " rate_law=sympy.Piecewise((safe_parse_expr('v_p*(1-P_NPQ)', local_dict=symbols),\n",
+ " CEF > sympy.Symbol('c_y')),\n",
+ " (0, True))),\n",
+ " NaturalConversion(\n",
+ " outcome=NADPH,\n",
+ " subject=NADPp,\n",
+ " rate_law=ETR*sympy.Symbol('eta_NADPp')),\n",
+ " ControlledConversion(\n",
+ " subject=NADPH,\n",
+ " outcome=NADPp,\n",
+ " controller=R,\n",
+ " rate_law=safe_parse_expr('v_C*R*NADPH*eta_NADPH', local_dict=symbols)),\n",
+ " NaturalProduction(\n",
+ " outcome=R,\n",
+ " rate_law=safe_parse_expr('v_R*(1-R)*min(d, NADPH/NADPp)', local_dict=symbols))\n",
+ "]\n",
+ "\n",
+ "observables = {\n",
+ " 'ETR': Observable(name='ETR', expression=ETR),\n",
+ " 'NPQ': Observable(name='NPQ', expression=sympy.Symbol('v_NPQ') * sympy.Symbol('Q')),\n",
+ " 'A': Observable(name='A', expression=sympy.Symbol('v_C')*sympy.Symbol('R')*sympy.Symbol('NADPH'))\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "ad2de988",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "parameters = {p: Parameter(name=p, value=v) for p, v in params.items()}\n",
+ "initials = {i: Initial(concept=Concept(name=i), expression=v) for i, v in inits.items()}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "596994c4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tm = TemplateModel(templates=templates,\n",
+ " parameters=parameters,\n",
+ " initials=initials,\n",
+ " observables=observables)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "9141c4a4",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "om = OdeModel(Model(tm), initialized=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "43e14dfe",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\left[\\begin{matrix}\\left(1 - \\frac{y_{0, 0}}{p_{3, 0}}\\right) p_{4, 0} p_{5, 0} p_{6, 0} - \\left(1 - \\frac{y_{3, 0}}{p_{7, 0}}\\right) p_{8, 0} y_{0, 0} y_{2, 0} - p_{0, 0} y_{0, 0} y_{1, 0}\\\\- p_{0, 0} p_{11, 0} y_{0, 0} y_{1, 0} + p_{2, 0} p_{12, 0} y_{4, 0} y_{5, 0}\\\\\\begin{cases} \\left(1 - y_{2, 0}\\right) p_{10, 0} & \\text{for}\\: p_{9, 0} < \\left(1 - \\frac{y_{0, 0}}{p_{3, 0}}\\right) p_{4, 0} p_{5, 0} p_{6, 0} - p_{0, 0} y_{0, 0} y_{1, 0} \\\\0 & \\text{otherwise} \\end{cases}\\\\\\left(1 - \\frac{y_{3, 0}}{p_{7, 0}}\\right) p_{8, 0} y_{0, 0} y_{2, 0} - p_{1, 0} y_{3, 0}\\\\p_{0, 0} p_{11, 0} y_{0, 0} y_{1, 0} - p_{2, 0} p_{12, 0} y_{4, 0} y_{5, 0}\\\\\\left(1 - y_{5, 0}\\right) p_{14, 0} \\min\\left(\\frac{y_{4, 0}}{y_{1, 0}}, p_{13, 0}\\right)\\end{matrix}\\right]$"
+ ],
+ "text/plain": [
+ "Matrix([\n",
+ "[ (1 - y[0, 0]/p[3, 0])*p[4, 0]*p[5, 0]*p[6, 0] - (1 - y[3, 0]/p[7, 0])*p[8, 0]*y[0, 0]*y[2, 0] - p[0, 0]*y[0, 0]*y[1, 0]],\n",
+ "[ -p[0, 0]*p[11, 0]*y[0, 0]*y[1, 0] + p[2, 0]*p[12, 0]*y[4, 0]*y[5, 0]],\n",
+ "[Piecewise(((1 - y[2, 0])*p[10, 0], p[9, 0] < (1 - y[0, 0]/p[3, 0])*p[4, 0]*p[5, 0]*p[6, 0] - p[0, 0]*y[0, 0]*y[1, 0]), (0, True))],\n",
+ "[ (1 - y[3, 0]/p[7, 0])*p[8, 0]*y[0, 0]*y[2, 0] - p[1, 0]*y[3, 0]],\n",
+ "[ p[0, 0]*p[11, 0]*y[0, 0]*y[1, 0] - p[2, 0]*p[12, 0]*y[4, 0]*y[5, 0]],\n",
+ "[ (1 - y[5, 0])*p[14, 0]*Min(y[4, 0]/y[1, 0], p[13, 0])]])"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "om.kinetics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "372acdf7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\left[\\begin{matrix}- E_{PSII} NADPp v_{ETR} - E_{PSII} P_{NPQ} v_{d} \\left(- \\frac{Q}{Q_{star}} + 1\\right) + PAR \\alpha c_{in} \\left(- \\frac{E_{PSII}}{E_{PSII star}} + 1\\right)\\\\- E_{PSII} NADPp \\eta_{NADPp} v_{ETR} + NADPH R \\eta_{NADPH} v_{C}\\\\\\begin{cases} v_{p} \\left(1 - P_{NPQ}\\right) & \\text{for}\\: c_{y} < - E_{PSII} NADPp v_{ETR} + PAR \\alpha c_{in} \\left(- \\frac{E_{PSII}}{E_{PSII star}} + 1\\right) \\\\0 & \\text{otherwise} \\end{cases}\\\\E_{PSII} P_{NPQ} v_{d} \\left(- \\frac{Q}{Q_{star}} + 1\\right) - Q v_{NPQ}\\\\E_{PSII} NADPp \\eta_{NADPp} v_{ETR} - NADPH R \\eta_{NADPH} v_{C}\\\\v_{R} \\left(1 - R\\right) \\min\\left(d, \\frac{NADPH}{NADPp}\\right)\\end{matrix}\\right]$"
+ ],
+ "text/plain": [
+ "Matrix([\n",
+ "[ -E_PSII*NADPp*v_ETR - E_PSII*P_NPQ*v_d*(-Q/Q_star + 1) + PAR*alpha*c_in*(-E_PSII/E_PSII_star + 1)],\n",
+ "[ -E_PSII*NADPp*eta_NADPp*v_ETR + NADPH*R*eta_NADPH*v_C],\n",
+ "[Piecewise((v_p*(1 - P_NPQ), c_y < -E_PSII*NADPp*v_ETR + PAR*alpha*c_in*(-E_PSII/E_PSII_star + 1)), (0, True))],\n",
+ "[ E_PSII*P_NPQ*v_d*(-Q/Q_star + 1) - Q*v_NPQ],\n",
+ "[ E_PSII*NADPp*eta_NADPp*v_ETR - NADPH*R*eta_NADPH*v_C],\n",
+ "[ v_R*(1 - R)*Min(d, NADPH/NADPp)]])"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "om.get_interpretable_kinetics()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "852ab828",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "({'E_PSII': 0, 'NADPp': 1, 'P_NPQ': 2, 'Q': 3, 'NADPH': 4, 'R': 5},\n",
+ " {'ETR': 0, 'NPQ': 1, 'A': 2})"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "om.vmap, om.observable_map"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "5cbe26d2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ts = numpy.linspace(0,60,1000)\n",
+ "res = simulate_ode_model(om, times=ts, with_observables=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "85d7a9dd",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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fXtmjLBarTCZTLBYLI3eXeNwOFBcXIycnBzodLooVRi7+PsjIiIiolhyumzQEC97IyIiIiKiuMDwQ0REREREcYHhh4iIiIiI4gLDDxERERERxQWGHyIiIiIiigsMP0REREREFBcYfoiIiIiIKC4w/BARERERUVxg+CEiIiIiorjA8ENERERERHGB4acLuf322yFJEhYtWhTW/tFHH0GSJADAd999B0mS5CktLQ1TpkzBwYMHw7b58ccfcdVVV6FHjx7Q6XQYMWIEnn32WXi93k77eYiIiIiIuhKGny5Gp9Ph6aefRlVV1Wn7FRYWorS0FO+//z5+/vlnXHPNNXKwWb16NS6++GL06dMH3377Lfbt24eHHnoITz75JG655RYIITrjRyEiIiIi6lIYfrqYvLw8pKenIz8//7T9UlNTkZGRgYsuuggLFizAnj17sH//fthsNkyfPh3//d//jWXLlmH06NHo168f7r77brz22mv44IMP8N5773XST0NERERE1HXER/gRAnDZOn9qwwiLUqnEU089heeffx5Hjx5t0TZ6vR4A4HK58NVXX+HkyZP4wx/+0KjfNddcg8GDB+Ptt99udV1ERERERLFOFe0COoXbDjyV2fnf+1gpoDG0erPrrrsOo0ePxsKFC7F8+fLT9i0rK8Pf/vY39O7dG0OGDMG///1vAMCwYcOa7D906FD88ssvra6JiIiIiCjWxcfITwx6+umn8dprr2Hv3r1Nru/Tpw8MBgMyMzNhs9nw4YcfQqPRyOtPd19PaD8iIiIiongRHyM/6gT/KEw0vreNLrroIkyaNAnz5s3D7bff3mj9999/D6PRiNTUVCQlJcntgwYNAgDs3bsX559/fqPt9u7di9GjR7e5LiIiIiKiWBXxkR+v14v58+cjJycHer0eAwYMwP/8z/+EjUQIIbBgwQJkZGRAr9cjLy8PRUVFkS6lniT5Lz/r7CnweOq2WrRoET799FNs2LCh0bqcnBwMGDAgLPgAwKRJk5CcnIy///3vjbb55JNPUFRU1GSYIiIiIiLq7iIefp5++mksWbIEL7zwAvbu3Yunn34azzzzDJ5//nm5zzPPPIPFixdj6dKl2LRpEwwGAyZNmgSHwxHpcmLaiBEjMHXqVCxevLjF2xgMBrz00kv4+OOPcc8992Dnzp04dOgQli9fjttvvx3Tp0/HVVdd1YFVExERERF1TREPPz/++COuvfZaXH311ejXrx9uuOEGXHHFFdi8eTMA/6jPc889hz/96U+49tprMXLkSLz++usoLS3FRx99FOlyYt4TTzwBn8/Xqm1uuOEGfPvttzhy5AguvPBC5OTk4O6778bcuXOxbNmyDqqUiIiIiKhri3j4Of/887F27Vr5iWI//fQTfvjhB/z6178GABQXF6O8vBx5eXnyNiaTCRMmTGjy8i4AcDqdsFqtYVN3tHLlykYBsF+/fnA6nfJlg5dccgmEEDCbzafd14UXXog1a9bAYrGgrq4OV1xxBVauXInjx493UPVERERERF1bxMPP3Llzccstt2Do0KFQq9UYM2YMZs2ahalTpwIAysvLAQBpaWlh26WlpcnrGsrPz4fJZJKnrKysSJfdrel0Onz88ce47bbbsH79+miXQ0REREQUFRF/2tt7772HVatW4a233sJZZ52FHTt2YNasWcjMzMS0adPatM958+Zhzpw58rLVamUAaiWdToe5c+dGuwwiIiIioqiJePj54x//KI/+AP6b9g8fPoz8/HxMmzYN6enpAICKigpkZGTI21VUVDT7CGatVgutVhvpUomIiIiIKI5E/LI3u90OhSJ8t0qlUr5pPycnB+np6Vi7dq283mq1YtOmTcjNzY10OURERERERAA6YOTnmmuuwV/+8hdkZ2fjrLPOwvbt2/Hss8/izjvvBABIkoRZs2bhySefxKBBg5CTk4P58+cjMzMTkydPjnQ5REREREREADog/Dz//POYP38+7r//flRWViIzMxO///3vsWDBArnPI488ApvNhnvuuQfV1dW44IILsGbNGuh0ukiXQ0REREQUl3w+AbfPB69PwOMT8HgFPMFlr7/N6/PB7RXw+gTc3qb7Btd7fD54gn19PmiUCtw4Lrbuw5dE8BnKMcRqtcJkMsFiscBoNIatczgcKC4uRk5ODsNUG/D3R0RERPFICFF/4u8T8Hj9oSB4wu/2+uAJBIRgcPA0aqvfRg4M3vA2T9j6ht/R+Pvk7/H6A0fYOvkzdP8+uAPrfB18lt8zUYOtf/pVx35JC5wuGzQU8ZEfIiIiIopvPp+AKxgMPD64vT64vPUn58F5t9fnX99MP/9yg37B+cC6YD+3VwS29QcEl9zug9tTHxw8IaGiYWiJB5IEqBUKKBUSVEoJKoUEpUIB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JydH1NXVRblyas59990nTCaT+O6770RZWZk82e12uc+9994rsrOzxTfffCO2bt0qcnNzRW5ubhSrpjOZO3euWLdunSguLhY7d+4Uc+fOFZIkia+++koIwWPaXYQ+7U0IHtdY9PDDD4vvvvtOFBcXi//85z8iLy9P9OzZU1RWVgoheExj0ebNm4VKpRJ/+ctfRFFRkVi1apVISEgQb775ptwn1s6XGH7a6fnnnxfZ2dlCo9GI8ePHi40bN0a7JGqhb7/9VgBoNE2bNk0I4X984/z580VaWprQarXi8ssvF4WFhdEtmk6rqeMJQKxYsULuU1dXJ+6//37Ro0cPkZCQIK677jpRVlYWvaLpjO68807Rt29fodFoRK9evcTll18uBx8heEy7i4bhh8c19tx8880iIyNDaDQa0bt3b3HzzTeL/fv3y+t5TGPTp59+Ks4++2yh1WrF0KFDxbJly8LWx9r5kiSEENEZcyIiIiIiIuo8vOeHiIiIiIjiAsMPERERERHFBYYfIiIiIiKKCww/REREREQUFxh+iIiIiIgoLjD8EBERERFRXGD4ISIiIiKiuMDwQ0REREREcYHhh4iIiIiI4gLDDxERERERxQWGHyIiIiIiigsMP0REREREFBf+P7VOCgmBKRw8AAAAAElFTkSuQmCC",
+ "text/plain": [
+ "