Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <limits> 7 : #include <memory> 8 : #include <pup.h> 9 : #include <pup_stl.h> 10 : #include <utility> 11 : 12 : #include "Options/String.hpp" 13 : #include "Time/StepChoosers/StepChooser.hpp" 14 : #include "Time/TimeSequence.hpp" 15 : #include "Time/TimeStepId.hpp" 16 : #include "Time/Utilities.hpp" 17 : #include "Utilities/Serialization/CharmPupable.hpp" 18 : #include "Utilities/TMPL.hpp" 19 : 20 : /// \cond 21 : namespace Tags { 22 : struct TimeStepId; 23 : } // namespace Tags 24 : /// \endcond 25 : 26 : namespace StepChoosers { 27 : /// Suggests step sizes to place steps at specific times. 28 : /// 29 : /// The suggestion provided depends on the current time, so it should 30 : /// be applied immediately, rather than delayed several slabs. 31 1 : class StepToTimes : public StepChooser<StepChooserUse::Slab> { 32 : public: 33 : /// \cond 34 : StepToTimes() = default; 35 : explicit StepToTimes(CkMigrateMessage* /*unused*/) {} 36 : using PUP::able::register_constructor; 37 : WRAPPED_PUPable_decl_template(StepToTimes); // NOLINT 38 : /// \endcond 39 : 40 0 : struct Times { 41 0 : using type = std::unique_ptr<TimeSequence<double>>; 42 0 : static constexpr Options::String help{"Times to force steps at"}; 43 : }; 44 : 45 0 : static constexpr Options::String help = 46 : "Suggests step sizes to place steps at specific times.\n" 47 : "\n" 48 : "The suggestion provided depends on the current time, so it should\n" 49 : "be applied immediately, rather than delayed several slabs."; 50 0 : using options = tmpl::list<Times>; 51 : 52 0 : explicit StepToTimes(std::unique_ptr<TimeSequence<double>> times) 53 : : times_(std::move(times)) {} 54 : 55 0 : using argument_tags = tmpl::list<::Tags::TimeStepId>; 56 : 57 0 : std::pair<double, bool> operator()(const TimeStepId& time_step_id, 58 : const double last_step_magnitude) const { 59 : const double now = time_step_id.substep_time(); 60 : // Trying to step to a given time might not get us exactly there 61 : // because of rounding errors. Avoid taking an extra tiny step if 62 : // we undershoot. 63 : const double sloppiness = slab_rounding_error(time_step_id.step_time()); 64 : 65 : const auto goal_times = times_->times_near(now); 66 : if (not goal_times[1]) { 67 : // No times requested. 68 : return std::make_pair(std::numeric_limits<double>::infinity(), true); 69 : } 70 : 71 : double distance_to_next_goal = std::numeric_limits<double>::signaling_NaN(); 72 : if (time_step_id.time_runs_forward()) { 73 : const auto next_time = 74 : *goal_times[1] > now + sloppiness ? goal_times[1] : goal_times[2]; 75 : if (not next_time) { 76 : // We've passed all the times. No restriction. 77 : return std::make_pair(std::numeric_limits<double>::infinity(), true); 78 : } 79 : distance_to_next_goal = *next_time - now; 80 : } else { 81 : const auto next_time = 82 : *goal_times[1] < now - sloppiness ? goal_times[1] : goal_times[0]; 83 : if (not next_time) { 84 : // We've passed all the times. No restriction. 85 : return std::make_pair(std::numeric_limits<double>::infinity(), true); 86 : } 87 : distance_to_next_goal = now - *next_time; 88 : } 89 : 90 : if (distance_to_next_goal < 2.0 / 3.0 * last_step_magnitude) { 91 : // Our goal is well within range of the expected allowed step 92 : // size. 93 : return std::make_pair(distance_to_next_goal, true); 94 : } else { 95 : // We can't reach our goal in one step, or at least might not be 96 : // able to if the step adjusts a relatively small amount for 97 : // other reasons. Prevent the step from bringing us too close 98 : // to the goal so that the step following this one will not be 99 : // too small. 100 : return std::make_pair(2.0 / 3.0 * distance_to_next_goal, true); 101 : } 102 : } 103 : 104 1 : bool uses_local_data() const override; 105 : 106 : // NOLINTNEXTLINE(google-runtime-references) 107 0 : void pup(PUP::er& p) override { p | times_; } 108 : 109 : private: 110 0 : std::unique_ptr<TimeSequence<double>> times_; 111 : }; 112 : } // namespace StepChoosers