SpECTRE Documentation Coverage Report
Current view: top level - IO/Observer/Actions - RegisterEvents.hpp Hit Total Coverage
Commit: aabde07399ba7837e5db64eedfd0a21f31f96922 Lines: 2 7 28.6 %
Date: 2024-04-26 02:38:13
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <optional>
       7             : 
       8             : #include "DataStructures/DataBox/DataBox.hpp"
       9             : #include "IO/Observer/Actions/ObserverRegistration.hpp"
      10             : #include "IO/Observer/ObserverComponent.hpp"
      11             : #include "IO/Observer/Tags.hpp"
      12             : #include "IO/Observer/TypeOfObservation.hpp"
      13             : #include "Parallel/AlgorithmExecution.hpp"
      14             : #include "Parallel/ArrayComponentId.hpp"
      15             : #include "Parallel/GlobalCache.hpp"
      16             : #include "Parallel/Invoke.hpp"
      17             : #include "Parallel/Local.hpp"
      18             : #include "Parallel/Protocols/ElementRegistrar.hpp"
      19             : #include "Parallel/Tags/Metavariables.hpp"
      20             : #include "Parallel/TypeTraits.hpp"
      21             : #include "ParallelAlgorithms/EventsAndDenseTriggers/Tags.hpp"
      22             : #include "ParallelAlgorithms/EventsAndTriggers/Tags.hpp"
      23             : #include "Utilities/ProtocolHelpers.hpp"
      24             : #include "Utilities/TMPL.hpp"
      25             : #include "Utilities/TaggedTuple.hpp"
      26             : #include "Utilities/TypeTraits/CreateHasTypeAlias.hpp"
      27             : 
      28             : namespace observers {
      29             : namespace detail {
      30             : CREATE_HAS_TYPE_ALIAS(observation_registration_tags)
      31             : CREATE_HAS_TYPE_ALIAS_V(observation_registration_tags)
      32             : }  // namespace detail
      33             : 
      34             : /*!
      35             :  * \brief Retrieves the observation type and key from an event, if it is an
      36             :  * event that needs to register with the observers.
      37             :  *
      38             :  * The event must define an `observation_registration_tags` type alias that is a
      39             :  * `tmpl::list<>` of all the tags from the DataBox needed to construct the
      40             :  * `ObservationKey`, and a `get_observation_type_and_key_for_registration`
      41             :  * member function if it is to be registered automatically.
      42             :  */
      43             : template <typename DbTagsList>
      44             : std::optional<
      45             :     std::pair<::observers::TypeOfObservation, ::observers::ObservationKey>>
      46           1 : get_registration_observation_type_and_key(const Event& event,
      47             :                                           const db::DataBox<DbTagsList>& box) {
      48             :   std::optional<
      49             :       std::pair<::observers::TypeOfObservation, ::observers::ObservationKey>>
      50             :       result{};
      51             :   bool already_registered = false;
      52             :   using factory_classes =
      53             :       typename std::decay_t<decltype(db::get<Parallel::Tags::Metavariables>(
      54             :           box))>::factory_creation::factory_classes;
      55             :   tmpl::for_each<tmpl::at<factory_classes, Event>>(
      56             :       [&already_registered, &box, &event, &result](auto event_type_v) {
      57             :         using EventType = typename decltype(event_type_v)::type;
      58             :         if constexpr (detail::has_observation_registration_tags_v<EventType>) {
      59             :           // We require that each event for which
      60             :           // `has_observation_registration_tags_v` is true be downcastable to
      61             :           // only *one* event type. This is checked by the `already_registered`
      62             :           // bool and the error message below. We need to downcast because we do
      63             :           // not want to impose that every event be registerable with the
      64             :           // IO/observer components. `dynamic_cast` returns a `nullptr` in the
      65             :           // case that the downcast failed, which we check for to see if we can
      66             :           // call the `get_observation_type_and_key_for_registration` function.
      67             :           const auto* const derived_class_ptr =
      68             :               dynamic_cast<const EventType*>(&event);
      69             :           if (derived_class_ptr != nullptr) {
      70             :             if (already_registered) {
      71             :               ERROR(
      72             :                   "Already registered the event by casting down to a "
      73             :                   "different Event derived class. This means you have an "
      74             :                   "Event where A inherits from B and both A and B define "
      75             :                   "get_observation_type_and_id_for_registration. This "
      76             :                   "behavior is not supported. Please make a separate Event.");
      77             :             }
      78             :             already_registered = true;
      79             :             result =
      80             :                 db::apply<typename EventType::observation_registration_tags>(
      81             :                     [&derived_class_ptr](const auto&... args) {
      82             :                       return derived_class_ptr
      83             :                           ->get_observation_type_and_key_for_registration(
      84             :                               args...);
      85             :                     },
      86             :                     box);
      87             :           }
      88             :         }
      89             :       });
      90             :   return result;
      91             : }
      92             : 
      93             : namespace Actions {
      94             : /*!
      95             :  * \brief Registers this element of a parallel component with the local
      96             :  * `Observer` parallel component for each triggered observation.
      97             :  *
      98             :  * \details This tells the `Observer` to expect data from this component, as
      99             :  * well as whether each observation is a Reduction or Volume observation.
     100             :  * Should be added to the phase dependent action list of the components that
     101             :  * contribute data for volume and reduction observations.
     102             :  *
     103             :  * When this struct is used as an action, the `apply` function will perform the
     104             :  * registration with observers. However, this struct also offers the static
     105             :  * member functions `perform_registration` and `perform_deregistration` that
     106             :  * are needed for either registering when an element is added to a core outside
     107             :  * of initialization or deregistering when an element is being eliminated from a
     108             :  * core. The use of separate functions is necessary to provide an interface
     109             :  * usable outside of iterable actions, e.g. in specialized `pup` functions.
     110             :  */
     111           1 : struct RegisterEventsWithObservers
     112             :     : tt::ConformsTo<Parallel::protocols::ElementRegistrar> {
     113             :  private:
     114             :   template <typename ParallelComponent, typename RegisterOrDeregisterAction,
     115             :             typename DbTagList, typename Metavariables, typename ArrayIndex>
     116           0 :   static void register_or_deregister_impl(
     117             :       const db::DataBox<DbTagList>& box,
     118             :       Parallel::GlobalCache<Metavariables>& cache,
     119             :       const ArrayIndex& array_index) {
     120             :     std::vector<
     121             :         std::pair<observers::TypeOfObservation, observers::ObservationKey>>
     122             :         type_of_observation_and_observation_key_pairs;
     123             :     const auto collect_observations =
     124             :         [&box,
     125             :          &type_of_observation_and_observation_key_pairs](const auto& event) {
     126             :           if (auto obs_type_and_obs_key =
     127             :                   get_registration_observation_type_and_key(event, box);
     128             :               obs_type_and_obs_key.has_value()) {
     129             :             type_of_observation_and_observation_key_pairs.push_back(
     130             :                 *obs_type_and_obs_key);
     131             :           }
     132             :         };
     133             : 
     134             : #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 10
     135             :     (void)collect_observations;
     136             : #endif  // defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 10
     137             : 
     138             :     if constexpr (db::tag_is_retrievable_v<::Tags::EventsAndTriggers,
     139             :                                            db::DataBox<DbTagList>>) {
     140             :       const auto& triggers_and_events = db::get<::Tags::EventsAndTriggers>(box);
     141             :       triggers_and_events.for_each_event(collect_observations);
     142             :     }
     143             : 
     144             :     if constexpr (db::tag_is_retrievable_v<::Tags::EventsAndDenseTriggers,
     145             :                                            db::DataBox<DbTagList>>) {
     146             :       const auto& triggers_and_events =
     147             :           db::get<::Tags::EventsAndDenseTriggers>(box);
     148             :       triggers_and_events.for_each_event(collect_observations);
     149             :     }
     150             : 
     151             :     if constexpr (db::tag_is_retrievable_v<::Tags::EventsRunAtCleanup,
     152             :                                            db::DataBox<DbTagList>>) {
     153             :       for (const auto& event : db::get<::Tags::EventsRunAtCleanup>(box)) {
     154             :         collect_observations(*event);
     155             :       }
     156             :     }
     157             : 
     158             :     if constexpr (Parallel::is_nodegroup_v<ParallelComponent>) {
     159             :       using volume_register_action =
     160             :           tmpl::conditional_t<std::is_same_v<RegisterOrDeregisterAction,
     161             :                                              RegisterContributorWithObserver>,
     162             :                               RegisterVolumeContributorWithObserverWriter,
     163             :                               DeregisterVolumeContributorWithObserverWriter>;
     164             :       using reduction_register_action =
     165             :           tmpl::conditional_t<std::is_same_v<RegisterOrDeregisterAction,
     166             :                                              RegisterContributorWithObserver>,
     167             :                               RegisterReductionContributorWithObserverWriter,
     168             :                               DeregisterReductionContributorWithObserverWriter>;
     169             :       auto* observer_writer = Parallel::local_branch(
     170             :           Parallel::get_parallel_component<
     171             :               observers::ObserverWriter<Metavariables>>(cache));
     172             :       ASSERT(observer_writer != nullptr,
     173             :              "The observer writer component should be valid. This is an "
     174             :              "internal bug.");
     175             :       for (const auto& [type_of_observation, observation_key] :
     176             :            type_of_observation_and_observation_key_pairs) {
     177             :         switch (type_of_observation) {
     178             :           case TypeOfObservation::Reduction:
     179             :             Parallel::simple_action<reduction_register_action>(
     180             :                 *observer_writer, observation_key,
     181             :                 Parallel::ArrayComponentId{
     182             :                     std::add_pointer_t<ParallelComponent>{nullptr},
     183             :                     Parallel::ArrayIndex<ArrayIndex>(array_index)});
     184             :             break;
     185             :           case TypeOfObservation::Volume:
     186             :             Parallel::simple_action<volume_register_action>(
     187             :                 *observer_writer, observation_key,
     188             :                 Parallel::ArrayComponentId{
     189             :                     std::add_pointer_t<ParallelComponent>{nullptr},
     190             :                     Parallel::ArrayIndex<ArrayIndex>(array_index)});
     191             :             break;
     192             :           default:
     193             :             ERROR(
     194             :                 "Attempting to deregister an unknown TypeOfObservation. "
     195             :                 "Should be one of 'Reduction' or 'Volume'");
     196             :         };
     197             :       }
     198             :     } else {
     199             :       static_assert(Parallel::is_array_v<ParallelComponent>);
     200             : 
     201             :       for (const auto& [type_of_observation, observation_key] :
     202             :            type_of_observation_and_observation_key_pairs) {
     203             :         auto& observer =
     204             :             *Parallel::local_branch(Parallel::get_parallel_component<
     205             :                                     observers::Observer<Metavariables>>(cache));
     206             :         Parallel::simple_action<RegisterOrDeregisterAction>(
     207             :             observer, observation_key,
     208             :             Parallel::ArrayComponentId(
     209             :                 std::add_pointer_t<ParallelComponent>{nullptr},
     210             :                 Parallel::ArrayIndex<std::decay_t<ArrayIndex>>{array_index}),
     211             :             type_of_observation);
     212             :       }
     213             :     }
     214             :   }
     215             : 
     216             :  public:  // ElementRegistrar protocol
     217             :   template <typename ParallelComponent, typename DbTagList,
     218             :             typename Metavariables, typename ArrayIndex>
     219           0 :   static void perform_registration(const db::DataBox<DbTagList>& box,
     220             :                                    Parallel::GlobalCache<Metavariables>& cache,
     221             :                                    const ArrayIndex& array_index) {
     222             :     register_or_deregister_impl<ParallelComponent,
     223             :                                 RegisterContributorWithObserver>(box, cache,
     224             :                                                                  array_index);
     225             :   }
     226             : 
     227             :   template <typename ParallelComponent, typename DbTagList,
     228             :             typename Metavariables, typename ArrayIndex>
     229           0 :   static void perform_deregistration(
     230             :       const db::DataBox<DbTagList>& box,
     231             :       Parallel::GlobalCache<Metavariables>& cache,
     232             :       const ArrayIndex& array_index) {
     233             :     register_or_deregister_impl<ParallelComponent,
     234             :                                 DeregisterContributorWithObserver>(box, cache,
     235             :                                                                    array_index);
     236             :   }
     237             : 
     238             :  public:  // Iterable action
     239             :   template <typename DbTagList, typename... InboxTags, typename Metavariables,
     240             :             typename ArrayIndex, typename ActionList,
     241             :             typename ParallelComponent>
     242           0 :   static Parallel::iterable_action_return_t apply(
     243             :       db::DataBox<DbTagList>& box,
     244             :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     245             :       Parallel::GlobalCache<Metavariables>& cache,
     246             :       const ArrayIndex& array_index, const ActionList /*meta*/,
     247             :       const ParallelComponent* const /*meta*/) {
     248             :     perform_registration<ParallelComponent>(box, cache, array_index);
     249             :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     250             :   }
     251             : };
     252             : }  // namespace Actions
     253             : }  // namespace observers

Generated by: LCOV version 1.14