Ejemplo n.º 1
0
class Simulation:
    # TODO: if lockdown or otherwise stopped: destination -1 means no motion
    def __init__(self, *args, **kwargs):
        # load default config data
        self.Config = Configuration()
        self.frame = 0

        # initialize default population
        self.population_init()

        self.pop_tracker = Population_trackers()

        # initalise destinations vector
        self.destinations = initialize_destination_matrix(self.Config.pop_size, 1)

        self.fig, self.spec, self.ax1, self.ax2 = build_fig(self.Config)

        # set_style(self.Config)

    def population_init(self):
        """(re-)initializes population"""
        self.population = initialize_population(
            self.Config,
            self.Config.mean_age,
            self.Config.max_age,
            self.Config.xbounds,
            self.Config.ybounds,
        )

    def tstep(self):
        """
        takes a time step in the simulation
        """

        # check destinations if active
        # define motion vectors if destinations active and not everybody is at destination
        active_dests = len(
            self.population[self.population[:, 11] != 0]
        )  # look op this only once

        if active_dests > 0 and len(self.population[self.population[:, 12] == 0]) > 0:
            self.population = set_destination(self.population, self.destinations)
            self.population = check_at_destination(
                self.population,
                self.destinations,
                wander_factor=self.Config.wander_factor_dest,
                speed=self.Config.speed,
            )

        if active_dests > 0 and len(self.population[self.population[:, 12] == 1]) > 0:
            # keep them at destination
            self.population = keep_at_destination(
                self.population, self.destinations, self.Config.wander_factor
            )

        # out of bounds
        # define bounds arrays, excluding those who are marked as having a custom destination
        if len(self.population[:, 11] == 0) > 0:
            _xbounds = np.array(
                [[self.Config.xbounds[0] + 0.02, self.Config.xbounds[1] - 0.02]]
                * len(self.population[self.population[:, 11] == 0])
            )
            _ybounds = np.array(
                [[self.Config.ybounds[0] + 0.02, self.Config.ybounds[1] - 0.02]]
                * len(self.population[self.population[:, 11] == 0])
            )
            self.population[self.population[:, 11] == 0] = out_of_bounds(
                self.population[self.population[:, 11] == 0], _xbounds, _ybounds
            )

        # set randoms
        if self.Config.lockdown:
            if len(self.pop_tracker.infectious) == 0:
                mx = 0
            else:
                mx = np.max(self.pop_tracker.infectious)

            if len(self.population[self.population[:, 6] == 1]) >= len(
                self.population
            ) * self.Config.lockdown_percentage or mx >= (
                len(self.population) * self.Config.lockdown_percentage
            ):
                # reduce speed of all members of society
                self.population[:, 5] = np.clip(
                    self.population[:, 5], a_min=None, a_max=0.001
                )
                # set speeds of complying people to 0
                self.population[:, 5][self.Config.lockdown_vector == 0] = 0
            else:
                # update randoms
                self.population = update_randoms(
                    self.population, self.Config.pop_size, self.Config.speed
                )
        else:
            # update randoms
            self.population = update_randoms(
                self.population, self.Config.pop_size, self.Config.speed
            )

        # for dead ones: set speed and heading to 0
        self.population[:, 3:5][self.population[:, 6] == 3] = 0

        # update positions
        self.population = update_positions(self.population)

        # find new infections
        self.population, self.destinations = infect(
            self.population,
            self.Config,
            self.frame,
            send_to_location=self.Config.self_isolate,
            location_bounds=self.Config.isolation_bounds,
            destinations=self.destinations,
            location_no=1,
            location_odds=self.Config.self_isolate_proportion,
        )

        # recover and die
        self.population = recover_or_die(self.population, self.frame, self.Config)

        # send cured back to population if self isolation active
        # perhaps put in recover or die class
        # send cured back to population
        self.population[:, 11][self.population[:, 6] == 2] = 0

        # update population statistics
        self.pop_tracker.update_counts(self.population)

        # visualise
        if self.Config.visualise:
            draw_tstep(
                self.Config,
                self.population,
                self.pop_tracker,
                self.frame,
                self.fig,
                self.spec,
                self.ax1,
                self.ax2,
            )

        # report stuff to console
        sys.stdout.write("\r")
        sys.stdout.write(
            "%i: healthy: %i, infected: %i, immune: %i, in treatment: %i, \
dead: %i, of total: %i"
            % (
                self.frame,
                self.pop_tracker.susceptible[-1],
                self.pop_tracker.infectious[-1],
                self.pop_tracker.recovered[-1],
                len(self.population[self.population[:, 10] == 1]),
                self.pop_tracker.fatalities[-1],
                self.Config.pop_size,
            )
        )

        # save popdata if required
        if self.Config.save_pop and (self.frame % self.Config.save_pop_freq) == 0:
            save_population(self.population, self.frame, self.Config.save_pop_folder)
        # run callback
        self.callback()

        # update frame
        self.frame += 1

    def callback(self):
        """placeholder function that can be overwritten.

        By ovewriting this method any custom behaviour can be implemented.
        The method is called after every simulation timestep.
        """

        if self.frame == 50:
            print("\ninfecting person")
            self.population[0][6] = 1
            self.population[0][8] = 50
            self.population[0][10] = 1

    def run(self):
        """run simulation"""

        i = 0

        while i < self.Config.simulation_steps:
            try:
                sim.tstep()
            except KeyboardInterrupt:
                print("\nCTRL-C caught, exiting")
                sys.exit(1)

            # check whether to end if no infecious persons remain.
            # check if self.frame is above some threshold to prevent early breaking when simulation
            # starts initially with no infections.
            if self.Config.endif_no_infections and self.frame >= 500:
                if (
                    len(
                        self.population[
                            (self.population[:, 6] == 1) | (self.population[:, 6] == 4)
                        ]
                    )
                    == 0
                ):
                    i = self.Config.simulation_steps

        if self.Config.save_data:
            save_data(self.population, self.pop_tracker)

        # report outcomes
        print("\n-----stopping-----\n")
        print("total timesteps taken: %i" % self.frame)
        print("total dead: %i" % len(self.population[self.population[:, 6] == 3]))
        print("total recovered: %i" % len(self.population[self.population[:, 6] == 2]))
        print("total infected: %i" % len(self.population[self.population[:, 6] == 1]))
        print(
            "total infectious: %i"
            % len(
                self.population[
                    (self.population[:, 6] == 1) | (self.population[:, 6] == 4)
                ]
            )
        )
        print("total unaffected: %i" % len(self.population[self.population[:, 6] == 0]))
