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

Generated by: LCOV version 1.14