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/Registration.hpp"
20 #include "Utilities/TMPL.hpp"
21 
22 /// \cond
23 namespace Parallel {
24 template <typename Metavariables>
25 class GlobalCache;
26 } // namespace Parallel
27 namespace Tags {
28 struct TimeStepId;
29 } // namespace Tags
30 /// \endcond
31 
32 namespace StepChoosers {
33 template <typename StepChooserRegistrars>
35 
36 namespace Registrars {
38 } // namespace Registrars
39 
40 /// Suggests step sizes to place steps at specific times.
41 ///
42 /// The suggestion provided depends on the current time, so it should
43 /// be applied immediately, rather than delayed several slabs. As
44 /// changing immediately is inefficient, it may be best to use
45 /// triggers to only activate this check near (within a few slabs of)
46 /// the desired time.
47 /// \warning This step chooser should be used only to choose slabs, not steps in
48 /// an LTS scheme. Because the times are chosen based on the current time step
49 /// id, using this as a step chooser in local time stepping will act
50 /// unintuitively. Further, roundoff-level fluctuations arising from taking
51 /// floating-point time differences will tend to interact poorly with
52 /// `StepController`s.
53 template <typename StepChooserRegistrars = tmpl::list<Registrars::StepToTimes>>
54 class StepToTimes : public StepChooser<StepChooserRegistrars> {
55  public:
56  /// \cond
57  StepToTimes() = default;
58  explicit StepToTimes(CkMigrateMessage* /*unused*/) noexcept {}
59  using PUP::able::register_constructor;
60  WRAPPED_PUPable_decl_template(StepToTimes); // NOLINT
61  /// \endcond
62 
63  struct Times {
65  static constexpr Options::String help{"Times to force steps at"};
66  };
67 
68  static constexpr Options::String help =
69  "Suggests step sizes to place steps at specific times.\n"
70  "\n"
71  "The suggestion provided depends on the current time, so it should\n"
72  "be applied immediately, rather than delayed several slabs. As\n"
73  "changing immediately is inefficient, it may be best to use\n"
74  "triggers to only activate this check near (within a few slabs of)\n"
75  "the desired time.\n";
76  using options = tmpl::list<Times>;
77 
78  explicit StepToTimes(std::unique_ptr<TimeSequence<double>> times) noexcept
79  : times_(std::move(times)) {}
80 
81  static constexpr UsableFor usable_for = UsableFor::OnlySlabChoice;
82 
83  using argument_tags = tmpl::list<::Tags::TimeStepId>;
84  using return_tags = tmpl::list<>;
85 
86  template <typename Metavariables>
87  std::pair<double, bool> operator()(
88  const TimeStepId& time_step_id, const double last_step_magnitude,
89  const Parallel::GlobalCache<Metavariables>& /*cache*/) const noexcept {
90  const auto& substep_time = time_step_id.substep_time();
91  const double now = substep_time.value();
92  // Trying to step to a given time might not get us exactly there
93  // because of rounding errors. Avoid taking an extra tiny step if
94  // we undershoot.
95  const double sloppiness = slab_rounding_error(substep_time);
96 
97  const auto goal_times = times_->times_near(now);
98  if (not goal_times[1]) {
99  // No times requested.
100  return std::make_pair(std::numeric_limits<double>::infinity(), true);
101  }
102 
103  double distance_to_next_goal = std::numeric_limits<double>::signaling_NaN();
104  if (time_step_id.time_runs_forward()) {
105  const auto next_time =
106  *goal_times[1] > now + sloppiness ? goal_times[1] : goal_times[2];
107  if (not next_time) {
108  // We've passed all the times. No restriction.
109  return std::make_pair(std::numeric_limits<double>::infinity(), true);
110  }
111  distance_to_next_goal = *next_time - now;
112  } else {
113  const auto next_time =
114  *goal_times[1] < now - sloppiness ? goal_times[1] : goal_times[0];
115  if (not next_time) {
116  // We've passed all the times. No restriction.
117  return std::make_pair(std::numeric_limits<double>::infinity(), true);
118  }
119  distance_to_next_goal = now - *next_time;
120  }
121 
122  if (distance_to_next_goal < 2.0 / 3.0 * last_step_magnitude) {
123  // Our goal is well within range of the expected allowed step
124  // size.
125  return std::make_pair(distance_to_next_goal, true);
126  } else {
127  // We can't reach our goal in one step, or at least might not be
128  // able to if the step adjusts a relatively small amount for
129  // other reasons. Prevent the step from bringing us too close
130  // to the goal so that the step following this one will not be
131  // too small.
132  return std::make_pair(2.0 / 3.0 * distance_to_next_goal, true);
133  }
134  }
135 
136  // NOLINTNEXTLINE(google-runtime-references)
137  void pup(PUP::er& p) noexcept override { p | times_; }
138 
139  private:
141 };
142 
143 /// \cond
144 template <typename StepChooserRegistrars>
145 PUP::able::PUP_ID StepToTimes<StepChooserRegistrars>::my_PUP_ID = 0; // NOLINT
146 /// \endcond
147 } // 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
Registration::Registrar
A template for defining a registrar.
Definition: Registration.hpp:42
TimeSequence
Represents a sequence of times.
Definition: TimeSequence.hpp:31
WRAPPED_PUPable_decl_template
#define WRAPPED_PUPable_decl_template(className)
Mark derived classes as serializable.
Definition: CharmPupable.hpp:22
StepChoosers::UsableFor
UsableFor
Designation for the context in which a step chooser may be used.
Definition: StepChooser.hpp:54
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:34
Options::String
const char *const String
The string used in option structs.
Definition: Options.hpp:32
std::unique_ptr< TimeSequence< double > >
StepChooser
Definition: StepChooser.hpp:98
StepChoosers::StepToTimes::Times
Definition: StepToTimes.hpp:63
std::numeric_limits
Parallel
Functionality for parallelization.
Definition: ElementReceiveInterpPoints.hpp:13
TMPL.hpp