Ejemplo n.º 2
0
class Simulation():
    #TODO: if lockdown or otherwise stopped: destination -1 means no motion
    def __init__(self, *args, **kwargs):
        #load default config data
        self.Config = Configuration(*args, **kwargs)
        self.frame = 0

        #initialize default population
        self.population_init()

        self.pop_tracker = Population_trackers(self.Config.simulation_steps)

        #initalise destinations vector
        self.destinations = initialize_destination_matrix(
            self.Config.pop_size, 1)
        self.testing = False
        self.positive = []
        self.last_positive = None
        self.last_number_of_tests = 0

    def reinitialise(self):
        '''reset the simulation'''

        self.frame = 0
        self.population_init()
        self.pop_tracker = Population_trackers(self.Config.simulation_steps)
        self.destinations = initialize_destination_matrix(
            self.Config.pop_size, 1)

    def population_init(self):
        '''(re-)initializes population'''
        self.population = initialize_population(self.Config,
                                                self.Config.xbounds,
                                                self.Config.ybounds)

    def tstep(self):
        '''
        takes a time step in the simulation
        '''

        if self.frame == 0 and self.Config.visualise:
            #initialize figure
            self.fig, self.spec, self.ax1, self.ax2 = build_fig(self.Config)

        #check destinations if active
        #define motion vectors if destinations active and not everybody is at destination
        active_dests = len(self.population[
            self.population[:, 11] != 0])  # look op this only once

        if active_dests > 0 and len(
                self.population[self.population[:, 12] == 0]) > 0:
            self.population = set_destination(self.population,
                                              self.destinations)
            self.population = check_at_destination(
                self.population,
                self.destinations,
                wander_factor=self.Config.wander_factor_dest,
                speed=self.Config.speed)

        if active_dests > 0 and len(
                self.population[self.population[:, 12] == 1]) > 0:
            #keep them at destination
            self.population = keep_at_destination(self.population,
                                                  self.destinations,
                                                  self.Config.wander_factor)

        #out of bounds
        #define bounds arrays, excluding those who are marked as having a custom destination
        if len(self.population[:, 11] == 0) > 0:
            _xbounds = np.array([[
                self.Config.xbounds[0] + 0.02, self.Config.xbounds[1] - 0.02
            ]] * len(self.population[self.population[:, 11] == 0]))
            _ybounds = np.array([[
                self.Config.ybounds[0] + 0.02, self.Config.ybounds[1] - 0.02
            ]] * len(self.population[self.population[:, 11] == 0]))
            self.population[self.population[:, 11] == 0] = out_of_bounds(
                self.population[self.population[:, 11] == 0], _xbounds,
                _ybounds)

        #set randoms
        if self.Config.lockdown:
            if len(self.pop_tracker.infectious) == 0:
                mx = 0
            else:
                mx = np.max(self.pop_tracker.infectious)

            if len(self.population[self.population[:,6] == 1]) >= len(self.population) * self.Config.lockdown_percentage or\
               mx >= (len(self.population) * self.Config.lockdown_percentage):
                #reduce speed of all members of society
                self.population[:, 5] = np.clip(self.population[:, 5],
                                                a_min=None,
                                                a_max=0.001)
                #set speeds of complying people to 0
                self.population[:, 5][self.Config.lockdown_vector == 0] = 0
            else:
                #update randoms
                self.population = update_randoms(self.population,
                                                 self.Config.pop_size,
                                                 self.Config.speed)
        else:
            #update randoms
            self.population = update_randoms(self.population,
                                             self.Config.pop_size,
                                             self.Config.speed)

        #for dead ones: set speed and heading to 0
        self.population[:, 3:5][self.population[:, 6] == 3] = 0

        #update positions
        self.population = update_positions(self.population)

        #find new infections
        self.population = infect(self.population, self.Config, self.frame)

        #test
        if len(
                self.population[self.population[:, 6] == 1]
        ) / self.Config.pop_size >= self.Config.test_proportion_to_start:
            self.testing = True
            self.population[:, 17] = np.random.uniform(size=(
                self.Config.pop_size, )) < self.Config.proportion_wearing_masks

        if self.testing:
            self.last_positive, self.last_number_of_tests = test_population(
                self.population,
                self.Config,
                self.frame,
                self.positive,
                send_to_location=self.Config.self_isolate,
                location_bounds=self.Config.isolation_bounds,
                destinations=self.destinations,
                location_no=1,
                location_odds=self.Config.self_isolate_proportion)
            if self.last_positive is not None:
                self.positive += [self.last_positive]

        #recover and die
        self.population = recover_or_die(self.population, self.frame,
                                         self.Config)

        #send cured back to population if self isolation active
        #perhaps put in recover or die class
        #send cured back to population
        self.population[:, 11][self.population[:, 6] == 2] = 0

        #update population statistics
        self.pop_tracker.update_counts(self.population, self.frame,
                                       self.last_positive,
                                       self.last_number_of_tests)

        #visualise
        if self.Config.visualise:
            draw_tstep(self.Config, self.population, self.pop_tracker,
                       self.frame, self.fig, self.spec, self.ax1, self.ax2)

        if not self.Config.quiet:
            #report stuff to console
            sys.stdout.write('\r')
            sys.stdout.write(
                '%i: healthy: %i, infected: %i, immune: %i, in treatment: %i, \
    dead: %i, of total: %i' %
                (self.frame, self.pop_tracker.susceptible[-1],
                 self.pop_tracker.infectious[-1],
                 self.pop_tracker.recovered[-1],
                 len(self.population[self.population[:, 10] == 1]),
                 self.pop_tracker.fatalities[-1], self.Config.pop_size))

        #save popdata if required
        if self.Config.save_pop and (self.frame %
                                     self.Config.save_pop_freq) == 0:
            save_population(self.population, self.frame,
                            self.Config.save_pop_folder)
        #run callback
        self.callback()

        #update frame
        self.frame += 1

    def callback(self):
        '''placeholder function that can be overwritten.

        By ovewriting this method any custom behaviour can be implemented.
        The method is called after every simulation timestep.
        '''

        if self.frame == 5:
            if not self.Config.quiet:
                print('\ninfecting patient zero')
            self.population[0:5, 6] = 1
            self.population[0:5, 8] = 5
            self.population[0:5, 10] = 1
            self.population[0:5, 18] = 2

    def run(self):
        '''run simulation'''

        i = 0

        while i < self.Config.simulation_steps:
            try:
                self.tstep()
            except KeyboardInterrupt:
                print('\nCTRL-C caught, exiting')
                sys.exit(1)

            #check whether to end if no infecious persons remain.
            #check if self.frame is above some threshold to prevent early breaking when simulation
            #starts initially with no infections.
            if self.Config.endif_no_infections and self.frame >= 500:
                if len(self.population[(self.population[:, 6] == 1) |
                                       (self.population[:, 6] == 4)]) == 0:
                    i = self.Config.simulation_steps

        if self.Config.save_data:
            save_data(self.population, self.pop_tracker)

        total_timesteps = self.frame
        total_dead = len(self.population[self.population[:, 6] == 3])
        total_recovered = len(self.population[self.population[:, 6] == 2])
        total_infected = len(self.population[self.population[:, 6] == 1])
        total_infectious = len(self.population[(self.population[:, 6] == 1) |
                                               (self.population[:, 6] == 4)])
        total_unaffected = len(self.population[self.population[:, 6] == 0])

        if (self.Config.print_summary):
            #report outcomes
            print('\n-----stopping-----\n')
            print('total timesteps taken: %i' % total_timesteps)
            print('total dead: %i' % total_dead)
            print('total recovered: %i' % total_recovered)
            print('total infected: %i' % total_infected)
            print('total infectious: %i' % total_infectious)
            print('total unaffected: %i' % total_unaffected)

        self.pop_tracker.save(self.Config.run_id, 'results')

    def plot_sir(self,
                 size=(6, 3),
                 include_fatalities=False,
                 title='S-I-R plot of simulation'):
        plot_sir(self.Config, self.pop_tracker, size, include_fatalities,
                 title)
