SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/Actions - FunctionsOfTimeAreReady.hpp Hit Total Coverage
Commit: 361cb8d8406bb752684a5f31c27320ec444a50e3 Lines: 5 12 41.7 %
Date: 2025-11-09 02:02:04
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 <array>
       7             : #include <cstddef>
       8             : #include <memory>
       9             : #include <optional>
      10             : #include <string>
      11             : #include <tuple>
      12             : #include <unordered_map>
      13             : #include <unordered_set>
      14             : #include <utility>
      15             : 
      16             : #include "DataStructures/DataBox/DataBox.hpp"
      17             : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp"
      18             : #include "Parallel/AlgorithmExecution.hpp"
      19             : #include "Parallel/ArrayCollection/IsDgElementCollection.hpp"
      20             : #include "Parallel/ArrayCollection/PerformAlgorithmOnElement.hpp"
      21             : #include "Parallel/ArrayCollection/Tags/ElementLocations.hpp"
      22             : #include "Parallel/ArrayComponentId.hpp"
      23             : #include "Parallel/Callback.hpp"
      24             : #include "Parallel/GlobalCache.hpp"
      25             : #include "Parallel/Info.hpp"
      26             : #include "Parallel/ParallelComponentHelpers.hpp"
      27             : #include "ParallelAlgorithms/Actions/GetItemFromDistributedObject.hpp"
      28             : #include "Utilities/Algorithm.hpp"
      29             : #include "Utilities/ErrorHandling/Assert.hpp"
      30             : #include "Utilities/StdHelpers.hpp"
      31             : 
      32             : /// \cond
      33             : namespace Tags {
      34             : struct Time;
      35             : }  // namespace Tags
      36             : namespace domain::Tags {
      37             : struct FunctionsOfTime;
      38             : }  // namespace domain::Tags
      39             : namespace tuples {
      40             : template <class... Tags>
      41             : class TaggedTuple;
      42             : }  // namespace tuples
      43             : /// \endcond
      44             : 
      45             : namespace domain {
      46             : namespace detail {
      47             : template <typename CacheTag, typename Callback, typename Metavariables,
      48             :           typename ArrayIndex, typename Component, typename... Args>
      49             : bool functions_of_time_are_ready_impl(
      50             :     Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
      51             :     const Component* /*meta*/, const double time,
      52             :     const std::optional<std::unordered_set<std::string>>& functions_to_check,
      53             :     Args&&... args) {
      54             :   if constexpr (Parallel::is_in_mutable_global_cache<Metavariables, CacheTag>) {
      55             :     const auto& proxy =
      56             :         ::Parallel::get_parallel_component<Component>(cache)[array_index];
      57             :     const Parallel::ArrayComponentId array_component_id =
      58             :         [&]() -> Parallel::ArrayComponentId {
      59             :       if constexpr (Parallel::is_dg_element_collection_v<Component>) {
      60             :         static_assert(
      61             :             sizeof...(args) == 1,
      62             :             "This currently assumes the only argument is the ElementId. If you "
      63             :             "need extra arguments, this can be generalized. We need the "
      64             :             "ElementId instead of the array_index (which is the nodegroup ID) "
      65             :             "since each ArrayComponentId is only allowed to register one "
      66             :             "callback, additional ones are ignored. This means of a "
      67             :             "DgElementCollection only 1 callback _per node_ would be "
      68             :             "registered, while we need 1 callback for each element. An "
      69             :             "alternative approach would be to have the callback be a broadcast "
      70             :             "to all elements instead of one specific one.");
      71             :         static_assert((std::is_same_v<ElementId<Metavariables::volume_dim>,
      72             :                                       std::decay_t<Args>> and
      73             :                        ...));
      74             :         return Parallel::make_array_component_id<Component>(args...);
      75             :       } else {
      76             :         return Parallel::make_array_component_id<Component>(array_index);
      77             :       }
      78             :     }();
      79             : 
      80             :     return Parallel::mutable_cache_item_is_ready<CacheTag>(
      81             :         cache, array_component_id,
      82             :         [&functions_to_check, &proxy, &time,
      83             :          &args...](const std::unordered_map<
      84             :                    std::string,
      85             :                    std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
      86             :                        functions_of_time) {
      87             :           using ::operator<<;
      88             :           ASSERT(
      89             :               alg::all_of(
      90             :                   functions_to_check.value_or(
      91             :                       std::unordered_set<std::string>{}),
      92             :                   [&functions_of_time](const std::string& function_to_check) {
      93             :                     return functions_of_time.count(function_to_check) == 1;
      94             :                   }),
      95             :               "Not all functions to check ("
      96             :                   << functions_to_check.value() << ") are in the global cache ("
      97             :                   << keys_of(functions_of_time) << ")");
      98             :           for (const auto& [name, f_of_t] : functions_of_time) {
      99             :             if (functions_to_check.has_value() and
     100             :                 functions_to_check->count(name) == 0) {
     101             :               continue;
     102             :             }
     103             :             const double expiration_time = f_of_t->time_bounds()[1];
     104             :             if (time > expiration_time) {
     105             :               return std::unique_ptr<Parallel::Callback>(
     106             :                   new Callback(proxy, std::forward<Args>(args)...));
     107             :             }
     108             :           }
     109             :           return std::unique_ptr<Parallel::Callback>{};
     110             :         });
     111             :   } else {
     112             :     (void)cache;
     113             :     (void)array_index;
     114             :     (void)time;
     115             :     (void)functions_to_check;
     116             :     EXPAND_PACK_LEFT_TO_RIGHT((void)args);
     117             :     return true;
     118             :   }
     119             : }
     120             : }  // namespace detail
     121             : 
     122             : /// \ingroup ComputationalDomainGroup
     123             : /// Check that functions of time are up-to-date.
     124             : ///
     125             : /// Check that functions of time in \p CacheTag with names in \p
     126             : /// functions_to_check are ready at time \p time.  If  \p functions_to_check is
     127             : /// a `std::nullopt`, checks all functions in \p CacheTag.  If any function is
     128             : /// not ready, schedules a `Parallel::SimpleActionCallback` with the GlobalCache
     129             : /// which calls the simple action passed in as a template parameter. The `Args`
     130             : /// are forwareded to the callback.
     131             : template <typename CacheTag, typename SimpleAction, typename Metavariables,
     132             :           typename ArrayIndex, typename Component, typename... Args>
     133           1 : bool functions_of_time_are_ready_simple_action_callback(
     134             :     Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
     135             :     const Component* component_p, const double time,
     136             :     const std::optional<std::unordered_set<std::string>>& functions_to_check,
     137             :     Args&&... args) {
     138             :   using ProxyType =
     139             :       std::decay_t<decltype(::Parallel::get_parallel_component<Component>(
     140             :           cache)[array_index])>;
     141             :   return detail::functions_of_time_are_ready_impl<
     142             :       CacheTag,
     143             :       Parallel::SimpleActionCallback<SimpleAction, ProxyType, Args...>>(
     144             :       cache, array_index, component_p, time, functions_to_check,
     145             :       std::forward<Args>(args)...);
     146             : }
     147             : 
     148             : /// \ingroup ComputationalDomainGroup
     149             : /// Check that functions of time are up-to-date.
     150             : ///
     151             : /// Check that functions of time in \p CacheTag with names in \p
     152             : /// functions_to_check are ready at time \p time.  If  \p functions_to_check is
     153             : /// a `std::nullopt`, checks all functions in \p CacheTag.  If any function is
     154             : /// not ready, schedules a `Parallel::ThreadedActionCallback` with the
     155             : /// GlobalCache which calls the threaded action passed in as a template
     156             : /// parameter. The `Args` are forwareded to the callback.
     157             : template <typename CacheTag, typename ThreadedAction, typename Metavariables,
     158             :           typename ArrayIndex, typename Component, typename... Args>
     159           1 : bool functions_of_time_are_ready_threaded_action_callback(
     160             :     Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
     161             :     const Component* component_p, const double time,
     162             :     const std::optional<std::unordered_set<std::string>>& functions_to_check,
     163             :     Args&&... args) {
     164             :   using ProxyType =
     165             :       std::decay_t<decltype(::Parallel::get_parallel_component<Component>(
     166             :           cache)[array_index])>;
     167             :   return detail::functions_of_time_are_ready_impl<
     168             :       CacheTag,
     169             :       Parallel::ThreadedActionCallback<ThreadedAction, ProxyType, Args...>>(
     170             :       cache, array_index, component_p, time, functions_to_check,
     171             :       std::forward<Args>(args)...);
     172             : }
     173             : 
     174             : /// \ingroup ComputationalDomainGroup
     175             : /// Check that functions of time are up-to-date.
     176             : ///
     177             : /// Check that functions of time in \p CacheTag with names in \p
     178             : /// functions_to_check are ready at time \p time.  If  \p functions_to_check is
     179             : /// a `std::nullopt`, checks all functions in \p CacheTag.  If any function is
     180             : /// not ready, schedules a `Parallel::PerformAlgorithmCallback` or
     181             : /// `Parallel::Actions::PerformAlgorithmOnElement<false>` callback with the
     182             : /// GlobalCache.
     183             : template <typename CacheTag, size_t Dim, typename Metavariables,
     184             :           typename ArrayIndex, typename Component>
     185           1 : bool functions_of_time_are_ready_algorithm_callback(
     186             :     Parallel::GlobalCache<Metavariables>& cache, const ArrayIndex& array_index,
     187             :     const Component* component_p, const double time,
     188             :     const std::optional<std::unordered_set<std::string>>& functions_to_check =
     189             :         std::nullopt) {
     190             :   if constexpr (Parallel::is_dg_element_collection_v<Component>) {
     191             :     const auto element_location =
     192             :         static_cast<int>(Parallel::local_synchronous_action<
     193             :                              Parallel::Actions::GetItemFromDistributedOject<
     194             :                                  Parallel::Tags::ElementLocations<Dim>>>(
     195             :                              Parallel::get_parallel_component<Component>(cache))
     196             :                              ->at(array_index));
     197             :     ASSERT(element_location == Parallel::my_node<int>(cache),
     198             :            "Expected to be running on node "
     199             :                << Parallel::my_node<int>(cache)
     200             :                << " but the record says it is on node " << element_location);
     201             :     return functions_of_time_are_ready_threaded_action_callback<
     202             :         domain::Tags::FunctionsOfTime,
     203             :         Parallel::Actions::PerformAlgorithmOnElement<false>>(
     204             :         cache, element_location, component_p, time, std::nullopt, array_index);
     205             :   } else {
     206             :     using ProxyType =
     207             :         std::decay_t<decltype(::Parallel::get_parallel_component<Component>(
     208             :             cache)[array_index])>;
     209             :     return detail::functions_of_time_are_ready_impl<
     210             :         CacheTag, Parallel::PerformAlgorithmCallback<ProxyType>>(
     211             :         cache, array_index, component_p, time, functions_to_check);
     212             :   }
     213             : }
     214             : 
     215           0 : namespace Actions {
     216             : /// \ingroup ComputationalDomainGroup
     217             : /// Check that functions of time are up-to-date.
     218             : ///
     219             : /// Wait for all functions of time in `domain::Tags::FunctionsOfTime`
     220             : /// to be ready at `::Tags::Time`.  This ensures that the coordinates
     221             : /// can be safely accessed in later actions without first verifying
     222             : /// the state of the time-dependent maps.
     223             : template <size_t Dim>
     224           1 : struct CheckFunctionsOfTimeAreReady {
     225             :   template <typename DbTags, typename... InboxTags, typename Metavariables,
     226             :             typename ArrayIndex, typename ActionList,
     227             :             typename ParallelComponent>
     228           0 :   static Parallel::iterable_action_return_t apply(
     229             :       db::DataBox<DbTags>& box, tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     230             :       Parallel::GlobalCache<Metavariables>& cache,
     231             :       const ArrayIndex& array_index, ActionList /*meta*/,
     232             :       const ParallelComponent* component) {
     233             :     const bool ready = functions_of_time_are_ready_algorithm_callback<
     234             :         domain::Tags::FunctionsOfTime, Dim>(cache, array_index, component,
     235             :                                             db::get<::Tags::Time>(box));
     236             : 
     237             :     return {ready ? Parallel::AlgorithmExecution::Continue
     238             :                   : Parallel::AlgorithmExecution::Retry,
     239             :             std::nullopt};
     240             :   }
     241             : };
     242             : }  // namespace Actions
     243             : 
     244             : /// \ingroup ComputationalDomainGroup
     245             : /// Dense-output postprocessor to check that functions of time are up-to-date.
     246             : ///
     247             : /// Check that all functions of time in
     248             : /// `domain::Tags::FunctionsOfTime` are ready at `::Tags::Time`.  This
     249             : /// ensures that the coordinates can be safely accessed in later
     250             : /// actions without first verifying the state of the time-dependent
     251             : /// maps.  This postprocessor does not actually modify anything.
     252             : template <size_t Dim>
     253           1 : struct CheckFunctionsOfTimeAreReadyPostprocessor {
     254           0 :   using return_tags = tmpl::list<>;
     255           0 :   using argument_tags = tmpl::list<>;
     256           0 :   static void apply() {}
     257             : 
     258             :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     259             :             typename ArrayIndex, typename ParallelComponent>
     260           0 :   static bool is_ready(
     261             :       const gsl::not_null<db::DataBox<DbTagsList>*> box,
     262             :       const gsl::not_null<tuples::TaggedTuple<InboxTags...>*> /*inboxes*/,
     263             :       Parallel::GlobalCache<Metavariables>& cache,
     264             :       const ArrayIndex& array_index, const ParallelComponent* component) {
     265             :     return functions_of_time_are_ready_algorithm_callback<
     266             :         domain::Tags::FunctionsOfTime, Dim>(cache, array_index, component,
     267             :                                             db::get<::Tags::Time>(*box));
     268             :   }
     269             : };
     270             : }  // namespace domain

Generated by: LCOV version 1.14