Modelling Disease Outbreak

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 <stdio.h>

#include <stdlib.h>

#include <string.h>

#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 <prob) {

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 <numInfected; 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 <contactRate; 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 <numIslands; 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 <numRoutes; 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 <numIslands; j++) {

infect_island(islands[j], &d, totalInfected);

}

// start the simulation

for (i = 1; i <= maxDays; i++)

{

// move persons between islands

for (k = 0; k <numRoutes; k++) {

move_persons(routes[k]);

}

// advance each Island’s state

for (j = 0; j <numIslands; 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 <numIslands; j++)

{

printf(“Island %d:\n”, j + 1);

display_island_status(islands[j]);

}

}

// free memory

for (j = 0; j <numIslands; j++) {

remove_island(islands[j]);

}

return 0;

}

 main.c 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#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 <prob) {

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 <numInfected; 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 <contactRate) {

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 <numIslands; 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 <numRoutes; 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 <numIslands; j++) {

infect_island(islands[j], &d, totalInfected);

}

// start the simulation

for (i = 1; i <= maxDays; i++)

{

// move persons between islands

for (k = 0; k <numRoutes; k++) {

move_persons(routes[k]);

}

// advance each Island’s state

for (j = 0; j <numIslands; 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 <numIslands; j++)

{

printf(“Island %d:\n”, j + 1);

display_island_status(islands[j]);

}

}

// free memory

for (j = 0; j <numIslands; j++) {

remove_island(islands[j]);

}

return 0;

}