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 "state.h"
10 #include <assert.h>
11 #include <stdlib.h>
12 #include <iostream>
13 #include <cmath>
14 
16 
17 // To perform a check on solveForRealTimeInterval <-> calculateInternalTimeInterval compatibility
18 #ifndef NDEBUG
19  #define EVENTBASE_CHECK_INVERSE
20 #endif // NDEBUG
21 
22 // IMPORTANT: this is only meant for positive times! we use a negative
23 // event time to indicate that a recalculation is necessary
24 
60 class EventBase
61 {
62 public:
63  EventBase();
64  virtual ~EventBase();
65 
66  // None of these public functions should be used directly in a simulation, they
67  // are meant to be used in the implementation of a simulation type
68 
76  virtual void fire(State *pState, double t);
77 
78  // This calls a virtual function so that a derived class can use another distribution for example,
79  // and does not need to limit itself to a poisson process
80  // Normally the state isn't needed, but it may come in handy, especially when
81  // using a different distribution
82  void generateNewInternalTimeDifference(GslRandomNumberGenerator *pRndGen, const State *pState);
83 
84  double getEventTime() const { return m_tEvent; }
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 
100  bool willBeRemoved() const { return m_willBeRemoved; }
101  void setWillBeRemoved(bool f) { m_willBeRemoved = f; }
102 protected:
115  virtual double getNewInternalTimeDifference(GslRandomNumberGenerator *pRndGen, const State *pState);
116 
126  virtual double calculateInternalTimeInterval(const State *pState, double t0, double dt);
127 
138  virtual double solveForRealTimeInterval(const State *pState, double Tdiff, double t0);
139 private:
140  double m_Tdiff;
141  double m_tLastCalc;
142  double m_tEvent; // we'll also use this as a marker to indicate that recalculation is needed
143 
144  bool m_willBeRemoved;
145 };
146 
147 inline double EventBase::solveForRealTimeInterval(const State *pState, double t0)
148 {
149  if (!needsEventTimeCalculation())
150  {
151  double dt = m_tEvent - t0;
152  assert(dt >= 0);
153  return dt;
154  }
155 
156  double dt = solveForRealTimeInterval(pState, m_Tdiff, t0);
157  assert(dt >= 0);
158 
159 #ifdef EVENTBASE_CHECK_INVERSE
160  double tmpDT = calculateInternalTimeInterval(pState, t0, dt);
161  double diff = std::abs(tmpDT - m_Tdiff);
162  if (diff > 1e-10)
163  {
164  std::cerr << "ERROR: mismatch 1 between solveForRealTimeInterval and calculateInternalTimeInterval" << std::endl;
165  exit(-1);
166  }
167 #endif // EVENTBASE_CHECK_INVERSE
168 
169  m_tEvent = t0 + dt; // automatically marks that we don't need to calculate this again
170  assert(m_tEvent >= 0);
171 
172  m_tLastCalc = t0;
173 
174  return dt;
175 }
176 
177 inline void EventBase::subtractInternalTimeInterval(const State *pState, double t1)
178 {
179  assert(m_Tdiff >= 0); // Could be the case for simultaneous events
180  assert(m_tLastCalc >= 0);
181 
182  double dT = calculateInternalTimeInterval(pState, m_tLastCalc, t1 - m_tLastCalc);
183 
184 #ifdef EVENTBASE_CHECK_INVERSE
185  double dt = t1 - m_tLastCalc;
186  double tmpDt = solveForRealTimeInterval(pState, dT, m_tLastCalc);
187  double diff = std::abs(tmpDt - dt);
188  if (diff > 1e-10)
189  {
190  std::cerr << "ERROR: mismatch 2 between solveForRealTimeInterval and calculateInternalTimeInterval" << std::endl;
191  exit(-1);
192  }
193 #endif // EVENTBASE_CHECK_INVERSE
194 
195  // It's possible that due to numerical inaccuracies dT even becomes
196  // negative. Detect and clip.
197 
198  assert(dT >= 0); // can be zero apparently
199  m_Tdiff -= dT;
200 
201 #ifndef NDEBUG
202  if (!(m_Tdiff > -1e-15))
203  std::cerr << "New m_Tdiff is " << m_Tdiff << std::endl;
204 #endif // NDEBUG
205  assert(m_Tdiff > -1e-15); // Error accumulation does happen!
206  if (m_Tdiff < 0)
207  m_Tdiff = 0;
208 
209  setNeedEventTimeCalculation();
210 }
211 
212 
213 #endif // EVENTBASE_H
This class both describes the simulation state and contains the core algorithm (as shown on the main ...
Definition: state.h:40
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:42
This class allows you to generate random numbers, and uses the GNU Scientific Library for this...
Definition: gslrandomnumbergenerator.h:15
virtual void fire(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:52
This is the base class for events in the mNRM algorithm.
Definition: eventbase.h:60
virtual double getNewInternalTimeDifference(GslRandomNumberGenerator *pRndGen, const State *pState)
This function will be called to generate a new internal time difference.
Definition: eventbase.cpp:28