SpECTRE Documentation Coverage Report
Current view: top level - Parallel/PhaseControl - ExecutePhaseChange.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 33.3 % 6 2
Test Date: 2026-10-22 17:29:42
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 "DataStructures/TaggedTuple.hpp"
      12              : #include "Parallel/AlgorithmExecution.hpp"
      13              : #include "Parallel/GlobalCache.hpp"
      14              : #include "Parallel/Phase.hpp"
      15              : #include "Parallel/PhaseControl/ContributeToPhaseChangeReduction.hpp"
      16              : #include "Parallel/PhaseControl/PhaseChange.hpp"
      17              : #include "Parallel/PhaseControl/PhaseControlTags.hpp"
      18              : #include "Utilities/Gsl.hpp"
      19              : #include "Utilities/TMPL.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 2.0-1