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