Simpact Cyan
Population based event driven simulation using mNRM
eventbase.h
Go to the documentation of this file.
1 #ifndef EVENTBASE_H
2 
3 #define EVENTBASE_H
4 
9 #include "algorithm.h"
10 #include <assert.h>
11 #include <stdlib.h>
12 #include <iostream>
13 #include <cmath>
14 
16 
17 // IMPORTANT: this is only meant for positive times! we use a negative
18 // event time to indicate that a recalculation is necessary
19 
55 class EventBase
56 {
57 public:
58  EventBase();
59  virtual ~EventBase();
60 
61  // None of these public functions should be used directly in a simulation, they
62  // are meant to be used in the implementation of a simulation type
63 
75  virtual void fire(Algorithm *pAlgorithm, State *pState, double t);
76 
77  // This calls a virtual function so that a derived class can use another distribution for example,
78  // and does not need to limit itself to a poisson process
79  // Normally the state isn't needed, but it may come in handy, especially when
80  // using a different distribution
81  void generateNewInternalTimeDifference(GslRandomNumberGenerator *pRndGen, const State *pState);
82 
83  double getEventTime() const { return m_tEvent; }
84  double getInternalTimeLeft() const { return m_Tdiff; }
85 
86  // always calculate with current state
87  double solveForRealTimeInterval(const State *pState, double t0);
88 
89  // Note that this doesn't need to be called if the propensity hasn't changed. It is
90  // for that reason that we also store m_tLastCalc
91  void subtractInternalTimeInterval(const State *pState, double t1);
92 
93  // May be useful to check for events that can only happen once
94  // (e.g. someone dying)
95  bool isInitialized() const { return !(m_Tdiff < 0); }
96 
97  bool needsEventTimeCalculation() const { return (m_tEvent < 0); }
98  void setNeedEventTimeCalculation() { m_tEvent = -12345; }
99 
102  bool willBeRemoved() const { return m_willBeRemoved; }
103 
106  void setWillBeRemoved(bool f) { m_willBeRemoved = f; }
107 
110  static bool_t setCheckInverse(bool check);
111 protected:
124  virtual double getNewInternalTimeDifference(GslRandomNumberGenerator *pRndGen, const State *pState);
125 
135  virtual double calculateInternalTimeInterval(const State *pState, double t0, double dt);
136 
147  virtual double solveForRealTimeInterval(const State *pState, double Tdiff, double t0);
148 private:
149  double m_Tdiff;
150  double m_tLastCalc;
151  double m_tEvent; // we'll also use this as a marker to indicate that recalculation is needed
152 
153  bool m_willBeRemoved;
154 #ifndef NDEBUG
155  static bool s_checkInverse;
156 #endif // !NDEBUG
157 };
158 
159 inline double EventBase::solveForRealTimeInterval(const State *pState, double t0)
160 {
161  if (!needsEventTimeCalculation())
162  {
163  double dt = m_tEvent - t0;
164  assert(dt >= 0);
165  return dt;
166  }
167 
168  double dt = solveForRealTimeInterval(pState, m_Tdiff, t0);
169  assert(dt >= 0);
170 
171 #ifndef NDEBUG
172  if (s_checkInverse)
173  {
174  double tmpDT = calculateInternalTimeInterval(pState, t0, dt);
175  double diff = std::abs(tmpDT - m_Tdiff);
176  if (diff > 1e-8)
177  {
178  std::cerr << "ERROR: mismatch 1 between solveForRealTimeInterval and calculateInternalTimeInterval" << std::endl;
179  abort();
180  }
181  }
182 #endif // !NDEBUG
183 
184  m_tEvent = t0 + dt; // automatically marks that we don't need to calculate this again
185  assert(m_tEvent >= 0);
186 
187 #ifdef EVENTBASE_ALWAYS_CHECK_NANTIME
188  if (m_tEvent != m_tEvent)
189  pState->setAbortAlgorithm("NaN detected in internal event time calculation");
190 #endif // EVENTBASE_ALWAYS_CHECK_NANTIME
191 
192  m_tLastCalc = t0;
193 
194  return dt;
195 }
196 
197 inline void EventBase::subtractInternalTimeInterval(const State *pState, double t1)
198 {
199  assert(m_Tdiff >= 0); // Could be the case for simultaneous events
200  assert(m_tLastCalc >= 0);
201 
202  double dT = calculateInternalTimeInterval(pState, m_tLastCalc, t1 - m_tLastCalc);
203 
204 #ifndef NDEBUG
205  if (s_checkInverse)
206  {
207  double dt = t1 - m_tLastCalc;
208  double tmpDt = solveForRealTimeInterval(pState, dT, m_tLastCalc);
209  double diff = std::abs(tmpDt - dt);
210  if (diff > 1e-8)
211  {
212  std::cerr << "ERROR: mismatch 2 between solveForRealTimeInterval and calculateInternalTimeInterval" << std::endl;
213  abort();
214  }
215  }
216 #endif // !NDEBUG
217 
218  // It's possible that due to numerical inaccuracies dT even becomes
219  // negative. Detect and clip.
220 
221  assert(dT >= 0); // can be zero apparently
222  m_Tdiff -= dT;
223 
224 #ifdef EVENTBASE_ALWAYS_CHECK_NANTIME
225  if (m_Tdiff != m_Tdiff)
226  pState->setAbortAlgorithm("NaN detected in internal event time calculation");
227 #endif // EVENTBASE_ALWAYS_CHECK_NANTIME
228 
229 #ifndef NDEBUG
230  if (!(m_Tdiff > -1e-15))
231  std::cerr << "New m_Tdiff is " << m_Tdiff << std::endl;
232 #endif // NDEBUG
233  assert(m_Tdiff > -1e-15); // Error accumulation does happen!
234  if (m_Tdiff < 0)
235  m_Tdiff = 0;
236 
237  setNeedEventTimeCalculation();
238 }
239 
240 #endif // EVENTBASE_H
241 
This class contains the core algorithm (as shown on the main page of the documentation) to execute th...
Definition: algorithm.h:82
This is the base class for events in the mNRM algorithm.
Definition: eventbase.h:56
virtual void fire(Algorithm *pAlgorithm, State *pState, double t)
This function will be called when the event fires, so this should most likely be re-implemented in yo...
Definition: eventbase.cpp:57
bool willBeRemoved() const
Check if the event has been marked for deletion, can avoid a call to the random number generator to c...
Definition: eventbase.h:102
void setWillBeRemoved(bool f)
When an event has fired, by default a new internal fire time will be calculated; setting this flag av...
Definition: eventbase.h:106
virtual double getNewInternalTimeDifference(GslRandomNumberGenerator *pRndGen, const State *pState)
This function will be called to generate a new internal time difference.
Definition: eventbase.cpp:33
static bool_t setCheckInverse(bool check)
In case the program is compiled in debug mode, setting this flag will enable double checking of the m...
Definition: eventbase.cpp:62
virtual double calculateInternalTimeInterval(const State *pState, double t0, double dt)
This function should map the real world time interval onto an internal time interval and return it.
Definition: eventbase.cpp:47
This class allows you to generate random numbers, and uses the GNU Scientific Library for this.
Definition: gslrandomnumbergenerator.h:17
This is a base class describing the simulation state of an mNRM algorithm.
Definition: algorithm.h:24
Type to return true/false with error description.
Definition: booltype.h:26