SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/Interpolation/Actions - VerifyTemporalIdsAndSendPoints.hpp Hit Total Coverage
Commit: 361cb8d8406bb752684a5f31c27320ec444a50e3 Lines: 1 3 33.3 %
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 <deque>
       7             : #include <limits>
       8             : #include <memory>
       9             : #include <sstream>
      10             : #include <string>
      11             : #include <type_traits>
      12             : #include <unordered_map>
      13             : 
      14             : #include "DataStructures/DataBox/DataBox.hpp"
      15             : #include "DataStructures/LinkedMessageId.hpp"
      16             : #include "Domain/Creators/Tags/Domain.hpp"
      17             : #include "Domain/Domain.hpp"
      18             : #include "IO/Logging/Verbosity.hpp"
      19             : #include "Parallel/ArrayComponentId.hpp"
      20             : #include "Parallel/Callback.hpp"
      21             : #include "Parallel/GlobalCache.hpp"
      22             : #include "Parallel/Invoke.hpp"
      23             : #include "Parallel/ParallelComponentHelpers.hpp"
      24             : #include "Parallel/Printf/Printf.hpp"
      25             : #include "ParallelAlgorithms/Interpolation/Actions/SendPointsToInterpolator.hpp"
      26             : #include "ParallelAlgorithms/Interpolation/InterpolationTargetDetail.hpp"
      27             : #include "ParallelAlgorithms/Interpolation/Tags.hpp"
      28             : #include "Utilities/Algorithm.hpp"
      29             : #include "Utilities/Gsl.hpp"
      30             : #include "Utilities/PrettyType.hpp"
      31             : 
      32             : namespace intrp::Actions {
      33             : /// \ingroup ActionsGroup
      34             : /// \brief Sends points to an Interpolator for verified temporal_ids.
      35             : ///
      36             : /// VerifyTemporalIdsAndSendPoints is invoked on an InterpolationTarget.
      37             : ///
      38             : /// In more detail, does the following:
      39             : /// - If any map is time-dependent:
      40             : ///   - If there is a CurrentTemporalId or no PendingTemporalIds, does nothing
      41             : ///   - If any map is time-dependent:
      42             : ///     Moves first verified PendingTemporalId to CurrentTemporalId, where
      43             : ///     verified means that the FunctionsOfTime in the GlobalCache
      44             : ///     are up-to-date for that TemporalId.  If no PendingTemporalIds are
      45             : ///     moved, then VerifyTemporalIdsAndSendPoints sets itself as a
      46             : ///     callback in the GlobalCache so that it is called again when the
      47             : ///     FunctionsOfTime are mutated.
      48             : ///   - If maps are time-independent:
      49             : ///     Verified means just the first id in PendingTemporalIds
      50             : ///   - If the temporal id type is a LinkedMessageId, determines if this
      51             : ///     verified id is in order. If it isn't, then this just returns and does
      52             : ///     nothing
      53             : ///   - Calls intrp::Actions::SendPointsToInterpolator directly for this
      54             : ///     verified TemporalId. (when interpolation is complete,
      55             : ///      intrp::Actions::InterpolationTargetReceiveVars will begin interpolation
      56             : ///     on the next verified Id)
      57             : ///
      58             : /// Uses:
      59             : /// - DataBox:
      60             : ///   - `intrp::Tags::PendingTemporalIds`
      61             : ///   - `intrp::Tags::CompletedTemporalIds`
      62             : ///   - `intrp::Tags::CurrentTemporalId`
      63             : ///
      64             : /// DataBox changes:
      65             : /// - Adds: nothing
      66             : /// - Removes: nothing
      67             : /// - Modifies:
      68             : ///   - `intrp::Tags::PendingTemporalIds`
      69             : ///   - `intrp::Tags::CurrentTemporalId`
      70             : ///
      71             : /// For requirements on InterpolationTargetTag, see InterpolationTarget
      72             : template <typename InterpolationTargetTag>
      73           1 : struct VerifyTemporalIdsAndSendPoints {
      74             :   template <typename ParallelComponent, typename DbTags, typename Metavariables,
      75             :             typename ArrayIndex>
      76           0 :   static void apply(db::DataBox<DbTags>& box,
      77             :                     Parallel::GlobalCache<Metavariables>& cache,
      78             :                     const ArrayIndex& array_index) {
      79             :     static_assert(
      80             :         InterpolationTargetTag::compute_target_points::is_sequential::value,
      81             :         "Actions::VerifyTemporalIdsAndSendPoints can be used only with "
      82             :         "sequential targets.");
      83             : 
      84             :     using TemporalId = typename InterpolationTargetTag::temporal_id::type;
      85             : 
      86             :     std::stringstream ss{};
      87             :     const ::Verbosity& verbosity = Parallel::get<intrp::Tags::Verbosity>(cache);
      88             :     const bool verbose_print = verbosity >= ::Verbosity::Verbose;
      89             :     if (verbose_print) {
      90             :       ss << InterpolationTarget_detail::target_output_prefix<
      91             :                 VerifyTemporalIdsAndSendPoints<InterpolationTargetTag>,
      92             :                 InterpolationTargetTag>()
      93             :          << ", ";
      94             :     }
      95             : 
      96             :     const auto& pending_temporal_ids =
      97             :         db::get<Tags::PendingTemporalIds<TemporalId>>(box);
      98             :     // Nothing to do if there's an interpolation in progress or there are no
      99             :     // pending temporal_ids.
     100             :     if (db::get<Tags::CurrentTemporalId<TemporalId>>(box).has_value() or
     101             :         pending_temporal_ids.empty()) {
     102             :       if (verbose_print) {
     103             :         if (db::get<Tags::CurrentTemporalId<TemporalId>>(box).has_value()) {
     104             :           ss << "Interpolation already in progess at id "
     105             :              << db::get<Tags::CurrentTemporalId<TemporalId>>(box).value();
     106             :         } else {
     107             :           ss << "No pending temporal ids to send points at.";
     108             :         }
     109             :         Parallel::printf("%s\n", ss.str());
     110             :       }
     111             : 
     112             :       return;
     113             :     }
     114             : 
     115             :     const auto& domain =
     116             :         get<domain::Tags::Domain<Metavariables::volume_dim>>(cache);
     117             : 
     118             :     // Account for time dependent maps. If the points are in the grid frame or
     119             :     // if we don't have FunctionsOfTime in the cache, then we don't have to
     120             :     // check the FunctionsOfTime.
     121             :     if constexpr (not std::is_same_v<typename InterpolationTargetTag::
     122             :                                          compute_target_points::frame,
     123             :                                      ::Frame::Grid> and
     124             :                   Parallel::is_in_global_cache<Metavariables,
     125             :                                                domain::Tags::FunctionsOfTime>) {
     126             :       if (domain.is_time_dependent()) {
     127             :         const auto& next_pending_id = pending_temporal_ids.front();
     128             : 
     129             :         auto& this_proxy =
     130             :             Parallel::get_parallel_component<ParallelComponent>(cache);
     131             :         double min_expiration_time = std::numeric_limits<double>::max();
     132             :         const Parallel::ArrayComponentId array_component_id =
     133             :             Parallel::make_array_component_id<ParallelComponent>(array_index);
     134             :         const bool next_pending_id_is_ready = [&cache, &array_component_id,
     135             :                                                &this_proxy, &next_pending_id,
     136             :                                                &min_expiration_time]() {
     137             :           return ::Parallel::mutable_cache_item_is_ready<
     138             :               domain::Tags::FunctionsOfTime>(
     139             :               cache, array_component_id,
     140             :               [&this_proxy, &next_pending_id, &min_expiration_time](
     141             :                   const std::unordered_map<
     142             :                       std::string,
     143             :                       std::unique_ptr<domain::FunctionsOfTime::FunctionOfTime>>&
     144             :                       functions_of_time)
     145             :                   -> std::unique_ptr<Parallel::Callback> {
     146             :                 min_expiration_time =
     147             :                     std::min_element(functions_of_time.begin(),
     148             :                                      functions_of_time.end(),
     149             :                                      [](const auto& a, const auto& b) {
     150             :                                        return a.second->time_bounds()[1] <
     151             :                                               b.second->time_bounds()[1];
     152             :                                      })
     153             :                         ->second->time_bounds()[1];
     154             : 
     155             :                 // Success: the next pending_temporal_id is ok.
     156             :                 // Failure: the next pending_temporal_id is not ok.
     157             :                 return InterpolationTarget_detail::get_temporal_id_value(
     158             :                            next_pending_id) <= min_expiration_time
     159             :                            ? std::unique_ptr<Parallel::Callback>{}
     160             :                            : std::unique_ptr<Parallel::Callback>(
     161             :                                  new Parallel::SimpleActionCallback<
     162             :                                      VerifyTemporalIdsAndSendPoints<
     163             :                                          InterpolationTargetTag>,
     164             :                                      decltype(this_proxy)>(this_proxy));
     165             :               });
     166             :         }();
     167             : 
     168             :         if (not next_pending_id_is_ready) {
     169             :           if (verbose_print) {
     170             :             ss << "The next pending temporal id " << next_pending_id
     171             :                << " is not ready.";
     172             :             Parallel::printf("%s\n", ss.str());
     173             :           }
     174             : 
     175             :           // A callback has been set so that VerifyTemporalIdsAndSendPoints will
     176             :           // be called by the GlobalCache when domain::Tags::FunctionsOfTime is
     177             :           // updated.  So we can exit now.
     178             :           return;
     179             :         }
     180             :       }  // if (domain.is_time_dependent())
     181             :     } else if constexpr (not std::is_same_v<typename InterpolationTargetTag::
     182             :                                                 compute_target_points::frame,
     183             :                                             ::Frame::Grid> and
     184             :                          not Parallel::is_in_global_cache<
     185             :                              Metavariables, domain::Tags::FunctionsOfTime>) {
     186             :       if (domain.is_time_dependent()) {
     187             :         // We error here because the maps are time-dependent, yet
     188             :         // the cache does not contain FunctionsOfTime.  It would be
     189             :         // nice to make this a compile-time error; however, we want
     190             :         // the code to compile for the completely time-independent
     191             :         // case where there are no FunctionsOfTime in the cache at
     192             :         // all.  Unfortunately, checking whether the maps are
     193             :         // time-dependent is currently not constexpr.
     194             :         ERROR(
     195             :             "There is a time-dependent CoordinateMap in at least one "
     196             :             "of the Blocks, but FunctionsOfTime are not in the "
     197             :             "GlobalCache.  If you intend to use a time-dependent "
     198             :             "CoordinateMap, please add FunctionsOfTime to the GlobalCache.");
     199             :       }
     200             :     }
     201             : 
     202             :     // Move the most recent PendingTemporalId to CurrentTemporalId. If this is a
     203             :     // LinkedMessageId, make sure this is the next id before sending points
     204             :     db::mutate_apply<tmpl::list<Tags::CurrentTemporalId<TemporalId>,
     205             :                                 Tags::PendingTemporalIds<TemporalId>>,
     206             :                      tmpl::list<Tags::CompletedTemporalIds<TemporalId>>>(
     207             :         [](const gsl::not_null<std::optional<TemporalId>*> current_id,
     208             :            const gsl::not_null<std::deque<TemporalId>*> pending_ids,
     209             :            const std::deque<TemporalId>& completed_ids) {
     210             :           auto& next_pending_id = pending_ids->front();
     211             :           bool use_next_pending_id = true;
     212             : 
     213             :           if constexpr (std::is_same_v<LinkedMessageId<double>, TemporalId>) {
     214             :             // If completed ids is empty (and at this point so is temporal ids)
     215             :             // then we must check if this is the first id.
     216             :             use_next_pending_id = completed_ids.empty()
     217             :                                       ? not next_pending_id.previous.has_value()
     218             :                                       : next_pending_id.previous.value() ==
     219             :                                             completed_ids.back().id;
     220             :           }
     221             : 
     222             :           if (use_next_pending_id) {
     223             :             *current_id = next_pending_id;
     224             :             pending_ids->pop_front();
     225             :           }
     226             :         },
     227             :         make_not_null(&box));
     228             : 
     229             :     // Send points to interpolator if the next id is ready
     230             :     if (const auto& current_id =
     231             :             db::get<Tags::CurrentTemporalId<TemporalId>>(box);
     232             :         current_id.has_value()) {
     233             :       if (verbose_print) {
     234             :         ss << "Going to send points to interpolator at temporal id "
     235             :            << current_id.value();
     236             :       }
     237             :       Actions::SendPointsToInterpolator<InterpolationTargetTag>::template apply<
     238             :           ParallelComponent>(box, cache, array_index, current_id.value());
     239             :     } else if (verbose_print) {
     240             :       ss << "No temporal ids to send points at.";
     241             :     }
     242             : 
     243             :     if (verbose_print) {
     244             :       Parallel::printf("%s\n", ss.str());
     245             :     }
     246             :   }
     247             : };
     248             : }  // namespace intrp::Actions

Generated by: LCOV version 1.14