initializer_flows.h Source File

CPP API: initializer_flows.h Source File
initializer_flows.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 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 LCTSECIR_INITIALIZER_H
22 #define LCTSECIR_INITIALIZER_H
23 
24 #include "memilio/config.h"
25 #include "lct_secir/model.h"
26 #include "lct_secir/infection_state.h"
27 #include "memilio/math/eigen.h"
30 #include "memilio/utils/logging.h"
33 
34 namespace mio
35 {
36 namespace lsecir
37 {
38 
52 template <typename FP, typename Model>
54 {
55 public:
57 
68  Initializer(TimeSeries<FP>&& flows, Model& model)
69  : m_flows(std::move(flows))
70  , m_model(model)
71  {
72  m_dt = m_flows.get_time(1) - m_flows.get_time(0);
73  }
74 
88  bool compute_initialization_vector(Eigen::VectorX<FP> const& total_population, Eigen::VectorX<FP> const& deaths,
89  Eigen::VectorX<FP> const& total_confirmed_cases)
90  {
91 
92  Eigen::VectorX<FP> init(m_model.populations.get_compartments());
93 
94  bool error = compute_initialization_vector_impl(init, total_population, deaths, total_confirmed_cases);
95  if (error) {
96  return true;
97  }
98 
99  // Update initial value vector of the model.
100  for (size_t i = 0; i < m_model.populations.get_num_compartments(); i++) {
101  m_model.populations[i] = init[i];
102  }
103 
104  // Check if constraints are fulfilled.
105  return check_constraints();
106  }
107 
113  void set_tol_for_support_max(FP new_tol)
114  {
115  m_tol = new_tol;
116  }
117 
118 private:
133  template <size_t Group = 0>
134  bool compute_initialization_vector_impl(Eigen::VectorX<FP>& init, Eigen::VectorX<FP> const& total_population,
135  Eigen::VectorX<FP> const& deaths,
136  Eigen::VectorX<FP> const& total_confirmed_cases)
137  {
138  static_assert((Group < Model::num_groups) && (Group >= 0), "The template parameter Group should be valid.");
139  using LctStateGroup = type_at_index_t<Group, LctStatesGroups>;
140  Eigen::Index first_index = m_model.populations.template get_first_index_of_group<Group>();
141  Eigen::Index first_index_flows = Group * (Eigen::Index)InfectionTransition::Count;
142 
143  bool error =
144  // Exposed.
145  (compute_compartment<InfectionState::Exposed, Group>(
146  init, first_index_flows + (Eigen::Index)InfectionTransition::SusceptibleToExposed,
147  1 / m_model.parameters.template get<TimeExposed<FP>>()[Group])) ||
148  // InfectedNoSymptoms.
149  (compute_compartment<InfectionState::InfectedNoSymptoms, Group>(
150  init, first_index_flows + (Eigen::Index)InfectionTransition::ExposedToInfectedNoSymptoms,
151  1 / m_model.parameters.template get<TimeInfectedNoSymptoms<FP>>()[Group])) ||
152  // InfectedSymptoms.
153  (compute_compartment<InfectionState::InfectedSymptoms, Group>(
154  init, first_index_flows + (Eigen::Index)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms,
155  1 / m_model.parameters.template get<TimeInfectedSymptoms<FP>>()[Group])) ||
156  // InfectedSevere.
157  (compute_compartment<InfectionState::InfectedSevere, Group>(
158  init, first_index_flows + (Eigen::Index)InfectionTransition::InfectedSymptomsToInfectedSevere,
159  1 / m_model.parameters.template get<TimeInfectedSevere<FP>>()[Group])) ||
160  // InfectedCritical.
161  (compute_compartment<InfectionState::InfectedCritical, Group>(
162  init, first_index_flows + (Eigen::Index)InfectionTransition::InfectedSevereToInfectedCritical,
163  1 / m_model.parameters.template get<TimeInfectedCritical<FP>>()[Group]));
164  if (error) {
165  return true;
166  }
167 
168  // Recovered.
169  // Number of recovered is equal to the cumulative number of confirmed cases minus the number of people
170  // in the group who are infected at the moment.
171  init[first_index + LctStateGroup::template get_first_index<InfectionState::Recovered>()] =
172  total_confirmed_cases[Group] -
173  init.segment(first_index + LctStateGroup::template get_first_index<InfectionState::InfectedSymptoms>(),
174  LctStateGroup::template get_num_subcompartments<InfectionState::InfectedSymptoms>() +
175  LctStateGroup::template get_num_subcompartments<InfectionState::InfectedSevere>() +
176  LctStateGroup::template get_num_subcompartments<InfectionState::InfectedCritical>())
177  .sum() -
178  deaths[Group];
179 
180  // Susceptibles.
181  init[first_index + LctStateGroup::template get_first_index<InfectionState::Susceptible>()] =
182  total_population[Group] -
183  init.segment(first_index + LctStateGroup::template get_first_index<InfectionState::Exposed>(),
184  LctStateGroup::Count - 2)
185  .sum() -
186  deaths[Group];
187 
188  // Dead.
189  init[first_index + LctStateGroup::template get_first_index<InfectionState::Dead>()] = deaths[Group];
190 
191  for (size_t state_idx : {LctStateGroup::template get_first_index<InfectionState::Susceptible>(),
192  LctStateGroup::template get_first_index<InfectionState::Recovered>(),
193  LctStateGroup::template get_first_index<InfectionState::Dead>()}) {
194  if (floating_point_less<FP>(init[first_index + state_idx], 0.0, 1e-8)) {
195  log_error("Initialization failed. Values of total_confirmed_cases, deaths and total_population do not "
196  "match the specified values for the transitions, leading to at least one negative result.");
197  return true;
198  }
199  }
200  // Function call for next group if applicable.
201  if constexpr (Group + 1 < Model::num_groups) {
202  return compute_initialization_vector_impl<Group + 1>(init, total_population, deaths, total_confirmed_cases);
203  }
204  else {
205  return false;
206  }
207  }
208 
213  bool check_constraints() const
214  {
215  if (!((Eigen::Index)InfectionTransition::Count * Model::num_groups == m_flows.get_num_elements())) {
216  log_error("Initial condition size does not match subcompartments.");
217  return true;
218  }
219 
220  if (!(floating_point_equal<FP>(0., m_flows.get_last_time(), 1e-8, 1e-14))) {
221  log_error("Last time point in flows has to be 0.");
222  return true;
223  }
224 
225  for (int i = 1; i < m_flows.get_num_time_points(); i++) {
226  if (!(floating_point_equal<FP>(m_dt, m_flows.get_time(i) - m_flows.get_time(i - 1), 1e-8, 1e-14))) {
227  log_error("Time points in flows have to be equidistant.");
228  return true;
229  }
230  }
231 
232  if (!(m_dt < 1)) {
233  log_warning("Step size was set very large. The result could be distorted.");
234  return true;
235  }
236 
237  // Check if model is valid and the calculated initial value vector is valid.
238  return m_model.check_constraints();
239  }
240 
256  template <InfectionState State, size_t Group>
257  bool compute_compartment(Eigen::VectorX<FP>& init, Eigen::Index idx_incoming_flow, FP transition_rate) const
258  {
259  using std::ceil;
260 
261  size_t first_index = m_model.populations.template get_first_index_of_group<Group>() +
262  type_at_index_t<Group, LctStatesGroups>::template get_first_index<State>();
263  size_t num_subcompartments = type_at_index_t<Group, LctStatesGroups>::template get_num_subcompartments<State>();
264 
265  // Initialize relevant density for the InfectionState.
266  // For the first subcompartment a shape parameter of one is needed.
267  ErlangDensity erlang(1, 1. / (num_subcompartments * transition_rate));
268 
269  // Initialize other relevant parameters.
270  FP calc_time{0};
271  Eigen::Index calc_time_index{0};
272  FP state_age{0};
273  FP sum{0};
274  Eigen::Index num_time_points = m_flows.get_num_time_points();
275 
276  // Calculate number of people in each subcompartment.
277  for (size_t j = 0; j < num_subcompartments; j++) {
278  // For subcompartment number j+1, shape parameter j+1 is needed.
279  erlang.set_distribution_parameter((FP)j + 1);
280 
281  // Determine relevant calculation area and corresponding index.
282  calc_time = erlang.get_support_max(m_dt, m_tol);
283  calc_time_index = (Eigen::Index)ceil(calc_time / m_dt) - 1;
284 
285  if (num_time_points < calc_time_index) {
286  log_error("Initialization failed. Not enough time points for the transitions are given. More than {} "
287  "are needed but just {} are given.",
288  calc_time_index, num_time_points);
289  return true;
290  }
291  else {
292  // Approximate integral with non-standard scheme.
293  for (Eigen::Index i = num_time_points - calc_time_index; i < num_time_points; i++) {
294  state_age = (num_time_points - i) * m_dt;
295  sum += erlang.eval(state_age) * m_flows[i][idx_incoming_flow];
296  }
297  init[first_index + j] = 1. / (num_subcompartments * transition_rate) * sum;
298  if (init[first_index + j] < 0) {
299  log_error(
300  "Initialization failed. Result for at least one subcompartment is less than zero. Please check "
301  "the input values.");
302  return true;
303  }
304  }
305  sum = 0;
306  }
307  return false;
308  }
309 
312  FP m_dt{};
313  FP m_tol{1e-10};
314 };
315 
316 } // namespace lsecir
317 } // namespace mio
318 
319 #endif
size_t get_num_compartments() const
get_num_compartments Returns the number of compartments.
Definition: lct_populations.h:75
Eigen::VectorX< FP > get_compartments() const
Returns an Eigen copy of the vector of populations.
Definition: lct_populations.h:125
stores vectors of values at time points (or some other abstract variable) the value at each time poin...
Definition: time_series.h:58
Class that can be used to compute an initialization vector out of flows for an LCT Model with divisio...
Definition: initializer_flows.h:54
FP m_dt
Step size of the times in m_flows and time step for the approximation of the integral.
Definition: initializer_flows.h:312
void set_tol_for_support_max(FP new_tol)
Setter for the tolerance used to calculate the maximum support of ErlangDensitys.
Definition: initializer_flows.h:113
Initializer(TimeSeries< FP > &&flows, Model &model)
Constructs a new Initializer object.
Definition: initializer_flows.h:68
bool compute_initialization_vector_impl(Eigen::VectorX< FP > &init, Eigen::VectorX< FP > const &total_population, Eigen::VectorX< FP > const &deaths, Eigen::VectorX< FP > const &total_confirmed_cases)
Implementation of the calculation of the initial value vector slice that corresponds to a specified g...
Definition: initializer_flows.h:134
FP m_tol
Tolerance used to calculate the maximum support of the ErlangDensitys.
Definition: initializer_flows.h:313
Model & m_model
The LCT-SECIR model for which the initialization should be performed.
Definition: initializer_flows.h:311
bool compute_initialization_vector(Eigen::VectorX< FP > const &total_population, Eigen::VectorX< FP > const &deaths, Eigen::VectorX< FP > const &total_confirmed_cases)
Core function of Initializer.
Definition: initializer_flows.h:88
TimeSeries< FP > m_flows
TimeSeries with the flows which are used to calculate the initial vector.
Definition: initializer_flows.h:310
typename Model::LctStatesGroups LctStatesGroups
Definition: initializer_flows.h:56
bool compute_compartment(Eigen::VectorX< FP > &init, Eigen::Index idx_incoming_flow, FP transition_rate) const
Computes a slice of the initial value vector for each subcompartment of one InfectionState for a spec...
Definition: initializer_flows.h:257
bool check_constraints() const
Checks constraints of the Initializer including checks for the model.
Definition: initializer_flows.h:213
Class that defines an LCT-SECIR model.
Definition: lct_secir/model.h:55
bool check_constraints() const
Checks that the model satisfies all constraints (e.g.
Definition: lct_secir/model.h:135
TypeList< LctStates... > LctStatesGroups
Definition: lct_secir/model.h:57
static constexpr size_t num_groups
Definition: lct_secir/model.h:61
static double ceil(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x)
Definition: ad.hpp:2449
void init()
Initialize MPI.
Definition: miompi.cpp:42
A collection of classes to simplify handling of matrix shapes in meta programming.
Definition: models/abm/analyze_result.h:30
auto i
Definition: io.h:809
void log_warning(spdlog::string_view_t fmt, const Args &... args)
Definition: logging.h:112
typename type_at_index< Index, Types... >::type type_at_index_t
The type at the Index-th position in the list Types.
Definition: metaprogramming.h:118
void log_error(spdlog::string_view_t fmt, const Args &... args)
Definition: logging.h:100
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
Definition: io.h:94
Populations populations
Definition: compartmental_model.h:156
ParameterSet parameters
Definition: compartmental_model.h:157
Class that defines the probability density function corresponding to the Erlang distribution with the...
Definition: state_age_function.h:720
ScalarType get_support_max(ScalarType dt, ScalarType tol=1e-10) override
Computes the maximum of the support of the function.
Definition: state_age_function.h:762
ScalarType eval(ScalarType state_age) override
Defines ErlangDensity depending on state_age.
Definition: state_age_function.h:741
void set_distribution_parameter(FP new_distribution_parameter)
Set the m_distribution_parameter object.
Definition: state_age_function.h:169
Average time spent in the Exposed compartment for each group.
Definition: lct_secir/parameters.h:44
Average time treated by ICU before dead or recover for each group in the SECIR model in day unit.
Definition: lct_secir/parameters.h:111
Average time spent in the TimeInfectedNoSymptoms before developing symptoms or recover for each group...
Definition: lct_secir/parameters.h:61
Average time being in the Hospital before treated by ICU or recover for each group in the SECIR model...
Definition: lct_secir/parameters.h:95
Average time spent in the TimeInfectedSymptoms before going to hospital or recover for each group in ...
Definition: lct_secir/parameters.h:78