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 next result time; system state is saved every dt time step
87  FP next_result_time = current_time + m_dt;
88  // iterate over time
89  while (current_time + m_waiting_times[next_event] < tmax) {
90  // update time
91  current_time += m_waiting_times[next_event];
92  // Save results until the next event time point
93  // do not save current time, as it does not yet include the next event
94  while (next_result_time < current_time) {
95  m_result.add_time_point(next_result_time);
96  m_result.get_last_value() = m_model->populations.get_compartments();
97  next_result_time += m_dt;
98  }
99  // decide event type by index and perform it
100  if (next_event < adoption_rates().size()) {
101  // perform adoption event
102  const auto& rate = adoption_rates()[next_event];
103  m_model->populations[{rate.region, rate.from}] -= 1.0;
104  m_model->populations[{rate.region, rate.to}] += 1.0;
105  }
106  else {
107  // perform transition event
108  const auto& rate = transition_rates()[next_event - adoption_rates().size()];
109  m_model->populations[{rate.from, rate.status}] -= 1.0;
110  m_model->populations[{rate.to, rate.status}] += 1.0;
111  }
112  // update internal times
113  for (size_t i = 0; i < m_internal_time.size(); i++) {
115  }
116  // draw new "next event" time for the occured event
117  m_tp_next_event[next_event] += mio::ExponentialDistribution<FP>::get_instance()(m_model->get_rng(), 1.0);
118  // precalculate next event
120  next_event = determine_next_event();
121  }
122  // copy last result, if no event occurs between last result time point and tmax
123  if (m_result.get_last_time() < tmax) {
124  while (next_result_time <= tmax) {
125  m_result.add_time_point(next_result_time);
126  m_result.get_last_value() = m_model->populations.get_compartments();
127  next_result_time += m_dt;
128  }
129  // update internal times
130  for (size_t i = 0; i < m_internal_time.size(); i++) {
131  m_internal_time[i] += m_current_rates[i] * (tmax - current_time);
132  }
133  }
134  return m_result.get_last_value();
135  }
136 
142  {
143  return m_result;
144  }
145  const TimeSeries<FP>& get_result() const
146  {
147  return m_result;
148  }
149 
153  const Model& get_model() const
154  {
155  return *m_model;
156  }
158  {
159  return *m_model;
160  }
161 
162 private:
167  {
168  return m_model->parameters.template get<smm::TransitionRates<FP, Status, Region>>();
169  }
170 
175  {
176  return m_model->parameters.template get<smm::AdoptionRates<FP, Status, Region>>();
177  }
178 
183  {
184  size_t i = 0; // shared index for iterating both rates
185  const auto last_values = m_model->populations.get_compartments();
186  for (const auto& rate : adoption_rates()) {
187  m_current_rates[i] = m_model->evaluate(rate, last_values);
191  i++;
192  }
193  for (const auto& rate : transition_rates()) {
194  m_current_rates[i] = m_model->evaluate(rate, last_values);
198  i++;
199  }
200  }
201 
205  inline size_t determine_next_event()
206  {
207  return std::distance(m_waiting_times.begin(), std::min_element(m_waiting_times.begin(), m_waiting_times.end()));
208  }
209 
210  FP m_dt;
211  std::unique_ptr<Model> m_model;
213 
214  std::vector<FP> m_internal_time;
215  std::vector<FP> m_tp_next_event;
216  std::vector<FP> m_waiting_times;
217  std::vector<FP> m_current_rates;
218 };
219 
220 } // namespace smm
221 } // namespace mio
222 
223 #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:212
std::vector< FP > m_internal_time
Internal times of all poisson processes (aka T_k).
Definition: models/smm/simulation.h:214
std::vector< FP > m_waiting_times
External times between m_internal_time and m_tp_next_event.
Definition: models/smm/simulation.h:216
constexpr const smm::TransitionRates< FP, Status, Region >::Type & transition_rates()
Returns the model's transition rates.
Definition: models/smm/simulation.h:166
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:157
const TimeSeries< FP > & get_result() const
Definition: models/smm/simulation.h:145
FP m_dt
Initial step size.
Definition: models/smm/simulation.h:210
std::unique_ptr< Model > m_model
Pointer to the model used in the simulation.
Definition: models/smm/simulation.h:211
void update_current_rates_and_waiting_times()
Calculate current values for m_current_rates and m_waiting_times.
Definition: models/smm/simulation.h:182
const Model & get_model() const
Returns the model used in the simulation.
Definition: models/smm/simulation.h:153
constexpr const smm::AdoptionRates< FP, Status, Region >::Type & adoption_rates()
Returns the model's adoption rates.
Definition: models/smm/simulation.h:174
std::vector< FP > m_current_rates
Current values of both types of rates i.e. adoption and transition rates.
Definition: models/smm/simulation.h:217
TimeSeries< FP > & get_result()
Returns the final simulation result.
Definition: models/smm/simulation.h:141
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:215
size_t determine_next_event()
Get next event i.e.
Definition: models/smm/simulation.h:205
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
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:810
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:95
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