SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/Actions - FunctionsOfTimeAreReady.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 41.7 % 12 5
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 <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 2.0-1