Esempio n. 1
0
    def infect(self, population: Population, frame):

        #Get the index of all the people who were infected in the previous step
        infected_idx = population.get_all_infected()
        persons = population.get_person()

        infected_counter = 0
        for idx in infected_idx:
            infected_counter += 1
            if (population.get_time_infected(int(idx[0]), frame) >=
                    self.recovery_time):
                population = self.die_or_immune(population, int(idx[0]))

            x_bounds = [
                persons[int(idx[0])][index.x_axis] -
                math.sqrt(self.infection_range),
                persons[int(idx[0])][index.x_axis] +
                math.sqrt(self.infection_range)
            ]
            y_bounds = [
                persons[int(idx[0])][index.y_axis] -
                math.sqrt(self.infection_range),
                persons[int(idx[0])][index.y_axis] +
                math.sqrt(self.infection_range)
            ]
            # print(population.get_time_infected(int(idx[0]), frame))
            tmp = self.find_nearby(persons, x_bounds, y_bounds)
            for i in tmp:
                chance = np.random.uniform(low=0.0001, high=1)
                if chance < persons[int(i)][index.susceptibility] and persons[
                        int(idx[0])][index.g_value] > 0:
                    population.persons[int(i)][9] = 1
                    population.persons[int(i)][index.infected_by] = idx[0]
                    population.set_infected_at(int(i), frame)
                    population.persons[int(idx[0])][index.g_value] -= 1
                    if (len(population.persons[
                            population.persons[:, index.hospitalized] == 1]) <
                            self.total_healthcare_capacity):
                        population.persons[int(i)][index.hospitalized] = 1

        return population
class MovementTest(unittest.TestCase):
    def setUp(self) -> None:
        self.pop = Population(size=10)
        logging.basicConfig(
            format='\n%(asctime)s:%(module)s:%(levelname)s:%(message)s',
            level=logging.DEBUG)
        logging.info('Testing Movements class')
        self.movement = Movement()

    def tearDown(self) -> None:
        self.pop = None
        self.movement = None
        pass

    def test_update_person(self) -> None:
        """

        Tests update_person() method of Movement class and movements module to check data is getting updated randomly
        """

        self.assertIsInstance(
            self.movement.update_persons(self.pop.get_person(),
                                         len(self.pop.get_person())),
            np.ndarray)
        self.pop.persons[:, idx.speed] = 0.1
        self.assertNotEqual(
            self.movement.update_persons(
                self.pop.get_person(),
                len(self.pop.get_person()),
                heading_update_chance=1)[:, idx.y_dir].any(), 0)
        self.assertNotEqual(
            self.movement.update_persons(
                self.pop.get_person(),
                len(self.pop.get_person()),
                heading_update_chance=1)[:, idx.x_dir].any(), 0)
        self.assertNotEqual(
            self.movement.update_persons(
                self.pop.get_person(),
                len(self.pop.get_person()),
                heading_update_chance=1)[:, idx.speed].any(), 0.1)

    def test_out_of_bounds(self) -> None:
        """
        
        Tests out_of_bounds() method of Movement class and movements module to check directions are updated accordingly to prevent a person from going out of bounds
        """

        self.assertIsInstance(
            self.movement.out_of_bounds(self.pop.get_person(),
                                        np.array([[0, 1]] * 10),
                                        np.array([[0, 1]] * 10)), np.ndarray)
        self.pop.persons[:, idx.speed] = 1
        self.pop.persons[:, idx.x_axis] = 1.1
        self.pop.persons[:, idx.y_axis] = 1.1
        self.pop.persons[:, idx.x_dir] = 0.5
        self.pop.persons[:, idx.y_dir] = 0.5

        self.assertLess(
            list(
                self.movement.out_of_bounds(
                    self.pop.get_person(), np.array([[0, 1]] * 10),
                    np.array([[0, 1]] * 10))[:, idx.x_dir]), [0] * 10)
        self.assertLess(
            list(
                self.movement.out_of_bounds(
                    self.pop.get_person(), np.array([[0, 1]] * 10),
                    np.array([[0, 1]] * 10))[:, idx.x_dir]), [0] * 10)

        self.pop.persons[:, idx.x_axis] = -0.1
        self.pop.persons[:, idx.y_axis] = -0.1
        self.pop.persons[:, idx.x_dir] = -0.5
        self.pop.persons[:, idx.y_dir] = -0.5
        self.assertGreater(
            list(
                self.movement.out_of_bounds(
                    self.pop.get_person(), np.array([[0, 1]] * 10),
                    np.array([[0, 1]] * 10))[:, idx.x_dir]), [0] * 10)
        self.assertGreater(
            list(
                self.movement.out_of_bounds(
                    self.pop.get_person(), np.array([[0, 1]] * 10),
                    np.array([[0, 1]] * 10))[:, idx.x_dir]), [0] * 10)

    def test_update_pop(self) -> None:
        """

        Tests the update_pop() method of Movement class and movements module to check if the position of the population members are getting updated according to the arguments
        """
        self.pop.persons[:, idx.x_dir] = 0.1
        self.pop.persons[:, idx.y_dir] = 0.1
        self.pop.persons[:, idx.speed] = 1

        expectd_x = list(self.pop.persons[:, idx.x_axis] + 0.1)
        expectd_y = list(self.pop.persons[:, idx.y_axis] + 0.1)

        self.pop.persons = self.movement.update_pop(self.pop.persons)

        self.assertIsInstance(self.pop.get_person(), np.ndarray)
        self.assertListEqual(list(self.pop.get_x_axis()), expectd_x)
        self.assertListEqual(list(self.pop.get_y_axis()), expectd_y)
