Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <cmath> 7 : #include <optional> 8 : #include <pup.h> 9 : 10 : #include "Options/String.hpp" 11 : #include "Time/History.hpp" 12 : #include "Time/SlabRoundingError.hpp" 13 : #include "Time/StepChoosers/StepChooser.hpp" 14 : #include "Time/Tags/HistoryEvolvedVariables.hpp" 15 : #include "Time/TimeStepRequest.hpp" 16 : #include "Utilities/Serialization/CharmPupable.hpp" 17 : #include "Utilities/TMPL.hpp" 18 : 19 : namespace StepChoosers { 20 : /// Limits the time step to prevent multistep integrator instabilities. 21 : /// 22 : /// Avoids instabilities due to rapid increases in the step size by 23 : /// preventing the step size from increasing if any step in the 24 : /// time-stepper history increased. If there have been recent step 25 : /// size increases, the new size bound is the size of the most recent 26 : /// step, otherwise no restriction is imposed. 27 : template <typename VariablesTag> 28 1 : class PreventRapidIncrease : public StepChooser<StepChooserUse::Slab>, 29 : public StepChooser<StepChooserUse::LtsStep> { 30 : public: 31 : /// \cond 32 : PreventRapidIncrease() = default; 33 : explicit PreventRapidIncrease(CkMigrateMessage* /*unused*/) {} 34 : using PUP::able::register_constructor; 35 : WRAPPED_PUPable_decl_template(PreventRapidIncrease); // NOLINT 36 : /// \endcond 37 : 38 0 : static constexpr Options::String help{ 39 : "Limits the time step to prevent multistep integrator instabilities."}; 40 0 : using options = tmpl::list<>; 41 : 42 0 : using argument_tags = 43 : tmpl::list<::Tags::HistoryEvolvedVariables<VariablesTag>>; 44 : 45 0 : TimeStepRequest operator()( 46 : const ::TimeSteppers::History<typename VariablesTag::type>& history, 47 : const double last_step) const { 48 : if (history.size() < 2) { 49 : return {}; 50 : } 51 : 52 : const double sloppiness = 53 : slab_rounding_error(history.front().time_step_id.step_time()); 54 : std::optional<Time> previous_time{}; 55 : double newer_step = abs(last_step); 56 : for (auto record = history.rbegin(); record != history.rend(); ++record) { 57 : const Time time = record->time_step_id.step_time(); 58 : if (previous_time.has_value()) { 59 : const double this_step = abs(*previous_time - time).value(); 60 : // Potential roundoff error comes from the inability to make 61 : // slabs exactly the same length. 62 : if (this_step < newer_step - sloppiness) { 63 : return {.size = last_step}; 64 : } 65 : newer_step = this_step; 66 : } 67 : previous_time.emplace(time); 68 : } 69 : return {}; 70 : } 71 : 72 1 : bool uses_local_data() const override { return false; } 73 1 : bool can_be_delayed() const override { return true; } 74 : 75 0 : void pup(PUP::er& p) override { 76 : StepChooser<StepChooserUse::Slab>::pup(p); 77 : StepChooser<StepChooserUse::LtsStep>::pup(p); 78 : } 79 : }; 80 : 81 : /// \cond 82 : template <typename VariablesTag> 83 : PUP::able::PUP_ID PreventRapidIncrease<VariablesTag>::my_PUP_ID = 0; // NOLINT 84 : /// \endcond 85 : } // namespace StepChoosers