Ejemplo n.º 3
0
class Simulation():

    #TODO: if lockdown or otherwise stopped: destination -1 means no motion
    def __init__(self, *args, **kwargs):
        #load default config data
        self.Config = Configuration()
        #set_style(self.Config)

    def population_init(self):
        '''(re-)initializes population'''
        self.population = initialize_population(self.Config,
                                                self.Config.mean_age,
                                                self.Config.max_age,
                                                self.Config.xbounds,
                                                self.Config.ybounds)

    def initialize_simulation(self):
        #initialize times
        self.frame = 0
        self.time = 0
        self.last_step_change = 0
        self.above_act_thresh = False
        self.above_deact_thresh = False
        self.above_test_thresh = False
        #initialize default population
        self.population_init()
        #initalise destinations vector
        self.destinations = initialize_destination_matrix(
            self.Config.pop_size, 1)
        #initalise grid for tracking population positions
        self.grid_coords, self.ground_covered = initialize_ground_covered_matrix(
            self.Config.pop_size, self.Config.n_gridpoints,
            self.Config.xbounds, self.Config.ybounds)
        #initalise population tracker
        self.pop_tracker = Population_trackers(self.Config, self.grid_coords,
                                               self.ground_covered)

    def tstep(self):
        '''
        takes a time step in the simulation
        '''
        start = time.time()  # start clock
        #======================================================================================#
        #check destinations if active
        #define motion vectors if destinations active and not everybody is at destination
        active_dests = len(self.population[
            self.population[:, 11] != 0])  # look op this only once

        if active_dests > 0 and len(
                self.population[self.population[:, 12] == 0]) > 0:
            self.population = set_destination(self.population,
                                              self.destinations)
            self.population = check_at_destination(
                self.population,
                self.destinations,
                wander_factor=self.Config.wander_factor_dest)

        if active_dests > 0 and len(
                self.population[self.population[:, 12] == 1]) > 0:
            #keep them at destination
            self.population = keep_at_destination(self.population,
                                                  self.Config.isolation_bounds)

        #======================================================================================#
        #gravity wells
        if self.Config.gravity_strength > 0:
            [self.population, self.last_step_change] = update_gravity_forces(
                self.population, self.time, self.last_step_change,
                self.Config.wander_step_size, self.Config.gravity_strength,
                self.Config.wander_step_duration)

        #======================================================================================#
        #activate social distancing above a certain infection threshold
        if not self.above_act_thresh and self.Config.social_distance_threshold_on > 0:
            # If not previously above infection threshold activate when threshold reached
            if self.Config.thresh_type == 'hospitalized':
                self.above_act_thresh = sum(
                    self.population[:, 11] ==
                    1) >= self.Config.social_distance_threshold_on
            elif self.Config.thresh_type == 'infected':
                self.above_act_thresh = sum(
                    self.population[:, 6] ==
                    1) >= self.Config.social_distance_threshold_on
        elif self.Config.social_distance_threshold_on == 0:
            self.above_act_thresh = True

        #deactivate social distancing after infection drops below threshold after using social distancing
        if self.above_act_thresh and not self.above_deact_thresh and self.Config.social_distance_threshold_off > 0:
            # If previously went above infection threshold deactivate when threshold reached
            self.above_deact_thresh = sum(self.population[:,6][self.population[:,11] == 0] == 1) <= \
                                       self.Config.social_distance_threshold_off

        # activate social distancing at the onset of infection
        if not self.Config.SD_act_onset:
            act_social_distancing = self.above_act_thresh and not self.above_deact_thresh and sum(
                self.population[:, 6] == 1) > 0
        # activate social distancing from start of simulation
        elif self.Config.SD_act_onset:
            act_social_distancing = self.above_act_thresh and not self.above_deact_thresh

        #activate social distancing only for compliant individuals
        if self.Config.social_distance_factor > 0 and act_social_distancing:
            self.population[(self.population[:,17] == 0) &\
                            (self.population[:,11] == 0)] = update_repulsive_forces(self.population[(self.population[:,17] == 0) &\
                                                                                                    (self.population[:,11] == 0)], self.Config.social_distance_factor)
        #======================================================================================#
        #out of bounds
        #define bounds arrays, excluding those who are marked as having a custom destination
        if len(self.population[:, 11] == 0) > 0:
            buffer = 0.0
            _xbounds = np.array([[
                self.Config.xbounds[0] + buffer,
                self.Config.xbounds[1] - buffer
            ]] * len(self.population[self.population[:, 11] == 0]))
            _ybounds = np.array([[
                self.Config.ybounds[0] + buffer,
                self.Config.ybounds[1] - buffer
            ]] * len(self.population[self.population[:, 11] == 0]))

            self.population[self.population[:, 11] == 0] = update_wall_forces(
                self.population[self.population[:, 11] == 0], _xbounds,
                _ybounds)

        #======================================================================================#
        #update velocities
        self.population[(self.population[:,11] == 0) |\
                        (self.population[:,12] == 1)] = update_velocities(self.population[(self.population[:,11] == 0) |\
                                                                                          (self.population[:,12] == 1)],
                                                                                          self.Config.max_speed,self.Config.dt)

        #for dead ones: set velocity and social distancing to 0 for dead ones
        self.population[:, 3:5][self.population[:, 6] == 3] = 0
        self.population[:, 17][self.population[:, 6] == 3] = 1

        #update positions
        self.population = update_positions(self.population, self.Config.dt)

        #======================================================================================#
        #find new infections

        if not self.above_test_thresh and self.Config.testing_threshold_on > 0:
            # If not previously above infection threshold activate when threshold reached
            self.above_test_thresh = sum(
                self.population[:, 6] == 1) >= self.Config.testing_threshold_on
            # self.above_test_thresh = sum(self.population[:,6] == 1) >= self.Config.social_distance_threshold_on
        elif self.Config.testing_threshold_on == 0:
            self.above_test_thresh = True

        act_testing = self.above_test_thresh and sum(
            self.population[:, 6] == 1) > 0

        self.population, self.destinations = infect(
            self.population,
            self.Config,
            self.frame,
            send_to_location=self.Config.self_isolate,
            location_bounds=self.Config.isolation_bounds,
            destinations=self.destinations,
            location_no=1,
            location_odds=self.Config.self_isolate_proportion,
            test_flag=act_testing)

        #recover and die
        self.population = recover_or_die(self.population, self.frame,
                                         self.Config)

        #======================================================================================#
        #send cured back to population if self isolation active
        #perhaps put in recover or die class
        #send cured back to population
        self.population[:, 11][self.population[:, 6] == 2] = 0

        #======================================================================================#
        #update population statistics
        self.pop_tracker.update_counts(self.population, self.frame)

        #======================================================================================#
        #visualise
        if self.Config.visualise and (
                self.frame % self.Config.visualise_every_n_frame) == 0:
            draw_tstep(self.Config, self.population, self.pop_tracker,
                       self.frame, self.fig, self.spec, self.ax1, self.ax2,
                       self.tight_bbox)

        #report stuff to console
        if (self.Config.verbose) and ((self.frame % self.Config.report_freq)
                                      == 0):
            end = time.time()
            time_elapsed = end - start  # elapsed time

            sys.stdout.write('\r')
            sys.stdout.write(
                '%i: S: %i, I: %i, R: %i, in treatment: %i, F: %i, of total: %i, D: %.5f, GC: %.5f, time: %.5f'
                % (self.frame, self.pop_tracker.susceptible[-1],
                   self.pop_tracker.infectious[-1],
                   self.pop_tracker.recovered[-1],
                   len(self.population[self.population[:, 10] == 1]),
                   self.pop_tracker.fatalities[-1], self.Config.pop_size,
                   self.pop_tracker.distance_travelled[-1],
                   self.pop_tracker.mean_perentage_covered[-1], time_elapsed))

        #save popdata if required
        if self.Config.save_pop and (self.frame %
                                     self.Config.save_pop_freq) == 0:
            save_population(self.population, self.frame,
                            self.Config.save_pop_folder)
        #run callback
        self.callback()

        #======================================================================================#
        #update frame
        self.frame += 1
        self.time += self.Config.dt

    def callback(self):
        '''placeholder function that can be overwritten.

        By overwriting this method any custom behavior can be implemented.
        The method is called after every simulation timestep.
        '''

        if self.frame == 50:
            print('\ninfecting person (Patient Zero)')

            if self.Config.patient_Z_loc == 'random':
                self.population[0][6] = 1
                self.population[0][8] = 50
                self.population[0][10] = 1
            elif self.Config.patient_Z_loc == 'central':

                center = np.zeros((self.Config.pop_size, 2))

                center[:, 0] = (self.Config.xbounds[0] +
                                self.Config.xbounds[1]) / 2
                center[:, 1] = (self.Config.ybounds[0] +
                                self.Config.ybounds[1]) / 2

                to_center = (center - self.population[:, 1:3])
                dist = np.linalg.norm(to_center, axis=1)

                # infect nearest individual to center
                self.population[np.argmin(dist)][6] = 1
                self.population[np.argmin(dist)][8] = 50
                self.population[np.argmin(dist)][10] = 1

    def run(self):
        '''run simulation'''

        if self.Config.visualise:
            self.fig, self.spec, self.ax1, self.ax2, self.tight_bbox = build_fig(
                self.Config)

        i = 0

        while i < self.Config.simulation_steps:
            try:
                self.tstep()
            except KeyboardInterrupt:
                print('\nCTRL-C caught, exiting')
                sys.exit(1)

            #check whether to end if no infectious persons remain.
            #check if self.frame is above some threshold to prevent early breaking when simulation
            #starts initially with no infections.
            if self.Config.endif_no_infections and self.frame >= 300:
                if len(self.population[(self.population[:, 6] == 1) |
                                       (self.population[:, 6] == 4)]) == 0:
                    i = self.Config.simulation_steps
            else:
                i += 1

        if self.Config.plot_last_tstep:
            self.fig_sir, self.spec_sir, self.ax1_sir = build_fig_SIRonly(
                self.Config)
            draw_SIRonly(self.Config, self.population, self.pop_tracker,
                         self.frame, self.fig_sir, self.spec_sir, self.ax1_sir)

        if self.Config.save_data:
            save_data(self.population, self.pop_tracker)

        #report outcomes
        if self.Config.verbose:
            print('\n-----stopping-----\n')
            print('total timesteps taken: %i' % self.frame)
            print('total dead: %i' %
                  len(self.population[self.population[:, 6] == 3]))
            print('total recovered: %i' %
                  len(self.population[self.population[:, 6] == 2]))
            print('total infected: %i' %
                  len(self.population[self.population[:, 6] == 1]))
            print('total infectious: %i' %
                  len(self.population[(self.population[:, 6] == 1) |
                                      (self.population[:, 6] == 4)]))
            print('total unaffected: %i' %
                  len(self.population[self.population[:, 6] == 0]))
            print('mean distance travelled: %f' %
                  np.mean(self.pop_tracker.distance_travelled))
