From 79907ee38c1f48289699eecb9ce6070487b57373 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:18:42 +0200 Subject: [PATCH 01/25] a lot more instructions for the getting started/installation --- docs/source/getting_started.rst | 137 ++++++++++++++++++++++++++------ 1 file changed, 114 insertions(+), 23 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 364a3192c5..436552a7de 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -37,37 +37,132 @@ Usage .. _installation: Installation -~~~~~~~~~~~~~ +~~~~~~~~~~~~ -You can download the latest code version of MEmilio from our `github repository `_ -in a Linux terminal via: +There are two main ways to set up MEmilio on your computer, depending on what you want to do: + +1. **Using the Python packages:** This is the recommended path for most users. You can run simulations using python bindings, download epidemiological data, and create plots all from Python, without needing to compile any C++ code yourself. +2. **Directly building the C++ Core:** This is for developers who want to modify the functionality, contribute new models etc. by running C++ code directly. + +Below, we will give you a step-by-step guide for both methods. If you're new to MEmilio, we recommend starting with the Python packages, as they are easier to use. + +Required Tools +***************** + +Before you can install MEmilio, you need to install some common development tools. + +* **Git:** This is a version control system used to download the project's source code. + + * **Windows:** Here, Git is not installed by default. Download and install it from `git-scm.com `_. + * **macOS & Linux:** Git is usually pre-installed. You can check by opening a terminal and typing ``git --version``. + +* **Python:** Required for the Python packages. + + * We recommend installing the latest version from the official website `python.org `_. + +* **C++ Compiler and CMake:** + + * **Windows:** The easiest way is to install **Visual Studio Community**. This includes a C++ compiler, CMake, and Git all in one. + * **macOS:** One option is installing the **Xcode Command Line Tools** by running ``xcode-select --install`` in your terminal. + * **Linux:** Install the essential build tools and CMake. On Debian/Ubuntu, you can do this with by running ``sudo apt-get install cmake gcc g++`` in your terminal. + +Step 1: Download the MEmilio Source Code +***************************************** + +Once the required tools are installed, open a terminaland download the MEmilio code with this command: .. code-block:: console git clone https://github.com/SciCompMod/memilio.git -You can now build the C++ code: +This command copies the entire MEmilio project into a new folder named ``memilio`` on your computer. -.. code-block:: console +.. note:: A Quick Note on HTTPS vs. SSH - cd memilio/cpp - mkdir build && cd build - cmake .. - cmake --build . + The ``git clone`` command above uses an **HTTPS** URL. This is the simplest method and works perfectly for downloading the code. -For details on the possible compile flags, help with errors and general a more detailed instruction, see the -:doc:`C++-interface ` section of this documentation. + However, if you plan to contribute code back to the project (i.e., "push" your changes), we recommend using **SSH**. To set this up, you can follow `GitHub's official guide on adding an SSH key `_. -For the installation of Python packages, e.g. ``memilio-epidata``, do + +Now, navigate into that folder: .. code-block:: console - - cd memilio/pycode - cd memilio-epidata - pip install . - -For more information, we refere to the :ref:`Python Interace Part ` of this documentation. + cd memilio + +From here, choose one of the following options. + +Option A: Installing the Python Packages (Recommended) +**************************************************** + +If you want to run simulations, download data, or create plots using Python, you only need to install our Python packages. + +1. Navigate to the directory containing our Python code: + + .. code-block:: console + + cd pycode + +2. From here, you can install the packages you need. For example, to install the ``memilio-epidata`` package for data downloading and handling, run: + + .. code-block:: console + + cd memilio-epidata + pip install -e . + +.. tip:: For Contributors: Installing development packages + + The ``-e`` flag installs the package in a mode, which links the installation to your local source code folder. + + If you plan to contribute to MEmilio, you can also install all the necessary development dependencies by adding ``[dev]`` to the command: + + .. code-block:: console + + pip install -e .[dev] + + For regular use, the simple ``pip install -e .`` is sufficient. + + +3. To install other packages, like ``memilio-simulation``, repeat the process: + + .. code-block:: console + + cd .. # Go back to the pycode directory + cd memilio-simulation + pip install -e . + + + +Option B: Building the C++ Core (Advanced) +**************************************** + +If you are a developer and want to build the C++ executables yourself, follow these instructions. + +1. Navigate to the C++ source code directory: + + .. code-block:: console + + cd cpp + +2. Create a separate directory for the build files. + + .. code-block:: console + + mkdir build && cd build + +3. Run CMake. This tool prepares the project for compilation on your specific system. + + .. code-block:: console + + cmake .. + +4. Compile the code and create the executables. + + .. code-block:: console + + cmake --build . + +For more detailed instructions, help with errors, and a list of compile options, please see the full :doc:`C++ Installation Guide `. Running simulations ~~~~~~~~~~~~~~~~~~~~~ @@ -84,10 +179,6 @@ Out of the box this works for all examples in the ``cpp/examples`` folder of our that do not depend on user-provided external libraries. Additional explanations for our models are linked at the corresponding sites of this documentation. -For the Python interface, you can find a short introduction in the :doc:`Python Interface ` section. - -Additionally we provide a python package for :doc:`surrogate models `, which can be used to c -reate fast approximations of our models. Loading data ~~~~~~~~~~~~~~~~~~~~~ @@ -112,4 +203,4 @@ For the latter we don't take any responsibilities! Further questions ~~~~~~~~~~~~~~~~~~~~~ -If you have any further questions, please take a look at our :doc:`faq` and feel free to contact us via `github `_. \ No newline at end of file +If you have any further questions, please take a look at our :doc:`faq` and feel free to contact us via `github `_. From c167266e3d640846275de9e2a8828fdf13dffb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=BChn?= Date: Tue, 1 Jul 2025 15:29:21 +0200 Subject: [PATCH 02/25] getting started, index and ref --- docs/source/citation.rst | 2 +- docs/source/getting_started.rst | 43 ++++++++++++++++++--------------- docs/source/references.rst | 10 ++++++-- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/docs/source/citation.rst b/docs/source/citation.rst index a8e0a26779..3036d0e41b 100644 --- a/docs/source/citation.rst +++ b/docs/source/citation.rst @@ -3,7 +3,7 @@ Citing MEmilio If you use MEmilio, please cite our work -- Kühn, Martin Joachim et al. (2025). *MEmilio - a High Performance Modular Epidemics Simulation Software (2022)*. Available at `https://github.com/SciCompMod/memilio `_ and `https://elib.dlr.de/213614/ `_. +- Bicker J, Kerkmann D, Korf S, Ploetzke L, Schmieding R, Wendler A, Zunker H et al. (2025). *MEmilio - a High Performance Modular Epidemics Simulation Software*. Available at `https://github.com/SciCompMod/memilio `_ and `https://elib.dlr.de/213614/ `_. and, in particular, for diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 436552a7de..eafde3d996 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -7,21 +7,23 @@ Overview .. note:: This project is under active development. -MEmilio is an extensive framework for tasks around infectious disease modelling. It supports various :ref:`model ` types +MEmilio is an extensive framework for tasks around infectious disease modeling. It supports a multitude of :ref:`model ` types including :doc:`equation-based`, :doc:`agent-based `, -and :doc:`hybrid graph-ODE-based models ` as well as data integration and visualizations. +and :doc:`hybrid graph-ODE-based models `. It furthermore provides ready-to-use tools for data integration and visualizations. Among the equation-based models, we provide models based on :doc:`ordinary differential equations `, -:doc:`the linear chain trick, ` and its :doc:`generalisation `, :doc:`integro-differential equations ` -and :doc:`stochastic differential equations `. The MEmilio framework is written in two languages: C++ and Python. +:doc:`the linear chain trick (LCT), ` and a recent :doc:`generalized LCT `, :doc:`integro-differential equations ` +and :doc:`stochastic differential equations `. With simple definitions, models can be spatially or demograpically resolved. -- The C++ backend powers the model and simulation components for optimal efficiency. -- Data acquisition, plotting, and machine-learning models are handled via Python. +The MEmilio framework is written in two languages: C++ and Python. -For more details on the C++ implementation, see the sections on :doc:`model usage ` if you are interested -in using or applying our models and :doc:`model creation ` if you want to write new models inside our framework. +- The C++ backend contains efficient and optimized model implementations that further use parallelization to speed up execution and reduce waiting times. +- Python is used for data acquisition, plotting, and machine-learning models. +- We, furthermore, provide Python interfaces to selected models (implemented in C++) to allow the use and study of advanced models by users less experience in programming or computer science. -If you prefer using Python, you can use our :doc:`memilio-simulation ` package to run simulations -in our C++ backend; this package uses ``pybind11`` to bind our C++ model code. +For more details on using models implemented in C++ directly, see the sections on :doc:`model usage `. +For more details on implementing new infection dynamics models that could then be combined with, e.g., our mobility patterns, see :doc:`model creation `. + +If you prefer using Python to call or run our models, you can use our :doc:`memilio-simulation ` package to run simulations. The :doc:`memilio-epidata ` package provides tools to download and structure important data such as infection or mobility data. More about this and our other Python packages can be found in the :doc:`Python Interface Section ` of this documentation. @@ -39,12 +41,15 @@ Usage Installation ~~~~~~~~~~~~ -There are two main ways to set up MEmilio on your computer, depending on what you want to do: +There are two main ways to set up MEmilio on your computer or on a remote cluster or supercomputer, depending on what you want to do: -1. **Using the Python packages:** This is the recommended path for most users. You can run simulations using python bindings, download epidemiological data, and create plots all from Python, without needing to compile any C++ code yourself. +1. **Using the Python packages:** This is the recommended path for many users not familiar with C++. Here, you can run simulations using python bindings. 2. **Directly building the C++ Core:** This is for developers who want to modify the functionality, contribute new models etc. by running C++ code directly. -Below, we will give you a step-by-step guide for both methods. If you're new to MEmilio, we recommend starting with the Python packages, as they are easier to use. +In addition, we provide several Python packages to download epidemiological data or create plots from Python. + +Below, we will give you a step-by-step guide for both methods. If you are new to MEmilio and more familiar with Python, Julia, or R than with C++, we recommend starting with the Python packages, +as they provide an easy access to simulate infection dynamics models from and collect experiences with MEmilio. Required Tools ***************** @@ -53,23 +58,23 @@ Before you can install MEmilio, you need to install some common development tool * **Git:** This is a version control system used to download the project's source code. - * **Windows:** Here, Git is not installed by default. Download and install it from `git-scm.com `_. - * **macOS & Linux:** Git is usually pre-installed. You can check by opening a terminal and typing ``git --version``. + * **Windows:** By default, Git is not installed. Download and install it from `git-scm.com `_. + * **macOS & Linux:** Git is usually preinstalled. You can check by opening a terminal and typing ``git --version``. * **Python:** Required for the Python packages. - * We recommend installing the latest version from the official website `python.org `_. + * MEmilio is tested daily with Python 3.8 and 3.11. While other versions might also work, we recommend installing the latest version tested daily from the official website `python.org `_. * **C++ Compiler and CMake:** * **Windows:** The easiest way is to install **Visual Studio Community**. This includes a C++ compiler, CMake, and Git all in one. * **macOS:** One option is installing the **Xcode Command Line Tools** by running ``xcode-select --install`` in your terminal. - * **Linux:** Install the essential build tools and CMake. On Debian/Ubuntu, you can do this with by running ``sudo apt-get install cmake gcc g++`` in your terminal. + * **Linux:** On Linux, essential build tools and CMake might be preinstalled. Otherwise, on Debian/Ubuntu, you could execute the installation by running ``sudo apt-get install cmake gcc g++`` in your terminal. Step 1: Download the MEmilio Source Code ***************************************** -Once the required tools are installed, open a terminaland download the MEmilio code with this command: +Once the required tools are installed, open a terminal and download the MEmilio code with this command: .. code-block:: console @@ -92,7 +97,7 @@ Now, navigate into that folder: From here, choose one of the following options. -Option A: Installing the Python Packages (Recommended) +Option A: Installing the Python Packages (Recommended for nonexperienced users or for data download and visualizations) **************************************************** If you want to run simulations, download data, or create plots using Python, you only need to install our Python packages. diff --git a/docs/source/references.rst b/docs/source/references.rst index aeef0f97c7..4511b59fc1 100644 --- a/docs/source/references.rst +++ b/docs/source/references.rst @@ -1,15 +1,15 @@ References =========== +The following gives an overview on (peer-reviewed) publications extending or using MEmilio. If you would like to add a publication, `contact us `. + Recently Submitted Publications -------------------------------------- - Zunker H, Dönges P, Lenz P, Contreras S, Kühn MJ. (2025). *Risk-mediated dynamic regulation of effective contacts de-synchronizes outbreaks in metapopulation epidemic models*. arXiv. `arXiv:2502.14428 `_ - Schmidt A, Zunker H, Heinlein A, Kühn MJ. (2024). *Towards Graph Neural Network Surrogates Leveraging Mechanistic Expert Knowledge for Pandemic Response*. arXiv. `arXiv:2411.06500 `_ - Wendler AC, Plötzke L, Tritzschak H, Kühn MJ. (2024). *A nonstandard numerical scheme for a novel SECIR integro differential equation-based model with nonexponentially distributed stay times*. Submitted for publication. `arXiv:2408.12228 `_ -- Kerkmann D, Korf S, Nguyen K, Abele D, Schengen A, et al. (2024). *Agent-based modeling for realistic reproduction of human mobility and contact behavior to evaluate test and isolation strategies in epidemic infectious disease spread*. arXiv. `arXiv:2410.08050 `_ - Plötzke L, Wendler A, Schmieding R, Kühn MJ. (2024). *Revisiting the Linear Chain Trick in epidemiological models: Implications of underlying assumptions for numerical solutions*. Submitted for publication. `DOI:10.48550/arXiv.2412.09140 `_ -- Schmid N, Bicker J, Hofmann AF, Wallrafen-Sam K, Kerkmann D, et al. (2024). *Integrative Modeling of the Spread of Serious Infectious Diseases and Corresponding Wastewater Dynamics*. medRxiv. `DOI:10.1101/2024.11.10.24317057 `_ Peer-Reviewed Publications @@ -17,6 +17,12 @@ Peer-Reviewed Publications **2025** +- Schmid N, Bicker J , Hofmann AF, Wallrafen-Sam K, Kerkmann D, Wieser A, Kühn MJ, Hasenauer J (2025). *Integrative Modeling of the Spread of Serious Infectious Diseases and Corresponding Wastewater Dynamics*. *Epidemics* 51:100836. `DOI:10.1016/j.epidem.2025.100836 `_ + +- Kerkmann D, Korf S, Nguyen K, Abele D, Schengen A, Gerstein C, Göbbert JH, Basermann A, Kühn MJ, Meyer-Hermann M (2025). *Agent-based modeling for realistic reproduction of human mobility and contact behavior to evaluate test and isolation strategies in epidemic infectious disease spread*. *Computers in Biology and Medicine* 193:110269. `DOI:10.1016/j.compbiomed.2025.110269 `_ + +- Diallo D, Schoenfeld J, Schmieding R, Korf S, Kühn MJ, Hecking T (2025). *Integrating Human Mobility Models with Epidemic Modeling: A Framework for Generating Synthetic Temporal Contact Networks*. *Entropy* 27(5), 507. `DOI:10.3390/e27050507 `_ + - Bicker J, Schmieding R, Meyer-Hermann M, Kühn MJ. (2025). *Hybrid metapopulation agent-based epidemiological models for efficient insight on the individual scale: A contribution to green computing*. *Infectious Disease Modelling* 10(2): 571-590. `DOI:10.1016/j.idm.2024.12.015 `_ **2024** From d56db6073138f706225b3478717cbb4df08d6b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=BChn?= Date: Tue, 1 Jul 2025 17:13:11 +0200 Subject: [PATCH 03/25] getting started --- docs/source/getting_started.rst | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index eafde3d996..60191cd741 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -100,7 +100,7 @@ From here, choose one of the following options. Option A: Installing the Python Packages (Recommended for nonexperienced users or for data download and visualizations) **************************************************** -If you want to run simulations, download data, or create plots using Python, you only need to install our Python packages. +You can run simulations, download data, or create plots, by only installing our Python packages. 1. Navigate to the directory containing our Python code: @@ -108,10 +108,18 @@ If you want to run simulations, download data, or create plots using Python, you cd pycode -2. From here, you can install the packages you need. For example, to install the ``memilio-epidata`` package for data downloading and handling, run: +2. To install the simulation package ``memilio-simulation``, from here you can do: .. code-block:: console + cd memilio-simulation + pip install -e . + +3. For afterwards installing the ``memilio-epidata`` package for data downloading and handling, run: + + .. code-block:: console + + cd .. # Go back to the pycode directory cd memilio-epidata pip install -e . @@ -127,21 +135,12 @@ If you want to run simulations, download data, or create plots using Python, you For regular use, the simple ``pip install -e .`` is sufficient. - -3. To install other packages, like ``memilio-simulation``, repeat the process: - - .. code-block:: console - - cd .. # Go back to the pycode directory - cd memilio-simulation - pip install -e . - - +To install other packages, see the items below *Python Interface* in the menu on the left hand side. Option B: Building the C++ Core (Advanced) **************************************** -If you are a developer and want to build the C++ executables yourself, follow these instructions. +For experienced developers and C++ programmers, we offer the C++ backend to fully benefit from all functionality and parallel performance. 1. Navigate to the C++ source code directory: @@ -172,7 +171,7 @@ For more detailed instructions, help with errors, and a list of compile options, Running simulations ~~~~~~~~~~~~~~~~~~~~~ You can run simulations either via the C++ interface where they are originally implemented or via the python bindings. -For the C++ Interface you can find explanations of the models as well as guides on their usage in the :doc:`C++ model usage ` section. +For the C++ Interface, you can find explanations of the models as well as guides on their usage in the :doc:`C++ model usage ` section. In short, the executables for different model instatiations are build as described above and can be run via .. code-block:: console @@ -202,10 +201,10 @@ the :doc:`C++ model creation ` section of this documentation Visualizations ~~~~~~~~~~~~~~~~~~~~~ -For visualizations we first of all recommend our :doc:`python package `. Apart from that we have +For visualizations, we provide our :doc:`python package MEmilio-plot `. Apart from that, we have collected some scripts that we used for visualizations in the `tools folder in our github repository `_. -For the latter we don't take any responsibilities! +For the latter, no regular testing is conducted. If you encounter errors, please `contact us `. Further questions ~~~~~~~~~~~~~~~~~~~~~ -If you have any further questions, please take a look at our :doc:`faq` and feel free to contact us via `github `_. +If you have any further questions, please take a look at our :doc:`faq` and feel free to contact us via `e-mail ` or open an issue or discusion on `github ` From 76f2cc058b4c449e90b562f38d3bb8e28eb16efd Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Tue, 15 Jul 2025 10:15:03 +0200 Subject: [PATCH 04/25] review glct and getting_started --- docs/source/cpp/glct.rst | 25 +++++++------------------ docs/source/getting_started.rst | 4 ++-- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/docs/source/cpp/glct.rst b/docs/source/cpp/glct.rst index e0d1639e19..7735c457b7 100644 --- a/docs/source/cpp/glct.rst +++ b/docs/source/cpp/glct.rst @@ -1,10 +1,10 @@ Generalized Linear Chain Trick model ==================================== -MEmilio implements a SECIR-type model utilizing the Generalized Linear Chain Trick (GLCT). This is a generalization of -the LCT model and allows for phase-type distributed stay times in the compartments. Phase-type distributions are dense +MEmilio implements a SECIR-type model utilizing the Generalized Linear Chain Trick (GLCT). This is a generalization of +the LCT model. In contrast to simpler ODE models that assume (possibly unrealistic) exponentially distributed stay times, the GLCT allows for more realistic, phase-type distributed stay times in the compartments through the use of subcompartments. Phase-type distributions are dense in the field of all positive-valued distributions. Therefore, for any positive-valued distribution, a phase-type -distribution of arbitrary precision can be identified. Note that the resulting system can still be described by ODEs. +distribution of arbitrary precision can be identified. Note that the resulting system can still be described by an ordinary differential equation system. In the following, we present the general structure of the GLCT model. The particular model documentation with examples is linked at the bottom of this page. @@ -12,7 +12,7 @@ is linked at the bottom of this page. Infection states ---------------- -The model contains a list of **InfectionState**\s that define particular features of the subpopulations in the particular state. +The model contains a list of **InfectionState**s that define particular features of the subpopulations in the particular state. .. code-block:: RST @@ -43,10 +43,10 @@ a set of contact matrices of arbitrary length and which can represent the differ schools, workplaces, or homes. The matrices can be loaded or stored in the particular example. In the **ContactPatterns**, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic group :math:`i` to group :math:`j`. The dimension of the matrix is automatically defined by the model initiation and it is reduced -to one value if no stratifcation is used. The values can be adjusted during the simulation, e.g., through implementing +to one value if no stratification is used. The values can be adjusted during the simulation, e.g., through implementing nonpharmaceutical interventions, see the section on :ref:`Nonpharmaceutical Interventions`. -Parameters can get accessed via ``model.parameters.get>()`` and set via either -``model.parameters.get>() = value`` or ``model.parameters.set>(value)``. +Parameters can be accessed via ``model.parameters.get>()`` and set via either +``model.parameters.set>(value)`` or ``model.parameters.get>() = value``. Initial conditions @@ -114,17 +114,6 @@ and its documentation. In the following, we give detailed explanations of the GLCT-SECIR model. -Introduction -------------- - -This model is based on the Generalized Linear Chain Trick (GLCT). - -The GLCT provides the option to use phase-type distributed stay times in the compartments through the use of subcompartments. The Generalized Linear Chain Trick is an extension of the Linear Chain Trick (as the name already suggests). Phase-type distributions are dense in the field of all positive-valued distributions. Therefore, for any positive-valued distribution, a phase-type distribution of arbitrary precision can be identified. -The normal ODE models have (possibly unrealistic) exponentially distributed stay times. -The GLCT model can still be described by an ordinary differential equation system. - - - List of models ----------------------------- diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 60191cd741..cce7cf2fa5 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -12,7 +12,7 @@ including :doc:`equation-based`, :doc:`agent-based `. It furthermore provides ready-to-use tools for data integration and visualizations. Among the equation-based models, we provide models based on :doc:`ordinary differential equations `, :doc:`the linear chain trick (LCT), ` and a recent :doc:`generalized LCT `, :doc:`integro-differential equations ` -and :doc:`stochastic differential equations `. With simple definitions, models can be spatially or demograpically resolved. +and :doc:`stochastic differential equations `. With simple definitions, models can be spatially or demographically resolved. The MEmilio framework is written in two languages: C++ and Python. @@ -172,7 +172,7 @@ Running simulations ~~~~~~~~~~~~~~~~~~~~~ You can run simulations either via the C++ interface where they are originally implemented or via the python bindings. For the C++ Interface, you can find explanations of the models as well as guides on their usage in the :doc:`C++ model usage ` section. -In short, the executables for different model instatiations are build as described above and can be run via +In short, the executables for different model instantiations are build as described above and can be run via .. code-block:: console From 556266c6f73dc522beacde237e69fb56a302af11 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:29:35 +0200 Subject: [PATCH 05/25] diffusive abm, lct, model creation, epidata review --- docs/source/cpp/diffusive_abm.rst | 2 +- docs/source/cpp/lct.rst | 6 ++-- docs/source/cpp/lct_creation.rst | 47 +++++++++++++------------- docs/source/cpp/model_creation.rst | 2 +- docs/source/cpp/ode_creation.rst | 4 +-- docs/source/python/memilio_epidata.rst | 19 ++++++----- 6 files changed, 41 insertions(+), 39 deletions(-) diff --git a/docs/source/cpp/diffusive_abm.rst b/docs/source/cpp/diffusive_abm.rst index dd2413ddcd..6d7c9c285d 100644 --- a/docs/source/cpp/diffusive_abm.rst +++ b/docs/source/cpp/diffusive_abm.rst @@ -122,7 +122,7 @@ There are no non-pharmaceutical interventions (NPIs) explicitly implemented in t .. code-block:: cpp //Reduce the transmission risk by 10% - model.get_adoption_rates().at({mio::mpm::Region(0), Status::S, Status::E}).factor *= 0.9; + model.get_adoption_rates().at({mio::regions::Region(0), Status::S, Status::E}).factor *= 0.9; Simulation ----------- diff --git a/docs/source/cpp/lct.rst b/docs/source/cpp/lct.rst index c4b27dfd47..58741d5173 100644 --- a/docs/source/cpp/lct.rst +++ b/docs/source/cpp/lct.rst @@ -12,7 +12,7 @@ is linked at the bottom of this page. Infection states ---------------- -The model contains a list of **InfectionState**\s that define particular features of the subpopulations in the particular state. +The model contains a list of **InfectionState**s that define particular features of the subpopulations in the particular state. .. code-block:: RST @@ -51,9 +51,9 @@ a set of contact matrices of arbitrary length and which can represent the differ schools, workplaces, or homes. The matrices can be loaded or stored in the particular example. In the **ContactPatterns**, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic group :math:`i` to group :math:`j`. The dimension of the matrix is automatically defined by the model initiation and it is reduced -to one value if no stratifcation is used. The values can be adjusted during the simulation, e.g., through implementing +to one value if no stratification is used. The values can be adjusted during the simulation, e.g., through implementing nonpharmaceutical interventions, see the section on :ref:`Nonpharmaceutical Interventions`. -Parameters can get accessed via ``model.parameters.get>()`` and set via either +Parameters can be accessed via ``model.parameters.get>()`` and set via either ``model.parameters.get>() = value`` or ``model.parameters.set>(value)``. diff --git a/docs/source/cpp/lct_creation.rst b/docs/source/cpp/lct_creation.rst index c487cc3849..5cb5a9560f 100644 --- a/docs/source/cpp/lct_creation.rst +++ b/docs/source/cpp/lct_creation.rst @@ -4,16 +4,16 @@ LCT model creation The mathematical model ---------------------- -Before implementing a model in MEmilio, we need to do a some math, in particular, define an initial value problem +Before implementing a model in MEmilio, we need to do some math, in particular, define an initial value problem given by a system of ordinary differential equations. In the here considered example, we consider a SIRD model where we -divide the Infectious compartment into :math`n` subcompartments. The model is defined by +divide the Infectious compartment into :math:`n` subcompartments. The model is defined by .. math:: \begin{aligned} - S'(t) & = -\rho\phi\ \frac{S(t)*I(t)}{N_{\perp D}} \\ - I_1'(t) & = \rho\phi\ \frac{S(t)*I(t)}{N_{\perp D}} - \frac{n}{T_I}I_1(t) \\ - I_j'(t) & = \frac{n}{T_I}I_{j-1}(t) - \frac{n}{T_I}I_j(t) \quad \text{for } j\in\{2,\dots,n}\\ + S'(t) & = -\rho\phi\ \frac{S(t)I(t)}{N_{\perp D}} \\ + I_1'(t) & = \rho\phi\ \frac{S(t)I(t)}{N_{\perp D}} - \frac{n}{T_I}I_1(t) \\ + I_j'(t) & = \frac{n}{T_I}I_{j-1}(t) - \frac{n}{T_I}I_j(t) \quad \text{for } j\in\{2,\dots,n\}\\ R'(t) & = \frac{\mu_R}{T_I}I(t) \\ D'(t) & = \frac{\mu_D}{T_I}I(t) \\ \end{aligned} @@ -21,7 +21,7 @@ divide the Infectious compartment into :math`n` subcompartments. The model is de with :math:`I(t) = \sum_{j=1}^n I_j(t)` and some initial values for :math:`t=0`. Here :math:`N_{\perp D} := S(t) + I(t) + R(t)`. This type of model belongs to the class of compartmental models because the model population is represented by discrete infection -states **S** usceptible, **I** nfectious, **R** ecovered, **D** eceased, also called compartments. +states **S**usceptible, **I**nfectious, **R**ecovered, **D**eceased, also called compartments. Infection states ~~~~~~~~~~~~~~~~ @@ -46,7 +46,7 @@ Parameters Next, we define the parameters in "parameters.h", which consist of a struct for each constant used in the mathematical model. This struct must define the data type, name and default value of the constant. For example, for the time a -person stays infectious :math:`T_I` we define a struct +person stays infectious :math:`T_I` we define a struct: .. code-block:: cpp @@ -67,23 +67,23 @@ person stays infectious :math:`T_I` we define a struct and for the contact rate :math:`\phi` a struct -We also define a parameter ``ContactPatterns`` determining the contacts of the different groups by +We also define a parameter ``ContactPatterns`` determining the contacts of the different groups by: .. code-block:: cpp struct ContactPatterns { - using Type = UncertainContactMatrix; + using Type = UncertainContactMatrix; - static Type get_default() - { - mio::ContactMatrixGroup contact_matrix(1, 1); - contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); - return Type(contact_matrix); - } - static std::string name() - { - return "ContactPatterns"; - } + static Type get_default() + { + mio::ContactMatrixGroup contact_matrix(1, 1); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); + return Type(contact_matrix); + } + static std::string name() + { + return "ContactPatterns"; + } }; Avoid using the mathematical symbols of the constant as names for the struct. Their connection can be noted in the @@ -144,12 +144,13 @@ Now we can define the model as a **CompartmentalModel** in the file model.h: const auto N = y[InfectionState::Susceptible] + y[InfectionState::Infectious] + y[InfectionState::Recovered]; - dydt[InfectionState::Susceptible] = params.template get>() * - params.template get>() * - y[InfectionState::Susceptible] * y[InfectionState::Infectious] / N; + dydt[InfectionState::Susceptible] = -params.template get>() * + params.template get>() * + y[InfectionState::Susceptible] * y[InfectionState::Infectious] / N; . . . } + }; Note that this class has a template parameter **LctStates** that defines the number of subcompartments per infection state. For LCT models, the class **CompartmentalModel** requires the following template arguments: @@ -165,4 +166,4 @@ It is also useful to implement the following methods within the model: - A function ``calculate_compartments()`` that accumulates the TimeSeries containing simulation results that are divided into subcompartments to a TimeSeries that conatins the simulation results according to the infection states without subcompartments. -- A function ``check_constraints()`` that checks that the model satisfies sensible constraints regarding parameters and initial conditions. \ No newline at end of file +- A function ``check_constraints()`` that checks that the model satisfies sensible constraints regarding parameters and initial conditions. diff --git a/docs/source/cpp/model_creation.rst b/docs/source/cpp/model_creation.rst index f6cec88541..5d4f6e1242 100644 --- a/docs/source/cpp/model_creation.rst +++ b/docs/source/cpp/model_creation.rst @@ -10,5 +10,5 @@ Here we collect information on how to create models. Ordinary differential equations Linear Chain Trick Stochastic-differential equations - Integro-differenatial equations + Integro-differential equations \ No newline at end of file diff --git a/docs/source/cpp/ode_creation.rst b/docs/source/cpp/ode_creation.rst index eacbb564b3..93ff9c12ae 100644 --- a/docs/source/cpp/ode_creation.rst +++ b/docs/source/cpp/ode_creation.rst @@ -146,7 +146,7 @@ Now we can define the model: const auto N = y[InfectionState::Susceptible] + y[InfectionState::Infectious] + y[InfectionState::Recovered]; - dydt[InfectionState::Susceptible] = params.template get>() * + dydt[InfectionState::Susceptible] = -params.template get>() * params.template get>() * y[InfectionState::Susceptible] * y[InfectionState::Infectious] / N; @@ -221,4 +221,4 @@ With the flows and classes also used by the CompartmentalModel, we can define a . . . } - }; \ No newline at end of file + }; diff --git a/docs/source/python/memilio_epidata.rst b/docs/source/python/memilio_epidata.rst index fe9d484f77..ca8874f22d 100644 --- a/docs/source/python/memilio_epidata.rst +++ b/docs/source/python/memilio_epidata.rst @@ -46,15 +46,16 @@ Usage ----- After installation the following functions are available: - * getcasedata: Downloads SARS-CoV-2 case data from Robert Koch-Institut (RKI-C). - * getpopuldata: Downloads population data for German federal states and counties from various public sources (P). - * getjhdata: Downloads COVID-19 case data from John Hopkins University (JH). - * getdividata: Downloads ICU data from German DIVI Intensivregister (DIVI). - * getsimdata: Downloads all data required for a simulation with the graph-metapopulation model which are SARS-CoV-2 case data(RKI-C), population data (P), ICU data (DIVI) and COVID-19 vaccination data from Robert Koch-Institut (RKI-V). - * getcommutermobility: Downloads data about commuter mobility from German Federal Employment Agency (BAA). - * gettestingdata: Downloads data about SARS-CoV-2 PCR tests from Robert Koch-Institut (RKI-T). - * gethospitalizationdata: Downloads data about COVID-19 hospitalizations data from Robert Koch-Institut (RKI-H) - * cleandata: Deletes all data files generated by the MEmilio Epidata package. + +* ``getcasedata``: Downloads SARS-CoV-2 case data from Robert Koch-Institut (RKI-C). +* ``getpopuldata``: Downloads population data for German federal states and counties from various public sources (P). +* ``getjhdata``: Downloads COVID-19 case data from John Hopkins University (JH). +* ``getdividata``: Downloads ICU data from German DIVI Intensivregister (DIVI). +* ``getsimdata``: Downloads all data required for a simulation with the graph-metapopulation model which are SARS-CoV-2 case data(RKI-C), population data (P), ICU data (DIVI) and COVID-19 vaccination data from Robert Koch-Institut (RKI-V). +* ``getcommutermobility``: Downloads data about commuter mobility from German Federal Employment Agency (BAA). +* ``gettestingdata``: Downloads data about SARS-CoV-2 PCR tests from Robert Koch-Institut (RKI-T). +* ``gethospitalizationdata``: Downloads data about COVID-19 hospitalizations data from Robert Koch-Institut (RKI-H) +* ``cleandata``: Deletes all data files generated by the MEmilio Epidata package. For a detailed description of the run options and the resulting data files written see the `epidata subfolder `_. From e15dda1e6065039daee17de8ba7d54357c1b5da8 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:34:35 +0200 Subject: [PATCH 06/25] [ci skip] Stochastic metapop review --- docs/source/cpp/smm.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/cpp/smm.rst b/docs/source/cpp/smm.rst index 0fdb670adf..f1892f530f 100644 --- a/docs/source/cpp/smm.rst +++ b/docs/source/cpp/smm.rst @@ -53,9 +53,9 @@ Using the infection states from above and two regions, there are five first-orde adoption_rates.push_back({InfectionState::I, InfectionState::D, mio::regions::Region(r), 0.01 / 5., {}}); } - //Set second-order adoption rate different for the two regions + //Set second-order adoption rate different for the two regions adoption_rates.push_back({InfectionState::S, InfectionState::E, mio::regions::Region(0), 0.1, {{InfectionState::C, 1}, {InfectionState::I, 0.5}}}); - adoption_rates.push_back({InfectionState::S, InfectionState::E, mio::regions::Region(0), 0.2, {{InfectionState::C, 1}, {InfectionState::I, 0.5}}}); + adoption_rates.push_back({InfectionState::S, InfectionState::E, mio::regions::Region(1), 0.2, {{InfectionState::C, 1}, {InfectionState::I, 0.5}}}); //Initialize model parameter model.parameters.get>() = adoption_rates; @@ -95,7 +95,7 @@ These populations have the class type **Populations** and can be set via: .. code-block:: cpp - double pop = 1000, numE = 0.001 * pop, numC = 0.0001 * pop, numI = 0.0001 * pop; + double pop = 1000, numE = 0.001 * pop, numC = 0.0001 * pop, numI = 0.0001 * pop, numR = 0, numD = 0; //Population is distributed equally to the regions for (size_t r = 0; r < num_regions; ++r) { @@ -118,11 +118,11 @@ As the spatial transition rates are dependent on infection state, region changes for (size_t i = 0; i < num_regions; ++i) { for (size_t j = 0; j < num_regions; ++j) if (i != j) { - transition_rates.push_back( - {InfectionState(s), mio::regions::Region(i), mio::regions::Region(j), 0.01}); - transition_rates.push_back( - {InfectionState(s), mio::regions::Region(j), mio::regions::Region(i), 0.01}); - } + transition_rates.push_back( + {InfectionState(s), mio::regions::Region(i), mio::regions::Region(j), 0.01}); + transition_rates.push_back( + {InfectionState(s), mio::regions::Region(j), mio::regions::Region(i), 0.01}); + } } } From 3d7238d441b582f945feb898afae33cef3b026b6 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:38:47 +0200 Subject: [PATCH 07/25] [ci skip] update citation --- README.md | 2 +- docs/source/citation.rst | 3 ++- docs/source/references.rst | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 722e8423cf..ad4d164be7 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ and, in particular, for - Hybrid agent-metapopulation-based models: Bicker J, Schmieding R, Meyer-Hermann M, Kühn MJ. (2025). *Hybrid metapopulation agent-based epidemiological models for efficient insight on the individual scale: A contribution to green computing*. *Infectious Disease Modelling* 10(2): 571-590. `https://doi.org/10.1016/j.idm.2024.12.015` - Graph Neural Networks: Schmidt A, Zunker H, Heinlein A, Kühn MJ. (2024). *Towards Graph Neural Network Surrogates Leveraging Mechanistic Expert Knowledge for Pandemic Response*. arXiv. `https://arxiv.org/abs/2411.06500` - ODE-based models with Linear Chain Trick: Plötzke L, Wendler A, Schmieding R, Kühn MJ. (2024). *Revisiting the Linear Chain Trick in epidemiological models: Implications of underlying assumptions for numerical solutions*. Submitted for publication. `https://doi.org/10.48550/arXiv.2412.09140` -- Behavior-based ODE models: Zunker H, Dönges P, Lenz P, Contreras S, Kühn MJ. (2025). *Risk-mediated dynamic regulation of effective contacts de-synchronizes outbreaks in metapopulation epidemic models*. arXiv. `https://arxiv.org/abs/2502.14428` +- Behavior-based ODE models: Zunker H, Dönges P, Lenz P, Contreras S, Kühn MJ. (2025). *Risk-mediated dynamic regulation of effective contacts de-synchronizes outbreaks in metapopulation epidemic models*. *Chaos, Solitons & Fractals* 199:116782. `https://doi.org/10.1016/j.chaos.2025.116782` **Getting started** diff --git a/docs/source/citation.rst b/docs/source/citation.rst index 3036d0e41b..bacc2c2a5d 100644 --- a/docs/source/citation.rst +++ b/docs/source/citation.rst @@ -13,4 +13,5 @@ and, in particular, for - **Hybrid agent-metapopulation-based models**: Bicker J, Schmieding R, Meyer-Hermann M, Kühn MJ. (2025). *Hybrid metapopulation agent-based epidemiological models for efficient insight on the individual scale: A contribution to green computing*. *Infectious Disease Modelling* 10(2): 571-590. `DOI:10.1016/j.idm.2024.12.015 `_ - **Graph Neural Networks**: Schmidt A, Zunker H, Heinlein A, Kühn MJ. (2024).*Towards Graph Neural Network Surrogates Leveraging Mechanistic Expert Knowledge for Pandemic Response*. arXiv. `arXiv:2411.06500 `_ - **ODE-based models with Linear Chain Trick**: Plötzke L, Wendler A, Schmieding R, Kühn MJ. (2024). *Revisiting the Linear Chain Trick in epidemiological models: Implications of underlying assumptions for numerical solutions*. Submitted for publication. `DOI:10.48550/arXiv.2412.09140 `_ -- **Behavior-based ODE models**: Zunker H, Dönges P, Lenz P, Contreras S, Kühn MJ. (2025). *Risk-mediated dynamic regulation of effective contacts de-synchronizes outbreaks in metapopulation epidemic models*. arXiv. `arXiv:2502.14428 `_ +- **Behavior-based ODE models**: Zunker H, Dönges P, Lenz P, Contreras S, Kühn MJ. (2025). *Risk-mediated dynamic regulation of effective contacts de-synchronizes outbreaks in metapopulation epidemic models*. *Chaos, Solitons & Fractals* 199:116782. `DOI:10.1016/j.chaos.2025.116782 `_ + diff --git a/docs/source/references.rst b/docs/source/references.rst index 4511b59fc1..eb19c550a0 100644 --- a/docs/source/references.rst +++ b/docs/source/references.rst @@ -6,7 +6,6 @@ The following gives an overview on (peer-reviewed) publications extending or usi Recently Submitted Publications -------------------------------------- -- Zunker H, Dönges P, Lenz P, Contreras S, Kühn MJ. (2025). *Risk-mediated dynamic regulation of effective contacts de-synchronizes outbreaks in metapopulation epidemic models*. arXiv. `arXiv:2502.14428 `_ - Schmidt A, Zunker H, Heinlein A, Kühn MJ. (2024). *Towards Graph Neural Network Surrogates Leveraging Mechanistic Expert Knowledge for Pandemic Response*. arXiv. `arXiv:2411.06500 `_ - Wendler AC, Plötzke L, Tritzschak H, Kühn MJ. (2024). *A nonstandard numerical scheme for a novel SECIR integro differential equation-based model with nonexponentially distributed stay times*. Submitted for publication. `arXiv:2408.12228 `_ - Plötzke L, Wendler A, Schmieding R, Kühn MJ. (2024). *Revisiting the Linear Chain Trick in epidemiological models: Implications of underlying assumptions for numerical solutions*. Submitted for publication. `DOI:10.48550/arXiv.2412.09140 `_ @@ -17,6 +16,8 @@ Peer-Reviewed Publications **2025** +- Zunker H, Dönges P, Lenz P, Contreras S, Kühn MJ. (2025). *Risk-mediated dynamic regulation of effective contacts de-synchronizes outbreaks in metapopulation epidemic models*. *Chaos, Solitons & Fractals* 199:116782. `DOI:10.1016/j.chaos.2025.116782 `_ + - Schmid N, Bicker J , Hofmann AF, Wallrafen-Sam K, Kerkmann D, Wieser A, Kühn MJ, Hasenauer J (2025). *Integrative Modeling of the Spread of Serious Infectious Diseases and Corresponding Wastewater Dynamics*. *Epidemics* 51:100836. `DOI:10.1016/j.epidem.2025.100836 `_ - Kerkmann D, Korf S, Nguyen K, Abele D, Schengen A, Gerstein C, Göbbert JH, Basermann A, Kühn MJ, Meyer-Hermann M (2025). *Agent-based modeling for realistic reproduction of human mobility and contact behavior to evaluate test and isolation strategies in epidemic infectious disease spread*. *Computers in Biology and Medicine* 193:110269. `DOI:10.1016/j.compbiomed.2025.110269 `_ From 0064b6c098ee32d9eb29776c77c039723b46c616 Mon Sep 17 00:00:00 2001 From: Sascha <51127093+xsaschako@users.noreply.github.com> Date: Fri, 18 Jul 2025 00:06:03 +0200 Subject: [PATCH 08/25] add figure description --- docs/source/development.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/source/development.rst b/docs/source/development.rst index 53a96e105e..0fb2dd7e2d 100644 --- a/docs/source/development.rst +++ b/docs/source/development.rst @@ -237,6 +237,32 @@ to your corresponding ``settings.json``. Docstrings in Python should be added for every function, as detailed in the C++ coding guidelines. However, the syntax is slightly different than for C++ code. An overview and examples can be found at https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html . +Figure colors and settings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to ensure that figures in the documentation and in the code have a consistent look, we use the following settings: + +**Default color scheme** + +- For figures in the documentation, we usually use the `matplotlib `_ library. +- The default color cycle is set to the `Set1 `_ colormap. + +**Colorblind-friendly alternatives** + +For better accessibility and when creating figures with many categories, consider using colorblind-friendly alternatives: + +- Use the `tab10 `_ colormap for up to 10 distinct categories +- For sequential data, prefer `viridis `_, `plasma`, or `cividis` colormaps +- For diverging data, use `RdBu `_ or `RdYlBu` colormaps +- Avoid using red-green color combinations without additional visual cues (patterns, shapes, etc.) + +**General figure guidelines** + +- Use consistent font sizes across all figures (typically 10-12pt for labels, 8-10pt for tick labels) +- Ensure sufficient contrast between colors and background +- Add appropriate legends and axis labels with units +- For line plots with multiple series, vary both color and line style (solid, dashed, dotted) for better distinction +- When possible, test figures with a colorblind simulator to ensure accessibility Git workflow ---------------------- From 9c410fa2302f8196bec2f45af8d45087c5b0b404 Mon Sep 17 00:00:00 2001 From: Sascha <51127093+xsaschako@users.noreply.github.com> Date: Fri, 18 Jul 2025 00:21:23 +0200 Subject: [PATCH 09/25] add review changes --- docs/source/cpp/io.rst | 2 +- docs/source/python/memilio_simulation.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/cpp/io.rst b/docs/source/cpp/io.rst index 325cac418a..a0a51a0342 100644 --- a/docs/source/cpp/io.rst +++ b/docs/source/cpp/io.rst @@ -101,7 +101,7 @@ The default serialization is intentionally less flexible than the serialize and - Every class member itself must be serializable, deserializable and assignable. -This feature is primarily meant to make data classes easy to (de)serialize, avoiding some repitition that is necessary +This feature is primarily meant to make data classes easy to (de)serialize, avoiding some repetition that is necessary when writing both a serialize and deserialize function. It can, however, be used for any class that should be serialized in its entirety, and that does not need to make any decisions or computations while doing so. For example, default serialization cannot be used if your class has optional members or values, or if one of its members is stored diff --git a/docs/source/python/memilio_simulation.rst b/docs/source/python/memilio_simulation.rst index ff37112e6b..f917330d03 100644 --- a/docs/source/python/memilio_simulation.rst +++ b/docs/source/python/memilio_simulation.rst @@ -13,8 +13,8 @@ Required Python packages: * scikit-build -For a succesful build, the development libraries for Python need to be installed, i.e. python3.x-dev. -Additionally, as this packages builds upon the MEmilio C++ library, +For a successful build, the development libraries for Python need to be installed, i.e. python3.x-dev. +Additionally, as this package builds upon the MEmilio C++ library, all dependencies of the main library need to be met. Read more about the C++ dependencies at :doc:`cpp <../getting_started>`. From 32febe9cfab3135adcbee07fc1682f87f867dc13 Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Fri, 18 Jul 2025 09:57:49 +0200 Subject: [PATCH 10/25] FIX: broken link in memilio-generation docs --- docs/source/python/memilio_generation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/python/memilio_generation.rst b/docs/source/python/memilio_generation.rst index 83fae181c7..ed7dbbf1a0 100644 --- a/docs/source/python/memilio_generation.rst +++ b/docs/source/python/memilio_generation.rst @@ -8,7 +8,7 @@ For a particular example, see the SEIR model with its files `oseir.cpp` and `ose This generating software was developed as a part of the Bachelor thesis `Automatische Codegenerierung für nutzerfreundliche mathematisch-epidemiologische Modelle `_. The following figure from Chapter 5 outlines the workflow of the generator. Blue boxes represent parts of the code generator and orange ones the input and output. Rectangular boxes contain classes with logic, the rest represent data. -.. image:: https://github.com/SciCompMod/memilio/main/blob/pycode/memilio-generation/generator_workflow.png +.. image:: ../../../pycode/memilio-generation/generator_workflow.png :alt: tikzGeneratorWorkflow Dependencies From ddd5f62bf9e6c37e16cef03215b7f9d37d27e2e7 Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:56:56 +0200 Subject: [PATCH 11/25] FIX: broken enumerations in memilio-generation docs --- docs/source/python/memilio_generation.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/python/memilio_generation.rst b/docs/source/python/memilio_generation.rst index ed7dbbf1a0..af2946f600 100644 --- a/docs/source/python/memilio_generation.rst +++ b/docs/source/python/memilio_generation.rst @@ -32,6 +32,7 @@ During the installation the package creates a compilation database (compile_comm The package provides an example script on how to use it in `memilio/tools`. The example uses the ode_seir model. Before running the example you have to do these steps of setup: + * Change `config.json.txt `_. * Check if the parameters set in __post_init__() of the [ScannerConfig class](./memilio/generation/scanner_config.py) match with the cpp-class names. @@ -60,6 +61,7 @@ Development ----------- When implementing new model features you can follow these steps: + * Add necessary configurations to `config.json.txt `_ and add corresponding attributes to the ``ScannerConfig``. * For the features you want to implement, find the nodes in the abstract syntax tree (AST) (use method Scanner.output_ast_file(); see the example in tools/). * Add the extraction of those features. Therefore you need to change the "check_..."-methods corresponding to the ``CursorKind`` of your nodes in the ``Scanner``. If there is no corresponding "check_..."-method you need to write a new one and add it to the switch-method (scanner.switch_node_kind()). From e963ab07244ed27afbaf1920e83bce111d33ca7c Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Fri, 18 Jul 2025 11:15:20 +0200 Subject: [PATCH 12/25] FIX: links and grammar in memeilio-generation docs --- docs/source/python/memilio_generation.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/python/memilio_generation.rst b/docs/source/python/memilio_generation.rst index af2946f600..09b0177389 100644 --- a/docs/source/python/memilio_generation.rst +++ b/docs/source/python/memilio_generation.rst @@ -34,23 +34,23 @@ The package provides an example script on how to use it in `memilio/tools`. The Before running the example you have to do these steps of setup: * Change `config.json.txt `_. -* Check if the parameters set in __post_init__() of the [ScannerConfig class](./memilio/generation/scanner_config.py) match with the cpp-class names. +* Check if the parameters set in ``__post_init__()`` of the `ScannerConfig class `_ match with the cpp-class names. Example: -After processing as described in the previous paragraph, run the example with the command (path according to the current folder): +After processing as described in the previous paragraph, run the example with the command (adjust the path according to your current folder): .. code-block:: console python memilio/tools/example_oseir.py -When working on a new model you can copy the example script and add an additional segment to the config.json.txt. The setup works similar to the example. Additionaly you can print the AST of your model into a file (Usefull for development/debugging). +When working on a new model, you can copy the example script and add an additional segment to the config.json.txt. The setup works similar to the example. Additionaly, you can print the AST of your model into a file for development or debugging. Testing ------- -The package provides a test suite in `memilio/generation_test `_. -To run the tests, simply run the following command: +The package provides a test suite in `memilio/generation_test `_. +To run the tests, simply use the following command: .. code-block:: console @@ -64,9 +64,9 @@ When implementing new model features you can follow these steps: * Add necessary configurations to `config.json.txt `_ and add corresponding attributes to the ``ScannerConfig``. * For the features you want to implement, find the nodes in the abstract syntax tree (AST) (use method Scanner.output_ast_file(); see the example in tools/). -* Add the extraction of those features. Therefore you need to change the "check_..."-methods corresponding to the ``CursorKind`` of your nodes in the ``Scanner``. If there is no corresponding "check_..."-method you need to write a new one and add it to the switch-method (scanner.switch_node_kind()). +* Add the extraction of those features. Therefore you need to change the "check_..."-methods corresponding to the ``CursorKind`` of your nodes in the ``Scanner``. If there is no corresponding "check\_..."-method you need to write a new one and add it to the switch-method (``scanner.switch_node_kind()``). * Extend the ``IntermediateRepresentation`` for the new model features. -* Adjust the `cpp-template `_ and the `string-template-methods `_. If needed, use new identifiers and write new string-template-methods for them. +* Adjust the `cpp-template `_ and the `string-template-methods `_. If needed, use new identifiers and write new string-template-methods for them. * Adjust the substitution dictionaries in the ``Generator``. -* Write new/Adjust script in the `tool folder `_ for the model and try to run. +* Write new/Adjust scripts in the `tool folder `_ for the model and try to run. * Update tests. \ No newline at end of file From 82756b726e17526c2b3079036c4d1ecdb01a4adc Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Fri, 18 Jul 2025 12:42:43 +0200 Subject: [PATCH 13/25] CHG: Add CI benchmarking issue to Development --- docs/source/cpp/development.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/cpp/development.rst b/docs/source/cpp/development.rst index ff19249dae..31acfe0003 100644 --- a/docs/source/cpp/development.rst +++ b/docs/source/cpp/development.rst @@ -34,7 +34,7 @@ Agent-based model benchmarks There is a suite of benchmarks for the ABM that can be used to check performance. The suite contains setups of different sizes. If you added a new feature (i.e., you didn't just fix a bug in an existing feature), make sure the feature is actually used by the benchmark. Add it to the benchmark if necessary, then run the benchmark to see if the cost for the new feature is acceptable and as expected. -Most new features will add some overhead, but this needs to be limited and in proportion to the added value of the feature so runtime doesn't grow out of control. Optional features that can be disabled should only incur minimal overhead. If you did not add any new feature, just run the benchmark before and after your changes to make sure there are no performance regressions. This process will hopefully be automated soon by running benchmarks in the CI. +Most new features will add some overhead, but this needs to be limited and in proportion to the added value of the feature so runtime doesn't grow out of control. Optional features that can be disabled should only incur minimal overhead. If you did not add any new feature, just run the benchmark before and after your changes to make sure there are no performance regressions. This process will hopefully be automated soon by running benchmarks in the CI (see the `corresponding issue `_ for progress). Build the benchmarks by defining the CMake variable ``MEMILIO_BUILD_BENCHMARKS=ON`` in the build. Make sure to use a **Release** build to test performance. From 296fa609281cf93ad8b6cdb696b9e88110edc0b1 Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:17:54 +0200 Subject: [PATCH 14/25] FIX: Typos in ode_creation --- docs/source/cpp/ode_creation.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/cpp/ode_creation.rst b/docs/source/cpp/ode_creation.rst index 93ff9c12ae..d71f86d0f4 100644 --- a/docs/source/cpp/ode_creation.rst +++ b/docs/source/cpp/ode_creation.rst @@ -19,12 +19,12 @@ given by a system of ordinary differential equations. For example we consider a and some initial values for :math:`t=0`. Here :math:`N_{\perp D} := S(t) + I(t) + R(t)`. This type of model is called compartmental model, because the model population is represented by discrete infection -states **S** usceptible, **I** nfectious, **R** ecovered, **D** eceased, also called compartments. +states **S**\usceptible, **I**\nfectious, **R**\ecovered, **D**\eceased, also called compartments. How to define an ODE model -------------------------- -To define an ODE model in MEmilio, there are two options. You can define a CompartmentalModel or FlowModel, which +To define an ODE model in MEmilio, there are two options. You can define a CompartmentalModel or a FlowModel, which use different methods to define the right hand side of the mathematical model above. Both classes need definitions for the infection states, population and parameters it uses. The FlowModel additionally requires a list of flows. @@ -35,9 +35,9 @@ other noteworthy features of the model in shortened form. All files in the follo Infection states ~~~~~~~~~~~~~~~~ -First we define an :code:`enum class` called InfectionState in the file "infection_state.h", which contains an entry +First we define an :code:`enum class` called ``InfectionState`` in the file "infection_state.h", which contains an entry for each infection state of the mathematical model, followed by an entry called :code:`Count`. This enumerates the -compartments starting from 0, with Count being equal to the number of compartments. For example: +compartments starting from 0, with Count being equal to the number of compartments. In our example we have: .. code-block:: cpp @@ -55,7 +55,7 @@ Parameters Next, we define the parameters in "parameters.h", which consist of a struct for each constant used in the mathematical model. This struct must define the data type, name and default value of the constant. For example, for the time a -person stays infectious :math:`T_I` we define a struct +person stays infectious, :math:`T_I`, we define a struct .. code-block:: cpp @@ -113,7 +113,7 @@ Population ~~~~~~~~~~ The population will be stored in a vector, with a component for each infection state. We define it using the class -`mio::Population`. +``mio::Population``. .. code-block:: cpp From e68edd1cf49be8ca0df657537c86387bec371f29 Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:58:55 +0200 Subject: [PATCH 15/25] CHG: Add Review changes to LCT creation --- docs/source/cpp/lct_creation.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/source/cpp/lct_creation.rst b/docs/source/cpp/lct_creation.rst index 5cb5a9560f..4013760d0d 100644 --- a/docs/source/cpp/lct_creation.rst +++ b/docs/source/cpp/lct_creation.rst @@ -5,7 +5,7 @@ The mathematical model ---------------------- Before implementing a model in MEmilio, we need to do some math, in particular, define an initial value problem -given by a system of ordinary differential equations. In the here considered example, we consider a SIRD model where we +given by a system of ordinary differential equations. Here, we consider a SIRD model where we divide the Infectious compartment into :math:`n` subcompartments. The model is defined by .. math:: @@ -21,7 +21,7 @@ divide the Infectious compartment into :math:`n` subcompartments. The model is d with :math:`I(t) = \sum_{j=1}^n I_j(t)` and some initial values for :math:`t=0`. Here :math:`N_{\perp D} := S(t) + I(t) + R(t)`. This type of model belongs to the class of compartmental models because the model population is represented by discrete infection -states **S**usceptible, **I**nfectious, **R**ecovered, **D**eceased, also called compartments. +states **S**\usceptible, **I**\nfectious, **R**\ecovered, **D**\eceased, also called compartments. Infection states ~~~~~~~~~~~~~~~~ @@ -46,7 +46,7 @@ Parameters Next, we define the parameters in "parameters.h", which consist of a struct for each constant used in the mathematical model. This struct must define the data type, name and default value of the constant. For example, for the time a -person stays infectious :math:`T_I` we define a struct: +person stays infectious, :math:`T_I`, we define a struct: .. code-block:: cpp @@ -65,7 +65,6 @@ person stays infectious :math:`T_I` we define a struct: } }; -and for the contact rate :math:`\phi` a struct We also define a parameter ``ContactPatterns`` determining the contacts of the different groups by: @@ -86,9 +85,11 @@ We also define a parameter ``ContactPatterns`` determining the contacts of the d } }; -Avoid using the mathematical symbols of the constant as names for the struct. Their connection can be noted in the +Avoid using the mathematical symbol of a constant as name for the struct. Their connection can be noted down in the documentation of these structs. -Additionally, we can determine parameters influencing the infection dynamics. In the case of the LCT-SECIR model we use the parameters ``TransmissionProbabilityOnContact``, ``RelativeTransmissionNoSymptoms``, ``RiskOfInfectionFromSymptomatic``, ``StartDay`` and ``Seasonality``. For each parameter, we need to define a default value and a name as for the above parameters. +Additionally, we can determine parameters influencing the infection dynamics. In the case of the LCT-SECIR model we use +the parameters ``TransmissionProbabilityOnContact``, ``RelativeTransmissionNoSymptoms``, ``RiskOfInfectionFromSymptomatic``, ``StartDay`` and ``Seasonality``. +For each parameter, we need to define a default value and a name as for the above parameters. Finally, define a type :code:`Parameters` by listing all parameter structs as template arguments of a :code:`mio::ParameterSet`: @@ -107,14 +108,14 @@ Population ~~~~~~~~~~ The population will be stored in a vector, with a component for each subcompartment of every infection state. We define -it using the class **LctPopulations**. +it using the class ``LctPopulations``. .. code-block:: cpp template using Population = mio::LctPopulations; -where **LctStates** contains the number of subcompartments per infection state. +where ``LctStates`` contains the number of subcompartments per infection state. Importantly, this class allows further stratifying the population vector, with the most common example being adding age groups. @@ -152,18 +153,17 @@ Now we can define the model as a **CompartmentalModel** in the file model.h: } }; -Note that this class has a template parameter **LctStates** that defines the number of subcompartments per infection state. -For LCT models, the class **CompartmentalModel** requires the following template arguments: +Note that this class has a template parameter ``LctStates`` that defines the number of subcompartments per infection state. +For LCT models, the class ``CompartmentalModel`` requires the following template arguments: -- type of floating point type, here **ScalarType**, -- a class **InfectionState** containing the compartments, see above, -- the class **LctPopulations** which is a class template for compartment populations of LCT models depending on the floating point type and the considered **LctStates**, -- the class **Parameters** containing all required parameters, see above. +- type of floating point type, here ``ScalarType``, +- a class ``InfectionState`` containing the compartments, see above, +- the class ``LctPopulations`` which is a class template for compartment populations of LCT models depending on the floating point type and the considered ``LctStates``, +- the class ``Parameters`` containing all required parameters, see above. The function ``get_derivatives()`` evaluates the right-hand-side of the ODE :math:`dydt = f(y, t)` that we want to solve, see above. It is also useful to implement the following methods within the model: -- A function ``calculate_compartments()`` that accumulates the TimeSeries containing simulation results that are divided -into subcompartments to a TimeSeries that conatins the simulation results according to the infection states without subcompartments. +- A function ``calculate_compartments()`` that accumulates the TimeSeries containing simulation results that are divided into subcompartments to a TimeSeries that conatins the simulation results according to the infection states without subcompartments. - A function ``check_constraints()`` that checks that the model satisfies sensible constraints regarding parameters and initial conditions. From 8ffec42bf8c6fd04e3fe7bfd2c4b2876f81763a5 Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Fri, 18 Jul 2025 14:18:11 +0200 Subject: [PATCH 16/25] FIX: All links in Input/Output were broken --- docs/source/cpp/io.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/cpp/io.rst b/docs/source/cpp/io.rst index a0a51a0342..a48b5500fb 100644 --- a/docs/source/cpp/io.rst +++ b/docs/source/cpp/io.rst @@ -6,7 +6,7 @@ This document describes utilities for reading and writing data from and to files - The serialization framework, that can be used to define the structure of data without using a specific file format. There are implementations of the framework for different formats. The framework is described in detail below, also - see the `serialization example <../../examples/serialize.cpp>`__. + see the `serialization example `__. - The command line interface, that can be used to set (and get) values of a ``ParameterSet``. @@ -272,8 +272,8 @@ Working with the History object The History object provides a way to save data throughout the simulation process. It offers an interface where users can define the data to be saved from a given object using Loggers and the method of saving it using Writers. Afterward, the user can access this data from the History object and manipulate it. For a basic Logger use case, refer to -`this example <../../examples/history.cpp>`__. For an example demonstrating using a Logger in the ABM, refer to -`this example <../../examples/abm_history_example.cpp>`__. +`this example `__. For an example demonstrating using a Logger in the ABM, refer to +`this example `__. Loggers ~~~~~~~ @@ -293,7 +293,7 @@ functions is the same as the one given to the ``History`` member-function ``Hist Users can derive their Loggers from ``LogOnce`` or ``LogAlways`` to use a predefined ``should_log`` function. ``LogOnce`` logs only at the first call of ``Logger::log()``, while ``LogAlways`` logs every time ``log`` is called. All implemented Loggers must be default constructible/destructible. For user-defined examples in the ABM, refer to -`this file <../../models/abm/common_abm_loggers.h>`__. +`this file `__. .. code-block:: cpp @@ -324,9 +324,9 @@ user-implemented ``Writer`` must have a ``Data`` Type and implement the - ``add_record``: This manipulates the passed Data member of the ``History`` class to store the value ``t`` returned by the Loggers. It is used whenever ``History::log`` is called and ``Logger::should_log`` is true. -A predefined universal ``Writer`` called ``DataWriterToMemory`` is already implemented in `history.h `__. +A predefined universal ``Writer`` called ``DataWriterToMemory`` is already implemented in `history.h `__. This stores the data from the loggers in a tuple of vectors every time the Logger is called. Another ``Writer`` named -``TimeSeriesWriter`` can be found in `this file <../../models/abm/common_abm_loggers.h>`__, which saves data in a +``TimeSeriesWriter`` can be found in `this file `__, which saves data in a Timeseries. The according Logger has to have a suitable return type. .. code-block:: cpp @@ -354,9 +354,9 @@ For this, the lifetime of the ``History`` has to be as long as one wants to have should not be constructed in the function it is called in when data is needed later. To access data from a specific Logger, one can use ``std::get`` where x is the position of the Logger in the template -argument list of the ``History`` object. Refer to `this example <../../examples/history.cpp>`__ for a simple -implementation of a history object and `this full ABM example <../../simulation/abm.cpp>`__ for a more advanced use case +argument list of the ``History`` object. Refer to `this example `__ for a simple +implementation of a history object and `this full ABM example `__ for a more advanced use case of the History object with several History objects in use. As mentioned, if multiple Writers have to be used simultaneously, a separate History object is needed for each Writer. -For a use case of this, refer to `the ABM Simulation advance function <../../models/abm/simulation.cpp>`__. +For a use case of this, refer to `the ABM Simulation advance function `__. From fc3a1d868d19e9b666a4c4e42d31a38a67603b68 Mon Sep 17 00:00:00 2001 From: reneSchm <49305466+reneSchm@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:08:45 +0200 Subject: [PATCH 17/25] clarifications on ABM benchmarking --- docs/source/cpp/development.rst | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/source/cpp/development.rst b/docs/source/cpp/development.rst index 31acfe0003..d6c7813d87 100644 --- a/docs/source/cpp/development.rst +++ b/docs/source/cpp/development.rst @@ -1,10 +1,10 @@ Development -================================= +=========== .. _performance-monitoring-cpp: Performance monitoring ---------------------------------- +---------------------- LIKWID ~~~~~~ @@ -30,11 +30,15 @@ Set the CMake variable ``MEMILIO_USE_LIKWID=ON`` to enable LIKWID support and ru For more details see the LIKWID documentation, available `here `_. Agent-based model benchmarks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There is a suite of benchmarks for the ABM that can be used to check performance. The suite contains setups of different sizes. If you added a new feature (i.e., you didn't just fix a bug in an existing feature), make sure the feature is actually used by the benchmark. Add it to the benchmark if necessary, then run the benchmark to see if the cost for the new feature is acceptable and as expected. +There is a suite of benchmarks for the ABM that are used to check its performance. The suite contains setups of different sizes, to check that the model maintains its linear scaling. -Most new features will add some overhead, but this needs to be limited and in proportion to the added value of the feature so runtime doesn't grow out of control. Optional features that can be disabled should only incur minimal overhead. If you did not add any new feature, just run the benchmark before and after your changes to make sure there are no performance regressions. This process will hopefully be automated soon by running benchmarks in the CI (see the `corresponding issue `_ for progress). +When you make any changes to the ABM or code used by it, run the benchmarks to check that its performance did not degrade. What exactly impacts the ABM's performance can be hard to tell (even parameter values may change its runtime), so it is best to run the bencharks on any change to the main library or the ABM specific code. + +If you added a new feature (i.e., you didn't just fix a bug in an existing feature), make sure the feature is actually used by the benchmark. Add it to the benchmark if necessary, then run the benchmark to see if the cost for the new feature is acceptable and as expected. + +Most new features will add some overhead, but this needs to be limited and in proportion to the added value of the feature so runtime doesn't grow out of control. Optional features that can be disabled should only incur minimal overhead. Always make sure there are no major performance regressions compared to the code in the current *main* branch. Build the benchmarks by defining the CMake variable ``MEMILIO_BUILD_BENCHMARKS=ON`` in the build. Make sure to use a **Release** build to test performance. @@ -91,6 +95,10 @@ However, it can be expensive because long-running benchmarks are repeated. **Suggested workflow:** -1. Run with 5–10 repetitions to check variance. -2. Increase ``benchmark_min_time`` until variance is acceptable. -3. Continue benchmarking with 1 repetition and the adjusted minimum time. \ No newline at end of file +1. Use the benchmark to check the performance of your current changes: + + 1. Run with 5–10 repetitions to check variance. + 2. Increase ``benchmark_min_time`` until variance is acceptable. + 3. Continue benchmarking with 1 repetition and the adjusted minimum time. + +2. Repeat the benchmark *on the main branch* with the same ``benchmark_min_time`` and compare the results. From bdffc95e5b2fb23c18ce2d32e2a8b165842d7cfe Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Tue, 22 Jul 2025 14:22:23 +0200 Subject: [PATCH 18/25] Restructure Development section to add types page --- docs/source/cpp/data_types.rst | 22 ++++ docs/source/cpp/development.rst | 104 +-------------- ..._timers.rst => performance_monitoring.rst} | 122 ++++++++++++++++-- docs/source/index.rst | 1 - 4 files changed, 141 insertions(+), 108 deletions(-) create mode 100644 docs/source/cpp/data_types.rst rename docs/source/cpp/{performance_timers.rst => performance_monitoring.rst} (62%) diff --git a/docs/source/cpp/data_types.rst b/docs/source/cpp/data_types.rst new file mode 100644 index 0000000000..6f381b7114 --- /dev/null +++ b/docs/source/cpp/data_types.rst @@ -0,0 +1,22 @@ +Common data types +----------------- + +Here we want to explain the intention behind the non-standard data types that are used throughout MEmilio. + +FP +~~ + +The template :code:`FP` and the derived types like :code:`UncertainValue` in these examples are commonly used throughout MEmilio. +:code:`FP` is a floating point type, usually :code:`double`. An :code:`UncertainValue` holds a value of type +:code:`FP` as well as (optionally) a distribution to sample new values from, e.g. for a parameter study. + +.. dropdown:: :fa:`gears` Expert's settings + + The type ``mio::AgeGroup`` is a typesafe ``size_t``, meaning an integer that cannot be confused with other integer + types. So assignment, addition, etc. only works with another ``mio::AgeGroup``, not ``size_t`` or another integer + type. This is useful for function interfaces or indexing, as it makes it (nearly) impossible to mix up, e.g., age + groups with infection states. Check out ``mio::Index`` if you want to learn more. + + The type ``mio::Populations`` is an extension of a ``mio::CustomIndexArray``, which is a template type that manages + a flat array. Its main purpose is to allow multidimensional indexing into this array, using typesafe indices like + a ``mio::Index`` or a ``enum class``. \ No newline at end of file diff --git a/docs/source/cpp/development.rst b/docs/source/cpp/development.rst index d6c7813d87..75e5a0524c 100644 --- a/docs/source/cpp/development.rst +++ b/docs/source/cpp/development.rst @@ -1,104 +1,10 @@ Development =========== -.. _performance-monitoring-cpp: +Here we collect some information that is relevant for the development processes of MEmilio. -Performance monitoring ----------------------- +.. toctree:: + :maxdepth: 2 -LIKWID -~~~~~~ - -To measure the performance of the code, we use LIKWID. We recommend measuring the performance on an HPC system with LIKWID installed or refer to ``_ on how to get LIKWID. -Run ``likwid-perfctr ./bin/my_example`` to measure the performance of the entire example. To measure the performance of a specific part, use the LIKWID marker API: - -.. code-block:: cpp - - #include - - // ... - - LIKWID_MARKER_INIT; - - LIKWID_MARKER_START("my_marker"); - // code to be measured - LIKWID_MARKER_STOP("my_marker"); - - LIKWID_MARKER_CLOSE; - -Set the CMake variable ``MEMILIO_USE_LIKWID=ON`` to enable LIKWID support and run ``likwid-perfctr -m ./bin/my_example``. -For more details see the LIKWID documentation, available `here `_. - -Agent-based model benchmarks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There is a suite of benchmarks for the ABM that are used to check its performance. The suite contains setups of different sizes, to check that the model maintains its linear scaling. - -When you make any changes to the ABM or code used by it, run the benchmarks to check that its performance did not degrade. What exactly impacts the ABM's performance can be hard to tell (even parameter values may change its runtime), so it is best to run the bencharks on any change to the main library or the ABM specific code. - -If you added a new feature (i.e., you didn't just fix a bug in an existing feature), make sure the feature is actually used by the benchmark. Add it to the benchmark if necessary, then run the benchmark to see if the cost for the new feature is acceptable and as expected. - -Most new features will add some overhead, but this needs to be limited and in proportion to the added value of the feature so runtime doesn't grow out of control. Optional features that can be disabled should only incur minimal overhead. Always make sure there are no major performance regressions compared to the code in the current *main* branch. - -Build the benchmarks by defining the CMake variable ``MEMILIO_BUILD_BENCHMARKS=ON`` in the build. Make sure to use a **Release** build to test performance. - -.. code-block:: bash - - cmake .. -DMEMILIO_BUILD_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=Release - cmake --build . - -Run the benchmark executable: - -.. code-block:: bash - - ./build/bin/abm_benchmark - -Each benchmark is run for a number of iterations and the average time is reported. - -.. code-block:: text - - Benchmark Time CPU Iterations - --------------------------------------------------------------------------- - abm_benchmark/abm_benchmark_50k 7583 ms 7583 ms 1 - abm_benchmark/abm_benchmark_100k 18216 ms 18214 ms 1 - abm_benchmark/abm_benchmark_200k 41492 ms 41489 ms 1 - -You may get a warning: - -.. code-block:: text - - ***WARNING*** CPU scaling is enabled, the benchmark real time measurements may be noisy and will incur extra overhead. - -If possible, disable CPU scaling to improve the consistency of results. See the Google Benchmark documentation here: -https://google.github.io/benchmark/reducing_variance.html - -Also, try to reduce other system load during the benchmark run. - -If it is not possible to disable frequency scaling, increase the runtime of the benchmark using the commands below. Constant CPU frequency is necessary to get the most reliable results and to measure small differences. - -**REMINDER:** Don't forget to re-enable CPU scaling after you ran the benchmarks to save energy. Rebooting may restore the settings as well. - -The benchmark executable has a number of command line arguments that customize execution. Use ``--help`` to list them all. - -Two important options for consistency and stability: - -- ``--benchmark_min_time=``: Iterate each benchmark so that the total runtime is at least ``T`` seconds. - Default is 1 second, which may not be enough. - Try 60 seconds for better stability (you may need to experiment). - -- ``--benchmark_repetitions=``: Repeat each benchmark ``N`` times and report mean, median, and variance. - (Repetitions are **not** iterations; a benchmark can be repeated 10 times with 5 iterations each. Each repetition runs for at least the minimum time.) - -``benchmark_repetitions`` is useful to check timing consistency, as it reports variance. -However, it can be expensive because long-running benchmarks are repeated. -``benchmark_min_time`` increases iterations only for fast-running benchmarks, which tend to be less stable. - -**Suggested workflow:** - -1. Use the benchmark to check the performance of your current changes: - - 1. Run with 5–10 repetitions to check variance. - 2. Increase ``benchmark_min_time`` until variance is acceptable. - 3. Continue benchmarking with 1 repetition and the adjusted minimum time. - -2. Repeat the benchmark *on the main branch* with the same ``benchmark_min_time`` and compare the results. + performance_monitoring + data_types \ No newline at end of file diff --git a/docs/source/cpp/performance_timers.rst b/docs/source/cpp/performance_monitoring.rst similarity index 62% rename from docs/source/cpp/performance_timers.rst rename to docs/source/cpp/performance_monitoring.rst index 6d7f39cc90..7959a02b56 100644 --- a/docs/source/cpp/performance_timers.rst +++ b/docs/source/cpp/performance_monitoring.rst @@ -1,11 +1,40 @@ +.. _performance-monitoring-cpp: + +Performance monitoring +====================== + +LIKWID +------ + +To measure the performance of the code, we use LIKWID. We recommend measuring the performance on an HPC system with LIKWID installed or refer to ``_ on how to get LIKWID. +Run ``likwid-perfctr ./bin/my_example`` to measure the performance of the entire example. To measure the performance of a specific part, use the LIKWID marker API: + +.. code-block:: cpp + + #include + + // ... + + LIKWID_MARKER_INIT; + + LIKWID_MARKER_START("my_marker"); + // code to be measured + LIKWID_MARKER_STOP("my_marker"); + + LIKWID_MARKER_CLOSE; + +Set the CMake variable ``MEMILIO_USE_LIKWID=ON`` to enable LIKWID support and run ``likwid-perfctr -m ./bin/my_example``. +For more details see the LIKWID documentation, available `here `_. + + Performance Timers -================== +------------------ Here we present MEmilio's own timing framework. Timer usage ------------ +~~~~~~~~~~~ In this section we present how to use the AutoTimer class. This is the preferred way of using the timing framework, as the class takes care of running the timer, managing its lifetime for later evaluation, and ensuring thread safety with @@ -20,7 +49,7 @@ You can also try out the `code example ``: Iterate each benchmark so that the total runtime is at least ``T`` seconds. + Default is 1 second, which may not be enough. + Try 60 seconds for better stability (you may need to experiment). + +- ``--benchmark_repetitions=``: Repeat each benchmark ``N`` times and report mean, median, and variance. + (Repetitions are **not** iterations; a benchmark can be repeated 10 times with 5 iterations each. Each repetition runs for at least the minimum time.) + +``benchmark_repetitions`` is useful to check timing consistency, as it reports variance. +However, it can be expensive because long-running benchmarks are repeated. +``benchmark_min_time`` increases iterations only for fast-running benchmarks, which tend to be less stable. + +**Suggested workflow:** + +1. Use the benchmark to check the performance of your current changes: + + 1. Run with 5–10 repetitions to check variance. + 2. Increase ``benchmark_min_time`` until variance is acceptable. + 3. Continue benchmarking with 1 repetition and the adjusted minimum time. + +2. Repeat the benchmark *on the main branch* with the same ``benchmark_min_time`` and compare the results. diff --git a/docs/source/index.rst b/docs/source/index.rst index 4f0e2e25d9..1831069186 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -52,7 +52,6 @@ Contents cpp/model_usage cpp/model_creation cpp/development - cpp/performance_timers .. toctree:: :maxdepth: 2 From 71be7ae6352bb04594eacbfcad295b00849ef389 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Tue, 22 Jul 2025 14:37:32 +0200 Subject: [PATCH 19/25] Docu review --- docs/source/cpp/models/oseair.rst | 6 +++--- docs/source/cpp/models/osecir.rst | 26 +++++++++++--------------- docs/source/cpp/models/oseir.rst | 28 ++++++++++++++-------------- docs/source/cpp/ode.rst | 31 +++++++++++++++---------------- 4 files changed, 43 insertions(+), 48 deletions(-) diff --git a/docs/source/cpp/models/oseair.rst b/docs/source/cpp/models/oseair.rst index 24d15a60ce..c4ad6b4312 100644 --- a/docs/source/cpp/models/oseair.rst +++ b/docs/source/cpp/models/oseair.rst @@ -1,8 +1,8 @@ -ODE SEAIR Compartment Model +ODE-based SEAIR-type model =========================== -This model is an extended ODE type model. The six compartments +This model is an extended ODE-type model. The six compartments - **Susceptible** (:math:`S`): may become Exposed at any time. - **Exposed** (:math:`E`): becomes Asymptomatic after some time. @@ -65,4 +65,4 @@ Below is an overview of the model architecture and its compartments. Overview of the ``oseair`` namespace: ----------------------------------------- -.. doxygennamespace:: mio::oseair \ No newline at end of file +.. doxygennamespace:: mio::oseair diff --git a/docs/source/cpp/models/osecir.rst b/docs/source/cpp/models/osecir.rst index 0b81b68632..b04b663907 100644 --- a/docs/source/cpp/models/osecir.rst +++ b/docs/source/cpp/models/osecir.rst @@ -1,12 +1,11 @@ ODE-based SECIR-type model =========================== -The ODE-SECIR module models and simulates an epidemic using an approach based on ordinary differential equations. +The ODE-SECIR module models and simulates an epidemic using an ODE-based SECIR-type model approach. The model is particularly suited for pathogens with pre- or asymptomatic infection states and when severe or critical -states are possible. The model assumes perfect immunity after recovery and is thus only suited for epidemic use cases. -In the following, we present the model in detail. +symptoms are possible. The model assumes perfect immunity after recovery and is thus only suited for epidemic use cases. -The infection states and the transitions (also see next to sections) are visualized in the following image. +The infection states and the transitions (also see next two sections) are visualized in the following graph. .. image:: https://github.com/SciCompMod/memilio/assets/70579874/46b09e8a-d083-4ef9-8328-21975890b60f :alt: secir_model @@ -69,7 +68,7 @@ see :doc:`Model Creation <../ode_creation>`. Parameters ---------- -The model implements the following parameters. +The model implements the following parameters: .. list-table:: :header-rows: 1 @@ -165,7 +164,7 @@ For age-resolved models, you need to set the initial conditions for each age gro Nonpharmaceutical Interventions ------------------------------- -In the SECIR model, nonpharmaceutical interventions (NPIs) are implemented through dampings in the contact matrix. These dampings reduce the contact rates between different groups to simulate interventions. +In the SECIR model, nonpharmaceutical interventions (NPIs) are implemented through dampings to the contact matrix. These dampings reduce the contact rates between different groups to simulate interventions. Basic dampings can be added to the contact matrix as follows: @@ -188,7 +187,7 @@ For age-resolved models, you can apply different dampings to different groups: contact_matrix.add_damping(Eigen::VectorX::Constant((size_t)nb_groups, 0.7).asDiagonal(), mio::SimulationTime(30.)); -The SECIR model also supports dynamic NPIs based on epidemic thresholds. These are implemented in the model specific Simulation class and are automatically triggered based on predefined criteria, such as the percentage of infected individuals in the population. +The SECIR model also supports dynamic NPIs based on epidemic thresholds. These are implemented in the model specific **Simulation** class and are automatically triggered based on predefined criteria, such as the percentage of infected individuals in the population. For more complex scenarios, such as real-world lockdown modeling, you can implement detailed NPIs with location-specific dampings. The SECIR model supports contact matrices for different locations (e.g., home, school, work, other) and can apply different dampings to each location. @@ -238,7 +237,7 @@ You can create intervention types that target specific locations with different Holidays, }; -For example, to implement a complex lockdown scenario with multiple interventions starting on a specific date: +A complex lockdown scenario with multiple interventions starting on a specific date can be implemented via: .. code-block:: cpp @@ -252,7 +251,7 @@ For example, to implement a complex lockdown scenario with multiple intervention contact_dampings.push_back(social_events(start_lockdown, 0.6, 0.8)); contact_dampings.push_back(physical_distancing(start_lockdown, 0.4, 0.6)); -For dynamic NPIs that activate automatically based on thresholds: +For dynamic NPIs that are automatically activated based on thresholds: .. code-block:: cpp @@ -272,7 +271,7 @@ The SECIR model offers two simulation functions: 1. **simulate**: Standard simulation that tracks the compartment sizes over time 2. **simulate_flows**: Extended simulation that additionally tracks the flows between compartments -Basic simulation: +Standard simulation: .. code-block:: cpp @@ -322,7 +321,7 @@ The output of the simulation is a `TimeSeries` object containing the sizes of ea Eigen::VectorXd last_value = secir.get_last_value(); double last_time = secir.get_last_time(); -For flow simulations, the result consists of two `TimeSeries` objects, one for compartment sizes and one for flows: +For flow simulations, the result consists of two `mio::TimeSeries` objects, one for compartment sizes and one for flows: .. code-block:: cpp @@ -352,7 +351,7 @@ Additionally, you can export the results to a CSV file: // Export results to CSV with default settings secir.export_csv("simulation_results.csv"); -The SECIR model also provides utility functions to extract specific measures, such as the reproduction number: +The ODE-SECIR model also provides utility functions to extract specific measures, such as the reproduction number: .. code-block:: cpp @@ -369,9 +368,6 @@ Visualization To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../../python/memilio_plot>` and its documentation. -You can export your simulation results to CSV format as described above. - - Examples -------- diff --git a/docs/source/cpp/models/oseir.rst b/docs/source/cpp/models/oseir.rst index 30c6b637e9..a262300512 100644 --- a/docs/source/cpp/models/oseir.rst +++ b/docs/source/cpp/models/oseir.rst @@ -1,11 +1,11 @@ ODE-based SEIR-type model ========================= -The ODE-based SEIR-type module models and simulates the epidemic using an ODE-based SEIR-type model approach. The model +The ODE-SEIR module models and simulates the epidemic using an ODE-based SEIR-type model approach. The model is particularly suited for simple simulations of infectious diseases in a population and getting started with the MEmilio code. The model assumes perfect immunity after recovery and is thus only suited for epidemic use cases. -The infection states and the transitions are visualized in the following image. +The infection states and the transitions are visualized in the following graph. .. image:: https://github.com/SciCompMod/memilio/assets/69154294/80a36be5-57d9-4012-9b5f-25eb08ec8837 :alt: SEIR_model @@ -27,7 +27,7 @@ Infection State Transitions --------------------------- The ODE-SEIR model is implemented as **FlowModel**. With just minimal overhead, the **FlowModel** computes the new -transmissions, infections, and hospitalizations explicitly in every time step instead of only computing the aggregated +transmissions, infections, and recoveries explicitly in every time step instead of only computing the aggregated compartment values. The defined transitions `FromState, ToState` are: .. code-block:: RST @@ -54,7 +54,7 @@ The number of age groups is specified in the model constructor and the model can Parameters ---------- -The model implements the following parameters. +The model implements the following parameters: .. list-table:: :header-rows: 1 @@ -115,7 +115,7 @@ and all other compartments: Nonpharmaceutical Interventions ------------------------------- -In the ODE-SEIR model, nonpharmaceutical interventions (NPIs) are implemented through dampings in the contact matrix. +In the ODE-SEIR model, nonpharmaceutical interventions (NPIs) are implemented through dampings to the contact matrix. These dampings reduce the contact rates between different sociodemographic groups to simulate interventions. Basic dampings can be added to the ContactPatterns as follows: @@ -148,13 +148,13 @@ The ODE-SEIR model offers two simulation functions: 1. **simulate**: Standard simulation that tracks the compartment sizes over time 2. **simulate_flows**: Extended simulation that additionally tracks the flows between compartments -Basic simulation: +Standard simulation: .. code-block:: cpp double t0 = 0; // Start time double tmax = 50; // End time - double dt = 0.1; // Time step + double dt = 0.1; // Initial step size // Run a standard simulation mio::TimeSeries result_sim = mio::oseir::simulate(t0, tmax, dt, model); @@ -182,8 +182,8 @@ For both simulation types, you can also specify a custom integrator: Output ------ -The output of the **Simulation** is a ``TimeSeries`` containing the sizes of each compartment at each time point. For A -basic simulation, you can access the results as follows: +The output of the **Simulation** is a ``mio::TimeSeries`` containing the sizes of each compartment at each time point. For A +standard simulation, you can access the results as follows: .. code-block:: cpp @@ -191,14 +191,14 @@ basic simulation, you can access the results as follows: auto num_points = static_cast(result_sim.get_num_time_points()); // Access data at specific time point - Eigen::VectorXd value_at_time_i = result_sim.get_value(i); + Eigen::VectorXd value_at_time_point_i = result_sim.get_value(i); double time_i = result_sim.get_time(i); // Access the last time point Eigen::VectorXd last_value = result_sim.get_last_value(); double last_time = result_sim.get_last_time(); -For flow simulations, the result consists of two `TimeSeries` objects, one for compartment sizes and one for flows: +For flow simulations, the result consists of two `mio::TimeSeries` objects, one for compartment sizes and one for flows: .. code-block:: cpp @@ -208,7 +208,7 @@ For flow simulations, the result consists of two `TimeSeries` objects, one for c // Access flows between compartments auto flows = result_flowsim[1]; -You can print the simulation results as a formatted table: +You can print the simulation results as a formatted table via: .. code-block:: cpp @@ -226,7 +226,7 @@ Additionally, you can export the results to a CSV file: // Export results to CSV with default settings result_sim.export_csv("simulation_results.csv"); -The SEIR model also provides utility functions to extract specific measures, such as the reproduction number: +The ODE-SEIR model also provides utility functions to extract specific measures, such as the reproduction number: .. code-block:: cpp // Calculate R value at a specific time index @@ -253,4 +253,4 @@ An example can be found at Overview of the ``oseir`` namespace: ----------------------------------------- -.. doxygennamespace:: mio::oseir \ No newline at end of file +.. doxygennamespace:: mio::oseir diff --git a/docs/source/cpp/ode.rst b/docs/source/cpp/ode.rst index ee435716c7..446568eb05 100644 --- a/docs/source/cpp/ode.rst +++ b/docs/source/cpp/ode.rst @@ -1,9 +1,9 @@ -ODE models -========== +ODE-based models +================ MEmilio implements various models based on ordinary differential equations (ODEs). ODE-based models are a subclass of -compartmental models in which individuals are grouped into compartments. MEmilio's ODE-based models range from most simple -SIR structure to complex models with multi-layer and waning immunity. These models can be stratified by age groups or +compartmental models in which individuals are grouped into subpopulations called compartments. MEmilio's ODE-based models range from most simple +SIR structures to complex models with multiple layers and waning immunity. These models can be stratified by age groups or other sociodemographic factors. In the following, we present the general structure for all simple ODE-based models. For generalizations via the Linear @@ -27,7 +27,7 @@ Infection state transitions Our ODE-based models are either implemented as **FlowModel** or as **CompartmentalModel**. In a **FlowModel**, flows ``Flow`` between **InfectionState**\s **State1** and **State2** are defined. Instead of a standard -solution to an ODE-based model, this implementation additionally realizes the solution of the transitions or flows +solution of an ODE-based model, this implementation additionally realizes the solution of the transitions or flows between states and directly enables users to access new transmissions or hospitalizations at any time point. The simpler class **CompartmentalModel** only considers the states of the system and not the flows. @@ -35,7 +35,7 @@ The simpler class **CompartmentalModel** only considers the states of the system Sociodemographic stratification ------------------------------- -For most models, the population can also be stratified by one sociodemographic dimension. This dimension is denoted +For most ODE-based models, the population can be stratified by one sociodemographic dimension. This dimension is denoted **AgeGroup** but can also be used for other interpretations. For stratifications with two or more dimensions, see :doc:`Model Creation `. @@ -49,10 +49,10 @@ compartment or the contact rates between different age groups. Most model parame pathogen-specific characteristics (possibly resolved by sociodemographic groups) and are represented by a vector with a value for each sociodemographic group. To model different contact rates between different sociodemographic groups, we use a parameter denoted **ContactPatterns** of type **UncertainContactMatrix**. The **UncertainContactMatrix** contains -a set of contact matrices of arbitrary length and which can represent the different contact locations in the model like +a set of contact matrices of arbitrary length which can represent different contact locations in the model like schools, workplaces, or homes. The matrices can be loaded or stored in the particular example. -In the **ContactPatterns**, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic -group :math:`i` to group :math:`j`. The dimension of the matrix is automatically defined by the model initiation and it is reduced +In the **ContactPatterns** parameter, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic +group :math:`i` and group :math:`j`. The dimension of the matrix is automatically defined by the model initiation and it is reduced to one value if no stratifcation is used. The values can be adjusted during the simulation, e.g., through implementing nonpharmaceutical interventions, see the section on :ref:`Nonpharmaceutical Interventions`. Parameters can get accessed via ``model.parameters.get>()`` and set via either @@ -102,13 +102,12 @@ reduction factor :math:`r`, the reduced contact rate is :math:`(1-r) * c_{i,j}`. Simulation ---------- -Once the model is setup, run a simple simulation from time ``t0`` to ``tmax`` with an initial step size ``dt`` using the -``mio::simulation()`` function. This will run a simulation of type **Simulation** that does not save the flows between -compartments but only the sizes of each compartment over time. To use the flow information, make sure to use a -**FlowModel** and run a simulation of type **FlowSimulation** with the ``mio::simulate_flows()`` function. -You can run a simulation using either fixed or adaptive solution schemes with an absolute or relative tolerance. By -default, the simulation uses an adaptive solution scheme of the boost library and an absolute tolerance of 1e-10 and a -relative tolerance of 1e-5. For more details on the possible integration schemes, see . +Once the model is set up, one can run a simple simulation from time ``t0`` to ``tmax`` with an initial step size ``dt`` using the +``mio::simulation()`` function. This will run a simulation of type **Simulation** that saves the sizes of each compartment over time. +To also save the flow information, make sure to use a **FlowModel** and run a simulation of type **FlowSimulation** with the ``mio::simulate_flows()`` function. +You can run a simulation using either fixed or adaptive integration schemes with an absolute or relative tolerance. By +default, the simulation uses an adaptive integration scheme of the boost library with an absolute tolerance of 1e-10 and a +relative tolerance of 1e-5. Output From ec3cd8ed7e0e90a53ce92e8848064f600ae0ac55 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Tue, 22 Jul 2025 15:12:36 +0200 Subject: [PATCH 20/25] start review ide --- docs/source/cpp/ide.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/cpp/ide.rst b/docs/source/cpp/ide.rst index b5dc11ea9b..84a7d0f922 100644 --- a/docs/source/cpp/ide.rst +++ b/docs/source/cpp/ide.rst @@ -45,16 +45,16 @@ Parameters The parameters of the model are defined as structs and are combined in a class ``ParameterSet``. We use different types of parameters to represent epidemiological parameters such as the distributions of the stay times in a -compartment or the contact rates between different age groups. Most model parameters are constants that describe +compartment or the contact rates between different sociodemographic groups. Most model parameters are constants that describe pathogen-specific characteristics (possibly resolved by sociodemographic groups) and are represented by a vector with a -value for each sociodemographic group. To model different contact rates between different sociodemographic groups, we +value for each group. To model different contact rates between different sociodemographic groups, we use a parameter denoted **ContactPatterns** of type **UncertainContactMatrix**. The **UncertainContactMatrix** contains a set of contact matrices of arbitrary length and which can represent the different contact locations in the model like schools, workplaces, or homes. The matrices can be loaded or stored in the particular example. In the **ContactPatterns**, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic -group :math:`i` to group :math:`j`. The dimension of the matrix is automatically defined by the model initiation and it is reduced -to one value if no stratifcation is used. The values can be adjusted during the simulation, e.g., through implementing +group :math:`i` and group :math:`j`. The dimension of the matrix is automatically defined by the model initiation and it is reduced +to one value if no stratification is used. The values can be adjusted during the simulation, e.g., through implementing nonpharmaceutical interventions, see the section on :ref:`Nonpharmaceutical Interventions`. An important feature of our IDE-based model is that we can choose the transition distributions in a flexible way. The From b8b6e5c5f5176c867b1d530caeb0fc59e4fcafd8 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Tue, 22 Jul 2025 15:43:15 +0200 Subject: [PATCH 21/25] Secirvvs and surrogate model review --- docs/source/cpp/models/osecirvvs.rst | 37 +++++++++++----------- docs/source/python/memilio_surrogate.rst | 39 +++++++++++++++--------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/docs/source/cpp/models/osecirvvs.rst b/docs/source/cpp/models/osecirvvs.rst index e19ebc0264..f5db982b0d 100644 --- a/docs/source/cpp/models/osecirvvs.rst +++ b/docs/source/cpp/models/osecirvvs.rst @@ -1,9 +1,9 @@ -SECIR model with COVID-19 variants and vaccinations -===================================================== +ODE-based SECIR-type model with COVID-19 variants and vaccinations +==================================================================== -This model extends the basic SECIR model by adding vaccinations and allowing the implicit modeling of a newly arriving variant that takes hold. +This model extends the basic ODE-SECIR model by adding vaccinations and allowing the implicit modeling of a newly arriving variant that takes hold. -Vaccinations are modeled by adding compartments for partially and fully vaccinated persons. ``Partially and fully vaccinated`` is to be understood in this context as the person having received a first and second vaccine shot as in 2021. These model lines can be reused by resetting parameters. Persons that have recovered from the disease are treated as fully vaccinated from that time forward. Vaccinated persons are added on every day of simulation, see parameters ``DailyPartialVaccinations`` and ``DailyFullVaccinations``. All groups can get an infection or get reinfected. Vaccinated persons are less likely to develop symptoms. For example, the probability to develop symptoms when carrying the virus is the base probability from the SECIR model multiplied with the ``ReducInfectedSymptomsPartialImmunity`` parameter. +Vaccinations are modeled by adding compartments for partially and fully vaccinated persons. **Partially** and **fully vaccinated** is to be understood in this context as the person having received a first and second vaccine shot as in 2021. Persons that have recovered from the disease are treated as fully vaccinated from that time forward. Vaccinated persons are added on every day of simulation, see parameters ``DailyPartialVaccinations`` and ``DailyFullVaccinations``. All groups can get an infection or get reinfected. Vaccinated persons are less likely to develop symptoms. For example, the probability to develop symptoms when carrying the virus is the base probability from the ODE-SECIR model multiplied with the ``ReducInfectedSymptomsPartialImmunity`` parameter. The ratio of two variants can change over time, which affects the average transmissibility of the disease. Infectiousness of different variants can be set in the parameters. @@ -15,7 +15,7 @@ Below is an overview of the model architecture and its compartments. Infection States ---------------- -The model extends the basic SECIR model by dividing the compartments based on immunity levels. It contains the following list of **InfectionState**\s: +The model extends the basic ODE-SECIR model by dividing the compartments based on immunity levels. It contains the following list of **InfectionState**\s: .. code-block:: RST @@ -57,7 +57,7 @@ All compartments with the same base state (e.g., ExposedNaive, ExposedPartialImm Infection State Transitions --------------------------- -The ODE-SECIRVVS model is implemented as a **FlowModel**, which computes the flows between compartments explicitly. The model follows the same flow pattern as the basic SECIR model but with three parallel sets of compartments representing different immunity levels. +The ODE-SECIRVVS model is implemented as a **FlowModel**, which computes the flows between compartments explicitly. The model follows the same flow pattern as the basic ODE-SECIR model but with three parallel sets of compartments representing different immunity levels. The key characteristic of this model is that recovered individuals always end up in the improved immunity level, regardless of their starting immunity level. This represents the immunity gained after infection. @@ -83,18 +83,19 @@ For each immunity level (Naive, PartialImmunity, ImprovedImmunity), the followin Where * stands for the immunity level suffix (Naive, PartialImmunity, or ImprovedImmunity). -**Important:** Vaccinations are not implemented as flows between compartments but are handled discretely by the simulation. At the beginning of each simulated day, susceptible individuals are moved between immunity levels according to the specified daily vaccination parameters. This discrete process is separate from ODE system and is managed by the `apply_vaccination` function in the model specific Simulation class. +**Important:** Vaccinations are not implemented as flows between compartments but are handled discretely by the simulation. At the beginning of each simulated day, susceptible individuals are moved between immunity levels according to the specified daily vaccination parameters. This discrete process is separate from the ODE system and is managed by the `apply_vaccination` function in the model specific **Simulation** class. Sociodemographic Stratification ------------------------------- -Like the basic SECIR model, the SECIRVVS model can be stratified by one sociodemographic dimension, typically age groups. This stratification is important for modeling different vaccination rates, symptom severities, and mortality risks across age groups. +Like the basic ODE-SECIR model, the ODE-SECIRVVS model can be stratified by one sociodemographic dimension, typically age groups. This stratification is important for modeling different vaccination rates, symptom severities, and mortality risks across age groups. The dimension is denoted +**AgeGroup** but can also be used for other interpretations For stratifications with two or more dimensions, see :doc:`Model Creation <../ode_creation>`. Parameters ---------- -The model includes all parameters from the basic SECIR model plus additional parameters specific to vaccination and variant modeling. Here is a comprehensive list of the key parameters: +The model includes all parameters from the basic ODE-SECIR model plus additional parameters specific to vaccination and variant modeling. .. list-table:: :header-rows: 1 @@ -217,7 +218,7 @@ Initial conditions The initial conditions of the model are represented by the class **Populations** which defines the number of individuals in each sociodemographic group and **InfectionState**. Before running a simulation, you should set the initial values for each compartment across all immunity levels. -Below is a example showing how to initialize all compartments for the SECIRVVS model: +Below is an example showing how to initialize all compartments for the ODE-SECIRVVS model: .. code-block:: cpp @@ -280,7 +281,7 @@ After setting the initial populations, you also need to set the vaccination para Nonpharmaceutical Interventions ------------------------------- -The SECIRVVS model supports nonpharmaceutical interventions (NPIs) through dampings in the contact matrix. These dampings reduce the contact rates between different groups to simulate interventions like lockdowns. +The ODE-SECIRVVS model supports nonpharmaceutical interventions (NPIs) through dampings to the contact matrix. These dampings reduce the contact rates between different groups to simulate interventions like e.g. lockdowns. Basic dampings can be added to the contact matrix as follows: @@ -295,7 +296,7 @@ Basic dampings can be added to the contact matrix as follows: // Add a damping that reduces contacts by 30% starting at day 5 contact_matrix[0].add_damping(0.3, mio::SimulationTime(5.0)); -For more complex scenarios, such as real-world lockdown modeling, you can implement detailed NPIs with location-specific dampings as in the SECIR model. The SECIRVVS model supports the same contact locations (e.g., home, school, work, other) and can apply different dampings to each location. +For more complex scenarios, such as real-world lockdown modeling, you can implement detailed NPIs with location-specific dampings as in the ODE-SECIR model. The ODE-SECIRVVS model supports the same contact locations (e.g., home, school, work, other) and can apply different dampings to each location. Example of defining locations and interventions for a detailed scenario: @@ -326,9 +327,9 @@ The model also supports dynamic NPIs based on epidemic thresholds: // Configure dynamic NPIs auto& dynamic_npis = params.get>(); - dynamic_npis.set_interval(mio::SimulationTime(3.0)); // Check every 3 days - dynamic_npis.set_duration(mio::SimulationTime(14.0)); // Apply for 14 days - dynamic_npis.set_base_value(100'000); // Per 100,000 population + dynamic_npis.set_interval(mio::SimulationTime(3.0)); // Check NPI every 3 days + dynamic_npis.set_duration(mio::SimulationTime(14.0)); // Apply NPI for 14 days + dynamic_npis.set_base_value(100'000); // Base value to trigger NPI is population of 100,000 dynamic_npis.set_threshold(200.0, dampings); // Trigger at 200 cases per 100,000 Simulation @@ -371,7 +372,7 @@ For both simulation types, you can also specify a custom integrator: Output ------ -The output of the simulation is a `TimeSeries` object containing the sizes of each compartment at each time point. For a basic simulation, you can access the results as follows: +The output of the simulation is a `mio::TimeSeries` object containing the sizes of each compartment at each time point. For a standard simulation, you can access the results as follows: .. code-block:: cpp @@ -409,7 +410,7 @@ Visualization ------------- To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../../python/memilio_plot>` -and its documentation. You can export your simulation results to CSV format as described above. +and its documentation. Examples -------- @@ -417,7 +418,7 @@ Examples The extended model is used in the ``2021_vaccination_sarscov2_delta_germany`` simulation. An easier example can be found in the `examples/ode_secirvvs.cpp `_. -Examples of the basic SECIR model can be found at: +Examples of the basic ODE-SECIR model can be found at: - `examples/ode_secir.cpp `_ - `examples/ode_secir_ageres.cpp `_ diff --git a/docs/source/python/memilio_surrogate.rst b/docs/source/python/memilio_surrogate.rst index c804d53d8b..354f230dc2 100644 --- a/docs/source/python/memilio_surrogate.rst +++ b/docs/source/python/memilio_surrogate.rst @@ -2,11 +2,11 @@ MEmilio Surrogate Model Package =============================== MEmilio Surrogate Model contains machine learning based surrogate models that make predictions based on the MEmilio simulation models. -Currently there are only surrogate models for ODE models. These simulations of these equation-based models are used for data generation. -The goal is to create a powerful tool that predicts the dynamics faster than a simulation of an expert model, +Currently there are only surrogate models for ODE-type models. The simulations of these models are used for data generation. +The goal is to create a powerful tool that predicts the infection dynamics faster than a simulation of an expert model, e.g., a metapopulation or agent-based model while still having acceptable errors with respect to the original simulations. -The package is contained inside the folder `pycode/memilio-surrogatemodel `_. +The package can be found in `pycode/memilio-surrogatemodel `_. For more details, we refer to: Schmidt A, Zunker H, Heinlein A, Kühn MJ. (2024).*Towards Graph Neural Network Surrogates Leveraging Mechanistic Expert Knowledge for Pandemic Response*. arXiv. `arXiv:2411.06500 `_ @@ -29,25 +29,25 @@ Usage The package currently provides the following modules: -- `models`: models for different specific tasks +- `models`: models for different tasks Currently we have the following models: - `ode_secir_simple`: A simple model allowing for asymptomatic as well as symptomatic infection not stratified by age groups. - `ode_secir_groups`: A model allowing for asymptomatic as well as symptomatic infection stratified by age groups and including one damping. Each model folder contains the following files: - - `data_generation`: data generation from expert model simulation. - - `model`: training and evaluation of the model. - - `network_architectures`: multiple network architectures are saved in this file. - - `grid_search`: utilities for hyperparameter optimization. - - `hyperparameter_tuning`: scripts for tuning model hyperparameters. + - `data_generation`: Data generation from expert model simulation outputs. + - `model`: Training and evaluation of the model. + - `network_architectures`: Contains multiple network architectures. + - `grid_search`: Utilities for hyperparameter optimization. + - `hyperparameter_tuning`: Scripts for tuning model hyperparameters. - `tests`: this file contains all tests -SECIR Simple Model +ODE-SECIR Simple Model ----------------- -The `ode_secir_simple` module provides surrogate models for the basic SECIR epidemiological model. This model is not stratified by age groups and simulates disease progression through the following compartments: +The `ode_secir_simple` module provides surrogate models for the basic ODE-SECIR epidemiological model. This model is not stratified by age groups and simulates disease progression through the following compartments: - **S**: Susceptible - **E**: Exposed @@ -58,12 +58,12 @@ The `ode_secir_simple` module provides surrogate models for the basic SECIR epid - **U**: ICU (critical cases) - **D**: Dead -For more details on the model structure and parameters, we refer to the ODE SECIR model documentation. +For more details on the model structure and parameters, we refer to the ODE-SECIR model documentation. Data Generation ~~~~~~~~~~~~~~ -The `data_generation.py` module provides functionality to generate training data for the surrogate models by running multiple simulations of the SECIR model with randomized initial conditions. The data generation process involves: +The `data_generation.py` module provides functionality to generate training data for the surrogate models by running multiple simulations of the basic ODE-SECIR model with randomized initial conditions. The data generation process involves: .. code-block:: python @@ -78,10 +78,10 @@ The `data_generation.py` module provides functionality to generate training data save_data=True ) -The data generation process: +The data generation process can be summarized as follows: 1. Randomly initializes the model parameters and initial compartment populations -2. Runs the SECIR simulation using the C++ backend via Python bindings +2. Runs the ODE-SECIR simulation using the C++ backend via Python bindings 3. Applies logarithmic normalization to improve training stability 4. Splits each time series into input and label segments 5. Saves the dataset as a pickle file for later use @@ -92,14 +92,17 @@ Network Architectures The `network_architectures.py` module provides different neural network architectures for time series prediction: 1. **MLP (Multi-Layer Perceptron)**: + - Simple feedforward networks that take flattened time series as input - Available in both single-output and multi-output variants 2. **LSTM (Long Short-Term Memory)**: + - Recurrent neural networks specialized for sequence modeling - Can process variable-length time series while maintaining temporal information 3. **CNN (Convolutional Neural Network)**: + - Uses 1D convolutions to detect patterns in time series data - Particularly efficient for capturing local temporal patterns @@ -109,14 +112,17 @@ Model Training and Evaluation The `model.py` module provides functionality for: 1. **Preparing data**: + - Splitting data into training, validation, and test sets - Processing data for different model architectures (classic vs. time series) 2. **Model training**: + - Initializing models with customizable hyperparameters - Training with early stopping and customizable loss functions 3. **Evaluation**: + - Computing error metrics (MAE, MAPE) across compartments - Visualizing predictions versus ground truth @@ -143,14 +149,17 @@ Hyperparameter Optimization The `grid_search.py` and `hyperparameter_tuning.py` modules provide tools for systematic hyperparameter optimization: 1. **Cross-validation**: + - K-fold cross-validation to prevent overfitting - Evaluation of multiple model architectures and training configurations 2. **Grid search**: + - Systematic exploration of hyperparameter space - Tracking and storage of performance metrics 3. **Result analysis**: + - Visualization of hyperparameter importance - Selection of optimal model configurations From 7f55da85a191b243c08f9a4c1bccf87434c2e938 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 23 Jul 2025 10:23:30 +0200 Subject: [PATCH 22/25] review graph metapop --- docs/source/cpp/graph_metapop.rst | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/source/cpp/graph_metapop.rst b/docs/source/cpp/graph_metapop.rst index b5498fe946..e10ed9dc2b 100644 --- a/docs/source/cpp/graph_metapop.rst +++ b/docs/source/cpp/graph_metapop.rst @@ -15,7 +15,7 @@ During the simulation, graph nodes are advanced independently from each other ac The instant mobility approach was introduced by Kühn et al. (2021) and mainly represents daily instant commuting activities between different regions. Using realistic commuting data, such as the absolute number of commuters between regions, we can model realistic exchanges of individuals in the metapopulation context. -In this approach, the commuters are exchanged twice daily in an instantaneous manner, allowing the integration of age-specific mobility restrictions. The implementation also allows the restriction of mobility activities for certain infection states, such as symptomatic infected individuals. An important feature implemented in Kühn et al. (2022) is the testing of commuters, which enables the detection and potential isolation of asymptomatic or symptomatic infected individuals before they can infect people in other regions. +In this approach, the commuters are exchanged twice daily in an instantaneous manner, allowing the integration of age-specific mobility restrictions. The implementation also allows for the restriction of mobility activities for certain infection states, such as symptomatic infected individuals. An important feature implemented in Kühn et al. (2022) is the testing of commuters, which enables the detection and potential isolation of asymptomatic or symptomatic infected individuals before they can infect people in other regions. The instant mobility approach assumes instant exchange between regions without considering travel times. The length of stay is fixed to half a day. Since all regions exchange commuters simultaneously, this scheme offers great properties for parallelization and has fewer constraints on the integration time step compared to more detailed mobility approaches. @@ -29,9 +29,9 @@ For further details, please refer to: The detailed mobility scheme was introduced in Zunker et al. (2024) and further develops the instant approach. The detailed mobility model addresses some of the constraints of the instant approach by adding realistic travel and stay times. -The core idea of this detailed approach is that each region has a second, local model, which can be parameterized independently from the existing model, to represent mobility within the region. This allows for more detailed modeling of population movement. +The core idea of this detailed approach is that each region has a second local model, which can be parameterized independently from the existing model, to represent mobility within the region. This allows for more detailed modeling of population movement. -To have a realistic representation of the exchange process, we calculate the centroids of each region, which is represented by a polygon. When modeling travel between two non-adjacent regions (nodes k and l), the model creates a path connecting their centroids, which may pass through other regions. The predefined travel time between regions is then distributed across all regions along this path. +To have a realistic representation of the exchange process, we calculate the centroids of each region, which is represented by a polygon. When modeling travel between two non-adjacent regions (nodes :math:`k` and :math:`l`), the model creates a path connecting their centroids, which may pass through other regions. The predefined travel time between regions is then distributed across all regions along this path. Commuters move along these paths and pass through various mobility models during their trip. This allows for potential interactions with other commuters during transit. The detailed mobility approach enables modeling of scenarios that cannot be addressed with the instant approach, such as the impact of different mask type usage in public transport. However, this increased realism comes at the cost of greater computational effort and requires more detailed input data. For further details, please refer to: @@ -40,25 +40,24 @@ For further details, please refer to: **Stochastic mobility approach** -In the stochastic mobility approach, transitions of individuals between regions, i.e. graph nodes, are modeled as stochastic jumps. The frequency of individuals transitioning from region i to region j is determined by a rate :math:`\lambda_{ij}` which can be interpreted as the (expected) fraction of the population in region i that commutes to region j within one day. In contrast to the instant and detailed mobility approach, the time points and the number of transitions between two regions are stochastic. +In the stochastic mobility approach, transitions of individuals between regions, i.e. graph nodes, are modeled as stochastic jumps. The frequency of individuals transitioning from region :math:`i` to region :math:`j` is determined by a rate :math:`\lambda_{ij}` which can be interpreted as the (expected) fraction of the population in region :math:`i` that commutes to region :math:`j` within one day. In contrast to the instant and detailed mobility approach, the time points and the number of transitions between two regions are stochastic. How to: Set up a graph and run a graph simulation ------------------------------------------------- -The graph simulation couples multiple simulation instances representing different geographic regions via a graph-based approach. In this example, a compartment model based on ODEs (ODE-SECIR) is used for each region. The simulation proceeds by advancing each region independently and then exchanging portions of the population between regions along the graph edges. +The graph simulation couples multiple simulation instances representing different geographic regions via a graph-based approach. In this example, a compartmental model based on ODEs (ODE-SECIR) is used for each region. The simulation proceeds by advancing each region independently and then exchanging portions of the population between regions along the graph edges. The following steps detail how to configure and execute a graph simulation: -1. **Initialize the local compartment model:** +1. **Initialize the local compartmental model:** - First, set up the compartment model by initializing the populations and parameters. In this example, we use a single age group and start with 10,000 susceptible individuals. Additionally, the necessary epidemiological parameters (e.g. time periods, transmission probabilities) are set. + First, set up the compartmental model by initializing the parameters that are equal in every region. In this example, we use a single age group and set the necessary epidemiological parameters (e.g. time periods, transmission probabilities). .. code-block:: cpp const size_t num_groups = 1; mio::osecir::Model model(num_groups); - model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::Susceptible}] = 10000; model.parameters.set(0); model.parameters.set>(0.2); @@ -83,7 +82,7 @@ The following steps detail how to configure and execute a graph simulation: 2. **Create simulation groups and adjust contact patterns:** - To represent different geographic regions, clone the base model into separate model groups. In this example, two model groups are created. The first group is modified by applying a contact damping to simulate contact restrictions. + To represent different geographic regions, clone the base model into separate model groups. In this example, two model groups are created. The first group is modified by applying a contact damping to simulate contact restrictions. Additionally, set the populations in all models. .. code-block:: cpp @@ -100,6 +99,8 @@ The following steps detail how to configure and execute a graph simulation: model_group1.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::Susceptible}] = 9990; model_group1.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::Exposed}] = 100; + model_group2.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::Susceptible}] = 10000; + 3. **Define compartments to save from edges:** To extract the mobility results, define the compartments to save from the edges. In this example, the compartments for infected individuals with and without symptoms are saved for each region. @@ -136,7 +137,7 @@ The following steps detail how to configure and execute a graph simulation: g.add_edge(1, 0, Eigen::VectorXd::Constant((size_t)mio::osecir::InfectionState::Count, 0.1), indices_save_edges); -For the stochastic mobility, ``mio::MobilityEdgeStochastic`` has to be used as edge type for the graph. The rates or mibility coefficients can be set as follows: + For the stochastic mobility, ``mio::MobilityEdgeStochastic`` has to be used as edge type for the graph. The rates or mobility coefficients can be set as follows: .. code-block:: cpp @@ -161,7 +162,7 @@ For the stochastic mobility, ``mio::MobilityEdgeStochastic`` has to be used as e .. code-block:: cpp const auto tmax = 30.; - const auto dt = 0.5; // time step or Mobility (daily mobility occurs every second step) + const auto dt = 0.5; // time step for Mobility (daily mobility occurs every second step) auto sim = mio::make_mobility_sim(t0, dt, std::move(g)); sim.advance(tmax); @@ -174,6 +175,4 @@ For the stochastic mobility, ``mio::MobilityEdgeStochastic`` has to be used as e auto& edge_1_0 = sim.get_graph().edges()[1]; auto& results = edge_1_0.property.get_mobility_results(); results.print_table({"Commuter INS", "Commuter ISy", "Commuter Total"}); - - return 0; - } + From ff11382d59928d5295cb488eab646d7117a95098 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 23 Jul 2025 10:55:06 +0200 Subject: [PATCH 23/25] review model creation ode --- docs/source/cpp/ode_creation.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/source/cpp/ode_creation.rst b/docs/source/cpp/ode_creation.rst index d71f86d0f4..3be94de6f5 100644 --- a/docs/source/cpp/ode_creation.rst +++ b/docs/source/cpp/ode_creation.rst @@ -4,8 +4,8 @@ ODE model creation The mathematical model ---------------------- -Before implementing a model in MEmilio, we need to do a some math, in particular, define an initial value problem -given by a system of ordinary differential equations. For example we consider a SIRD model given by +Before implementing a model in MEmilio, we need to do some math, in particular, define an initial value problem +given by a system of ordinary differential equations. For example, we consider a SIRD model given by .. math:: @@ -16,7 +16,7 @@ given by a system of ordinary differential equations. For example we consider a D'(t) & = \frac{\mu_D}{T_I}I(t) \\ \end{aligned} -and some initial values for :math:`t=0`. Here :math:`N_{\perp D} := S(t) + I(t) + R(t)`. +and some initial values for :math:`t=0`. Here, :math:`N_{\perp D} := S(t) + I(t) + R(t)`. This type of model is called compartmental model, because the model population is represented by discrete infection states **S**\usceptible, **I**\nfectious, **R**\ecovered, **D**\eceased, also called compartments. @@ -29,15 +29,15 @@ use different methods to define the right hand side of the mathematical model ab the infection states, population and parameters it uses. The FlowModel additionally requires a list of flows. We start by creating a new directory for our model under "cpp/models", in this case we can call it "ode_sird". The name -must be unique and start with "ode\_", so the type of model is obvious. The rest usually contains the compartments or +must be unique and start with "ode\_", so the type of model is obvious. The rest of the name usually contains the compartments or other noteworthy features of the model in shortened form. All files in the following are put into this directory. Infection states ~~~~~~~~~~~~~~~~ -First we define an :code:`enum class` called ``InfectionState`` in the file "infection_state.h", which contains an entry +First, we define an :code:`enum class` called ``InfectionState`` in the file "infection_state.h", which contains an entry for each infection state of the mathematical model, followed by an entry called :code:`Count`. This enumerates the -compartments starting from 0, with Count being equal to the number of compartments. In our example we have: +compartments starting from 0, with :code:`Count` being equal to the number of compartments. In our example we have: .. code-block:: cpp @@ -154,6 +154,8 @@ Now we can define the model: } }; +Here, the :code:`get_derivatives` function implements the right hand side of the differential equations. + Define a flow model ^^^^^^^^^^^^^^^^^^^ @@ -161,7 +163,7 @@ A flow model is a special case of a compartmental model, where each compartment .. math:: - Z_i(t) = \sum_{i \ne j} f_{Z_j \rightarrow Z_i}(t) - \sum_{i \ne j} f_{Z_i \rightarrow Z_j}(t), + Z'_i(t) = \sum_{j \ne i} f_{Z_j \rightarrow Z_i}(t) - \sum_{j \ne i} f_{Z_i \rightarrow Z_j}(t), where the flows :math:`f_{Z_i \rightarrow Z_j} \gt 0` are the amount of population changing from compartment :math:`Z_i` to :math:`Z_j` at time :math:`t`. So the first sum accumulates all inflows, the second subtracts all From e59c89f3ea6e8aa1ebc9d122c85e65a362f4af5f Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Wed, 23 Jul 2025 13:15:28 +0200 Subject: [PATCH 24/25] docu review --- docs/source/cpp/lct.rst | 55 ++++++++------------------ docs/source/cpp/models/lsecir.rst | 59 ++++++++++------------------ docs/source/cpp/models/osecirts.rst | 44 ++++++++++----------- docs/source/cpp/models/osecirvvs.rst | 2 +- docs/source/cpp/ode.rst | 6 +-- 5 files changed, 63 insertions(+), 103 deletions(-) diff --git a/docs/source/cpp/lct.rst b/docs/source/cpp/lct.rst index 58741d5173..33a61109cd 100644 --- a/docs/source/cpp/lct.rst +++ b/docs/source/cpp/lct.rst @@ -1,13 +1,9 @@ Linear Chain Trick model ========================= -MEmilio implements a SECIR-type model utilizing the Linear Chain Trick (LCT). This is a generalization of simple ODE -models and allows for Erlang distributed stay times in the compartments by introducing subcompartments. Note that the -resulting system can still be described by ODEs. The LCT-SECIR model can be stratified by age groups or other sociodemographic -factors. +MEmilio implements a SECIR-type model utilizing the Linear Chain Trick (LCT). This is a generalization of simple ODE-based models and allows for Erlang distributed stay times in the compartments by introducing subcompartments. Note that the resulting system is still described by ODEs. The LCT-SECIR model can be stratified by age groups or other sociodemographic factors. -In the following, we present the general structure of the LCT model. The particular model documentation with examples -is linked at the bottom of this page. +In the following, we present the general structure of the LCT model. The particular model documentation with examples is linked at the bottom of this page. Infection states ---------------- @@ -27,15 +23,15 @@ To make use of the LCT, we additionally need to define the numbers of subcompart `Number of subcompartments of State2` `...` -Note that the model is implemented as **CompartmentalModel**. +The model is implemented as **CompartmentalModel**. Sociodemographic stratification ------------------------------- -For this model, the population can also be stratified by one sociodemographic dimension. This dimension can be used -for age groups but can also be used for other interpretations. +For this model, the population can be stratified by one sociodemographic dimension. This dimension can be used +for age groups but for other interpretations. Parameters @@ -44,15 +40,10 @@ Parameters The parameters of the model are defined as structs and are combined in a class ``ParameterSet``. We use different types of parameters to represent epidemiological parameters such as the mean stay times in a compartment or the contact rates between different age groups. Most model parameters are constants that describe -pathogen-specific characteristics (possibly resolved by sociodemographic groups) and are represented by a vector with a -value for each sociodemographic group. To model different contact rates between different sociodemographic groups, we -use a parameter denoted **ContactPatterns** of type **UncertainContactMatrix**. The **UncertainContactMatrix** contains -a set of contact matrices of arbitrary length and which can represent the different contact locations in the model like +pathogen-specific characteristics (possibly resolved by sociodemographic groups) and are represented by a vector with a value for each sociodemographic group. +To model different contact rates between different sociodemographic groups, we use a parameter denoted **ContactPatterns** of type **UncertainContactMatrix**. The **UncertainContactMatrix** contains a set of contact matrices of arbitrary length and which can represent the different contact locations in the model like schools, workplaces, or homes. The matrices can be loaded or stored in the particular example. -In the **ContactPatterns**, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic -group :math:`i` to group :math:`j`. The dimension of the matrix is automatically defined by the model initiation and it is reduced -to one value if no stratification is used. The values can be adjusted during the simulation, e.g., through implementing -nonpharmaceutical interventions, see the section on :ref:`Nonpharmaceutical Interventions`. +In the **ContactPatterns**, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic group :math:`i` to group :math:`j`. The dimension of the matrix is automatically defined by the model initialization and is reduced to one value if no stratification is used. The values can be adjusted during the simulation, e.g., through implementing nonpharmaceutical interventions, see the section on :ref:`Nonpharmaceutical Interventions`. Parameters can be accessed via ``model.parameters.get>()`` and set via either ``model.parameters.get>() = value`` or ``model.parameters.set>(value)``. @@ -60,20 +51,15 @@ Parameters can be accessed via ``model.parameters.get>()`` and set Initial conditions ------------------ -The initial conditions of the model are represented by a class **LctPopulations** that gives the number of individuals in -each sociodemographic group and each subcompartment of each **InfectionState**. For more details, see -:doc:`Model Creation `. Before the simulation, set the initial conditions for each **InfectionState** and -sociodemographic group. +The initial conditions of the model are represented by a class **LctPopulations** that gives the number of individuals in each sociodemographic group and each subcompartment for each **InfectionState**. For more details, see :doc:`Model Creation `. Before the simulation, the initial conditions for each **InfectionState** and sociodemographic group must be set. .. _Nonpharmaceutical Interventions: Nonpharmaceutical interventions ------------------------------- -Contact rates can be adjusted during the simulation to model nonpharmaceutical interventions (NPIs) such as lockdowns, -school closures, or social distancing. This is done by adding **Damping**\s to the **ContactPatterns** of the model. A -**Damping** is defined by a time point at which the intervention starts and a matrix of the same size as the -**ContactMatrix**. While in many cases, the reduction matrix is given by a constant matrix with factor :math:`r`, also +Contact rates can be adjusted during the simulation to model nonpharmaceutical interventions (NPIs) such as lockdowns, school closures, or social distancing. This is done by adding **Damping**\s to the **ContactPatterns** of the model. A **Damping** is defined by a time point at which the intervention starts and a matrix of the same size as the **ContactMatrix**. +While in many cases, the reduction matrix is given by a constant matrix with factor :math:`r`, also group-specific reductions are possible through setting particular rows or columns differently. With a constant reduction factor :math:`r`, the reduced contact rate is :math:`(1-r) * c_{i,j}`. @@ -94,31 +80,24 @@ reduction factor :math:`r`, the reduced contact rate is :math:`(1-r) * c_{i,j}`. Simulation ---------- -Once the model is setup, run a simple simulation from time ``t0`` to ``tmax`` with an initial step size ``dt`` using the -``mio::simulation()`` function. This will run a simulation of type **Simulation** that saves the sizes of each -subcompartment over time. -You can run a simulation using either fixed or adaptive solution schemes with an absolute or relative tolerance. By -default, the simulation uses an adaptive solution scheme of the boost library and an absolute tolerance of 1e-10 and a -relative tolerance of 1e-5. For more details on the possible integration schemes, see . +Once the model is set up, one can run a simple simulation from time ``t0`` to ``tmax`` with initial step size ``dt`` using the ``mio::simulation()`` function. This will run a simulation of type **Simulation** that saves the sizes of each subcompartment over time. +You can run a simulation using either fixed or adaptive integration schemes with an absolute or relative tolerance. By default, the simulation uses an adaptive solution scheme of the boost library with an absolute tolerance of 1e-10 and a relative tolerance of 1e-5. For more details on the possible integration schemes, see . Output ------ -The output of the **Simulation** is a **TimeSeries** ``result`` containing the sizes of each subcompartment at each time point. +The output of the **Simulation** is a ``mio::TimeSeries`` containing the sizes of each subcompartment at each time point. To obtain a result with respect to the compartments, the subcompartments can be accumulated via the function ``calculate_compartments()``. A simple table can be printed using the ``print_table()`` function of the -``TimeSeries`` class. The compartment sizes can be printed with ``model.calculate_compartments(result).print_table()``. -As adaptive step size methods are used by default, the output will not be available on equidistant time points like `dt` -or days. To obtain outputs on days or user-defined time points, you can interpolate the results to days or -any other series of times points with ``mio::interpolate_simulation_result()``. +``mio::TimeSeries`` class. The compartment sizes can be printed with ``model.calculate_compartments(result).print_table()``. +As adaptive step size methods are used by default, the output will not be available on equidistant time points like `dt` or days. To obtain outputs on days or user-defined time points, you can interpolate the results to days or any other series of times points with ``mio::interpolate_simulation_result()``. Visualization ------------- -To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../python/memilio_plot>` -and its documentation. +To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../python/memilio_plot>` and its documentation. List of models diff --git a/docs/source/cpp/models/lsecir.rst b/docs/source/cpp/models/lsecir.rst index a848e94b6a..fdaec8d6bb 100644 --- a/docs/source/cpp/models/lsecir.rst +++ b/docs/source/cpp/models/lsecir.rst @@ -2,12 +2,10 @@ LCT-based SECIR-type model ========================== The LCT-SECIR module models and simulates an epidemic using an ODE-based approach while making use of the Linear Chain -Trick to provide the option of Erlang distributed stay times in the compartments through the use of subcompartments. -The model is particularly suited for pathogens with pre- or asymptomatic infection states and when severe or critical -states are possible. The model assumes perfect immunity after recovery and is thus only suited for epidemic use cases. -In the following, we present the model in detail. +This provides the option of Erlang distributed stay times in the compartments through the use of subcompartments. +The model is particularly suited for pathogens with pre- or asymptomatic infection states and when severe or critical states are possible. The model assumes perfect immunity after recovery and is thus only suited for epidemic use cases. -Below is a visualization of the infection states and transitions. without a stratification according to groups. +Below is a visualization of the infection states and transitions without a stratification according to socisdemographic groups. .. image:: https://github.com/SciCompMod/memilio/assets/70579874/6a5d5a95-20f9-4176-8894-c091bd48bfb7 :alt: tikzLCTSECIR @@ -15,12 +13,9 @@ Below is a visualization of the infection states and transitions. without a stra For a detailed description and application of the model, see: -- Plötzke L, Wendler A, Schmieding R, Kühn MJ. (2024). *Revisiting the Linear Chain Trick in epidemiological models: -Implications of underlying assumptions for numerical solutions*. Under review. `https://doi.org/10.48550/arXiv.2412.09140 `_ -- Plötzke L. (2023). *Der Linear Chain Trick in der epidemiologischen Modellierung als Kompromiss zwischen gewöhnlichen -und Integro-Differentialgleichungen*. Master's thesis, University of Cologne. `https://elib.dlr.de/200381/ `_ -- Hurtado PJ, Kirosingh AS. (2019). *Generalizations of the ‘Linear Chain Trick’: incorporating more flexible dwell -time distributions into mean field ODE models*. Journal of Mathematical Biology. `https://doi.org/10.1007/s00285-019-01412-w `_ +- Plötzke L, Wendler A, Schmieding R, Kühn MJ. (2024). *Revisiting the Linear Chain Trick in epidemiological models: Implications of underlying assumptions for numerical solutions*. Under review. `https://doi.org/10.48550/arXiv.2412.09140 `_ +- Plötzke L. (2023). *Der Linear Chain Trick in der epidemiologischen Modellierung als Kompromiss zwischen gewöhnlichen und Integro-Differentialgleichungen*. Master's thesis, University of Cologne. `https://elib.dlr.de/200381/ `_ +- Hurtado PJ, Kirosingh AS. (2019). *Generalizations of the ‘Linear Chain Trick’: incorporating more flexible dwell time distributions into mean field ODE models*. Journal of Mathematical Biology. `https://doi.org/10.1007/s00285-019-01412-w `_ Infection States @@ -45,14 +40,13 @@ It is possible to include subcompartments for the five compartments `Exposed`, ` Sociodemographic Stratification ------------------------------- -In the LDE-SECIR model, the population can be stratified by one sociodemographic dimension. This dimension is denoted -**Group**. It can be used for age groups as well as for other interpretations. +In the LCT-SECIR model, the population can be stratified by one sociodemographic dimension. This dimension is denoted **Group**. It can be used for age groups as well as for other interpretations. Parameters ---------- -The model implements the following parameters. +The model implements the following parameters: .. list-table:: :header-rows: 1 @@ -128,7 +122,7 @@ The notation of the compartments with indices here stands for subcompartments an Initial conditions ------------------ -To initialize the model, we start by defining the number of subcompartments and constructing the model. We can choose the number of subcompartments. +To initialize the model, we start by defining the number of subcompartments and constructing the model with it. .. code-block:: cpp @@ -140,7 +134,7 @@ To initialize the model, we start by defining the number of subcompartments and using Model = mio::lsecir::Model; Model model; -For the simulation, we need initial values for all (sub)compartments. If we do not set the initial values manually, these are internally set to :math:`0`. +For the simulation, we need initial values for all (sub)compartments. If we do not set the initial values manually, these are set to :math:`0` by default. We start with constructing a vector ``initial_populations`` that we will pass on to the model. It contains vectors for each compartment, that contains a vector with initial values for the respective subcompartments. @@ -149,7 +143,7 @@ We start with constructing a vector ``initial_populations`` that we will pass on std::vector> initial_populations = {{750}, {30, 20}, {20, 10, 10}, {50}, {50}, {10, 10, 5, 3, 2}, {20}, {10}}; -We assert that vector has the correct size by checking that the number of `InfectionState`\s and the numbers of subcompartments are correct. +We assert that the vector has the correct size by checking that the number of `InfectionState`\s and the numbers of subcompartments are correct. .. code-block:: cpp @@ -175,7 +169,7 @@ We assert that vector has the correct size by checking that the number of `Infec return 1; } -Now, we transfer the vector ``initial_populations`` to the model. +The initial populations in the model are set via: .. code-block:: cpp @@ -191,21 +185,15 @@ Now, we transfer the vector ``initial_populations`` to the model. In addition to setting the initial populations manually, MEmilio provides two other ways of setting the initial populations: -- The file `parameters_io `_ provides -functionality to compute an initial value vector for the LCT-SECIR model based on reported data. -- The file `initializer_flows `_ -provides functionality to compute an initial value vector for the LCT-SECIR model based on initial data in the form of -a TimeSeries of InfectionTransitions. For the concept of the InfectionTransitions or flows, see also the IDE-SECIR model. -This method can be particularly useful if a comparison is to be made with an IDE model with matching initialization or -if the reported data is in the form of flows. +- The file `parameters_io `_ provides functionality to compute an initial value vector for the LCT-SECIR model based on reported data. +- The file `initializer_flows `_ provides functionality to compute an initial value vector for the LCT-SECIR model based on initial data in the form of a ``mio::TimeSeries`` of InfectionTransitions. For the concept of the InfectionTransitions or flows, see also the IDE-SECIR model. This method can be particularly useful if a comparison is to be made with an IDE model with matching initialization or if the reported data is in the form of flows. .. _Nonpharmaceutical Interventions: Nonpharmaceutical Interventions ------------------------------- -In the SECIR model, nonpharmaceutical interventions (NPIs) are implemented through dampings in the contact matrix. -These dampings reduce the contact rates between different groups to simulate interventions. +In the LCT-SECIR model, nonpharmaceutical interventions (NPIs) are implemented through dampings in the contact matrix. These dampings reduce the contact rates between different groups to simulate interventions. Basic dampings can be added to the contact matrix as follows: @@ -231,8 +219,7 @@ For age-resolved models, you can apply different dampings to different groups: mio::SimulationTime(30.)); -For more complex scenarios, such as real-world lockdown modeling, you can implement detailed NPIs with location-specific -dampings. The SECIR model supports contact matrices for different locations (e.g., home, school, work, other) and can apply different dampings to each location. +For more complex scenarios, such as real-world lockdown modeling, you can implement detailed NPIs with location-specific dampings. The LCT-SECIR model supports contact matrices for different locations (e.g., home, school, work, other) and can apply different dampings to each location. Example for defining different contact locations: @@ -284,7 +271,7 @@ You can create intervention types that target specific locations with different Simulation ---------- -We can simulate using the defined model from :math:`t_0` to :math:`t_{\max}` with initial step size :math:`dt` as follows: +We can simulate the model from :math:`t_0` to :math:`t_{\max}` with initial step size :math:`dt` as follows: .. code-block:: cpp @@ -309,14 +296,13 @@ You can also specify a custom integrator: Output ------ -The simulation result is divided by subcompartments. We can call the function ``calculate_compartments()`` to get a -result according to the `InfectionState`\s . +The simulation result is stratefied by subcompartments. The function ``calculate_compartments()`` aggregates the subcompartments by `InfectionState`\s. .. code-block:: cpp mio::TimeSeries population_no_subcompartments = model.calculate_compartments(result); -You can access the data in the `TimeSeries` object as follows: +You can access the data in the `mio::TimeSeries` object as follows: .. code-block:: cpp @@ -354,10 +340,7 @@ Additionally, you can export the results to a CSV file: Visualization ------------- -To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../../python/memilio_plot>` -and its documentation. - -You can export your simulation results to CSV format as described above. +To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../../python/memilio_plot>` and its documentation. Examples @@ -371,4 +354,4 @@ An example can be found at: Overview of the ``lsecir`` namespace: ----------------------------------------- -.. doxygennamespace:: mio::lsecir \ No newline at end of file +.. doxygennamespace:: mio::lsecir diff --git a/docs/source/cpp/models/osecirts.rst b/docs/source/cpp/models/osecirts.rst index 6f2fbcac40..1624803ee1 100644 --- a/docs/source/cpp/models/osecirts.rst +++ b/docs/source/cpp/models/osecirts.rst @@ -1,10 +1,10 @@ -SECIRTS-type model including multi-layer waning immunity -========================================================= +ODE-based SECIRTS-type model including multi-layer waning immunity +================================================================== -This model extends the SECIRVVS model by adding waning immunity and introducing temporary immunity states that change the meaning of recovery. -We structured the model into three layers of immunity: naive immunity, partial immunity, improved immunity. +This model extends the ODE-SECIRVVS model by adding waning immunity and introducing temporary immunity states that change the meaning of recovery. +Like the ODE-SECIRVVS model, the ODE-SECIRTS model has three layers of immunity: naive immunity, partial immunity, improved immunity. -In the model, waning immunity is defined by the parameters ``TimeWaningPartialImmunity``, ``TimeWaningImprovedImmunity``, ``TimeTemporaryImmunityPI``, and ``TimeTemporaryImmunityII``. The parameters ``TimeWaningPartialImmunity`` and ``TimeWaningImprovedImmunity`` represent the (mean) duration after which an individual transitions from one immunity layer to the next less protected one due to waning immunity, assuming no vaccination or recovery from infection has occurred during this period. Also, the parameters ``TimeTemporaryImmunityPI`` and ``TimeTemporaryImmunityII`` denote the (mean) duration of temporary immunity following exposure to the virus, either through vaccination or recovery. During this state of temporary immunity, individuals are protected from reinfection and are incapable of transmitting the virus to others. Should individuals previously reside in the naive or partial immunity layer, their stay in the temporary immunity state results in a transition to the next more protected immunity layer. +Additionally, waning immunity is defined by the parameters ``TimeWaningPartialImmunity``, ``TimeWaningImprovedImmunity``, ``TimeTemporaryImmunityPI``, and ``TimeTemporaryImmunityII``. The parameters ``TimeWaningPartialImmunity`` and ``TimeWaningImprovedImmunity`` represent the (mean) duration after which an individual transitions from one immunity layer to the next weaker one due to waning immunity, assuming no vaccination or recovery from infection has occurred during this period. Similarly, the parameters ``TimeTemporaryImmunityPI`` and ``TimeTemporaryImmunityII`` denote the (mean) duration of temporary immunity following exposure to the virus, either through vaccination or recovery. During this state of temporary immunity, individuals are protected from reinfection and are incapable of transmitting the virus to others. Should individuals previously reside in the naive or partial immunity layer, their stay in the temporary immunity state results in a transition to the next stronger immunity layer. For more details about the model, we refer to `1 `_. @@ -16,7 +16,7 @@ Below is an overview of the model architecture and its compartments. Infection States ---------------- -The model extends the SECIRVVS model by adding temporary immunity states and flow paths for waning immunity. It contains the following list of **InfectionState**\s: +The model extends the ODE-SECIRVVS model by adding temporary immunity states and flow paths for waning immunity. It contains the following list of **InfectionState**\s: .. code-block:: RST @@ -62,9 +62,9 @@ The model extends the SECIRVVS model by adding temporary immunity states and flo Infection State Transitions --------------------------- -The ODE-SECIRTS model is implemented as a **FlowModel**, which computes the flows between compartments explicitly. A key difference from the SECIRVVS model is that vaccinations in the SECIRTS model are implemented as flows within the ODE system rather than discrete events. +The ODE-SECIRTS model is implemented as a **FlowModel**, which computes the flows between compartments explicitly. A key difference from the ODE-SECIRVVS model is that vaccinations in the ODE-SECIRTS model are implemented as flows within the ODE system rather than discrete events. -The complete list of flows defined in the model is extensive and includes: +The model has the following state trnsitions: .. code-block:: RST @@ -110,14 +110,14 @@ The complete list of flows defined in the model is extensive and includes: Sociodemographic Stratification ------------------------------- -Like the previous SECIR models, the SECIRTS model can be stratified by one sociodemographic dimension, typically age groups. This stratification is important for modeling different vaccination rates, symptom severities, mortality risks, and immunity waning rates across age groups. - +Like the other ODE-SECIR models, the ODE-SECIRTS model can be stratified by one sociodemographic dimension, typically age groups. This stratification is important for modeling different vaccination rates, symptom severities, mortality risks, and immunity waning rates across age groups. The dimension is denoted +**AgeGroup** but can also be used for other interpretations. For stratifications with two or more dimensions, see :doc:`Model Creation <../ode_creation>`. Parameters ---------- -The model includes all parameters from the SECIRVVS model plus additional parameters specific to waning immunity and temporary immunity states: +The model includes all parameters from the ODE-SECIRVVS model as well as additional parameters specific to waning and temporary immunity states: .. list-table:: :header-rows: 1 @@ -226,7 +226,7 @@ The model includes all parameters from the SECIRVVS model plus additional parame Initial conditions ------------------ -The initial conditions of the model are represented by the class **Populations** which defines the number of individuals in each sociodemographic group and **InfectionState**. Before running a simulation, you should set the initial values for each compartment across all immunity levels. The following code is from the ode_secirts.cpp example: +The initial conditions of the model are represented by the class **Populations** which defines the number of individuals in each sociodemographic group and **InfectionState**. Before running a simulation, the initial values for each compartment across all immunity levels have to be set. This can be done via: .. code-block:: cpp @@ -263,7 +263,7 @@ The initial conditions of the model are represented by the class **Populations** model.populations[{i, mio::osecirts::InfectionState::DeadImprovedImmunity}] = 0; } -After setting the initial populations, you also need to configure the daily vaccination parameters, which are directly integrated into the ODE system in this model: +After setting the initial populations, the daily vaccination parameters, which are directly integrated into the ODE system in this model, also need to be configured: .. code-block:: cpp @@ -287,7 +287,7 @@ After setting the initial populations, you also need to configure the daily vacc Nonpharmaceutical Interventions ------------------------------- -Like other SECIR models, the SECIRTS model supports nonpharmaceutical interventions (NPIs) through dampings in the contact matrix. These dampings reduce the contact rates between different groups to simulate interventions like lockdowns. +Like the other ODE-SECIR models, the ODE-SECIRTS model supports nonpharmaceutical interventions (NPIs) through dampings in the contact matrix. These dampings reduce the contact rates between different groups to simulate interventions like lockdowns. Basic dampings can be added to the contact matrix as follows: @@ -313,18 +313,18 @@ The model also supports dynamic NPIs based on epidemic thresholds: dynamic_npis.set_base_value(100'000); // Per 100,000 population dynamic_npis.set_threshold(200.0, dampings); // Trigger at 200 cases per 100,000 -For more complex scenarios, such as real-world lockdown modeling, you can implement detailed NPIs with location-specific dampings, we refer to the documentation of the ODE SECIR model. +For more complex scenarios, such as real-world lockdown modeling, detailed NPIs with location-specific dampings can be implemented. For further details, see the documentation of the ODE-SECIR model. Simulation ---------- -The SECIRTS model offers the same simulation functions as the other SECIR models: +The SECIRTS model offers the same simulation functions as the other ODE-SECIR models: 1. **simulate**: Standard simulation that tracks the compartment sizes over time 2. **simulate_flows**: Extended simulation that additionally tracks the flows between compartments -Basic simulation: +Standard simulation: .. code-block:: cpp @@ -337,9 +337,9 @@ Basic simulation: During simulation, the model handles several special processes: -1. **Vaccinations**: Unlike the SECIRVVS model, vaccinations are integrated directly into the ODE system through flows from susceptible compartments to temporary immunity compartments. +1. **Vaccinations**: Unlike the ODE-SECIRVVS model, vaccinations are integrated directly into the ODE system through flows from susceptible compartments to temporary immunity compartments. -2. **Variant Evolution**: The `apply_variant` function updates the transmission probability based on the existance of a new variant over time, similar to other SECIR models. +2. **Variant Evolution**: The `apply_variant` function updates the transmission probability based on the existance of a new variant over time, similar to other ODE-SECIR models. For both simulation types, you can also specify a custom integrator: @@ -356,7 +356,7 @@ For both simulation types, you can also specify a custom integrator: Output ------ -The output of the simulation is a `TimeSeries` object containing the sizes of each compartment at each time point. For a basic simulation, you can access the results as follows: +The output of the simulation is a `mio::TimeSeries` object containing the sizes of each compartment at each time point. For a standard simulation, you can access the results as follows: .. code-block:: cpp @@ -390,12 +390,12 @@ Visualization ------------- To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../../python/memilio_plot>` -and its documentation. You can export your simulation results to CSV format as described above. +and its documentation. Examples -------- -To get started with the SECIRTS model, check out the code example in the memilio repository: +To get started with the ODE-SECIRTS model, check out the code example in the memilio repository: `examples/ode_secirts.cpp `_. Overview of the ``osecirts`` namespace: diff --git a/docs/source/cpp/models/osecirvvs.rst b/docs/source/cpp/models/osecirvvs.rst index f5db982b0d..b86179a4ca 100644 --- a/docs/source/cpp/models/osecirvvs.rst +++ b/docs/source/cpp/models/osecirvvs.rst @@ -89,7 +89,7 @@ Sociodemographic Stratification ------------------------------- Like the basic ODE-SECIR model, the ODE-SECIRVVS model can be stratified by one sociodemographic dimension, typically age groups. This stratification is important for modeling different vaccination rates, symptom severities, and mortality risks across age groups. The dimension is denoted -**AgeGroup** but can also be used for other interpretations +**AgeGroup** but can also be used for other interpretations. For stratifications with two or more dimensions, see :doc:`Model Creation <../ode_creation>`. Parameters diff --git a/docs/source/cpp/ode.rst b/docs/source/cpp/ode.rst index 446568eb05..4ccf0ffa3f 100644 --- a/docs/source/cpp/ode.rst +++ b/docs/source/cpp/ode.rst @@ -35,9 +35,7 @@ The simpler class **CompartmentalModel** only considers the states of the system Sociodemographic stratification ------------------------------- -For most ODE-based models, the population can be stratified by one sociodemographic dimension. This dimension is denoted -**AgeGroup** but can also be used for other interpretations. For stratifications with two or more dimensions, -see :doc:`Model Creation `. +For most ODE-based models, the population can be stratified by one sociodemographic dimension. This dimension is denoted **AgeGroup** but can also be used for other interpretations. For stratifications with two or more dimensions, see :doc:`Model Creation `. Parameters @@ -113,7 +111,7 @@ relative tolerance of 1e-5. Output ------ -The output of the **Simulation** is a ``TimeSeries`` containing the sizes of each compartment at each time point. A +The output of the **Simulation** is a ``mio::TimeSeries`` containing the sizes of each compartment at each time point. A simple table can be printed using the ``print_table()`` function of the ``TimeSeries`` class. The output of the **FlowSimulation** additionally contains the flows between compartments at each time point. The compartment sizes can be printed with ``result[0].print_table()`` and the flows with ``result[1].print_table()``. From 7786b0812df76025d9b223adb87e4a45c0d2b7fc Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Wed, 23 Jul 2025 14:50:02 +0200 Subject: [PATCH 25/25] GLCT Review --- docs/source/cpp/glct.rst | 56 +++++++------------------- docs/source/cpp/models/glsecir.rst | 63 ++++++++++++------------------ 2 files changed, 39 insertions(+), 80 deletions(-) diff --git a/docs/source/cpp/glct.rst b/docs/source/cpp/glct.rst index 7735c457b7..dc8ca98d7e 100644 --- a/docs/source/cpp/glct.rst +++ b/docs/source/cpp/glct.rst @@ -1,13 +1,10 @@ Generalized Linear Chain Trick model ==================================== -MEmilio implements a SECIR-type model utilizing the Generalized Linear Chain Trick (GLCT). This is a generalization of -the LCT model. In contrast to simpler ODE models that assume (possibly unrealistic) exponentially distributed stay times, the GLCT allows for more realistic, phase-type distributed stay times in the compartments through the use of subcompartments. Phase-type distributions are dense -in the field of all positive-valued distributions. Therefore, for any positive-valued distribution, a phase-type -distribution of arbitrary precision can be identified. Note that the resulting system can still be described by an ordinary differential equation system. +MEmilio implements a SECIR-type model utilizing the Generalized Linear Chain Trick (GLCT). This is a generalization of the LCT model. In contrast to simpler ODE models that assume (possibly unrealistic) exponentially distributed stay times, the GLCT allows for more realistic, phase-type distributed stay times in the compartments through the use of subcompartments. Phase-type distributions are dense in the field of all positive-valued distributions. Therefore, for any positive-valued distribution, a phase-type +distribution of arbitrary precision can be identified. Note that the resulting system can still be described by an ODE-system. -In the following, we present the general structure of the GLCT model. The particular model documentation with examples -is linked at the bottom of this page. +In the following, we present the general structure of the GLCT model. The particular model documentation with examples is linked at the bottom of this page. Infection states ---------------- @@ -27,7 +24,7 @@ To make use of the GLCT, we additionally need to define the numbers of subcompar `Number of subcompartments of State2` `...` -Note that the model is implemented as **CompartmentalModel**. +The model is implemented as **CompartmentalModel**. Parameters @@ -36,15 +33,8 @@ Parameters The parameters of the model are defined as structs and are combined in a class ``ParameterSet``. We use different types of parameters to represent epidemiological parameters such as the mean stay times in a compartment or the contact rates between different age groups. Most model parameters are constants that describe -pathogen-specific characteristics (possibly resolved by sociodemographic groups) and are represented by a vector with a -value for each sociodemographic group. To model different contact rates between different sociodemographic groups, we -use a parameter denoted **ContactPatterns** of type **UncertainContactMatrix**. The **UncertainContactMatrix** contains -a set of contact matrices of arbitrary length and which can represent the different contact locations in the model like -schools, workplaces, or homes. The matrices can be loaded or stored in the particular example. -In the **ContactPatterns**, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic -group :math:`i` to group :math:`j`. The dimension of the matrix is automatically defined by the model initiation and it is reduced -to one value if no stratification is used. The values can be adjusted during the simulation, e.g., through implementing -nonpharmaceutical interventions, see the section on :ref:`Nonpharmaceutical Interventions`. +pathogen-specific characteristics (possibly resolved by sociodemographic groups) and are represented by a vector with a value for each sociodemographic group. To model different contact rates between different sociodemographic groups, we use a parameter denoted **ContactPatterns** of type **UncertainContactMatrix**. The **UncertainContactMatrix** contains a set of contact matrices of arbitrary length which can e.g. represent the different contact locations in the model like schools, workplaces, or homes. The matrices can be loaded or stored in the particular example. +In the **ContactPatterns**, each matrix element stores baseline contact rates :math:`c_{i,j}` between sociodemographic group :math:`i` to group :math:`j`. The dimension of the matrix is automatically defined by the model initialization and it is reduced to one value if no stratification is used. The values can be adjusted during the simulation, e.g., through implementing nonpharmaceutical interventions, see the section on :ref:`Nonpharmaceutical Interventions`. Parameters can be accessed via ``model.parameters.get>()`` and set via either ``model.parameters.set>(value)`` or ``model.parameters.get>() = value``. @@ -52,22 +42,14 @@ Parameters can be accessed via ``model.parameters.get>()`` and set Initial conditions ------------------ -The initial conditions of the model are represented by a class **LctPopulations** that gives the number of individuals in -each sociodemographic group and each subcompartment of each **InfectionState**. For more details, see -:doc:`Model Creation `. Before the simulation, set the initial conditions for each **InfectionState** and -sociodemographic group. +The initial conditions of the model are represented by a class **LctPopulations** that gives the number of individuals in each sociodemographic group and each subcompartment of each **InfectionState**. For more details, see :doc:`Model Creation `. Before the simulation, the initial conditions for each **InfectionState** and sociodemographic group must be set. .. _Nonpharmaceutical Interventions: Nonpharmaceutical interventions ------------------------------- -Contact rates can be adjusted during the simulation to model nonpharmaceutical interventions (NPIs) such as lockdowns, -school closures, or social distancing. This is done by adding **Damping**\s to the **ContactPatterns** of the model. A -**Damping** is defined by a time point at which the intervention starts and a matrix of the same size as the -**ContactMatrix**. While in many cases, the reduction matrix is given by a constant matrix with factor :math:`r`, also -group-specific reductions are possible through setting particular rows or columns differently. With a constant -reduction factor :math:`r`, the reduced contact rate is :math:`(1-r) * c_{i,j}`. +Contact rates can be adjusted during the simulation to model nonpharmaceutical interventions (NPIs) such as lockdowns, school closures, or social distancing. This is done by adding **Damping**\s to the **ContactPatterns** of the model. A **Damping** is defined by a time point at which the intervention starts and a matrix of the same size as the **ContactMatrix**. While in many cases, the reduction matrix is given by a constant matrix with factor :math:`r`, also group-specific reductions are possible through setting particular rows or columns differently. With a constant reduction factor :math:`r`, the reduced contact rate is :math:`(1-r) * c_{i,j}`. .. dropdown:: :fa:`gears` Expert's settings @@ -86,36 +68,28 @@ reduction factor :math:`r`, the reduced contact rate is :math:`(1-r) * c_{i,j}`. Simulation ---------- -Once the model is setup, run a simple simulation from time ``t0`` to ``tmax`` with an initial step size ``dt`` using the -``mio::simulation()`` function. This will run a simulation of type **Simulation** that saves the sizes of each -subcompartment over time. -You can run a simulation using either fixed or adaptive solution schemes with an absolute or relative tolerance. By -default, the simulation uses an adaptive solution scheme of the boost library and an absolute tolerance of 1e-10 and a -relative tolerance of 1e-5. For more details on the possible integration schemes, see . +Once the model is setup, one can run a simple simulation from time ``t0`` to ``tmax`` with initial step size ``dt`` using the ``mio::simulation()`` function. This will run a simulation of type **Simulation** that saves the sizes of each subcompartment over time. +You can run a simulation using either fixed or adaptive integration schemes with an absolute or relative tolerance. By default, the simulation uses an adaptive solution scheme of the boost library with an absolute tolerance of 1e-10 and a relative tolerance of 1e-5. For more details on the possible integration schemes, see . Output ------ -The output of the **Simulation** is a **TimeSeries** ``result`` containing the sizes of each subcompartment at each time point. +The output of the **Simulation** is a ``mio::TimeSeries`` containing the sizes of each subcompartment at each time point. To obtain a result with respect to the compartments, the subcompartments can be accumulated via the function ``calculate_compartments()``. A simple table can be printed using the ``print_table()`` function of the -``TimeSeries`` class. The compartment sizes can be printed with ``model.calculate_compartments(result).print_table()``. -As adaptive step size methods are used by default, the output will not be available on equidistant time points like `dt` -or days. To obtain outputs on days or user-defined time points, you can interpolate the results to days or -any other series of times points with ``mio::interpolate_simulation_result()``. +``mio::TimeSeries`` class. The compartment sizes can be printed with ``model.calculate_compartments(result).print_table()``. +As adaptive step size methods are used by default, the output will not be available on equidistant time points like `dt` or days. To obtain outputs on days or user-defined time points, you can interpolate the results to days or any other series of times points with ``mio::interpolate_simulation_result()``. Visualization ------------- -To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../python/memilio_plot>` -and its documentation. +To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../python/memilio_plot>` and its documentation. -In the following, we give detailed explanations of the GLCT-SECIR model. List of models ------------------------------ +-------------- .. toctree:: :titlesonly: diff --git a/docs/source/cpp/models/glsecir.rst b/docs/source/cpp/models/glsecir.rst index c3a50f48bf..c0454f0a59 100644 --- a/docs/source/cpp/models/glsecir.rst +++ b/docs/source/cpp/models/glsecir.rst @@ -1,16 +1,10 @@ GLCT SECIR model ================ -The GLCT-SECIR module models and simulates an epidemic using an ODE-based approach while making use of the Generalized -Linear Chain Trick to provide the option of phase-type distributed stay times in the compartments through the use of -subcompartments. The model is particularly suited for pathogens with pre- or asymptomatic infection states and when -severe or critical states are possible. The model assumes perfect immunity after recovery and is thus only suited for -epidemic use cases. In the following, we present the model in detail. +The GLCT-SECIR module models and simulates an epidemic using an ODE-based approach while making use of the Generalized Linear Chain Trick to provide the option of phase-type distributed stay times in the compartments through the use of subcompartments. The model is particularly suited for pathogens with pre- or asymptomatic infection states and when severe or critical states are possible. The model assumes perfect immunity after recovery and is thus only suited for epidemic use cases. In the following, we present the model in detail. The compartment structure with subcompartments is the same as in the LCT-SECIR model. An overview of the model -architecture can be found in the `LCT model `_. For the GLCT model, some additional transitions are possible and -we have more arrows in the model architecture. Below is an example for the Exposed compartment. Note that some indices -are omitted (e.g., :math:`n` instead of :math:`n_E`) to keep the picture simple. +architecture can be found in the `LCT model `_. For the GLCT model, some additional transitions are possible and we have more arrows in the model architecture. Below is an example for the Exposed compartment. Note that some indices are omitted (e.g., :math:`n` instead of :math:`n_E`) to keep the picture simple. .. image:: https://github.com/user-attachments/assets/fc075b7a-6cd2-4e70-bdd0-a2f4b9f2cf53 :alt: tikzGLCTSECIR @@ -41,8 +35,7 @@ It is possible to include subcompartments for the five compartments `Exposed`, ` Parameters --------------- -Below is an overview of the model variables and the model equations are stated. For a simpler description let -:math:`\mathcal{Z}=\{E,I_{NS},I_{Sy},I_{Sev},I_{Cr}\}` be the set of the compartments that can be divided into subcompartments. +Below is an overview of the model variables: .. list-table:: :header-rows: 1 @@ -73,10 +66,12 @@ Below is an overview of the model variables and the model equations are stated. - ``TransitionMatrix(...z)To(...*)`` - Matrix describing the transitions in between the subcompartments of :math:`z \in \mathcal{Z}` that describes the transition to the compartment *. +The model equations are given below. For a simpler description let :math:`\mathcal{Z}=\{E,I_{NS},I_{Sy},I_{Sev},I_{Cr}\}` be the set of the compartments that can be divided into subcompartments. + .. image:: https://github.com/SciCompMod/memilio/assets/70579874/e1da5e1d-e719-4c16-9f14-45374be7c353 :alt: equations -Note that the bold notation :math:`\mathbf{z}(t)` for :math:`z \in \mathcal{Z}` stands for a vector. If several transitions are possible from a compartment, the vector is split in order to be able to select the stay times until the transitions in each case phase-type distributed. For example, the order +Note that the bold notation :math:`\mathbf{z}(t)` for :math:`z \in \mathcal{Z}` stands for a vector. If several transitions are possible from a compartment, the vector is split in order to be able to select the stay times until the transitions individually. For example, the order .. math:: @@ -124,7 +119,7 @@ It is important that the sizes of the vectors and matrices match each other and Initial conditions ------------------ -We start by defining the number of subcompartments and constructing the model. We can choose the number of subcompartments individually for the compartments Exposed, InfectedNoSymptoms, InfectedSymptoms, InfectedSevere and InfectedCritical. +We start by defining the number of subcompartments and constructing the model with it. We can choose the number of subcompartments individually for the compartments Exposed, InfectedNoSymptoms, InfectedSymptoms, InfectedSevere and InfectedCritical. Note that in the GLCT model, we define two strains for the compartments `InfectedNoSymptoms`, `InfectedSymptoms`, `InfectedSevere` and `InfectedCritical` as individuals in these compartments can either transition to an infection state corresponding to a more severe disease state or recover. This is why we define the model with twice the number of subcompartments compared to the LCT-SECIR model for these infection states. .. code-block:: cpp @@ -152,19 +147,14 @@ We continue by defining some epidemiological parameters needed throughout the mo const ScalarType criticalPerSevere = 0.25; const ScalarType deathsPerCritical = 0.3; -Now, we define the initial values with the distribution of the population into subcompartments. Note that this method -of defining the initial values using a vector of vectors is not necessary, but should remind you how the entries of the -initial value vector relate to the defined template parameters of the model or the number of subcompartments. It is -also possible to define the initial values directly. +Now, we define the initial values with the distribution of the population into subcompartments. Note that this method of defining the initial values using a vector of vectors is not necessary, but should show how the entries of the initial value vector relate to the defined template parameters of the model or the number of subcompartments. It is also possible to define the initial values directly. -In this example, we want to initialize the GLCT model so that it corresponds to the example given for the LCT model. -This is why we take the initial population from the LCT example and split it into two strains according to the -respective transition probabilities for the the compartments InfectedNoSymptoms, InfectedSymptoms, InfectedSevere and +In this example, we initialize the GLCT model so that it corresponds to the example given for the LCT model. +For that, we take the initial population from the LCT example and split it into two strains according to the +respective transition probabilities for the compartments InfectedNoSymptoms, InfectedSymptoms, InfectedSevere and InfectedCritical. -Note that in the case of InfectedNoSymptoms, the first three subcompartments correspond to the first strain, i.e. the -individuals that will transition to InfectedSymptoms afterwards, and the other three subcompartments correspond to the -second strain, i.e. the individuals that willl recover. For the other compartments for which we defined two strains in -the model, this is done analogously. +In the case of InfectedNoSymptoms, the first three subcompartments correspond to the first strain, i.e. the +individuals that will transition to InfectedSymptoms afterwards, and the other three subcompartments correspond to the second strain, i.e. the individuals that willl recover. For the other compartments for which we defined two strains in the model, this is done analogously. We continue by defining some epidemiological parameters needed throughout the model definition and initialization. @@ -184,7 +174,7 @@ We continue by defining some epidemiological parameters needed throughout the mo {20}, // Recovered {10}}; // Dead -Here, we assert that ``initial_populations`` has the right shape. +Below, we assert that ``initial_populations`` has the right shape. .. code-block:: cpp @@ -221,9 +211,9 @@ Finally, we transfer the initial values in ``initial_populations`` to the model. } -Since we want to recreate the LCT model as defined in the corresponding example, we want to set the parameters determining the transition distributions such that we obtain Erlang distributions. +Since we want to recreate the LCT model as defined in the corresponding example, we set the parameters determining the transition distributions such that we obtain Erlang distributions. -We will explain how to do this for the different compartments below. In general, we need to define a vector ``StartingProbabilities(...)`` and a matrix ``TransitionMatrix(...z)To(...*)`` for all compartments with subcompartments, i.e. `Exposed`, `InfectedNoSymptoms`, `InfectedSymptoms`, `InfectedSevere` and `InfectedCritical`. +We will explain how to do this for the different compartments in the following. In general, we need to define a vector ``StartingProbabilities(...)`` and a matrix ``TransitionMatrix(...z)To(...*)`` for all compartments with subcompartments, i.e. `Exposed`, `InfectedNoSymptoms`, `InfectedSymptoms`, `InfectedSevere` and `InfectedCritical`. The size of the vector ``StartingProbabilities`` is the number of subcompartments and contains the initial probability of starting in any of the subcompartments of the respective compartment. The entries should sum up to 1. @@ -262,7 +252,7 @@ The strains have a length of ``NumInfectedNoSymptoms/2`` each as we choose the s model.parameters.get() = StartingProbabilitiesInfectedNoSymptoms; -Define equal transition matrices for the strains. They follow the same Erlang distribution such that we get the same result as with LCT model that can only consider one strain. +Equal transition matrices for the strains have to be defined. They follow the same Erlang distribution such that we get the same result as with the LCT model that can only consider one strain. .. code-block:: cpp @@ -326,7 +316,7 @@ We proceed analogously for the remaining compartments `InfectedSymptoms`, `Infec Nonpharmaceutical Interventions ------------------------------- -In the SECIR model, nonpharmaceutical interventions (NPIs) are implemented through dampings in the contact matrix. +In the GLCT-SECIR model, nonpharmaceutical interventions (NPIs) are implemented through dampings in the contact matrix. These dampings reduce the contact rates between different groups to simulate interventions. Basic dampings can be added to the contact matrix as follows: @@ -354,8 +344,7 @@ For age-resolved models, you can apply different dampings to different groups: -For more complex scenarios, such as real-world lockdown modeling, you can implement detailed NPIs with location-specific -dampings. The SECIR model supports contact matrices for different locations (e.g., home, school, work, other) and can apply different dampings to each location. +For more complex scenarios, such as real-world lockdown modeling, you can implement detailed NPIs with location-specific dampings. The GLCT-SECIR model supports contact matrices for different locations (e.g., home, school, work, other) and can apply different dampings to each location. Example for defining different contact locations: @@ -407,7 +396,7 @@ You can create intervention types that target specific locations with different Simulation ---------- -We can simulate using the defined model from :math:`t_0` to :math:`t_{\max}` with initial step size :math:`dt_init` as follows: +Simulating the model from :math:`t_0` to :math:`t_{\max}` with initial step size :math:`dt_init` id done as follows: .. code-block:: cpp @@ -431,14 +420,13 @@ You can also specify a custom integrator: Output ------ -The simulation result is divided by subcompartments. We can call the function ``calculate_compartments()`` to get a -result according to the `InfectionState`\s . +The simulation result is divided by subcompartments. The function ``calculate_compartments()`` aggregates the subcompartments by `InfectionState`\s . .. code-block:: cpp mio::TimeSeries population_no_subcompartments = model.calculate_compartments(result); -You can access the data in the `TimeSeries` object as follows: +You can access the data in the `mio::TimeSeries` object as follows: .. code-block:: cpp @@ -476,10 +464,7 @@ Additionally, you can export the results to a CSV file: Visualization ------------- -To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../../python/memilio_plot>` -and its documentation. - -You can export your simulation results to CSV format as described above. +To visualize the results of a simulation, you can use the Python package :doc:`memilio_plot <../../python/memilio_plot>` and its documentation. Examples @@ -493,4 +478,4 @@ An example can be found at: Overview of the ``glsecir`` namespace: -------------------------------------- -.. doxygennamespace:: mio::glsecir \ No newline at end of file +.. doxygennamespace:: mio::glsecir