Time.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Defines Time and TimeDelta
6 
7 #pragma once
8 
9 #include <cstddef>
10 #include <functional>
11 #include <iosfwd>
12 #include <limits>
13 #include <utility>
14 
15 #include "ErrorHandling/Assert.hpp"
16 #include "Time/Slab.hpp"
17 #include "Utilities/Rational.hpp"
18 
19 /// \cond
20 namespace PUP {
21 class er;
22 } // namespace PUP
23 class TimeDelta;
24 /// \endcond
25 
26 /// \ingroup TimeGroup
27 ///
28 /// The time in a simulation. Times can be safely compared for exact
29 /// equality as long as they do not belong to overlapping unequal
30 /// slabs.
31 class Time {
32  public:
33  using rational_t = Rational;
34 
35  /// Default constructor gives an invalid Time.
36  Time() noexcept : fraction_(0) {}
37 
38  /// A time a given fraction of the way through the given slab.
39  Time(Slab slab, rational_t fraction) noexcept
40  // clang-tidy: move trivially copyable type
41  : slab_(std::move(slab)), fraction_(std::move(fraction)) { // NOLINT
42  range_check();
43  compute_value();
44  }
45 
46  /// Move the time to a different slab. The time must be at an end
47  /// of the current slab and the new slab must share that endpoint.
48  Time with_slab(const Slab& new_slab) const noexcept;
49 
50  /// Approximate numerical value of the Time.
51  double value() const noexcept { return value_; }
52  const Slab& slab() const noexcept { return slab_; }
53  const rational_t& fraction() const noexcept { return fraction_; }
54 
55  Time& operator+=(const TimeDelta& delta) noexcept;
56  Time& operator-=(const TimeDelta& delta) noexcept;
57 
58  bool is_at_slab_start() const noexcept { return fraction_ == 0; }
59  bool is_at_slab_end() const noexcept { return fraction_ == 1; }
60  bool is_at_slab_boundary() const noexcept {
61  return is_at_slab_start() or is_at_slab_end();
62  }
63 
64  // clang-tidy: google-runtime-references
65  void pup(PUP::er& p) noexcept; // NOLINT
66 
67  /// A comparison operator that compares Times structurally, i.e.,
68  /// just looking at the class members. This is only intended for
69  /// use as the comparator in a map. The returned ordering does not
70  /// match the time ordering and opposite sides of slab boundaries do
71  /// not compare equal. It is, however, much faster to compute than
72  /// the temporal ordering, so it is useful when an ordering is
73  /// required, but the ordering does not have to be physically
74  /// meaningful.
76  bool operator()(const Time& a, const Time& b) const {
77  if (a.fraction().numerator() != b.fraction().numerator()) {
78  return a.fraction().numerator() < b.fraction().numerator();
79  }
80  if (a.fraction().denominator() != b.fraction().denominator()) {
81  return a.fraction().denominator() < b.fraction().denominator();
82  }
83  return a.slab() < b.slab();
84  }
85  };
86 
87  private:
88  Slab slab_;
89  rational_t fraction_;
91 
92  // The value is precomputed so that we can avoid doing the rational
93  // math repeatedly. The value of a Time should almost always be
94  // needed at some point.
95  void compute_value() noexcept;
96 
97  inline void range_check() const noexcept {
98  ASSERT(fraction_ >= 0 and fraction_ <= 1,
99  "Out of range slab fraction: " << fraction_);
100  }
101 
102  friend class TimeDelta;
103 };
104 
105 /// \ingroup TimeGroup
106 ///
107 /// Represents an interval of time within a single slab.
108 class TimeDelta {
109  public:
111 
112  /// Default constructor gives an invalid TimeDelta.
113  TimeDelta() noexcept : fraction_(0) {}
114 
115  /// An interval covering a given fraction of the slab.
116  TimeDelta(Slab slab, rational_t fraction) noexcept
117  // clang-tidy: move trivially copyable type
118  : slab_(std::move(slab)), fraction_(std::move(fraction)) {} // NOLINT
119 
120  /// Move the interval to a different slab. The resulting interval
121  /// will in general not be the same length, but will take up the
122  /// same fraction of its slab.
123  TimeDelta with_slab(const Slab& new_slab) const noexcept {
124  return {new_slab, fraction()};
125  }
126 
127  Slab slab() const noexcept { return slab_; }
128  rational_t fraction() const noexcept { return fraction_; }
129 
130  /// Approximate numerical length of the interval.
131  double value() const noexcept {
132  return (slab_.end_ - slab_.start_) * fraction_.value();
133  }
134 
135  /// Test if the interval is oriented towards larger time.
136  bool is_positive() const noexcept { return fraction_ > 0; }
137 
138  TimeDelta& operator+=(const TimeDelta& other) noexcept;
139  TimeDelta& operator-=(const TimeDelta& other) noexcept;
140  TimeDelta operator+() const noexcept;
141  TimeDelta operator-() const noexcept;
142  TimeDelta& operator*=(const rational_t& mult) noexcept;
143  TimeDelta& operator/=(const rational_t& div) noexcept;
144 
145  // clang-tidy: google-runtime-references
146  void pup(PUP::er& p) noexcept; // NOLINT
147 
148  private:
149  Slab slab_;
150  rational_t fraction_;
151 
152  friend class Time;
153 };
154 
155 // Time <cmp> Time
156 // clang-tidy: clang-tidy wants this removed in favor of friend
157 // declaration in different header.
158 bool operator==(const Time& a, const Time& b) noexcept; // NOLINT
159 inline bool operator!=(const Time& a, const Time& b) noexcept {
160  return not(a == b);
161 }
162 inline bool operator<(const Time& a, const Time& b) noexcept {
163  // Non-equality test in second clause is required to avoid
164  // assertions in Slab.
165  return (a.slab() == b.slab() and a.fraction() < b.fraction()) or
166  (a != b and a.slab() < b.slab());
167 }
168 inline bool operator>(const Time& a, const Time& b) noexcept {
169  return b < a;
170 }
171 inline bool operator<=(const Time& a, const Time& b) noexcept {
172  return not(a > b);
173 }
174 inline bool operator>=(const Time& a, const Time& b) noexcept {
175  return not(a < b);
176 }
177 
178 // TimeDelta <cmp> TimeDelta
179 inline bool operator==(const TimeDelta& a, const TimeDelta& b) noexcept {
180  return a.slab() == b.slab() and a.fraction() == b.fraction();
181 }
182 inline bool operator!=(const TimeDelta& a, const TimeDelta& b) noexcept {
183  return not(a == b);
184 }
185 inline bool operator<(const TimeDelta& a, const TimeDelta& b) noexcept {
186  ASSERT(a.slab() == b.slab(),
187  "Can't check cross-slab TimeDelta inequalities");
188  return a.fraction() < b.fraction();
189 }
190 inline bool operator>(const TimeDelta& a, const TimeDelta& b) noexcept {
191  return b < a;
192 }
193 inline bool operator<=(const TimeDelta& a, const TimeDelta& b) noexcept {
194  return not(a > b);
195 }
196 inline bool operator>=(const TimeDelta& a, const TimeDelta& b) noexcept {
197  return not(a < b);
198 }
199 
200 // Time <op> Time
201 TimeDelta operator-(const Time& a, const Time& b) noexcept;
202 
203 // Time <op> TimeDelta, TimeDelta <op> Time
204 inline Time operator+(Time a, const TimeDelta& b) noexcept {
205  a += b;
206  return a;
207 }
208 
209 inline Time operator+(const TimeDelta& a, Time b) noexcept {
210  b += a;
211  return b;
212 }
213 
214 inline Time operator-(Time a, const TimeDelta& b) noexcept {
215  a -= b;
216  return a;
217 }
218 
219 // TimeDelta <op> TimeDelta
220 inline TimeDelta operator+(TimeDelta a, const TimeDelta& b) noexcept {
221  a += b;
222  return a;
223 }
224 
225 inline TimeDelta operator-(TimeDelta a, const TimeDelta& b) noexcept {
226  a -= b;
227  return a;
228 }
229 
230 // This returns a double rather than a rational so we can compare dt
231 // in different slabs.
232 double operator/(const TimeDelta& a, const TimeDelta& b) noexcept;
233 
234 // rational <op> TimeDelta, TimeDelta <op> rational
235 inline TimeDelta operator*(TimeDelta a,
236  const TimeDelta::rational_t& b) noexcept {
237  a *= b;
238  return a;
239 }
240 
242  TimeDelta b) noexcept {
243  b *= a;
244  return b;
245 }
246 
247 inline TimeDelta operator/(TimeDelta a,
248  const TimeDelta::rational_t& b) noexcept {
249  a /= b;
250  return a;
251 }
252 
253 inline TimeDelta abs(TimeDelta t) noexcept {
254  if (not t.is_positive()) {
255  t *= -1;
256  }
257  return t;
258 }
259 
260 std::ostream& operator<<(std::ostream& os, const Time& t) noexcept;
261 
262 std::ostream& operator<<(std::ostream& os, const TimeDelta& dt) noexcept;
263 
264 // Time member functions
265 inline Time& Time::operator+=(const TimeDelta& delta) noexcept {
266  *this = this->with_slab(delta.slab_);
267  fraction_ += delta.fraction_;
268  range_check();
269  compute_value();
270  return *this;
271 }
272 
273 inline Time& Time::operator-=(const TimeDelta& delta) noexcept {
274  *this = this->with_slab(delta.slab_);
275  fraction_ -= delta.fraction_;
276  range_check();
277  compute_value();
278  return *this;
279 }
280 
281 // TimeDelta member functions
282 inline TimeDelta& TimeDelta::operator+=(const TimeDelta& other) noexcept {
283  ASSERT(slab_ == other.slab_, "Can't add TimeDeltas from different slabs");
284  fraction_ += other.fraction_;
285  return *this;
286 }
287 
288 inline TimeDelta& TimeDelta::operator-=(const TimeDelta& other) noexcept {
289  ASSERT(slab_ == other.slab_,
290  "Can't subtract TimeDeltas from different slabs");
291  fraction_ -= other.fraction_;
292  return *this;
293 }
294 
295 inline TimeDelta TimeDelta::operator+() const noexcept { return *this; }
296 
297 inline TimeDelta TimeDelta::operator-() const noexcept {
298  return {slab_, -fraction_};
299 }
300 
301 inline TimeDelta& TimeDelta::operator*=(const rational_t& mult) noexcept {
302  fraction_ *= mult;
303  return *this;
304 }
305 
306 inline TimeDelta& TimeDelta::operator/=(const rational_t& div) noexcept {
307  fraction_ /= div;
308  return *this;
309 }
310 
311 size_t hash_value(const Time& t) noexcept;
312 
313 namespace std {
314 template <>
315 struct hash<Time> {
316  size_t operator()(const Time& t) const noexcept;
317 };
318 } // namespace std
Definition: Strahlkorper.hpp:14
bool operator>(const Slab &a, const Slab &b) noexcept
Slab comparison operators give the time ordering. Overlapping unequal slabs should not be compared (a...
Definition: Slab.hpp:122
T signaling_NaN(T... args)
Time() noexcept
Default constructor gives an invalid Time.
Definition: Time.hpp:36
The time in a simulation. Times can be safely compared for exact equality as long as they do not belo...
Definition: Time.hpp:31
Time with_slab(const Slab &new_slab) const noexcept
Move the time to a different slab. The time must be at an end of the current slab and the new slab mu...
Definition: Time.cpp:18
auto operator*(const TensorExpression< T1, X, Symm1, IndexList1, Args1 > &t1, const TensorExpression< T2, X, Symm2, IndexList2, Args2 > &t2)
Definition: Product.hpp:89
A chunk of time. Every element must reach slab boundaries exactly, no matter how it actually takes ti...
Definition: Slab.hpp:29
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
Prefix indicating the divergence.
Definition: Divergence.hpp:40
bool operator<=(const Slab &a, const Slab &b) noexcept
Slab comparison operators give the time ordering. Overlapping unequal slabs should not be compared (a...
Definition: Slab.hpp:125
double value() const noexcept
Approximate numerical value of the Time.
Definition: Time.hpp:51
bool is_positive() const noexcept
Test if the interval is oriented towards larger time.
Definition: Time.hpp:136
TimeDelta(Slab slab, rational_t fraction) noexcept
An interval covering a given fraction of the slab.
Definition: Time.hpp:116
TimeDelta() noexcept
Default constructor gives an invalid TimeDelta.
Definition: Time.hpp:113
A rational number.
Definition: Rational.hpp:24
Time(Slab slab, rational_t fraction) noexcept
A time a given fraction of the way through the given slab.
Definition: Time.hpp:39
Represents an interval of time within a single slab.
Definition: Time.hpp:108
Defines class Slab.
Defines macro ASSERT.
TimeDelta with_slab(const Slab &new_slab) const noexcept
Move the interval to a different slab. The resulting interval will in general not be the same length...
Definition: Time.hpp:123
A comparison operator that compares Times structurally, i.e., just looking at the class members...
Definition: Time.hpp:75
double value() const noexcept
Approximate numerical length of the interval.
Definition: Time.hpp:131
bool operator>=(const Slab &a, const Slab &b) noexcept
Slab comparison operators give the time ordering. Overlapping unequal slabs should not be compared (a...
Definition: Slab.hpp:128
bool operator<(const Slab &a, const Slab &b) noexcept
Slab comparison operators give the time ordering. Overlapping unequal slabs should not be compared (a...
Definition: Slab.hpp:117