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 template <typename StepChooserRegistrars = tmpl::list<Registrars::StepToTimes>>
48 class StepToTimes : public StepChooser<StepChooserRegistrars> {
49  public:
50  /// \cond
51  StepToTimes() = default;
52  explicit StepToTimes(CkMigrateMessage* /*unused*/) noexcept {}
53  using PUP::able::register_constructor;
54  WRAPPED_PUPable_decl_template(StepToTimes); // NOLINT
55  /// \endcond
56 
57  struct Times {
59  static constexpr Options::String help{"Times to force steps at"};
60  };
61 
62  static constexpr Options::String help =
63  "Suggests step sizes to place steps at specific times.\n"
64  "\n"
65  "The suggestion provided depends on the current time, so it should\n"
66  "be applied immediately, rather than delayed several slabs. As\n"
67  "changing immediately is inefficient, it may be best to use\n"
68  "triggers to only activate this check near (within a few slabs of)\n"
69  "the desired time.\n";
70  using options = tmpl::list<Times>;
71 
72  explicit StepToTimes(std::unique_ptr<TimeSequence<double>> times) noexcept
73  : times_(std::move(times)) {}
74 
75  using argument_tags = tmpl::list<Tags::TimeStepId>;
76 
77  template <typename Metavariables>
78  double operator()(
79  const TimeStepId& time_step_id, const double last_step_magnitude,
80  const Parallel::GlobalCache<Metavariables>& /*cache*/) const noexcept {
81  const auto& substep_time = time_step_id.substep_time();
82  const double now = substep_time.value();
83  // Trying to step to a given time might not get us exactly there
84  // because of rounding errors. Avoid taking an extra tiny step if
85  // we undershoot.
86  const double sloppiness = slab_rounding_error(substep_time);
87 
88  const auto goal_times = times_->times_near(now);
89  if (not goal_times[1]) {
90  // No times requested.
92  }
93 
94  double distance_to_next_goal = std::numeric_limits<double>::signaling_NaN();
95  if (time_step_id.time_runs_forward()) {
96  const auto next_time =
97  *goal_times[1] > now + sloppiness ? goal_times[1] : goal_times[2];
98  if (not next_time) {
99  // We've passed all the times. No restriction.
101  }
102  distance_to_next_goal = *next_time - now;
103  } else {
104  const auto next_time =
105  *goal_times[1] < now - sloppiness ? goal_times[1] : goal_times[0];
106  if (not next_time) {
107  // We've passed all the times. No restriction.
109  }
110  distance_to_next_goal = now - *next_time;
111  }
112 
113  if (distance_to_next_goal < 2.0 / 3.0 * last_step_magnitude) {
114  // Our goal is well within range of the expected allowed step
115  // size.
116  return distance_to_next_goal;
117  } else {
118  // We can't reach our goal in one step, or at least might not be
119  // able to if the step adjusts a relatively small amount for
120  // other reasons. Prevent the step from bringing us too close
121  // to the goal so that the step following this one will not be
122  // too small.
123  return 2.0 / 3.0 * distance_to_next_goal;
124  }
125  }
126 
127  // NOLINTNEXTLINE(google-runtime-references)
128  void pup(PUP::er& p) noexcept override { p | times_; }
129 
130  private:
132 };
133 
134 /// \cond
135 template <typename StepChooserRegistrars>
136 PUP::able::PUP_ID StepToTimes<StepChooserRegistrars>::my_PUP_ID = 0; // NOLINT
137 /// \endcond
138 } // namespace StepChoosers
CharmPupable.hpp
StepChoosers
Definition: ByBlock.hpp:33
utility
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
Options.hpp
slab_rounding_error
double slab_rounding_error(const Time &time) noexcept
Definition: Utilities.cpp:12
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
std::numeric_limits::infinity
T infinity(T... args)
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:43
StepChoosers::StepToTimes::Times
Definition: StepToTimes.hpp:57
TMPL.hpp