NearTimes.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <algorithm>
7 #include <cmath>
8 #include <limits>
9 #include <pup.h>
10 #include <string>
11 #include <utility>
12 
13 #include "Options/Options.hpp"
15 #include "ParallelAlgorithms/EventsAndTriggers/Trigger.hpp"
16 #include "Time/Slab.hpp"
17 #include "Time/Time.hpp"
18 #include "Time/TimeSequence.hpp"
19 #include "Utilities/Registration.hpp"
20 #include "Utilities/TMPL.hpp"
21 
22 /// \cond
23 namespace Tags {
24 struct Time;
25 struct TimeStep;
26 } // namespace Tags
27 /// \endcond
28 
29 namespace Triggers {
30 template <typename TriggerRegistrars>
31 class NearTimes;
32 
33 namespace Registrars {
35 } // namespace Registrars
36 
37 namespace NearTimes_enums {
38 enum class Unit { Time, Slab, Step };
39 enum class Direction { Before, After, Both };
40 } // namespace NearTimes_enums
41 
42 /// \ingroup EventsAndTriggersGroup
43 /// \ingroup TimeGroup
44 /// Trigger in intervals surrounding particular times.
45 ///
46 /// When using adaptive time stepping, intervals specified in terms of
47 /// slabs or steps are approximate.
48 ///
49 /// \see Times
50 template <typename TriggerRegistrars = tmpl::list<Registrars::NearTimes>>
51 class NearTimes : public Trigger<TriggerRegistrars> {
52  public:
53  /// \cond
54  NearTimes() = default;
55  explicit NearTimes(CkMigrateMessage* /*unused*/) noexcept {}
56  using PUP::able::register_constructor;
57  WRAPPED_PUPable_decl_template(NearTimes); // NOLINT
58  /// \endcond
59 
60  using Unit = NearTimes_enums::Unit;
61  using Direction = NearTimes_enums::Direction;
62 
63  struct OptionTags {
64  struct Times {
66  static constexpr Options::String help = "Times to trigger at";
67  };
68 
69  struct Range {
70  using type = double;
71  static type lower_bound() noexcept { return 0.0; }
72  static constexpr Options::String help =
73  "Maximum time difference to trigger at";
74  };
75 
76  struct Unit {
77  using type = NearTimes::Unit;
78  static constexpr Options::String help =
79  "Interpret Range as 'Time', 'Step's, or 'Slab's";
80  };
81 
82  struct Direction {
83  using type = NearTimes::Direction;
84  static constexpr Options::String help =
85  "Trigger 'Before', 'After', or 'Both' from the times";
86  };
87  };
88 
89  static constexpr Options::String help =
90  "Trigger in intervals surrounding particular times.";
91  using options =
92  tmpl::list<typename OptionTags::Times, typename OptionTags::Range,
93  typename OptionTags::Unit, typename OptionTags::Direction>;
94 
95  NearTimes(std::unique_ptr<TimeSequence<double>> times, const double range,
96  const Unit unit, const Direction direction) noexcept
97  : times_(std::move(times)),
98  range_(range),
99  unit_(unit),
100  direction_(direction) {}
101 
102  using argument_tags = tmpl::list<Tags::Time, Tags::TimeStep>;
103 
104  bool operator()(const double now, const TimeDelta& time_step) const noexcept {
105  const bool time_runs_forward = time_step.is_positive();
106 
107  double range_code_units = range_;
108  if (unit_ == Unit::Slab) {
109  range_code_units *= time_step.slab().duration().value();
110  } else if (unit_ == Unit::Step) {
111  range_code_units *= std::abs(time_step.value());
112  }
113 
114  if (not time_runs_forward) {
115  range_code_units = -range_code_units;
116  }
117 
118  // Interval around now to look for trigger times in.
119  auto trigger_range = std::make_pair(
120  direction_ == Direction::Before ? now : now - range_code_units,
121  direction_ == Direction::After ? now : now + range_code_units);
122 
123  if (not time_runs_forward) {
124  std::swap(trigger_range.first, trigger_range.second);
125  }
126 
127  const auto nearby_times = times_->times_near(trigger_range.first);
128  for (const auto& time : nearby_times) {
129  if (time and *time >= trigger_range.first and
130  *time <= trigger_range.second) {
131  return true;
132  }
133  }
134  return false;
135  }
136 
137  // NOLINTNEXTLINE(google-runtime-references)
138  void pup(PUP::er& p) noexcept override {
139  p | times_;
140  p | range_;
141  p | unit_;
142  p | direction_;
143  }
144 
145  private:
148  Unit unit_{};
149  Direction direction_{};
150 };
151 
152 /// \cond
153 template <typename TriggerRegistrars>
154 PUP::able::PUP_ID NearTimes<TriggerRegistrars>::my_PUP_ID = 0; // NOLINT
155 /// \endcond
156 } // namespace Triggers
157 
158 template <>
159 struct Options::create_from_yaml<Triggers::NearTimes_enums::Unit> {
160  using type = Triggers::NearTimes_enums::Unit;
161  template <typename Metavariables>
162  static type create(const Options::Option& options) {
163  const auto unit = options.parse_as<std::string>();
164  if (unit == "Time") {
165  return type::Time;
166  } else if (unit == "Step") {
167  return type::Step;
168  } else if (unit == "Slab") {
169  return type::Slab;
170  } else {
171  PARSE_ERROR(options.context(), "Unit must be 'Time', 'Step', or 'Slab'");
172  }
173  }
174 };
175 
176 template <>
178  typename Triggers::NearTimes_enums::Direction> {
179  using type = Triggers::NearTimes_enums::Direction;
180  template <typename Metavariables>
181  static type create(const Options::Option& options) {
182  const auto unit = options.parse_as<std::string>();
183  if (unit == "Before") {
184  return type::Before;
185  } else if (unit == "After") {
186  return type::After;
187  } else if (unit == "Both") {
188  return type::Both;
189  } else {
190  PARSE_ERROR(options.context(),
191  "Direction must be 'Before', 'After', or 'Both'");
192  }
193  }
194 };
std::string
CharmPupable.hpp
utility
Slab
Definition: Slab.hpp:27
PARSE_ERROR
#define PARSE_ERROR(context, m)
Definition: Options.hpp:71
Options.hpp
Triggers::NearTimes::OptionTags
Definition: NearTimes.hpp:63
cmath
algorithm
Direction
Definition: Direction.hpp:23
Triggers::NearTimes::OptionTags::Range
Definition: NearTimes.hpp:69
Triggers::NearTimes::OptionTags::Times
Definition: NearTimes.hpp:64
Options::Option
Definition: Options.hpp:108
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
Triggers::NearTimes
Definition: NearTimes.hpp:31
Options::create_from_yaml
Definition: MinmodType.hpp:11
TimeDelta
Definition: Time.hpp:88
Trigger
Definition: Trigger.hpp:34
std::numeric_limits::signaling_NaN
T signaling_NaN(T... args)
Time.hpp
limits
Options::Option::parse_as
T parse_as() const
Convert to an object of type T.
Definition: ParseOptions.hpp:76
Time
Definition: Time.hpp:29
Options::String
const char *const String
The string used in option structs.
Definition: Options.hpp:32
Triggers::NearTimes::OptionTags::Direction
Definition: NearTimes.hpp:82
Triggers::NearTimes::OptionTags::Unit
Definition: NearTimes.hpp:76
Slab.hpp
std::unique_ptr< TimeSequence< double > >
TMPL.hpp
string