Core Functions

move

If the person is not dead, then

        if(states[current_person_id] != DEAD)

First, the function randomly picks whether the person moves left or right or does not move in the x dimension.

The code uses (random() % 3) - 1; to achieve this. (random() % 3) returns either 0, 1, or 2. Subtracting 1 from this produces -1, 0, or 1. This means the person can move to the right, stay in place (0), or move to the left (-1).

then the function randomly picks whether the person moves up or down or does not move in the y dimension. This is similar to movement in x dimension.

            // The thread randomly picks whether the person moves left 
            // or right or does not move in the x dimension
            x_move_direction = (random() % 3) - 1;

            // The thread randomly picks whether the person moves up
            // or down or does not move in the y dimension
            y_move_direction = (random() % 3) - 1;

Next, If the person will remain in the bounds of the environment after moving, then

We check this by making sure the person’s x location is greater than or equal to 0 and less than the width of the environment and that the person’s y location is greater than or equal to 0 and less than the height of the environment. In the code, it looks like this:

            if((x_locations[current_person_id] + x_move_direction >= 0)
                && (x_locations[current_person_id] 
                    + x_move_direction < environment_width)
                && (y_locations[current_person_id] 
                    + y_move_direction >= 0)
                && (y_locations[current_person_id] 
                    + y_move_direction < environment_height))

Finally, The function moves the person

image
                x_locations[current_person_id] 
                += x_move_direction;
                y_locations[current_person_id] 
                += y_move_direction;

The function is able to achieve this by simply changing values in the x_locations and y_locations arrays.

susceptible

For each people, the function to do the following

    for(current_person_id = 0; current_person_id 
        <= global->number_of_people - 1; current_person_id++)

If the person is susceptible,

        if(states[current_person_id] == SUSCEPTIBLE)

For each of the infected people or until the number of infected people nearby is 1, the function does the following

            for(my_person = 0; my_person <= global->num_infected - 1
                && num_infected_nearby < 1; my_person++)

If the person is within the infection radius, then

                if((x_locations[current_person_id] 
                    > infected_x_locations[my_person] - infection_radius)
                    && (x_locations[current_person_id] 
                        < infected_x_locations[my_person] + infection_radius)
                    && (y_locations[current_person_id]
                        > infected_y_locations[my_person] - infection_radius)
                    && (y_locations[current_person_id]
                        < infected_y_locations[my_person] + infection_radius))

Finally, the function increments the number of infected people nearby

                    num_infected_nearby++;
image

This is where a large chunk of the algorithm’s computation occurs. Each susceptible person must be computed with each infected person to determine how many infected people are nearby each person. Two nested loops means many computations. In this step, the computation is fairly simple, however. The function simply increments the num_infected_nearby variable.

Note in the code that if the number of infected nearby is greater than or equal to 1 and we have SHOW_RESULTS enabled, we increment the num_infection_attempts variable. This helps us keep track of the number of attempted infections, which will help us calculate the actual contagiousness of the disease at the end of the simulation.

If there is at least one infected person nearby, and a random number less than 100 is less than or equal to the contagiousness factor, then

            if(num_infected_nearby >= 1 && (random() % 100) 
                <= contagiousness_factor)

Recall that the contagiousness factor is the likelihood that the disease will be spread. We measure this as a number less than 100. For example, if there is a 30% chance of contagiousness, we use 30 as the value of the contagiousness factor. To figure out if the disease is spread for any given interaction of people, we find a random number less than 100 and check if it is less than or equal to the contagiousness factor, because this will be equivalent to calculating the odds of actually spreading the disease (e.g. there is a 30% chance of spreading the disease and also a 30% chance that a random number less than 100 will be less than or equal to 30).

The function changes the state to infected

                states[current_person_id] = INFECTED;

The function updates the counters

                // The thread updates the counters
                global->num_infected++;
                global->num_susceptible--;
image

These steps are as simple as updating the states array by states[my_current_person_id] = INFECTED, incrementing the num_infected variable, and decrementing the num_susceptible variable.

Note in the code that if the infection succeeds and we have SHOW_RESULTS enabled, we increment the num_infections variable. This helps us keep track of the actual number of infections, which will help us calculate the actual contagiousness of the disease at the end of the simulation.

infected

For each people, the function to do the following

    for(current_person_id = 0; current_person_id 
        <= global->number_of_people - 1; current_person_id++)

If the person is infected and has been for the full duration of the disease, then

        if(states[current_person_id] == INFECTED
            && num_days_infected[current_person_id] 
            == duration_of_disease)

Note in the code that if we have SHOW_RESULTS enabled, we increment the num_recovery_attempts variable. This helps us keep track of the number of attempted recoveries, which will help us calculate the actual deadliness of the disease at the end of the simulation.

            stats->num_recovery_attempts++;

If a random number less than 100 is less than the deadliness factor, then

            if((random() % 100) < deadliness_factor)

The function changes the person’s state to dead

                states[current_person_id] = DEAD;

The function updates the counters

                // The thread updates the counters
                global->num_dead++;
                global->num_infected--;
image

This step is effectively the same as function susceptible, considering deadliness instead of contagiousness. The difference here is the following step:

Otherwise,

The function changes the person’s state to immune

                states[current_person_id] = IMMUNE;

The function updates the counters

                // The thread updates the counters
                global->num_immune++;
                global->num_infected--;
image

If deadliness fails, then immunity succeeds.

Note in the code that if the person dies and we have SHOW_RESULTS enabled, we increment the num_deaths variable. This helps us keep track of the actual number of deaths, which will help us calculate the actual deadliness of the disease at the end of the simulation.

                // The thread updates stats counter
                #ifdef SHOW_RESULTS
                    stats->num_deaths++;
                #endif

update_days_infected

For each people, the function to do the following

    for(current_person_id = 0; current_person_id 
        <= global->number_of_people - 1; current_person_id++)

If the person is infected, then

        if(states[current_person_id] == INFECTED)

Increment the number of days the person has been infected

            num_days_infected[current_person_id]++;
image

This is achieved by incrementing each member of the num_days_infected array, which can be done as follows: num_days_infected[my_current_person_id]++