Version: SMASH-3.1
clock.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2020,2022-2023
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_SMASH_CLOCK_H_
11 #define SRC_INCLUDE_SMASH_CLOCK_H_
12 
13 #include <algorithm>
14 #include <cmath>
15 #include <cstdint>
16 #include <cstdio>
17 #include <limits>
18 #include <stdexcept>
19 #include <vector>
20 
21 #include "logging.h"
22 
23 namespace smash {
24 
25 static constexpr int LClock = LogArea::Clock::id;
26 
86 class Clock {
87  public:
89  using Representation = std::int64_t;
91  virtual double timestep_duration() const = 0;
93  virtual double current_time() const = 0;
95  virtual double next_time() const = 0;
103  virtual void reset(double start_time, bool is_output_clock) = 0;
110  virtual void remove_times_in_past(double start_time) = 0;
119  // guard against overflow:
120  if (counter_ >= std::numeric_limits<Representation>::max() - 1) {
121  throw std::overflow_error("Too many timesteps, clock overflow imminent");
122  }
123  ++counter_;
124  return *this;
125  }
126 
135  Clock& operator+=(Representation advance_several_timesteps) {
136  if (counter_ >= std::numeric_limits<Representation>::max() -
137  advance_several_timesteps) {
138  throw std::overflow_error("Too many timesteps, clock overflow imminent");
139  }
140  counter_ += advance_several_timesteps;
141  return *this;
142  }
143 
149  bool operator<(const Clock& rhs) const {
151  }
152 
158  bool operator<(double time) const { return present_internal_time() < time; }
159 
165  bool operator>(double time) const { return present_internal_time() > time; }
166 
167  virtual ~Clock() = default;
168 
169  protected:
181  virtual double present_internal_time() const = 0;
186 };
187 
209 class UniformClock : public Clock {
222  static constexpr double resolution = 0.000001;
223 
224  public:
226  UniformClock() = default;
234  UniformClock(double time, double dt, double time_end)
236  reset_time_(convert(time)),
237  time_end_(convert(time_end)) {
238  if (dt <= 0.) {
239  throw std::range_error("Time increment must be positive and non-zero");
240  }
241  if (reset_time_ >= time_end_) {
242  throw std::range_error(
243  "The initial time of UniformClock must be smaller than the end time. "
244  "(Attempt to set initial time to " +
245  std::to_string(time) + " and end time to " +
246  std::to_string(time_end) + " not possible)");
247  }
248  }
252  double current_time() const override {
253  auto present_time = present_internal_time();
254  // Do comparison in internal representation unit and return converted values
255  if (convert(present_time) > time_end_) {
256  return convert(time_end_);
257  } else {
258  return present_time;
259  }
260  }
269  double next_time() const override {
271  std::numeric_limits<Representation>::max() - timestep_duration_) {
272  throw std::overflow_error("Too many timesteps, clock overflow imminent");
273  }
274  auto next_point_in_time = reset_time_ + timestep_duration_ * (counter_ + 1);
275  if (next_point_in_time > time_end_) {
276  return convert(time_end_);
277  } else {
278  return convert(next_point_in_time);
279  }
280  }
281 
288  double timestep_duration() const override {
289  auto present_time = convert(present_internal_time());
290  if (present_time > time_end_) {
291  logg[LClock].warn() << "UniformClock asked for timestep duration beyond "
292  "end of simulation, returning 0.";
293  return 0.0;
294  } else if (present_time + timestep_duration_ > time_end_) {
295  return convert(time_end_ - present_time);
296  } else {
297  return convert(timestep_duration_);
298  }
299  }
305  void set_timestep_duration(double dt) {
306  if (dt <= 0.) {
307  throw std::range_error("Time increment must be positive and non-zero!");
308  }
310  counter_ = 0;
312  }
313 
320  void reset(double start_time, bool is_output_clock) override {
321  double reset_time;
322  if (is_output_clock) {
323  auto delta_t = convert(timestep_duration_);
324  reset_time = std::floor(start_time / delta_t) * delta_t;
325  } else {
326  reset_time = start_time;
327  }
328  if (reset_time < current_time()) {
329  logg[LClock].debug("Resetting clock from", current_time(), " fm to ",
330  reset_time, " fm");
331  }
332  reset_time_ = convert(reset_time);
333  counter_ = 0;
334  }
335 
336  void remove_times_in_past(double) override{};
337 
346  template <typename T>
347  typename std::enable_if<std::is_floating_point<T>::value, Clock&>::type
348  operator+=(T big_timestep) {
349  if (big_timestep < 0.) {
350  throw std::range_error("The clock cannot be turned back.");
351  }
352  reset_time_ += convert(big_timestep);
353  return *this;
354  }
363  Clock& operator+=(Representation advance_several_timesteps) {
364  if (counter_ >= std::numeric_limits<Representation>::max() -
365  advance_several_timesteps) {
366  throw std::overflow_error("Too many timesteps, clock overflow imminent");
367  }
368  counter_ += advance_several_timesteps;
369  return *this;
370  }
371 
372  protected:
378  double present_internal_time() const override {
380  }
381 
382  private:
384  static constexpr double to_double = resolution;
386  static constexpr double from_double = 1. / resolution;
387 
389  static Representation convert(double x) {
390  return std::round(x * from_double);
391  }
393  static double convert(Representation x) { return x * to_double; }
394 
401 };
402 
404 class CustomClock : public Clock {
405  public:
411  explicit CustomClock(std::vector<double> times) : custom_times_(times) {
412  std::sort(custom_times_.begin(), custom_times_.end());
413  counter_ = -1;
414  }
419  double current_time() const override {
420  if (counter_ == -1) {
421  // current time before the first output should be the starting time
422  return start_time_;
423  } else if (counter_ < -1) {
424  throw std::runtime_error("Trying to access undefined zeroth output time");
425  } else {
426  return custom_times_[counter_];
427  }
428  }
430  double next_time() const override { return custom_times_[counter_ + 1]; }
431  double timestep_duration() const override {
432  return next_time() - current_time();
433  }
434  void reset(double start_time, bool) override {
435  counter_ = -1;
436  start_time_ = start_time;
437  }
438 
444  void remove_times_in_past(double start_time) override {
445  std::remove_if(custom_times_.begin(), custom_times_.end(),
446  [start_time](double t) {
447  if (t <= start_time) {
448  logg[LClock].warn("Removing custom output time ", t,
449  " fm since it is earlier than the "
450  "starting time of the simulation");
451  return true;
452  } else {
453  return false;
454  }
455  });
456  }
457 
458  protected:
465  double present_internal_time() const override { return current_time(); }
466 
467  private:
469  std::vector<double> custom_times_;
471  double start_time_ = 0.;
472 };
473 } // namespace smash
474 
475 #endif // SRC_INCLUDE_SMASH_CLOCK_H_
Clock tracks the time in the simulation.
Definition: clock.h:86
bool operator<(double time) const
Compares the internal time of the clock against a fixed time.
Definition: clock.h:158
virtual ~Clock()=default
bool operator<(const Clock &rhs) const
Compares the internal times of two clocks.
Definition: clock.h:149
std::int64_t Representation
The type used for counting ticks/time.
Definition: clock.h:89
virtual double current_time() const =0
virtual double timestep_duration() const =0
virtual double present_internal_time() const =0
This function always returns the clock time, even if children might attribute a different behaviour t...
virtual void reset(double start_time, bool is_output_clock)=0
reset the clock to the starting time of the simulation
Representation counter_
Internally used to count the number of time steps.
Definition: clock.h:185
bool operator>(double time) const
Compares the internal time of the clock against a fixed time.
Definition: clock.h:165
Clock & operator++()
Advances the clock by one tick.
Definition: clock.h:118
virtual double next_time() const =0
virtual void remove_times_in_past(double start_time)=0
Remove output times before the starting time of the simulation if this is a custom clock.
Clock & operator+=(Representation advance_several_timesteps)
Advances the clock by an arbitrary number of ticks.
Definition: clock.h:135
Clock with explicitly defined time steps.
Definition: clock.h:404
double next_time() const override
Definition: clock.h:430
CustomClock(std::vector< double > times)
Initialises a custom clock with explicitly given output times.
Definition: clock.h:411
double start_time_
Starting time of the simulation.
Definition: clock.h:471
void remove_times_in_past(double start_time) override
Remove all custom times before start_time.
Definition: clock.h:444
std::vector< double > custom_times_
Vector of times where output is generated.
Definition: clock.h:469
void reset(double start_time, bool) override
reset the clock to the starting time of the simulation
Definition: clock.h:434
double present_internal_time() const override
For the CustomClock, the internal time is basically by design the same as what the current_time() met...
Definition: clock.h:465
double timestep_duration() const override
Definition: clock.h:431
double current_time() const override
Definition: clock.h:419
Clock with uniformly spaced time steps.
Definition: clock.h:209
void reset(double start_time, bool is_output_clock) override
Resets the time to the starting time of an event.
Definition: clock.h:320
static constexpr double from_double
A multiplier transferring the real time to the internal integer.
Definition: clock.h:386
void set_timestep_duration(double dt)
Sets the time step size (and resets the counter).
Definition: clock.h:305
static constexpr double to_double
A multiplier transferring the internal integer to the real time.
Definition: clock.h:384
Representation timestep_duration_
The time step size in .
Definition: clock.h:396
void remove_times_in_past(double) override
Remove output times before the starting time of the simulation if this is a custom clock.
Definition: clock.h:336
UniformClock(double time, double dt, double time_end)
Initialize with base time and time step size.
Definition: clock.h:234
double next_time() const override
Definition: clock.h:269
static constexpr double resolution
Defines the resolution of the clock (namely the smallest representable time difference).
Definition: clock.h:222
Representation time_end_
The end time of the particle propagation.
Definition: clock.h:400
static Representation convert(double x)
Convert a double x into the internal int representation.
Definition: clock.h:389
Representation reset_time_
The time of last reset (when counter_ was set to 0).
Definition: clock.h:398
UniformClock()=default
default initializer: Timestep size is set to 0!
double timestep_duration() const override
Definition: clock.h:288
std::enable_if< std::is_floating_point< T >::value, Clock & >::type operator+=(T big_timestep)
Advances the clock by an arbitrary timestep (multiple of 0.000001 fm).
Definition: clock.h:348
Clock & operator+=(Representation advance_several_timesteps)
advances the clock by an arbitrary number of ticks.
Definition: clock.h:363
static double convert(Representation x)
Convert an internal int value x into the double representation.
Definition: clock.h:393
double current_time() const override
Definition: clock.h:252
double present_internal_time() const override
Access the internal time of the clock, independently from the end time.
Definition: clock.h:378
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
Definition: action.h:24
static constexpr int LClock
Definition: clock.h:25