model.h Source File

CPP API: model.h Source File
ode_seir/model.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: Daniel Abele, Jan Kleinert, Martin J. Kuehn
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 SEIR_MODEL_H
21 #define SEIR_MODEL_H
22 
24 #include "memilio/config.h"
30 #include "ode_seir/parameters.h"
31 
33 GCC_CLANG_DIAGNOSTIC(ignored "-Wshadow")
34 #include <Eigen/Dense>
36 
37 namespace mio
38 {
39 namespace oseir
40 {
41 
42 /********************
43  * define the model *
44  ********************/
45 
46 // clang-format off
50 // clang-format on
51 template <typename FP>
52 class Model
53  : public FlowModel<FP, InfectionState, mio::Populations<FP, AgeGroup, InfectionState>, Parameters<FP>, Flows>
54 {
56 
57 public:
58  using typename Base::ParameterSet;
59  using typename Base::Populations;
60 
61  Model(const Populations& pop, const ParameterSet& params)
62  : Base(pop, params)
63  {
64  }
65 
66  Model(int num_agegroups)
67  : Base(Populations({AgeGroup(num_agegroups), InfectionState::Count}), ParameterSet(AgeGroup(num_agegroups)))
68  {
69  }
70 
71  void get_flows(Eigen::Ref<const Eigen::VectorX<FP>> pop, Eigen::Ref<const Eigen::VectorX<FP>> y, FP t,
72  Eigen::Ref<Eigen::VectorX<FP>> flows) const override
73  {
74  const Index<AgeGroup> age_groups = reduce_index<Index<AgeGroup>>(this->populations.size());
75  const auto& params = this->parameters;
76 
77  for (auto i : make_index_range(age_groups)) {
78  const size_t Si = this->populations.get_flat_index({i, InfectionState::Susceptible});
79  const size_t Ei = this->populations.get_flat_index({i, InfectionState::Exposed});
80  const size_t Ii = this->populations.get_flat_index({i, InfectionState::Infected});
81 
82  for (auto j : make_index_range(age_groups)) {
83  const size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible});
84  const size_t Ej = this->populations.get_flat_index({j, InfectionState::Exposed});
85  const size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected});
86  const size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered});
87 
88  const FP Nj = pop[Sj] + pop[Ej] + pop[Ij] + pop[Rj];
89  const FP divNj = (Nj < Limits<FP>::zero_tolerance()) ? FP(0.0) : FP(1.0 / Nj);
90  const FP coeffStoE = params.template get<ContactPatterns<FP>>().get_cont_freq_mat().get_matrix_at(
91  SimulationTime<FP>(t))(i.get(), j.get()) *
92  params.template get<TransmissionProbabilityOnContact<FP>>()[i] * divNj;
93 
94  flows[Base::template get_flat_flow_index<InfectionState::Susceptible, InfectionState::Exposed>(i)] +=
95  coeffStoE * y[Si] * pop[Ij];
96  }
97  flows[Base::template get_flat_flow_index<InfectionState::Exposed, InfectionState::Infected>(i)] =
98  (1.0 / params.template get<TimeExposed<FP>>()[i]) * y[Ei];
99  flows[Base::template get_flat_flow_index<InfectionState::Infected, InfectionState::Recovered>(i)] =
100  (1.0 / params.template get<TimeInfected<FP>>()[i]) * y[Ii];
101  }
102  }
103 
111  {
112  if (!(t_idx < static_cast<size_t>(y.get_num_time_points()))) {
113  return mio::failure(mio::StatusCode::OutOfRange, "t_idx is not a valid index for the TimeSeries");
114  }
115 
116  auto const& params = this->parameters;
117 
118  const size_t num_groups = (size_t)params.get_num_groups();
119  constexpr size_t num_infected_compartments = 2;
120  const size_t total_infected_compartments = num_infected_compartments * num_groups;
121 
122  ContactMatrixGroup<FP> const& contact_matrix = params.template get<ContactPatterns<ScalarType>>();
123 
124  Eigen::MatrixX<FP> F = Eigen::MatrixX<FP>::Zero(total_infected_compartments, total_infected_compartments);
125  Eigen::MatrixX<FP> V = Eigen::MatrixX<FP>::Zero(total_infected_compartments, total_infected_compartments);
126 
127  for (auto i = AgeGroup(0); i < AgeGroup(num_groups); i++) {
129  for (auto j = AgeGroup(0); j < AgeGroup(num_groups); j++) {
130 
131  const ScalarType Nj = this->populations.get_group_total(j);
132  const ScalarType divNj = (Nj < 1e-12) ? 0.0 : 1.0 / Nj;
133 
134  FP coeffStoE = contact_matrix.get_matrix_at(SimulationTime<FP>(y.get_time(t_idx)))(i.get(), j.get()) *
135  params.template get<TransmissionProbabilityOnContact<FP>>()[i] * divNj;
136  F((size_t)i, (size_t)j + num_groups) = coeffStoE * y.get_value(t_idx)[Si];
137  }
138 
139  FP T_Ei = params.template get<mio::oseir::TimeExposed<FP>>()[i];
140  FP T_Ii = params.template get<mio::oseir::TimeInfected<FP>>()[i];
141  V((size_t)i, (size_t)i) = 1.0 / T_Ei;
142  V((size_t)i + num_groups, (size_t)i) = -1.0 / T_Ei;
143  V((size_t)i + num_groups, (size_t)i + num_groups) = 1.0 / T_Ii;
144  }
145 
146  V = V.inverse();
147 
148  Eigen::MatrixXd NextGenMatrix(total_infected_compartments, total_infected_compartments);
149  NextGenMatrix.noalias() = F * V;
150 
151  // Compute the largest eigenvalue in absolute value
152  Eigen::ComplexEigenSolver<Eigen::MatrixX<ScalarType>> ces;
153  ces.compute(NextGenMatrix);
154  FP rho = ces.eigenvalues().cwiseAbs().maxCoeff();
155 
156  return mio::success(rho);
157  }
158 
164  Eigen::VectorX<FP> get_reproduction_numbers(const mio::TimeSeries<FP>& y)
165  {
166  auto num_time_points = y.get_num_time_points();
167  Eigen::VectorX<FP> temp(num_time_points);
168  for (size_t i = 0; i < static_cast<size_t>(num_time_points); i++) {
169  temp[i] = get_reproduction_number(i, y).value();
170  }
171  return temp;
172  }
173 
181  {
182  if (t_value < y.get_time(0) || t_value > y.get_last_time()) {
184  "Cannot interpolate reproduction number outside computed horizon of the TimeSeries");
185  }
186 
187  if (t_value == y.get_time(0)) {
188  return mio::success(get_reproduction_number((size_t)0, y).value());
189  }
190 
191  auto times = std::vector<FP>(y.get_times().begin(), y.get_times().end());
192 
193  auto time_late = std::distance(times.begin(), std::lower_bound(times.begin(), times.end(), t_value));
194 
195  FP y1 = get_reproduction_number(static_cast<size_t>(time_late - 1), y).value();
196  FP y2 = get_reproduction_number(static_cast<size_t>(time_late), y).value();
197 
198  auto result = linear_interpolation(t_value, y.get_time(time_late - 1), y.get_time(time_late), y1, y2);
199  return mio::success(static_cast<FP>(result));
200  }
201 
206  template <class IOContext>
207  void serialize(IOContext& io) const
208  {
209  auto obj = io.create_object("Model");
210  obj.add_element("Parameters", this->parameters);
211  obj.add_element("Populations", this->populations);
212  }
213 
218  template <class IOContext>
219  static IOResult<Model> deserialize(IOContext& io)
220  {
221  auto obj = io.expect_object("Model");
222  auto par = obj.expect_element("Parameters", Tag<ParameterSet>{});
223  auto pop = obj.expect_element("Populations", Tag<Populations>{});
224  return apply(
225  io,
226  [](auto&& par_, auto&& pop_) {
227  return Model{pop_, par_};
228  },
229  par, pop);
230  }
231 };
232 
233 } // namespace oseir
234 } // namespace mio
235 
236 #endif // SEIR_MODEL_H
represents a collection of contact frequency matrices that whose sum is the total number of contacts.
Definition: contact_matrix.h:536
mio::Index< Tag > size() const
returns the size along the dimension provided as template parameter
Definition: custom_index_array.h:204
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
A class template for compartment populations.
Definition: populations.h:55
FP get_group_total(mio::Index< T > group_idx) const
get_group_total returns the total population of a group in one category
Definition: populations.h:136
double simulation time.
Definition: damping.h:58
stores vectors of values at time points (or some other abstract variable) the value at each time poin...
Definition: time_series.h:58
Eigen::Ref< const Vector > get_value(Eigen::Index i) const
reference to value vector at time point i
Definition: time_series.h:298
Range< time_iterator > get_times()
Definition: time_series.h:453
FP & get_last_time()
time of time point at index num_time_points - 1
Definition: time_series.h:286
Eigen::Index get_num_time_points() const
number of time points in the series
Definition: time_series.h:197
FP & get_time(Eigen::Index i)
time of time point at index i
Definition: time_series.h:272
Parameters of the simulation that are the same everywhere within the Model.
Definition: abm/parameters.h:764
size_t get_num_groups() const
Get the number of the age groups.
Definition: abm/parameters.h:783
Definition: ode_seir/model.h:54
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_seir/model.h:71
IOResult< FP > get_reproduction_number(FP t_value, const mio::TimeSeries< FP > &y)
Computes the reproduction number at a given time point of the Model output obtained by the Simulation...
Definition: ode_seir/model.h:180
void serialize(IOContext &io) const
serialize this.
Definition: ode_seir/model.h:207
Model(int num_agegroups)
Definition: ode_seir/model.h:66
static IOResult< Model > deserialize(IOContext &io)
deserialize an object of this class.
Definition: ode_seir/model.h:219
IOResult< FP > get_reproduction_number(size_t t_idx, const mio::TimeSeries< FP > &y)
Computes the reproduction number at a given index time of the Model output obtained by the Simulation...
Definition: ode_seir/model.h:110
Model(const Populations &pop, const ParameterSet &params)
Definition: ode_seir/model.h:61
Eigen::VectorX< FP > get_reproduction_numbers(const mio::TimeSeries< FP > &y)
Computes the reproduction number for all time points of the Model output obtained by the Simulation.
Definition: ode_seir/model.h:164
Parameters of an age-resolved SECIR/SECIHURD model.
Definition: ode_seir/parameters.h:112
#define GCC_CLANG_DIAGNOSTIC(...)
Definition: compiler_diagnostics.h:62
double ScalarType
Configuration of memilio library.
Definition: memilio/config.h:30
trait_value< T >::RETURN_TYPE & value(T &x)
Definition: ad.hpp:3308
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 failure(const IOStatus &s)
Create an object that is implicitly convertible to an error IOResult<T>.
Definition: io.h:380
boost::outcome_v2::in_place_type_t< T > Tag
Type that is used for overload resolution.
Definition: io.h:407
auto i
Definition: io.h:809
details::ApplyResultT< F, T... > apply(IOContext &io, F f, const IOResult< T > &... rs)
Evaluate a function with zero or more unpacked IOResults as arguments.
Definition: io.h:481
auto linear_interpolation(const X &x_eval, const X &x_1, const X &x_2, const V &y1, const V &y2)
Linear interpolation between two data values.
Definition: interpolation.h:44
auto success()
Create an object that is implicitly convertible to a succesful IOResult<void>.
Definition: io.h:359
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
boost::outcome_v2::unchecked< T, IOStatus > IOResult
Value-or-error type for operations that return a value but can fail.
Definition: io.h:353
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
probability of getting infected from a contact
Definition: ode_seir/parameters.h:43