SpECTRE Documentation Coverage Report
Current view: top level - Parallel/PhaseControl - ExecutePhaseChange.hpp Hit Total Coverage
Commit: 058fd9f3a53606b32c6beec17aafdb5fcf4268be Lines: 2 6 33.3 %
Date: 2024-04-27 02:05:51
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             : #include <tuple>
       8             : #include <type_traits>
       9             : #include <utility>
      10             : 
      11             : #include "Parallel/AlgorithmExecution.hpp"
      12             : #include "Parallel/GlobalCache.hpp"
      13             : #include "Parallel/Phase.hpp"
      14             : #include "Parallel/PhaseControl/ContributeToPhaseChangeReduction.hpp"
      15             : #include "Parallel/PhaseControl/PhaseChange.hpp"
      16             : #include "Parallel/PhaseControl/PhaseControlTags.hpp"
      17             : #include "Utilities/Gsl.hpp"
      18             : #include "Utilities/TMPL.hpp"
      19             : #include "Utilities/TaggedTuple.hpp"
      20             : 
      21             : /// \cond
      22             : namespace Tags {
      23             : struct TimeStepId;
      24             : }  // namespace Tags
      25             : namespace db {
      26             : template <typename TagsList>
      27             : class DataBox;
      28             : }  // namespace db
      29             : /// \endcond
      30             : 
      31             : namespace PhaseControl {
      32           0 : namespace Actions {
      33             : 
      34             : /*!
      35             :  * \ingroup ActionsGroup
      36             :  * \brief Check if any triggers are activated, and perform phase changes as
      37             :  * needed.
      38             :  *
      39             :  * This action is intended to be executed on every component that repeatedly
      40             :  * runs iterable actions that would need to halt during a phase change. This
      41             :  * action sends data to the Main chare via a reduction.
      42             :  *
      43             :  * This action iterates over the `Tags::PhaseChangeAndTriggers`, sending
      44             :  * reduction data for the phase decision for each triggered `PhaseChange`, then
      45             :  * halts the algorithm execution so that the `Main` chare can make a phase
      46             :  * decision if any were triggered.
      47             :  *
      48             :  * Uses:
      49             :  * - GlobalCache: `Tags::PhaseChangeAndTriggers`
      50             :  * - DataBox: As specified by the `PhaseChange` option-created objects.
      51             :  *   - `PhaseChange` objects are permitted to perform mutations on the
      52             :  *     \ref DataBoxGroup "DataBox" to store persistent state information.
      53             :  */
      54           1 : struct ExecutePhaseChange {
      55           0 :   using const_global_cache_tags =
      56             :       tmpl::list<PhaseControl::Tags::PhaseChangeAndTriggers>;
      57             : 
      58             :   template <typename DbTags, typename... InboxTags, typename Metavariables,
      59             :             typename ArrayIndex, typename ActionList,
      60             :             typename ParallelComponent>
      61           0 :   static Parallel::iterable_action_return_t apply(
      62             :       db::DataBox<DbTags>& box,
      63             :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
      64             :       Parallel::GlobalCache<Metavariables>& cache,
      65             :       const ArrayIndex& array_index, const ActionList /*meta*/,
      66             :       const ParallelComponent* const /*component*/) {
      67             :     if constexpr (db::tag_is_retrievable_v<::Tags::TimeStepId,
      68             :                                            db::DataBox<DbTags>>) {
      69             :       if (not db::get<::Tags::TimeStepId>(box).is_at_slab_boundary()) {
      70             :         return {Parallel::AlgorithmExecution::Continue, std::nullopt};
      71             :       }
      72             :     }
      73             :     const auto& phase_change_and_triggers =
      74             :         Parallel::get<Tags::PhaseChangeAndTriggers>(cache);
      75             :     bool should_halt = false;
      76             :     for (const auto& trigger_and_phase_changes : phase_change_and_triggers) {
      77             :       const auto& trigger = trigger_and_phase_changes.trigger;
      78             :       if (trigger->is_triggered(box)) {
      79             :         const auto& phase_changes = trigger_and_phase_changes.phase_changes;
      80             :         for (const auto& phase_change : phase_changes) {
      81             :           phase_change->template contribute_phase_data<ParallelComponent>(
      82             :               make_not_null(&box), cache, array_index);
      83             :         }
      84             :         should_halt = true;
      85             :       }
      86             :     }
      87             :     // if we halt, we need to make sure that the Main chare knows that it is
      88             :     // because we are requesting phase change arbitration, regardless of what
      89             :     // data was actually sent to make that decision.
      90             :     if (should_halt) {
      91             :       if constexpr (std::is_same_v<typename ParallelComponent::chare_type,
      92             :                     Parallel::Algorithms::Array>) {
      93             :         Parallel::contribute_to_phase_change_reduction<ParallelComponent>(
      94             :             tuples::TaggedTuple<TagsAndCombines::UsePhaseChangeArbitration>{
      95             :                 true},
      96             :             cache, array_index);
      97             :       } else {
      98             :         Parallel::contribute_to_phase_change_reduction<ParallelComponent>(
      99             :             tuples::TaggedTuple<TagsAndCombines::UsePhaseChangeArbitration>{
     100             :                 true},
     101             :             cache);
     102             :       }
     103             :     }
     104             :     return {should_halt ? Parallel::AlgorithmExecution::Halt
     105             :                         : Parallel::AlgorithmExecution::Continue,
     106             :             std::nullopt};
     107             :   }
     108             : };
     109             : }  // namespace Actions
     110             : 
     111             : /*!
     112             :  * \brief Use the runtime data aggregated in `phase_change_decision_data` to
     113             :  * decide which phase to execute next.
     114             :  *
     115             :  * \details This function will iterate through each of the option-created pairs
     116             :  * of `PhaseChange`s, and obtain from each a
     117             :  * `std::optional<std::pair<Parallel::Phase,
     118             :  * PhaseControl::ArbitrationStrategy>`. Any `std::nullopt` is skipped. If all
     119             :  * `PhaseChange`s provide `std::nullopt`, the phase will either keep its
     120             :  * current value (if the halt was caused by one of the triggers associated with
     121             :  * an  option-created `PhaseChange`), or this function will return a
     122             :  * `std::nullopt` as well (otherwise), indicating that the phase should proceed
     123             :  * according to other information, such as global ordering.
     124             :  *
     125             :  * In the case of a `PhaseControl::ArbitrationStrategy::RunPhaseImmediately`,
     126             :  * the first such return value is immediately run, and no further `PhaseChange`s
     127             :  * are queried for their input.
     128             :  *
     129             :  * \note There can be cases where multiple triggers activate, and/or multiple
     130             :  * `PhaseChange` objects have data in a state for which they would request a
     131             :  * specific phase. When multiple phases are requested, arbitration will
     132             :  * proceed in order of appearance in the `PhaseChangeAndTriggers`, determined
     133             :  * from the input file options. Therefore, if that order of execution is
     134             :  * important for the logic of the executable, the input file ordering and
     135             :  * `ArbitrationStrategy` must be chosen carefully.
     136             :  */
     137             : template <typename... DecisionTags, typename Metavariables>
     138           1 : typename std::optional<Parallel::Phase> arbitrate_phase_change(
     139             :     const gsl::not_null<tuples::TaggedTuple<DecisionTags...>*>
     140             :         phase_change_decision_data,
     141             :     Parallel::Phase current_phase,
     142             :     const Parallel::GlobalCache<Metavariables>& cache) {
     143             :   if constexpr (tmpl::list_contains_v<typename Parallel::GlobalCache<
     144             :                                           Metavariables>::const_tags_list,
     145             :                                       Tags::PhaseChangeAndTriggers>) {
     146             :     const auto& phase_change_and_triggers =
     147             :         Parallel::get<Tags::PhaseChangeAndTriggers>(cache);
     148             :     bool phase_chosen = false;
     149             :     for (const auto& trigger_and_phase_changes : phase_change_and_triggers) {
     150             :       for (const auto& phase_change : trigger_and_phase_changes.phase_changes) {
     151             :         const auto phase_result = phase_change->arbitrate_phase_change(
     152             :             phase_change_decision_data, current_phase, cache);
     153             :         if (phase_result.has_value()) {
     154             :           if (phase_result.value().second ==
     155             :               ArbitrationStrategy::RunPhaseImmediately) {
     156             :             tuples::get<TagsAndCombines::UsePhaseChangeArbitration>(
     157             :                 *phase_change_decision_data) = false;
     158             :             return phase_result.value().first;
     159             :           }
     160             :           current_phase = phase_result.value().first;
     161             :           phase_chosen = true;
     162             :         }
     163             :       }
     164             :     }
     165             :     if (tuples::get<TagsAndCombines::UsePhaseChangeArbitration>(
     166             :             *phase_change_decision_data) == false and
     167             :         not phase_chosen) {
     168             :       return std::nullopt;
     169             :     }
     170             :     // if no phase change object suggests a specific phase, return to execution
     171             :     // in the current phase.
     172             :     tuples::get<TagsAndCombines::UsePhaseChangeArbitration>(
     173             :         *phase_change_decision_data) = false;
     174             :     return current_phase;
     175             :   } else {
     176             :     (void)phase_change_decision_data;
     177             :     (void)current_phase;
     178             :     (void)cache;
     179             :     return std::nullopt;
     180             :   }
     181             : }
     182             : }  // namespace PhaseControl

Generated by: LCOV version 1.14