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 
43 DECL_TYPESAFE(int, DampingLevel);
44 
48 DECL_TYPESAFE(int, DampingType);
49 
53 template <typename FP>
54 class MEMILIO_ENABLE_EBO SimulationTime : public TypeSafe<FP, SimulationTime<FP>>,
55  public OperatorAdditionSubtraction<SimulationTime<FP>>,
56  public OperatorScalarMultiplicationDivision<SimulationTime<FP>, FP>,
57  public OperatorComparison<SimulationTime<FP>>
58 {
59 public:
61 };
62 
70 template <typename FP, class S>
71 class Damping : public std::tuple<typename S::Matrix, DampingLevel, DampingType, SimulationTime<FP>>
72 {
73 public:
74  using Shape = S;
75  using Matrix = typename Shape::Matrix;
76  using Base = std::tuple<Matrix, DampingLevel, DampingType, SimulationTime<FP>>;
77 
83  template <class... T>
84  requires std::is_constructible_v<Shape, T...>
85  explicit Damping(T... shape_args)
86  : Base(Matrix::Zero(Shape(shape_args...).rows(), Shape(shape_args...).cols()), {}, {}, {})
87  {
88  }
89 
98  template <class ME>
99  Damping(const Eigen::MatrixBase<ME>& m, DampingLevel level, DampingType type, SimulationTime<FP> t)
100  : Base(m, level, type, t)
101  {
102  assert((get_coeffs().array() <= 1.).all() && "damping coefficient out of range");
103  }
104 
114  template <class... T>
115  requires std::is_constructible_v<Shape, T...>
116  Damping(FP d, DampingLevel level, DampingType type, SimulationTime<FP> t, T... shape_args)
117  : Damping(Matrix::Constant(Shape(shape_args...).rows(), Shape(shape_args...).cols(), d), level, type, t)
118  {
119  }
120 
127  template <class ME>
128  Damping(const Eigen::MatrixBase<ME>& m, SimulationTime<FP> t)
129  : Damping(m, DampingLevel(0), DampingType(0), t)
130  {
131  }
132 
140  template <class... T>
141  requires std::is_constructible_v<Shape, T...>
142  Damping(FP d, SimulationTime<FP> t, T... shape_args)
143  : Damping(d, DampingLevel(0), DampingType(0), t, shape_args...)
144  {
145  }
146 
151  {
152  return std::get<SimulationTime<FP>>(*this);
153  }
155  {
156  return std::get<SimulationTime<FP>>(*this);
157  }
158 
162  DampingLevel& get_level()
163  {
164  return std::get<DampingLevel>(*this);
165  }
166  const DampingLevel& get_level() const
167  {
168  return std::get<DampingLevel>(*this);
169  }
170 
174  DampingType& get_type()
175  {
176  return std::get<DampingType>(*this);
177  }
178  const DampingType& get_type() const
179  {
180  return std::get<DampingType>(*this);
181  }
182 
186  const Matrix& get_coeffs() const
187  {
188  return std::get<Matrix>(*this);
189  }
191  {
192  return std::get<Matrix>(*this);
193  }
194 
198  Shape get_shape() const
199  {
200  return Shape::get_shape_of(get_coeffs());
201  }
202 
206  friend void PrintTo(const Damping& self, std::ostream* os)
207  {
208  *os << '[' << std::get<SimulationTime<FP>>(self) << ',' << std::get<DampingType>(self) << ','
209  << std::get<DampingLevel>(self) << ']';
210  *os << '\n' << std::get<Matrix>(self);
211  }
212 
217  template <class IOContext>
218  void serialize(IOContext& io) const
219  {
220  auto obj = io.create_object("Damping");
221  obj.add_element("Time", get_time());
222  obj.add_element("Type", get_type());
223  obj.add_element("Level", get_level());
224  obj.add_element("Coeffs", get_coeffs());
225  }
226 
231  template <class IOContext>
232  static IOResult<Damping> deserialize(IOContext& io)
233  {
234  auto obj = io.expect_object("Damping");
235  auto ti = obj.expect_element("Time", Tag<SimulationTime<FP>>{});
236  auto ty = obj.expect_element("Type", Tag<DampingType>{});
237  auto l = obj.expect_element("Level", Tag<DampingLevel>{});
238  auto c = obj.expect_element("Coeffs", Tag<Matrix>{});
239  return apply(
240  io,
241  [](auto&& ti_, auto&& ty_, auto&& l_, auto&& c_) {
242  return Damping(c_, l_, ty_, ti_);
243  },
244  ti, ty, l, c);
245  }
246 };
247 
255 template <typename FP, class D>
256 class Dampings
257 {
258 public:
259  using Shape = typename D::Shape;
260  using Matrix = typename Shape::Matrix;
261  using value_type = D;
263  using const_reference = const value_type&;
264  using iterator = typename std::vector<value_type>::iterator;
265  using const_iterator = typename std::vector<value_type>::const_iterator;
266 
273  template <class... T>
274  requires std::is_constructible_v<Shape, T...>
275  explicit Dampings(T... shape_args)
276  : m_dampings()
277  , m_shape(shape_args...)
278  {
279  update_cache();
280  }
281 
286  Dampings(std::initializer_list<value_type> il)
287  : m_dampings(il)
288  {
289  assert(il.size() > 0);
290  m_shape = il.begin()->get_shape();
291  update_cache();
292  }
293 
298  void add(const value_type& damping)
299  {
300  add_(damping);
301  }
302  template <class... T>
303  void add(T&&... t)
304  {
305  add_(value_type(std::forward<T>(t)...));
306  }
307  template <class... T>
308  void add(FP d, T... t)
309  {
310  add_(value_type(d, std::forward<T>(t)..., m_shape));
311  }
312 
316  void remove(size_t i)
317  {
318  assert(m_dampings.size() > i);
319  m_dampings.erase(m_dampings.begin() + i);
321  }
322 
326  void clear()
327  {
328  m_dampings.clear();
330  }
331 
341  {
344  }
345 
361  {
362  assert(!m_accumulated_dampings_cached.empty() &&
363  "Cache is not current. Did you disable the automatic cache update?");
364 
365  auto ub = std::upper_bound(m_accumulated_dampings_cached.begin(), m_accumulated_dampings_cached.end(),
366  std::make_tuple(t), [](auto&& tup1, auto&& tup2) {
367  return std::get<SimulationTime<FP>>(tup1) < std::get<SimulationTime<FP>>(tup2);
368  });
369 
370  auto damping = smoother_cosine<FP>(
371  t.get(), (std::get<SimulationTime<FP>>(*ub) - mio::SimulationTime<FP>(1.0)).get(),
372  std::get<SimulationTime<FP>>(*ub).get(), std::get<Matrix>(*(ub - 1)), std::get<Matrix>(*ub));
373 
374  return damping;
375  }
376 
381  {
382  return m_dampings[i];
383  }
385  {
386  return m_dampings[i];
387  }
388 
392  bool operator==(const Dampings& other) const
393  {
394  return m_dampings == other.m_dampings;
395  }
396  bool operator!=(const Dampings& other) const
397  {
398  return !(*this == other);
399  }
400 
404  size_t get_num_dampings() const
405  {
406  return m_dampings.size();
407  }
408 
412  Shape get_shape() const
413  {
414  return m_shape;
415  }
416 
421  {
422  return m_dampings.begin();
423  }
425  {
426  return m_dampings.end();
427  }
429  {
430  return m_dampings.begin();
431  }
433  {
434  return m_dampings.end();
435  }
436 
440  friend void PrintTo(const Dampings& self, std::ostream* os)
441  {
442  for (auto& d : self.m_dampings) {
443  *os << '\n'
444  << '[' << std::get<SimulationTime<FP>>(d) << ',' << std::get<DampingType>(d) << ','
445  << std::get<DampingLevel>(d) << ']';
446  *os << '\n' << std::get<Matrix>(d);
447  }
448  }
449 
454  template <class IOContext>
455  void serialize(IOContext& io) const
456  {
457  auto obj = io.create_object("Dampings");
458  obj.add_element("Shape", get_shape());
459  obj.add_list("Dampings", begin(), end());
460  }
461 
466  template <class IOContext>
467  static IOResult<Dampings> deserialize(IOContext& io)
468  {
469  auto obj = io.expect_object("Dampings");
470  auto s = obj.expect_element("Shape", Tag<Shape>{});
471  auto d = obj.expect_list("Dampings", Tag<value_type>{});
472  return apply(
473  io,
474  [](auto&& s_, auto&& d_) -> IOResult<Dampings> {
475  Dampings dampings(s_);
476  for (auto&& i : d_) {
477  if (i.get_shape() != s_) {
478  return failure(StatusCode::InvalidValue, "Dampings must all have the same shape.");
479  }
480  dampings.add(i);
481  }
482  return success(dampings);
483  },
484  s, d);
485  }
486 
487 private:
491  void add_(const value_type& damping);
492 
498  void update_cache();
499 
505  {
507  update_cache();
508  }
509  }
510 
515  static void update_active_dampings(
516  const value_type& damping,
517  std::vector<std::tuple<std::reference_wrapper<const Matrix>, DampingLevel, DampingType>>& active_by_type,
518  std::vector<std::tuple<Matrix, DampingLevel>>& sum_by_level);
519 
524  template <class Iter>
525  static void inclusive_exclusive_sum_rec(Iter b, Iter e, Matrix& sum)
526  {
527  if (b != e) {
528  auto& mat_b = std::get<Matrix>(*b);
529  auto mat_prod = (sum.array() * mat_b.array()).matrix();
530  sum = sum + mat_b - mat_prod;
531  inclusive_exclusive_sum_rec(++b, e, sum);
532  }
533  }
534  template <class Tuple>
535  static Matrix inclusive_exclusive_sum(const std::vector<Tuple>& v)
536  {
537  assert(!v.empty());
538  Matrix sum = std::get<Matrix>(v.front());
539  inclusive_exclusive_sum_rec(v.begin() + 1, v.end(), sum);
540  return sum;
541  }
542 
543  std::vector<value_type> m_dampings;
545  std::vector<std::tuple<Matrix, SimulationTime<FP>>> m_accumulated_dampings_cached;
547 };
548 
549 template <typename FP, class D>
551 {
552  using std::get;
553 
554  if (m_accumulated_dampings_cached.empty()) {
555  m_accumulated_dampings_cached.emplace_back(Matrix::Zero(m_shape.rows(), m_shape.cols()),
556  SimulationTime<FP>(std::numeric_limits<FP>::lowest()));
557 
558  std::vector<std::tuple<std::reference_wrapper<const Matrix>, DampingLevel, DampingType>> active_by_type;
559  std::vector<std::tuple<Matrix, DampingLevel>> sum_by_level;
560  for (auto& damping : m_dampings) {
561  //update active damping
562  update_active_dampings(damping, active_by_type, sum_by_level);
563  auto combined_damping = inclusive_exclusive_sum(sum_by_level);
564  assert((combined_damping.array() <= FP(1.0)).all() &&
565  "unexpected error, accumulated damping out of range.");
566  if (floating_point_equal<FP>(get<SimulationTime<FP>>(damping).get(),
567  get<SimulationTime<FP>>(m_accumulated_dampings_cached.back()).get(), 1e-15,
568  1e-15)) {
569  get<Matrix>(m_accumulated_dampings_cached.back()) = combined_damping;
570  }
571  else {
572  m_accumulated_dampings_cached.emplace_back(combined_damping, get<SimulationTime<FP>>(damping));
573  }
574  }
575 
576  m_accumulated_dampings_cached.emplace_back(get<Matrix>(m_accumulated_dampings_cached.back()),
578  }
579 }
580 
581 template <typename FP, class D>
582 void Dampings<FP, D>::add_(const value_type& damping)
583 {
584  assert(damping.get_shape() == m_shape && "Inconsistent matrix shape.");
585  insert_sorted_replace<value_type>(m_dampings, damping, [](auto& tup1, auto& tup2) {
586  return std::make_tuple(tup1.get_time(), int(tup1.get_type()), int(tup1.get_level())) <
587  std::make_tuple(tup2.get_time(), int(tup2.get_type()), int(tup2.get_level()));
588  });
589  m_accumulated_dampings_cached.clear();
590  if (m_automatic_cache_update) {
591  update_cache();
592  }
593 }
594 
595 template <typename FP, class S>
597  const value_type& damping,
598  std::vector<std::tuple<std::reference_wrapper<const Matrix>, DampingLevel, DampingType>>& active_by_type,
599  std::vector<std::tuple<Matrix, DampingLevel>>& sum_by_level)
600 {
601  using std::get;
602 
603  const int MatrixIdx = 0;
604 
605  //find active with same type and level if existent
606  auto iter_active_same_type = std::find_if(active_by_type.begin(), active_by_type.end(), [&damping](auto& active) {
607  return get<DampingLevel>(active) == get<DampingLevel>(damping) &&
608  get<DampingType>(active) == get<DampingType>(damping);
609  });
610  if (iter_active_same_type != active_by_type.end()) {
611  //replace active of the same type and level
612  auto& active_same_type = *iter_active_same_type;
613  //find active with the same level
614  auto& sum_same_level = *std::find_if(sum_by_level.begin(), sum_by_level.end(), [&damping](auto& sum) {
615  return get<DampingLevel>(sum) == get<DampingLevel>(damping);
616  });
617  //remove active with the same type and level and add new one
618  get<MatrixIdx>(sum_same_level) += get<MatrixIdx>(damping) - get<MatrixIdx>(active_same_type).get();
619  get<MatrixIdx>(active_same_type) = get<MatrixIdx>(damping);
620  }
621  else {
622  //add new type to active
623  active_by_type.emplace_back(get<MatrixIdx>(damping), get<DampingLevel>(damping), get<DampingType>(damping));
624  //find damping with same level if existent
625  auto iter_sum_same_level = std::find_if(sum_by_level.begin(), sum_by_level.end(), [&damping](auto& sum) {
626  return get<DampingLevel>(sum) == get<DampingLevel>(damping);
627  });
628  if (iter_sum_same_level != sum_by_level.end()) {
629  //add to existing level
630  get<MatrixIdx>(*iter_sum_same_level) += get<MatrixIdx>(damping);
631  }
632  else {
633  //add new level
634  sum_by_level.emplace_back(get<MatrixIdx>(damping), get<DampingLevel>(damping));
635  }
636  }
637 }
638 
642 template <typename FP>
644 template <typename FP>
646 template <typename FP>
648 template <typename FP>
650 
651 } // namespace mio
652 
653 #endif // DAMPING_H
represent interventions or effects that affect contact frequencies between multiple groups.
Definition: damping.h:72
DampingType & get_type()
the type of this damping.
Definition: damping.h:174
void serialize(IOContext &io) const
serialize this.
Definition: damping.h:218
requires std::is_constructible_v< Shape, T... > Damping(T... shape_args)
create a default Damping.
Definition: damping.h:85
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:142
const DampingLevel & get_level() const
Definition: damping.h:166
static IOResult< Damping > deserialize(IOContext &io)
deserialize an object of this class.
Definition: damping.h:232
Damping(const Eigen::MatrixBase< ME > &m, DampingLevel level, DampingType type, SimulationTime< FP > t)
create a Damping.
Definition: damping.h:99
const SimulationTime< FP > & get_time() const
Definition: damping.h:154
typename Shape::Matrix Matrix
Definition: damping.h:75
Shape get_shape() const
shape of the damping matrix.
Definition: damping.h:198
Matrix & get_coeffs()
Definition: damping.h:190
const Matrix & get_coeffs() const
the coefficients of this damping.
Definition: damping.h:186
DampingLevel & get_level()
the level of this damping.
Definition: damping.h:162
friend void PrintTo(const Damping &self, std::ostream *os)
GTest printer.
Definition: damping.h:206
S Shape
Definition: damping.h:74
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:116
const DampingType & get_type() const
Definition: damping.h:178
SimulationTime< FP > & get_time()
the time this damping becomes active.
Definition: damping.h:150
std::tuple< Matrix, DampingLevel, DampingType, SimulationTime< FP > > Base
Definition: damping.h:76
Damping(const Eigen::MatrixBase< ME > &m, SimulationTime< FP > t)
create a Damping at level and type zero
Definition: damping.h:128
collection of dampings at different time points.
Definition: damping.h:257
const_iterator end() const
Definition: damping.h:432
D value_type
Definition: damping.h:261
reference operator[](size_t i)
access one damping in this collection.
Definition: damping.h:380
bool operator!=(const Dampings &other) const
Definition: damping.h:396
iterator end()
Definition: damping.h:424
void add(const value_type &damping)
add a damping.
Definition: damping.h:298
friend void PrintTo(const Dampings &self, std::ostream *os)
GTest printer.
Definition: damping.h:440
size_t get_num_dampings() const
get the number of matrices.
Definition: damping.h:404
std::vector< value_type > m_dampings
Definition: damping.h:543
bool operator==(const Dampings &other) const
equality operators.
Definition: damping.h:392
const value_type & const_reference
Definition: damping.h:263
Dampings(std::initializer_list< value_type > il)
create damping collection.
Definition: damping.h:286
value_type & reference
Definition: damping.h:262
const_iterator begin() const
Definition: damping.h:428
auto get_matrix_at(SimulationTime< FP > t) const
Computes the real contact frequency at a point in time.
Definition: damping.h:360
std::vector< std::tuple< Matrix, SimulationTime< FP > > > m_accumulated_dampings_cached
Definition: damping.h:545
void add(T &&... t)
Definition: damping.h:303
void set_automatic_cache_update(bool b)
Disable the internal cache to speed up multiple modifications in a row.
Definition: damping.h:340
typename std::vector< value_type >::iterator iterator
Definition: damping.h:264
void remove(size_t i)
remove the damping at index i.
Definition: damping.h:316
typename std::vector< value_type >::const_iterator const_iterator
Definition: damping.h:265
static IOResult< Dampings > deserialize(IOContext &io)
deserialize an object of this class.
Definition: damping.h:467
Shape m_shape
Definition: damping.h:544
void automatic_cache_update()
updates the cache if automatic cache updates are enabled.
Definition: damping.h:504
typename Shape::Matrix Matrix
Definition: damping.h:260
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:596
iterator begin()
STL iterators over matrices.
Definition: damping.h:420
static void inclusive_exclusive_sum_rec(Iter b, Iter e, Matrix &sum)
e.g.
Definition: damping.h:525
const_reference operator[](size_t i) const
Definition: damping.h:384
void update_cache()
compute the cache of accumulated dampings.
Definition: damping.h:550
bool m_automatic_cache_update
Definition: damping.h:546
static Matrix inclusive_exclusive_sum(const std::vector< Tuple > &v)
Definition: damping.h:535
requires std::is_constructible_v< Shape, T... > Dampings(T... shape_args)
create damping collection.
Definition: damping.h:275
void add_(const value_type &damping)
internal add.
Definition: damping.h:582
Shape get_shape() const
dimensions of the damping matrix.
Definition: damping.h:412
void clear()
remove all dampings.
Definition: damping.h:326
typename D::Shape Shape
Definition: damping.h:259
void add(FP d, T... t)
Definition: damping.h:308
void serialize(IOContext &io) const
serialize this.
Definition: damping.h:455
base class to add default operator +, +=, -, -= to a class derived from TypeSafe.
Definition: type_safe.h:152
base class to add operator <, <=, >, >= to a class derived from TypeSafe.
Definition: type_safe.h:205
base class to add operator *, *=, /, /= with a scalar to a class derived from TypeSafe.
Definition: type_safe.h:179
double simulation time.
Definition: damping.h:58
typesafe wrapper around any type to make function arguments, tuple elements, etc.
Definition: type_safe.h:42
T get() const
Definition: type_safe.h:66
#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:380
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
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:359
DECL_TYPESAFE(int, DampingLevel)
integer damping level.
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
boost::outcome_v2::unchecked< T, IOStatus > IOResult
Value-or-error type for operations that return a value but can fail.
Definition: io.h:353