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  // TODO: This is in the real time path. We should not use heap here.
357  };
358 
367  template <class U>
368  typename Attribute<U>::Ptr
369  derive(typename AttributeUpdateTask<U, T>::Actor getter =
370  typename AttributeUpdateTask<U, T>::Actor(),
371  typename AttributeUpdateTask<U, T>::Actor setter =
372  typename AttributeUpdateTask<U, T>::Actor()) {
373  auto derivedAttribute = std::make_shared<AttributeDynamic<U>>();
374  if (setter) {
375  derivedAttribute->addTask(
376  UpdateTaskKind::UPDATE_ON_SET,
378  UpdateTaskKind::UPDATE_ON_SET, setter,
379  Attribute<T>::Ptr(this->shared_from_this())));
380  }
381  if (getter) {
382  derivedAttribute->addTask(
383  UpdateTaskKind::UPDATE_ON_GET,
385  UpdateTaskKind::UPDATE_ON_GET, getter,
386  Attribute<T>::Ptr(this->shared_from_this())));
387  }
388  return derivedAttribute;
389  }
390 
395  template <typename U = T,
396  std::enable_if_t<std::is_same_v<Complex, U>, bool> = true>
398  // requires std::same_as<T, CPS::Complex> //CPP20
399  {
400  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor getter =
401  [](std::shared_ptr<Real> &dependent,
402  typename Attribute<Complex>::Ptr dependency) {
403  *dependent = (**dependency).real();
404  };
405  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor setter =
406  [](std::shared_ptr<Real> &dependent,
407  typename Attribute<Complex>::Ptr dependency) {
408  CPS::Complex currentValue = dependency->get();
409  currentValue.real(*dependent);
410  dependency->set(currentValue);
411  };
412  return derive<CPS::Real>(getter, setter);
413  }
414 
419  template <typename U = T,
420  std::enable_if_t<std::is_same_v<Complex, U>, bool> = true>
422  // requires std::same_as<T, CPS::Complex> //CPP20
423  {
424  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor getter =
425  [](std::shared_ptr<Real> &dependent,
426  Attribute<Complex>::Ptr dependency) {
427  *dependent = (**dependency).imag();
428  };
429  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor setter =
430  [](std::shared_ptr<Real> &dependent,
431  Attribute<Complex>::Ptr dependency) {
432  CPS::Complex currentValue = dependency->get();
433  currentValue.imag(*dependent);
434  dependency->set(currentValue);
435  };
436  return derive<CPS::Real>(getter, setter);
437  }
438 
443  template <typename U = T,
444  std::enable_if_t<std::is_same_v<Complex, U>, bool> = true>
446  // requires std::same_as<T, CPS::Complex> //CPP20
447  {
448  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor getter =
449  [](std::shared_ptr<Real> &dependent,
450  Attribute<Complex>::Ptr dependency) {
451  *dependent = Math::abs(**dependency);
452  };
453  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor setter =
454  [](std::shared_ptr<Real> &dependent,
455  Attribute<Complex>::Ptr dependency) {
456  CPS::Complex currentValue = dependency->get();
457  dependency->set(Math::polar(*dependent, Math::phase(currentValue)));
458  };
459  return derive<CPS::Real>(getter, setter);
460  }
461 
466  template <typename U = T,
467  std::enable_if_t<std::is_same_v<Complex, U>, bool> = true>
469  // requires std::same_as<T, CPS::Complex> //CPP20
470  {
471  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor getter =
472  [](std::shared_ptr<Real> &dependent,
473  Attribute<Complex>::Ptr dependency) {
474  *dependent = Math::phase(**dependency);
475  };
476  AttributeUpdateTask<CPS::Real, CPS::Complex>::Actor setter =
477  [](std::shared_ptr<Real> &dependent,
478  Attribute<Complex>::Ptr dependency) {
479  CPS::Complex currentValue = dependency->get();
480  dependency->set(Math::polar(Math::abs(currentValue), *dependent));
481  };
482  return derive<CPS::Real>(getter, setter);
483  }
484 
490  template <typename U = T, std::enable_if_t<std::is_same_v<Real, U> ||
491  std::is_same_v<Complex, U>,
492  bool> = true>
494  // requires std::same_as<T, CPS::Complex> || std::same_as<T, CPS::Real> //CPP20
495  {
496  typename AttributeUpdateTask<T, T>::Actor getter =
497  [scale](std::shared_ptr<T> &dependent, Attribute<T>::Ptr dependency) {
498  *dependent = scale * (**dependency);
499  };
500  typename AttributeUpdateTask<T, T>::Actor setter =
501  [scale](std::shared_ptr<T> &dependent, Attribute<T>::Ptr dependency) {
502  dependency->set((*dependent) / scale);
503  };
504  return derive<T>(getter, setter);
505  }
506 
514  template <class U, class V = T,
515  std::enable_if_t<std::is_same_v<CPS::MatrixVar<U>, V>, bool> = true>
517  deriveCoeff(typename CPS::MatrixVar<U>::Index row,
518  typename CPS::MatrixVar<U>::Index column)
519  // requires std::same_as<T, CPS::MatrixVar<U>> //CPP20
520  {
521  typename AttributeUpdateTask<U, T>::Actor getter =
522  [row, column](std::shared_ptr<U> &dependent,
523  Attribute<T>::Ptr dependency) {
524  *dependent = (**dependency)(row, column);
525  };
526  typename AttributeUpdateTask<U, T>::Actor setter =
527  [row, column](std::shared_ptr<U> &dependent,
528  Attribute<T>::Ptr dependency) {
529  CPS::MatrixVar<U> currentValue = dependency->get();
530  currentValue(row, column) = *dependent;
531  dependency->set(currentValue);
532  };
533  return derive<U>(getter, setter);
534  }
535 };
536 
541 template <class T>
542 class AttributeStatic : public Attribute<T>,
543  public SharedFactory<AttributeStatic<T>> {
544  friend class SharedFactory<AttributeStatic<T>>;
545 
546 public:
547  AttributeStatic(T initialValue = T()) : Attribute<T>(initialValue) {}
548 
549  virtual void set(T value) override { *this->mData = value; };
550 
551  virtual T &get() override { return *this->mData; };
552 
553  virtual bool isStatic() const override { return true; }
554 
555  virtual void setReference(typename Attribute<T>::Ptr reference) override {
556  throw TypeException();
557  }
558 
559  virtual std::shared_ptr<T> asRawPointer() override { return this->mData; }
560 
561  virtual void appendDependencies(AttributeBase::Set *deps) override {
562  deps->insert(this->shared_from_this());
563  }
564 };
565 
569 template <class T>
570 class AttributeDynamic : public Attribute<T>,
571  public SharedFactory<AttributeDynamic<T>> {
572  friend class SharedFactory<AttributeDynamic<T>>;
573 
574 protected:
575  std::vector<typename AttributeUpdateTaskBase<T>::Ptr> updateTasksOnce;
576  std::vector<typename AttributeUpdateTaskBase<T>::Ptr> updateTasksOnGet;
577  std::vector<typename AttributeUpdateTaskBase<T>::Ptr> updateTasksOnSet;
578 
579 public:
580  AttributeDynamic(T initialValue = T()) : Attribute<T>(initialValue) {}
581 
587  void addTask(UpdateTaskKind kind,
588  typename AttributeUpdateTaskBase<T>::Ptr task) {
589  switch (kind) {
590  case UpdateTaskKind::UPDATE_ONCE:
591  updateTasksOnce.push_back(task);
593  task->executeUpdate(this->mData);
594  break;
595  case UpdateTaskKind::UPDATE_ON_GET:
596  updateTasksOnGet.push_back(task);
597  break;
598  case UpdateTaskKind::UPDATE_ON_SET:
599  updateTasksOnSet.push_back(task);
600  break;
601  case UpdateTaskKind::UPDATE_ON_SIMULATION_STEP:
602  throw InvalidArgumentException();
603  };
604  }
605 
610  void clearTasks(UpdateTaskKind kind) {
611  switch (kind) {
612  case UpdateTaskKind::UPDATE_ONCE:
613  updateTasksOnce.clear();
614  break;
615  case UpdateTaskKind::UPDATE_ON_GET:
616  updateTasksOnGet.clear();
617  break;
618  case UpdateTaskKind::UPDATE_ON_SET:
619  updateTasksOnSet.clear();
620  break;
621  case UpdateTaskKind::UPDATE_ON_SIMULATION_STEP:
622  throw InvalidArgumentException();
623  };
624  }
625 
629  void clearAllTasks() {
630  updateTasksOnce.clear();
631  updateTasksOnGet.clear();
632  updateTasksOnSet.clear();
633  }
634 
635  virtual void setReference(typename Attribute<T>::Ptr reference) override {
636  typename AttributeUpdateTask<T, T>::Actor getter =
637  [](std::shared_ptr<T> &dependent,
638  typename Attribute<T>::Ptr dependency) {
639  dependent = dependency->asRawPointer();
640  };
641  this->clearAllTasks();
642  if (reference->isStatic()) {
643  this->addTask(UpdateTaskKind::UPDATE_ONCE,
644  AttributeUpdateTask<T, T>::make(UpdateTaskKind::UPDATE_ONCE,
645  getter, reference));
646  } else {
647  this->addTask(UpdateTaskKind::UPDATE_ON_GET,
649  UpdateTaskKind::UPDATE_ON_GET, getter, reference));
650  }
651  }
652 
653  virtual std::shared_ptr<T> asRawPointer() override {
654  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnGet) {
655  task->executeUpdate(this->mData);
656  }
657  return this->mData;
658  }
659 
660  virtual void set(T value) override {
661  *this->mData = value;
662  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnSet) {
663  task->executeUpdate(this->mData);
664  }
665  };
666 
667  virtual T &get() override {
668  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnGet) {
669  task->executeUpdate(this->mData);
670  }
671  return *this->mData;
672  };
673 
674  virtual bool isStatic() const override { return false; }
675 
681  virtual void appendDependencies(AttributeBase::Set *deps) override {
682  deps->insert(this->shared_from_this());
683 
684  AttributeBase::Set newDeps = AttributeBase::Set();
685  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnce) {
686  AttributeBase::List taskDeps = task->getDependencies();
687  newDeps.insert(taskDeps.begin(), taskDeps.end());
688  }
689 
690  for (typename AttributeUpdateTaskBase<T>::Ptr task : updateTasksOnGet) {
691  AttributeBase::List taskDeps = task->getDependencies();
692  newDeps.insert(taskDeps.begin(), taskDeps.end());
693  }
694 
695  for (auto dependency : newDeps) {
696  dependency->appendDependencies(deps);
697  }
698  }
699 };
700 
701 template <> String Attribute<Real>::toString();
702 
703 template <> String Attribute<Complex>::toString();
704 
705 template <> String Attribute<String>::toString();
706 
707 } // namespace CPS
708 
709 namespace std {
713 template <typename T> struct hash<CPS::AttributePointer<T>> {
714  size_t operator()(CPS::AttributePointer<T> const &x) const {
715  return std::hash<std::shared_ptr<T>>()(x.getPtr());
716  }
717 };
718 } // 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:587
virtual std::shared_ptr< T > asRawPointer() override
Definition: Attribute.h:653
virtual T & get() override
Definition: Attribute.h:667
virtual void setReference(typename Attribute< T >::Ptr reference) override
Definition: Attribute.h:635
virtual void appendDependencies(AttributeBase::Set *deps) override
Definition: Attribute.h:681
void clearTasks(UpdateTaskKind kind)
Definition: Attribute.h:610
virtual void set(T value) override
Definition: Attribute.h:660
virtual bool isStatic() const override
Definition: Attribute.h:674
AttributePointer< Attribute< T > > deriveScaled(T scale)
Definition: Attribute.h:493
AttributePointer< Attribute< Real > > deriveMag()
Definition: Attribute.h:445
AttributePointer< Attribute< U > > deriveCoeff(typename CPS::MatrixVar< U >::Index row, typename CPS::MatrixVar< U >::Index column)
Definition: Attribute.h:517
virtual std::shared_ptr< T > asRawPointer()=0
AttributePointer< Attribute< Real > > derivePhase()
Definition: Attribute.h:468
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:369
AttributePointer< Attribute< Real > > deriveReal()
Definition: Attribute.h:397
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:421
virtual void set(T value) override
Definition: Attribute.h:549
virtual void appendDependencies(AttributeBase::Set *deps) override
Definition: Attribute.h:561
virtual void setReference(typename Attribute< T >::Ptr reference) override
Definition: Attribute.h:555
virtual bool isStatic() const override
Definition: Attribute.h:553
virtual T & get() override
Definition: Attribute.h:551
virtual std::shared_ptr< T > asRawPointer() override
Definition: Attribute.h:559
virtual AttributeBase::List getDependencies() override
Definition: Attribute.h:251