simulation.h Source File

CPP API: simulation.h Source File
models/smm/simulation.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: René Schmieding, Julia Bicker
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 MIO_SMM_SIMULATION_H
22 #define MIO_SMM_SIMULATION_H
23 
24 #include "smm/model.h"
25 #include "smm/parameters.h"
27 
28 namespace mio
29 {
30 
31 namespace smm
32 {
33 
39 template <typename FP, class Comp, class Status = Comp, class Region = mio::regions::Region>
41 {
42 public:
44 
51  Simulation(Model const& model, FP t0 = 0., FP dt = 1.)
52  : m_dt(dt)
53  , m_model(std::make_unique<Model>(model))
54  , m_result(t0, m_model->get_initial_values())
59  {
60  assert(dt > 0);
61  assert(m_waiting_times.size() > 0);
62  assert(std::all_of(adoption_rates().begin(), adoption_rates().end(),
63  [regions = reduce_index<Region>(model.populations.size())](auto&& r) {
64  return r.region < regions;
65  }));
66  assert(std::all_of(transition_rates().begin(), transition_rates().end(),
67  [regions = reduce_index<Region>(model.populations.size())](auto&& r) {
68  return r.from < regions && r.to < regions;
69  }));
70  // initialize (internal) next event times by random values
71  for (size_t i = 0; i < m_tp_next_event.size(); i++) {
72  m_tp_next_event[i] += mio::ExponentialDistribution<FP>::get_instance()(m_model->get_rng(), 1.0);
73  }
74  }
75 
81  Eigen::Ref<Eigen::VectorX<FP>> advance(FP tmax)
82  {
84  size_t next_event = determine_next_event(); // index of the next event
85  FP current_time = m_result.get_last_time();
86  // set current time to add next time point in the future
87  FP last_result_time = current_time;
88  // iterate over time
89  while (current_time + m_waiting_times[next_event] < tmax) {
90  // If the next event happens further in the future than the next stored time point, add a new one.
91  if (current_time + m_waiting_times[next_event] >= last_result_time) {
92  auto num_dt = std::ceil((current_time + m_waiting_times[next_event] - last_result_time) / m_dt);
93  last_result_time = std::min(tmax, last_result_time + num_dt * m_dt);
94  m_result.add_time_point(last_result_time);
95  // copy from the previous last value
96  m_result.get_last_value() = m_result[m_result.get_num_time_points() - 2];
97  }
98  // update time
99  current_time += m_waiting_times[next_event];
100  // decide event type by index and perform it
101  if (next_event < adoption_rates().size()) {
102  // perform adoption event
103  const auto& rate = adoption_rates()[next_event];
104  m_result.get_last_value()[m_model->populations.get_flat_index({rate.region, rate.from})] -= 1;
105  m_model->populations[{rate.region, rate.from}] -= 1.0;
106  m_result.get_last_value()[m_model->populations.get_flat_index({rate.region, rate.to})] += 1;
107  m_model->populations[{rate.region, rate.to}] += 1.0;
108  }
109  else {
110  // perform transition event
111  const auto& rate = transition_rates()[next_event - adoption_rates().size()];
112  m_result.get_last_value()[m_model->populations.get_flat_index({rate.from, rate.status})] -= 1;
113  m_model->populations[{rate.from, rate.status}] -= 1.0;
114  m_result.get_last_value()[m_model->populations.get_flat_index({rate.to, rate.status})] += 1;
115  m_model->populations[{rate.to, rate.status}] += 1.0;
116  }
117  // update internal times
118  for (size_t i = 0; i < m_internal_time.size(); i++) {
120  }
121  // draw new "next event" time for the occured event
122  m_tp_next_event[next_event] += mio::ExponentialDistribution<FP>::get_instance()(m_model->get_rng(), 1.0);
123  // precalculate next event
125  next_event = determine_next_event();
126  }
127  // copy last result, if no event occurs between last_result_time and tmax
128  if (last_result_time < tmax) {
129  m_result.add_time_point(tmax);
130  m_result.get_last_value() = m_result[m_result.get_num_time_points() - 2];
131  // update internal times
132  for (size_t i = 0; i < m_internal_time.size(); i++) {
133  m_internal_time[i] += m_current_rates[i] * (tmax - current_time);
134  }
135  }
136  return m_result.get_last_value();
137  }
138 
144  {
145  return m_result;
146  }
147  const TimeSeries<FP>& get_result() const
148  {
149  return m_result;
150  }
151 
155  const Model& get_model() const
156  {
157  return *m_model;
158  }
160  {
161  return *m_model;
162  }
163 
164 private:
169  {
170  return m_model->parameters.template get<smm::TransitionRates<FP, Status, Region>>();
171  }
172 
177  {
178  return m_model->parameters.template get<smm::AdoptionRates<FP, Status, Region>>();
179  }
180 
185  {
186  size_t i = 0; // shared index for iterating both rates
187  const auto last_values = m_result.get_last_value();
188  for (const auto& rate : adoption_rates()) {
189  m_current_rates[i] = m_model->evaluate(rate, last_values);
193  i++;
194  }
195  for (const auto& rate : transition_rates()) {
196  m_current_rates[i] = m_model->evaluate(rate, last_values);
200  i++;
201  }
202  }
203 
207  inline size_t determine_next_event()
208  {
209  return std::distance(m_waiting_times.begin(), std::min_element(m_waiting_times.begin(), m_waiting_times.end()));
210  }
211 
212  FP m_dt;
213  std::unique_ptr<Model> m_model;
215 
216  std::vector<FP> m_internal_time;
217  std::vector<FP> m_tp_next_event;
218  std::vector<FP> m_waiting_times;
219  std::vector<FP> m_current_rates;
220 };
221 
222 } // namespace smm
223 } // namespace mio
224 
225 #endif
mio::Index< Tag > size() const
returns the size along the dimension provided as template parameter
Definition: custom_index_array.h:204
stores vectors of values at time points (or some other abstract variable) the value at each time poin...
Definition: time_series.h:58
Stochastic Metapopulation Model.
Definition: smm/model.h:56
A specialized Simulation for mio::smm::Model.
Definition: models/smm/simulation.h:41
mio::TimeSeries< FP > m_result
Result time series.
Definition: models/smm/simulation.h:214
std::vector< FP > m_internal_time
Internal times of all poisson processes (aka T_k).
Definition: models/smm/simulation.h:216
std::vector< FP > m_waiting_times
External times between m_internal_time and m_tp_next_event.
Definition: models/smm/simulation.h:218
constexpr const smm::TransitionRates< FP, Status, Region >::Type & transition_rates()
Returns the model's transition rates.
Definition: models/smm/simulation.h:168
Eigen::Ref< Eigen::VectorX< FP > > advance(FP tmax)
Advance simulation to tmax.
Definition: models/smm/simulation.h:81
Simulation(Model const &model, FP t0=0., FP dt=1.)
Set up the simulation for a Stochastic Metapopulation Model.
Definition: models/smm/simulation.h:51
Model & get_model()
Definition: models/smm/simulation.h:159
const TimeSeries< FP > & get_result() const
Definition: models/smm/simulation.h:147
FP m_dt
Initial step size.
Definition: models/smm/simulation.h:212
std::unique_ptr< Model > m_model
Pointer to the model used in the simulation.
Definition: models/smm/simulation.h:213
void update_current_rates_and_waiting_times()
Calculate current values for m_current_rates and m_waiting_times.
Definition: models/smm/simulation.h:184
const Model & get_model() const
Returns the model used in the simulation.
Definition: models/smm/simulation.h:155
constexpr const smm::AdoptionRates< FP, Status, Region >::Type & adoption_rates()
Returns the model's adoption rates.
Definition: models/smm/simulation.h:176
std::vector< FP > m_current_rates
Current values of both types of rates i.e. adoption and transition rates.
Definition: models/smm/simulation.h:219
TimeSeries< FP > & get_result()
Returns the final simulation result.
Definition: models/smm/simulation.h:143
std::vector< FP > m_tp_next_event
Internal time points of next event i after m_internal[i] (aka P_k).
Definition: models/smm/simulation.h:217
size_t determine_next_event()
Get next event i.e.
Definition: models/smm/simulation.h:207
static min_max_return_type< ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > >::type min(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &a, const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &b)
Definition: ad.hpp:2599
static min_max_return_type< ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > >::type max(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &a, const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &b)
Definition: ad.hpp:2596
static double ceil(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x)
Definition: ad.hpp:2449
int size(Comm comm)
Return the size of the given communicator.
Definition: miompi.cpp:75
A collection of classes to simplify handling of matrix shapes in meta programming.
Definition: models/abm/analyze_result.h:30
requires details::IsElementReference< M > RowMajorIterator< M, false > end(M &m)
create a non-const end iterator for the matrix m.
Definition: eigen_util.h:449
auto i
Definition: io.h:809
requires details::IsElementReference< M > RowMajorIterator< M, false > begin(M &m)
create a non-const iterator to first element of the matrix m.
Definition: eigen_util.h:421
Definition: io.h:94
Populations populations
Definition: compartmental_model.h:156
std::vector< AdoptionRate< FP, Status, Region > > Type
Definition: smm/parameters.h:42
std::vector< TransitionRate< FP, Status, Region > > Type
Definition: smm/parameters.h:71