RegisterEvents.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 #include <optional>
8 #include <unordered_map>
9 
11 #include "IO/Observer/Actions/ObserverRegistration.hpp"
12 #include "IO/Observer/ArrayComponentId.hpp"
13 #include "IO/Observer/ObserverComponent.hpp"
14 #include "IO/Observer/Tags.hpp"
15 #include "IO/Observer/TypeOfObservation.hpp"
16 #include "Parallel/GlobalCache.hpp"
17 #include "Parallel/Invoke.hpp"
19 #include "Utilities/Gsl.hpp"
20 #include "Utilities/TMPL.hpp"
21 #include "Utilities/TaggedTuple.hpp"
22 #include "Utilities/TypeTraits/CreateHasTypeAlias.hpp"
23 
24 namespace observers {
25 namespace detail {
26 CREATE_HAS_TYPE_ALIAS(observation_registration_tags)
27 CREATE_HAS_TYPE_ALIAS_V(observation_registration_tags)
28 } // namespace detail
29 
30 /*!
31  * \brief Retrieves the observation type and key from an event, if it is an
32  * event that needs to register with the observers.
33  *
34  * The event must define an `observation_registration_tags` type alias that is a
35  * `tmpl::list<>` of all the tags from the DataBox needed to construct the
36  * `ObservationKey`, and a `get_observation_type_and_key_for_registration`
37  * member function if it is to be registered automatically.
38  */
39 template <typename EventRegistrars, typename DbTagsList>
42 get_registration_observation_type_and_key(
43  const Event<EventRegistrars>& event,
44  const db::DataBox<DbTagsList>& box) noexcept {
47  result{};
48  bool already_registered = false;
49  tmpl::for_each<typename Event<EventRegistrars>::creatable_classes>(
50  [&already_registered, &box, &event, &result](auto event_type_v) noexcept {
51  using EventType = typename decltype(event_type_v)::type;
52  if constexpr (detail::has_observation_registration_tags_v<EventType>) {
53  // We require that each event for which
54  // `has_observation_registration_tags_v` is true be downcastable to
55  // only *one* event type. This is checked by the `already_registered`
56  // bool and the error message below. We need to downcast because we do
57  // not want to impose that every event be registerable with the
58  // IO/observer components. `dynamic_cast` returns a `nullptr` in the
59  // case that the downcast failed, which we check for to see if we can
60  // call the `get_observation_type_and_key_for_registration` function.
61  const auto* const derived_class_ptr =
62  dynamic_cast<const EventType*>(&event);
63  if (derived_class_ptr != nullptr) {
64  if (already_registered) {
65  ERROR(
66  "Already registered the event by casting down to a "
67  "different Event derived class. This means you have an "
68  "Event where A inherits from B and both A and B define "
69  "get_observation_type_and_id_for_registration. This "
70  "behavior is not supported. Please make a separate Event.");
71  }
72  already_registered = true;
73  result =
74  db::apply<typename EventType::observation_registration_tags>(
75  [&derived_class_ptr](const auto&... args) noexcept {
76  return derived_class_ptr
77  ->get_observation_type_and_key_for_registration(
78  args...);
79  },
80  box);
81  }
82  }
83  });
84  return result;
85 }
86 
87 namespace Actions {
88 /*!
89  * \brief Registers this element of a parallel component with the local
90  * `Observer` parallel component for each triggered observation.
91  *
92  * \details This tells the `Observer` to expect data from this component, as
93  * well as whether each observation is a Reduction or Volume observation.
94  * Should be added to the phase dependent action list of the components that
95  * contribute data for volume and reduction observations.
96  *
97  * When this struct is used as an action, the `apply` function will perform the
98  * registration with observers. However, this struct also offers the static
99  * member functions `perform_registration` and `perform_deregistration` that
100  * are needed for either registering when an element is added to a core outside
101  * of initialization or deregistering when an element is being eliminated from a
102  * core. The use of separate functions is necessary to provide an interface
103  * usable outside of iterable actions, e.g. in specialized `pup` functions.
104  */
106  private:
107  template <typename ParallelComponent, typename RegisterOrDeregisterAction,
108  typename DbTagList, typename Metavariables, typename ArrayIndex>
109  static void register_or_deregister_impl(
110  const db::DataBox<DbTagList>& box,
112  const ArrayIndex& array_index) noexcept {
113  auto& observer =
114  *Parallel::get_parallel_component<observers::Observer<Metavariables>>(
115  cache)
116  .ckLocalBranch();
117  std::vector<
119  type_of_observation_and_observation_key_pairs;
120  if constexpr (db::tag_is_retrievable_v<::Tags::EventsAndTriggersBase,
121  db::DataBox<DbTagList>>) {
122  const auto& triggers_and_events =
123  db::get<::Tags::EventsAndTriggersBase>(box);
124  for (const auto& trigger_and_events :
125  triggers_and_events.events_and_triggers()) {
126  for (const auto& event : trigger_and_events.second) {
127  if (auto obs_type_and_obs_key =
128  get_registration_observation_type_and_key(*event, box);
129  obs_type_and_obs_key.has_value()) {
130  type_of_observation_and_observation_key_pairs.push_back(
131  *obs_type_and_obs_key);
132  }
133  }
134  }
135 
136  for (const auto& [type_of_observation, observation_key] :
137  type_of_observation_and_observation_key_pairs) {
138  Parallel::simple_action<RegisterOrDeregisterAction>(
139  observer, observation_key,
143  type_of_observation);
144  }
145  } else {
146  ERROR(
147  "Cannot perform registration of events, "
148  "`::Tags::EventsAndTriggersBase` is not retrievable from the "
149  "DataBox");
150  }
151  }
152 
153  public:
154  template <typename ParallelComponent, typename DbTagList,
155  typename Metavariables, typename ArrayIndex>
156  static void perform_registration(const db::DataBox<DbTagList>& box,
158  const ArrayIndex& array_index) noexcept {
159  register_or_deregister_impl<ParallelComponent,
161  array_index);
162  }
163 
164  template <typename ParallelComponent, typename DbTagList,
165  typename Metavariables, typename ArrayIndex>
166  static void perform_deregistration(
167  const db::DataBox<DbTagList>& box,
169  const ArrayIndex& array_index) noexcept {
170  register_or_deregister_impl<ParallelComponent,
172  array_index);
173  }
174 
175  template <typename DbTagList, typename... InboxTags, typename Metavariables,
176  typename ArrayIndex, typename ActionList,
177  typename ParallelComponent>
178  static std::tuple<db::DataBox<DbTagList>&&> apply(
179  db::DataBox<DbTagList>& box,
180  const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
182  const ArrayIndex& array_index, const ActionList /*meta*/,
183  const ParallelComponent* const /*meta*/) noexcept {
184  perform_registration<ParallelComponent>(box, cache, array_index);
185  return {std::move(box)};
186  }
187 };
188 } // namespace Actions
189 } // namespace observers
observers::Actions::RegisterEventsWithObservers
Registers this element of a parallel component with the local Observer parallel component for each tr...
Definition: RegisterEvents.hpp:105
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
Tags.hpp
std::pair
GlobalCache.hpp
std::vector
std::tuple
observers::Actions::DeregisterContributorWithObserver
Deregister the ArrayComponentId that will no longer send the data to the observer for the given Obser...
Definition: ObserverRegistration.hpp:483
ERROR
#define ERROR(m)
prints an error message to the standard error stream and aborts the program.
Definition: Error.hpp:37
CREATE_HAS_TYPE_ALIAS
#define CREATE_HAS_TYPE_ALIAS(ALIAS_NAME)
Generate a type trait to check if a class has a type alias with a particular name,...
Definition: CreateHasTypeAlias.hpp:27
std::add_pointer_t
Event
Definition: Event.hpp:30
DataBox.hpp
cstddef
tuples::TaggedTuple
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:271
ActionTesting::cache
Parallel::GlobalCache< Metavariables > & cache(MockRuntimeSystem< Metavariables > &runner, const ArrayIndex &array_index) noexcept
Returns the GlobalCache of Component with index array_index.
Definition: MockRuntimeSystemFreeFunctions.hpp:382
Gsl.hpp
optional
observers::ArrayComponentId
An ID type that identifies both the parallel component and the index in the parallel component.
Definition: ArrayComponentId.hpp:27
Parallel::ArrayIndex
The array index used for indexing Chare Arrays, mostly an implementation detail.
Definition: ArrayIndex.hpp:28
unordered_map
TMPL.hpp
observers::Actions::RegisterContributorWithObserver
Register the ArrayComponentId that will send the data to the observer for the given ObservationIdRegi...
Definition: ObserverRegistration.hpp:397