Simpact Cyan
Population based event driven simulation using mNRM
hazardfunctionformationagegap.h
1 #ifndef HAZARDFUNCTIONFORMATIONAGEGAP_H
2 
3 #define HAZARDFUNCTIONFORMATIONAGEGAP_H
4 
5 #include "hazardfunction.h"
6 #include "person.h"
7 #include <cmath>
8 
9 class HazardFunctionFormationAgeGap : public HazardFunction
10 {
11 public:
12  HazardFunctionFormationAgeGap(const Person *pPerson1, const Person *pPerson2, double tr,
13  double a0, double a1, double a2, double a3, double a4,
14  double a5, double a8, double a9, double a10, double b);
15  ~HazardFunctionFormationAgeGap();
16 
17  double evaluate(double t);
18  double calculateInternalTimeInterval(double t0, double dt);
19  double solveForRealTimeInterval(double t0, double Tdiff);
20 private:
21  void getTippingPoints(double &t1, double &t2, double &B, double &C, double &D);
22  void getEFValues(double t, double B, double C, double D, double &E, double &F);
23  static double calculateIntegral(double t0, double dt, double E, double F);
24  static double solveIntegral(double t0, double Tdiff, double E, double F);
25 
26  const Person *m_pPerson1;
27  const Person *m_pPerson2;
28  const double m_tr, m_a0, m_a1, m_a2, m_a3, m_a4, m_a5, m_a8, m_a9, m_a10, m_b;
29 };
30 
31 inline void HazardFunctionFormationAgeGap::getTippingPoints(double &t1, double &t2, double &B, double &C, double &D)
32 {
33  double Pi = m_pPerson1->getNumberOfRelationships();
34  double Pj = m_pPerson2->getNumberOfRelationships();
35  double tBi = m_pPerson1->getDateOfBirth();
36  double tBj = m_pPerson2->getDateOfBirth();
37  double Dpi = m_pPerson1->getPreferredAgeDifference();
38  double Dpj = m_pPerson2->getPreferredAgeDifference();
39 
40  B = m_a0 + m_a1*Pi + m_a2*Pj + m_a3*std::abs(Pi-Pj) - m_a4*(tBi+tBj)/2.0 - m_b*m_tr;
41  C = (m_a8-1.0)*tBi + tBj - Dpi;
42  D = (m_a10+1.0)*tBj - tBi - Dpj;
43 
44  if (m_a8 == 0 || m_a10 == 0)
45  {
46  if (m_a8 != 0)
47  {
48  t1 = C/m_a8;
49  t2 = -1e200;
50  }
51  else if (m_a10 != 0)
52  {
53  t1 = D/m_a10;
54  t2 = -1e200;
55  }
56  else // both are zero, this case should never happen, should already be handled
57  {
58  t1 = -1e200;
59  t2 = -1e200;
60  }
61  }
62  else
63  {
64  t1 = C/m_a8;
65  t2 = D/m_a10;
66 
67  if (t1 > t2)
68  std::swap(t1, t2);
69  }
70 }
71 
72 inline void HazardFunctionFormationAgeGap::getEFValues(double t, double B, double C, double D, double &E, double &F)
73 {
74  double a8t = m_a8*t;
75  double a10t = m_a10*t;
76 
77  if (C > a8t)
78  {
79  if (D > a10t)
80  {
81  E = B + m_a5*C + m_a9*D;
82  F = m_a4 + m_b - m_a5*m_a8 - m_a9*m_a10;
83  }
84  else
85  {
86  E = B + m_a5*C - m_a9*D;
87  F = m_a4 + m_b - m_a5*m_a8 + m_a9*m_a10;
88  }
89  }
90  else
91  {
92  if (D > a10t)
93  {
94  E = B - m_a5*C + m_a9*D;
95  F = m_a4 + m_b + m_a5*m_a8 - m_a9*m_a10;
96  }
97  else
98  {
99  E = B - m_a5*C - m_a9*D;
100  F = m_a4 + m_b + m_a5*m_a8 + m_a9*m_a10;
101  }
102  }
103 }
104 
105 inline double HazardFunctionFormationAgeGap::calculateIntegral(double t0, double dt, double E, double F)
106 {
107  double dT = 0;
108 
109  if (F == 0)
110  dT = std::exp(E)*dt;
111  else
112  dT = std::exp(E+F*t0)*(std::exp(F*dt) - 1.0)/F;
113 
114  return dT;
115 }
116 
117 inline double HazardFunctionFormationAgeGap::solveIntegral(double t0, double Tdiff, double E, double F)
118 {
119  double dt = 0;
120 
121  if (F == 0)
122  dt = Tdiff/std::exp(E);
123  else
124  dt = 1.0/F*std::log(F*Tdiff/std::exp(E+F*t0)+1.0);
125 
126  return dt;
127 }
128 
129 #endif // HAZARDFUNCTIONFORMATIONAGEGAP2_H
Abstract base class which can be used for a hazard.
Definition: hazardfunction.h:18
virtual double calculateInternalTimeInterval(double t0, double dt)=0
Map the real-world time dt to an internal time interval.
virtual double solveForRealTimeInterval(double t0, double Tdiff)=0
For the specified internal time interval Tdiff, calculate the corresponding real-world time interval...
virtual double evaluate(double t)=0
Evaluate the hazard at time t.