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 #include <vector>
13 
14 #include "Options/Options.hpp"
16 #include "ParallelAlgorithms/EventsAndTriggers/Trigger.hpp"
17 #include "Time/Slab.hpp"
18 #include "Time/Time.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 SpecifiedTimes
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 Options {
64  struct Times {
65  using type = std::vector<double>;
66  static constexpr OptionString 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 OptionString help =
73  "Maximum time difference to trigger at";
74  };
75 
76  struct Unit {
77  using type = NearTimes::Unit;
78  static constexpr OptionString help =
79  "Interpret Range as 'Time', 'Step's, or 'Slab's";
80  };
81 
82  struct Direction {
83  using type = NearTimes::Direction;
84  static constexpr OptionString help =
85  "Trigger 'Before', 'After', or 'Both' from the times";
86  };
87  };
88 
89  static constexpr OptionString help =
90  "Trigger in intervals surrounding particular times.";
91  using options =
92  tmpl::list<typename Options::Times, typename Options::Range,
93  typename Options::Unit, typename Options::Direction>;
94 
95  NearTimes(std::vector<double> times, const double range, const Unit unit,
96  const Direction direction) noexcept
97  : times_(std::move(times)),
98  range_(range),
99  unit_(unit),
100  direction_(direction) {
101  std::sort(times_.begin(), times_.end());
102  }
103 
104  using argument_tags = tmpl::list<Tags::Time, Tags::TimeStep>;
105 
106  bool operator()(const double now, const TimeDelta& time_step) const noexcept {
107  const bool time_runs_forward = time_step.is_positive();
108 
109  double range_code_units = range_;
110  if (unit_ == Unit::Slab) {
111  range_code_units *= time_step.slab().duration().value();
112  } else if (unit_ == Unit::Step) {
113  range_code_units *= std::abs(time_step.value());
114  }
115 
116  if (not time_runs_forward) {
117  range_code_units = -range_code_units;
118  }
119 
120  // Interval around now to look for trigger times in.
121  auto trigger_range = std::make_pair(
122  direction_ == Direction::Before ? now : now - range_code_units,
123  direction_ == Direction::After ? now : now + range_code_units);
124 
125  if (not time_runs_forward) {
126  std::swap(trigger_range.first, trigger_range.second);
127  }
128 
129  const auto next_time =
130  std::lower_bound(times_.begin(), times_.end(), trigger_range.first);
131  return next_time != times_.end() and *next_time <= trigger_range.second;
132  }
133 
134  // NOLINTNEXTLINE(google-runtime-references)
135  void pup(PUP::er& p) noexcept {
136  p | times_;
137  p | range_;
138  p | unit_;
139  p | direction_;
140  }
141 
142  private:
143  std::vector<double> times_{};
145  Unit unit_{};
146  Direction direction_{};
147 };
148 
149 /// \cond
150 template <typename TriggerRegistrars>
151 PUP::able::PUP_ID NearTimes<TriggerRegistrars>::my_PUP_ID = 0; // NOLINT
152 /// \endcond
153 } // namespace Triggers
154 
155 template <>
156 struct create_from_yaml<Triggers::NearTimes_enums::Unit> {
157  using type = Triggers::NearTimes_enums::Unit;
158  template <typename Metavariables>
159  static type create(const Option& options) {
160  const std::string unit = options.parse_as<std::string>();
161  if (unit == "Time") {
162  return type::Time;
163  } else if (unit == "Step") {
164  return type::Step;
165  } else if (unit == "Slab") {
166  return type::Slab;
167  } else {
168  PARSE_ERROR(options.context(), "Unit must be 'Time', 'Step', or 'Slab'");
169  }
170  }
171 };
172 
173 template <>
174 struct create_from_yaml<typename Triggers::NearTimes_enums::Direction> {
175  using type = Triggers::NearTimes_enums::Direction;
176  template <typename Metavariables>
177  static type create(const Option& options) {
178  const std::string unit = options.parse_as<std::string>();
179  if (unit == "Before") {
180  return type::Before;
181  } else if (unit == "After") {
182  return type::After;
183  } else if (unit == "Both") {
184  return type::Both;
185  } else {
186  PARSE_ERROR(options.context(),
187  "Direction must be 'Before', 'After', or 'Both'");
188  }
189  }
190 };
std::string
CharmPupable.hpp
utility
Triggers::NearTimes::Options
Definition: NearTimes.hpp:63
Slab
Definition: Slab.hpp:27
PARSE_ERROR
#define PARSE_ERROR(context, m)
Definition: Options.hpp:70
Options.hpp
vector
Triggers::NearTimes::Options::Times
Definition: NearTimes.hpp:64
cmath
algorithm
Direction
Definition: Direction.hpp:23
Registration::Registrar
A template for defining a registrar.
Definition: Registration.hpp:42
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
Option::parse_as
T parse_as() const
Convert to an object of type T.
Definition: ParseOptions.hpp:77
TimeDelta
Definition: Time.hpp:88
Triggers::NearTimes::Options::Range
Definition: NearTimes.hpp:69
Trigger
Definition: Trigger.hpp:34
std::numeric_limits::signaling_NaN
T signaling_NaN(T... args)
Time.hpp
create_from_yaml
Definition: MinmodType.hpp:10
Option
Definition: Options.hpp:107
limits
Time
Definition: Time.hpp:29
Triggers::NearTimes::Options::Unit
Definition: NearTimes.hpp:76
Triggers::NearTimes::Options::Direction
Definition: NearTimes.hpp:82
Slab.hpp
OptionString
const char *const OptionString
The string used in option structs.
Definition: Options.hpp:30
TMPL.hpp
string