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 : };