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> // IWYU pragma: keep // for abs 7 : #include <limits> 8 : #include <pup.h> 9 : #include <utility> 10 : 11 : #include "Options/String.hpp" 12 : #include "Time/StepChoosers/StepChooser.hpp" // IWYU pragma: keep 13 : #include "Time/Tags/HistoryEvolvedVariables.hpp" 14 : #include "Time/Utilities.hpp" 15 : #include "Utilities/Serialization/CharmPupable.hpp" 16 : #include "Utilities/TMPL.hpp" 17 : 18 : namespace StepChoosers { 19 : /// Avoids instabilities due to rapid increases in the step size by 20 : /// preventing the step size from increasing unless all steps in the 21 : /// time-stepper history are the same size. If there have been recent 22 : /// step size changes the new size bound is the size of the most 23 : /// recent step, otherwise it is infinite (no restriction is imposed). 24 : template <typename StepChooserUse> 25 1 : class PreventRapidIncrease : public StepChooser<StepChooserUse> { 26 : public: 27 : /// \cond 28 : PreventRapidIncrease() = default; 29 : explicit PreventRapidIncrease(CkMigrateMessage* /*unused*/) {} 30 : using PUP::able::register_constructor; 31 : WRAPPED_PUPable_decl_template(PreventRapidIncrease); // NOLINT 32 : /// \endcond 33 : 34 0 : static constexpr Options::String help{ 35 : "Prevents rapid increases in time step that can cause integrator \n" 36 : "instabilities."}; 37 0 : using options = tmpl::list<>; 38 : 39 0 : using argument_tags = tmpl::list<::Tags::HistoryEvolvedVariables<>>; 40 : 41 : template <typename History> 42 0 : std::pair<double, bool> operator()(const History& history, 43 : const double last_step_magnitude) const { 44 : if (history.size() < 2) { 45 : return std::make_pair(std::numeric_limits<double>::infinity(), true); 46 : } 47 : 48 : const double sloppiness = 49 : slab_rounding_error(history.front().time_step_id.step_time()); 50 : std::optional<Time> previous_time{}; 51 : for (const auto& record : history) { 52 : const Time time = record.time_step_id.step_time(); 53 : if (previous_time.has_value()) { 54 : // Potential roundoff error comes from the inability to make 55 : // slabs exactly the same length. 56 : if (abs(abs(*previous_time - time).value() - last_step_magnitude) > 57 : sloppiness) { 58 : return std::make_pair(last_step_magnitude, true); 59 : } 60 : } 61 : previous_time.emplace(time); 62 : } 63 : // Request that the step size be at most infinity. This imposes 64 : // no restriction on the chosen step. 65 : return std::make_pair(std::numeric_limits<double>::infinity(), true); 66 : } 67 : 68 1 : bool uses_local_data() const override { return false; } 69 : }; 70 : 71 : /// \cond 72 : template <typename StepChooserUse> 73 : PUP::able::PUP_ID PreventRapidIncrease<StepChooserUse>::my_PUP_ID = 74 : 0; // NOLINT 75 : /// \endcond 76 : } // namespace StepChoosers