LCOV - code coverage report
Current view: top level - models/ide_seir - model.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 56 58 96.6 %
Date: 2024-11-18 12:45:26 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* 
       2             : * Copyright (C) 2020-2024 MEmilio
       3             : *
       4             : * Authors: Lena Ploetzke
       5             : *
       6             : * Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
       7             : *
       8             : * Licensed under the Apache License, Version 2.0 (the "License");
       9             : * you may not use this file except in compliance with the License.
      10             : * You may obtain a copy of the License at
      11             : *
      12             : *     http://www.apache.org/licenses/LICENSE-2.0
      13             : *
      14             : * Unless required by applicable law or agreed to in writing, software
      15             : * distributed under the License is distributed on an "AS IS" BASIS,
      16             : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      17             : * See the License for the specific language governing permissions and
      18             : * limitations under the License.
      19             : */
      20             : 
      21             : #ifndef IDE_SEIR_H
      22             : #define IDE_SEIR_H
      23             : 
      24             : #include "memilio/math/eigen.h"
      25             : #include "memilio/utils/time_series.h"
      26             : #include "ide_seir/parameters.h"
      27             : #include "ide_seir/infection_state.h"
      28             : #include "memilio/utils/logging.h"
      29             : 
      30             : #include <iostream>
      31             : 
      32             : #include <vector>
      33             : 
      34             : namespace mio
      35             : {
      36             : namespace iseir
      37             : {
      38             : template <typename FP = double>
      39             : class Model
      40             : {
      41             :     using Pa  = ParametersBase<FP>;
      42             :     using Vec = TimeSeries<double>::Vector;
      43             : 
      44             : public:
      45             :     /**
      46             :         * @brief Create an IDE SEIR model.
      47             :         *
      48             :         * @param[in, out] init TimeSeries with the initial values of the number of susceptibles at associated initial times.
      49             :         *   The time steps in this vector should be equidistant and equal to the time step used for the simulation. 
      50             :         *   A certain history of time steps and values for susceptibles is needed. 
      51             :         *   A warning is displayed if the condition is violated.
      52             :         *   Co be more precise, the first time point needs to be smaller than -(k-1)*TimeStep with 
      53             :         *       k=ceil((InfectiousTime + LatencyTime)/TimeStep).
      54             :         *   The last time point in this vector should be a time 0.
      55             :         * @param[in] dt_init The size of the time step used for numerical simulation.
      56             :         * @param[in] N_init The population of the considered region. 
      57             :         */
      58           2 :     Model(TimeSeries<double>&& init, double dt_init, int N_init, const Pa& Parameterset_init = Pa())
      59           2 :         : parameters{Parameterset_init}
      60           2 :         , m_result{std::move(init)}
      61           2 :         , m_result_SEIR{TimeSeries<double>(4)}
      62           2 :         , m_dt{dt_init}
      63           2 :         , m_N{N_init}
      64             :     {
      65           2 :     }
      66             : 
      67             :     /**
      68             :         * @brief Simulate the evolution of infection numbers with the given IDE SEIR model.
      69             :         *
      70             :         * The simulation is performed by solving the underlying model equation numerically. 
      71             :         * Here, an integro-differential equation is to be solved. The model parameters and the initial data are used.
      72             :         *
      73             :         * @param[in] t_max Last simulation day. 
      74             :         *   If the last point of time of the initial TimeSeries was 0, the simulation will be executed for t_max days.
      75             :         * @return The result of the simulation, stored in a TimeSeries with simulation time and 
      76             :         *       associated number of susceptibles.
      77             :         */
      78           2 :     TimeSeries<double> const& simulate(int t_max)
      79             :     {
      80             : 
      81           2 :         m_l = (int)std::floor(parameters.template get<LatencyTime>() / m_dt);
      82           2 :         m_k =
      83           2 :             (int)std::ceil((parameters.template get<InfectiousTime>() + parameters.template get<LatencyTime>()) / m_dt);
      84           2 :         if (m_result.get_time(0) > -(m_k - 1) * m_dt) {
      85           0 :             log_warning("Constraint check: Initial data starts later than necessary. The simulation may be distorted. "
      86             :                         "Start the data at time {:.4f} at the latest.",
      87           0 :                         -(m_k - 1) * m_dt);
      88             :         }
      89             : 
      90         162 :         while (m_result.get_last_time() < t_max) {
      91         160 :             m_result.add_time_point(m_result.get_last_time() + m_dt);
      92         160 :             Eigen::Index idx = m_result.get_num_time_points();
      93             : 
      94             :             // R0t is the effective reproduction number at time t
      95         320 :             auto R0t1 = parameters.template get<ContactFrequency<double>>().get_cont_freq_mat().get_matrix_at(
      96         320 :                             m_result.get_time(idx - 2))(0, 0) *
      97         160 :                         parameters.template get<TransmissionRisk>() * parameters.template get<InfectiousTime>();
      98         320 :             auto R0t2 = parameters.template get<ContactFrequency<double>>().get_cont_freq_mat().get_matrix_at(
      99         320 :                             m_result.get_last_time())(0, 0) *
     100         160 :                         parameters.template get<TransmissionRisk>() * parameters.template get<InfectiousTime>();
     101             : 
     102         320 :             m_result.get_last_value() =
     103         320 :                 Vec::Constant(1, m_result[idx - 2][0] * exp(m_dt * (0.5 * 1 / m_N) *
     104         160 :                                                             (R0t1 * num_integration_inner_integral(idx - 2) +
     105         160 :                                                              R0t2 * num_integration_inner_integral(idx - 1))));
     106             :         }
     107           2 :         return m_result;
     108             :     }
     109             : 
     110             :     /**
     111             :         * @brief Calculate the distribution of the population in E, I and, R based on the calculated values for S.
     112             :         *
     113             :         * The values are calculated using the average latency and infection time, not using model equations. 
     114             :         * The simulated values of S are used for this purpose, so the simulate() function should be called beforehand.
     115             :         * 
     116             :         * @return The result of the calculation stored in an TimeSeries. The TimeSeries contains the simulation time and an
     117             :         *   associated Vector with values for S, E, I, and R.
     118             :         */
     119           2 :     TimeSeries<double> const& calculate_EIR()
     120             :     {
     121           2 :         Eigen::Index num_points = m_result.get_num_time_points();
     122           2 :         double S, E, I, R;
     123         206 :         for (Eigen::Index i = m_k; i < num_points; ++i) {
     124         204 :             S = m_result[i][Eigen::Index(InfectionState::S)];
     125         204 :             E = m_result[i - m_l][Eigen::Index(InfectionState::S)] - S;
     126         204 :             I = m_result[i - m_k][Eigen::Index(InfectionState::S)] - m_result[i - m_l][Eigen::Index(InfectionState::S)];
     127         204 :             R = m_N - S - E - I;
     128         204 :             m_result_SEIR.add_time_point(m_result.get_time(i), (Vec(4) << S, E, I, R).finished());
     129             :         }
     130           4 :         return m_result_SEIR;
     131             :     }
     132             : 
     133             :     // Used Parameters for the simulation.
     134             :     Pa parameters{};
     135             : 
     136             : private:
     137             :     /**
     138             :         * @brief Density of the generalized beta distribution used for the function f_{beta} of the IDE SEIR model.
     139             :         *
     140             :         * @param[in] tau evaluation point of the generalized Beta distribution.
     141             :         * @param[in] p parameter p of the generalized Beta distribution.
     142             :         * @param[in] q parameter q of the generalized Beta distribution.
     143             :         * @result Evaluation of the generalized beta distribution at the given evaluation point.
     144             :         */
     145       26560 :     double generalized_beta_distribution(double tau, double p = 3.0, double q = 10.0) const
     146             :     {
     147       52800 :         if ((parameters.template get<LatencyTime>() < tau) &&
     148       26240 :             (parameters.template get<InfectiousTime>() + parameters.template get<LatencyTime>() > tau)) {
     149       26240 :             return tgamma(p + q) * pow(tau - parameters.template get<LatencyTime>(), p - 1) *
     150       26240 :                    pow(parameters.template get<InfectiousTime>() + parameters.template get<LatencyTime>() - tau,
     151             :                        q - 1) /
     152       26240 :                    (tgamma(p) * tgamma(q) * pow(parameters.template get<InfectiousTime>(), p + q - 1));
     153             :         }
     154         320 :         return 0.0;
     155             :     }
     156             : 
     157             :     /**
     158             :         * @brief Numerical differentiation of one compartment using a central difference quotient.
     159             :         * 
     160             :         * @param[in] ts_ide TimeSeries with the time steps already calculated. 
     161             :         *       Used as function values in numerical differentiation.
     162             :         * @param[in] idx Time index at which the numerical differentiation should be performed.
     163             :         * @param[in] compartment Compartment for which the numerical differentiation is to be performed.
     164             :         * @return Numerically approximated derivative of the function belonging to the compartment at the point t[idx].
     165             :         */
     166       26560 :     double central_difference_quotient(TimeSeries<double> const& ts_ide, InfectionState compartment,
     167             :                                        Eigen::Index idx) const
     168             :     {
     169       26560 :         return (ts_ide[idx + 1][Eigen::Index(compartment)] - ts_ide[idx - 1][Eigen::Index(compartment)]) / (2 * m_dt);
     170             :     }
     171             : 
     172             :     /**
     173             :         * @brief Numerical integration of the inner integral of the integro-differential equation for the group S using
     174             :         *    a trapezoidal sum.
     175             :         * 
     176             :         * @param[in] idx Index of the point of time used in the inner integral.
     177             :         * @return Result of the numerical integration.
     178             :         */
     179         320 :     double num_integration_inner_integral(Eigen::Index idx) const
     180             :     {
     181         320 :         double res     = 0.5 * (generalized_beta_distribution(m_result.get_time(idx) - m_result.get_time(idx - m_k)) *
     182         320 :                                 central_difference_quotient(m_result, InfectionState::S, m_k) +
     183         320 :                             generalized_beta_distribution(m_result.get_time(idx) - m_result.get_time(idx - m_l)) *
     184         320 :                                 central_difference_quotient(m_result, InfectionState::S, idx - m_l));
     185         320 :         Eigen::Index i = idx - m_k + 1;
     186       26240 :         while (i <= idx - m_l - 2) {
     187       25920 :             res += (generalized_beta_distribution(m_result.get_time(idx) - m_result.get_time(i)) *
     188       25920 :                     central_difference_quotient(m_result, InfectionState::S, i));
     189       25920 :             ++i;
     190             :         }
     191         320 :         return res;
     192             :     }
     193             : 
     194             :     // TimeSeries containing points of time and the corresponding number of susceptibles.
     195             :     TimeSeries<double> m_result;
     196             :     // TimeSeries containing points of time and the corresponding number of susceptibles, exposed,
     197             :     // infected and recovered.
     198             :     TimeSeries<double> m_result_SEIR;
     199             : 
     200             :     // Timestep used for simulation.
     201             :     double m_dt{0};
     202             :     // Population of the considered region.
     203             :     int m_N{0};
     204             : 
     205             :     // Two Indices used for simulation.
     206             :     Eigen::Index m_k{0};
     207             :     Eigen::Index m_l{0};
     208             : };
     209             : } // namespace iseir
     210             : } // namespace mio
     211             : #endif

Generated by: LCOV version 1.14