dynamic_npis.h Source File

CPP API: dynamic_npis.h Source File
dynamic_npis.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: Martin J. Kuehn, Daniel Abele
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 MIO_EPI_DYNAMIC_LOCKDOWN_H
21 #define MIO_EPI_DYNAMIC_LOCKDOWN_H
22 
24 #include "memilio/utils/stl_util.h"
25 
26 namespace mio
27 {
28 
33 template <typename FP>
35 {
36 public:
42  void set_threshold(FP threshold, const std::vector<DampingSampling<FP>>& dampings)
43  {
44  insert_sorted_replace(m_thresholds, std::make_pair(threshold, dampings), [](auto& t1, auto& t2) {
45  return t1.first > t2.first;
46  });
47  }
48 
56  {
57  //thresholds are sorted by value descending, so upper_bound returns the first threshold that is smaller using binary search
58  auto iter_max_exceeded_threshold =
59  std::upper_bound(m_thresholds.begin(), m_thresholds.end(), value, [](auto& val, auto& t2) {
60  return val > t2.first;
61  });
62  return iter_max_exceeded_threshold;
63  }
64 
71  auto get_thresholds() const
72  {
73  return Range(m_thresholds);
74  }
76  {
77  return Range(m_thresholds);
78  }
86  {
87  return m_duration;
88  }
89 
95  {
96  m_duration = v;
97  }
98 
107  {
108  return m_interval;
109  }
114  {
115  m_interval = interval;
116  }
128  FP get_base_value() const
129  {
130  return m_base;
131  }
135  void set_base_value(FP v)
136  {
137  m_base = v;
138  }
144  void draw_sample()
145  {
146  for (auto&& t : m_thresholds) {
147  for (auto&& d : t.second) {
148  d.draw_sample();
149  }
150  }
151  }
152 
157  template <class IOContext>
158  void serialize(IOContext& io) const
159  {
160  auto obj = io.create_object("DynamicNPIs");
161  obj.add_list("Thresholds", get_thresholds().begin(), get_thresholds().end());
162  obj.add_element("Duration", get_duration());
163  obj.add_element("Interval", get_interval());
164  obj.add_element("BaseValue", get_base_value());
165  }
166 
171  template <class IOContext>
172  static IOResult<DynamicNPIs> deserialize(IOContext& io)
173  {
174  auto obj = io.expect_object("DynamicNPIs");
175  auto t = obj.expect_list("Thresholds", Tag<std::pair<FP, std::vector<DampingSampling<FP>>>>{});
176  auto d = obj.expect_element("Duration", Tag<SimulationTime<FP>>{});
177  auto i = obj.expect_element("Interval", Tag<SimulationTime<FP>>{});
178  auto b = obj.expect_element("BaseValue", Tag<FP>{});
179  return apply(
180  io,
181  [](auto&& t_, auto&& d_, auto&& i_, auto&& b_) {
182  auto npis = DynamicNPIs();
183  npis.set_duration(d_);
184  npis.set_interval(i_);
185  npis.set_base_value(b_);
186  for (auto&& e : t_) {
187  npis.set_threshold(e.first, e.second);
188  }
189  return npis;
190  },
191  t, d, i, b);
192  }
193 
194 private:
195  std::vector<std::pair<FP, std::vector<DampingSampling<FP>>>> m_thresholds;
198  FP m_base{1.0};
199 };
200 
213 template <typename FP, class DampingExpr>
214 std::vector<size_t> get_damping_indices(const DampingExpr& damping_expr, DampingLevel lvl, DampingType type,
216 {
217  std::vector<size_t> indices;
218  for (size_t i = 0; i < damping_expr.get_dampings().size(); ++i) {
219  const auto d = damping_expr.get_dampings()[i];
220  if (d.get_level() == lvl && d.get_type() == type && d.get_time() > begin && d.get_time() < end) {
221  indices.push_back(i);
222  }
223  }
224  return indices;
225 }
226 
238 template <typename FP, class DampingExpr>
239 Eigen::Ref<const typename DampingExpr::Matrix> get_active_damping(const DampingExpr& damping_expr, DampingLevel lvl,
240  DampingType type, SimulationTime<FP> t)
241 {
242  auto ub =
243  std::find_if(damping_expr.get_dampings().rbegin(), damping_expr.get_dampings().rend(), [lvl, type, t](auto& d) {
244  return d.get_level() == lvl && d.get_type() == type && d.get_time() <= t;
245  });
246  if (ub != damping_expr.get_dampings().rend()) {
247  return ub->get_coeffs();
248  }
249  return DampingExpr::Matrix::Zero(damping_expr.get_shape().rows(), damping_expr.get_shape().cols());
250 }
251 
278 template <typename FP, class DampingExprGroup, class MakeMatrix>
279 void implement_dynamic_npis(DampingExprGroup& damping_expr_group, const std::vector<DampingSampling<FP>>& npis,
280  SimulationTime<FP> begin, SimulationTime<FP> end, MakeMatrix&& make_matrix)
281 {
282  for (auto& npi : npis) {
283  for (auto& mat_idx : npi.get_matrix_indices()) {
284  auto type = npi.get_type();
285  auto level = npi.get_level();
286  auto& damping_expr = damping_expr_group[mat_idx];
287 
288  auto active = get_active_damping<FP>(damping_expr, level, type, begin);
289  auto active_end = get_active_damping<FP>(damping_expr, level, type, end)
290  .eval(); //copy because it may be removed or changed
291  auto value = make_matrix(npi.get_value().value() * npi.get_group_weights());
292 
293  auto npi_implemented = false;
294 
295  //add begin of npi if not already bigger
296  if ((active.array() < value.array()).any()) {
297  damping_expr.add_damping(max(value, active), level, type, begin);
298  npi_implemented = true;
299  }
300 
301  //replace dampings during the new npi
302  auto damping_indices = get_damping_indices<FP>(damping_expr, level, type, begin, end);
303  for (auto& i : damping_indices) {
304  auto& d = damping_expr.get_dampings()[i];
305  damping_expr.add_damping(max(d.get_coeffs(), value), level, type, d.get_time());
306  npi_implemented = true;
307  }
308 
309  //add end of npi to restore active dampings if any change was made
310  if (npi_implemented) {
311  damping_expr.add_damping(active_end, level, type, end);
312  }
313  }
314  }
315 
316  //remove duplicates that accumulated because of dampings that become active during the time span
317  //a damping is obsolete if the most recent damping of the same type and level has the same value
318  for (auto& damping_expr : damping_expr_group) {
319  //go from the back so indices aren't invalidated when dampings are removed
320  //use indices to loop instead of reverse iterators because removing invalidates the current iterator
321  for (auto i = int(0); i < int(damping_expr.get_dampings().size()) - 1; ++i) {
322  auto it = damping_expr.get_dampings().rbegin() + i;
323 
324  //look for previous damping of the same type/level
325  auto it_prev = std::find_if(it + 1, damping_expr.get_dampings().rend(), [&di = *it](auto& dj) {
326  return di.get_level() == dj.get_level() && di.get_type() == dj.get_type();
327  });
328 
329  //remove if match is found and has same value
330  if (it_prev != damping_expr.get_dampings().rend() && it->get_coeffs() == it_prev->get_coeffs()) {
331  damping_expr.remove_damping(damping_expr.get_dampings().size() - 1 - i);
332  }
333  }
334  }
335 }
336 
337 } // namespace mio
338 
339 #endif // MIO_EPI_DYNAMIC_LOCKDOWN_H
randomly sample dampings for e.g.
Definition: damping_sampling.h:38
represents non-pharmaceutical interventions (NPI) that are activated during the simulation if some va...
Definition: dynamic_npis.h:35
void draw_sample()
draw a random sample from the damping distributions
Definition: dynamic_npis.h:144
static IOResult< DynamicNPIs > deserialize(IOContext &io)
deserialize an object of this class.
Definition: dynamic_npis.h:172
FP get_base_value() const
Get/Set the base value of the thresholds.
Definition: dynamic_npis.h:128
SimulationTime< FP > get_duration() const
get the duration of the NPIs.
Definition: dynamic_npis.h:85
void set_threshold(FP threshold, const std::vector< DampingSampling< FP >> &dampings)
set a threshold and the NPIs that should be enacted.
Definition: dynamic_npis.h:42
auto get_max_exceeded_threshold(FP value)
find the highest threshold that is smaller than the value.
Definition: dynamic_npis.h:55
void serialize(IOContext &io) const
serialize this.
Definition: dynamic_npis.h:158
SimulationTime< FP > m_interval
Definition: dynamic_npis.h:197
void set_duration(SimulationTime< FP > v)
set the duration of the NPIs.
Definition: dynamic_npis.h:94
SimulationTime< FP > m_duration
Definition: dynamic_npis.h:196
std::vector< std::pair< FP, std::vector< DampingSampling< FP > > > > m_thresholds
Definition: dynamic_npis.h:195
auto get_thresholds()
range of pairs of threshold values and NPIs.
Definition: dynamic_npis.h:75
auto get_thresholds() const
range of pairs of threshold values and NPIs.
Definition: dynamic_npis.h:71
FP m_base
Definition: dynamic_npis.h:198
void set_base_value(FP v)
Definition: dynamic_npis.h:135
void set_interval(SimulationTime< FP > interval)
Definition: dynamic_npis.h:113
SimulationTime< FP > get_interval() const
Get/Set the interval at which the NPIs are checked.
Definition: dynamic_npis.h:106
double simulation time.
Definition: damping.h:58
trait_value< T >::RETURN_TYPE & value(T &x)
Definition: ad.hpp:3308
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
Range(std::pair< I, S > iterator_pair) -> Range< I, S >
Deduction guide to correctly deduce range type when constructed from a pair.
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
std::vector< size_t > get_damping_indices(const DampingExpr &damping_expr, DampingLevel lvl, DampingType type, SimulationTime< FP > begin, SimulationTime< FP > end)
Get a list of indices of specified dampings.
Definition: dynamic_npis.h:214
void implement_dynamic_npis(DampingExprGroup &damping_expr_group, const std::vector< DampingSampling< FP >> &npis, SimulationTime< FP > begin, SimulationTime< FP > end, MakeMatrix &&make_matrix)
implement dynamic NPIs for a time span.
Definition: dynamic_npis.h:279
auto max(const Eigen::MatrixBase< A > &a, B &&b)
coefficient wise maximum of two matrices.
Definition: eigen_util.h:171
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
Eigen::Ref< const typename DampingExpr::Matrix > get_active_damping(const DampingExpr &damping_expr, DampingLevel lvl, DampingType type, SimulationTime< FP > t)
Get the value of the damping that matches the given type and level and that is active at the specifie...
Definition: dynamic_npis.h:239
boost::outcome_v2::unchecked< T, IOStatus > IOResult
Value-or-error type for operations that return a value but can fail.
Definition: io.h:353
void insert_sorted_replace(std::vector< T > &vec, T const &item, Pred pred)
inserts element in a sorted vector, replacing items that are equal precondition: elements in the vect...
Definition: stl_util.h:66