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