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"
18 #include "Parallel/Tags/Metavariables.hpp"
20 #include "Utilities/Gsl.hpp"
21 #include "Utilities/TMPL.hpp"
22 #include "Utilities/TaggedTuple.hpp"
23 #include "Utilities/TypeTraits/CreateHasTypeAlias.hpp"
24 
25 /// \cond
26 namespace evolution::Tags {
27 struct EventsAndDenseTriggers;
28 } // namespace evolution::Tags
29 /// \endcond
30 
31 namespace observers {
32 namespace detail {
33 CREATE_HAS_TYPE_ALIAS(observation_registration_tags)
34 CREATE_HAS_TYPE_ALIAS_V(observation_registration_tags)
35 } // namespace detail
36 
37 /*!
38  * \brief Retrieves the observation type and key from an event, if it is an
39  * event that needs to register with the observers.
40  *
41  * The event must define an `observation_registration_tags` type alias that is a
42  * `tmpl::list<>` of all the tags from the DataBox needed to construct the
43  * `ObservationKey`, and a `get_observation_type_and_key_for_registration`
44  * member function if it is to be registered automatically.
45  */
46 template <typename DbTagsList>
49 get_registration_observation_type_and_key(
50  const Event& event, const db::DataBox<DbTagsList>& box) noexcept {
53  result{};
54  bool already_registered = false;
55  using factory_classes =
57  box))>::factory_creation::factory_classes;
58  tmpl::for_each<tmpl::at<factory_classes, Event>>(
59  [&already_registered, &box, &event, &result](auto event_type_v) noexcept {
60  using EventType = typename decltype(event_type_v)::type;
61  if constexpr (detail::has_observation_registration_tags_v<EventType>) {
62  // We require that each event for which
63  // `has_observation_registration_tags_v` is true be downcastable to
64  // only *one* event type. This is checked by the `already_registered`
65  // bool and the error message below. We need to downcast because we do
66  // not want to impose that every event be registerable with the
67  // IO/observer components. `dynamic_cast` returns a `nullptr` in the
68  // case that the downcast failed, which we check for to see if we can
69  // call the `get_observation_type_and_key_for_registration` function.
70  const auto* const derived_class_ptr =
71  dynamic_cast<const EventType*>(&event);
72  if (derived_class_ptr != nullptr) {
73  if (already_registered) {
74  ERROR(
75  "Already registered the event by casting down to a "
76  "different Event derived class. This means you have an "
77  "Event where A inherits from B and both A and B define "
78  "get_observation_type_and_id_for_registration. This "
79  "behavior is not supported. Please make a separate Event.");
80  }
81  already_registered = true;
82  result =
83  db::apply<typename EventType::observation_registration_tags>(
84  [&derived_class_ptr](const auto&... args) noexcept {
85  return derived_class_ptr
86  ->get_observation_type_and_key_for_registration(
87  args...);
88  },
89  box);
90  }
91  }
92  });
93  return result;
94 }
95 
96 namespace Actions {
97 /*!
98  * \brief Registers this element of a parallel component with the local
99  * `Observer` parallel component for each triggered observation.
100  *
101  * \details This tells the `Observer` to expect data from this component, as
102  * well as whether each observation is a Reduction or Volume observation.
103  * Should be added to the phase dependent action list of the components that
104  * contribute data for volume and reduction observations.
105  *
106  * When this struct is used as an action, the `apply` function will perform the
107  * registration with observers. However, this struct also offers the static
108  * member functions `perform_registration` and `perform_deregistration` that
109  * are needed for either registering when an element is added to a core outside
110  * of initialization or deregistering when an element is being eliminated from a
111  * core. The use of separate functions is necessary to provide an interface
112  * usable outside of iterable actions, e.g. in specialized `pup` functions.
113  */
115  private:
116  template <typename ParallelComponent, typename RegisterOrDeregisterAction,
117  typename DbTagList, typename Metavariables, typename ArrayIndex>
118  static void register_or_deregister_impl(
119  const db::DataBox<DbTagList>& box,
121  const ArrayIndex& array_index) noexcept {
122  auto& observer =
123  *Parallel::get_parallel_component<observers::Observer<Metavariables>>(
124  cache)
125  .ckLocalBranch();
126  std::vector<
128  type_of_observation_and_observation_key_pairs;
129  const auto collect_observations =
130  [&box, &type_of_observation_and_observation_key_pairs](
131  const auto& event) noexcept {
132  if (auto obs_type_and_obs_key =
133  get_registration_observation_type_and_key(event, box);
134  obs_type_and_obs_key.has_value()) {
135  type_of_observation_and_observation_key_pairs.push_back(
136  *obs_type_and_obs_key);
137  }
138  };
139 
140 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 10
141  (void)collect_observations;
142 #endif // defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 10
143 
145  db::DataBox<DbTagList>>) {
146  const auto& triggers_and_events = db::get<::Tags::EventsAndTriggers>(box);
147  triggers_and_events.for_each_event(collect_observations);
148  }
149 
150  if constexpr (db::tag_is_retrievable_v<
152  db::DataBox<DbTagList>>) {
153  const auto& triggers_and_events =
154  db::get<evolution::Tags::EventsAndDenseTriggers>(box);
155  triggers_and_events.for_each_event(collect_observations);
156  }
157 
158  for (const auto& [type_of_observation, observation_key] :
159  type_of_observation_and_observation_key_pairs) {
160  Parallel::simple_action<RegisterOrDeregisterAction>(
161  observer, observation_key,
165  type_of_observation);
166  }
167  }
168 
169  public:
170  template <typename ParallelComponent, typename DbTagList,
171  typename Metavariables, typename ArrayIndex>
172  static void perform_registration(const db::DataBox<DbTagList>& box,
174  const ArrayIndex& array_index) noexcept {
175  register_or_deregister_impl<ParallelComponent,
177  array_index);
178  }
179 
180  template <typename ParallelComponent, typename DbTagList,
181  typename Metavariables, typename ArrayIndex>
182  static void perform_deregistration(
183  const db::DataBox<DbTagList>& box,
185  const ArrayIndex& array_index) noexcept {
186  register_or_deregister_impl<ParallelComponent,
188  array_index);
189  }
190 
191  template <typename DbTagList, typename... InboxTags, typename Metavariables,
192  typename ArrayIndex, typename ActionList,
193  typename ParallelComponent>
194  static std::tuple<db::DataBox<DbTagList>&&> apply(
195  db::DataBox<DbTagList>& box,
196  const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
198  const ArrayIndex& array_index, const ActionList /*meta*/,
199  const ParallelComponent* const /*meta*/) noexcept {
200  perform_registration<ParallelComponent>(box, cache, array_index);
201  return {std::move(box)};
202  }
203 };
204 } // namespace Actions
205 } // namespace observers
observers::Actions::RegisterEventsWithObservers
Registers this element of a parallel component with the local Observer parallel component for each tr...
Definition: RegisterEvents.hpp:114
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
evolution::Tags::EventsAndDenseTriggers
The Events to run based on DenseTriggers.
Definition: Tags.hpp:30
Tags.hpp
std::pair
GlobalCache.hpp
db::tag_is_retrievable_v
constexpr bool tag_is_retrievable_v
Definition: DataBox.hpp:61
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:19
DataBox.hpp
cstddef
tuples::TaggedTuple
An associative container that is indexed by structs.
Definition: TaggedTuple.hpp:271
std::decay_t
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
Tags::EventsAndTriggers
Definition: Tags.hpp:51
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
CREATE_HAS_TYPE_ALIAS_V
#define CREATE_HAS_TYPE_ALIAS_V(ALIAS_NAME)
Generate a type trait to check if a class has a type alias with a particular name,...
Definition: CreateHasTypeAlias.hpp:39
TMPL.hpp
observers::Actions::RegisterContributorWithObserver
Register the ArrayComponentId that will send the data to the observer for the given ObservationIdRegi...
Definition: ObserverRegistration.hpp:397