Stride Reference Manual  1.0
Infector.cpp
Go to the documentation of this file.
1 /*
2  * This is free software: you can redistribute it and/or modify it
3  * under the terms of the GNU General Public License as published by
4  * the Free Software Foundation, either version 3 of the License, or
5  * any later version.
6  * The software is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  * You should have received a copy of the GNU General Public License
11  * along with the software. If not, see <http://www.gnu.org/licenses/>.
12  *
13  * Copyright 2017, Willem L, Kuylen E, Stijven S & Broeckhove J
14  */
15 
21 #include "calendar/Calendar.h"
22 #include "core/Cluster.h"
23 #include "core/Health.h"
24 #include "core/Infector.h"
25 #include "core/LogMode.h"
26 #include "pop/Person.h"
27 #include "util/Random.h"
28 
29 #include <spdlog/spdlog.h>
30 #include <cstddef>
31 #include <memory>
32 #include <utility>
33 #include <vector>
34 
35 namespace stride {
36 
37 using namespace std;
38 using namespace util;
39 
43 template<bool track_index_case = false>
44 class R0_POLICY {
45 public:
46  static void execute(Simulator::PersonType* p) {}
47 };
48 
52 template<>
53 class R0_POLICY<true> {
54 public:
55  static void execute(Simulator::PersonType* p) { p->getHealth().stopInfection(); }
56 };
57 
61 template<LogMode log_level = LogMode::None>
62 class LOG_POLICY {
63 public:
64  static void execute(spdlog::logger& logger, Simulator::PersonType* p1, Simulator::PersonType* p2,
65  ClusterType cluster_type, shared_ptr<const Calendar> environ) {}
66 };
67 
71 template<>
72 class LOG_POLICY<LogMode::Transmissions> {
73 public:
74  static void execute(spdlog::logger& logger, Simulator::PersonType* p1, Simulator::PersonType* p2,
75  ClusterType cluster_type, shared_ptr<const Calendar> environ) {
76  logger.info("[TRAN] {} {} {} {}",
77  p1->getId(), p2->getId(), toString(cluster_type), environ->getSimulationDay());
78  }
79 };
80 
84 template<>
85 class LOG_POLICY<LogMode::Contacts> {
86 public:
87  static void execute(spdlog::logger& logger, Simulator::PersonType* p1, Simulator::PersonType* p2,
88  ClusterType cluster_type, shared_ptr<const Calendar> calendar) {
89  unsigned int home = (cluster_type == ClusterType::Household);
90  unsigned int work = (cluster_type == ClusterType::Work);
91  unsigned int school = (cluster_type == ClusterType::School);
92  unsigned int primary_community = (cluster_type == ClusterType::PrimaryCommunity);
93  unsigned int secundary_community = (cluster_type == ClusterType::SecondaryCommunity);
94 
95  logger.info("[CONT] {} {} {} {} {} {} {} {} {}",
96  p1->getId(), p1->getAge(), p2->getAge(), home, school, work, primary_community,
97  secundary_community,
98  calendar->getSimulationDay());
99  }
100 };
101 
102 //--------------------------------------------------------------------------
103 // Definition for primary template covers the situation for
104 // LogMode::None & LogMode::Transmissions, both with
105 // track_index_case false and true.
106 // And every local information policy except NoLocalInformation
107 //--------------------------------------------------------------------------
108 template<LogMode log_level, bool track_index_case, typename local_information_policy>
110  Cluster& cluster, DiseaseProfile disease_profile,
111  util::Random& contact_handler, shared_ptr<const Calendar> calendar, spdlog::logger& logger) {
112  cluster.updateMemberPresence();
113 
114  // set up some stuff
115  const auto c_type = cluster.m_cluster_type;
116  const auto& c_members = cluster.m_members;
117  const auto transmission_rate = disease_profile.getTransmissionRate();
118 
119  // check all contacts
120  for (size_t i_person1 = 0; i_person1 < c_members.size(); i_person1++) {
121  // check if member is present today
122  if (c_members[i_person1].second) {
123  auto p1 = c_members[i_person1].first;
124  const double contact_rate = cluster.getContactRate(p1);
125 
126  // loop over possible contacts
127  // FIXME should this loop start from 0? Because of asymm. contact rates
128  for (size_t i_person2 = i_person1 + 1; i_person2 < c_members.size(); i_person2++) {
129  // check if member is present today
130  if (c_members[i_person2].second) {
131  auto p2 = c_members[i_person2].first;
132 
133  // check for contact
134  if (contact_handler.hasContact(contact_rate)) {
135  // exchange information about health state & beliefs
136  local_information_policy::update(p1, p2);
137 
138  bool transmission = contact_handler.hasTransmission(transmission_rate);
139  if (transmission) {
140  if (p1->getHealth().isInfectious() && p2->getHealth().isSusceptible()) {
141  LOG_POLICY<log_level>::execute(logger, p1, p2, c_type, calendar);
142  p2->getHealth().startInfection();
143  R0_POLICY<track_index_case>::execute(p2);
144  } else if (p2->getHealth().isInfectious() && p1->getHealth().isSusceptible()) {
145  LOG_POLICY<log_level>::execute(logger, p2, p1, c_type, calendar);
146  p1->getHealth().startInfection();
147  R0_POLICY<track_index_case>::execute(p1);
148  }
149  }
150  }
151  }
152  }
153  }
154  }
155 }
156 
157 
158 //-------------------------------------------------------------------------------------------
159 // Definition of partial specialization for LocalInformationPolicy:NoLocalInformation.
160 //-------------------------------------------------------------------------------------------
161 template<LogMode log_level, bool track_index_case>
163  Cluster& cluster, DiseaseProfile disease_profile,
164  util::Random& contact_handler, shared_ptr<const Calendar> calendar, spdlog::logger& logger) {
165 
166  // check if the cluster has infected members and sort
167  bool infectious_cases;
168  size_t num_cases;
169  tie(infectious_cases, num_cases) = cluster.sortMembers();
170 
171  if (infectious_cases) {
172  cluster.updateMemberPresence();
173 
174  // set up some stuff
175  const auto c_type = cluster.m_cluster_type;
176  const auto c_immune = cluster.m_index_immune;
177  const auto& c_members = cluster.m_members;
178  const auto transmission_rate = disease_profile.getTransmissionRate();
179 
180  // match infectious in first part with susceptible in second part, skip last part (immune)
181  for (size_t i_infected = 0; i_infected < num_cases; i_infected++) {
182  // check if member is present today
183  if (c_members[i_infected].second) {
184  const auto p1 = c_members[i_infected].first;
185  // FIXME Is it necessary to check for infectiousness here? Infectious members are already sorted...
186  if (p1->getHealth().isInfectious()) {
187  const double contact_rate = cluster.getContactRate(p1);
188  // FIXME if loop 2 in all contacts algorithm should start from 0, we should also implement this symmetry here!
189  for (size_t i_contact = num_cases; i_contact < c_immune; i_contact++) {
190  // check if member is present today
191  if (c_members[i_contact].second) {
192  auto p2 = c_members[i_contact].first;
193  if (contact_handler.hasContactAndTransmission(contact_rate, transmission_rate)) {
194  LOG_POLICY<log_level>::execute(logger, p1, p2, c_type, calendar);
195  p2->getHealth().startInfection();
196  R0_POLICY<track_index_case>::execute(p2);
197  }
198  }
199  }
200  }
201  }
202  }
203  }
204 }
205 
206 
207 //-------------------------------------------------------------------------------------------
208 // Definition of partial specialization for LogMode::Contacts and NoLocalInformation policy.
209 //-------------------------------------------------------------------------------------------
210 template<bool track_index_case>
212  Cluster& cluster, DiseaseProfile disease_profile,
213  util::Random& contact_handler, shared_ptr<const Calendar> calendar, spdlog::logger& logger) {
214 
215  cluster.updateMemberPresence();
216 
217  // set up some stuff
218  const auto c_type = cluster.m_cluster_type;
219  const auto& c_members = cluster.m_members;
220  const auto transmission_rate = disease_profile.getTransmissionRate();
221 
222  // check all contacts
223  for (size_t i_person1 = 0; i_person1 < c_members.size(); i_person1++) {
224  // check if member participates in the social contact survey && member is present today
225  if (c_members[i_person1].second && c_members[i_person1].first->isParticipatingInSurvey()) {
226  auto p1 = c_members[i_person1].first;
227  const double contact_rate = cluster.getContactRate(p1);
228  // loop over possible contacts
229  for (size_t i_person2 = i_person1 + 1; i_person2 < c_members.size(); i_person2++) {
230  // check if member is present today
231  if (c_members[i_person2].second) {
232  auto p2 = c_members[i_person2].first;
233  // check for contact
234  if (contact_handler.hasContact(contact_rate)) {
235  bool transmission = contact_handler.hasTransmission(transmission_rate);
236  if (transmission) {
237  if (p1->getHealth().isInfectious() && p2->getHealth().isSusceptible()) {
238  p2->getHealth().startInfection();
239  R0_POLICY<track_index_case>::execute(p2);
240  } else if (p2->getHealth().isInfectious() && p1->getHealth().isSusceptible()) {
241  p1->getHealth().startInfection();
242  R0_POLICY<track_index_case>::execute(p1);
243  }
244  }
245 
246  LOG_POLICY<LogMode::Contacts>::execute(logger, p1, p2, c_type, calendar);
247  }
248  }
249  }
250  }
251  }
252 }
253 
254 
255 //--------------------------------------------------------------------------
256 // All explicit instantiations.
257 //--------------------------------------------------------------------------
258 template
260 
261 template
263 
264 template
266 
267 template
269 
270 template
272 
273 template
275 
276 template
278 
279 template
281 
282 template
284 
285 template
287 
288 template
290 
291 template
293 
294 }
void updateMemberPresence()
Calculate which members are present in the cluster on the current day.
Definition: Cluster.cpp:115
Person< BehaviourPolicy, BeliefPolicy > PersonType
Definition: Simulator.h:72
string toString(ClusterType c)
Converts a ClusterType value to corresponding name.
Definition: ClusterType.cpp:54
double getContactRate(const Simulator::PersonType *p) const
Get basic contact rate in this cluster.
Definition: Cluster.h:73
Header for the Infector class.
Header file for the Calendar class.
std::vector< std::pair< Simulator::PersonType *, bool > > m_members
Container with pointers to Cluster members.
Definition: Cluster.h:103
Time Dependent Person DataType.
Definition: NoBehaviour.h:17
bool hasContact(double contact_rate)
Check if two individuals have contact.
Definition: Random.h:57
static void execute(Cluster &cluster, DiseaseProfile disease_profile, util::Random &contact_handler, std::shared_ptr< const Calendar > calendar, spdlog::logger &logger)
Definition: Infector.cpp:109
Header file for the Person class.
bool hasContactAndTransmission(double contact_rate, double transmission_rate)
Definition: Random.h:66
bool hasTransmission(double transmission_rate)
Check if two individuals have transmission.
Definition: Random.h:62
Header for the Random Number Generator class.
std::tuple< bool, size_t > sortMembers()
Sort members w.r.t. health status (order: exposed/infected/recovered, susceptible, immune).
Definition: Cluster.cpp:81
Actual contacts and transmission in cluster (primary template).
Definition: Infector.h:42
STL namespace.
LogMode
Enum specifiying the level of logging required:
Definition: LogMode.h:32
std::size_t m_index_immune
Index of the first immune member in the Cluster.
Definition: Cluster.h:102
Header for the LogMode class.
Represents a location for social contacts, an group of people.
Definition: Cluster.h:46
ClusterType
Enumerates the cluster types.
Definition: ClusterType.h:28
Header for the core Cluster class.
ClusterType m_cluster_type
The type of the Cluster (for logging purposes).
Definition: Cluster.h:101
The random number generator.
Definition: Random.h:39
double getTransmissionRate()
Return transmission rate.