SpECTRE Documentation Coverage Report
Current view: top level - Time/ChangeSlabSize - Event.hpp Hit Total Coverage
Commit: c3e43f8d41800b0ecefb9d1393f1de1d5a280c8f Lines: 3 25 12.0 %
Date: 2026-07-24 22:09:25
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 <algorithm>
       7             : #include <cstddef>
       8             : #include <cstdint>
       9             : #include <limits>
      10             : #include <map>
      11             : #include <memory>
      12             : #include <pup.h>
      13             : #include <pup_stl.h>
      14             : #include <typeindex>
      15             : #include <unordered_map>
      16             : #include <utility>
      17             : #include <vector>
      18             : 
      19             : #include "DataStructures/DataBox/DataBox.hpp"
      20             : #include "Options/Context.hpp"
      21             : #include "Options/ParseError.hpp"
      22             : #include "Options/String.hpp"
      23             : #include "Parallel/ArrayCollection/IsDgElementCollection.hpp"
      24             : #include "Parallel/GlobalCache.hpp"
      25             : #include "Parallel/Reduction.hpp"
      26             : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
      27             : #include "Time/ChangeSlabSize/Tags.hpp"
      28             : #include "Time/LtsMode.hpp"
      29             : #include "Time/RequestsStepperErrorTolerances.hpp"
      30             : #include "Time/StepChoosers/StepChooser.hpp"
      31             : #include "Time/StepperErrorTolerances.hpp"
      32             : #include "Time/TimeStepId.hpp"
      33             : #include "Time/TimeStepRequest.hpp"
      34             : #include "Time/TimeStepRequestProcessor.hpp"
      35             : #include "Utilities/ErrorHandling/Error.hpp"
      36             : #include "Utilities/Functional.hpp"
      37             : #include "Utilities/PrettyType.hpp"
      38             : #include "Utilities/Serialization/CharmPupable.hpp"
      39             : #include "Utilities/TMPL.hpp"
      40             : 
      41             : /// \cond
      42             : namespace Tags {
      43             : struct DataBox;
      44             : struct LtsMode;
      45             : struct TimeStepId;
      46             : }  // namespace Tags
      47             : /// \endcond
      48             : 
      49             : namespace Events {
      50             : namespace ChangeSlabSize_detail {
      51             : struct StoreNewSlabSize {
      52             :   template <typename ParallelComponent, typename DbTags, typename Metavariables,
      53             :             typename ArrayIndex>
      54             :   static void apply(db::DataBox<DbTags>& box,
      55             :                     Parallel::GlobalCache<Metavariables>& /*cache*/,
      56             :                     const ArrayIndex& /*array_index*/,
      57             :                     const int64_t slab_number,
      58             :                     const TimeStepRequestProcessor& requests) {
      59             :     db::mutate<::Tags::ChangeSlabSize::NewSlabSize>(
      60             :         [&](const gsl::not_null<
      61             :             std::map<int64_t, std::vector<TimeStepRequestProcessor>>*>
      62             :                 sizes) { (*sizes)[slab_number].emplace_back(requests); },
      63             :         make_not_null(&box));
      64             :   }
      65             : };
      66             : }  // namespace ChangeSlabSize_detail
      67             : 
      68             : /// \ingroup TimeGroup
      69             : /// %Trigger a slab size change.
      70             : ///
      71             : /// The new size will be the minimum suggested by any of the provided
      72             : /// step choosers on any element.  This requires a global reduction,
      73             : /// so it is possible to delay the change until a later slab to avoid
      74             : /// a global synchronization.  The actual change is carried out by
      75             : /// Actions::ChangeSlabSize.
      76             : ///
      77             : /// When running with global time-stepping, the slab size and step
      78             : /// size are the same, so this adjusts the step size used by the time
      79             : /// integration.  With local time-stepping this controls the interval
      80             : /// between times when the sequences of steps on all elements are
      81             : /// forced to align.
      82           1 : class ChangeSlabSize : public Event, public RequestsStepperErrorTolerances {
      83           0 :   using ReductionData = Parallel::ReductionData<
      84             :       Parallel::ReductionDatum<int64_t, funcl::AssertEqual<>>,
      85             :       Parallel::ReductionDatum<TimeStepRequestProcessor, funcl::Plus<>>>;
      86             : 
      87             :  public:
      88             :   /// \cond
      89             :   explicit ChangeSlabSize(CkMigrateMessage* /*unused*/) {}
      90             :   using PUP::able::register_constructor;
      91             :   WRAPPED_PUPable_decl_template(ChangeSlabSize);  // NOLINT
      92             :   /// \endcond
      93             : 
      94           0 :   struct StepChoosers {
      95           0 :     static constexpr Options::String help = "Limits on slab size";
      96           0 :     using type =
      97             :         std::vector<std::unique_ptr<StepChooser<StepChooserUse::Slab>>>;
      98           0 :     static size_t lower_bound_on_size() { return 1; }
      99             :   };
     100             : 
     101           0 :   struct DelayChange {
     102           0 :     static constexpr Options::String help = "Slabs to wait before changing";
     103           0 :     using type = uint64_t;
     104             :   };
     105             : 
     106           0 :   using options = tmpl::list<StepChoosers, DelayChange>;
     107           0 :   static constexpr Options::String help =
     108             :       "Trigger a slab size change chosen by the provided step choosers.\n"
     109             :       "The actual changing of the slab size can be delayed until a later\n"
     110             :       "slab to improve parallelization.";
     111             : 
     112           0 :   ChangeSlabSize() = default;
     113           0 :   ChangeSlabSize(std::vector<std::unique_ptr<StepChooser<StepChooserUse::Slab>>>
     114             :                      step_choosers,
     115             :                  const uint64_t delay_change, const Options::Context& context)
     116             :       : step_choosers_(std::move(step_choosers)), delay_change_(delay_change) {
     117             :     if (delay_change != 0) {
     118             :       for (const auto& chooser : step_choosers_) {
     119             :         if (not chooser->can_be_delayed()) {
     120             :           // The runtime name might not be exactly the same as the one
     121             :           // used by the factory, but hopefully it's close enough that
     122             :           // the user can figure it out.
     123             :           PARSE_ERROR(context,
     124             :                       "The " << pretty_type::get_runtime_type_name(*chooser)
     125             :                       << " StepChooser cannot be applied with a delay.");
     126             :         }
     127             :       }
     128             :     }
     129             :   }
     130             : 
     131           0 :   using compute_tags_for_observation_box = tmpl::list<>;
     132             : 
     133             :   // Need a const version of the full box for the step choosers, but
     134             :   // can't get a const version while mutating other tags, so request a
     135             :   // mutable version.
     136           0 :   using return_tags = tmpl::list<::Tags::DataBox>;
     137           0 :   using argument_tags = tmpl::list<::Tags::TimeStepId, ::Tags::LtsMode>;
     138             : 
     139             :   template <typename DbTags, typename Metavariables, typename ArrayIndex,
     140             :             typename ParallelComponent>
     141           0 :   void operator()(const gsl::not_null<db::DataBox<DbTags>*> box,
     142             :                   const TimeStepId& time_step_id, const LtsMode lts_mode,
     143             :                   Parallel::GlobalCache<Metavariables>& cache,
     144             :                   const ArrayIndex& array_index,
     145             :                   const ParallelComponent* const /*meta*/,
     146             :                   const ObservationValue& /*observation_value*/) const {
     147             :     const auto next_changable_slab = time_step_id.is_at_slab_boundary()
     148             :                                          ? time_step_id.slab_number()
     149             :                                          : time_step_id.slab_number() + 1;
     150             :     const auto slab_to_change =
     151             :         next_changable_slab + static_cast<int64_t>(delay_change_);
     152             :     const auto slab_start = time_step_id.step_time();
     153             :     const auto current_slab_size = (time_step_id.time_runs_forward() ? 1 : -1) *
     154             :                                    slab_start.slab().duration();
     155             : 
     156             :     TimeStepRequestProcessor step_requests(time_step_id.time_runs_forward());
     157             :     bool synchronization_required = false;
     158             :     for (const auto& step_chooser : step_choosers_) {
     159             :       if (lts_mode != LtsMode::Off and step_chooser->must_set_step_size()) {
     160             :         // The runtime name might not be exactly the same as the one
     161             :         // used by the factory, but hopefully it's close enough that
     162             :         // the user can figure it out.
     163             :         ERROR_NO_TRACE("The "
     164             :                        << pretty_type::get_runtime_type_name(*step_chooser)
     165             :                        << " StepChooser cannot be used for the slab size in "
     166             :                           "an LTS evolution.");
     167             :       }
     168             :       step_requests.process(
     169             :           step_chooser->desired_step(current_slab_size.value(), *box));
     170             :       // We must synchronize if any step chooser requires it, not just
     171             :       // the limiting one, because choosers requiring synchronization
     172             :       // can be limiting on some processors and not others.
     173             :       if (not synchronization_required) {
     174             :         synchronization_required = step_chooser->uses_local_data();
     175             :       }
     176             :     }
     177             : 
     178             :     db::mutate<::Tags::ChangeSlabSize::NumberOfExpectedMessages>(
     179             :         [&](const gsl::not_null<std::map<int64_t, size_t>*> expected) {
     180             :           ++(*expected)[slab_to_change];
     181             :         },
     182             :         box);
     183             : 
     184             :     if constexpr (Parallel::is_dg_element_collection_v<ParallelComponent>) {
     185             :       ERROR(
     186             :           "Slab changing is not yet implemented for the DgElementCollection "
     187             :           "parallel component. Specifically, the ability to do reductions "
     188             :           "using Charm++-style reductions has not been implemented.");
     189             :     } else {
     190             :       const auto& component_proxy =
     191             :           Parallel::get_parallel_component<ParallelComponent>(cache);
     192             :       const auto& self_proxy = component_proxy[array_index];
     193             :       if (synchronization_required) {
     194             :         Parallel::contribute_to_reduction<
     195             :             ChangeSlabSize_detail::StoreNewSlabSize>(
     196             :             ReductionData(slab_to_change, step_requests), self_proxy,
     197             :             component_proxy);
     198             :       } else {
     199             :         db::mutate<::Tags::ChangeSlabSize::NewSlabSize>(
     200             :             [&](const gsl::not_null<
     201             :                 std::map<int64_t, std::vector<TimeStepRequestProcessor>>*>
     202             :                     sizes) {
     203             :               (*sizes)[slab_to_change].push_back(step_requests);
     204             :             },
     205             :             box);
     206             :       }
     207             :     }
     208             :     (void)cache, (void)array_index;
     209             :   }
     210             : 
     211           0 :   using is_ready_argument_tags = tmpl::list<>;
     212             : 
     213             :   template <typename Metavariables, typename ArrayIndex, typename Component>
     214           0 :   bool is_ready(Parallel::GlobalCache<Metavariables>& /*cache*/,
     215             :                 const ArrayIndex& /*array_index*/,
     216             :                 const Component* const /*meta*/) const {
     217             :     return true;
     218             :   }
     219             : 
     220           1 :   bool needs_evolved_variables() const override {
     221             :     // This depends on the chosen StepChoosers, but they don't have a
     222             :     // way to report this information so we just return true to be
     223             :     // safe.
     224             :     return true;
     225             :   }
     226             : 
     227           1 :   std::unordered_map<std::type_index, StepperErrorTolerances> tolerances()
     228             :       const override;
     229             : 
     230             :   // NOLINTNEXTLINE(google-runtime-references)
     231           0 :   void pup(PUP::er& p) override {
     232             :     Event::pup(p);
     233             :     p | step_choosers_;
     234             :     p | delay_change_;
     235             :   }
     236             : 
     237             :  private:
     238             :   std::vector<std::unique_ptr<StepChooser<StepChooserUse::Slab>>>
     239           0 :       step_choosers_;
     240           0 :   uint64_t delay_change_ = std::numeric_limits<uint64_t>::max();
     241             : };
     242             : }  // namespace Events

Generated by: LCOV version 1.14