Ejemplo n.º 4
0
class Simulation():
    def __init__(self):

        self.Config = Configuration()
        self.frame = 0

        self.population = initialize_population(self.Config,
                                                self.Config.xbounds,
                                                self.Config.ybounds)

        self.pop_tracker = Population_trackers()

        self.peak_infections = 0

    def tstep(self):

        if self.frame == 0:
            self.fig, self.spec, self.ax1, self.ax2 = build_fig(self.Config)

        xbounds = np.array(
            [[self.Config.xbounds[0] + 0.02, self.Config.xbounds[1] - 0.02]] *
            self.Config.pop_size)
        ybounds = np.array(
            [[self.Config.ybounds[0] + 0.02, self.Config.ybounds[1] - 0.02]] *
            self.Config.pop_size)
        self.population = out_of_bounds(self.population, xbounds, ybounds)

        if self.Config.is_lockdown and self.Config.lockdown == False:
            if len(self.population[(self.population[:, 6] == 1)]
                   ) >= self.Config.lockdown_percentage * self.Config.pop_size:
                self.Config.lockdown = True
                print("\nLockdown Started")

        left_range = [
            self.Config.xbounds[0] + 0.02, self.Config.xbounds[1] / 3 - 0.02
        ]
        mid_range = [
            self.Config.xbounds[1] / 3 + 0.02,
            2 * self.Config.xbounds[1] / 3 - 0.02
        ]
        right_range = [
            2 * self.Config.xbounds[1] / 3 + 0.02,
            self.Config.xbounds[1] - 0.02
        ]

        bottom_range = [
            self.Config.ybounds[0] + 0.02, self.Config.ybounds[1] / 2 - 0.02
        ]
        top_range = [
            self.Config.ybounds[1] / 2 + 0.02, self.Config.ybounds[1] - 0.02
        ]

        left_condition = (self.population[:, 1] <= self.Config.xbounds[1] / 3)
        mid_condition = (
            self.population[:, 1] > self.Config.xbounds[1] / 3) & (
                self.population[:, 1] <= 2 * self.Config.xbounds[1] / 3)
        right_condition = (self.population[:, 1] >
                           2 * self.Config.xbounds[1] / 3)

        bottom_condition = (self.population[:, 2] <=
                            self.Config.ybounds[1] / 2)
        top_condition = (self.population[:, 2] > self.Config.ybounds[1] / 2)

        if self.Config.lockdown:

            x_left_bottom = np.array(
                [left_range] *
                len(self.population[left_condition & bottom_condition]))
            y_left_bottom = np.array(
                [bottom_range] *
                len(self.population[left_condition & bottom_condition]))
            self.population[left_condition & bottom_condition] = out_of_bounds(
                self.population[left_condition & bottom_condition],
                x_left_bottom, y_left_bottom)

            x_left_top = np.array(
                [left_range] *
                len(self.population[left_condition & top_condition]))
            y_left_top = np.array(
                [top_range] *
                len(self.population[left_condition & top_condition]))
            self.population[left_condition & top_condition] = out_of_bounds(
                self.population[left_condition & top_condition], x_left_top,
                y_left_top)

            x_mid_bottom = np.array(
                [mid_range] *
                len(self.population[mid_condition & bottom_condition]))
            y_mid_bottom = np.array(
                [bottom_range] *
                len(self.population[mid_condition & bottom_condition]))
            self.population[mid_condition & bottom_condition] = out_of_bounds(
                self.population[mid_condition & bottom_condition],
                x_mid_bottom, y_mid_bottom)

            x_mid_top = np.array(
                [mid_range] *
                len(self.population[mid_condition & top_condition]))
            y_mid_top = np.array(
                [top_range] *
                len(self.population[mid_condition & top_condition]))
            self.population[mid_condition & top_condition] = out_of_bounds(
                self.population[mid_condition & top_condition], x_mid_top,
                y_mid_top)

            x_right_bottom = np.array(
                [right_range] *
                len(self.population[right_condition & bottom_condition]))
            y_right_bottom = np.array(
                [bottom_range] *
                len(self.population[right_condition & bottom_condition]))
            self.population[right_condition
                            & bottom_condition] = out_of_bounds(
                                self.population[right_condition
                                                & bottom_condition],
                                x_right_bottom, y_right_bottom)

            x_right_top = np.array(
                [right_range] *
                len(self.population[right_condition & top_condition]))
            y_right_top = np.array(
                [top_range] *
                len(self.population[right_condition & top_condition]))
            self.population[right_condition & top_condition] = out_of_bounds(
                self.population[right_condition & top_condition], x_right_top,
                y_right_top)

        self.population = update_randoms(self.population, self.Config.pop_size,
                                         self.Config.speed)

        self.population[:, 5][self.population[:, 6] == 3] = 0

        self.population = update_positions(self.population)

        self.population = infect(self.population, self.Config, self.frame)

        self.population = recover_or_die(self.population, self.frame,
                                         self.Config)

        self.pop_tracker.update_counts(self.population)

        draw_tstep(self.Config, self.population, self.pop_tracker, self.frame,
                   self.fig, self.spec, self.ax1, self.ax2)

        self.peak_infections = max(
            self.peak_infections,
            len(self.population[self.population[:, 6] == 1]))

        if self.frame == 50:
            print('\ninfecting patient zero')
            self.population[0][6] = 1

        self.frame += 1

    def run(self):

        i = 0

        while i < 10000:
            try:
                self.tstep()
            except KeyboardInterrupt:
                print('\nCTRL-C caught, exiting')
                sys.exit(1)

            if self.frame >= 500:
                if len(self.population[(self.population[:, 6] == 1) |
                                       (self.population[:, 6] == 4)]) == 0:
                    break
        i = i + 1

        print('\n-----stopping-----\n')
        print('total timesteps taken: %i' % self.frame)
        print('total dead: %i' %
              len(self.population[self.population[:, 6] == 3]))
        print('total recovered: %i' %
              len(self.population[self.population[:, 6] == 2]))
        print('total unaffected: %i' %
              len(self.population[self.population[:, 6] == 0]))
        print('peak infections: %i' % self.peak_infections)