DPsim
Attribute.h
1 /* Copyright 2017-2022 Institute for Automation of Complex Power Systems,
2  * EONERC, RWTH Aachen University
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7  *********************************************************************************/
8 
9 #pragma once
10 #include <iostream>
11 #include <set>
12 
13 #include <dpsim-models/Config.h>
14 #include <dpsim-models/Definitions.h>
15 #include <dpsim-models/MathUtils.h>
16 #include <dpsim-models/PtrFactory.h>
17 namespace CPS {
18 
27 enum UpdateTaskKind {
28  UPDATE_ONCE,
29  UPDATE_ON_GET,
30  UPDATE_ON_SET,
31  UPDATE_ON_SIMULATION_STEP,
32 };
33 
34 template <class T> class Attribute;
35 
36 template <class T> class AttributeStatic;
37 
38 template <class T> class AttributeDynamic;
39 
46 template <class T> class AttributePointer {
47 public:
48  using element_type = T;
49 
50  AttributePointer() : mPtr(){};
51  AttributePointer(const AttributePointer &r) = default;
52  AttributePointer(std::shared_ptr<T> ptr) : mPtr(ptr){};
53  AttributePointer(std::nullptr_t ptr) : mPtr(ptr){};
54  explicit AttributePointer(T *ptr) : mPtr(ptr){};
55 
56  template <class U> AttributePointer(AttributePointer<U> ptr) : mPtr() {
57  this->mPtr = ptr.getPtr();
58  };
59 
60  template <class U> AttributePointer(std::shared_ptr<U> ptr) : mPtr(ptr){};
61 
62  AttributePointer &operator=(const AttributePointer &r) noexcept {
63  this->mPtr = r.getPtr();
64  return *this;
65  };
66 
67  template <class U>
68  AttributePointer &operator=(const AttributePointer<U> &r) noexcept {
69  this->mPtr = r.getPtr();
70  return *this;
71  };
72 
73  AttributePointer &operator=(AttributePointer &&r) {
74  this->mPtr = r.getPtr();
75  return *this;
76  }
77 
78  template <class U> AttributePointer &operator=(AttributePointer<U> &&r) {
79  this->mPtr = r.getPtr();
80  return *this;
81  }
82 
83  T &operator*() const noexcept { return *mPtr; }
84 
85  T *operator->() const noexcept { return mPtr.operator->(); }
86 
87  T *get() const { return mPtr.get(); }
88 
89  std::shared_ptr<T> getPtr() const { return mPtr; }
90 
91  bool isNull() const { return mPtr == nullptr; }
92 
93  /*
94  These (implicit) comparison operators are disabled to avoid accidentally comparing pointers instead of attribute values.
95  When a pointer comparison is necessary, this can be done via the `getPtr` method or by using the `AttributeCmp` and `AttributeEq` structs.
96 
97  template<class U>
98  bool operator<(const AttributePointer<U>& rhs) const noexcept {
99  return this->mPtr < rhs.getPtr();
100  }
101 
102  template<class U>
103  bool operator>(const AttributePointer<U>& rhs) const noexcept {
104  return this->mPtr > rhs.getPtr();
105  }
106 
107  template<class U>
108  bool operator==(const AttributePointer<U>& rhs) const noexcept {
109  return this->mPtr == rhs.getPtr();
110  }
111 
112  template<class U>
113  bool operator!=(const AttributePointer<U>& rhs) const noexcept {
114  return this->mPtr != rhs.getPtr();
115  }*/
116 
117 private:
118  std::shared_ptr<T> mPtr;
119 };
120 
124 template <class T> struct AttributeCmp {
125  bool operator()(CPS::AttributePointer<T> a,
126  CPS::AttributePointer<T> b) const {
127  return a.getPtr() < b.getPtr();
128  }
129 };
130 
134 template <class T> struct AttributeEq {
135  bool operator()(CPS::AttributePointer<T> a,
136  CPS::AttributePointer<T> b) const {
137  return a.getPtr() == b.getPtr();
138  }
139 };
140 
145 public:
147  typedef std::vector<Ptr> List;
148  typedef std::set<Ptr, AttributeCmp<AttributeBase>> Set;
149  typedef std::map<String, Ptr> Map;
150 
154  virtual String toString() = 0;
155 
160  virtual bool isStatic() const = 0;
161 
162  virtual ~AttributeBase() = default;
163 
168  virtual bool copyValue(AttributeBase::Ptr copyFrom) = 0;
169 
174  virtual const std::type_info &getType() = 0;
175 
181 
187  virtual void appendDependencies(AttributeBase::Set *deps) = 0;
188 
193  virtual AttributeBase::Set getDependencies() final {
194  AttributeBase::Set deps = AttributeBase::Set();
195  this->appendDependencies(&deps);
196  return deps;
197  }
198 };
199 
203 template <class DependentType> class AttributeUpdateTaskBase {
204 
205 public:
206  typedef std::shared_ptr<AttributeUpdateTaskBase<DependentType>> Ptr;
207 
208  virtual void executeUpdate(std::shared_ptr<DependentType> &dependent) = 0;
209  virtual AttributeBase::List getDependencies() = 0;
210  virtual ~AttributeUpdateTaskBase() = default;
211 };
212 
218 template <class DependentType, class... DependencyTypes>
220  : public AttributeUpdateTaskBase<DependentType>,
221  public SharedFactory<
222  AttributeUpdateTask<DependentType, DependencyTypes...>> {
223 
224 public:
225  using Actor =
226  std::function<void(std::shared_ptr<DependentType> &,
227  typename Attribute<DependencyTypes>::Ptr...)>;
228 
229 protected:
230  std::tuple<typename Attribute<DependencyTypes>::Ptr...> mDependencies;
231  Actor mActorFunction;
232  UpdateTaskKind mKind;
233 
234 public:
235  AttributeUpdateTask(UpdateTaskKind kind, Actor &actorFunction,
236  typename Attribute<DependencyTypes>::Ptr... dependencies)
237  : mDependencies(std::forward<typename Attribute<DependencyTypes>::Ptr>(
238  dependencies)...),
239  mActorFunction(actorFunction), mKind(kind) {}
240 
241  virtual void
242  executeUpdate(std::shared_ptr<DependentType> &dependent) override {
243  mActorFunction(
244  dependent,
245  std::get<typename Attribute<DependencyTypes>::Ptr...>(mDependencies));
246  }
247 
251  virtual AttributeBase::List getDependencies() override {
252  return std::apply(
253  [](auto &&...elems) {
254  return std::vector<AttributeBase::Ptr>{
255  std::forward<decltype(elems)>(elems)...};
256  },
257  mDependencies);
258  };
259 };
260 
265 template <class T>
266 class Attribute : public AttributeBase,
267  public std::enable_shared_from_this<Attribute<T>> {
268 
269 protected:
270  std::shared_ptr<T> mData;
271 
272 public:
273  using Type = T;
275 
276  Attribute(T initialValue = T())
277  : AttributeBase(), mData(std::make_shared<T>()) {
278  *mData = initialValue;
279  }
280 
285  virtual void set(T value) = 0;
286 
290  virtual T &get() = 0;
291 
298  virtual void setReference(Attribute<T>::Ptr reference) = 0;
299 
304  virtual std::shared_ptr<T> asRawPointer() = 0;
305 
307  String toString() override {
308  std::stringstream ss;
309  ss << this->get();
310  return ss.str();
311  }
312 
322  operator const T &() { return this->get(); }
323 
327  T &operator*() { return this->get(); }
328 
333  bool copyValue(AttributeBase::Ptr copyFrom) override {
334  Attribute<T>::Ptr copyFromTyped =
335  std::dynamic_pointer_cast<Attribute<T>>(copyFrom.getPtr());
336  if (copyFromTyped.getPtr() == nullptr) {
337  return false;
338  }
339  this->set(**copyFromTyped);
340  return true;
341  }
342 
347  const std::type_info &getType() override { return typeid(T); }
348 
355  AttributeStatic<T>::make(this->get()));
356  };
357 
366  template <class U>
367  typename Attribute<U>::Ptr
368  derive(typename AttributeUpdateTask<U, T>::Actor getter =
369  typename AttributeUpdateTask<U, T>::Actor(),
370  typename AttributeUpdateTask<U, T>::Actor setter =
371  typename AttributeUpdateTask<U, T>::Actor()) {
372  auto derivedAttribute = std::make_shared<AttributeDynamic<U>>();
373  if (setter) {
374  derivedAttribute->addTask(
375  UpdateTaskKind::UPDATE_ON_SET,
377  UpdateTaskKind::UPDATE_ON_SET, setter,
378  Attribute<T>::Ptr(this->shared_from_this())));
379  }
380  if (getter) {
381  derivedAttribute->addTask(
382  UpdateTaskKind::UPDATE_ON_GET,
384  UpdateTaskKind::UPDATE_ON_GET, getter,
385  Attribute<T>::Ptr(this->shared_from_this())));
386  }
387  return derivedAttribute;
388  }
389 
394  template <typename U = T,
395  std::enable_if_t<std::is_same_v<Complex, U>, bool> = true>
397  // requires std::same_as<T, CPS::Complex> //CPP20
398  {
399  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor getter =
400  [](std::shared_ptr<Real> &dependent,
401  typename Attribute<Complex>::Ptr dependency) {
402  *dependent = (**dependency).real();
403  };
404  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor setter =
405  [](std::shared_ptr<Real> &dependent,
406  typename Attribute<Complex>::Ptr dependency) {
407  CPS::Complex currentValue = dependency->get();
408  currentValue.real(*dependent);
409  dependency->set(currentValue);
410  };
411  return derive<CPS::Real>(getter, setter);
412  }
413 
418  template <typename U = T,
419  std::enable_if_t<std::is_same_v<Complex, U>, bool> = true>
421  // requires std::same_as<T, CPS::Complex> //CPP20
422  {
423  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor getter =
424  [](std::shared_ptr<Real> &dependent,
425  Attribute<Complex>::Ptr dependency) {
426  *dependent = (**dependency).imag();
427  };
428  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor setter =
429  [](std::shared_ptr<Real> &dependent,
430  Attribute<Complex>::Ptr dependency) {
431  CPS::Complex currentValue = dependency->get();
432  currentValue.imag(*dependent);
433  dependency->set(currentValue);
434  };
435  return derive<CPS::Real>(getter, setter);
436  }
437 
442  template <typename U = T,
443  std::enable_if_t<std::is_same_v<Complex, U>, bool> = true>
445  // requires std::same_as<T, CPS::Complex> //CPP20
446  {
447  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor getter =
448  [](std::shared_ptr<Real> &dependent,
449  Attribute<Complex>::Ptr dependency) {
450  *dependent = Math::abs(**dependency);
451  };
452  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor setter =
453  [](std::shared_ptr<Real> &dependent,
454  Attribute<Complex>::Ptr dependency) {
455  CPS::Complex currentValue = dependency->get();
456  dependency->set(Math::polar(*dependent, Math::phase(currentValue)));
457  };
458  return derive<CPS::Real>(getter, setter);
459  }
460 
465  template <typename U = T,
466  std::enable_if_t<std::is_same_v<Complex, U>, bool> = true>
468  // requires std::same_as<T, CPS::Complex> //CPP20
469  {
470  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor getter =
471  [](std::shared_ptr<Real> &dependent,
472  Attribute<Complex>::Ptr dependency) {
473  *dependent = Math::phase(**dependency);
474  };
475  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor setter =
476  [](std::shared_ptr<Real> &dependent,
477  Attribute<Complex>::Ptr dependency) {
478  CPS::Complex currentValue = dependency->get();
479  dependency->set(Math::polar(Math::abs(currentValue), *dependent));
480  };
481  return derive<CPS::Real>(getter, setter);
482  }
483 
489  template <typename U = T, std::enable_if_t<std::is_same_v<Real, U> ||
490  std::is_same_v<Complex, U>,
491  bool> = true>
493  // requires std::same_as<T, CPS::Complex> || std::same_as<T, CPS::Real> //CPP20
494  {
495  typename AttributeUpdateTask<T, T>::Actor getter =
496  [scale](std::shared_ptr<T> &dependent, Attribute<T>::Ptr dependency) {
497  *dependent = scale * (**dependency);
498  };
499  typename AttributeUpdateTask<T, T>::Actor setter =
500  [scale](std::shared_ptr<T> &dependent, Attribute<T>::Ptr dependency) {
501  dependency->set((*dependent) / scale);
502  };
503  return derive<T>(getter, setter);
504  }
505 
513  template <class U, class V = T,
514  std::enable_if_t<std::is_same_v<CPS::MatrixVar<U>, V>, bool> = true>
516  deriveCoeff(typename CPS::MatrixVar<U>::Index row,
517  typename CPS::MatrixVar<U>::Index column)
518  // requires std::same_as<T, CPS::MatrixVar<U>> //CPP20
519  {
520  typename AttributeUpdateTask<U, T>::Actor getter =
521  [row, column](std::shared_ptr<U> &dependent,
522  Attribute<T>::Ptr dependency) {
523  *dependent = (**dependency)(row, column);
524  };
525  typename AttributeUpdateTask<U, T>::Actor setter =
526  [row, column](std::shared_ptr<U> &dependent,
527  Attribute<T>::Ptr dependency) {
528  CPS::MatrixVar<U> currentValue = dependency->get();
529  currentValue(row, column) = *dependent;
530  dependency->set(currentValue);
531  };
532  return derive<U>(getter, setter);
533  }
534 };
535 
540 template <class T>
541 class AttributeStatic : public Attribute<T>,
542  public SharedFactory<AttributeStatic<T>> {
543  friend class SharedFactory<AttributeStatic<T>>;
544 
545 public:
546  AttributeStatic(T initialValue = T()) : Attribute<T>(initialValue) {}
547 
548  virtual void set(T value) override { *this->mData = value; };
549 
550  virtual T &get() override { return *this->mData; };
551 
552  virtual bool isStatic() const override { return true; }
553 
554  virtual void setReference(typename Attribute<T>::Ptr reference) override {
555  throw TypeException();
556  }
557 
558  virtual std::shared_ptr<T> asRawPointer() override { return this->mData; }
559 
560  virtual void appendDependencies(AttributeBase::Set *deps) override {
561  deps->insert(this->shared_from_this());
562  }
563 };
564 
568 template <class T>
569 class AttributeDynamic : public Attribute<T>,
570  public SharedFactory<AttributeDynamic<T>> {
571  friend class SharedFactory<AttributeDynamic<T>>;
572 
573 protected:
574  std::vector<typename AttributeUpdateTaskBase<T>::Ptr> updateTasksOnce;
575  std::vector<typename AttributeUpdateTaskBase<T>::Ptr> updateTasksOnGet;
576  std::vector<typename AttributeUpdateTaskBase<T>::Ptr> updateTasksOnSet;
577 
578 public:
579  AttributeDynamic(T initialValue = T()) : Attribute<T>(initialValue) {}
580 
586  void addTask(UpdateTaskKind kind,
587  typename AttributeUpdateTaskBase<T>::Ptr task) {
588  switch (kind) {
589  case UpdateTaskKind::UPDATE_ONCE:
590  updateTasksOnce.push_back(task);
592  task->executeUpdate(this->mData);
593  break;
594  case UpdateTaskKind::UPDATE_ON_GET:
595  updateTasksOnGet.push_back(task);
596  break;
597  case UpdateTaskKind::UPDATE_ON_SET:
598  updateTasksOnSet.push_back(task);
599  break;
600  case UpdateTaskKind::UPDATE_ON_SIMULATION_STEP:
601  throw InvalidArgumentException();
602  };
603  }
604 
609  void clearTasks(UpdateTaskKind kind) {
610  switch (kind) {
611  case UpdateTaskKind::UPDATE_ONCE:
612  updateTasksOnce.clear();
613  break;
614  case UpdateTaskKind::UPDATE_ON_GET:
615  updateTasksOnGet.clear();
616  break;
617  case UpdateTaskKind::UPDATE_ON_SET:
618  updateTasksOnSet.clear();
619  break;
620  case UpdateTaskKind::UPDATE_ON_SIMULATION_STEP:
621  throw InvalidArgumentException();
622  };
623  }
624 
628  void clearAllTasks() {
629  updateTasksOnce.clear();
630  updateTasksOnGet.clear();
631  updateTasksOnSet.clear();
632  }
633 
634  virtual void setReference(typename Attribute<T>::Ptr reference) override {
635  typename AttributeUpdateTask<T, T>::Actor getter =
636  [](std::shared_ptr<T> &dependent,
637  typename Attribute<T>::Ptr dependency) {
638  dependent = dependency->asRawPointer();
639  };
640  this->clearAllTasks();
641  if (reference->isStatic()) {
642  this->addTask(UpdateTaskKind::UPDATE_ONCE,
643  AttributeUpdateTask<T, T>::make(UpdateTaskKind::UPDATE_ONCE,
644  getter, reference));
645  } else {
646  this->addTask(UpdateTaskKind::UPDATE_ON_GET,
648  UpdateTaskKind::UPDATE_ON_GET, getter, reference));
649  }
650  }
651 
652  virtual std::shared_ptr<T> asRawPointer() override {
653  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnGet) {
654  task->executeUpdate(this->mData);
655  }
656  return this->mData;
657  }
658 
659  virtual void set(T value) override {
660  *this->mData = value;
661  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnSet) {
662  task->executeUpdate(this->mData);
663  }
664  };
665 
666  virtual T &get() override {
667  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnGet) {
668  task->executeUpdate(this->mData);
669  }
670  return *this->mData;
671  };
672 
673  virtual bool isStatic() const override { return false; }
674 
680  virtual void appendDependencies(AttributeBase::Set *deps) override {
681  deps->insert(this->shared_from_this());
682 
683  AttributeBase::Set newDeps = AttributeBase::Set();
684  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnce) {
685  AttributeBase::List taskDeps = task->getDependencies();
686  newDeps.insert(taskDeps.begin(), taskDeps.end());
687  }
688 
689  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnGet) {
690  AttributeBase::List taskDeps = task->getDependencies();
691  newDeps.insert(taskDeps.begin(), taskDeps.end());
692  }
693 
694  for (auto dependency : newDeps) {
695  dependency->appendDependencies(deps);
696  }
697  }
698 };
699 
700 template <> String Attribute<Real>::toString();
701 
702 template <> String Attribute<Complex>::toString();
703 
704 template <> String Attribute<String>::toString();
705 
706 } // namespace CPS
707 
708 namespace std {
712 template <typename T> struct hash<CPS::AttributePointer<T>> {
713  size_t operator()(CPS::AttributePointer<T> const &x) const {
714  return std::hash<std::shared_ptr<T>>()(x.getPtr());
715  }
716 };
717 } // namespace std
virtual bool isStatic() const =0
virtual const std::type_info & getType()=0
Get the type of this attribute.
virtual bool copyValue(AttributeBase::Ptr copyFrom)=0
Copy the attribute value of copyFrom onto this attribute.
virtual String toString()=0
virtual AttributeBase::Set getDependencies() final
Definition: Attribute.h:193
virtual void appendDependencies(AttributeBase::Set *deps)=0
virtual AttributeBase::Ptr cloneValueOntoNewAttribute()=0
Generates a new attribute of the same type and copies the current value in the heap....
void addTask(UpdateTaskKind kind, typename AttributeUpdateTaskBase< T >::Ptr task)
Definition: Attribute.h:586
virtual std::shared_ptr< T > asRawPointer() override
Definition: Attribute.h:652
virtual T & get() override
Definition: Attribute.h:666
virtual void setReference(typename Attribute< T >::Ptr reference) override
Definition: Attribute.h:634
virtual void appendDependencies(AttributeBase::Set *deps) override
Definition: Attribute.h:680
void clearTasks(UpdateTaskKind kind)
Definition: Attribute.h:609
virtual void set(T value) override
Definition: Attribute.h:659
virtual bool isStatic() const override
Definition: Attribute.h:673
AttributePointer< Attribute< T > > deriveScaled(T scale)
Definition: Attribute.h:492
AttributePointer< Attribute< Real > > deriveMag()
Definition: Attribute.h:444
AttributePointer< Attribute< U > > deriveCoeff(typename CPS::MatrixVar< U >::Index row, typename CPS::MatrixVar< U >::Index column)
Definition: Attribute.h:516
virtual std::shared_ptr< T > asRawPointer()=0
AttributePointer< Attribute< Real > > derivePhase()
Definition: Attribute.h:467
T & operator*()
User-defined dereference operator.
Definition: Attribute.h:327
Attribute< U >::Ptr derive(typename AttributeUpdateTask< U, T >::Actor getter=typename AttributeUpdateTask< U, T >::Actor(), typename AttributeUpdateTask< U, T >::Actor setter=typename AttributeUpdateTask< U, T >::Actor())
Definition: Attribute.h:368
AttributePointer< Attribute< Real > > deriveReal()
Definition: Attribute.h:396
virtual void setReference(Attribute< T >::Ptr reference)=0
const std::type_info & getType() override
Get the type of this attribute.
Definition: Attribute.h:347
virtual void set(T value)=0
String toString() override
Fallback method for all attribute types not covered by the specifications in Attribute....
Definition: Attribute.h:307
AttributeBase::Ptr cloneValueOntoNewAttribute() override
Generates a new attribute of the same type and copies the current value in the heap....
Definition: Attribute.h:353
virtual T & get()=0
bool copyValue(AttributeBase::Ptr copyFrom) override
Copy the attribute value of copyFrom onto this attribute.
Definition: Attribute.h:333
AttributePointer< Attribute< Real > > deriveImag()
Definition: Attribute.h:420
virtual void set(T value) override
Definition: Attribute.h:548
virtual void appendDependencies(AttributeBase::Set *deps) override
Definition: Attribute.h:560
virtual void setReference(typename Attribute< T >::Ptr reference) override
Definition: Attribute.h:554
virtual bool isStatic() const override
Definition: Attribute.h:552
virtual T & get() override
Definition: Attribute.h:550
virtual std::shared_ptr< T > asRawPointer() override
Definition: Attribute.h:558
virtual AttributeBase::List getDependencies() override
Definition: Attribute.h:251