diff --git a/documentation/example_large_models b/documentation/example_large_models new file mode 120000 index 0000000000..bddb4a0383 --- /dev/null +++ b/documentation/example_large_models @@ -0,0 +1 @@ +../python/examples/example_large_models/ \ No newline at end of file diff --git a/documentation/python_interface.rst b/documentation/python_interface.rst index 4e4c607c65..a7409e2ec1 100644 --- a/documentation/python_interface.rst +++ b/documentation/python_interface.rst @@ -149,6 +149,7 @@ Examples ExampleExperimentalConditions.ipynb ExampleEquilibrationLogic.ipynb example_errors.ipynb + example_large_models/example_performance_optimization.ipynb Environment variables affecting model import ============================================ diff --git a/python/examples/example_large_models/example_performance_optimization.ipynb b/python/examples/example_large_models/example_performance_optimization.ipynb new file mode 100644 index 0000000000..9f4cefb144 --- /dev/null +++ b/python/examples/example_large_models/example_performance_optimization.ipynb @@ -0,0 +1,530 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "dbe0a770", + "metadata": {}, + "source": [ + "# Speeding up model import and simulation - with a focus on large models\n", + "\n", + "**Objective:** Give some hints to speed up import and simulation of larger models\n", + "\n", + "This notebook gives some hints that may help to speed up import and simulation of (mostly) larger models. While some of these settings may also yield slight performance improvements for smaller models, other settings may make things slower. The impact may be highly model-dependent (number of states, number of parameters, rate expressions) or system-dependent and it's worthile doing some benchmarking.\n", + "\n", + "To simulate models in AMICI, a model specified in a high-level format needs to be imported first, as shown in the following figure. This rougly involves the following steps:\n", + "\n", + "1. Generating the ODEs\n", + "2. Computing derivatives\n", + "3. Generating C++ code\n", + "4. Compiling the generated code\n", + "5. Simulating the model\n", + "\n", + "![AMICI workflow](https://raw.githubusercontent.com/AMICI-dev/AMICI/master/documentation/gfx/amici_workflow.png)\n", + "\n", + "There are various options to speed up individual steps of this process. Generally, faster import comes with slower simulation and vice versa. During parameter estimation, a model is often imported only once, and then millions of simulations are run. Therefore, faster simulation will easily compensate for slower import (one-off cost). In other cases, many models may to have to be imported, but only few simulations will be executed. In this case, faster import may bee more relevant.\n", + "\n", + "In the following, we will present various settings that (may) influence import and simulation time. We will follow the order of steps outlined above.\n", + "\n", + "Since many of the following demonstrations take quite some time to compute, this notebook mostly shows pre-generated results." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "411be08a", + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.core.pylabtools import figsize, getfigs\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "\n", + "plt.rcParams.update({'font.size': 12})" + ] + }, + { + "cell_type": "markdown", + "id": "bfd50810", + "metadata": {}, + "source": [ + "## Examples\n", + "\n", + "The demos below make use of the following models contained in the [PEtab benchmark collection](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab) and other publications:\n", + "\n", + "| Model | # parameters | # states |\n", + "|----------------------------------------------------------------------------------------------------------------------------------------------------------|--------------|----------|\n", + "| [Chen_MSB2009](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab/tree/master/Benchmark-Models/Chen_MSB2009) | 155 | 500 |\n", + "| [Froehlich_CellSystems2018](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab/tree/master/Benchmark-Models/Froehlich_CellSystems2018) | 4231 | 1396 |\n", + "| [FröhlichGer2022 (RTKERK__base)](https://doi.org/10.1101/2022.02.17.480899) | 105 | 2272 |\n", + "| [hello_pysb](https://github.com/pysb/pysb/blob/master/pysb/examples/hello_pysb.py) | 4 | 3 |\n", + "\n", + "All data has been generated with AMICI v0.15.0 or v0.16.0 unless stated otherwise." + ] + }, + { + "cell_type": "markdown", + "id": "b772af14", + "metadata": {}, + "source": [ + "## Model import\n", + "\n", + "### Symbolic processing\n", + "\n", + "#### Parameters as constants\n", + "\n", + "By default, AMICI will generate sensitivity equations with respect to all model parameters. If it is clear upfront, that sensitivities with respect to certain parameters will not be required, their IDs can be passed to [amici.sbml_import.SbmlImporter.sbml2amici](https://amici.readthedocs.io/en/latest/generated/amici.sbml_import.SbmlImporter.html#amici.sbml_import.SbmlImporter.sbml2amici) or [amici.pysb_import.pysb2amici](https://amici.readthedocs.io/en/latest/generated/amici.pysb_import.html?highlight=pysb2amici#amici.pysb_import.pysb2amici) via the `constant_parameters` argument to not generate the respective equations. This will reduce CPU time and RAM requirements during import and simulation.\n", + "The PEtab import will automatically pass all parameters with `petab.ESTIMATE==False` as `constant_parameters` arguments.\n", + "\n", + "See also the following section for the case that no sensitivities are required at all.\n", + "\n", + "\n", + "#### Not generating sensivitiy code\n", + "\n", + "If only forward simulations of a model are required, a modest import speedup can be obtained from not generating sensitivity code. This can be enabled via the `generate_sensitivity_code` argument of [amici.sbml_import.SbmlImporter.sbml2amici](https://amici.readthedocs.io/en/latest/generated/amici.sbml_import.SbmlImporter.html#amici.sbml_import.SbmlImporter.sbml2amici) or [amici.pysb_import.pysb2amici](https://amici.readthedocs.io/en/latest/generated/amici.pysb_import.html?highlight=pysb2amici#amici.pysb_import.pysb2amici).\n", + "\n", + "Example:\n", + "```bash\n", + "petab_yaml=\"https://raw.githubusercontent.com/Benchmarking-Initiative/Benchmark-Models-PEtab/master/Benchmark-Models/Froehlich_CellSystems2018/Froehlich_CellSystems2018.yaml\"\n", + "/usr/bin/time -v amici_import_petab -y \"$petab_yaml\" --no-compile\n", + "# vs.\n", + "/usr/bin/time -v amici_import_petab -y \"$petab_yaml\" --no-compile --no-sensitivities\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4f3af02d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "speedup: 1.25x\n" + ] + } + ], + "source": [ + "figsize(4, 4)\n", + "plt.bar([\"True\", \"False\"], [873.54, 697.85])\n", + "plt.xlabel(\"generate_sensitivity_code\")\n", + "plt.ylabel(\"Import time (s)\")\n", + "plt.title(\"Import speed-up when not generating sensitivity code\\n(Froehlich_CellSystems2018)\");\n", + "plt.show()\n", + "\n", + "print(f\"speedup: {873.54/697.85:.2f}x\")" + ] + }, + { + "cell_type": "markdown", + "id": "490d8987", + "metadata": {}, + "source": [ + "#### Extracting common subexpressions\n", + "\n", + "For some models, the size of the generated model code can be significantly reduced by extracting common subexpressions. This can yield substantial reductions of compile times and RAM-requirements. Very large models might not compile without this option. Extracting common subexpressions can be enabled by setting an environment variable `AMICI_EXTRACT_CSE=1` before model import.\n", + "The downside is, that the generated model code becomes rather unreadable. The increase in import time when enabling this feature is usually <15%, the effect on code size and compile time is highly model dependent. Mostly models with tightly coupled ODEs, as obtained from complex rate laws or spatial discretizations of ODEs, seem to benefit. For models with mass action or similar kinetics, this option seems to not be helpful and rather increases compile time (e.g., for FröhlichGer2022, the compile time doubles).\n", + "\n", + "Benchmark result from [here](https://github.com/AMICI-dev/AMICI/pull/1852) (SBML import, `AMICI_IMPORT_NPROCS=2`, sequential compilation with clang14, `CFLAGS=-O2`):\n", + "\n", + "| | default | `AMICI_EXTRACT_CSE=1` |\n", + "|---------------------|----------------|-----------------------|\n", + "| import time | 160 min (100%) | 164 min (103%) |\n", + "| code size | 89 MB (100%) | 27 MB (30%) |\n", + "| compile time | 169 min (100%) | 90 min (53%) |\n", + "| compile RAM | 7.49 GB (100%) | 1.18 GB (16%) |\n", + "| simulation time (*) | 100% | 97% |\n", + "\n", + "(*) lowest out of 20 identical simulations using ASA" + ] + }, + { + "cell_type": "markdown", + "id": "21421f47", + "metadata": {}, + "source": [ + "#### Parallelization\n", + "\n", + "For large models or complex model expressions, symbolic computation of the derivatives can be quite time consuming. This can be parallelized by setting the environment variable `AMICI_IMPORT_NPROCS` to the number of parallel processes that should be used. The impact strongly depends on the model. Note that setting this value too high may have a negative performance impact (benchmark!).\n", + "\n", + "Impact for a large and a tiny model:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "49cd66c1", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Import time decreased by up to ~44%.\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAEXCAYAAACqIS9uAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAAsTAAALEwEAmpwYAAAp+klEQVR4nO3deZgcZ3Xv8e+ZXbNppJE02ldrF7YBgW0gGGxDDBjMzQMBJ3ZMIHFICJjEwGVJLskNa1hNDCG+YOywGIiBYLPaGBuzKpaMbE9Lsmxrn5Y0I400PZqRZj33j6oe9Yw1UmvU3dU99fs8Tz/TXVVddbpsnXrrvFVvmbsjIiLxURZ1ACIiUlhK/CIiMaPELyISM0r8IiIxo8QvIhIzSvwiIjGjxC+xYmZ/amb3Fmhbbmbnnet3zex2M/tQbqM7d2a2y8yuiDoOOXtK/HJWiukfu5k9aGZ/cZr5i8MEWpGe5u5fd/eXFyZCkeJUceZFRIqLmRlgUcchUqrU4pcJM7M3mdmvzewzZnbUzHaY2QvC6XvNrN3Mrs9Y/nYz+6KZ3Wdm3Wb2CzNblDH/BWb2sJl1hX9fkDHvQTP7sJn9GugFvgr8AXCLmR0zs1tOEeJD4d+j4TKXhLH9KmO9bmZ/Y2ZPhjH9i5ktM7PfmFnKzL5tZlUZy19lZpvD3/sbMzv/DLvpinDdR83s8+FBK72uN5vZVjM7YmY/zdwXZ9jvf2lmT5lZp5ndbWZzs/iOm9k7wv9Gh8zsE2ZWZmZV4XqelbHsLDPrNbOZZjbDzH4Qxt9pZr80s8y88Twz2xL+hq+YWU02v0Ei5u566ZX1C9gFXBG+fxMwCPw5UA58CNgDfB6oBl4OdAP14fK3h59fHM6/GfhVOG86cAS4juBM9Jrwc3M4/8Fw3WvD+ZXhtL84TayLAQcqMqa9Kb3N8LMD3wcaw3X3AfcDS4GpwBbg+nDZZwPtwEXh770+3B/V42zfgR8ATcBCoAO4Mpx3NfAUsDr8Pf8A/GbMd8/L2G8fCt9fBhwCnhPuw38DHsriv5sDD4T7eSGwPb3vgC8AH89Y9kbgnvD9R4Evhvu7kuBgaxn/L7QCC8L1/jodp17F/VKLX87VTnf/irsPAd8iSAL/19373P1eoB/I7OD8obs/5O59wAeAS8xsAfAq4El3/6q7D7r7ncA24NUZ373d3RPh/IEc/oZ/dfeUuycIEtm97r7D3buAHxMkfIAbgP9w9w3uPuTudxAcKC4+zbo/5u5H3X0PQeK9MJz+VuCj7r7V3QeBjwAXZtHq/1PgNnd/JNyH7yPYh4uz+J0fd/fOMJbPEhxcAe4Arsk4G7mO4IwKYACYAyxy9wF3/6W7Zw7wdYu773X3TuDDGeuUIqbEL+fqYMb74wDuPnZafcbnvek37n4M6ATmhq/dY9a9G5h3qu/m2Nh4x4t/EXBTWPY4amZHCQ50pyu1HMh43ztmXTdnrKeToN9iHqc3aj+F+/BwFt+D0ftvdzpud98QxvYSM1tFcKC+O1zuEwRnJveGZaL3ZrNOKW5K/FJoC9JvzKyeoESQDF9jW7sLgbaMz2OHkj3T0LK5Hnp2L/Bhd2/KeNWGZycTWddfjVnXFHf/zRm+N2o/mVkd0Mzo/TSeBRnvF4brSrsDuJagtX+Xu58AcPdud7/J3ZcCrwH+3swuz3KdUqSU+KXQXmlmLwo7TP8F+J277wV+BKwwsz8xswozewOwhqBGPp6DBLX48XQAw2dY5mz8P+CtZnaRBerM7FVm1jCBdX0ReJ+ZrQUws6lm9vosvncn8OdmdqGZVROUiDa4+64svvtuM5sWltZuJCjNpX0N+F8Eyf8/0xPDzuzzwjJQFzBEsE/T3mZm881sOkHpLnOdUqSU+KXQvgF8kKC08VyCRIO7HwauAm4iKF28B7jK3Q+dZl03A68Lryj53NiZ7t5LUHf+dVhSOV0t/ozcfSPwl8AtBB3PTxF0Fk9kXd8DPg5808xSBH0Lr8jiez8D/hH4DrAfWAa8McvNfh/YBGwGfgh8OWO9e4FHCM6SfpnxneXAz4BjwG+BL7j7AxnzvwHcC+wAnibo4JciZ6P7aUTyx8xuB/a5+z9EHUvcmJkDy939qdMscxuQ1H+fyU83cIkI4VVBf8TJK5hkElOpR2QSMLM/CG9Se8Yri+/+C0Gp6RPuvjP/0UrUVOoREYkZtfhFRGKmJGr8M2bM8MWLF0cdhohISdm0adMhd585dnpJJP7FixezcePGqMMQESkpZjb2bnhApR4RkdhR4hcRiRklfhGRmFHiFxGJGSV+EZGYUeIXEYkZJX4RkZgpiev4ZeK6egd4cHs7929t56EnO2iaUslFS5q5aOl0Ll7azNymKVGHKCIFpsQ/CT3dcYz7tx7k/q3tbNx9hKFhp7muistWzSJ1fJCfJA7wrY3BE/MWTJ8SHAiWBAeCBdNrI45eRPJNiX8SGBga5uFdndy/tZ2fb2tn56EeAFbNbuCtly7l8tUtXDi/ibKy4Fnaw8POtgPd/G7HYTbsPMz9Ww9y16Z9AMxrmjJyELho6XQWTq/l5DO4RWQyKInROdevX+8asmG0o739PPhEBz/bepBfbO+g+8QgVeVlXLKsmctXz+KyVbOYPy271vvwsLO9vZsNOzrZsPMwG3Z0crinH4DZjTVcvHQ6Fy0NzgqWzKjTgUCkRJjZJndf/4zpSvylwd15uqMno4TTybDDjPqghHPZqhb+YPkM6qrP/STO3Xmq/Ri/29nJhh2H+d2OTg4d6wNgVkP1yEHg4qXTWTazXgcCkQkaGnYO9/TRnuqjo7uP9u4TtKf6aE+/7+7jn169lgsWNE1o/eMlfpV6itjA0DAP7+zkZ1vbuX/bQXYf7gVg9ZxG3vbS87hs1SwuyCjh5IqZsbylgeUtDVx38SLcnR2Hetiwo3OkPHTPo0kgOPCkO4svWtLM8ln1OY9HpNT0Dw5z6FiYwFMnRv/NSPCHe/oZGn5m47uptpJZDdXMaqhhOA+N87y1+MPnd14FtLv7uozpbwfeBgwBP3T395xpXXFq8R/p6efB7e38bGs7Dz3RQXffIFUVZbxgWTOXr5rFZatbmBfxlTjuzu7DveFBIDgrSHadAGB6XRXPXzx95ECwanaDDgQyrhMDQ2zZn+LRvUfZvPcoj+3roqdvkNqqcqZUVVBbVR68rywfNa0u4/2UcJlguYzvVJVTGy5TXVGWkzPT4/1DIy3xoGU++n1HmNg7w1JpJjNorqsOEnpj9UhiT7+f2VBDS2M1Mxuqqa4oP+dYg20WuNRjZi8GjgH/mU78ZvZS4APAq9y9z8xmuXv7mdY1mRN/uqxy/7Z27t96kE27j4QlnOow0c/iReflpoSTL+7OviPH+e2OwyP9BPuOHAeClsvzFk8f6TBePaeR8hgfCE4MDLG3s5ddh3vZfbiH3Yd76ekbZNmselbNbmDl7AbmNU2ZlOWz4WFnx6FjbN7bxea9R3h0bxdb96cYDFu8LY3VXDC/iWm1VfQODHG8f5De/iF6+4c43j9E78Bg8Ld/iOMDQ5xN6jKD2soxB5NxDxbBgabr+MDoBJ/qo7tv8Bnrriw3ZtZXM7OxJkzmoxN6+n1zXRUV5YW9dSqSGn/4AOcfZCT+bwO3uvvPzmY9ky3x9w8O8z87O7l/W1Cv39MZlHDWzGnkitVBq/78eVNLuqW870jvyc7inZ0jZaqGmgqetzjoJJ4ztYaWxpqRvy2NNVRVlP49hakTA+w53MuuMLGnE/yezl72h2dGaQ01FdRXV4yaXl9dwYqWelbObhw5GKxsaWBaXVWhf8o5OZg6weawJf/o3qM8vq9rJHHWV1dw/vypXLCgiQvmN3HhgiZmT63Jet3uzomBYXrDg8PxgaHwIJFxcAg/BweRoYyDyNjvZEzrH6J3YIihYaemsixI2iMt9BpmphN7RpKfVltVtP9WiyXxbwa+D1wJnADe5e4Pj/PdG4AbABYuXPjc3btP+TyBktHZ088D24LLLR/afrKE88JlzVy+uoXLVs2a1DdT7e86PnIg2LjrCPuOHOf4wNAzlptRX83sqdXMbpzCnKk1zJ5aw+zG8G/4PuqzH3fn0LF+9nT2sOtQL7s7Ryf3saf5MxuqWTS9lkXNdSxqrg1fdSyaXktTbSVmRveJAbYf7GbbgW6eSL8OdnO0d2BkPbMaqlk5u4FVsxtY0dLAqtmNLG+pp6YyN2WBc9F9YoDH93WxeV+Q5B/d28WBVHAwqygzVs9p5IIFU0eS/NKZ9UV75ufuDAw5leVW8mdexZL4W4EHgHcAzwO+BSz1MwRR6i3+j/xoK1/65Q6GPUgCl6+axeWrW3jhec3UVhVvCSef3J3UiUEOpk6wv+sEB7qOc6CrjwOp4xzoCqelToxKfGkNNRWjzhZmT53C7JH3wcEhnVAnamjY2d91PGy597K7s4fdYZLfc7iHnv6TB60ygzlTp7B4Ri0Lp9exOCO5L5xeO+EDlbvT3t0XHgxSPHHgGE8cTPHkwWP0DQ6PbHtxcx0rRw4GwRnCoua6vCXWgaFhtu3vzkjyR3mq49hI6WVxc+1IS/6CBU2sndtYFAenOCqWq3r2Ad8NE/3/mNkwMAPoKHAcBfW937exftF0PvCq1TyrxEs4uWJmTJ1SydQplaxoaRh3uRMDQyMHgvRBIvgbHCC2H+ymvbvvGfXe6oqykYPAnKk1tEytYc7ImUNwNjF1SiVtR4+PKsvs6Qze7+s8Tv/Q8Mj6qsrLmD99Coub67hoyfQwuQct+PnTavNSojKzkRLYpStOPjZ1aNjZdbjn5JnBgeBM4SeJAyP7obqijOUt9axsOVkuWjW7gZkN1Wd1QEx35D+672TJpjWZoj888Eyvq+LCBU1cdf7ckRZ9qZWk4qjQif+/gZcCD5jZCqAKOFTgGAoq3dP/1kuXTfha3DirqSxn8Yw6Fs+oG3eZgaFhOrr7OJA6wYGu8JU+SHSdYNOeIxzs6huVyE+lrqqchc11rJjVwMvWtLAobL0vbK5lztQpRVOaKC8zls2sZ9nMel75rDkj04/3D/Fk++hS0UNPdvCdR/aNLDOttjLjzKCRlbPrWdHSQENNJQCHj/WFSb4raM3vOzpy1lVTWcaz5k3lzy5exAULgpLN/GmTsyN6sstb4jezO4GXADPMbB/wQeA24Law5NMPXH+mMk+pSyRTAKyd2xhxJJNXZXkZc5umnLaPxN3p7OkfdeZwtLd/VIlmRn1VSSexKVXlnD+/ifPnN42a3tnTHx4MUjwR9iPctWnfqHLVvKYplJXB3s7gaqwygxUtDfzhmtlB2WbBVFa2NBT8qhTJj7wlfne/ZpxZ1+Zrm8VoS5j41yjxR8rMaK6vprm+mnXzpkYdTkFNr6vikmXNXLKseWTa8LDTdvT4yJnBtgPdDA87114UtOafNW9q5J3okj/6L5tnrW1dLGqupTE8lRYpBmVlxoLptSyYXssVa1qiDkcKTOdteZZIplTmEZGiosSfR6kTA+zp7GXt3HiVFkSkuCnx59EWdeyKSBFS4s+j1rYuALX4RaSoKPHn0ZZkKhx1rzrqUERERijx51EimYrdpYMiUvyU+PPkxMAQT3UcU31fRIqOEn+ebDvQzdCwK/GLSNFR4s+TRFIduyJSnJT48ySRTNFYU8H8aZN3jH0RKU1K/HmSaOti7dypJT3ol4hMTkr8eTA4NMy2A92q74tIUVLiz4OnO3roGxxm7TwlfhEpPkr8eZDu2F2njl0RKUJK/HnQ2paiprKMpTProw5FROQZ8pb4zew2M2sPn7Y1dt5NZuZmNiNf249SItnFqtmNRfOoPhGRTPls8d8OXDl2opktAF4O7MnjtiPj7mzZn2Kd6vsiUqTylvjd/SGg8xSzPgO8B5iUz9rd23mc7hODunFLRIpWQWv8ZnY10Obuj2ax7A1mttHMNnZ0dBQgutxoHbljVy1+ESlOBUv8ZlYLvB/4P9ks7+63uvt6d18/c+bM/AaXQ4lkF+VlxoqWhqhDERE5pUK2+JcBS4BHzWwXMB94xMxmFzCGvEskUyyfVU9NZXnUoYiInFJFoTbk7o8Ds9Kfw+S/3t0PFSqGQmhtS3HpitI5QxGR+Mnn5Zx3Ar8FVprZPjN7S762VSzaUyc4dKxP9X0RKWp5a/G7+zVnmL84X9uOSkIPVxeREqA7d3MoPVTDGiV+ESliSvw51NqWYnFzLQ01lVGHIiIyLiX+HErs79KNWyJS9JT4c6Tr+AB7O4+rzCMiRU+JP0e2hB276+apxS8ixU2JP0cSGqpBREqEEn+OJJIpWhqrmVFfHXUoIiKnpcSfI4lkl564JSIlQYk/B473D/FU+zGVeUSkJCjx58C2AymGHdaoxS8iJUCJPwc0VIOIlBIl/hxIJFNMnVLJ/GlTog5FROSMlPhzIJHsYu3cRsz0cHURKX5K/OdoYGiYbQe6VeYRkZKhxH+Onu44Rv/gsMboEZGSocR/jhJt6aEa1OIXkdKQzydw3WZm7WbWmjHtE2a2zcweM7PvmVlTvrZfKK3JLqZUlrNkRn3UoYiIZCWfLf7bgSvHTLsPWOfu5wPbgfflcfsFkUimWDWngfIydeyKSGnIW+J394eAzjHT7nX3wfDj74D5+dp+IQwPO1uTKQ3VICIlJcoa/5uBH48308xuMLONZraxo6OjgGFlb++RXrr7BnVFj4iUlEgSv5l9ABgEvj7eMu5+q7uvd/f1M2fOLFxwZ6G1LX3Hrlr8IlI6Kgq9QTN7E3AVcLm7e6G3n0uJZBcVZcaK2erYFZHSUdDEb2ZXAu8BLnX33kJuOx8SyRTLWxqoriiPOhQRkazl83LOO4HfAivNbJ+ZvQW4BWgA7jOzzWb2xXxtP9/cfWSoBhGRUpK3Fr+7X3OKyV/O1/YKrb27j0PH+pX4RaTknDbxm1kNQT3+D4C5wHGgFfihuyfyH17xOvmMXXXsikhpGTfxm9k/EyT9B4ENQDtQA6wAPhYeFG5y98cKEGfRSQ/VsEYtfhEpMadr8f+Pu39wnHmfNrNZwMI8xFQSWpNdLJlRR311wS+MEhE5J+NmLXf/4dhpZlYG1Lt7yt3bCc4CYimRTHHBgqaowxAROWtnvKrHzL5hZo1mVkdQ399iZu/Of2jFq6t3gH1HjqtjV0RKUjaXc65x9xTwWoIhFpYA1+UzqGKX2B907GqMHhEpRdkk/kozqyRI/He7+wBQ0nfcnqtEmx6uLiKlK5vE/x/ALqAOeMjMFgGpfAZV7BLJLmY31tBcXx11KCIiZ+2Mid/dP+fu89z9leHYOnuAl+Y/tOKVSKb0xC0RKVnjJn4zuza8imcUDwya2TIze1F+wys+x/uHeLrjGGtU3xeREnW6i9Cbgd+b2SZgE9BBcAPXecClwCHgvXmPsMhsPZBi2FXfF5HSdbrr+G82s1uAy4AXAucTDNmwFbjO3fcUJsTikkiqY1dESttpbzt19yGC5+TeV5hwit+WZBdNtZXMa5oSdSgiIhMS5aMXS1JrW4q1cxsx08PVRaQ0KfGfhYGhYZ440K0ROUWkpCnxn4Wn2o/RPzSs+r6IlLRsxuppMbMvm9mPw89rwqdpnel7t5lZu5m1Zkybbmb3mdmT4d9p5xZ+YZ3s2FWLX0RKVzYt/tuBnxI8iAVgO/DOLL935Zhp7wXud/flwP2U2OWgrW1dTKksZ8mMuqhDERGZsGwS/wx3/zYwDODug8DQmb7k7g8BnWMmXw3cEb6/g2D8n5KxJZli9ZwGysvUsSsipSubxN9jZs2EA7OZ2cVA1wS31+Lu+8P3B4CW8RY0sxvMbKOZbezo6Jjg5nJneNjZsj/Funkq84hIacvm8VF/D9wNLDOzXwMzgded64bd3c1s3FE+3f1W4FaA9evXRz4a6J7OXo71DapjV0RK3hkTv7s/YmaXAisBA54Ih2aeiINmNsfd95vZHEroCV6teri6iEwSZ0z8ZlYOvBJYHC7/cjPD3T89ge3dDVwPfCz8+/0JrCMSiWSKijJjeUt91KGIiJyTbEo99wAngMcJO3izYWZ3Ai8BZpjZPuCDBAn/2+HloLuBPz7bgKOSSKZY0dJAdUV51KGIiJyTbBL/fHc//2xX7O7XjDPr8rNdV9TcnURbF5etmhV1KCIi5yybq3p+bGYvz3skRexgqo/DPf3q2BWRSSGbFv/vgO+FD2UZIOjgdXePTRZMpDt2dSmniEwC2ST+TwOXAI+Hj16MnUQyhRmsnhObY52ITGLZlHr2Aq1xTfoQDNWwpLmO+upsjpMiIsUtm0y2A3gwHKStLz1xgpdzlqREMsWzFzZFHYaISE5k0+LfSTCgWhXQkPGKhaO9/bQdPa6hGkRk0sjmzt1/LkQgxWqLnrErIpPMuInfzD7r7u80s3sIB2jL5O6vyWtkRUJDNYjIZHO6Fv9Xw7+fLEQgxSqRTDFnag3T66qiDkVEJCfGTfzuvil8e6G735w5z8xuBH6Rz8CKRSKZUmtfRCaVbDp3rz/FtDflOI6i1Ns/yNMdx1TfF5FJ5XQ1/muAPwGWmNndGbMaeOaTtSalrfu7cVfHrohMLqer8f8G2A/MAD6VMb0beCyfQRWLLRqqQUQmodPV+HcTDJ18SeHCKS6JZIpptZXMnVoTdSgiIjmTTY0/tlqTXaydOxUzPVxdRCYPJf5xDAwNs/2AOnZFZPI5Y+IPL90847SzYWZ/Z2YJM2s1szvNrOhqKU8ePEb/0DBrlPhFZJIp+OWcZjYPeAew3t3XAeXAGye6vnxJj8GvMXpEZLLJ5nLOpXm4nLMCmGJmA0AtkDzH9eVcIpmitqqcJc11UYciIpJTBb+c093bzOyTwB7gOHCvu987djkzuwG4AWDhwoUT3dyEJZJdrJ7TSFmZOnZFZHIZt9QTXs75S+CEu/8i4/WIuw9OdINmNg24GlgCzAXqzOzaU2z/Vndf7+7rZ86cOdHNTcjwsLMlmWKd6vsiMgmdtsbv7kPAsJnlstB9BbDT3TvcfQD4LvCCHK7/nO3u7KWnf0hj9IjIpJTNE7iOAY+b2X1AT3qiu79jgtvcA1xsZrUEpZ7LgY0TXFdetLYFHbu6okdEJqNsEv93w1dOuPsGM7sLeAQYBH4P3Jqr9edCIpmistxY0RKbB42JSIxk8wSuO8ysClgRTnoiLNFMmLt/EPjguawjnxLJLla0NFBVofvbRGTyyeYGrpcATwKfB74AbDezF+c3rOi4ezgGv8o8IjI5ZVPq+RTwcnd/AsDMVgB3As/NZ2BROZA6QWdPvzp2RWTSyqaWUZlO+gDuvh2ozF9I0Uq06eHqIjK5ZdPi32hmXwK+Fn7+U4rsKpxcSiRTmMHqOUr8IjI5ZZP4/xp4G8H4OhDc1PWFvEUUsdZkF0tm1FFXnc2uEREpPdlc1dNnZrcA9wPDBFf19Oc9sohsSaZ4zqJpUYchIpI32VzV8yrgaeBm4BbgKTN7Rb4Di8KRnn7ajh7XUA0iMqlle1XPS939KQAzWwb8EPhxPgOLwpb96Y5dXdEjIpNXNlf1dKeTfmgHwQidk056qAZd0SMik1m2V/X8CPg24MDrgYfN7I8A3D1nwzlELZFMMXdqDdPqqqIORUQkb7JJ/DXAQeDS8HMHMAV4NcGBYBIl/i7W6olbIjLJZXNVz58XIpCo9fYPsuNQD6++YG7UoYiI5NUZE7+ZLQHeDizOXN7dX5O/sApv6/4U7urYFZHJL5tSz38DXwbuIbiOf1JKJDVUg4jEQzaJ/4S7fy7vkUQs0ZZiel0Vc6bWRB2KiEheZZP4bzazDwL3An3pie7+SN6iikBrsou1cxsx08PVRWRyyybxPwu4DriMk6UeDz9PiJk1AV8C1oXrerO7/3ai6ztX/YPDbD/YzZtftCSqEERECiabxP96YGmOx+e5GfiJu78ufLpXbQ7XfdaebO9mYMjVsSsisZDNnbutQFOuNmhmU4EXE3QY4+797n40V+ufiHTHrsboEZE4yKbF3wRsM7OHGV3jn+jlnEsIbgL7ipldAGwCbnT3nsyFzOwG4AaAhQsXTnBT2Um0dVFXVc7i5rq8bkdEpBhkk/hz/VD0CuA5wNvdfYOZ3Qy8F/jHzIXc/VbgVoD169d7jmMYJZFMsXpOI2Vl6tgVkckvmzt3f5Hjbe4D9rn7hvDzXQSJPxLDw87W/Slev35BVCGIiBTUuInfzLoJrrh5xizA3X1CBXF3P2Bme81sZfgs38uBLRNZVy7sOtxDT/8Qa1TfF5GYGDfxu3tDHrf7duDr4RU9O4DIxgNq1R27IhIzkTxY1t03A+uj2PZYiWQXleXG8ln5PM6JiBSPbC7nnNS2JFOsnN1AVUXsd4WIxESss52709rWxdo5unFLROIj1ol/f9cJjvQOsHae6vsiEh+xTvwaillE4ijmib8LM1g9R4lfROIj1om/tS3F0hl11FZFcnGTiEgkYp34tyS7NCKniMRObBP/kZ5+kl0nWKeOXRGJmdgm/pMdu2rxi0i8xDbxtya7AF3RIyLxE9vEn0immNc0habaqqhDEREpqBgn/i619kUklmKZ+Hv6Btl5qEf1fRGJpVgm/q37U7irvi8i8RTLxD9yRY8u5RSRGIpp4u+iua6K2Y01UYciIlJwkSV+Mys3s9+b2Q8Kve3WthRr5jZipoeri0j8RNnivxHYWuiN9g8O82R7tzp2RSS2Ikn8ZjYfeBXwpUJve/vBbgaGXB27IhJbUbX4Pwu8BxgebwEzu8HMNprZxo6OjpxteEvYsbtunlr8IhJPBU/8ZnYV0O7um063nLvf6u7r3X39zJkzc7b91mQX9dUVLJpem7N1ioiUkiha/C8EXmNmu4BvApeZ2dcKtfFEMsXqOQ2UlaljV0TiqeCJ393f5+7z3X0x8Ebg5+5+bSG2PTTsbN2fUseuiMRarK7j33W4h97+IXXsikisRfrMQXd/EHiwUNtrbUsPxawWv4jEV6xa/FuSKarKy1jeUh91KCIikYlV4k8kU6yc3UBleax+tojIKLHJgO5Oq8bgFxGJT+JPdp3gaO+AEr+IxF5sEn8i7Nhdo45dEYm5+CT+ZIoyg9VzGqIORUQkUjFK/F0snVlPbVWkV7CKiEQuRok/pfq+iAgxSfydPf3s7zrBOtX3RUTikfgTyfQdu2rxi4jEIvG3tgVj8K9R4hcRiUfiTyS7mNc0habaqqhDERGJXCwS/5ZkinXz1NoXEYEYJP5jfYPsPNyjETlFREKTPvFv3Z/CXR27IiJpkz7xJzQGv4jIKFE8bH2BmT1gZlvMLGFmN+Zze4lkihn1VbQ0VudzMyIiJSOK8QsGgZvc/REzawA2mdl97r4lHxtrTaZYM3cqZnq4uogIRPOw9f3u/kj4vhvYCszLx7b6Bod48mC36vsiIhkirfGb2WLg2cCGU8y7wcw2mtnGjo6OCa3/yYPHGBx2JX4RkQyRJX4zqwe+A7zT3VNj57v7re6+3t3Xz5w5c0LbSA/VoDF6REROiiTxm1klQdL/urt/N1/baW1LUV9dwcLptfnahIhIySl4564FvaxfBra6+6fzua1rnr+QS5Y1U1amjl0RkbQorup5IXAd8LiZbQ6nvd/df5TrDa2Z26iB2URExih44nf3XwFqgouIRGTS37krIiKjKfGLiMSMEr+ISMwo8YuIxIwSv4hIzCjxi4jEjBK/iEjMKPGLiMSMEr+ISMwo8YuIxIwSv4hIzCjxi4jEjBK/iEjMKPGLiMSMEr+ISMwo8YuIxExUz9y90syeMLOnzOy9UcQgIhJXBU/8ZlYOfB54BbAGuMbM1hQ6DhGRuIqixf984Cl33+Hu/cA3gasjiENEJJaieNj6PGBvxud9wEVjFzKzG4Abwo/HzOyJAsSWTzOAQ1EHUUS0P07SvhhN+2O0c9kfi041MYrEnxV3vxW4Neo4csXMNrr7+qjjKBbaHydpX4ym/TFaPvZHFKWeNmBBxuf54TQRESmAKBL/w8ByM1tiZlXAG4G7I4hDRCSWCl7qcfdBM/tb4KdAOXCbuycKHUcEJk3ZKke0P07SvhhN+2O0nO8Pc/dcr1NERIqY7twVEYkZJX4RkZhR4s8zM1tgZg+Y2RYzS5jZjVHHFDUzKzez35vZD6KOJWpm1mRmd5nZNjPbamaXRB1TVMzs78J/I61mdqeZ1UQdUyGZ2W1m1m5mrRnTppvZfWb2ZPh3Wi62pcSff4PATe6+BrgYeJuGqOBGYGvUQRSJm4GfuPsq4AJiul/MbB7wDmC9u68juPDjjdFGVXC3A1eOmfZe4H53Xw7cH34+Z0r8eebu+939kfB9N8E/7HnRRhUdM5sPvAr4UtSxRM3MpgIvBr4M4O797n400qCiVQFMMbMKoBZIRhxPQbn7Q0DnmMlXA3eE7+8AXpuLbSnxF5CZLQaeDWyIOJQofRZ4DzAccRzFYAnQAXwlLH19yczqog4qCu7eBnwS2APsB7rc/d5ooyoKLe6+P3x/AGjJxUqV+AvEzOqB7wDvdPdU1PFEwcyuAtrdfVPUsRSJCuA5wL+7+7OBHnJ0Kl9qwtr11QQHw7lAnZldG21UxcWDa+9zcv29En8BmFklQdL/urt/N+p4IvRC4DVmtotgVNbLzOxr0YYUqX3APndPnwHeRXAgiKMrgJ3u3uHuA8B3gRdEHFMxOGhmcwDCv+25WKkSf56ZmRHUcLe6+6ejjidK7v4+d5/v7osJOu5+7u6xbdW5+wFgr5mtDCddDmyJMKQo7QEuNrPa8N/M5cS0o3uMu4Hrw/fXA9/PxUqV+PPvhcB1BK3bzeHrlVEHJUXj7cDXzewx4ELgI9GGE43wrOcu4BHgcYLcFKuhG8zsTuC3wEoz22dmbwE+BrzMzJ4kOCv6WE62pSEbRETiRS1+EZGYUeIXEYkZJX4RkZhR4hcRiRklfhGRmFHiFxGJGSV+ySsze62ZuZmtCj8vDj9/KGOZGWY2YGa3hJ//yczelTH/XeGwxZvN7GEz+7Nw+oNmtv40295lZjPC9555l7CZVZhZR3poaDN7U/h5cziE9l+O+Q2PhcMmP25mr82Yd7uZ7Qy/96iZXW5mH8i4Z2Mo4/07xonzn8ys18xmZUw7lvE+vY5WM/svM6s9xfR7zKwp4ztrzeznZvZEOKTvP4Y3RqXnv8LMNoa/9fdm9qlw+spwv24Of2+srqWPCyV+ybdrgF+Ff9N2EozQmfZ64JTPXTaztwIvA57v7hcS3NFpp1r2DHqAdWY2Jfz8MqBtzDLfCrfxEuAjZtZiZhcQDB52tbuvBl4DfNLMzs/43rvD770T+KK7f9jdLwynHU+/d/fPnSa+Q8BN48xLr2Md0A+89RTTO4G3AYS/8W7gY+6+kmC45xcAfxPOXwfcAlwbDhe+HngqXOfngM+E610N/NtpYpYSpcQveRMOTPci4C2MHlu9F9ia0Vp/A/DtcVbzfuCv0wPbuXvK3e8YZ9kz+REnDzjXAHeeaiF3bweeBhYB7wI+4u47w3k7gY8C7z7FV3/LxIfcvg14g5lNP8NyvwTOO8O2/wT4dXp0S3fvBf6WkwPAvQf4sLtvC+cPufu/h/PmEIwhRDjv8Qn8FilySvyST1cTPGRkO3DYzJ6bMe+bwBvNbAEwxCnGXjezRqDB3XfkKJ70NmuA8xlneGwzWwosJWgFrwXGjia6MZw+1pXAf08wtmMEyX/cJ7SF49S/gmBIg8zp5QRnQneHk54Rs7s/DdSH+3Td2PkZPgP83Mx+bMETsZrO/qdIsVPil3y6hiDZEv7NLPf8hKDc8kbgW4UIxt0fAxaHcfzoFIu8wcw2E5wJ/JW7j30oxng+YWbbgW8AHz+HED8HXG9mDWOmTwnj2kgwmNmXx0xPj9N+3zlsGwB3/wqwGvgvgpLX78ys+lzXK8VFiV/yIixZXAZ8KRyG+d3AHxPW5929n6DVeRPB4FzPEJZ3joUt8Fy5m6Bmf6oyz7fC2vZF7v69cNoW4Lljlnsuo/sk3u3uK4D/TdBqn5Dw6VvfIKzVZ8jsJ3h7uO9GphOUpCzje8+IOdyHx8J9mjjFb8qMI+nut7n71QSPDl030d8kxUmJX/LldcBX3X2Ruy929wUEnboLMpb5FPC/z9Cy/ijw+bBEgZnVp6/qmaDbgH8+i9r1J4H3WfD0tPRT1N5PEPtYtwBlZvaH5xDfp4G/InhIS1bCGv47gJvCctDXgReZ2RVhzFMIzib+NfzKJ4D3m9mKcH5Z2ImOmV1pwfMjMLPZQDPP7ASXEqfEL/lyDfC9MdO+A7wv/cHdE1l01P478ADwsJm1EnRuTvixje6+7wxX14xdfjNBS/4eM9sG3AO8J5w+dlkHPkTQeTrR+A4R7LezKq+4+++Bx4Br3P04Qf/KP5jZEwR9Ag8THJjSJa93Anea2VaglaBPA+DlQKuZPQr8lOBs5sBEf48UJw3LLCISM2rxi4jETNZ1RJFiZWYbeGZp5LpiuwbdzD5AcLNapv9y9w9HEY/El0o9IiIxo1KPiEjMKPGLiMSMEr+ISMwo8YuIxMz/B6q2ki00MzIEAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Import time increased by at least ~774%.\n" + ] + } + ], + "source": [ + "df_import = pd.read_csv(\"results_import.tsv\", sep=\"\\t\")\n", + "for model_name, df in df_import.groupby(\"model_name\"):\n", + " plt.plot(df.nprocs, df.time)\n", + " plt.title(f\"Import time {model_name}\")\n", + " plt.xlabel(\"AMICI_IMPORT_NPROCS\")\n", + " plt.ylabel(\"Import time (s)\")\n", + " plt.ylim(ymin=0)\n", + " plt.show()\n", + " \n", + " import_times = df.sort_values(\"nprocs\")[\"time\"].values\n", + " percent_change = (import_times[0] - min(import_times[1:])) / import_times[0] * 100\n", + " if percent_change > 0:\n", + " print(f\"Import time decreased by up to ~{percent_change:.0f}%.\")\n", + " else:\n", + " print(f\"Import time increased by at least ~{-percent_change:.0f}%.\")" + ] + }, + { + "cell_type": "markdown", + "id": "c32065a1", + "metadata": {}, + "source": [ + "### Compilation\n", + "\n", + "#### Choice of compiler\n", + "\n", + "From own experience, `clang` seems to handle larger models, or more specifically, their large source files, better than `g++`, both in terms of memory requirement and compile time. You can use a different compiler by setting the `CC` and `CXX` environment variables to, e.g., `CC=clang`, `CXX=clang`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "62cfce84", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Clang was ~10x as fast as g++.\n" + ] + } + ], + "source": [ + "figsize(8, 4)\n", + "compilation_time_s = [3022.453, 289.518]\n", + "labels = [\"g++ (Ubuntu 12.2.0-3ubuntu1) 12.2.0\", \"Ubuntu clang version 15.0.2-1\"]\n", + "plt.bar(labels, compilation_time_s)\n", + "plt.ylim(ymin=0)\n", + "plt.title(\"Choice of compiler - FröhlichGer2022\")\n", + "plt.xlabel(\"Compiler\")\n", + "plt.ylabel(\"Walltime for compilation (s)\");\n", + "plt.show()\n", + "print(f\"Clang was ~{compilation_time_s[0] / compilation_time_s[1]:.0f}x as fast as g++.\")" + ] + }, + { + "cell_type": "markdown", + "id": "ee9e4b2a", + "metadata": {}, + "source": [ + "#### Parallel compilation\n", + "\n", + "It's possible to compile multiple source files in parallel by specifying the number of parallel processes via the `AMICI_PARALLEL_COMPILE` environment variable. This is also beneficial for small models.\n", + "Note, however, that for large models, this may require significant amounts of RAM. \n", + "\n", + "Example for a large and tiny model:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "779b773a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "We were able to reduce compile time by up to ~45%.\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "We were able to reduce compile time by up to ~73%.\n" + ] + } + ], + "source": [ + "df_compile = pd.read_csv(\"results_compile.tsv\", sep=\"\\t\")\n", + "figsize(6, 4)\n", + "\n", + "for model_name, df in df_compile.groupby(\"model_name\"):\n", + " plt.plot(df.nprocs, df.time)\n", + " plt.title(f\"Compile time {model_name}\")\n", + " plt.xlabel(\"AMICI_PARALLEL_COMPILE\")\n", + " plt.ylabel(\"Compile time (s)\")\n", + " plt.ylim(ymin=0)\n", + " plt.show()\n", + " \n", + " compilation_time_s = df.sort_values(\"nprocs\")[\"time\"].values\n", + " print(\"We were able to reduce compile time by up to \"\n", + " f\"~{(compilation_time_s[0] - min(compilation_time_s[1:])) / compilation_time_s[0] * 100:.0f}%.\")" + ] + }, + { + "cell_type": "markdown", + "id": "0f68459d", + "metadata": {}, + "source": [ + "#### Compiler flags\n", + "\n", + "For most compilers, different machine code optimizations can be enabled/disabled by the `-O0`, `-O1`, `-O2`, `-O3` flags, where a higher number enables more optimizations. For fastet simulation, `-O3` should be used. However, these optimizations come at the cost of increased compile times. If models grow very large, some optimizations (especially with `g++`, see above) become prohibitively slow. In this case, a lower optimization level may be necessary to be able to compile models at all.\n", + "\n", + "Another potential performance gain can be obtained from using CPU-specific instructions using `-march=native`. The disadvantage is, that the compiled model extension will only run on CPUs supporting the same instruction set. This may be become problematic when attempting to use an AMICI model on a machine other than on which it was compiled (e.g. on hetergenous compute clusters).\n", + "\n", + "These compiler flags should be set for both, AMICI installation installation and model compilation. \n", + "\n", + "For AMICI installation, e.g.,\n", + "```bash\n", + "CFLAGS=\"-O3 -march=native\" pip install amici\n", + "```\n", + "\n", + "For model compilation, flags can be passed via the `AMICI_CXXFLAGS` environment variable.\n", + "\n", + "\n", + "Example:\n", + "```bash\n", + "petab_yaml=\"https://raw.githubusercontent.com/Benchmarking-Initiative/Benchmark-Models-PEtab/master/Benchmark-Models/Chen_MSB2009/Chen_MSB2009.yaml\"\n", + "amici_import_petab -y \"${petab_yaml}\" --no-compile\n", + "cd Chen_MSB2009-amici0.16.0/\n", + "for cflags in \"-O0\" \"-O1\" \"-O2\" \"-O3\" \"-O3 -march=native\"\n", + " # this line only builds the model extension, and is normally performed automatically during import\n", + " do AMICI_PARALLEL_COMPILE=1 AMICI_CXXFLAGS=${cflags} /usr/bin/time -v python setup.py build_ext --force --build-lib .\n", + "done\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b94b979b", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiYAAAEXCAYAAACZAI/TAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAAsTAAALEwEAmpwYAAAiFklEQVR4nO3dd7hlVX3/8fdHkCIdIQQUGCFoAiojjiVIVNQYFBSNBUfFEg0aUTGxgBVbIj8VxIIYVAIaC0YhoCBqUDRYmRGkSgAF6VWaFCnf3x97X+ZwvWXPnXvuOXPP+/U8+zln9+9e58yc71177bVSVUiSJA2D+w06AEmSpDEmJpIkaWiYmEiSpKFhYiJJkoaGiYkkSRoaJiaSJGlomJhIfZLkuUkuSXJLkkf1+VwvSfLdGe77N0nOG6aYOhz7n5Jc1ZbtA5NUkr/ox7lGwfjPakXKs5+fu0ZD7MdEwyDJRcCrq+p/Bh3LmCQFbFNVF8xw/wuBf6mqY2c5rgXAb4H7V9Vds3nsmZrLmJLcH7gJeHxV/apdtkKfle6ra3kO43dRKz9rTKT+2RI4e9BBzEObAGtg2UrzkomJhk6SVyT5cZKPJbkhyW+S7NguvyTJ1Ule3rP9EUk+k+R7SW5O8sMkW/as/3i7301Jlib5m551qyR5R5IL232XJtk8yY/aTX7V3i7YY4I475fkXUkubmP6QpL1kqye5BZglXb/Cye5zh2TnJrkxvZ1x551Jyf5UJJftHEfm2TDdvVYbDe0sf11Wzan9OxfSV6X5Pz2uj6QZOskP2mP97Ukq7XbPjnJpe37Pdpjjk13JDm5XbdrktPa/S9J8t6ey+kS03TX+4H2c785yXeTbDRBmT0UOK/nXN+fYJup4iTJy9rP7Lok705yUZKntesem2RJu+9VSQ6a6LNrt/3HJBckuT7JcUk2G1f+r23L/4YkhyTJJMeZ8DvYscw+2H6mtyT5ZprbWl9q4z81TY1Gb0xvTPPv6dokH0lyv3bdfT6r5SjPOfncNWKqyslp4BNwEfC09v0rgLuAV9L8uH8Q+B1wCLA68HTgZmDtdvsj2vkntus/DpzSc+yXAg8EVgXeDFwJrNGueytwJvAwIMD2wAPbdQX8xRQx/wNwAbAVsDZwNPDFnvWT7g9sCPwe2LONa3E7P3buk4HLgIcDawHfAP6zXbegPfaqPcd7xbhrLuBYYF1gO+AO4KQ21vWAc4CXt9s+Gbh0ghjXBc4FXtOz3SNo/qB5JHAV8JwuMXW83guBhwJrtvMHTFJ2E53r3rKeJs5tgVuAnYDVgI8Cd7Lsu/dTYM/2/do0t4smiuEpwLXADjTfuU8CPxoXz7eA9YEtgGuAXSY51oTfwY5ldgGwdc9n+n/A09rtvwD8x7iYftAed4t221dP8f3pUp5z9rk7jc408ACcnKomTEzO71n3iPY/v016ll0HLGzfHwF8tWfd2sDdwOaTnOv3wPbt+/OA3SfZbrrE5CTgdT3zD6P5kVt1uv3b/6h/MW7ZT4FXtO/v8x80zQ/qH2kStSl/DHrO/YSe+aXAvj3zBwIHt++fzLjEpP0R+hZw6BTXfzDwsfb9dD9QXa73XT3rXgecOMl5JzrXVGXdG+d7gK/0rHtAW65j370fAe8DNprm+/p54MPjvnN3Agt64tmpZ/3XgP0mOdaE38GOZfbOcZ/pt3vmnwWcPq6MdumZfx1w0hTfny7lOWefu9PoTN7K0bC6quf9bQBVNX7Z2j3zl4y9qapbgOuBzQCSvCXJuW1V8g00f12OVRdvTvMX20xsBlzcM38xzV+Fm8xg37H9H9Qzf8m4dfdnWdxdjC+vqcpvvH8F1gHeOLYgyeOS/CDJNUluBF67HPF0ud4re97fOk18k5omzs2473flVpokd8yraP56/3V722G3SU5zn+tpv3PXzfB6JvsOdimz5f2Mx3+nNmMaK8vnrvnDxETzxeZjb5KsTVOFfHma9iRvA14IbFBV6wM30lSZQ/Mf9dYzPOflNA1cx2xBcwvqqok3n3Lfsf0v65nffNy6O2luH9RyR7ockryIpsr9+VV1Z8+qLwPH0dRErQd8hmXlOF1MXa53tkwV5xXAg8c2TLImzW0TAKrq/KpaDPwZ8P+ArydZa4Jz3Od62m0eyMyuZ7LvYD/KbPx36vIO+6wsn7vmCRMTzRfPTLJTmgadHwB+VlWX0PzVfxfNPf5Vk7yHpu3EmM8BH0iyTRqPTDL2Q3UVTZuMyXwF+OckD2mToX8Djqpuj02eADw0yYuTrJqmce22NLdPxrw0ybZJHgC8H/h6Vd3dXss908Q2I2n6W/kkTRuCa8atXge4vqpuT/JY4MU966aLqcv1zpap4vw68Ky2QeZqwHtZ9iNLkpcm2biq7gFuaBffM8E5vgK8MsnCJKvTfPY/r6qLZhDvZN/BfpTZW5Ns0Dau3Qc4qsM+K8vnrnnCxETzxZeB/Wlu4TyapsErwHeAE2ka+l0M3M59q7MPorn//12avjE+T9MID5ofrSPTPFXxwgnOeTjwRZp2Cb9tj/2GLsFW1XXAbjSNca+jqdXZraqu7dnsizTtZ66keTz2je2+t9LcavlxG9vju5yzo92BDYBTsuzJnG+3614HvD/JzTRtNb7Wcz1TxtTxemfLVHGeTfMZfZWm9uQW4GqaxsEAuwBnp3mq6uPAi6rqtvEnqKa/nXfTNEq+gqbG40UzjHfC72CfyuxYmvZGpwPHt+eazsryuWuesIM1rfSSHEHTePNdg45ltqR5RPc/q+pzg45lPmtrum6g6UzstwMOp69iJ3RaSVhjImmkJHlWkge07UI+SvOo7kWDjUrSGBMTSaNmd5pGmZcD29DcrrHqWBoS3sqRJElDwxoTSZI0NFYddABdbLTRRrVgwYJBhyFJkmbB0qVLr62qjSdat1IkJgsWLGDJkiWDDkOSJM2CJON7BL6Xt3IkSdLQMDGRJElDw8REkiQNDRMTSZI0NExMJEnS0DAxkSRJQ8PERJIkDQ0TE0mSNDRMTCRJ0tBYKXp+lSRpRS3Y7/hBh7BSueiAXQdyXmtMJEnS0DAxkSRJQ8PERJIkDQ0TE0mSNDRMTCRJ0tAwMZEkSUPDxESSJA0NExNJkjQ0TEwkSdLQMDGRJElDw8REkiQNDRMTSZI0NExMJEnS0DAxkSRJQ8PERJIkDQ0TE0mSNDRMTCRJ0tAwMZEkSUNj1UEHIGnuLdjv+EGHsFK56IBdZ+1Ylv3ymc2y18qhbzUmSTZP8oMk5yQ5O8k+7fL3Jrksyent9Mx+xSBJklYu/awxuQt4c1X9Msk6wNIk32vXfayqPtrHc0uSpJVQ3xKTqroCuKJ9f3OSc4EH9et8kiRp5TcnjV+TLAAeBfy8XfT6JGckOTzJBpPss1eSJUmWXHPNNXMRpiRJGrC+JyZJ1ga+Abypqm4CDgW2BhbS1KgcONF+VXVYVS2qqkUbb7xxv8OUJElDoK+JSZL70yQlX6qqowGq6qqquruq7gE+Czy2nzFIkqSVR9/amCQJ8Hng3Ko6qGf5pm37E4DnAmf1KwYNNx+bXD4+NilpFPTzqZwnAHsCZyY5vV32DmBxkoVAARcBr+ljDJIkaSXSz6dyTgEywaoT+nVOSZK0crNLekmSNDRMTCRJ0tCY9lZOkvsB2wObAbcBZ1XV1f0OTJIkjZ5JE5MkWwP7Ak8DzgeuAdYAHprkVuDfgSPbx34lSZJW2FQ1Jh+k6QztNVVVvSuS/BnwYpqnbo7sX3iSJGmUTJqYVNXiKdZdDRzcj4AkSdLomrbxa5IXtKMDk+TdSY5OskP/Q5MkSaOmy1M5725HB94JeCpNb66H9jcsSZI0irokJne3r7sCh1XV8cBq/QtJkiSNqi6JyWVJ/h3YAzghyeod95MkSVouXRKMFwLfAf6uqm4ANgTe2s+gJEnSaJqqH5O1q+qWqroVOHpseTsy8BW92/Q/TEmSNAqmqjE5NsmBSZ6YZK2xhUm2SvKqJN8Bdul/iJIkaVRM1Y/JU5M8E3gN8IQkGwB3AecBxwMvr6or5yZMSZI0CqYcK6eqTgBOmKNYJEnSiPPpGkmSNDRMTCRJ0tAwMZEkSUNjyjYmY5KsAmzSu31V/a5fQUmSpNE0bWKS5A3A/sBVwD3t4gIe2ce4JEnSCOpSY7IP8LCquq7fwUiSpNHWpY3JJcCN/Q5EkiSpS43Jb4CTkxwP3DG2sKoO6ltUkiRpJHVJTH7XTqu1kyRJUl9Mm5hU1fugGbCvnXfQPkmS1BfTtjFJ8vAkpwFnA2cnWZpku/6HJkmSRk2Xxq+HAf9SVVtW1ZbAm4HP9jcsSZI0irokJmtV1Q/GZqrqZGCtvkUkSZJGVpfE5DdJ3p1kQTu9i+ZJnSkl2TzJD5Kck+TsJPu0yzdM8r0k57evG6zoRUiSpPmhS2LyD8DGwNHttHG7bDp3AW+uqm2BxwN7J9kW2A84qaq2AU5q5yVJkjo9lfN74I3Le+CqugK4on1/c5JzgQcBuwNPbjc7EjgZ2Hd5jy9JkuafSROTJAdX1ZuSfJNmbJz7qKpndz1JkgXAo4CfA5u0SQvAlTSDA060z17AXgBbbLFF11MttwX7Hd+3Y89HFx2w66BDkCTNY1PVmHyxff3oipyg7f/kG8CbquqmJPeuq6pK8idJT7vuMJongli0aNGE20iSpPll0jYmVbW0fbuwqn7YOwELuxw8yf1pkpIvVdXR7eKrkmzart8UuHrG0UuSpHmlS+PXl0+w7BXT7ZSmauTzwLnjxtU5rueYLweO7RCDJEkaAVO1MVkMvBh4SJLjelatA1zf4dhPAPYEzkxyervsHcABwNeSvAq4GHjhDOKWJEnz0FRtTH5C81TNRsCBPctvBs6Y7sBVdQqQSVY/tWuAkiRpdEyamFTVxTQ1Gn89d+FIkqRR1mUQv8cnOTXJLUn+mOTuJDfNRXCSJGm0dGn8+ilgMXA+sCbwauCQfgYlSZJGU5fEhKq6AFilqu6uqv8AdulvWJIkaRRN2yU9cGuS1YDTk3yYpkFsp4RGkiRpeXRJMPYEVgFeD/wB2Bx4Xj+DkiRJo6nLIH4Xt29vA97X33AkSdIom6qDtTOZYPC+MVX1yL5EJEmSRtZUNSa7zVkUkiRJTN/BmiRJ0pyZtPFrklPa15uT3DT+de5ClCRJo2KqGpOd2td15i4cSZI0yrr0Y0KSHYCdaBrDnlJVp/U1KkmSNJK6jJXzHuBI4IE0Iw0fkeRd/Q5MkiSNni41Ji8Btq+q2wGSHACcDnywj3FJkqQR1KXn18uBNXrmVwcu6084kiRplHWpMbkRODvJ92jamPwt8IsknwCoqjf2MT5JkjRCuiQmx7TTmJP7E4okSRp1XcbKOXIuApEkSeryVM5uSU5Lcr0drEmSpH7qcivnYODvgTOratJB/SRJklZUl6dyLgHOMimRJEn91qXG5G3ACUl+CNwxtrCqDupbVJIkaSR1SUz+FbiFpi+T1fobjiRJGmVdEpPNqurhfY9EkiSNvC5tTE5I8vS+RyJJkkZel8Tkn4ATk9zePirs48KSJKkvunSwts5cBCJJktSlxoQkz07y0XbareM+hye5OslZPcvem+SyJKe30zNnGrgkSZp/uvT8egCwD3BOO+2T5EMdjn0EsMsEyz9WVQvb6YTlCVaSJM1vXZ7KeSawsKruAUhyJHAa8PapdqqqHyVZsMIRSpKkkdHpVg6wfs/79VbwnK9PckZ7q2eDyTZKsleSJUmWXHPNNSt4SkmStDLokph8CDgtyRFtbclSmk7XZuJQYGtgIXAFcOBkG1bVYVW1qKoWbbzxxjM8nSRJWpl0eSrnK0lOBh7TLtq3qq6cycmq6qqx90k+C3xrJseRJEnzU5fGr88Fbq2q46rqOOD2JM+ZycmSbNoz+1zgrMm2lSRJo6fLrZz9q+rGsZmqugHYf7qdknwF+CnwsCSXJnkV8OEkZyY5A9gZ+OeZhS1JkuajLk/lTJS8dLkFtHiCxZ/vcD5JkjSiutSYLElyUJKt2+kgmgawkiRJs6pLYvIG4I/AUcBXgduBvfsZlCRJGk1dbsn8AdhvDmKRJEkjrmsHa5IkSX1nYiJJkobGlIlJklWS+EivJEmaE1MmJlV1NzDRY7+SJEmzrks/Jj9O8imap3L+MLawqn7Zt6gkSdJI6pKYLGxf39+zrICnzHo0kiRppHV5XHjnuQhEkiSpyyB+67U9vy5ppwOTrDcXwUmSpNHS5XHhw4GbgRe2003Af/QzKEmSNJq6tDHZuqqe1zP/viSn9ykeSZI0wrrUmNyWZKexmSRPAG7rX0iSJGlUdakxeS3whZ52Jb8HXt6/kCRJ0qiaNDFJsk9VfRxYu6q2T7IuQFXdNGfRSZKkkTLVrZxXtq+fhCYhMSmRJEn9NNWtnHOTnA9sluSMnuUBqqoe2d/QJEnSqJk0MamqxUn+HPgO8Oy5C0mSJI2qKRu/VtWVwPZzFIskSRpxXR4XliRJmhMmJpIkaWh0TkySPKCfgUiSJHUZxG/HJOcAv27nt0/y6b5HJkmSRk6XGpOPAX8HXAdQVb8CntjPoCRJ0mjqdCunqi4Zt+juPsQiSZJGXJexci5JsiNQSe4P7AOc29+wJEnSKOpSY/JaYG/gQcBlwMJ2fkpJDk9ydZKzepZtmOR7Sc5vXzeYYdySJGkemjYxqaprq+olVbVJVf1ZVb20qq7rcOwjgF3GLdsPOKmqtgFOauclSZKADrdykjwEeAOwoHf7qpqym/qq+lGSBeMW7w48uX1/JHAysG/XYCVJ0vzWpY3JfwOfB74J3LOC59ukqq5o318JbDLZhkn2AvYC2GKLLVbwtJIkaWXQJTG5vao+MdsnrqpKUlOsPww4DGDRokWTbidJkuaPLonJx5PsD3wXuGNsYVX9cgbnuyrJplV1RZJNgatncAxJkjRPdUlMHgHsCTyFZbdyqp1fXscBLwcOaF+PncExJEnSPNUlMXkBsFVV/XF5DpzkKzQNXTdKcimwP01C8rUkrwIuBl64fOFKkqT5rEtichawPst526WqFk+y6qnLcxxJkjQ6uiQm6wO/TnIq921jMuXjwpIkScurS2Kyf9+jkCRJokNiUlU/nItAJEmSJk1MkpxSVTsluZnmKZx7V9F0Q7Ju36OTJEkjZdLEpKp2al/XmbtwJEnSKJt2EL8kX+yyTJIkaUVNm5gA2/XOJFkVeHR/wpEkSaNs0sQkydvb9iWPTHJTO90MXIU9tkqSpD6YNDGpqg+17Us+UlXrttM6VfXAqnr7HMYoSZJGxFRP5ezQvv2vnvf3muEgfpIkSZOaqh+TA6dYN9NB/CRJkiY11ePCO89lIJIkSVPdyvn7qXasqqNnPxxJkjTKprqV86wp1hVgYiJJkmbVVLdyXjmXgUiSJHUZXZgku9J0tLbG2LKqen+/gpIkSaOpS5f0nwH2AN5AM4DfC4At+xyXJEkaQV26pN+xql4G/L6q3gf8NfDQ/oYlSZJGUZfE5Lb29dYkmwF3Apv2LyRJkjSqurQx+VaS9YGPAL+keSLns/0MSpIkjaap+jF5E/AT4ENVdRfwjSTfAtaoqhvnKD5JkjRCpqoxeTBwMPCXSc4EfkyTqPxkDuKSJEkjaKp+TN4CkGQ1YBGwI/BK4LAkN1TVtnMToiRJGhVd2pisCawLrNdOlwNn9jMoSZI0mqZqY3IYTadqNwM/p7mFc1BV/X6OYpMkSSNmqseFtwBWB64ELgMuBW6Yg5gkSdKImqqNyS5JQlNrsiPwZuDhSa4HflpV+89RjJIkaURM2cakqgo4K8kNwI3ttBvwWMDERJIkzaqp2pi8kaamZEea3l7HHhU+nBVs/JrkIpq2K3cDd1XVohU5niRJmh+mqjFZAPwX8M9VdUUfzr1zVV3bh+NKkqSV1FRtTP5lLgORJEnqMohfPxTw3SRLk+w10QZJ9kqyJMmSa665Zo7DkyRJgzCoxGSnqtoBeAawd5Injt+gqg6rqkVVtWjjjTee+wglSdKcG0hiUlWXta9XA8fQPOUjSZJG3JwnJknWSrLO2Hvg6cBZcx2HJEkaPl3GypltmwDHNH23sSrw5ao6cQBxSJKkITPniUlV/QbYfq7PK0mSht+gGr9KkiT9CRMTSZI0NExMJEnS0DAxkSRJQ8PERJIkDQ0TE0mSNDRMTCRJ0tAwMZEkSUPDxESSJA0NExNJkjQ0TEwkSdLQMDGRJElDw8REkiQNDRMTSZI0NExMJEnS0DAxkSRJQ8PERJIkDQ0TE0mSNDRMTCRJ0tAwMZEkSUPDxESSJA0NExNJkjQ0TEwkSdLQMDGRJElDw8REkiQNDRMTSZI0NExMJEnS0DAxkSRJQ2MgiUmSXZKcl+SCJPsNIgZJkjR85jwxSbIKcAjwDGBbYHGSbec6DkmSNHwGUWPyWOCCqvpNVf0R+Cqw+wDikCRJQyZVNbcnTJ4P7FJVr27n9wQeV1WvH7fdXsBe7ezDgPPmNNDB2wi4dtBBjCjLfnAs+8Gx7AdnFMt+y6raeKIVq851JF1V1WHAYYOOY1CSLKmqRYOOYxRZ9oNj2Q+OZT84lv19DeJWzmXA5j3zD26XSZKkETeIxORUYJskD0myGvAi4LgBxCFJkobMnN/Kqaq7krwe+A6wCnB4VZ0913GsBEb2NtYQsOwHx7IfHMt+cCz7HnPe+FWSJGky9vwqSZKGhomJJEkaGiYmQyDJdkm+33bTf36SdydJuy5JPtF2339Gkh0GHe98Mk3Z/2WSnya5I8lbBh3rfDRN+b+k/c6fmeQnSbYfdLzzyTRlv3tb9qcnWZJkp0HHu7xWxutL8ookn5qjc62f5HU985sl+fpcnHs6JiYDlmRNmqeSDqiqhwHbAzsCY1+YZwDbtNNewKGDiHM+6lD21wNvBD46mAjntw7l/1vgSVX1COAD2EBw1nQo+5OA7atqIfAPwOcGEedMDfv1JRmGPsTWZ1l5UFWXV9XzBxfOMiYmg/di4MdV9V2AqroVeD0wNrjh7sAXqvEzYP0kmw4m1HlnyrKvqqur6lTgzsGFOK9NV/4/qarft9v+jKbPI82O6cr+llr2ZMRawMr2lMSsX1+S9yY5Msn/Jrk4yd8n+XBbo3dikvu3270nyalJzkpyWE8tzclJDk6yBNgnyWPamsBfJflFknXaU23WHu/8JB/uesFJjmhr13+S5DdtL+skWTvJSUl+2cY6NgTMAcDWba3RR5IsSHJWu8/PkmzXc+yTkyxKslaSw9t4T+s51qwyMRm87YClvQuq6kJg7STrAg8CLulZfWm7TCtuurJXfy1P+b8K+PZcBTYCpi37JM9N8mvgeJpahZVJv65va+ApwLOB/wR+0Nbo3Qbs2m7zqap6TFU9HFgT2K1n/9XaHl4/CRwF7FNV2wNPa48BsBDYA3gEsEeSzdt4j2qTiPHTy3qOvymwU3vOA9pltwPPraodgJ2BA9tkaT/gwqpaWFVvHXedRwEvbM+7KbBpVS0B3gl8v6oe2x7rI0nW6lh2nQ1DdZIkTSrJzjSJyVC0AxgVVXUMcEySJ9LcSnvagEOaVTO8vm9X1Z1JzqTph+vEdvmZwIL2/c5J3gY8ANgQOBv4ZrvuqPb1YcAVbY0sVXUTQFu5clJV3djOnwNsCVxSVXt0iO+/q+oe4Jwkm7TLAvxbe5330Pxhu8lkB2h9DfgusD9NgjLW9uTpwLOzrM3dGsAWwLkdYuvMGpMBSLL3WLYL3AA8etz6rYBb2i+rXfjPouUse82y5S3/JI+kuf+/e1VdN8fhzisz/e5X1Y+ArZJsNFexLq/ea0uyGXAOK3h9ExwT4I52n3uAO3tuB90DrJpkDeDTwPPbmpTP0vx4j/lDh8u5o+f93bQVCB1rTHr3Tfv6EmBj4NFtm5qrxsX0J6rqMuC69t/fHixLqAI8r61lWVhVW1TVrCYlYGIyEFV1yNgHC3wE2CnJ0+DeRlufAMbuLR4HvCyNxwM3VtUVg4h7PljOstcsW57yT7IFcDSwZ1X934BCnjeWs+z/oqdtxA7A6sDQJoa911ZVlwNfYgWvb4JjdjH2g39tkrWByRqTngdsmuQxbQzrZJoGsVW1R088vdMXpolpPeDqtqZnZ5oaGICbgXUm342jgLcB61XVGe2y7wBv6Cm7R01z7hnxVs6AVdVtbQOiTyY5hKZ68IvA2CNjJwDPBC4AbgVeOZBA56Hpyj7JnwNLgHWBe5K8CdjW2pTZ0eG7/x7ggcCn2/8H73IE1tnRoeyfR/MH0Z00bR/26KkdGHqDur6quiHJZ4GzgCtpxoabaLs/JtmjjW/NNoZ+3Sr7EvDN9vbTEuDXbQzXJflxmgav3wYOGbff14GP09zmGvMB4GDgjCT3o3lybjdmmV3SS5KkoeGtHEmSNDRMTCRJ0tAwMZEkSUPDxESSJA0NExNJkjQ0TEwkSdLQMDGRRkSS5ySpJH/Zzi9o5z/Ys81GSe5MO/R6moHL3tKz/i1Jft32OHnqWK+TaQf5muLcayf59yQXJlnabv+4JJsn+W2SDdvtNmjnF6QZNOzsJKu167ZOMzjZukmenOTGnt4v/2eieMfFMHZtrx23fJMkX26PvTTJT5M8t133gCRfSjP42VlJTmk7zpLUJyYm0uhYDJzSvo75LcsGHwN4Ac3YHn+i/UH/W+Cxbe+hT2VZt9fT+RxwPbBNVT2apqPAjarqEuBQlg04dgBwWFVd1A4a9kNgLNE4BHhnTwd3/9vT+2WXzqleQDNK8b3X3/Zg+d/Aj6pqqza2F7FsJON9gKuq6hHtoGyvwtGmpb6y51dpBLR/5e9EMyLoN2kG54KmN+FzkyxqE4E9aAbw2myCw7wDePJYYtC+Htnh3FsDjwNe0o4xQlX9liYpAvgYsLTtWXcnmuHpe895WpK7gFWr6iudL/pPLQbeDHw5yYOr6lKakWL/WFWfGduoqi6mGf0VmtFaL+5Zd94KnF9SB9aYSKNhd+DEdsyZ65L0DnD2VeBFaYZXvxv4k3FB0gwVv05V/WYG594OOL2q7p5oZVXdCbyVJkF5Uzs/tu4GmlqUDwF7j9v1b3pu5bxzqgDaa9u0qn5Bk3iNjdS6HfDLKXY9HNi3vb3zwSTbTHUeSSvOxEQaDYtpEhDa197bOSfS3KJ5EctGEZ1rzwCuAB4+ybqrgG3HLe+9lfOv0xx/rCYI/vT675XkkCS/SjI2HP3pwFY0g95tCJya5K86XI+kGfJWjjTPtQ1LnwI8IknRDGhWtIN2tQOKLaW5zbEt8Ozxx6iqm5LckmSrGdSanA1sn2SViWpNkiykSYweD5yS5KtjI2gn2Y1mdNS/A45J8p2qunU5zw9NIvLnSV7Szm/W1n6cTTOgGwBVtXeSjWgGOxtbdgvNKMdHJ7mHZlDNWR/qXVLDGhNp/ns+8MWq2rKqFlTV5jTtOzbv2eZAYN+qun6K43wIOKS9rTP2pM3Lpjt5VV1I80P/vp7h0hck2bWdP5TmFs7vaGomPtpusyZwELB3VZ0JHAtMectmIkkeCqxdVQ9qr39Bey2Lge8DayT5p55dHtCz7xOSbNC+X40mcbsYSX1jYiLNf4uBY8Yt+wbw9rGZqjq7qqZryHoo8AOa2xlnAf8L3NMxhlcDmwAXtPseAVwN/CPwu6r6Xrvdp4G/SvIk4N3AMVV1TrvuvcDiDu083pXk0rGJya9/cTvU/XOAJ7WPKf+CpkHvvu12WwM/bIeMP40mwfpGx2uWNANp/l1KkiQNnjUmkiRpaNj4VdKsSfJzYPVxi/ds24hI0rS8lSNJkoaGt3IkSdLQMDGRJElDw8REkiQNDRMTSZI0NP4/C+pMYA/qCXwAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "compilation_time_s = [20.01, 24.62, 25.59, 25.63, 28.21]\n", + "labels = [\"-O0\", \"-O1\", \"-O2\", \"-O3\", \"-O3 -march=native\"]\n", + "figsize(9, 4)\n", + "plt.bar(labels, compilation_time_s)\n", + "plt.title(\"Impact of optimization flags on compilation\")\n", + "plt.xlabel(\"AMICI_CXXFLAGS\")\n", + "plt.ylabel(\"Walltime for compilation (s)\");" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "33ebf019", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.bar(\n", + " [\"-O0\", \"-O1\", \"-O2\", \"-O3\", \"-O3 -march=native\"],\n", + " [4357.768, 3276.873, 3140.092, 3069.855, 3039.262],\n", + ")\n", + "plt.title(\"Impact of optimization flags on simulation\")\n", + "plt.xlabel(\"AMICI_CXXFLAGS\")\n", + "plt.ylabel(\"Simulation time (s)\");" + ] + }, + { + "cell_type": "markdown", + "id": "37d0713f", + "metadata": {}, + "source": [ + "#### Using some optimized BLAS\n", + "\n", + "You might have access to some custom [BLAS](https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms) optimized for your hardware which might speed up your simulations somewhat. We are not aware of any systematic evaluation and cannot make any recomendation. You pass the respective compiler and linker flags via the environment variables `BLAS_CFLAGS` and `BLAS_LIBS`, respectively." + ] + }, + { + "cell_type": "markdown", + "id": "47781b8c", + "metadata": {}, + "source": [ + "## Model simulation\n", + "\n", + "A major determinant of simulation time for a given model is the required accuracy and the selected solvers. This has been evaluated, for example, in https://doi.org/10.1038/s41598-021-82196-2 and is not covered further here. \n", + "\n", + "### Adjoint *vs.* forward sensivities\n", + "\n", + "If only the objective function gradient is required, adjoint sensitivity analysis are often preferable over forward sensitivity analysis. As a rule of thumb, adjoint sensitivity analysis seems to outperform forward sensitivity analysis for models with more than 20 parameters:\n", + "\n", + "![](https://journals.plos.org/ploscompbiol/article/figure/image?size=medium&id=10.1371/journal.pcbi.1005331.g002)\n", + "\n", + "*CC BY 4.0 Fröhlich et al., [DOI:10.1371/journal.pcbi.1005331](https://doi.org/10.1371/journal.pcbi.1005331)*\n", + "\n", + "### Sensitivities w.r.t. a subset of parameters\n", + "\n", + "If only sensitivities with respect to a subset of model parameters are of interest to you (see also *Parameters as constants* above), you can speed up the simulation by selecting the relevant parameter indices via [amici.Model.setParameterList](https://amici.readthedocs.io/en/latest/generated/amici.amici.Model.html#amici.amici.Model.setParameterList).\n" + ] + }, + { + "cell_type": "markdown", + "id": "af4bd3d5", + "metadata": {}, + "source": [ + "\n", + "### Parallel simulation of multiple conditions\n", + "\n", + "Whenever there are multiple independent simulations to perform, you can use [amici.runAmiciSimulations(..., num_threads=...)](https://amici.readthedocs.io/en/latest/generated/amici.amici.html#amici.amici.runAmiciSimulations) instead of [amici.runAmiciSimulations(...)](https://amici.readthedocs.io/en/latest/generated/amici.amici.html#amici.amici.runAmiciSimulation) to run them in parallel. Note that all simulation results have to be kept in memory, which may become problematic for very large numbers of simulations.\n", + "Parallelization is based on OpenMP and does not come with the issues associated with Python's multiprocessing or multithreading (spawning extra processes or limitations related to the global interpreter lock).\n", + "\n", + "### Reporting mode\n", + "\n", + "During model simulation, many quantities are calculated, but not all might be of interest for you. For example, for parameter estimation you might only be interested in the likelihood and gradient. In this case, you can save time and memory using \n", + "[amici.Solver.setReturnDataReportingMode(amici.RDataReporting.likelihood)](https://amici.readthedocs.io/en/latest/generated/amici.amici.Solver.html#amici.amici.Solver.setReturnDataReportingMode)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.10.6" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/examples/example_large_models/results_compile.tsv b/python/examples/example_large_models/results_compile.tsv new file mode 100644 index 0000000000..6b7a9bfe31 --- /dev/null +++ b/python/examples/example_large_models/results_compile.tsv @@ -0,0 +1,21 @@ + model_name task nprocs time +0 hello_pysb compile 1 20.741835117340088 +1 hello_pysb compile 2 11.944610834121704 +2 hello_pysb compile 3 9.319742441177368 +3 hello_pysb compile 4 7.94843316078186 +4 hello_pysb compile 5 7.121765375137329 +5 hello_pysb compile 6 6.689377069473267 +6 hello_pysb compile 7 6.251616954803467 +7 hello_pysb compile 8 6.100285291671753 +8 hello_pysb compile 9 5.753735780715942 +9 hello_pysb compile 10 5.667196750640869 +10 RTKERK__base compile 1 3067.3388171195984 +11 RTKERK__base compile 2 2061.4823524951935 +12 RTKERK__base compile 3 1754.1764636039734 +13 RTKERK__base compile 4 1725.0178718566895 +14 RTKERK__base compile 5 1697.654798746109 +15 RTKERK__base compile 6 1691.5322842597961 +16 RTKERK__base compile 7 1720.0398466587067 +17 RTKERK__base compile 8 1714.9537448883057 +18 RTKERK__base compile 9 1721.5932655334473 +19 RTKERK__base compile 10 1726.7770998477936 diff --git a/python/examples/example_large_models/results_import.tsv b/python/examples/example_large_models/results_import.tsv new file mode 100644 index 0000000000..6770fc5c91 --- /dev/null +++ b/python/examples/example_large_models/results_import.tsv @@ -0,0 +1,21 @@ + Unnamed: 0 model_name task nprocs time size +0 0 hello_pysb import 1 1.787031888961792 12054809 +1 1 hello_pysb import 2 15.872491359710692 12067022 +2 2 hello_pysb import 3 16.68442177772522 12054052 +3 3 hello_pysb import 4 16.014235973358154 12067022 +4 4 hello_pysb import 5 15.72178030014038 12054052 +5 5 hello_pysb import 6 16.097049713134766 12067022 +6 6 hello_pysb import 7 15.62270975112915 12054052 +7 7 hello_pysb import 8 16.196629762649536 12067022 +8 8 hello_pysb import 9 16.08016848564148 12054052 +9 9 hello_pysb import 10 16.345548152923584 12067022 +10 10 RTKERK__base import 1 1376.1798136234283 43516541 +11 11 RTKERK__base import 2 1041.8015067577362 43349758 +12 12 RTKERK__base import 3 927.154144525528 43336620 +13 13 RTKERK__base import 4 878.066201210022 43349758 +14 14 RTKERK__base import 5 837.5367295742035 43336620 +15 15 RTKERK__base import 6 823.1699328422546 43349758 +16 16 RTKERK__base import 7 811.7395029067993 43336620 +17 17 RTKERK__base import 8 789.2430837154388 43349758 +18 18 RTKERK__base import 9 772.3326945304871 43336620 +19 19 RTKERK__base import 10 784.638739824295 43349758