model.h Source File

CPP API: model.h Source File
ode_seirv/model.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: Henrik Zunker
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 #ifndef SEIRV_MODEL_H
21 #define SEIRV_MODEL_H
22 
24 #include "memilio/config.h"
29 #include "ode_seirv/parameters.h"
30 
32 GCC_CLANG_DIAGNOSTIC(ignored "-Wshadow")
33 #include <Eigen/Dense>
34 #include <Eigen/Eigenvalues>
36 
37 #include <cmath>
38 #include <numbers>
39 
40 namespace mio
41 {
42 namespace oseirv
43 {
44 
45 // clang-format off
52 // clang-format on
53 
54 template <typename FP>
55 class Model
56  : public FlowModel<FP, InfectionState, mio::Populations<FP, AgeGroup, InfectionState>, Parameters<FP>, Flows>
57 {
59 
60 public:
61  using ParameterSet = typename Base::ParameterSet;
63 
64  Model(const PopulationsType& pop, const ParameterSet& params)
65  : Base(pop, params)
66  {
67  }
68  Model(int num_agegroups)
69  : Base(PopulationsType({AgeGroup(num_agegroups), InfectionState::Count}), ParameterSet(AgeGroup(num_agegroups)))
70  {
71  }
72 
73  void get_flows(Eigen::Ref<const Eigen::VectorX<FP>> pop, Eigen::Ref<const Eigen::VectorX<FP>> y, FP t,
74  Eigen::Ref<Eigen::VectorX<FP>> flows) const override
75  {
76  const auto& params = this->parameters;
77  const size_t num_groups = (size_t)params.get_num_groups();
78 
79  // Get effective contact matrix effective_contacts = contacts_healthy + m*contacts_sick
80  Eigen::MatrixX<FP> contacts_healthy =
81  params.template get<ContactPatternsHealthy<FP>>().get_cont_freq_mat().get_matrix_at(SimulationTime<FP>(t));
82  Eigen::MatrixX<FP> contacts_sick =
83  params.template get<ContactPatternsSick<FP>>().get_cont_freq_mat().get_matrix_at(SimulationTime<FP>(t));
84  const FP m = params.template get<SickMixing<FP>>();
85  Eigen::MatrixX<FP> effective_contacts = contacts_healthy + m * contacts_sick;
86 
87  // Normalization ν(m): prepare susceptibility scaling and next-generation matrix (NG)
88  Eigen::VectorX<FP> susceptibility(num_groups);
89  for (size_t i = 0; i < num_groups; ++i)
90  susceptibility[(Eigen::Index)i] = params.template get<SusceptibilityByAge<FP>>()[AgeGroup(i)] *
91  params.template get<SusceptibleFraction<FP>>();
92  // Sigma is a diagonal matrix applying susceptibility on the receiving (row) side of contacts.
93  Eigen::MatrixX<FP> Sigma = susceptibility.asDiagonal();
94 
95  // NG = Sigma * effective_contacts is the (unnormalized) next-generation matrix. Its spectral radius will be used
96  // below to scale contacts effective_contacts so that structure (mixing pattern) and transmissibility magnitude (BaselineTransmissibility)
97  // are cleanly separated.
98  Eigen::MatrixX<FP> NG = Sigma * effective_contacts;
99 
100  Eigen::ComplexEigenSolver<Eigen::MatrixX<FP>> ces;
101  ces.compute(NG);
102  FP scale_transmissibility = ces.eigenvalues().cwiseAbs().maxCoeff();
103  if (scale_transmissibility > FP(0.)) {
104  effective_contacts /= scale_transmissibility;
105  }
106 
107  const FP transmissibility_baseline =
108  params.template get<BaselineTransmissibility<FP>>(); // baseline transmissibility scaling (R-like factor)
109  const FP infection_rate = FP(1) / params.template get<TimeExposed<FP>>(); // 1 / mean latent duration
110  const FP recovery_rate = FP(1) / params.template get<TimeInfected<FP>>(); // 1 / mean infectious duration
111  const FP season_amplitude = params.template get<SeasonalityAmplitude<FP>>(); // amplitude of seasonal modulation
112  const FP season_shift_per_subtype =
113  params.template get<SeasonalityShiftPerSubtype<FP>>(); // base phase shift for seasonality
114  const FP season_shift_per_season =
115  params.template get<SeasonalityShiftPerSeason<FP>>(); // additional phase shift (e.g. season-specific)
116  const FP outside_foi = params.template get<OutsideFoI<FP>>(); // constant external force of infection
117  const FP clustering_exp = params.template get<ClusteringExponent<
118  FP>>(); // clustering exponent; clustering_exp<1 dampens, clustering_exp>1 amplifies prevalence effect
119 
120  const FP season =
121  std::exp(season_amplitude * std::sin(FP(2) * std::numbers::pi_v<FP> *
122  (t / FP(52.0) - season_shift_per_subtype + season_shift_per_season)));
123 
124  for (auto i : make_index_range((mio::AgeGroup)num_groups)) {
125  // Flat indices
126  const size_t Si = this->populations.get_flat_index({i, InfectionState::Susceptible});
128  const size_t Ei = this->populations.get_flat_index({i, InfectionState::Exposed});
129  const size_t EVi = this->populations.get_flat_index({i, InfectionState::ExposedVaccinated});
130  const size_t Ii = this->populations.get_flat_index({i, InfectionState::Infected});
131  const size_t IVi = this->populations.get_flat_index({i, InfectionState::InfectedVaccinated});
132 
133  FP sum = FP(0);
134  for (auto j : make_index_range((mio::AgeGroup)num_groups)) {
135  const size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible});
137  const size_t Ej = this->populations.get_flat_index({j, InfectionState::Exposed});
138  const size_t EVj = this->populations.get_flat_index({j, InfectionState::ExposedVaccinated});
139  const size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected});
140  const size_t IVj = this->populations.get_flat_index({j, InfectionState::InfectedVaccinated});
141  const size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered});
142  const size_t RVj = this->populations.get_flat_index({j, InfectionState::RecoveredVaccinated});
143 
144  const FP Nj = pop[Sj] + pop[SVj] + pop[Ej] + pop[EVj] + pop[Ij] + pop[IVj] + pop[Rj] + pop[RVj];
145  const FP inf_frac = (Nj > FP(0)) ? ((pop[Ij] + pop[IVj]) / Nj) : FP(0);
146  const FP transmission_rate = (clustering_exp == FP(1)) ? inf_frac : std::pow(inf_frac, clustering_exp);
147  sum += effective_contacts(i.get(), j.get()) * transmission_rate;
148  }
149  const FP foi_i = transmissibility_baseline * recovery_rate * season * sum + outside_foi;
150 
151  // Flows: S->E, S^V->E^V, E->I, E^V->I^V, I->R, I^V->R^V
152  flows[Base::template get_flat_flow_index<InfectionState::Susceptible, InfectionState::Exposed>(i)] =
153  foi_i * y[Si];
155  InfectionState::ExposedVaccinated>(i)] = foi_i * y[SVi];
156 
157  flows[Base::template get_flat_flow_index<InfectionState::Exposed, InfectionState::Infected>(i)] =
158  infection_rate * y[Ei];
160  InfectionState::InfectedVaccinated>(i)] = infection_rate * y[EVi];
161 
162  flows[Base::template get_flat_flow_index<InfectionState::Infected, InfectionState::Recovered>(i)] =
163  recovery_rate * y[Ii];
165  InfectionState::RecoveredVaccinated>(i)] = recovery_rate * y[IVi];
166  }
167  }
168 };
169 
170 } // namespace oseirv
171 } // namespace mio
172 #endif
size_t get_flat_index(Index const &index) const
get_flat_index returns the flat index into the stored array, given the indices of each category
Definition: custom_index_array.h:309
A FlowModel is a CompartmentalModel defined by the flows between compartments.
Definition: flow_model.h:74
constexpr size_t get_flat_flow_index() const
A flat index into an array of flows (as computed by get_flows), if the only used category in Pop is C...
Definition: flow_model.h:201
double simulation time.
Definition: damping.h:58
size_t get_num_groups() const
Get the number of the age groups.
Definition: abm/parameters.h:783
Definition: ode_seirv/model.h:57
typename Base::Populations PopulationsType
Definition: ode_seirv/model.h:62
Model(int num_agegroups)
Definition: ode_seirv/model.h:68
typename Base::ParameterSet ParameterSet
Definition: ode_seirv/model.h:61
Model(const PopulationsType &pop, const ParameterSet &params)
Definition: ode_seirv/model.h:64
void get_flows(Eigen::Ref< const Eigen::VectorX< FP >> pop, Eigen::Ref< const Eigen::VectorX< FP >> y, FP t, Eigen::Ref< Eigen::VectorX< FP >> flows) const override
Definition: ode_seirv/model.h:73
Parameter set for the age-resolved SEIRV model (S,E,I,R plus vaccinated states) as per the appendix.
Definition: ode_seirv/parameters.h:327
#define GCC_CLANG_DIAGNOSTIC(...)
Definition: compiler_diagnostics.h:62
ad::internal::unary_intermediate< AD_TAPE_REAL, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::operations::ad_sin< AD_TAPE_REAL > > sin(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x1)
Definition: ad.hpp:913
ad::internal::binary_intermediate_aa< AD_TAPE_REAL, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::operations::ad_pow_aa< AD_TAPE_REAL > > pow(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x1, const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x2)
Definition: ad.hpp:1610
ad::internal::unary_intermediate< AD_TAPE_REAL, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::operations::ad_exp< AD_TAPE_REAL > > exp(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x1)
Definition: ad.hpp:990
A collection of classes to simplify handling of matrix shapes in meta programming.
Definition: models/abm/analyze_result.h:30
Range< MultiIndexIterator< Index< Categories... > > > make_index_range(Index< Categories... > dimensions)
Construct a range that can be used to iterate over all MultiIndices in the given dimensions.
Definition: index_range.h:168
auto i
Definition: io.h:809
constexpr std::tuple_element< I, std::tuple< Index< CategoryTags >... > >::type & get(Index< CategoryTags... > &i) noexcept
Retrieves the Index (by reference) at the Ith position of a MultiIndex.
Definition: index.h:294
The AgeGroup struct is used as a dynamically sized tag for all age dependent categories.
Definition: age_group.h:32
mio::Populations< FP, AgeGroup, InfectionState > Populations
Definition: compartmental_model.h:62
A Flow defines a possible transition between two Compartments in a FlowModel.
Definition: flow.h:33
Collection of types. Each type is mapped to an index of type size_t.
Definition: type_list.h:32
Clustering/concavity parameter ρ (dimensionless).
Definition: ode_seirv/parameters.h:172