Core Functions

move()

For of the each process’s people, this function moves them around randomly.

For everyone handled by this process,

    for(my_current_person_id = 0; my_current_person_id 
        <= our->our_number_of_people - 1; my_current_person_id++)

If the person is not dead, then

        if(our_states[my_current_person_id] != DEAD)

First, The thread 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).

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

The thread then 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 up
            // or down or does not move in the y dimension
            my_y_move_direction = (random() % 3) - 1;

Next, we need to make sure that the person will remain in the bounds of the environment after moving. 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( (our_x_locations[my_current_person_id] 
                    + my_x_move_direction >= 0) &&
                (our_x_locations[my_current_person_id] 
                    + my_x_move_direction < environment_width) &&
                (our_y_locations[my_current_person_id] 
                    + my_y_move_direction >= 0) &&
                (our_y_locations[my_current_person_id] 
                    + my_y_move_direction < environment_height) )

Finally, The thread moves the person

image

The thread is able to achieve this by simply changing values in the our_x_locations and our_y_locations arrays.

                // The thread moves the person
                our_x_locations[my_current_person_id] += my_x_move_direction;
                our_y_locations[my_current_person_id] += my_y_move_direction;

susceptible()

For of the each process’s people, this function handles those that are ssusceptible by deciding whether or not they should be marked infected.

For everyone handled by this process,

    for(my_current_person_id = 0; my_current_person_id 
          <= our->our_number_of_people - 1; my_current_person_id++)

If the person is susceptible,

       if(our_states[my_current_person_id] == SUSCEPTIBLE)

For each of the infected people (received earlier from all processes) or until the number of infected people nearby is 1, the thread does the following

            for(my_person2 = 0; my_person2 <= total_num_infected - 1
                && my_num_infected_nearby < 1; my_person2++)

If this person is within the infection radius,

                if((our_x_locations[my_current_person_id] 
                    > their_infected_x_locations[my_person2] - infection_radius) &&
                   (our_x_locations[my_current_person_id] 
                    < their_infected_x_locations[my_person2] + infection_radius) &&
                   (our_y_locations[my_current_person_id]
                    > their_infected_y_locations[my_person2] - infection_radius) &&
                   (our_y_locations[my_current_person_id]
                    < their_infected_y_locations[my_person2] + infection_radius))

then, the function increments the number of infected people nearby

                    my_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 thread simply increments the my_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 our_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.

            // The thread updates stats counter
            #ifdef SHOW_RESULTS
            if(my_num_infected_nearby >= 1)
                stats->our_num_infection_attempts++;
            #endif

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(my_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 thread changes this person state to infected

                // The thread changes person1’s state to infected
                our_states[my_current_person_id] = INFECTED;

The thread updates the counters

                // The thread updates the counters
                our->our_num_infected++;
                our->our_num_susceptible--;
image

Note in the code that if the infection succeeds and we have SHOW_RESULTS enabled, we increment the our_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.

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

infected()

For of the each process’s people, this function to handles those that are infected by deciding whether they should be marked immune or dead.

For everyone handled by this process,

    for(my_current_person_id = 0; my_current_person_id 
        <= our->our_number_of_people - 1; my_current_person_id++)

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

        if(our_states[my_current_person_id] == INFECTED
            && our_num_days_infected[my_current_person_id] == duration_of_disease)

Note in the code that if we have SHOW_RESULTS enabled, we increment the our_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.

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

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

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

then, the thread changes the person’s state to dead

                our_states[my_current_person_id] = DEAD;

and then the thread updates the counters

                // The thread updates the counters
                our->our_num_dead++;
                our->our_num_infected--;
image

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

if a random number less than 100 is less than the deadliness factor, the thread changes the person’s state to immune

                // The thread changes the person’s state to immune
                our_states[my_current_person_id] = IMMUNE;

The thread updates the counters

                // The thread updates the counters
                our->our_num_immune++;
                our->our_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 our_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->our_num_deaths++;
                #endif

update_days_infected()

For of the each process’s people, this function to handles those that are infected by increasing the number of days infected.

For everyone handled by this process,

    for(my_current_person_id = 0; my_current_person_id 
        <= our->our_number_of_people - 1; my_current_person_id++)

If the person is infected,

        if(our_states[my_current_person_id] == INFECTED)

then, the function increment the number of days the person has been infected

            our_num_days_infected[my_current_person_id]++;
image