SpECTRE Documentation Coverage Report
Current view: top level - Time - ChangeStepSize.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 16.7 % 6 1
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 <bit>
       7              : #include <cmath>
       8              : #include <cstddef>
       9              : #include <optional>
      10              : #include <type_traits>
      11              : 
      12              : #include "DataStructures/DataBox/DataBox.hpp"
      13              : #include "Time/AdaptiveSteppingDiagnostics.hpp"
      14              : #include "Time/ChooseLtsStepSize.hpp"
      15              : #include "Time/LtsMode.hpp"
      16              : #include "Time/Tags/HistoryEvolvedVariables.hpp"
      17              : #include "Time/Tags/LtsStepChoosers.hpp"
      18              : #include "Time/Tags/MinimumTimeStep.hpp"
      19              : #include "Time/Time.hpp"
      20              : #include "Time/TimeStepId.hpp"
      21              : #include "Time/TimeStepRequest.hpp"
      22              : #include "Time/TimeStepRequestProcessor.hpp"
      23              : #include "Time/TimeSteppers/LtsTimeStepper.hpp"
      24              : #include "Utilities/ErrorHandling/Assert.hpp"
      25              : #include "Utilities/ErrorHandling/Error.hpp"
      26              : #include "Utilities/Gsl.hpp"
      27              : #include "Utilities/TMPL.hpp"
      28              : 
      29              : /// \cond
      30              : struct AllStepChoosers;
      31              : namespace Tags {
      32              : struct AdaptiveSteppingDiagnostics;
      33              : struct DataBox;
      34              : struct FixedLtsRatio;
      35              : struct LtsMode;
      36              : template <typename Tag>
      37              : struct Next;
      38              : struct TimeStep;
      39              : struct TimeStepId;
      40              : template <typename StepperInterface>
      41              : struct TimeStepper;
      42              : }  // namespace Tags
      43              : /// \endcond
      44              : 
      45              : /// \brief Adjust the step size for local time stepping.
      46              : ///
      47              : /// \details
      48              : /// Usually, the new step size is chosen by calling the StepChoosers from
      49              : /// `Tags::LtsStepChoosers`, restricted based on the allowed step sizes at the
      50              : /// current time, and limits from history initialization.
      51              : ///
      52              : /// If `Tags::FixedLtsRatio` is present in the DataBox and not empty, the
      53              : /// StepChoosers are not called and instead the desired step is taken to be the
      54              : /// slab size over that value.  Early in the evolution, the actual chosen step
      55              : /// may differ from this because of restrictions on the allowed step, but all
      56              : /// such restrictions are global and will not result in different decisions for
      57              : /// different elements with the same desired fixed ratio.
      58              : ///
      59              : /// The optional template parameter `StepChoosersToUse` may be used to
      60              : /// indicate a subset of the constructable step choosers to use for the current
      61              : /// application of `ChangeStepSize`. Passing `AllStepChoosers` (default)
      62              : /// indicates that any constructible step chooser may be used. This option is
      63              : /// used when multiple components need to invoke `ChangeStepSize` with step
      64              : /// choosers that may not be compatible with all components.
      65              : template <typename StepChoosersToUse = AllStepChoosers,
      66              :           template <typename> typename CacheTagPrefix = std::type_identity_t>
      67            1 : struct ChangeStepSize {
      68            0 :   using const_global_cache_tags =
      69              :       tmpl::list<CacheTagPrefix<Tags::MinimumTimeStep>,
      70              :                  CacheTagPrefix<Tags::LtsStepChoosers>>;
      71              : 
      72            0 :   using return_tags = tmpl::list<Tags::DataBox>;
      73            0 :   using argument_tags = tmpl::list<>;
      74              : 
      75              :   template <typename DbTags>
      76            0 :   static void apply(const gsl::not_null<db::DataBox<DbTags>*> box) {
      77              :     if (db::get<CacheTagPrefix<Tags::LtsMode>>(*box) == LtsMode::Off) {
      78              :       return;
      79              :     }
      80              : 
      81              :     const auto& time_step_id = db::get<Tags::TimeStepId>(*box);
      82              :     if (time_step_id.substep() != 0) {
      83              :       return;
      84              :     }
      85              : 
      86              :     const LtsTimeStepper& time_stepper =
      87              :         db::get<CacheTagPrefix<Tags::TimeStepper<LtsTimeStepper>>>(*box);
      88              :     const auto& step_choosers =
      89              :         db::get<CacheTagPrefix<Tags::LtsStepChoosers>>(*box);
      90              : 
      91              :     using history_tags = ::Tags::get_all_history_tags<DbTags>;
      92              :     bool can_change_step_size = true;
      93              :     tmpl::for_each<history_tags>([&box, &can_change_step_size, &time_stepper,
      94              :                                   &time_step_id](auto tag_v) {
      95              :       if (not can_change_step_size) {
      96              :         return;
      97              :       }
      98              :       using tag = typename decltype(tag_v)::type;
      99              :       const auto& history = db::get<tag>(*box);
     100              :       can_change_step_size =
     101              :           time_stepper.can_change_step_size(time_step_id, history);
     102              :     });
     103              : 
     104              :     const auto current_step = db::get<Tags::TimeStep>(*box);
     105              : 
     106              :     std::optional<size_t> fixed_lts_ratio{};
     107              :     if constexpr (db::tag_is_retrievable_v<Tags::FixedLtsRatio,
     108              :                                            db::DataBox<DbTags>>) {
     109              :       fixed_lts_ratio = db::get<Tags::FixedLtsRatio>(*box);
     110              :     }
     111              : 
     112              :     TimeStepRequestProcessor step_requests(time_step_id.time_runs_forward());
     113              :     if (fixed_lts_ratio.has_value()) {
     114              :       ASSERT(std::popcount(*fixed_lts_ratio) == 1,
     115              :              "fixed_lts_ratio must be a power of 2, not " << *fixed_lts_ratio);
     116              :       step_requests.process(TimeStepRequest{
     117              :           .size_goal =
     118              :               (current_step.slab().duration() / *fixed_lts_ratio).value()});
     119              :     } else {
     120              :       const double last_step_size = current_step.value();
     121              :       for (const auto& step_chooser : step_choosers) {
     122              :         const auto step_request =
     123              :             step_chooser->template desired_step<StepChoosersToUse>(
     124              :                 last_step_size, *box);
     125              :         step_requests.process(step_request);
     126              :       }
     127              :     }
     128              : 
     129              :     if (not can_change_step_size) {
     130              :       step_requests.error_on_hard_limit(
     131              :           current_step.value(),
     132              :           (time_step_id.step_time() + current_step).value());
     133              :       return;
     134              :     }
     135              : 
     136              :     const double desired_step = step_requests.step_size(
     137              :         time_step_id.step_time().value(), current_step.value());
     138              : 
     139              :     const auto& minimum_time_step =
     140              :         db::get<CacheTagPrefix<::Tags::MinimumTimeStep>>(*box);
     141              : 
     142              :     // We do this check twice, first on the desired value, and then on
     143              :     // the actual chosen value, which is probably slightly smaller.
     144              :     if (std::abs(desired_step) < minimum_time_step) {
     145              :       ERROR_NO_TRACE(
     146              :           "Chosen step size "
     147              :           << desired_step << " is smaller than the MinimumTimeStep of "
     148              :           << minimum_time_step
     149              :           << ".\n"
     150              :              "\n"
     151              :              "This can indicate a flaw in the step chooser, the grid, or a "
     152              :              "simulation instability that an error-based stepper is naively "
     153              :              "attempting to resolve. A possible issue is an aliasing-driven "
     154              :              "instability that could be cured by more aggressive filtering if "
     155              :              "you are using DG.");
     156              :     }
     157              : 
     158              :     const auto new_step =
     159              :         choose_lts_step_size(time_step_id.step_time(), desired_step);
     160              :     step_requests.error_on_hard_limit(
     161              :         new_step.value(), (time_step_id.step_time() + new_step).value());
     162              : 
     163              :     if (new_step == current_step) {
     164              :       return;
     165              :     }
     166              : 
     167              :     if (std::abs(new_step.value()) < minimum_time_step) {
     168              :       ERROR_NO_TRACE(
     169              :           "Chosen step size after conversion to a fraction of a slab "
     170              :           << new_step << " is smaller than the MinimumTimeStep of "
     171              :           << minimum_time_step
     172              :           << ".\n"
     173              :              "\n"
     174              :              "This can indicate a flaw in the step chooser, the grid, or a "
     175              :              "simulation instability that an error-based stepper is naively "
     176              :              "attempting to resolve. A possible issue is an aliasing-driven "
     177              :              "instability that could be cured by more aggressive filtering if "
     178              :              "you are using DG.");
     179              :     }
     180              : 
     181              :     db::mutate<Tags::Next<Tags::TimeStepId>, Tags::TimeStep,
     182              :                Tags::AdaptiveSteppingDiagnostics>(
     183              :         [&](const gsl::not_null<TimeStepId*> local_next_time_id,
     184              :             const gsl::not_null<TimeDelta*> time_step,
     185              :             const gsl::not_null<AdaptiveSteppingDiagnostics*> diags) {
     186              :           *time_step = new_step;
     187              :           *local_next_time_id =
     188              :               time_stepper.next_time_id(time_step_id, *time_step);
     189              :           ++diags->number_of_step_fraction_changes;
     190              :         },
     191              :         box);
     192              :   }
     193              : };
        

Generated by: LCOV version 2.0-1