damping.h Source File

CPP API: damping.h Source File
damping.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 DAMPING_H
21 #define DAMPING_H
22 
23 #include "memilio/config.h" // IWYU pragma: keep
24 #include "memilio/math/eigen.h" // IWYU pragma: keep
27 #include "memilio/utils/stl_util.h"
29 #include "memilio/math/smoother.h"
31 
32 #include <tuple>
33 #include <vector>
34 #include <algorithm>
35 #include <ostream>
36 
37 namespace mio
38 {
39 
49 DECL_TYPESAFE(int, DampingLevel);
50 
60 DECL_TYPESAFE(int, DampingType);
61 
73 template <typename FP>
74 class MEMILIO_ENABLE_EBO SimulationTime : public TypeSafe<FP, SimulationTime<FP>>,
75  public OperatorAdditionSubtraction<SimulationTime<FP>>,
76  public OperatorScalarMultiplicationDivision<SimulationTime<FP>, FP>,
77  public OperatorComparison<SimulationTime<FP>>
78 {
79 public:
81 };
82 
90 template <typename FP, class S>
91 class Damping : public std::tuple<typename S::Matrix, DampingLevel, DampingType, SimulationTime<FP>>
92 {
93 public:
94  using Shape = S;
95  using Matrix = typename Shape::Matrix;
96  using Base = std::tuple<Matrix, DampingLevel, DampingType, SimulationTime<FP>>;
97 
103  template <class... T>
104  requires std::is_constructible_v<Shape, T...>
105  explicit Damping(T... shape_args)
106  : Base(Matrix::Zero(Shape(shape_args...).rows(), Shape(shape_args...).cols()), {}, {}, {})
107  {
108  }
109 
118  template <class ME>
119  Damping(const Eigen::MatrixBase<ME>& m, DampingLevel level, DampingType type, SimulationTime<FP> t)
120  : Base(m, level, type, t)
121  {
122  assert((get_coeffs().array() <= 1.).all() && "damping coefficient out of range");
123  }
124 
134  template <class... T>
135  requires std::is_constructible_v<Shape, T...>
136  Damping(FP d, DampingLevel level, DampingType type, SimulationTime<FP> t, T... shape_args)
137  : Damping(Matrix::Constant(Shape(shape_args...).rows(), Shape(shape_args...).cols(), d), level, type, t)
138  {
139  }
140 
147  template <class ME>
148  Damping(const Eigen::MatrixBase<ME>& m, SimulationTime<FP> t)
149  : Damping(m, DampingLevel(0), DampingType(0), t)
150  {
151  }
152 
160  template <class... T>
161  requires std::is_constructible_v<Shape, T...>
162  Damping(FP d, SimulationTime<FP> t, T... shape_args)
163  : Damping(d, DampingLevel(0), DampingType(0), t, shape_args...)
164  {
165  }
166 
171  {
172  return std::get<SimulationTime<FP>>(*this);
173  }
175  {
176  return std::get<SimulationTime<FP>>(*this);
177  }
178 
182  DampingLevel& get_level()
183  {
184  return std::get<DampingLevel>(*this);
185  }
186  const DampingLevel& get_level() const
187  {
188  return std::get<DampingLevel>(*this);
189  }
190 
194  DampingType& get_type()
195  {
196  return std::get<DampingType>(*this);
197  }
198  const DampingType& get_type() const
199  {
200  return std::get<DampingType>(*this);
201  }
202 
206  const Matrix& get_coeffs() const
207  {
208  return std::get<Matrix>(*this);
209  }
211  {
212  return std::get<Matrix>(*this);
213  }
214 
218  Shape get_shape() const
219  {
220  return Shape::get_shape_of(get_coeffs());
221  }
222 
226  friend void PrintTo(const Damping& self, std::ostream* os)
227  {
228  *os << '[' << std::get<SimulationTime<FP>>(self) << ',' << std::get<DampingType>(self) << ','
229  << std::get<DampingLevel>(self) << ']';
230  *os << '\n' << std::get<Matrix>(self);
231  }
232 
237  template <class IOContext>
238  void serialize(IOContext& io) const
239  {
240  auto obj = io.create_object("Damping");
241  obj.add_element("Time", get_time());
242  obj.add_element("Type", get_type());
243  obj.add_element("Level", get_level());
244  obj.add_element("Coeffs", get_coeffs());
245  }
246 
251  template <class IOContext>
252  static IOResult<Damping> deserialize(IOContext& io)
253  {
254  auto obj = io.expect_object("Damping");
255  auto ti = obj.expect_element("Time", Tag<SimulationTime<FP>>{});
256  auto ty = obj.expect_element("Type", Tag<DampingType>{});
257  auto l = obj.expect_element("Level", Tag<DampingLevel>{});
258  auto c = obj.expect_element("Coeffs", Tag<Matrix>{});
259  return apply(
260  io,
261  [](auto&& ti_, auto&& ty_, auto&& l_, auto&& c_) {
262  return Damping(c_, l_, ty_, ti_);
263  },
264  ti, ty, l, c);
265  }
266 };
267 
275 template <typename FP, class D>
276 class Dampings
277 {
278 public:
279  using Shape = typename D::Shape;
280  using Matrix = typename Shape::Matrix;
281  using value_type = D;
283  using const_reference = const value_type&;
284  using iterator = typename std::vector<value_type>::iterator;
285  using const_iterator = typename std::vector<value_type>::const_iterator;
286 
293  template <class... T>
294  requires std::is_constructible_v<Shape, T...>
295  explicit Dampings(T... shape_args)
296  : m_dampings()
297  , m_shape(shape_args...)
298  {
299  update_cache();
300  }
301 
306  Dampings(std::initializer_list<value_type> il)
307  : m_dampings(il)
308  {
309  assert(il.size() > 0);
310  m_shape = il.begin()->get_shape();
311  update_cache();
312  }
313 
318  void add(const value_type& damping)
319  {
320  add_(damping);
321  }
322  template <class... T>
323  void add(T&&... t)
324  {
325  add_(value_type(std::forward<T>(t)...));
326  }
327  template <class... T>
328  void add(FP d, T... t)
329  {
330  add_(value_type(d, std::forward<T>(t)..., m_shape));
331  }
332 
336  void remove(size_t i)
337  {
338  assert(m_dampings.size() > i);
339  m_dampings.erase(m_dampings.begin() + i);
341  }
342 
346  void clear()
347  {
348  m_dampings.clear();
351  }
352 
362  {
365  }
366 
382  {
383  assert(!m_accumulated_dampings_cached.empty() &&
384  "Cache is not current. Did you disable the automatic cache update?");
385 
386  auto ub = std::upper_bound(m_accumulated_dampings_cached.begin(), m_accumulated_dampings_cached.end(),
387  std::make_tuple(t), [](auto&& tup1, auto&& tup2) {
388  return std::get<SimulationTime<FP>>(tup1) < std::get<SimulationTime<FP>>(tup2);
389  });
390 
391  auto damping = smoother_cosine<FP>(
392  t.get(), (std::get<SimulationTime<FP>>(*ub) - mio::SimulationTime<FP>(1.0)).get(),
393  std::get<SimulationTime<FP>>(*ub).get(), std::get<Matrix>(*(ub - 1)), std::get<Matrix>(*ub));
394 
395  return damping;
396  }
397 
402  {
403  return m_dampings[i];
404  }
406  {
407  return m_dampings[i];
408  }
409 
413  bool operator==(const Dampings& other) const
414  {
415  return m_dampings == other.m_dampings;
416  }
417  bool operator!=(const Dampings& other) const
418  {
419  return !(*this == other);
420  }
421 
425  size_t get_num_dampings() const
426  {
427  return m_dampings.size();
428  }
429 
433  Shape get_shape() const
434  {
435  return m_shape;
436  }
437 
442  {
443  return m_dampings.begin();
444  }
446  {
447  return m_dampings.end();
448  }
450  {
451  return m_dampings.begin();
452  }
454  {
455  return m_dampings.end();
456  }
457 
461  friend void PrintTo(const Dampings& self, std::ostream* os)
462  {
463  for (auto& d : self.m_dampings) {
464  *os << '\n'
465  << '[' << std::get<SimulationTime<FP>>(d) << ',' << std::get<DampingType>(d) << ','
466  << std::get<DampingLevel>(d) << ']';
467  *os << '\n' << std::get<Matrix>(d);
468  }
469  }
470 
475  template <class IOContext>
476  void serialize(IOContext& io) const
477  {
478  auto obj = io.create_object("Dampings");
479  obj.add_element("Shape", get_shape());
480  obj.add_list("Dampings", begin(), end());
481  }
482 
487  template <class IOContext>
488  static IOResult<Dampings> deserialize(IOContext& io)
489  {
490  auto obj = io.expect_object("Dampings");
491  auto s = obj.expect_element("Shape", Tag<Shape>{});
492  auto d = obj.expect_list("Dampings", Tag<value_type>{});
493  return apply(
494  io,
495  [](auto&& s_, auto&& d_) -> IOResult<Dampings> {
496  Dampings dampings(s_);
497  for (auto&& i : d_) {
498  if (i.get_shape() != s_) {
499  return failure(StatusCode::InvalidValue, "Dampings must all have the same shape.");
500  }
501  dampings.add(i);
502  }
503  return success(dampings);
504  },
505  s, d);
506  }
507 
508 private:
512  void add_(const value_type& damping);
513 
519  void update_cache();
520 
526  {
528  update_cache();
529  }
530  }
531 
536  static void update_active_dampings(
537  const value_type& damping,
538  std::vector<std::tuple<std::reference_wrapper<const Matrix>, DampingLevel, DampingType>>& active_by_type,
539  std::vector<std::tuple<Matrix, DampingLevel>>& sum_by_level);
540 
545  template <class Iter>
546  static void inclusive_exclusive_sum_rec(Iter b, Iter e, Matrix& sum)
547  {
548  if (b != e) {
549  auto& mat_b = std::get<Matrix>(*b);
550  auto mat_prod = (sum.array() * mat_b.array()).matrix();
551  sum = sum + mat_b - mat_prod;
552  inclusive_exclusive_sum_rec(++b, e, sum);
553  }
554  }
555  template <class Tuple>
556  static Matrix inclusive_exclusive_sum(const std::vector<Tuple>& v)
557  {
558  assert(!v.empty());
559  Matrix sum = std::get<Matrix>(v.front());
560  inclusive_exclusive_sum_rec(v.begin() + 1, v.end(), sum);
561  return sum;
562  }
563 
564  std::vector<value_type> m_dampings;
566  std::vector<std::tuple<Matrix, SimulationTime<FP>>> m_accumulated_dampings_cached;
568 };
569 
570 template <typename FP, class D>
572 {
573  using std::get;
574 
575  if (m_accumulated_dampings_cached.empty()) {
576  m_accumulated_dampings_cached.emplace_back(Matrix::Zero(m_shape.rows(), m_shape.cols()),
577  SimulationTime<FP>(std::numeric_limits<FP>::lowest()));
578 
579  std::vector<std::tuple<std::reference_wrapper<const Matrix>, DampingLevel, DampingType>> active_by_type;
580  std::vector<std::tuple<Matrix, DampingLevel>> sum_by_level;
581  for (auto& damping : m_dampings) {
582  //update active damping
583  update_active_dampings(damping, active_by_type, sum_by_level);
584  auto combined_damping = inclusive_exclusive_sum(sum_by_level);
585  assert((combined_damping.array() <= FP(1.0)).all() &&
586  "unexpected error, accumulated damping out of range.");
587  if (floating_point_equal<FP>(get<SimulationTime<FP>>(damping).get(),
588  get<SimulationTime<FP>>(m_accumulated_dampings_cached.back()).get(), 1e-15,
589  1e-15)) {
590  get<Matrix>(m_accumulated_dampings_cached.back()) = combined_damping;
591  }
592  else {
593  m_accumulated_dampings_cached.emplace_back(combined_damping, get<SimulationTime<FP>>(damping));
594  }
595  }
596 
597  m_accumulated_dampings_cached.emplace_back(get<Matrix>(m_accumulated_dampings_cached.back()),
599  }
600 }
601 
602 template <typename FP, class D>
603 void Dampings<FP, D>::add_(const value_type& damping)
604 {
605  assert(damping.get_shape() == m_shape && "Inconsistent matrix shape.");
606  insert_sorted_replace<value_type>(m_dampings, damping, [](auto& tup1, auto& tup2) {
607  return std::make_tuple(tup1.get_time(), int(tup1.get_type()), int(tup1.get_level())) <
608  std::make_tuple(tup2.get_time(), int(tup2.get_type()), int(tup2.get_level()));
609  });
610  m_accumulated_dampings_cached.clear();
611  if (m_automatic_cache_update) {
612  update_cache();
613  }
614 }
615 
616 template <typename FP, class S>
618  const value_type& damping,
619  std::vector<std::tuple<std::reference_wrapper<const Matrix>, DampingLevel, DampingType>>& active_by_type,
620  std::vector<std::tuple<Matrix, DampingLevel>>& sum_by_level)
621 {
622  using std::get;
623 
624  const int MatrixIdx = 0;
625 
626  //find active with same type and level if existent
627  auto iter_active_same_type = std::find_if(active_by_type.begin(), active_by_type.end(), [&damping](auto& active) {
628  return get<DampingLevel>(active) == get<DampingLevel>(damping) &&
629  get<DampingType>(active) == get<DampingType>(damping);
630  });
631  if (iter_active_same_type != active_by_type.end()) {
632  //replace active of the same type and level
633  auto& active_same_type = *iter_active_same_type;
634  //find active with the same level
635  auto& sum_same_level = *std::find_if(sum_by_level.begin(), sum_by_level.end(), [&damping](auto& sum) {
636  return get<DampingLevel>(sum) == get<DampingLevel>(damping);
637  });
638  //remove active with the same type and level and add new one
639  get<MatrixIdx>(sum_same_level) += get<MatrixIdx>(damping) - get<MatrixIdx>(active_same_type).get();
640  get<MatrixIdx>(active_same_type) = get<MatrixIdx>(damping);
641  }
642  else {
643  //add new type to active
644  active_by_type.emplace_back(get<MatrixIdx>(damping), get<DampingLevel>(damping), get<DampingType>(damping));
645  //find damping with same level if existent
646  auto iter_sum_same_level = std::find_if(sum_by_level.begin(), sum_by_level.end(), [&damping](auto& sum) {
647  return get<DampingLevel>(sum) == get<DampingLevel>(damping);
648  });
649  if (iter_sum_same_level != sum_by_level.end()) {
650  //add to existing level
651  get<MatrixIdx>(*iter_sum_same_level) += get<MatrixIdx>(damping);
652  }
653  else {
654  //add new level
655  sum_by_level.emplace_back(get<MatrixIdx>(damping), get<DampingLevel>(damping));
656  }
657  }
658 }
659 
663 template <typename FP>
665 template <typename FP>
667 template <typename FP>
669 template <typename FP>
671 
672 } // namespace mio
673 
674 #endif // DAMPING_H
represent interventions or effects that affect contact frequencies between multiple groups.
Definition: damping.h:92
DampingType & get_type()
the type of this damping.
Definition: damping.h:194
void serialize(IOContext &io) const
serialize this.
Definition: damping.h:238
requires std::is_constructible_v< Shape, T... > Damping(T... shape_args)
create a default Damping.
Definition: damping.h:105
requires std::is_constructible_v< Shape, T... > Damping(FP d, SimulationTime< FP > t, T... shape_args)
create a Damping with constant coefficients and zero level and type.
Definition: damping.h:162
const DampingLevel & get_level() const
Definition: damping.h:186
static IOResult< Damping > deserialize(IOContext &io)
deserialize an object of this class.
Definition: damping.h:252
Damping(const Eigen::MatrixBase< ME > &m, DampingLevel level, DampingType type, SimulationTime< FP > t)
create a Damping.
Definition: damping.h:119
const SimulationTime< FP > & get_time() const
Definition: damping.h:174
typename Shape::Matrix Matrix
Definition: damping.h:95
Shape get_shape() const
shape of the damping matrix.
Definition: damping.h:218
Matrix & get_coeffs()
Definition: damping.h:210
const Matrix & get_coeffs() const
the coefficients of this damping.
Definition: damping.h:206
DampingLevel & get_level()
the level of this damping.
Definition: damping.h:182
friend void PrintTo(const Damping &self, std::ostream *os)
GTest printer.
Definition: damping.h:226
S Shape
Definition: damping.h:94
requires std::is_constructible_v< Shape, T... > Damping(FP d, DampingLevel level, DampingType type, SimulationTime< FP > t, T... shape_args)
create a Damping with constant coefficients.
Definition: damping.h:136
const DampingType & get_type() const
Definition: damping.h:198
SimulationTime< FP > & get_time()
the time this damping becomes active.
Definition: damping.h:170
std::tuple< Matrix, DampingLevel, DampingType, SimulationTime< FP > > Base
Definition: damping.h:96
Damping(const Eigen::MatrixBase< ME > &m, SimulationTime< FP > t)
create a Damping at level and type zero
Definition: damping.h:148
collection of dampings at different time points.
Definition: damping.h:277
const_iterator end() const
Definition: damping.h:453
D value_type
Definition: damping.h:281
reference operator[](size_t i)
access one damping in this collection.
Definition: damping.h:401
bool operator!=(const Dampings &other) const
Definition: damping.h:417
iterator end()
Definition: damping.h:445
void add(const value_type &damping)
add a damping.
Definition: damping.h:318
friend void PrintTo(const Dampings &self, std::ostream *os)
GTest printer.
Definition: damping.h:461
size_t get_num_dampings() const
get the number of matrices.
Definition: damping.h:425
std::vector< value_type > m_dampings
Definition: damping.h:564
bool operator==(const Dampings &other) const
equality operators.
Definition: damping.h:413
const value_type & const_reference
Definition: damping.h:283
Dampings(std::initializer_list< value_type > il)
create damping collection.
Definition: damping.h:306
value_type & reference
Definition: damping.h:282
const_iterator begin() const
Definition: damping.h:449
auto get_matrix_at(SimulationTime< FP > t) const
Computes the real contact frequency at a point in time.
Definition: damping.h:381
std::vector< std::tuple< Matrix, SimulationTime< FP > > > m_accumulated_dampings_cached
Definition: damping.h:566
void add(T &&... t)
Definition: damping.h:323
void set_automatic_cache_update(bool b)
Disable the internal cache to speed up multiple modifications in a row.
Definition: damping.h:361
typename std::vector< value_type >::iterator iterator
Definition: damping.h:284
void remove(size_t i)
remove the damping at index i.
Definition: damping.h:336
typename std::vector< value_type >::const_iterator const_iterator
Definition: damping.h:285
static IOResult< Dampings > deserialize(IOContext &io)
deserialize an object of this class.
Definition: damping.h:488
Shape m_shape
Definition: damping.h:565
void automatic_cache_update()
updates the cache if automatic cache updates are enabled.
Definition: damping.h:525
typename Shape::Matrix Matrix
Definition: damping.h:280
static void update_active_dampings(const value_type &damping, std::vector< std::tuple< std::reference_wrapper< const Matrix >, DampingLevel, DampingType >> &active_by_type, std::vector< std::tuple< Matrix, DampingLevel >> &sum_by_level)
replace matrices of the same type, sum up matrices on the same level.
Definition: damping.h:617
iterator begin()
STL iterators over matrices.
Definition: damping.h:441
static void inclusive_exclusive_sum_rec(Iter b, Iter e, Matrix &sum)
e.g.
Definition: damping.h:546
const_reference operator[](size_t i) const
Definition: damping.h:405
void update_cache()
compute the cache of accumulated dampings.
Definition: damping.h:571
bool m_automatic_cache_update
Definition: damping.h:567
static Matrix inclusive_exclusive_sum(const std::vector< Tuple > &v)
Definition: damping.h:556
requires std::is_constructible_v< Shape, T... > Dampings(T... shape_args)
create damping collection.
Definition: damping.h:295
void add_(const value_type &damping)
internal add.
Definition: damping.h:603
Shape get_shape() const
dimensions of the damping matrix.
Definition: damping.h:433
void clear()
remove all dampings.
Definition: damping.h:346
typename D::Shape Shape
Definition: damping.h:279
void add(FP d, T... t)
Definition: damping.h:328
void serialize(IOContext &io) const
serialize this.
Definition: damping.h:476
base class to add default operator +, +=, -, -= to a class derived from TypeSafe.
Definition: type_safe.h:175
base class to add operator <, <=, >, >= to a class derived from TypeSafe.
Definition: type_safe.h:228
base class to add operator *, *=, /, /= with a scalar to a class derived from TypeSafe.
Definition: type_safe.h:202
Typesafe wrapper for a floating-point simulation time value (in days).
Definition: damping.h:78
Typesafe wrapper around any type to make function arguments, tuple elements, etc.
Definition: type_safe.h:59
T get() const
Returns the underlying value.
Definition: type_safe.h:89
#define MEMILIO_ENABLE_EBO
Definition: compiler_diagnostics.h:75
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
A collection of classes to simplify handling of matrix shapes in meta programming.
Definition: models/abm/analyze_result.h:30
auto failure(const IOStatus &s)
Create an object that is implicitly convertible to an error IOResult<T>.
Definition: io.h:381
boost::outcome_v2::in_place_type_t< T > Tag
Type that is used for overload resolution.
Definition: io.h:408
auto i
Definition: io.h:810
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:482
requires(!std::is_trivial_v< T >) void BinarySerializerObject
Definition: binary_serializer.h:333
auto success()
Create an object that is implicitly convertible to a succesful IOResult<void>.
Definition: io.h:360
DECL_TYPESAFE(int, DampingLevel)
Typesafe integer representing the level of a damping.
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:304
boost::outcome_v2::unchecked< T, IOStatus > IOResult
Value-or-error type for operations that return a value but can fail.
Definition: io.h:354