SpECTRE Documentation Coverage Report
Current view: top level - Parallel/PhaseControl - PhaseChange.hpp Hit Total Coverage
Commit: 9a905b0737f373631c1b8e8389b8f26e67fa5313 Lines: 5 9 55.6 %
Date: 2024-03-28 09:03:18
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 <memory>
       7             : #include <optional>
       8             : #include <type_traits>
       9             : #include <utility>
      10             : #include <vector>
      11             : 
      12             : #include "DataStructures/DataBox/DataBox.hpp"
      13             : #include "Parallel/GlobalCache.hpp"
      14             : #include "Parallel/Phase.hpp"
      15             : #include "ParallelAlgorithms/EventsAndTriggers/Trigger.hpp"
      16             : #include "Utilities/CallWithDynamicType.hpp"
      17             : #include "Utilities/Gsl.hpp"
      18             : #include "Utilities/TMPL.hpp"
      19             : #include "Utilities/TaggedTuple.hpp"
      20             : 
      21             : 
      22             : /// Contains utilities for determining control-flow among phases
      23             : namespace PhaseControl {
      24             : /// The possible options for instructing the Main chare in deciding the next
      25             : /// phase to jump to.
      26             : ///
      27             : /// An object of this enum type is packaged with a requested phase in the
      28             : /// `PhaseChange::arbitrate_phase_change` function.
      29           1 : enum ArbitrationStrategy {
      30             :   /// Jump to the requested phase immediately, before considering other
      31             :   /// requested phases.
      32             :   ///
      33             :   /// This will ensure that the requested phase is always run, where
      34             :   /// alternative methods could have 'double-jumps' where the Main chare
      35             :   /// replaces a requested phase immediately without actually entering the
      36             :   /// phase.
      37             :   RunPhaseImmediately,
      38             :   /// After the requested phase is considered, continue considering other
      39             :   /// requests, potentially replacing this request.
      40             :   ///
      41             :   /// This will permit reprocessing the phase-jumps to help with cases where
      42             :   /// multiple phases are simultaneously requested.
      43             :   /// The `PermitAdditionalJumps` permits 'double-jumps' where a requested phase
      44             :   /// is immediately replaced by another phase to jump to.
      45             :   PermitAdditionalJumps
      46             : };
      47             : }  // namespace PhaseControl
      48             : 
      49             : /*!
      50             :  * \brief `PhaseChange` objects determine the storage types and logic for
      51             :  * moving between phases based on runtime data.
      52             :  *
      53             :  * The phase control flow must have the cooperation of each parallel component,
      54             :  * but make phase decisions centrally so that at any point, all components are
      55             :  * in the same phase. The operations needed by the parallel components and by
      56             :  * the Main chare, are:
      57             :  *
      58             :  * 1. Parallel components must select and/or compute the runtime data necessary
      59             :  *    for choosing the next phase, then contribute it to a global reduction to
      60             :  *    the Main component.
      61             :  *    The components must then halt at a globally-valid state for the phase
      62             :  *    change.
      63             :  *    The requirements for the state will vary depending on the phase choices,
      64             :  *    so triggers must be selected appropriately for the `PhaseChange` object.
      65             :  *    For instance, selecting a common slab will usually represent a globally
      66             :  *    well-behaved state for a `DgElementArray`.
      67             :  * 2. On the Main chare, the `PhaseChange` objects must use the collected
      68             :  *    reduction data, or other persistent data stored in
      69             :  *    `phase_change_decision_data` to decide on a phase to request and an
      70             :  *    `PhaseControl::ArbitrationStrategy` to determine how to resolve multiple
      71             :  *    simultaneous requests.
      72             :  *    Additionally, the `PhaseChange` objects must specify initialization
      73             :  *    functions to set the starting state of the tags in
      74             :  *    `phase_change_decision_data` for which they are responsible.
      75             :  *
      76             :  * In addition to the `options` type alias and `static constexpr Options::String
      77             :  * help` variable needed to be option-creatable, a derived class of
      78             :  * `PhaseChange` must specify the type aliases:
      79             :  * - `argument_tags`: A `tmpl::list` of tags from the
      80             :  *   \ref DataBoxGroup "DataBox" to be passed to `contribute_phase_data_impl` as
      81             :  *   const references.
      82             :  * - `return_tags`: A `tmpl::list` of mutable tags from the
      83             :  *   \ref DataBoxGroup "DataBox" to be passed to `contribute_phase_data_impl` as
      84             :  *   `gsl::not_null` pointers. This should be used only for tags that may be
      85             :  *   altered during the `contribute_phase_data_impl` function.
      86             :  * - `phase_change_tags_and_combines`: A `tmpl::list` of tags for
      87             :  *   populating the `phase_change_decision_data` in the Main chare. Each tag in
      88             :  *   this list must also define a `combine_method` and a `main_combine_method`
      89             :  *   for performing the aggregation during reduction.
      90             :  * - `participating_components` (templated on `Metavariables`): A `tmpl::list`
      91             :  *   of components that contribute data during this reduction. This can be used
      92             :  *   to screen out components that will not have the necessary information to
      93             :  *   contribute to the reduction. If all components should participate, this
      94             :  *   type alias can be set to simply `typename Metavariables::component_list`.
      95             :  *
      96             :  * And member functions with signatures:
      97             :  *
      98             :  * ```
      99             :  * template <typename... DecisionTags>
     100             :  * void initialize_phase_data_impl(
     101             :  *     const gsl::not_null<tuples::TaggedTuple<DecisionTags...>*>
     102             :  *         phase_change_decision_data) const;
     103             :  * ```
     104             :  * - Must set all tags in `phase_change_tags_and_combines` to useful
     105             :  *   initial states in the `phase_change_decision_data`.
     106             :  *
     107             :  * ```
     108             :  * template <typename ParallelComponent, typename ArrayIndex>
     109             :  * void contribute_phase_data_impl(
     110             :  *     [DataBox return tags...], [DataBox argument tags...],
     111             :  *     Parallel::GlobalCache<Metavariables>& cache,
     112             :  *     const ArrayIndex& array_index) const;
     113             :  * ```
     114             :  * - Should send any data relevant for the associated phase change decision made
     115             :  *   in `arbitrate_phase_change_impl` to the Main chare via function
     116             :  *   `Parallel::contribute_to_phase_change_reduction`.
     117             :  *
     118             :  * ```
     119             :  * template <typename... DecisionTags, typename Metavariables>
     120             :  * typename std::optional<
     121             :  *     std::pair<Parallel::Phase, ArbitrationStrategy>>
     122             :  * arbitrate_phase_change_impl(
     123             :  *     const gsl::not_null<tuples::TaggedTuple<DecisionTags...>*>
     124             :  *         phase_change_decision_data,
     125             :  *     const Parallel::Phase current_phase,
     126             :  *     const Parallel::GlobalCache<Metavariables>& cache) const;
     127             :  * ```
     128             :  * - Should examine the collected data in `phase_change_decision_data` and
     129             :  *   optionally return a `std::pair` with the desired `Parallel::Phase` and
     130             :  *   an `PhaseControl::ArbitrationStrategy` indicating a method for arbitrating
     131             :  *   multiple simultaneous requests. Alternatively, it may return `std::nullopt`
     132             :  *   to abstain from the phase decision.
     133             :  *   The `arbitrate_phase_change_impl` may (and often will) mutate the
     134             :  *   `phase_change_decision_data`. For instance, it may be desirable to 'reset'
     135             :  *   the data to allow for future jumps associated with the same `PhaseChange`,
     136             :  *   or the `PhaseChange` will describe multiple changes in sequence, and the
     137             :  *   state of that sequential process can be recorded in
     138             :  *   `phase_change_decision_data`.
     139             :  */
     140           1 : struct PhaseChange : public PUP::able {
     141             :  protected:
     142             :   /// \cond
     143             :   PhaseChange() = default;
     144             :   PhaseChange(const PhaseChange&) = default;
     145             :   PhaseChange(PhaseChange&&) = default;
     146             :   PhaseChange& operator=(const PhaseChange&) = default;
     147             :   PhaseChange& operator=(PhaseChange&&) = default;
     148             :   /// \endcond
     149             : 
     150             :  public:
     151           0 :   PhaseChange(CkMigrateMessage* msg) : PUP::able(msg){};
     152             : 
     153           0 :   ~PhaseChange() override = default;
     154             : 
     155           0 :   WRAPPED_PUPable_abstract(PhaseChange);  // NOLINT
     156             : 
     157             :   /// Send data from all `participating_components` to the Main chare for
     158             :   /// determining the next phase.
     159             :   template <typename ParallelComponent, typename DbTags, typename Metavariables,
     160             :             typename ArrayIndex>
     161           1 :   void contribute_phase_data(const gsl::not_null<db::DataBox<DbTags>*> box,
     162             :                              Parallel::GlobalCache<Metavariables>& cache,
     163             :                              const ArrayIndex& array_index) const {
     164             :     using factory_classes =
     165             :         typename Metavariables::factory_creation::factory_classes;
     166             :     call_with_dynamic_type<void, tmpl::at<factory_classes, PhaseChange>>(
     167             :         this, [&box, &cache, &array_index](const auto* const phase_change) {
     168             :           using phase_change_t = typename std::decay_t<decltype(*phase_change)>;
     169             :           if constexpr (tmpl::list_contains_v<
     170             :                             typename phase_change_t::
     171             :                                 template participating_components<
     172             :                                     Metavariables>,
     173             :                             ParallelComponent>) {
     174             :             db::mutate_apply<typename phase_change_t::return_tags,
     175             :                              typename phase_change_t::argument_tags>(
     176             :                 [&phase_change, &cache, &array_index](auto&&... args) {
     177             :                   phase_change
     178             :                       ->template contribute_phase_data_impl<ParallelComponent>(
     179             :                           args..., cache, array_index);
     180             :                 },
     181             :                 box);
     182             :           }
     183             :         });
     184             :   }
     185             : 
     186             :   /// Determine a phase request and `PhaseControl::ArbitrationStrategy` based on
     187             :   /// aggregated `phase_change_decision_data` on the Main Chare.
     188             :   template <typename... DecisionTags, typename Metavariables>
     189             :   std::optional<std::pair<Parallel::Phase, PhaseControl::ArbitrationStrategy>>
     190           1 :   arbitrate_phase_change(
     191             :       const gsl::not_null<tuples::TaggedTuple<DecisionTags...>*>
     192             :           phase_change_decision_data,
     193             :       const Parallel::Phase current_phase,
     194             :       const Parallel::GlobalCache<Metavariables>& cache) const {
     195             :     using factory_classes =
     196             :         typename Metavariables::factory_creation::factory_classes;
     197             :     return call_with_dynamic_type<
     198             :         std::optional<
     199             :             std::pair<Parallel::Phase, PhaseControl::ArbitrationStrategy>>,
     200             :         tmpl::at<factory_classes, PhaseChange>>(
     201             :         this, [&current_phase, &phase_change_decision_data,
     202             :                &cache](const auto* const phase_change) {
     203             :           return phase_change->arbitrate_phase_change_impl(
     204             :               phase_change_decision_data, current_phase, cache);
     205             :         });
     206             :   }
     207             : 
     208             :   /// Initialize the `phase_change_decision_data` on the main chare to starting
     209             :   /// values.
     210             :   template <typename Metavariables, typename... Tags>
     211           1 :   void initialize_phase_data(const gsl::not_null<tuples::TaggedTuple<Tags...>*>
     212             :                                  phase_change_decision_data) const {
     213             :     using factory_classes =
     214             :         typename Metavariables::factory_creation::factory_classes;
     215             :     return call_with_dynamic_type<void, tmpl::at<factory_classes, PhaseChange>>(
     216             :         this, [&phase_change_decision_data](const auto* const phase_change) {
     217             :           return phase_change->initialize_phase_data_impl(
     218             :               phase_change_decision_data);
     219             :         });
     220             :   }
     221             : };

Generated by: LCOV version 1.14