StepToTimes.hpp
1 // 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/Options.hpp"
14 #include "Time/StepChoosers/StepChooser.hpp"
15 #include "Time/Time.hpp"
16 #include "Time/TimeSequence.hpp"
17 #include "Time/TimeStepId.hpp"
18 #include "Time/Utilities.hpp"
19 #include "Utilities/TMPL.hpp"
20 
21 /// \cond
22 namespace Parallel {
23 template <typename Metavariables>
24 class GlobalCache;
25 } // namespace Parallel
26 namespace Tags {
27 struct TimeStepId;
28 } // namespace Tags
29 /// \endcond
30 
31 namespace StepChoosers {
32 /// Suggests step sizes to place steps at specific times.
33 ///
34 /// The suggestion provided depends on the current time, so it should
35 /// be applied immediately, rather than delayed several slabs. As
36 /// changing immediately is inefficient, it may be best to use
37 /// triggers to only activate this check near (within a few slabs of)
38 /// the desired time.
39 class StepToTimes : public StepChooser<StepChooserUse::Slab> {
40  public:
41  /// \cond
42  StepToTimes() = default;
43  explicit StepToTimes(CkMigrateMessage* /*unused*/) noexcept {}
44  using PUP::able::register_constructor;
46  /// \endcond
47 
48  struct Times {
50  static constexpr Options::String help{"Times to force steps at"};
51  };
52 
53  static constexpr Options::String help =
54  "Suggests step sizes to place steps at specific times.\n"
55  "\n"
56  "The suggestion provided depends on the current time, so it should\n"
57  "be applied immediately, rather than delayed several slabs. As\n"
58  "changing immediately is inefficient, it may be best to use\n"
59  "triggers to only activate this check near (within a few slabs of)\n"
60  "the desired time.\n";
61  using options = tmpl::list<Times>;
62 
63  explicit StepToTimes(std::unique_ptr<TimeSequence<double>> times) noexcept
64  : times_(std::move(times)) {}
65 
66  using argument_tags = tmpl::list<::Tags::TimeStepId>;
67  using return_tags = tmpl::list<>;
68 
69  template <typename Metavariables>
70  std::pair<double, bool> operator()(
71  const TimeStepId& time_step_id, const double last_step_magnitude,
72  const Parallel::GlobalCache<Metavariables>& /*cache*/) const noexcept {
73  const auto& substep_time = time_step_id.substep_time();
74  const double now = substep_time.value();
75  // Trying to step to a given time might not get us exactly there
76  // because of rounding errors. Avoid taking an extra tiny step if
77  // we undershoot.
78  const double sloppiness = slab_rounding_error(substep_time);
79 
80  const auto goal_times = times_->times_near(now);
81  if (not goal_times[1]) {
82  // No times requested.
83  return std::make_pair(std::numeric_limits<double>::infinity(), true);
84  }
85 
86  double distance_to_next_goal = std::numeric_limits<double>::signaling_NaN();
87  if (time_step_id.time_runs_forward()) {
88  const auto next_time =
89  *goal_times[1] > now + sloppiness ? goal_times[1] : goal_times[2];
90  if (not next_time) {
91  // We've passed all the times. No restriction.
92  return std::make_pair(std::numeric_limits<double>::infinity(), true);
93  }
94  distance_to_next_goal = *next_time - now;
95  } else {
96  const auto next_time =
97  *goal_times[1] < now - sloppiness ? goal_times[1] : goal_times[0];
98  if (not next_time) {
99  // We've passed all the times. No restriction.
100  return std::make_pair(std::numeric_limits<double>::infinity(), true);
101  }
102  distance_to_next_goal = now - *next_time;
103  }
104 
105  if (distance_to_next_goal < 2.0 / 3.0 * last_step_magnitude) {
106  // Our goal is well within range of the expected allowed step
107  // size.
108  return std::make_pair(distance_to_next_goal, true);
109  } else {
110  // We can't reach our goal in one step, or at least might not be
111  // able to if the step adjusts a relatively small amount for
112  // other reasons. Prevent the step from bringing us too close
113  // to the goal so that the step following this one will not be
114  // too small.
115  return std::make_pair(2.0 / 3.0 * distance_to_next_goal, true);
116  }
117  }
118 
119  // NOLINTNEXTLINE(google-runtime-references)
120  void pup(PUP::er& p) noexcept override { p | times_; }
121 
122  private:
124 };
125 } // namespace StepChoosers
CharmPupable.hpp
StepChoosers
Definition: ByBlock.hpp:33
utility
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
std::pair
Options.hpp
slab_rounding_error
double slab_rounding_error(const Time &time) noexcept
TimeSequence
Represents a sequence of times.
Definition: TimeSequence.hpp:21
WRAPPED_PUPable_decl_template
#define WRAPPED_PUPable_decl_template(className)
Mark derived classes as serializable.
Definition: CharmPupable.hpp:22
std::numeric_limits::signaling_NaN
T signaling_NaN(T... args)
Time.hpp
memory
TimeStepId
Definition: TimeStepId.hpp:25
TimeStepId.hpp
limits
StepChoosers::StepToTimes
Suggests step sizes to place steps at specific times.
Definition: StepToTimes.hpp:39
Options::String
const char *const String
The string used in option structs.
Definition: Options.hpp:32
std::unique_ptr< TimeSequence< double > >
StepChooser
StepChoosers suggest upper bounds on step sizes.
Definition: StepChooser.hpp:56
StepChoosers::StepToTimes::Times
Definition: StepToTimes.hpp:48
std::numeric_limits
Parallel
Functionality for parallelization.
Definition: ElementReceiveInterpPoints.hpp:13
TMPL.hpp