diff --git a/doc/examples/how_to_dmms/conditions.tsv b/doc/examples/how_to_dmms/conditions.tsv
new file mode 100644
index 0000000..da6fd62
--- /dev/null
+++ b/doc/examples/how_to_dmms/conditions.tsv
@@ -0,0 +1,3 @@
+conditionId
+cond1
+cond2
diff --git a/doc/examples/how_to_dmms/how_to_dmms.ipynb b/doc/examples/how_to_dmms/how_to_dmms.ipynb
new file mode 100644
index 0000000..8a27c7c
--- /dev/null
+++ b/doc/examples/how_to_dmms/how_to_dmms.ipynb
@@ -0,0 +1,562 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "b3339048-6d80-4eeb-befa-4bc1b3c468ec",
+ "metadata": {},
+ "source": [
+ "# How To: Deep Mechanistic Models"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d54f42a2-a31d-4fad-926a-b562ba26cc11",
+ "metadata": {},
+ "source": [
+ "This is the case where the outputs from a neural network are used as inputs to the ODE. In this case, using the Lotka-Voltera system as an example, the output from the network replaces the parameter $\\gamma$.\n",
+ "\n",
+ "$$\\frac{\\mathrm{d} \\text{prey}}{\\mathrm{d} t} = \\alpha \\cdot \\text{prey} - \\beta \\cdot \\text{prey} \\cdot \\text{predator}$$\n",
+ "\n",
+ "$$\\frac{\\mathrm{d} \\text{predator}}{\\mathrm{d} t} = \\text{NN}[0] \\cdot \\text{prey} \\cdot \\text{predator} - \\delta \\cdot \\text{predator}$$\n",
+ "\n",
+ "This example also demonstrates how array input data to the neural network for multiple conditions is handled."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "292488b8-24c6-43c9-9e88-5270fa0efb33",
+ "metadata": {},
+ "source": [
+ "## Loading the PEtab problem"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "79c7c39c-e010-4bfd-971f-70bf26c82d93",
+ "metadata": {},
+ "source": [
+ "Let's load the PEtab problem, build our model and define the overall hybrid problem as a ``JAXProblem``."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e9880e7f-a9dd-4a00-9ee1-5ed95eda9110",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from amici.petab import import_petab_problem\n",
+ "from amici.jax import (\n",
+ " JAXProblem,\n",
+ " run_simulations,\n",
+ ")\n",
+ "from petab.v2 import Problem\n",
+ "\n",
+ "# Create the PEtab problem\n",
+ "petab_problem = Problem.from_yaml(\"problem.yaml\")\n",
+ "\n",
+ "# Create AMICI model for the petab problem\n",
+ "jax_model = import_petab_problem(\n",
+ " petab_problem,\n",
+ " model_output_dir=\"model\",\n",
+ " compile_=True,\n",
+ " jax=True\n",
+ ")\n",
+ "\n",
+ "# Create the JAXProblem - wrapper for the AMICI model\n",
+ "jax_problem = JAXProblem(jax_model, petab_problem)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "da148931-f7ba-4b1b-850d-8c8754cd4ad9",
+ "metadata": {},
+ "source": [
+ "By looking at the hybridization, parameters and mapping tables we can see how this deep mechanistic modelling problem has been defined."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "7c1e0233-7e4b-411b-8ff7-ac57a2febf06",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " targetValue | \n",
+ "
\n",
+ " \n",
+ " | targetId | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | gamma | \n",
+ " net3_output1 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " targetValue\n",
+ "targetId \n",
+ "gamma net3_output1"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "jax_problem._petab_problem.hybridization_df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "38411614-bf14-4854-b655-5b29c3e345ec",
+ "metadata": {},
+ "source": [
+ "The ``gamma`` species from the model is mapped to a parameter with PEtab identifier ``net3_output1``. Looking at the mapping table, we can see that that PEtab id is defined as the first output from the neural network."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "832c8deb-927d-4189-b278-0bc8e5dfdfbd",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " modelEntityId | \n",
+ "
\n",
+ " \n",
+ " | petabEntityId | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | input0 | \n",
+ " net3.inputs[0] | \n",
+ "
\n",
+ " \n",
+ " | net3_output1 | \n",
+ " net3.outputs[0][0] | \n",
+ "
\n",
+ " \n",
+ " | net3_ps | \n",
+ " net3.parameters | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " modelEntityId\n",
+ "petabEntityId \n",
+ "input0 net3.inputs[0]\n",
+ "net3_output1 net3.outputs[0][0]\n",
+ "net3_ps net3.parameters"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "petab_problem.mapping_df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c999332c-e901-4f2c-877a-7ca482f75fdd",
+ "metadata": {},
+ "source": [
+ "Finally, in the parameters table, the network parameters are listed with infinite bounds and no nominal value, so that they are free to be optimised. Also note that $\\gamma$ does not appear in the parameters table, because we will set it with the neural network instead."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "3cb05448-ca2a-4fbc-92e8-9d6f1f8ff630",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " parameterScale | \n",
+ " lowerBound | \n",
+ " upperBound | \n",
+ " nominalValue | \n",
+ " estimate | \n",
+ "
\n",
+ " \n",
+ " | parameterId | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | alpha | \n",
+ " lin | \n",
+ " 0.0 | \n",
+ " 15.0 | \n",
+ " 1.3 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | delta | \n",
+ " lin | \n",
+ " 0.0 | \n",
+ " 15.0 | \n",
+ " 1.8 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | beta | \n",
+ " lin | \n",
+ " 0.0 | \n",
+ " 15.0 | \n",
+ " 0.9 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | net3_ps | \n",
+ " lin | \n",
+ " -inf | \n",
+ " inf | \n",
+ " NaN | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " parameterScale lowerBound upperBound nominalValue estimate\n",
+ "parameterId \n",
+ "alpha lin 0.0 15.0 1.3 1\n",
+ "delta lin 0.0 15.0 1.8 1\n",
+ "beta lin 0.0 15.0 0.9 1\n",
+ "net3_ps lin -inf inf NaN 1"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "petab_problem.parameter_df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bb0d08d2-088b-4850-96e2-d0c12e1605eb",
+ "metadata": {},
+ "source": [
+ "### Array input data\n",
+ "\n",
+ "The PEtab problem specified under ``extensions_config`` that there were two files of array data to be added to the problem:\n",
+ "- ``net3_ps.hdf5`` to set the values of the network parameters\n",
+ "- ``net3_input2.hdf5`` to provide the inputs into the network"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "c30ec3c9-6de5-403f-999d-cfe7020c6c69",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{\n",
+ " \"sciml\": {\n",
+ " \"array_files\": [\n",
+ " \"net3_ps.hdf5\",\n",
+ " \"net3_input2.hdf5\"\n",
+ " ],\n",
+ " \"hybridization_files\": [\n",
+ " \"hybridization.tsv\"\n",
+ " ],\n",
+ " \"neural_nets\": {\n",
+ " \"net3\": {\n",
+ " \"location\": \"net3.yaml\",\n",
+ " \"static\": true,\n",
+ " \"format\": \"YAML\"\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n"
+ ]
+ }
+ ],
+ "source": [
+ "import json # for pretty printing only\n",
+ "\n",
+ "print(json.dumps(petab_problem.extensions_config, indent=4))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3393b6c1-b193-4f64-8269-838c054bce97",
+ "metadata": {},
+ "source": [
+ "The nested structure of the neural network input file can be seen below. The input data to the neural network is under ``inputs/input0`` and data for two conditions is specified. The keys for the different conditions match those defined in the conditions table."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "87200584-39ec-4bb2-a4ee-919065598b65",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " inputs\n",
+ " input0\n",
+ " cond1\n",
+ " cond2\n",
+ " metadata\n",
+ " perm\n"
+ ]
+ }
+ ],
+ "source": [
+ "import h5py\n",
+ "\n",
+ "# Convenience function to show the nested structure of an HDF5 file\n",
+ "def show_h5_struct(file):\n",
+ " file.visit(lambda x: print(\" \" * (len(x.split(\"/\")) - 1), x.split(\"/\")[-1]))\n",
+ "\n",
+ "file = h5py.File(\"net3_input2.hdf5\")\n",
+ "show_h5_struct(file)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "78615c62-63c7-4b53-ab69-1a0cff91482d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " | conditionId | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | cond1 | \n",
+ "
\n",
+ " \n",
+ " | cond2 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ "Empty DataFrame\n",
+ "Columns: []\n",
+ "Index: [cond1, cond2]"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "petab_problem.condition_df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9c605a29-3fd7-4899-82e3-ed36a782fc7c",
+ "metadata": {},
+ "source": [
+ "Also note the ``static: true`` setting in the neural network definition of the extensions config. This means the input to the neural network is not expected to depend on the model. This keyword will indicate to PEtab SciML importers that the network precedes the ODE, as opposed to being inside it (i.e. a UDE) or in one of the observable formulae."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c6a998ed-e561-4025-8572-36d7d1eb350a",
+ "metadata": {},
+ "source": [
+ "### Network Architecture\n",
+ "\n",
+ "The PyTorch snippet below shows how a network architecture would be defined and exported to YAML format using PEtab SciML. The predefined YAML file is also provided in the PEtab SciML repo for completeness. We have used a convolution architecture here to indicate how the DMM problem set up could enable inclusion of information from high dimensional inputs in the mechanistic model. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "743ed691-5ceb-41b8-9255-6576bfcc3996",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from petab_sciml.standard.nn_model import Input, NNModel, NNModelStandard\n",
+ "import torch\n",
+ "from torch import nn\n",
+ "import torch.nn.functional as F\n",
+ "\n",
+ "class NeuralNetwork(nn.Module):\n",
+ " def __init__(self):\n",
+ " super().__init__()\n",
+ " self.layer1 = torch.nn.Conv2d(\n",
+ " 3, 1, (5, 5), stride=(1, 1), padding=(0, 0), dilation=(1, 1)\n",
+ " )\n",
+ " self.layer2 = torch.nn.Flatten()\n",
+ " self.layer3 = torch.nn.Linear(36, 1)\n",
+ "\n",
+ " def forward(self, net_input):\n",
+ " x = self.layer1(net_input)\n",
+ " x = self.layer2(x)\n",
+ " x = self.layer3(x)\n",
+ " x = F.relu(x)\n",
+ " return x\n",
+ "\n",
+ "net1 = NeuralNetwork()\n",
+ "nn_model1 = NNModel.from_pytorch_module(\n",
+ " module=net1, nn_model_id=\"net3\", inputs=[Input(input_id=\"input0\")]\n",
+ ")\n",
+ "NNModelStandard.save_data(\n",
+ " data=nn_model1, filename=\"net3_from_pytorch.yaml\"\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8b04d5fe-42f0-443b-b02d-38832b6523f6",
+ "metadata": {},
+ "source": [
+ "### Network inputs as parameters\n",
+ "\n",
+ "An alternative to defining network inputs as array data in files, is to define them in the parameters table, with appropriate bounds and nominal values. \n",
+ "\n",
+ "| parameterId | parameterScale | lowerBound | upperBound | nominalValue | estimate |\n",
+ "|-----------------|----------------|------------|------------|--------------|----------|\n",
+ "| net1_input_pre1 | lin | -inf | inf | 1 | 0 |\n",
+ "| net1_input_pre2 | lin | -inf | inf | 1 | 0 |\n",
+ "| | | | | | |\n",
+ "\n",
+ "And the corresponding mapping table to define the model entities for those PEtab identifiers.\n",
+ "\n",
+ "| petabEntityId | modelEntityId |\n",
+ "|-----------------|-------------------|\n",
+ "| net1_input_pre1 | net1.inputs[0][0] |\n",
+ "| net1_input_pre2 | net1.inputs[0][1] |"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/doc/examples/how_to_dmms/hybridization.tsv b/doc/examples/how_to_dmms/hybridization.tsv
new file mode 100644
index 0000000..8dc4719
--- /dev/null
+++ b/doc/examples/how_to_dmms/hybridization.tsv
@@ -0,0 +1,2 @@
+targetId targetValue
+gamma net3_output1
diff --git a/doc/examples/how_to_dmms/lv.xml b/doc/examples/how_to_dmms/lv.xml
new file mode 100644
index 0000000..3ec6640
--- /dev/null
+++ b/doc/examples/how_to_dmms/lv.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+ PEtab implementation of the simple model
+
+
+
+
+
+
+
+
+
+ Ognissanti
+ Damiano
+
+
+
+
+
+ 2022-08-19T11:46:48Z
+
+
+ 2022-08-19T11:46:48Z
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/examples/how_to_dmms/mapping.tsv b/doc/examples/how_to_dmms/mapping.tsv
new file mode 100644
index 0000000..f4aa306
--- /dev/null
+++ b/doc/examples/how_to_dmms/mapping.tsv
@@ -0,0 +1,4 @@
+petabEntityId modelEntityId
+input0 net3.inputs[0]
+net3_output1 net3.outputs[0][0]
+net3_ps net3.parameters
diff --git a/doc/examples/how_to_dmms/measurements.tsv b/doc/examples/how_to_dmms/measurements.tsv
new file mode 100644
index 0000000..3a2ab59
--- /dev/null
+++ b/doc/examples/how_to_dmms/measurements.tsv
@@ -0,0 +1,41 @@
+observableId simulationConditionId measurement time
+prey_o cond1 0.17301723066961405 1.0
+prey_o cond1 0.48917673783409993 2.0
+prey_o cond1 1.6439955318035595 3.0
+prey_o cond1 5.451962785760956 4.0
+prey_o cond1 2.977522019296872 5.0
+prey_o cond1 0.18166337921190132 6.0
+prey_o cond1 0.34811222588891116 7.0
+prey_o cond1 0.9379191086100471 8.0
+prey_o cond1 3.1132400328752725 9.0
+prey_o cond1 8.86393324304537 10.0
+predator_o cond1 0.8474159434933868 1.0
+predator_o cond1 0.21113451571705152 2.0
+predator_o cond1 -0.025053892754896945 3.0
+predator_o cond1 0.1250104939525384 4.0
+predator_o cond1 6.700454555504469 5.0
+predator_o cond1 2.0071582885977066 6.0
+predator_o cond1 0.4200924826891049 7.0
+predator_o cond1 0.048031851600281825 8.0
+predator_o cond1 0.128669393707342 9.0
+predator_o cond1 1.1927837762326177 10.0
+prey_o cond2 0.2219828904947475 1.0
+prey_o cond2 0.5276545477245373 2.0
+prey_o cond2 1.4489892769025072 3.0
+prey_o cond2 4.870854183709297 4.0
+prey_o cond2 1.4339315443619947 5.0
+prey_o cond2 0.20198520102077788 6.0
+prey_o cond2 0.35315037605528066 7.0
+prey_o cond2 0.9502200881229326 8.0
+prey_o cond2 3.4021902017878376 9.0
+prey_o cond2 4.8268184728460115 10.0
+predator_o cond2 0.9788999227307986 1.0
+predator_o cond2 0.24676970118818284 2.0
+predator_o cond2 0.0635336820792109 3.0
+predator_o cond2 0.250021606661362 4.0
+predator_o cond2 6.3573469863762835 5.0
+predator_o cond2 1.661922951387048 6.0
+predator_o cond2 0.355368743021419 7.0
+predator_o cond2 0.056211961187334625 8.0
+predator_o cond2 0.16872950412564128 9.0
+predator_o cond2 4.457131477744339 10.0
diff --git a/doc/examples/how_to_dmms/net3.yaml b/doc/examples/how_to_dmms/net3.yaml
new file mode 100644
index 0000000..7ffd123
--- /dev/null
+++ b/doc/examples/how_to_dmms/net3.yaml
@@ -0,0 +1,72 @@
+nn_model_id: net3
+inputs:
+- input_id: input0
+layers:
+- layer_id: layer1
+ layer_type: Conv2d
+ args:
+ stride:
+ - 1
+ - 1
+ padding:
+ - 0
+ - 0
+ dilation:
+ - 1
+ - 1
+ groups: 1
+ padding_mode: zeros
+ in_channels: 3
+ out_channels: 1
+ kernel_size:
+ - 5
+ - 5
+ bias: true
+- layer_id: layer2
+ layer_type: Flatten
+ args:
+ start_dim: 1
+ end_dim: -1
+- layer_id: layer3
+ layer_type: Linear
+ args:
+ in_features: 36
+ out_features: 1
+ bias: true
+forward:
+- name: net_input
+ op: placeholder
+ target: net_input
+ args: []
+ kwargs: {}
+- name: layer1
+ op: call_module
+ target: layer1
+ args:
+ - net_input
+ kwargs: {}
+- name: layer2
+ op: call_module
+ target: layer2
+ args:
+ - layer1
+ kwargs: {}
+- name: layer3
+ op: call_module
+ target: layer3
+ args:
+ - layer2
+ kwargs: {}
+- name: relu
+ op: call_function
+ target: relu
+ args:
+ - layer3
+ kwargs:
+ inplace: false
+- name: output
+ op: output
+ target: output
+ args:
+ - relu
+ kwargs: {}
diff --git a/doc/examples/how_to_dmms/net3_from_pytorch.yaml b/doc/examples/how_to_dmms/net3_from_pytorch.yaml
new file mode 100644
index 0000000..7ffd123
--- /dev/null
+++ b/doc/examples/how_to_dmms/net3_from_pytorch.yaml
@@ -0,0 +1,72 @@
+nn_model_id: net3
+inputs:
+- input_id: input0
+layers:
+- layer_id: layer1
+ layer_type: Conv2d
+ args:
+ stride:
+ - 1
+ - 1
+ padding:
+ - 0
+ - 0
+ dilation:
+ - 1
+ - 1
+ groups: 1
+ padding_mode: zeros
+ in_channels: 3
+ out_channels: 1
+ kernel_size:
+ - 5
+ - 5
+ bias: true
+- layer_id: layer2
+ layer_type: Flatten
+ args:
+ start_dim: 1
+ end_dim: -1
+- layer_id: layer3
+ layer_type: Linear
+ args:
+ in_features: 36
+ out_features: 1
+ bias: true
+forward:
+- name: net_input
+ op: placeholder
+ target: net_input
+ args: []
+ kwargs: {}
+- name: layer1
+ op: call_module
+ target: layer1
+ args:
+ - net_input
+ kwargs: {}
+- name: layer2
+ op: call_module
+ target: layer2
+ args:
+ - layer1
+ kwargs: {}
+- name: layer3
+ op: call_module
+ target: layer3
+ args:
+ - layer2
+ kwargs: {}
+- name: relu
+ op: call_function
+ target: relu
+ args:
+ - layer3
+ kwargs:
+ inplace: false
+- name: output
+ op: output
+ target: output
+ args:
+ - relu
+ kwargs: {}
diff --git a/doc/examples/how_to_dmms/net3_input2.hdf5 b/doc/examples/how_to_dmms/net3_input2.hdf5
new file mode 100644
index 0000000..ac76834
Binary files /dev/null and b/doc/examples/how_to_dmms/net3_input2.hdf5 differ
diff --git a/doc/examples/how_to_dmms/net3_ps.hdf5 b/doc/examples/how_to_dmms/net3_ps.hdf5
new file mode 100644
index 0000000..258ba97
Binary files /dev/null and b/doc/examples/how_to_dmms/net3_ps.hdf5 differ
diff --git a/doc/examples/how_to_dmms/observables.tsv b/doc/examples/how_to_dmms/observables.tsv
new file mode 100644
index 0000000..fc5f605
--- /dev/null
+++ b/doc/examples/how_to_dmms/observables.tsv
@@ -0,0 +1,3 @@
+observableId observableFormula noiseFormula observableTransformation noiseDistribution
+prey_o prey 0.05 lin normal
+predator_o predator 0.05 lin normal
diff --git a/doc/examples/how_to_dmms/parameters.tsv b/doc/examples/how_to_dmms/parameters.tsv
new file mode 100644
index 0000000..ecad86e
--- /dev/null
+++ b/doc/examples/how_to_dmms/parameters.tsv
@@ -0,0 +1,5 @@
+parameterId parameterScale lowerBound upperBound nominalValue estimate
+alpha lin 0.0 15.0 1.3 1
+delta lin 0.0 15.0 1.8 1
+beta lin 0.0 15.0 0.9 1
+net3_ps lin -inf inf 1
diff --git a/doc/examples/how_to_dmms/problem.yaml b/doc/examples/how_to_dmms/problem.yaml
new file mode 100644
index 0000000..1ddb698
--- /dev/null
+++ b/doc/examples/how_to_dmms/problem.yaml
@@ -0,0 +1,27 @@
+problems:
+ - model_files:
+ lv:
+ location: "lv.xml"
+ language: "sbml"
+ measurement_files:
+ - "measurements.tsv"
+ observable_files:
+ - "observables.tsv"
+ condition_files:
+ - "conditions.tsv"
+ mapping_files:
+ - "mapping.tsv"
+format_version: 2.0.0
+extensions:
+ sciml:
+ array_files:
+ - "net3_ps.hdf5"
+ - "net3_input2.hdf5"
+ hybridization_files:
+ - "hybridization.tsv"
+ neural_nets:
+ net3:
+ location: "net3.yaml"
+ static: true
+ format: "YAML"
+parameter_file: "parameters.tsv"
diff --git a/doc/examples/how_to_neural_ode/conditions.tsv b/doc/examples/how_to_neural_ode/conditions.tsv
new file mode 100644
index 0000000..fdcc030
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/conditions.tsv
@@ -0,0 +1,2 @@
+conditionId
+cond1
diff --git a/doc/examples/how_to_neural_ode/how_to_neural_ode.ipynb b/doc/examples/how_to_neural_ode/how_to_neural_ode.ipynb
new file mode 100644
index 0000000..00cf0c9
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/how_to_neural_ode.ipynb
@@ -0,0 +1,427 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "85e61efa-c382-4fcd-a649-19aff93f7309",
+ "metadata": {},
+ "source": [
+ "# How To: Neural ODE"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e2ae1512-526e-4287-82a8-f95234bc5f84",
+ "metadata": {},
+ "source": [
+ "In the Neural ODE case, the whole RHS of each equation is replaced with a network. So the Lotka-Voltera system,\n",
+ "\n",
+ "$$\\frac{\\mathrm{d} \\text{prey}}{\\mathrm{d} t} = \\alpha \\cdot \\text{prey} - \\beta \\cdot \\text{prey} \\cdot \\text{predator}$$\n",
+ "\n",
+ "$$\\frac{\\mathrm{d} \\text{predator}}{\\mathrm{d} t} = \\gamma \\cdot \\text{prey} \\cdot \\text{predator} - \\delta \\cdot \\text{predator}$$\n",
+ "\n",
+ "simply becomes,\n",
+ "\n",
+ "$$\\frac{\\mathrm{d} \\text{prey}}{\\mathrm{d} t} = \\text{NN}(\\text{prey}, \\text{predator})[0]$$\n",
+ "\n",
+ "$$\\frac{\\mathrm{d} \\text{predator}}{\\mathrm{d} t} = \\text{NN}(\\text{prey}, \\text{predator})[1]$$\n",
+ "\n",
+ "In the SBML model the species ``prey`` and ``predator`` are defined as these will be used as inputs to the neural network. Also two parameters $\\alpha$ and $\\delta$ are defined. These will be mapped to neural network outputs in the PEtab files."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a706dd6a-98c8-493b-b73e-a4173af450cd",
+ "metadata": {},
+ "source": [
+ "## Defining the network architecture"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "c1d328c2-8032-4ab8-9fe6-fd2e74622a61",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from petab_sciml.standard.nn_model import Input, NNModel, NNModelStandard\n",
+ "import torch\n",
+ "from torch import nn\n",
+ "import torch.nn.functional as F\n",
+ "\n",
+ "class NeuralNetwork(nn.Module):\n",
+ " def __init__(self):\n",
+ " super().__init__()\n",
+ " self.layer1 = torch.nn.Linear(2, 5)\n",
+ " self.layer2 = torch.nn.Linear(5, 5)\n",
+ " self.layer3 = torch.nn.Linear(5, 1)\n",
+ "\n",
+ " def forward(self, net_input):\n",
+ " x = self.layer1(net_input)\n",
+ " x = F.sigmoid(x)\n",
+ " x = self.layer2(x)\n",
+ " x = F.sigmoid(x)\n",
+ " x = self.layer3(x)\n",
+ " return x\n",
+ "\n",
+ "net1 = NeuralNetwork()\n",
+ "nn_model1 = NNModel.from_pytorch_module(\n",
+ " module=net1, nn_model_id=\"net1\", inputs=[Input(input_id=\"input0\")]\n",
+ ")\n",
+ "NNModelStandard.save_data(\n",
+ " data=nn_model1, filename=\"net1.yaml\"\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "320f12b5-8b91-42c4-ab26-0e9977746e47",
+ "metadata": {},
+ "source": [
+ "The network architecture in this example is kept simple for demonstration purposes. Refer to the page on supported layers and activation functions for more inspiration, but note that PEtab SciML and its importers currently only support networks with vector outputs. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "56e1044a-da75-4766-a063-db803c64962b",
+ "metadata": {},
+ "source": [
+ "## Generating the PEtab files\n",
+ "\n",
+ "The PEtab SciML python package provides utility functions to generate the model and PEtab files for a neural ODE case. The names of the species in the ODE system are required to generate the model. The utility functions will generate hybridization, mapping and parameter files. The measurement, observable and array input files need to be supplied by the user to fully define the PEtab problem. These files are included in the docs as a demonstration. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "47c89dd2-822d-465c-bc15-3406aa91a59f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from petab_sciml.problem_utils.neural_ode import (\n",
+ " create_neural_ode, \n",
+ " create_neural_ode_problem\n",
+ ")\n",
+ "\n",
+ "create_neural_ode([\"prey\", \"predator\"], model_filename=\"lv.xml\")\n",
+ "create_neural_ode_problem(\n",
+ " \"lv.xml\", \n",
+ " \"measurements.tsv\", \n",
+ " \"observables.tsv\", \n",
+ " \"net1.yaml\", \n",
+ " [\"net1_ps.hdf5\"]\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d6af94a7-08fe-456b-a91b-6f326f2e286e",
+ "metadata": {},
+ "source": [
+ "## Loading the PEtab problem"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "37db1309-2d0d-47c6-ba23-8b513db2a128",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "from amici.petab import import_petab_problem\n",
+ "from amici.jax import (\n",
+ " JAXProblem,\n",
+ " run_simulations,\n",
+ ")\n",
+ "from petab.v2 import Problem\n",
+ "\n",
+ "# Create the PEtab problem\n",
+ "petab_problem = Problem.from_yaml(\"problem.yaml\")\n",
+ "\n",
+ "# Create AMICI model for the petab problem\n",
+ "jax_model = import_petab_problem(\n",
+ " petab_problem,\n",
+ " model_output_dir=\"model\",\n",
+ " compile_=True,\n",
+ " jax=True\n",
+ ")\n",
+ "\n",
+ "# Create the JAXProblem - wrapper for the AMICI model\n",
+ "jax_problem = JAXProblem(jax_model, petab_problem)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b8ab3aa8-a5dc-498e-9457-34e3e0d5bcec",
+ "metadata": {},
+ "source": [
+ "The hybridization and mapping tables show us how the neural network inputs and outputs are mapped to the model."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "c33ade41-69d5-4b7c-8e4c-6f06137c017a",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " targetValue | \n",
+ "
\n",
+ " \n",
+ " | targetId | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | net1_input0 | \n",
+ " prey | \n",
+ "
\n",
+ " \n",
+ " | net1_input1 | \n",
+ " predator | \n",
+ "
\n",
+ " \n",
+ " | prey_param | \n",
+ " net1_output0 | \n",
+ "
\n",
+ " \n",
+ " | predator_param | \n",
+ " net1_output1 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " targetValue\n",
+ "targetId \n",
+ "net1_input0 prey\n",
+ "net1_input1 predator\n",
+ "prey_param net1_output0\n",
+ "predator_param net1_output1"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "jax_problem._petab_problem.hybridization_df"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "0b42b898-b3a9-4163-9847-d40170f18835",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " modelEntityId | \n",
+ "
\n",
+ " \n",
+ " | petabEntityId | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | net1_input0 | \n",
+ " net1.inputs[0][0] | \n",
+ "
\n",
+ " \n",
+ " | net1_input1 | \n",
+ " net1.inputs[0][1] | \n",
+ "
\n",
+ " \n",
+ " | net1_output0 | \n",
+ " net1.outputs[0][0] | \n",
+ "
\n",
+ " \n",
+ " | net1_output1 | \n",
+ " net1.outputs[0][1] | \n",
+ "
\n",
+ " \n",
+ " | net1_ps | \n",
+ " net1.parameters | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " modelEntityId\n",
+ "petabEntityId \n",
+ "net1_input0 net1.inputs[0][0]\n",
+ "net1_input1 net1.inputs[0][1]\n",
+ "net1_output0 net1.outputs[0][0]\n",
+ "net1_output1 net1.outputs[0][1]\n",
+ "net1_ps net1.parameters"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "petab_problem.mapping_df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "736d0ff5-a4b3-427b-a2e4-ccd3516a60bf",
+ "metadata": {},
+ "source": [
+ "The inputs to the neural network are given by the ``prey`` and ``predator`` species. $\\alpha$, the ``prey`` concentration over time as defined by the SBML model, is given by the first output of the network. $\\delta$, the ``predator`` concentration over time, is given by the second output of the network."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c134e21c-1654-4ec8-a5ec-e3a3be337314",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "It is also worth showing that the parameter table only has the network parameters defined in it. Unlike previous examples, there are no other parameters to be estimated in the problem. We will optimise the network parameters and then the outputs of the network will give us the solution to our ODEs."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "53d584e2-b3c5-485c-a648-7139a6f4c4ca",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " parameterScale | \n",
+ " lowerBound | \n",
+ " upperBound | \n",
+ " nominalValue | \n",
+ " estimate | \n",
+ "
\n",
+ " \n",
+ " | parameterId | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | net1_ps | \n",
+ " lin | \n",
+ " -inf | \n",
+ " inf | \n",
+ " NaN | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " parameterScale lowerBound upperBound nominalValue estimate\n",
+ "parameterId \n",
+ "net1_ps lin -inf inf NaN 1"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "petab_problem.parameter_df"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/doc/examples/how_to_neural_ode/hybridization.tsv b/doc/examples/how_to_neural_ode/hybridization.tsv
new file mode 100644
index 0000000..e031c89
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/hybridization.tsv
@@ -0,0 +1,5 @@
+targetId targetValue
+net1_input0 prey
+net1_input1 predator
+prey_param net1_output0
+predator_param net1_output1
diff --git a/doc/examples/how_to_neural_ode/lv.xml b/doc/examples/how_to_neural_ode/lv.xml
new file mode 100644
index 0000000..e014704
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/lv.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/examples/how_to_neural_ode/mapping.tsv b/doc/examples/how_to_neural_ode/mapping.tsv
new file mode 100644
index 0000000..f941d67
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/mapping.tsv
@@ -0,0 +1,6 @@
+petabEntityId modelEntityId
+net1_input0 net1.inputs[0][0]
+net1_input1 net1.inputs[0][1]
+net1_output0 net1.outputs[0][0]
+net1_output1 net1.outputs[0][1]
+net1_ps net1.parameters
diff --git a/doc/examples/how_to_neural_ode/measurements.tsv b/doc/examples/how_to_neural_ode/measurements.tsv
new file mode 100644
index 0000000..3721571
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/measurements.tsv
@@ -0,0 +1,21 @@
+observableId simulationConditionId measurement time
+prey_o cond1 0.17301723066954827 1.0
+prey_o cond1 0.48917673783383914 2.0
+prey_o cond1 1.643995531803569 3.0
+prey_o cond1 5.45196278566626 4.0
+prey_o cond1 2.9775220192442062 5.0
+prey_o cond1 0.18166337927167636 6.0
+prey_o cond1 0.3481122259853288 7.0
+prey_o cond1 0.9379191088947356 8.0
+prey_o cond1 3.113240033804055 9.0
+prey_o cond1 8.863933242141234 10.0
+predator_o cond1 0.8474159434934865 1.0
+predator_o cond1 0.2111345157163205 2.0
+predator_o cond1 -0.025053892755649274 3.0
+predator_o cond1 0.12501049397609923 4.0
+predator_o cond1 6.700454554758639 5.0
+predator_o cond1 2.007158288516007 6.0
+predator_o cond1 0.42009248269510124 7.0
+predator_o cond1 0.04803185161440934 8.0
+predator_o cond1 0.12866939374360575 9.0
+predator_o cond1 1.192783778293036 10.0
diff --git a/doc/examples/how_to_neural_ode/net1.yaml b/doc/examples/how_to_neural_ode/net1.yaml
new file mode 100644
index 0000000..4b28a93
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/net1.yaml
@@ -0,0 +1,64 @@
+nn_model_id: net1
+inputs:
+- input_id: input0
+layers:
+- layer_id: layer1
+ layer_type: Linear
+ args:
+ in_features: 2
+ out_features: 5
+ bias: true
+- layer_id: layer2
+ layer_type: Linear
+ args:
+ in_features: 5
+ out_features: 5
+ bias: true
+- layer_id: layer3
+ layer_type: Linear
+ args:
+ in_features: 5
+ out_features: 1
+ bias: true
+forward:
+- name: net_input
+ op: placeholder
+ target: net_input
+ args: []
+ kwargs: {}
+- name: layer1
+ op: call_module
+ target: layer1
+ args:
+ - net_input
+ kwargs: {}
+- name: sigmoid
+ op: call_method
+ target: sigmoid
+ args:
+ - layer1
+ kwargs: {}
+- name: layer2
+ op: call_module
+ target: layer2
+ args:
+ - sigmoid
+ kwargs: {}
+- name: sigmoid_1
+ op: call_method
+ target: sigmoid
+ args:
+ - layer2
+ kwargs: {}
+- name: layer3
+ op: call_module
+ target: layer3
+ args:
+ - sigmoid_1
+ kwargs: {}
+- name: output
+ op: output
+ target: output
+ args:
+ - layer3
+ kwargs: {}
diff --git a/doc/examples/how_to_neural_ode/net1_ps.hdf5 b/doc/examples/how_to_neural_ode/net1_ps.hdf5
new file mode 100644
index 0000000..84b0490
Binary files /dev/null and b/doc/examples/how_to_neural_ode/net1_ps.hdf5 differ
diff --git a/doc/examples/how_to_neural_ode/observables.tsv b/doc/examples/how_to_neural_ode/observables.tsv
new file mode 100644
index 0000000..fc5f605
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/observables.tsv
@@ -0,0 +1,3 @@
+observableId observableFormula noiseFormula observableTransformation noiseDistribution
+prey_o prey 0.05 lin normal
+predator_o predator 0.05 lin normal
diff --git a/doc/examples/how_to_neural_ode/parameters.tsv b/doc/examples/how_to_neural_ode/parameters.tsv
new file mode 100644
index 0000000..07910d8
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/parameters.tsv
@@ -0,0 +1,2 @@
+parameterId parameterScale lowerBound upperBound nominalValue estimate
+net1_ps lin -inf inf 1
diff --git a/doc/examples/how_to_neural_ode/problem.yaml b/doc/examples/how_to_neural_ode/problem.yaml
new file mode 100644
index 0000000..1804dfa
--- /dev/null
+++ b/doc/examples/how_to_neural_ode/problem.yaml
@@ -0,0 +1,26 @@
+problems:
+ - model_files:
+ model:
+ location: lv.xml
+ language: sbml
+ measurement_files:
+ - measurements.tsv
+ observable_files:
+ - observables.tsv
+ condition_files:
+ - conditions.tsv
+ mapping_files:
+ - mapping.tsv
+format_version: 2.0.0
+extensions:
+ sciml:
+ array_files:
+ - net1_ps.hdf5
+ hybridization_files:
+ - hybridization.tsv
+ neural_nets:
+ net1:
+ location: net1.yaml
+ static: false
+ format: YAML
+parameter_file: parameters.tsv
diff --git a/doc/examples/how_to_observable/conditions.tsv b/doc/examples/how_to_observable/conditions.tsv
new file mode 100644
index 0000000..fdcc030
--- /dev/null
+++ b/doc/examples/how_to_observable/conditions.tsv
@@ -0,0 +1,2 @@
+conditionId
+cond1
diff --git a/doc/examples/how_to_observable/how_to_observable.ipynb b/doc/examples/how_to_observable/how_to_observable.ipynb
new file mode 100644
index 0000000..16a1dc8
--- /dev/null
+++ b/doc/examples/how_to_observable/how_to_observable.ipynb
@@ -0,0 +1,466 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "81cd17cb-2d7f-4d74-a63f-e6ff16ec8319",
+ "metadata": {},
+ "source": [
+ "# How To: Neural networks in the observables\n",
+ "\n",
+ "This is the case where a neural network appears in an observable formula. The SBML model for the Lotka-Voltera system would be:\n",
+ "\n",
+ "$$\\frac{\\mathrm{d} \\text{prey}}{\\mathrm{d} t} = \\alpha \\cdot \\text{prey} - \\beta \\cdot \\text{prey} \\cdot \\text{predator}$$\n",
+ "\n",
+ "$$\\frac{\\mathrm{d} \\text{predator}}{\\mathrm{d} t} = \\gamma \\cdot \\text{prey} \\cdot \\text{predator} - \\delta \\cdot \\text{predator}$$\n",
+ "\n",
+ "No species in these expressions are substituted. Instead it is all accomplished in the PEtab files."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "51c1a0d5-102f-46a4-821d-28f58bc4be48",
+ "metadata": {},
+ "source": [
+ "## Loading the PEtab problem"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d810c818-7914-4e3f-acbf-9596fe4cbfda",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from amici.petab import import_petab_problem\n",
+ "from amici.jax import (\n",
+ " JAXProblem,\n",
+ " run_simulations,\n",
+ ")\n",
+ "from petab.v2 import Problem\n",
+ "\n",
+ "# Create the PEtab problem\n",
+ "petab_problem = Problem.from_yaml(\"problem.yaml\")\n",
+ "\n",
+ "# Create AMICI model for the petab problem\n",
+ "jax_model = import_petab_problem(\n",
+ " petab_problem,\n",
+ " model_output_dir=\"model\",\n",
+ " compile_=True,\n",
+ " jax=True\n",
+ ")\n",
+ "\n",
+ "# Create the JAXProblem - wrapper for the AMICI model\n",
+ "jax_problem = JAXProblem(jax_model, petab_problem)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "d44cbd06-a3fe-4984-86dc-d5a48c7718c5",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " observableFormula | \n",
+ " noiseFormula | \n",
+ " observableTransformation | \n",
+ " noiseDistribution | \n",
+ "
\n",
+ " \n",
+ " | observableId | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | prey_o | \n",
+ " net1_output1 | \n",
+ " 0.05 | \n",
+ " lin | \n",
+ " normal | \n",
+ "
\n",
+ " \n",
+ " | predator_o | \n",
+ " predator | \n",
+ " 0.05 | \n",
+ " lin | \n",
+ " normal | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " observableFormula noiseFormula observableTransformation \\\n",
+ "observableId \n",
+ "prey_o net1_output1 0.05 lin \n",
+ "predator_o predator 0.05 lin \n",
+ "\n",
+ " noiseDistribution \n",
+ "observableId \n",
+ "prey_o normal \n",
+ "predator_o normal "
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "petab_problem.observable_df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "618ca834-e138-4189-bf93-16c46c5daa7a",
+ "metadata": {},
+ "source": [
+ "We can see here that the formula for the ``prey`` observable is defined by a PEtab identifier indicating a network output. The model definition of that PEtab id can be found in the mapping table. It is given by the first output of the neural network."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "217954a4-3488-4f23-9a8e-15ca29ca5a08",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " modelEntityId | \n",
+ "
\n",
+ " \n",
+ " | petabEntityId | \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | net1_input1 | \n",
+ " net1.inputs[0][0] | \n",
+ "
\n",
+ " \n",
+ " | net1_input2 | \n",
+ " net1.inputs[0][1] | \n",
+ "
\n",
+ " \n",
+ " | net1_output1 | \n",
+ " net1.outputs[0][0] | \n",
+ "
\n",
+ " \n",
+ " | net1_ps | \n",
+ " net1.parameters | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " modelEntityId\n",
+ "petabEntityId \n",
+ "net1_input1 net1.inputs[0][0]\n",
+ "net1_input2 net1.inputs[0][1]\n",
+ "net1_output1 net1.outputs[0][0]\n",
+ "net1_ps net1.parameters"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "petab_problem.mapping_df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8b8e370f-49ea-40e3-93b2-b3c7c4a74f48",
+ "metadata": {},
+ "source": [
+ "Wherever the problem formulation refers to the prey observable (``prey_o``) the neural network will be evaluated and its output used in place of that observable value, for instance, in the measurements table."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "e1fac571-1ad7-4acc-9fb6-c43b06e6d53d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " observableId | \n",
+ " simulationConditionId | \n",
+ " measurement | \n",
+ " time | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 0.173017 | \n",
+ " 1.0 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 0.489177 | \n",
+ " 2.0 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 1.643996 | \n",
+ " 3.0 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 5.451963 | \n",
+ " 4.0 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 2.977522 | \n",
+ " 5.0 | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 0.181663 | \n",
+ " 6.0 | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 0.348112 | \n",
+ " 7.0 | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 0.937919 | \n",
+ " 8.0 | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 3.113240 | \n",
+ " 9.0 | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " prey_o | \n",
+ " cond1 | \n",
+ " 8.863933 | \n",
+ " 10.0 | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 0.847416 | \n",
+ " 1.0 | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 0.211135 | \n",
+ " 2.0 | \n",
+ "
\n",
+ " \n",
+ " | 12 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " -0.025054 | \n",
+ " 3.0 | \n",
+ "
\n",
+ " \n",
+ " | 13 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 0.125010 | \n",
+ " 4.0 | \n",
+ "
\n",
+ " \n",
+ " | 14 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 6.700455 | \n",
+ " 5.0 | \n",
+ "
\n",
+ " \n",
+ " | 15 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 2.007158 | \n",
+ " 6.0 | \n",
+ "
\n",
+ " \n",
+ " | 16 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 0.420092 | \n",
+ " 7.0 | \n",
+ "
\n",
+ " \n",
+ " | 17 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 0.048032 | \n",
+ " 8.0 | \n",
+ "
\n",
+ " \n",
+ " | 18 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 0.128669 | \n",
+ " 9.0 | \n",
+ "
\n",
+ " \n",
+ " | 19 | \n",
+ " predator_o | \n",
+ " cond1 | \n",
+ " 1.192784 | \n",
+ " 10.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " observableId simulationConditionId measurement time\n",
+ "0 prey_o cond1 0.173017 1.0\n",
+ "1 prey_o cond1 0.489177 2.0\n",
+ "2 prey_o cond1 1.643996 3.0\n",
+ "3 prey_o cond1 5.451963 4.0\n",
+ "4 prey_o cond1 2.977522 5.0\n",
+ "5 prey_o cond1 0.181663 6.0\n",
+ "6 prey_o cond1 0.348112 7.0\n",
+ "7 prey_o cond1 0.937919 8.0\n",
+ "8 prey_o cond1 3.113240 9.0\n",
+ "9 prey_o cond1 8.863933 10.0\n",
+ "10 predator_o cond1 0.847416 1.0\n",
+ "11 predator_o cond1 0.211135 2.0\n",
+ "12 predator_o cond1 -0.025054 3.0\n",
+ "13 predator_o cond1 0.125010 4.0\n",
+ "14 predator_o cond1 6.700455 5.0\n",
+ "15 predator_o cond1 2.007158 6.0\n",
+ "16 predator_o cond1 0.420092 7.0\n",
+ "17 predator_o cond1 0.048032 8.0\n",
+ "18 predator_o cond1 0.128669 9.0\n",
+ "19 predator_o cond1 1.192784 10.0"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "petab_problem.measurement_df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "261867c9-48a2-4310-ac0a-e52ae2012e85",
+ "metadata": {},
+ "source": [
+ "It is worth noting that the PEtab standard supports mathematical expressions in the observables table. For instance, instead of `net1_output1`, we could write `sum(net1_output1) + 2` in its place and PEtab importers would duly perform that arithmetic. "
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/doc/examples/how_to_observable/hybridization.tsv b/doc/examples/how_to_observable/hybridization.tsv
new file mode 100644
index 0000000..ccfd3d7
--- /dev/null
+++ b/doc/examples/how_to_observable/hybridization.tsv
@@ -0,0 +1,3 @@
+targetId targetValue
+net1_input1 prey
+net1_input2 predator
diff --git a/doc/examples/how_to_observable/lv.xml b/doc/examples/how_to_observable/lv.xml
new file mode 100644
index 0000000..3ec6640
--- /dev/null
+++ b/doc/examples/how_to_observable/lv.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+ PEtab implementation of the simple model
+
+
+
+
+
+
+
+
+
+ Ognissanti
+ Damiano
+
+
+
+
+
+ 2022-08-19T11:46:48Z
+
+
+ 2022-08-19T11:46:48Z
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/examples/how_to_observable/mapping.tsv b/doc/examples/how_to_observable/mapping.tsv
new file mode 100644
index 0000000..767a48a
--- /dev/null
+++ b/doc/examples/how_to_observable/mapping.tsv
@@ -0,0 +1,5 @@
+petabEntityId modelEntityId
+net1_input1 net1.inputs[0][0]
+net1_input2 net1.inputs[0][1]
+net1_output1 net1.outputs[0][0]
+net1_ps net1.parameters
diff --git a/doc/examples/how_to_observable/measurements.tsv b/doc/examples/how_to_observable/measurements.tsv
new file mode 100644
index 0000000..3721571
--- /dev/null
+++ b/doc/examples/how_to_observable/measurements.tsv
@@ -0,0 +1,21 @@
+observableId simulationConditionId measurement time
+prey_o cond1 0.17301723066954827 1.0
+prey_o cond1 0.48917673783383914 2.0
+prey_o cond1 1.643995531803569 3.0
+prey_o cond1 5.45196278566626 4.0
+prey_o cond1 2.9775220192442062 5.0
+prey_o cond1 0.18166337927167636 6.0
+prey_o cond1 0.3481122259853288 7.0
+prey_o cond1 0.9379191088947356 8.0
+prey_o cond1 3.113240033804055 9.0
+prey_o cond1 8.863933242141234 10.0
+predator_o cond1 0.8474159434934865 1.0
+predator_o cond1 0.2111345157163205 2.0
+predator_o cond1 -0.025053892755649274 3.0
+predator_o cond1 0.12501049397609923 4.0
+predator_o cond1 6.700454554758639 5.0
+predator_o cond1 2.007158288516007 6.0
+predator_o cond1 0.42009248269510124 7.0
+predator_o cond1 0.04803185161440934 8.0
+predator_o cond1 0.12866939374360575 9.0
+predator_o cond1 1.192783778293036 10.0
diff --git a/doc/examples/how_to_observable/net1.yaml b/doc/examples/how_to_observable/net1.yaml
new file mode 100644
index 0000000..01b1003
--- /dev/null
+++ b/doc/examples/how_to_observable/net1.yaml
@@ -0,0 +1,64 @@
+nn_model_id: net1
+inputs:
+- input_id: input0
+layers:
+- layer_id: layer1
+ layer_type: Linear
+ args:
+ in_features: 2
+ out_features: 5
+ bias: true
+- layer_id: layer2
+ layer_type: Linear
+ args:
+ in_features: 5
+ out_features: 5
+ bias: true
+- layer_id: layer3
+ layer_type: Linear
+ args:
+ in_features: 5
+ out_features: 1
+ bias: true
+forward:
+- name: net_input
+ op: placeholder
+ target: net_input
+ args: []
+ kwargs: {}
+- name: layer1
+ op: call_module
+ target: layer1
+ args:
+ - net_input
+ kwargs: {}
+- name: tanh
+ op: call_method
+ target: tanh
+ args:
+ - layer1
+ kwargs: {}
+- name: layer2
+ op: call_module
+ target: layer2
+ args:
+ - tanh
+ kwargs: {}
+- name: tanh_1
+ op: call_method
+ target: tanh
+ args:
+ - layer2
+ kwargs: {}
+- name: layer3
+ op: call_module
+ target: layer3
+ args:
+ - tanh_1
+ kwargs: {}
+- name: output
+ op: output
+ target: output
+ args:
+ - layer3
+ kwargs: {}
diff --git a/doc/examples/how_to_observable/net1_ps.hdf5 b/doc/examples/how_to_observable/net1_ps.hdf5
new file mode 100644
index 0000000..d1318c0
Binary files /dev/null and b/doc/examples/how_to_observable/net1_ps.hdf5 differ
diff --git a/doc/examples/how_to_observable/observables.tsv b/doc/examples/how_to_observable/observables.tsv
new file mode 100644
index 0000000..3213df8
--- /dev/null
+++ b/doc/examples/how_to_observable/observables.tsv
@@ -0,0 +1,3 @@
+observableId observableFormula noiseFormula observableTransformation noiseDistribution
+prey_o net1_output1 0.05 lin normal
+predator_o predator 0.05 lin normal
diff --git a/doc/examples/how_to_observable/parameters.tsv b/doc/examples/how_to_observable/parameters.tsv
new file mode 100644
index 0000000..609676d
--- /dev/null
+++ b/doc/examples/how_to_observable/parameters.tsv
@@ -0,0 +1,6 @@
+parameterId parameterScale lowerBound upperBound nominalValue estimate
+alpha lin 0.0 15.0 1.3 1
+delta lin 0.0 15.0 1.8 1
+beta lin 0.0 15.0 0.9 1
+gamma lin 0.0 15.0 0.8 1
+net1_ps lin -inf inf 1
diff --git a/doc/examples/how_to_observable/problem.yaml b/doc/examples/how_to_observable/problem.yaml
new file mode 100644
index 0000000..c24db02
--- /dev/null
+++ b/doc/examples/how_to_observable/problem.yaml
@@ -0,0 +1,26 @@
+problems:
+ - model_files:
+ lv:
+ location: "lv.xml"
+ language: "sbml"
+ measurement_files:
+ - "measurements.tsv"
+ observable_files:
+ - "observables.tsv"
+ condition_files:
+ - "conditions.tsv"
+ mapping_files:
+ - "mapping.tsv"
+format_version: 2.0.0
+extensions:
+ sciml:
+ array_files:
+ - "net1_ps.hdf5"
+ hybridization_files:
+ - "hybridization.tsv"
+ neural_nets:
+ net1:
+ location: "net1.yaml"
+ static: false
+ format: "YAML"
+parameter_file: "parameters.tsv"
diff --git a/doc/index.rst b/doc/index.rst
index 4ad82dd..6dbff0a 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -11,6 +11,14 @@ PEtab SciML - Scientific Machine Learning Format and Tooling
Introduction
Getting Started
+.. toctree::
+ :maxdepth: 3
+ :caption: How To Guides
+
+ Deep Mechanistic Models
+ Observable Formulae
+ Neural ODE
+
.. toctree::
:caption: PEtab SciML file format
:maxdepth: 3