Modelling Disease Outbreak
Outbreak Model
Instructions
For this program you will be implementing an outbreak model in C or C++. Specifically, you will be creating an agentbased model of a flu outbreak in an island nation. You will need to come up with a way to represent each individual, oneach island, and their respective health status: Healthy, Infected, Infectious, and Recovered. Your program should beable to read in multiple user defined parameters from the terminal and/or from a file, and output the outbreak’s
progress over time in a consistent, understandable format.
Disease Modelling Basics
Some of the key parts of modeling many diseases are how to model the transmission of a disease from person toperson, and how to represent the disease characteristics. To start, representing a transmission is based on two factors,contacts and a transmission probability. In this model, each individual will have a set number of contacts they can makewith other individuals every day. When two individuals make a contact, one of two things can happen based on theirhealth status:
1. If one individual is Infectious and the other is Healthy, then both individuals expend a contact and there is apossible transmission of disease from the Infectious individual to the Healthy one.
2. All other cases result in both individuals expending a contact and no transmission occurring.
An additional part of the model is how to represent the disease itself. First, we need to represent the infectious period,or how many days someone remains Infectious before becoming Recovered. Next, we need to represent the infectedperiod, or how many days after someone is Infected they become Infectious. We also assume that once a person has
recovered from the disease they are permanently immune and can never be reinfected. Additionally, a number ofrandomly selected individuals must be initially Infectious at the outset of the model for the disease to begin spreading.
Further, the population itself needs to be modelled in such a way that each individual is represented, rather thanrepresenting the population as a total count. We assume that because the outbreak will not last sufficiently long, thehuman population total will not change during the model. Since this is an island nation, we assume that people can onlymake contacts with other individuals on the same island each day. We also assume that every day a certain number ofpeople travel from island to island via ferry or airplane. For the purposes of this model we will assume travel time isrelatively small and thus people move instantly from one island to another, though an individual may only move onceper day.
As an example, we could set the model parameters to:
·The infected period is 3 days
·The infectious period is 5 days
·The transmission probability is a 10% chance of a successful transmission during a contact
·The maximum number of contacts each person can make every day is 5
·10 randomly selected people are infectious at the beginning of the model
Solution
This design document describes both main and bonus parts. The bonus part is done as a separate program, but it is actually the extension of the main program for the case where disease is transmitted by mosquitoes.
Data Structures:
The Health Status of persons and mosquitoes is represented by HealthStatusenumwith named constants for each possible state. It is also possible to create two separate enums for Persons and Mosquotoes, but for sake of clarity and consistency I put them into a single data structure with M_ prefix for mosquito states.
The Disease is a simple struct with 3 fields: transmissionProb, infectedPeriod, and infectiousPeriod. Those 3 numbers characterize the disease and it makes sense to keep them together.
The person is represented by a type Person which is a struct with fields describing individual person’s status, days of being infected and infectious and a pointer to the disease object. It makes sense to store a pointer to the disease because there will be only a single instance of Disease for all Persons in the whole program which wouldn’t change.
Similarly to a Person, a Mosquito is a struct with the individual mosquito’s status, days of being infectious and a pointer to the disease object.
The Island is another struct with dynamic arrays of pointers to Person and Mosquito
objects and the number of elements in the respective arrays.
Finally, Route is a structure describing the transfer of the Person between two Islands. It contains the pointers to the island from which Persons move (src), to which Persons move (dst) and the number of Persons to move (numPersons).
All instances of Person, Mosquito,and Island are allocated dynamically and are freed in the end of program. It provides a good flexibility of code and many possibilities of future extensions.
All model configuration data is entered by the user. First, the user enters the number of Islands and is asked to enter the number of Persons and Mosquitios for each Island. Similarly the user is asked to enter the Routes between Islands. The maximum number of Islands and Routes is hard-coded and can be easily modified if needed.
After that the user enters values for Total Infected, Contact Rate, Transmission Probability, Infected Period, Infectious Period, and Max Days (the number of days to simulate).
Having all user input entered, the infection is spread on each Island randomly choosing
totalInfected Persons (for main program) or totalInfected Mosquitos (bonus part).
Next, the simulation loop starts.
On the first step Persons are moved between Islands using move_persons function call.
It uses realloc and memcpy to move the last numPersons from src Island to the end ofdst Island.
The function also update Islands’ population. The Persons in this step are not picked randomly,
but since all other actions are random, this design feature does not cause any issues. On the other
hand, it allows to efficiently move data between two arrays of pointers.
On the second step the state of each Island is advanced by 1 day. This step consists of 2 substeps, which are implemented in advance_island_state function. On the first substep each Person and Mosquito is updated itself (changing state INFECTED -> INFECTIOUS -> RECOVERED for Person and M_INFECTIOUS -> M_HEALTY for Mosquito). The second substep implements contact between two persons (in main) or between a person and a mosquito (in bonus). In both cases the person to contact with is selected randomly.
Finally, on the third step the statistics for each Island is displayed with detailed counts of each heath status.
bonus.c
#include
#include
#include
#define MAX_ISLANDS 10
#define MAX_ROUTES 100
/* type dectarations */
typedefenum __healthStatus {HEALTHY, INFECTED, INFECTIOUS, RECOVERED} HealthStatus;
typedefenum __mosquitoStatus {M_HEALTHY, M_INFECTIOUS} MosquitoStatus;
typedefstruct __disease {
doubletransmissionProb;
intinfectedPeriod;
intinfectiousPeriod;
} Disease;
typedefstruct __person {
HealthStatus status;
Disease *disease;
intdaysInfected;
intdaysInfectious;
} Person;
typedefstruct __mosquito {
MosquitoStatus status;
Disease *disease;
intdaysInfectious;
} Mosquito;
typedefstruct __island {
int population;
intnumMosquitos;
Person **persons;
Mosquito **mosquitos;
} Island;
typedefstruct __route {
Island *src;
Island *dst;
intnumPersons;
} Route;
Person* create_person() {
Person *person = malloc(sizeof(Person));
person->status = HEALTHY;
person->disease = NULL;
person->daysInfected = 0;
person->daysInfectious = 0;
return person;
}
voidinfect_person(Person *p, Disease *d) {
// only healthy person can be infected
if (p->status == HEALTHY) {
p->status = INFECTED;
p->disease = d;
}
}
voidadvance_person_state(Person *p) {
if (p->status == INFECTED) {
p->daysInfected++;
if (p->daysInfected == p->disease->infectedPeriod) {
p->status = INFECTIOUS;
}
}
else if (p->status == INFECTIOUS) {
p->daysInfectious++;
if (p->daysInfectious == p->disease->infectiousPeriod) {
p->status = RECOVERED;
}
}
}
Mosquito* create_mosquito() {
Mosquito *mosquito = malloc(sizeof(Mosquito));
mosquito->status = M_HEALTHY;
mosquito->disease = NULL;
mosquito->daysInfectious = 0;
return mosquito;
}
voidinfect_mosquito(Mosquito *m, Disease *d) {
if (m->status == M_HEALTHY) {
m->status = M_INFECTIOUS;
m->disease = d;
}
}
voidadvance_mosquito_state(Mosquito *m) {
if (m->status == M_INFECTIOUS) {
m->daysInfectious++;
if (m->daysInfectious == m->disease->infectiousPeriod) {
m->status = M_HEALTHY;
m->daysInfectious = 0; // reset count
}
}
}
voidcontact_person(Mosquito *m, Person *p) {
if (m->status == M_INFECTIOUS) { // can infect only when infectious
doubleprob = m->disease->transmissionProb;
if (rand() / (double)RAND_MAX
infect_person(p, m->disease);
}
}
if (p->status == INFECTIOUS) { // 100% chance
infect_mosquito(m, p->disease);
}
}
Island *create_island(int population, intnumMosquitos) {
Island *island = malloc(sizeof(Island *));
island->population = population;
island->numMosquitos = numMosquitos;
// allocate space for the population
island->persons = malloc(population * sizeof(Person *));
// allocate space for mosquitos
island->mosquitos = malloc(numMosquitos * sizeof(Mosquito *));
int i, j;
// create persons
for (i = 0; i < island->population; i++) {
island->persons[i] = create_person();
}
// create mosquitos
for (j = 0; j < island->numMosquitos; j++) {
island->mosquitos[j] = create_mosquito();
}
return island;
}
voidremove_island(Island *island) {
int i, j;
// free each person
for (i = 0; i < island->population; i++) {
free(island->persons[i]);
}
// free each mosquito
for (j = 0; j < island->numMosquitos; j++) {
free(island->mosquitos[j]);
}
free(island->persons);
free(island->mosquitos);
free(island);
}
voidinfect_island(Island *island, Disease *d, intnumInfected) {
int i, j;
// pick numInfected random Mosquitos to infect with disease
for (i = 0; i
j = rand() % island->numMosquitos;
infect_mosquito(island->mosquitos[j], d);
}
}
voidadvance_island_state(Island *island, intcontactRate) {
int i, j;
// advance each person on the island
for (i = 0; i < island->population; i++) {
advance_person_state(island->persons[i]);
}
// advance each mosquito on the island
for (i = 0; i < island->numMosquitos; i++) {
advance_mosquito_state(island->mosquitos[i]);
}
// each person contacts with contactRate persons
for (i = 0; i < island->numMosquitos; i++) {
int j = 0;
for (j = 0; j
int k = rand() % island->population;
contact_person(island->mosquitos[i], island->persons[k]);
}
}
}
voiddisplay_island_status(Island *island) {
int i, j;
int counts[4] = {0, 0, 0, 0}, m_counts[2] = {0, 0};
// counts for each health status
for (i = 0; i < island->population; i++) {
counts[island->persons[i]->status]++;
}
// counts for each mosquito status
for (j = 0; j < island->numMosquitos; j++) {
m_counts[island->mosquitos[j]->status]++;
}
printf(“People:\n”);
printf(“Population: %d\n”, island->population);
printf(“Healthy : %d\n”, counts[0]);
printf(“Infected : %d\n”, counts[1]);
printf(“Infectious: %d\n”, counts[2]);
printf(“Recovered : %d\n”, counts[3]);
printf(“Mosquitos:\n”);
printf(“Healthy : %d\n”, m_counts[0]);
printf(“Infectious: %d\n”, m_counts[1]);
printf(“\n”);
}
voidmove_persons(Route route) {
// alocate space for incoming Persons
route.dst->population = route.dst->population + route.numPersons;
route.dst->persons = realloc(route.dst->persons, route.dst->population * sizeof(Person *));
// copy last route.numPersons Persons from route.src->persons to route.dst->persons
memcpy(route.dst->persons + route.dst->population – route.numPersons,
route.src->persons + route.src->population – route.numPersons,
route.numPersons * sizeof(Person *));
// remove Persons moved
route.src->population = route.src->population – route.numPersons;
route.src->persons = realloc(route.src->persons, route.src->population * sizeof(Person *));
}
int main(intargc, char **argv)
{
int i, j, k;
intnumIslands = 0, numRoutes = 0;
inttotalInfected, contactRate, maxDays;
intinfectedPeriod, infectiousPeriod, transmissionProb;
Island *islands[MAX_ISLANDS];
Route routes[MAX_ROUTES];
printf(” —- Disease Outbreak Model —-\n”);
printf(“\n”);
printf(“Enter the number of islands: “);
scanf(“%d”, &numIslands);
// create islands
for (j = 0; j
int population, numMosquitos;
printf(“Enter Island #%d’s population: “, j + 1);
scanf(“%d”, &population);
printf(“Enter the number of mosquitos on Island #%d: “, j + 1);
scanf(“%d”, &numMosquitos);
islands[j] = create_island(population, numMosquitos);
}
printf(“\n”);
printf(“Enter the number of routes between islands: “);
scanf(“%d”, &numRoutes);
if (numRoutes> 0) {
printf(“Enter three integers for source island, destination island,\n”);
printf(” and the number of persons travelling (e.g. 1 3 7)\n”);
}
// create routes
for (k = 0; k
intsrc, dst, numPersons;
printf(“Route #%d: “, k + 1);
scanf(“%d %d %d”, &src, &dst, &numPersons);
routes[k] = (Route){islands[src-1], islands[dst-1], numPersons};
}
printf(“\n”);
printf(“Enter the number of infected mosquitos per island: “);
scanf(“%d”, &totalInfected);
printf(“Enter the maximum number of contacts each mosquito can make: “);
scanf(“%d”, &contactRate);
printf(“Enter the chance of a successful disease transmission during a contact in %%: “);
scanf(“%d”, &transmissionProb);
printf(“Enter the infected period in days: “);
scanf(“%d”, &infectedPeriod);
printf(“Enter the infectious period in days: “);
scanf(“%d”, &infectiousPeriod);
printf(“Enter the number of days to simulate the outbreak: “);
scanf(“%d”, &maxDays);
// create Disease instance
Disease d = (Disease){transmissionProb / 100.0, infectedPeriod, infectiousPeriod};
// spread the Disease (initially infected)
for (j = 0; j
infect_island(islands[j], &d, totalInfected);
}
// start the simulation
for (i = 1; i <= maxDays; i++)
{
// move persons between islands
for (k = 0; k
move_persons(routes[k]);
}
// advance each Island’s state
for (j = 0; j
advance_island_state(islands[j], contactRate);
}
// print daily stats for each island
printf(“=====================================\n”);
printf(” Day %d\n”, i);
printf(“=====================================\n”);
for (j = 0; j
{
printf(“Island %d:\n”, j + 1);
display_island_status(islands[j]);
}
}
// free memory
for (j = 0; j
remove_island(islands[j]);
}
return 0;
}
main.c
#include
#include
#include
#define MAX_ISLANDS 10
#define MAX_ROUTES 100
/* type dectarations */
typedefenum __healthStatus {HEALTHY, INFECTED, INFECTIOUS, RECOVERED} HealthStatus;
typedefstruct __disease {
doubletransmissionProb;
intinfectedPeriod;
intinfectiousPeriod;
} Disease;
typedefstruct __person {
HealthStatus status;
Disease *disease;
intdaysInfected;
intdaysInfectious;
} Person;
typedefstruct __island {
int population;
Person **persons;
} Island;
typedefstruct __route {
Island *src;
Island *dst;
intnumPersons;
} Route;
Person* create_person() {
Person *person = malloc(sizeof(Person));
person->status = HEALTHY;
person->disease = NULL;
person->daysInfected = 0;
person->daysInfectious = 0;
return person;
}
voidinfect_person(Person *p, Disease *d) {
// only healthy person can be infected
if (p->status == HEALTHY) {
p->status = INFECTED;
p->disease = d;
}
}
voidadvance_person_state(Person *p) {
if (p->status == INFECTED) {
p->daysInfected++;
if (p->daysInfected == p->disease->infectedPeriod) {
p->status = INFECTIOUS;
}
}
else if (p->status == INFECTIOUS) {
p->daysInfectious++;
if (p->daysInfectious == p->disease->infectiousPeriod) {
p->status = RECOVERED;
}
}
}
voidcontact_persons(Person *this, Person *other) {
if (this->status == INFECTIOUS) { // can infect only when infectious
doubleprob = this->disease->transmissionProb;
if (rand() / (double)RAND_MAX
infect_person(other, this->disease);
}
}
}
Island *create_island(int population) {
Island *island = malloc(sizeof(Island *));
island->population = population;
// allocate space for the population
island->persons = malloc(population * sizeof(Person *));
int i;
// create persons
for (i = 0; i < island->population; i++) {
island->persons[i] = create_person();
}
return island;
}
voidremove_island(Island *island) {
int i;
// free each person
for (i = 0; i < island->population; i++) {
free(island->persons[i]);
}
free(island->persons);
free(island);
}
voidinfect_island(Island *island, Disease *d, intnumInfected) {
int i, j;
// pick numInfected random Persons to infect with disease
for (i = 0; i
j = rand() % island->population;
infect_person(island->persons[j], d);
}
}
voidadvance_island_state(Island *island, intcontactRate) {
int i;
// advance each person on the island
for (i = 0; i < island->population; i++) {
advance_person_state(island->persons[i]);
}
// each person contacts with contactRate persons
for (i = 0; i < island->population; i++) {
int j = 0;
while (j
int k = rand() % island->population;
if (k != i) {// skip itself
contact_persons(island->persons[i], island->persons[k]);
j++;
}
}
}
}
voiddisplay_island_status(Island *island) {
int i;
int counts[4] = {0, 0, 0, 0};
// counts for each health status
for (i = 0; i < island->population; i++) {
counts[island->persons[i]->status]++;
}
printf(“Population: %d\n”, island->population);
printf(“Healthy : %d\n”, counts[0]);
printf(“Infected : %d\n”, counts[1]);
printf(“Infectious: %d\n”, counts[2]);
printf(“Recovered : %d\n”, counts[3]);
printf(“\n”);
}
voidmove_persons(Route route) {
// alocate space for incoming Persons
route.dst->population = route.dst->population + route.numPersons;
route.dst->persons = realloc(route.dst->persons, route.dst->population * sizeof(Person *));
// copy last route.numPersons Persons from route.src->persons to route.dst->persons
memcpy(route.dst->persons + route.dst->population – route.numPersons,
route.src->persons + route.src->population – route.numPersons,
route.numPersons * sizeof(Person *));
// remove Persons moved
route.src->population = route.src->population – route.numPersons;
route.src->persons = realloc(route.src->persons, route.src->population * sizeof(Person *));
}
int main(intargc, char **argv)
{
int i, j, k;
intnumIslands = 0, numRoutes = 0;
inttotalInfected, contactRate, maxDays;
intinfectedPeriod, infectiousPeriod, transmissionProb;
Island *islands[MAX_ISLANDS];
Route routes[MAX_ROUTES];
printf(” —- Disease Outbreak Model —-\n”);
printf(“\n”);
printf(“Enter the number of islands: “);
scanf(“%d”, &numIslands);
// create islands
for (j = 0; j
int population;
printf(“Enter Island #%d’s population: “, j + 1);
scanf(“%d”, &population);
islands[j] = create_island(population);
}
printf(“\n”);
printf(“Enter the number of routes between islands: “);
scanf(“%d”, &numRoutes);
if (numRoutes> 0) {
printf(“Enter three integers for source island, destination island,\n”);
printf(” and the number of persons travelling (e.g. 1 3 7)\n”);
}
// create routes
for (k = 0; k
intsrc, dst, numPersons;
printf(“Route #%d: “, k + 1);
scanf(“%d %d %d”, &src, &dst, &numPersons);
routes[k] = (Route){islands[src-1], islands[dst-1], numPersons};
}
printf(“\n”);
printf(“Enter the number of infected persons per island: “);
scanf(“%d”, &totalInfected);
printf(“Enter the maximum number of contacts each person can make: “);
scanf(“%d”, &contactRate);
printf(“Enter the chance of a successful disease transmission during a contact in %%: “);
scanf(“%d”, &transmissionProb);
printf(“Enter the infected period in days: “);
scanf(“%d”, &infectedPeriod);
printf(“Enter the infectious period in days: “);
scanf(“%d”, &infectiousPeriod);
printf(“Enter the number of days to simulate the outbreak: “);
scanf(“%d”, &maxDays);
// create Disease instance
Disease d = (Disease){transmissionProb / 100.0, infectedPeriod, infectiousPeriod};
// spread the Disease (initially infected)
for (j = 0; j
infect_island(islands[j], &d, totalInfected);
}
// start the simulation
for (i = 1; i <= maxDays; i++)
{
// move persons between islands
for (k = 0; k
move_persons(routes[k]);
}
// advance each Island’s state
for (j = 0; j
advance_island_state(islands[j], contactRate);
}
// print daily stats for each island
printf(“=====================================\n”);
printf(” Day %d\n”, i);
printf(“=====================================\n”);
for (j = 0; j
{
printf(“Island %d:\n”, j + 1);
display_island_status(islands[j]);
}
}
// free memory
for (j = 0; j
remove_island(islands[j]);
}
return 0;
}