class PopulationUtil(object):
    """
    Class representing the self.person.persons 
    """

    #_instance = Population()
    # def getInstance():
    #     return Population._instance

    def __init__(self, size: int, r: float, k: float, min_age: int,
                 max_age: int, mortality_rate: int, social_distance_per: int,
                 infection_range: float, recovery_time: int,
                 total_healthcare_capacity: int, mask_effectiveness: dict,
                 speed: float, social_distancing_at: int,
                 mask_wearing_at: int):
        """
        Constructor used for initializing the bound for the x axis, y axis, the k and R value for the particular population

        Parameters
        ----------
        size : int
            Size of the population
        x_bounds : list
            The list containing the lower and upper bound for the x axis of the population map
        y_bounds : list
            The list containing the lower and upper bound for the y axis of the population map
        r : float
            Disease reproduction (R0) rate for the virus
        k : float
            The k value for the virus
        """
        self.population = Population(size)
        self.virus = Virus(infection_range, recovery_time,
                           total_healthcare_capacity)
        self.recovery_time = recovery_time
        self.total_healthcare_capacity = total_healthcare_capacity
        self.movement = Movement()
        self.size = size
        self.x_bounds = [0, 1]
        self.y_bounds = [0, 1]
        self.k = k
        self.r = r
        self.destinations = np.random.uniform(low=0,
                                              high=1,
                                              size=(self.size, 2))
        self.min_age = min_age
        self.max_age = max_age
        self.mortality_rate = mortality_rate
        self.social_distance_per = social_distance_per
        self.mask_effectiveness = mask_effectiveness
        self.speed = speed
        self.persons = self.population.get_person()
        self.enforce_social_distance_at = social_distancing_at
        self.enforce_mask_wearing_at = mask_wearing_at
        self.social_distancing_enforced = False
        self.mask_wearing_enforced = False

        self.initialize_persons()

    def initialize_persons(self):
        """
        Method which initializes the person list in the population and further calls another method to update other 
        properties of the individual persons
        """
        self.population.initialize_id(0, self.size)
        self.population.initialize_ages(self.min_age, self.max_age, self.size)
        self.population.initialize_positions(self.x_bounds, self.y_bounds,
                                             self.size)
        self.population.initialize_g_value(self.r, 1 / self.k, self.size)
        self.population.initialize_mortality_rate(self.size,
                                                  self.mortality_rate)
        self.population.initialize_susceptibility()
        self.population.initialize_infected_by()

        self.persons[:, 7] = 1
        self.persons[:, 10] = 0.1
        self.persons[:, 11] = 0.1

        #Update the destination each person is headed to and corresponding speed randomly
        self.persons = self.movement.update_persons(self.persons, self.size,
                                                    self.speed, 1)

        self.infected_person = np.random.randint(0, self.size)
        self.persons[self.infected_person, index.g_value] = 3
        self.population.set_infected_at(self.infected_person, 0)
        self.persons[self.infected_person,
                     index.infected_by] = self.infected_person
        self.persons[self.infected_person, index.social_distance] = 0
        self.persons[self.infected_person, 9] = 1

    def move(self, frame):
        if frame == self.enforce_mask_wearing_at:
            self.population.initialize_mask_eff(self.size,
                                                self.mask_effectiveness)
            self.population.initialize_susceptibility()
            self.mask_wearing_enforced = True

        if frame == self.enforce_social_distance_at:
            self.population.initialize_social_distancing(
                self.social_distance_per)
            self.persons[self.infected_person, index.social_distance] = 0
            self.social_distancing_enforced = True

        if frame >= self.enforce_social_distance_at and frame % 300 == 0 and self.enforce_social_distance_at >= 0:
            self.population.initialize_social_distancing(
                self.social_distance_per)

        _xbounds = np.array([[0, 1]] * self.size)
        _ybounds = np.array([[0, 1]] * self.size)

        self.persons = self.movement.out_of_bounds(self.persons, _xbounds,
                                                   _ybounds)

        self.persons = self.movement.update_persons(self.persons, self.size,
                                                    self.speed)

        self.persons = self.movement.update_pop(self.persons)

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