Esempio n. 1
0
    def __init__(self,
                 env,
                 name,
                 infection_timestamp,
                 household,
                 workplace,
                 rho=0.3,
                 gamma=0.21):
        self.env = env
        self.events = []
        self.name = name

        self.household = household
        self.workplace = workplace
        self.location = household
        self.rho = rho
        self.gamma = gamma

        self.action = Human.actions['at_home']
        self.visits = Visits()

        # Indicates whether this person will show severe signs of illness.
        self.infection_timestamp = infection_timestamp
        self.really_sick = self.is_sick and random.random() >= 0.9
        self.never_recovers = random.random() >= 0.99

        # habits
        self.avg_shopping_time = _draw_random_discreet_gaussian(
            AVERAGE_SHOP_TIME_MINUTES, SCALE_SHOP_TIME_MINUTES)
        self.scale_shopping_time = _draw_random_discreet_gaussian(
            AVG_SCALE_SHOP_TIME_MINUTES, SCALE_SCALE_SHOP_TIME_MINUTES)

        self.avg_exercise_time = _draw_random_discreet_gaussian(
            AVG_EXERCISE_MINUTES, SCALE_EXERCISE_MINUTES)
        self.scale_exercise_time = _draw_random_discreet_gaussian(
            AVG_SCALE_EXERCISE_MINUTES, SCALE_SCALE_EXERCISE_MINUTES)

        self.avg_working_hours = _draw_random_discreet_gaussian(
            AVG_WORKING_HOURS, SCALE_WORKING_HOURS)
        self.scale_working_hours = _draw_random_discreet_gaussian(
            AVG_SCALE_WORKING_HOURS, SCALE_SCALE_WORKING_HOURS)

        self.avg_misc_time = _draw_random_discreet_gaussian(
            AVG_MISC_MINUTES, SCALE_MISC_MINUTES)
        self.scale_misc_time = _draw_random_discreet_gaussian(
            AVG_SCALE_MISC_MINUTES, SCALE_SCALE_MISC_MINUTES)

        # TODO: multiple possible days and times & limit these activities in a week
        self.shopping_days = np.random.choice(range(7))
        self.shopping_hours = np.random.choice(range(7, 20))

        self.exercise_days = np.random.choice(range(7))
        self.exercise_hours = np.random.choice(range(7, 20))

        self.work_start_hour = np.random.choice(range(7, 12))
Esempio n. 2
0
    def excursion(self, city, type):

        if type == "shopping":
            grocery_store = self._select_location(location_type="stores",
                                                  city=city)
            t = _draw_random_discreet_gaussian(self.avg_shopping_time,
                                               self.scale_shopping_time,
                                               self.rng)
            with grocery_store.request() as request:
                yield request
                yield self.env.process(self.at(grocery_store, t))

        elif type == "exercise":
            park = self._select_location(location_type="park", city=city)
            t = _draw_random_discreet_gaussian(self.avg_exercise_time,
                                               self.scale_exercise_time,
                                               self.rng)
            yield self.env.process(self.at(park, t))

        elif type == "work":
            t = _draw_random_discreet_gaussian(self.avg_working_hours,
                                               self.scale_working_hours,
                                               self.rng)
            yield self.env.process(self.at(self.workplace, t))

        elif type == "leisure":
            S = 0
            p_exp = 1.0
            while True:
                if self.rng.random() > p_exp:  # return home
                    yield self.env.process(self.at(self.household, 60))
                    break

                loc = self._select_location(location_type='miscs', city=city)
                S += 1
                p_exp = self.rho * S**(-self.gamma * self.adjust_gamma)
                with loc.request() as request:
                    yield request
                    t = _draw_random_discreet_gaussian(self.avg_misc_time,
                                                       self.scale_misc_time,
                                                       self.rng)
                    yield self.env.process(self.at(loc, t))
        else:
            raise ValueError(f'Unknown excursion type:{type}')
Esempio n. 3
0
    def shop(self, city):
        self.action = Human.actions['shopping']
        grocery_store = self._select_location(location_type="stores",
                                              city=city)  ## MAKE IT EPR

        with grocery_store.request() as request:
            yield request
            t = _draw_random_discreet_gaussian(self.avg_shopping_time,
                                               self.scale_shopping_time)
            yield self.env.process(self.at(grocery_store, t))
Esempio n. 4
0
    def __init__(self, env, rng, name, infection_timestamp, household, workplace, age, rho=0.3, gamma=0.21, symptoms=None, test_results=None):
        self.env = env
        self.events = []
        self.name = name
        self.rng = rng
        self.visits = Visits()
        self.age=age

        self.household = household
        self.workplace = workplace

        self.rho = rho
        self.gamma = gamma
        self.location = household

        # Indicates whether this person will show severe signs of illness.
        # probability of being asymptomatic is basically 50%, but a bit less if you're older
        # and a bit more if you're younger
        self.asymptomatic = rng.random() > (BASELINE_P_ASYMPTOMATIC - (self.age - 50)*0.5)/100
        self.infection_timestamp = infection_timestamp
        self.never_recovers = rng.random() >= 0.99
        self.recovered_timestamp =  datetime.datetime.min
        self.r0 = []
        self.has_logged_symptoms = False

        self.last_state = None
        # metrics
        self.n_infectious_contacts = 0

        # habits
        self.avg_shopping_time = _draw_random_discreet_gaussian(AVG_SHOP_TIME_MINUTES, SCALE_SHOP_TIME_MINUTES, rng)
        self.scale_shopping_time = _draw_random_discreet_gaussian(AVG_SCALE_SHOP_TIME_MINUTES, SCALE_SCALE_SHOP_TIME_MINUTES, rng)

        self.avg_exercise_time = _draw_random_discreet_gaussian(AVG_EXERCISE_MINUTES, SCALE_EXERCISE_MINUTES, rng)
        self.scale_exercise_time = _draw_random_discreet_gaussian(AVG_SCALE_EXERCISE_MINUTES, SCALE_SCALE_EXERCISE_MINUTES, rng)

        self.avg_working_hours = _draw_random_discreet_gaussian(AVG_WORKING_MINUTES, SCALE_WORKING_MINUTES, rng)
        self.scale_working_hours = _draw_random_discreet_gaussian(AVG_SCALE_WORKING_MINUTES, SCALE_SCALE_WORKING_MINUTES, rng)

        self.avg_misc_time = _draw_random_discreet_gaussian(AVG_MISC_MINUTES, SCALE_MISC_MINUTES, rng)
        self.scale_misc_time = _draw_random_discreet_gaussian(AVG_SCALE_MISC_MINUTES, SCALE_SCALE_MISC_MINUTES, rng)

        # TODO: multiple possible days and times & limit these activities in a week
        self.shopping_days = rng.choice(range(7))
        self.shopping_hours = rng.choice(range(7, 20))

        self.exercise_days = rng.choice(range(7))
        self.exercise_hours = rng.choice(range(7, 20))

        self.work_start_hour = rng.choice(range(7, 12))
Esempio n. 5
0
    def take_a_trip(self, city):
        S = 0
        p_exp = 1.0
        while True:
            if np.random.random() > p_exp:  # return home
                yield self.env.process(self.at(self.household, 60))
                break

            loc = self._select_location(location_type='miscs', city=city)
            S += 1
            p_exp = self.rho * S ** (-self.gamma * self.adjust_gamma)
            with loc.request() as request:
                yield request
                t = _draw_random_discreet_gaussian(self.avg_misc_time, self.scale_misc_time)
                yield self.env.process(self.at(loc, t))
Esempio n. 6
0
    def send_message(self,
                     owner,
                     tracing_method,
                     order=1,
                     reason="test",
                     payload=None):
        p_contact = tracing_method.p_contact
        delay = tracing_method.delay
        app = tracing_method.app
        today = (owner.env.timestamp - owner.env.initial_timestamp).days
        if app and not owner.has_app:
            return

        for idx, human in enumerate(self.book):

            redundant_tracing = human.message_info[
                'traced'] and tracing_method.dont_trace_traced
            if redundant_tracing:  # manual and digital - no effect of new messages
                continue

            if not app or (app and human.has_app):
                if human.rng.random() < p_contact:
                    self.update_book(human)
                    t = 0
                    if delay:
                        t = _draw_random_discreet_gaussian(
                            MANUAL_TRACING_DELAY_AVG, MANUAL_TRACING_DELAY_STD,
                            human.rng)

                    total_contacts = sum(map(lambda x: x[1], self.book[human]))
                    human.update_risk(
                        update_messages={
                            'n': total_contacts,
                            'delay': t,
                            'order': order,
                            'reason': reason,
                            'payload': payload
                        })
                    sent_at = human.env.timestamp + datetime.timedelta(
                        minutes=idx)
                    for i in range(total_contacts):
                        # FIXME when we have messages sent hourly with a bucketed set of users sending messages
                        human.update_messages.append(
                            owner.cur_message_risk_update(
                                today, owner.uid, owner.risk, sent_at))
Esempio n. 7
0
    def send_message(self, owner, city, cur_day, RISK_MODEL):
        if RISK_MODEL == "manual tracing":
            p_contact = MANUAL_TRACING_NOISE
            delay = 1
            app = False

        elif RISK_MODEL in [
                'digital tracing', 'first order probabilistic tracing'
        ]:
            p_contact = 1
            delay = 0
            app = True
            if not owner.has_app:
                return

        # if each person has the app, increment the contacts for that person
        contact_count = defaultdict(int)
        for message in self.messages:
            if not app or not message.has_app:
                continue
            if owner.rng.random() < p_contact:
                contact_count[message.unobs_id] += 1

        ts = {}
        # for each unique person contacted, determine when they will receive an update and update their risk
        for contact_id, num_contacts in contact_count.items():
            t = delay * _draw_random_discreet_gaussian(
                MANUAL_TRACING_DELAY_AVG, MANUAL_TRACING_DELAY_STD, owner.rng)
            ts[contact_id] = t
            city.hd[contact_id].update_risk(cur_day,
                                            update_messages={
                                                'n': num_contacts,
                                                'delay': t
                                            })

        # for each message add the message to sent update_messages
        for message in self.messages:
            if not app or not message.has_app:
                continue
            if owner.rng.random() < p_contact:
                t = ts[message.unobs_id]
                self.update_messages.append(
                    city.hd[message.unobs_id].cur_message_risk_update(
                        cur_day, message.day, message.uid, message.risk, t))
Esempio n. 8
0
def run_simu(n_stores=None,
             n_people=None,
             n_parks=None,
             n_misc=None,
             init_percent_sick=0,
             store_capacity=30,
             misc_capacity=30,
             start_time=datetime.datetime(2020, 2, 28, 0, 0),
             simulation_days=10,
             outfile=None,
             print_progress=False):
    env = Env(start_time)
    city_limit = ((0, 1000), (0, 1000))
    stores = [
        Location(
            env,
            capacity=_draw_random_discreet_gaussian(store_capacity,
                                                    int(0.5 * store_capacity)),
            cont_prob=0.1,
            location_type='store',
            name=f'store{i}',
            lat=random.randint(*city_limit[0]),
            lon=random.randint(*city_limit[1]),
        ) for i in range(n_stores)
    ]
    parks = [
        Location(env,
                 cont_prob=0.02,
                 name=f'park{i}',
                 location_type='park',
                 lat=random.randint(*city_limit[0]),
                 lon=random.randint(*city_limit[1])) for i in range(n_parks)
    ]
    households = [
        Location(
            env,
            cont_prob=1,
            name=f'household{i}',
            location_type='household',
            lat=random.randint(*city_limit[0]),
            lon=random.randint(*city_limit[1]),
        ) for i in range(int(n_people / 2))
    ]
    workplaces = [
        Location(
            env,
            cont_prob=1,
            name=f'workplace{i}',
            location_type='workplace',
            lat=random.randint(*city_limit[0]),
            lon=random.randint(*city_limit[1]),
        ) for i in range(int(n_people / 30))
    ]
    miscs = [
        Location(env,
                 cont_prob=1,
                 capacity=_draw_random_discreet_gaussian(
                     misc_capacity, int(0.5 * misc_capacity)),
                 name=f'misc{i}',
                 location_type='misc',
                 lat=random.randint(*city_limit[0]),
                 lon=random.randint(*city_limit[1])) for i in range(n_misc)
    ]

    humans = [
        Human(env=env,
              name=i,
              infection_timestamp=start_time
              if i < n_people * init_percent_sick else None,
              household=np.random.choice(households),
              workplace=np.random.choice(workplaces)) for i in range(n_people)
    ]

    city = City(stores=stores, parks=parks, humans=humans, miscs=miscs)
    monitors = [EventMonitor(f=120)]

    # run the simulation
    if print_progress:
        monitors.append(TimeMonitor(60))

    for human in humans:
        env.process(human.run(city=city))

    for m in monitors:
        env.process(m.run(env, city=city))
    env.run(until=simulation_days * 24 * 60 / TICK_MINUTE)

    monitors[0].dump(outfile)
    return monitors[0].data
Esempio n. 9
0
    def excursion(self, city, type):

        if type == "shopping":
            grocery_store = self._select_location(location_type="stores", city=city)
            t = _draw_random_discreet_gaussian(self.avg_shopping_time, self.scale_shopping_time, self.rng)
            with grocery_store.request() as request:
                yield request
                yield self.env.process(self.at(grocery_store, city, t))

        elif type == "exercise":
            park = self._select_location(location_type="park", city=city)
            t = _draw_random_discreet_gaussian(self.avg_exercise_time, self.scale_exercise_time, self.rng)
            yield self.env.process(self.at(park, city, t))

        elif type == "work":
            t = _draw_random_discreet_gaussian(self.avg_working_minutes, self.scale_working_minutes, self.rng)
            yield self.env.process(self.at(self.workplace, city, t))

        elif type == "hospital":
            print(f"{self} got hospitalized")
            hospital = self._select_location(location_type=type, city=city)
            if hospital is None: # no more hospitals
                self.dead = True
                self.recovered_timestamp = datetime.datetime.max
                yield self.env.timeout(np.inf)

            self.obs_hospitalized = True
            t = self.recovery_days -(self.env.timestamp - self.infection_timestamp).total_seconds() / 86400 # DAYS
            yield self.env.process(self.at(hospital, city, t * 24 * 60))

        elif type == "hospital-icu":
            print(f"{self} got icu-ed")
            icu = self._select_location(location_type=type, city=city)
            if icu is None:
                self.dead = True
                self.recovered_timestamp = datetime.datetime.max
                yield self.env.timeout(np.inf)

            if len(self.preexisting_conditions) < 2:
                extra_time = self.rng.choice([1, 2, 3], p=[0.5, 0.3, 0.2])
            else:
                extra_time = self.rng.choice([1, 2, 3], p=[0.2, 0.3, 0.5]) # DAYS
            t = self.viral_load_plateau_end - self.viral_load_plateau_start + extra_time

            yield self.env.process(self.at(icu, city, t * 24 * 60))

        elif type == "leisure":
            S = 0
            p_exp = 1.0
            while True:
                if self.rng.random() > p_exp:  # return home
                    yield self.env.process(self.at(self.household, city, 60))
                    break

                loc = self._select_location(location_type='miscs', city=city)
                S += 1
                p_exp = self.rho * S ** (-self.gamma * self.adjust_gamma)
                with loc.request() as request:
                    yield request
                    t = _draw_random_discreet_gaussian(self.avg_misc_time, self.scale_misc_time, self.rng)
                    yield self.env.process(self.at(loc, city, t))
        else:
            raise ValueError(f'Unknown excursion type:{type}')
Esempio n. 10
0
    def __init__(self, env, name, age, rng, infection_timestamp, household, workplace, profession, rho=0.3, gamma=0.21, symptoms=[],
                 test_results=None):

        self.last_date = env.timestamp.date()
        self.env = env
        self._events = []
        self.name = f"human:{name}"
        self.rng = rng
        self.profession = profession
        self.is_healthcare_worker = True if profession == "healthcare" else False
        self.assign_household(household)
        self.workplace = workplace
        self.rho = rho
        self.gamma = gamma

        self.age = age
        self.sex = _get_random_sex(self.rng)
        self.preexisting_conditions = _get_preexisting_conditions(self.age, self.sex, self.rng)

        age_modifier = 2 if self.age > 40 or self.age < 12 else 2
        # &carefulness
        if self.rng.rand() < P_CAREFUL_PERSON:
            self.carefulness = (round(self.rng.normal(55, 10)) + self.age/2) / 100
        else:
            self.carefulness = (round(self.rng.normal(25, 10)) + self.age/2) / 100

        self.has_app = self.rng.rand() < (P_HAS_APP / age_modifier) + (self.carefulness / 2)

        # logged info can be quite different
        self.has_logged_info = self.has_app and self.rng.rand() < self.carefulness
        self.obs_is_healthcare_worker = True if self.is_healthcare_worker and rng.random()<0.9 else False # 90% of the time, healthcare workers will declare it
        self.obs_age = self.age if self.has_app and self.has_logged_info else None
        self.obs_sex = self.sex if self.has_app and self.has_logged_info else None
        self.obs_preexisting_conditions = self.preexisting_conditions if self.has_app and self.has_logged_info else None

        self.rest_at_home = False # to track mobility due to symptoms
        self.visits = Visits()
        self.travelled_recently = self.rng.rand() > 0.9

        # &symptoms, &viral-load
        # probability of being asymptomatic is basically 50%, but a bit less if you're older and a bit more if you're younger
        self.is_asymptomatic = self.rng.rand() < (BASELINE_P_ASYMPTOMATIC - (self.age - 50) * 0.5) / 100
        self.asymptomatic_infection_ratio = ASYMPTOMATIC_INFECTION_RATIO if self.is_asymptomatic else 0.0 # draw a beta with the distribution in documents
        self.viral_load_plateau_height, self.viral_load_plateau_start, self.viral_load_plateau_end, self.viral_load_recovered = _sample_viral_load_piecewise(rng, age=age)
        self.infectiousness_onset_days = self.rng.normal(loc=INFECTIOUSNESS_ONSET_DAYS_AVG, scale=INFECTIOUSNESS_ONSET_DAYS_STD)
        self.incubation_days = self.infectiousness_onset_days + self.viral_load_plateau_start + self.rng.normal(loc=SYMPTOM_ONSET_WRT_VIRAL_LOAD_PEAK_AVG, scale=SYMPTOM_ONSET_WRT_VIRAL_LOAD_PEAK_STD)
        self.recovery_days = self.infectiousness_onset_days + self.viral_load_recovered
        self.test_result, self.test_type = None, None

        # Indicates whether this person will show severe signs of illness.
        self.infection_timestamp = infection_timestamp
        self.cold_timestamp = self.env.timestamp if self.rng.random() < P_COLD else None
        self.flu_timestamp = self.env.timestamp if self.rng.random() < P_FLU else None # different from asymptomatic
        self.recovered_timestamp = datetime.datetime.min
        self.is_immune = False # different from asymptomatic
        self.can_get_really_sick = self.rng.random() >= 0.8 + (age/100)
        self.can_get_extremely_sick = self.can_get_really_sick and self.rng.random() >= 0.7 # &severe; 30% of severe cases need ICU
        self.never_recovers = self.rng.random() <= P_NEVER_RECOVERS[min(math.floor(self.age/10),8)]
        self.obs_hospitalized = False
        self.obs_in_icu = False

        # counters and memory
        self.r0 = []
        self.has_logged_symptoms = False
        self.has_logged_test = False
        self.last_state = self.state
        self.n_infectious_contacts = 0
        self.last_date_to_check_symptoms = self.env.timestamp.date()

        # symptoms
        self.symptom_start_time = None
        self.all_cold_symptoms = _get_cold_symptoms_v2(self.age, self.rng, self.carefulness, self.preexisting_conditions, self.can_get_really_sick, self.can_get_extremely_sick)
        self.all_flu_symptoms = _get_flu_symptoms_v2(self.age, self.rng, self.carefulness, self.preexisting_conditions, self.can_get_really_sick, self.can_get_extremely_sick)
        self.all_covid_symptoms = _get_covid_symptoms(self.viral_load_plateau_start, self.viral_load_plateau_end,
                                        self.viral_load_recovered, age=self.age, incubation_days=self.incubation_days,
                                                          really_sick=self.can_get_really_sick, extremely_sick=self.can_get_extremely_sick,
                          rng=self.rng, preexisting_conditions=self.preexisting_conditions)
        self.all_symptoms, self.cold_symptoms, self.flu_symptoms, self.covid_symptoms = [], [], [], []

        # habits
        self.avg_shopping_time = _draw_random_discreet_gaussian(AVG_SHOP_TIME_MINUTES, SCALE_SHOP_TIME_MINUTES, self.rng)
        self.scale_shopping_time = _draw_random_discreet_gaussian(AVG_SCALE_SHOP_TIME_MINUTES,
                                                                  SCALE_SCALE_SHOP_TIME_MINUTES, self.rng)

        self.avg_exercise_time = _draw_random_discreet_gaussian(AVG_EXERCISE_MINUTES, SCALE_EXERCISE_MINUTES, self.rng)
        self.scale_exercise_time = _draw_random_discreet_gaussian(AVG_SCALE_EXERCISE_MINUTES,
                                                                  SCALE_SCALE_EXERCISE_MINUTES, self.rng)

        self.avg_working_minutes = _draw_random_discreet_gaussian(AVG_WORKING_MINUTES, SCALE_WORKING_MINUTES, self.rng)
        self.scale_working_minutes = _draw_random_discreet_gaussian(AVG_SCALE_WORKING_MINUTES, SCALE_SCALE_WORKING_MINUTES, self.rng)

        self.avg_hospital_hours = _draw_random_discreet_gaussian(AVG_HOSPITAL_HOURS, SCALE_HOSPITAL_HOURS, self.rng)
        self.scale_hospital_hours = _draw_random_discreet_gaussian(AVG_SCALE_HOSPITAL_HOURS, SCALE_SCALE_HOSPITAL_HOURS, self.rng)

        self.avg_misc_time = _draw_random_discreet_gaussian(AVG_MISC_MINUTES, SCALE_MISC_MINUTES, self.rng)
        self.scale_misc_time = _draw_random_discreet_gaussian(AVG_SCALE_MISC_MINUTES, SCALE_SCALE_MISC_MINUTES, self.rng)

        #getting the number of shopping days and hours from a distribution
        self.number_of_shopping_days = _draw_random_discreet_gaussian(AVG_NUM_SHOPPING_DAYS, SCALE_NUM_SHOPPING_DAYS, self.rng)
        self.number_of_shopping_hours = _draw_random_discreet_gaussian(AVG_NUM_SHOPPING_HOURS, SCALE_NUM_SHOPPING_HOURS, self.rng)

        #getting the number of exercise days and hours from a distribution
        self.number_of_exercise_days = _draw_random_discreet_gaussian(AVG_NUM_EXERCISE_DAYS, SCALE_NUM_EXERCISE_DAYS, self.rng)
        self.number_of_exercise_hours = _draw_random_discreet_gaussian(AVG_NUM_EXERCISE_HOURS, SCALE_NUM_EXERCISE_HOURS, self.rng)

        #Multiple shopping days and hours
        self.shopping_days = self.rng.choice(range(7), self.number_of_shopping_days)
        self.shopping_hours = self.rng.choice(range(7, 20), self.number_of_shopping_hours)

        #Multiple exercise days and hours
        self.exercise_days = self.rng.choice(range(7), self.number_of_exercise_days)
        self.exercise_hours = self.rng.choice(range(7, 20), self.number_of_exercise_hours)

        #Limiting the number of hours spent shopping per week
        self.max_shop_per_week = _draw_random_discreet_gaussian(AVG_MAX_NUM_SHOP_PER_WEEK, SCALE_MAX_NUM_SHOP_PER_WEEK, self.rng)
        self.count_shop=0

        # Limiting the number of hours spent exercising per week
        self.max_exercise_per_week = _draw_random_discreet_gaussian(AVG_MAX_NUM_EXERCISE_PER_WEEK, SCALE_MAX_NUM_EXERCISE_PER_WEEK, self.rng)
        self.count_exercise=0

        self.work_start_hour = self.rng.choice(range(7, 12), 3)
    def __init__(self, env, name, age, rng, infection_timestamp, household, workplace, rho=0.3, gamma=0.21, symptoms=None,
                 test_results=None):
        self.env = env
        self.events = []
        self.name = name
        self.age = age
        self.rng = rng

        # probability of being asymptomatic is basically 50%, but a bit less if you're older
        # and a bit more if you're younger
        self.is_asymptomatic = self.rng.rand() > (BASELINE_P_ASYMPTOMATIC - (self.age - 50) * 0.5) / 100
        self.asymptomatic_infection_ratio = 0.0
        if self.is_asymptomatic:
            self.asymptomatic_infection_ratio = ASYMPTOMATIC_INFECTION_RATIO # draw a beta with the distribution in documents
        self.incubation_days = _draw_random_discreet_gaussian(AVG_INCUBATION_DAYS, SCALE_INCUBATION_DAYS, self.rng)
        self.recovery_days = _draw_random_discreet_gaussian(AVG_RECOVERY_DAYS, SCALE_RECOVERY_DAYS, self.rng) # make it IQR &recovery

        self.household = household
        self.workplace = workplace
        self.location = household
        self.rho = rho
        self.gamma = gamma

        self.visits = Visits()
        self.travelled_recently = self.rng.rand() > 0.9

        # &carefullness
        if self.rng.rand() < P_CAREFUL_PERSON:
            self.carefullness = round(self.rng.normal(75, 10))
        else:
            self.carefullness = round(self.rng.normal(35, 10))

        age_modifier = 1
        if self.age > 40 or self.age < 12:
            age_modifier = 2
        self.has_cold = self.rng.rand() < P_COLD * age_modifier
        self.has_flu = self.rng.rand() < P_FLU * age_modifier
        self.has_app = self.rng.rand() < (P_HAS_APP / age_modifier) + (self.carefullness / 2)

        # Indicates whether this person will show severe signs of illness.
        self.infection_timestamp = infection_timestamp
        self.recovered_timestamp = datetime.datetime.min
        self.really_sick = self.is_exposed and self.rng.random() >= 0.9
        self.never_recovers = self.rng.random() >= 0.99

        # counters and memory
        self.r0 = []
        self.has_logged_symptoms = False
        self.has_logged_test = False
        self.n_infectious_contacts = 0
        self.last_state = self.state

        # habits
        self.avg_shopping_time = _draw_random_discreet_gaussian(AVG_SHOP_TIME_MINUTES, SCALE_SHOP_TIME_MINUTES, self.rng)
        self.scale_shopping_time = _draw_random_discreet_gaussian(AVG_SCALE_SHOP_TIME_MINUTES,
                                                                  SCALE_SCALE_SHOP_TIME_MINUTES, self.rng)

        self.avg_exercise_time = _draw_random_discreet_gaussian(AVG_EXERCISE_MINUTES, SCALE_EXERCISE_MINUTES, self.rng)
        self.scale_exercise_time = _draw_random_discreet_gaussian(AVG_SCALE_EXERCISE_MINUTES,
                                                                  SCALE_SCALE_EXERCISE_MINUTES, self.rng)

        self.avg_working_hours = _draw_random_discreet_gaussian(AVG_WORKING_MINUTES, SCALE_WORKING_MINUTES, self.rng)
        self.scale_working_hours = _draw_random_discreet_gaussian(AVG_SCALE_WORKING_MINUTES, SCALE_SCALE_WORKING_MINUTES, self.rng)

        self.avg_misc_time = _draw_random_discreet_gaussian(AVG_MISC_MINUTES, SCALE_MISC_MINUTES, self.rng)
        self.scale_misc_time = _draw_random_discreet_gaussian(AVG_SCALE_MISC_MINUTES, SCALE_SCALE_MISC_MINUTES, self.rng)

        #getting the number of shopping days and hours from a distribution
        self.number_of_shopping_days = _draw_random_discreet_gaussian(AVG_NUM_SHOPPING_DAYS, SCALE_NUM_SHOPPING_DAYS, self.rng)
        self.number_of_shopping_hours = _draw_random_discreet_gaussian(AVG_NUM_SHOPPING_HOURS, SCALE_NUM_SHOPPING_HOURS, self.rng)

        #getting the number of exercise days and hours from a distribution
        self.number_of_exercise_days = _draw_random_discreet_gaussian(AVG_NUM_EXERCISE_DAYS, SCALE_NUM_EXERCISE_DAYS, self.rng)
        self.number_of_exercise_hours = _draw_random_discreet_gaussian(AVG_NUM_EXERCISE_HOURS, SCALE_NUM_EXERCISE_HOURS, self.rng)

        #Multiple shopping days and hours
        self.shopping_days = self.rng.choice(range(7), self.number_of_shopping_days)
        self.shopping_hours = self.rng.choice(range(7, 20), self.number_of_shopping_hours)

        #Multiple exercise days and hours
        self.exercise_days = self.rng.choice(range(7), self.number_of_exercise_days)
        self.exercise_hours = self.rng.choice(range(7, 20), self.number_of_exercise_hours)

        #Limiting the number of hours spent shopping per week
        self.max_shop_per_week = _draw_random_discreet_gaussian(AVG_MAX_NUM_SHOP_PER_WEEK, SCALE_MAX_NUM_SHOP_PER_WEEK, self.rng)
        self.count_shop=0

        #Limiting the number of hours spent exercising per week
        self.max_exercise_per_week = _draw_random_discreet_gaussian(AVG_MAX_NUM_EXERCISE_PER_WEEK, SCALE_MAX_NUM_EXERCISE_PER_WEEK, self.rng)
        self.count_exercise=0

        self.work_start_hour = self.rng.choice(range(7, 12))
Esempio n. 12
0
def run_simu(n_stores=None,
             n_people=None,
             n_parks=None,
             n_misc=None,
             init_percent_sick=0,
             store_capacity=30,
             misc_capacity=30,
             start_time=datetime.datetime(2020, 2, 28, 0, 0),
             simulation_days=10,
             outfile=None,
             print_progress=False,
             seed=0,
             Human=None):

    if Human is None:
        from simulator import Human

    rng = np.random.RandomState(seed)
    env = Env(start_time)
    city_limit = ((0, 1000), (0, 1000))
    total_area = (city_limit[0][1] - city_limit[0][0]) * (city_limit[1][1] -
                                                          city_limit[1][0])
    area_dict = {
        'store':
        _get_random_area('store', n_stores, total_area, rng),
        'park':
        _get_random_area('park', n_parks, total_area, rng),
        'misc':
        _get_random_area('misc', n_misc, total_area, rng),
        'household':
        _get_random_area('household', int(n_people / 2), total_area, rng),
        'workplace':
        _get_random_area('workplace', int(n_people / 30), total_area, rng)
    }

    stores = [
        Location(env,
                 rng,
                 capacity=_draw_random_discreet_gaussian(
                     store_capacity, int(0.5 * store_capacity), rng),
                 cont_prob=0.6,
                 location_type='store',
                 name=f'store{i}',
                 area=area_dict['store'][i],
                 lat=rng.randint(*city_limit[0]),
                 lon=rng.randint(*city_limit[1]),
                 surface_prob=[0.1, 0.1, 0.3, 0.2, 0.3])
        for i in range(n_stores)
    ]

    parks = [
        Location(env,
                 rng,
                 cont_prob=0.05,
                 name=f'park{i}',
                 area=area_dict['park'][i],
                 location_type='park',
                 lat=rng.randint(*city_limit[0]),
                 lon=rng.randint(*city_limit[1]),
                 surface_prob=[0.7, 0.05, 0.05, 0.1, 0.1])
        for i in range(n_parks)
    ]
    households = [
        Location(env,
                 rng,
                 cont_prob=1,
                 name=f'household{i}',
                 location_type='household',
                 area=area_dict['household'][i],
                 lat=rng.randint(*city_limit[0]),
                 lon=rng.randint(*city_limit[1]),
                 surface_prob=[0.05, 0.05, 0.05, 0.05, 0.8])
        for i in range(int(n_people / 2))
    ]
    workplaces = [
        Location(env,
                 rng,
                 cont_prob=0.3,
                 name=f'workplace{i}',
                 location_type='workplace',
                 area=area_dict['workplace'][i],
                 lat=rng.randint(*city_limit[0]),
                 lon=rng.randint(*city_limit[1]),
                 surface_prob=[0.1, 0.1, 0.3, 0.2, 0.3])
        for i in range(int(n_people / 30))
    ]
    miscs = [
        Location(env,
                 rng,
                 cont_prob=1,
                 capacity=_draw_random_discreet_gaussian(
                     misc_capacity, int(0.5 * misc_capacity), rng),
                 name=f'misc{i}',
                 area=area_dict['misc'][i],
                 location_type='misc',
                 lat=rng.randint(*city_limit[0]),
                 lon=rng.randint(*city_limit[1]),
                 surface_prob=[0.1, 0.1, 0.3, 0.2, 0.3]) for i in range(n_misc)
    ]

    humans = [
        Human(env=env,
              name=i,
              rng=rng,
              age=_get_random_age(rng),
              infection_timestamp=start_time
              if i < n_people * init_percent_sick else None,
              household=rng.choice(households),
              workplace=rng.choice(workplaces)) for i in range(n_people)
    ]

    city = City(stores=stores, parks=parks, humans=humans, miscs=miscs)
    monitors = [EventMonitor(f=120), SEIRMonitor(f=1440)]

    extra_info = {}
    extra_info['init_percent_sick'] = init_percent_sick
    extra_info['initial_states'] = [
        'infected' if i < n_people * init_percent_sick else 'not_infected'
        for i in range(n_people)
    ]
    extra_info['recovery_probs'] = [1.0 / h.recovery_days for h in humans]
    import json
    with open('extra_info.json', 'w') as f:
        json.dump(extra_info, f)

    # run the simulation
    if print_progress:
        monitors.append(TimeMonitor(60))

    for human in humans:
        env.process(human.run(city=city))

    for m in monitors:
        env.process(m.run(env, city=city))
    env.run(until=simulation_days * 24 * 60 / TICK_MINUTE)
    return monitors
Esempio n. 13
0
 def exercise(self, city):
     self.action = Human.actions['exercise']
     park = self._select_location(location_type="park", city=city)
     t = _draw_random_discreet_gaussian(self.avg_shopping_time, self.scale_shopping_time)
     yield self.env.process(self.at(park, t))
Esempio n. 14
0
 def go_to_work(self):
     t = _draw_random_discreet_gaussian(self.avg_working_hours, self.scale_working_hours)
     yield self.env.process(self.at(self.workplace, t))
Esempio n. 15
0
    def __init__(self, env, name, infection_timestamp, household, workplace, age=35, rho=0.3, gamma=0.21, symptoms=None,
                 test_results=None):
        self.env = env
        self.events = []
        self.name = name
        self.age = _get_random_age()

        # probability of being asymptomatic is basically 50%, but a bit less if you're older
        # and a bit more if you're younger
        self.asymptomatic = np.random.rand() > (BASELINE_P_ASYMPTOMATIC - (self.age - 50) * 0.5) / 100
        self.incubation_days = _draw_random_discreet_gaussian(AVERAGE_INCUBATION_DAYS, SCALE_INCUBATION_DAYS)

        self.household = household
        self.workplace = workplace
        self.location = household
        self.rho = rho
        self.gamma = gamma

        self.action = Human.actions['at_home']
        self.visits = Visits()
        self.travelled_recently = np.random.rand() > 0.9

        # &carefullness
        if np.random.rand() < P_CAREFUL_PERSON:
            self.carefullness = round(np.random.normal(75, 10))
        else:
            self.carefullness = round(np.random.normal(35, 10))

        age_modifier = 1
        if self.age > 40 or self.age < 12:
            age_modifier = 2
        self.has_cold = np.random.rand() < P_COLD * age_modifier
        self.has_flu = np.random.rand() < P_FLU * age_modifier
        self.has_app = np.random.rand() < (P_HAS_APP / age_modifier) + (self.carefullness / 2)

        # Indicates whether this person will show severe signs of illness.
        self.infection_timestamp = infection_timestamp
        self.really_sick = self.is_sick and random.random() >= 0.9
        self.never_recovers = random.random() >= 0.99

        # habits
        self.avg_shopping_time = _draw_random_discreet_gaussian(AVERAGE_SHOP_TIME_MINUTES, SCALE_SHOP_TIME_MINUTES)
        self.scale_shopping_time = _draw_random_discreet_gaussian(AVG_SCALE_SHOP_TIME_MINUTES,
                                                                  SCALE_SCALE_SHOP_TIME_MINUTES)

        self.avg_exercise_time = _draw_random_discreet_gaussian(AVG_EXERCISE_MINUTES, SCALE_EXERCISE_MINUTES)
        self.scale_exercise_time = _draw_random_discreet_gaussian(AVG_SCALE_EXERCISE_MINUTES,
                                                                  SCALE_SCALE_EXERCISE_MINUTES)

        self.avg_working_hours = _draw_random_discreet_gaussian(AVG_WORKING_HOURS, SCALE_WORKING_HOURS)
        self.scale_working_hours = _draw_random_discreet_gaussian(AVG_SCALE_WORKING_HOURS, SCALE_SCALE_WORKING_HOURS)

        self.avg_misc_time = _draw_random_discreet_gaussian(AVG_MISC_MINUTES, SCALE_MISC_MINUTES)
        self.scale_misc_time = _draw_random_discreet_gaussian(AVG_SCALE_MISC_MINUTES, SCALE_SCALE_MISC_MINUTES)

        # TODO: multiple possible days and times & limit these activities in a week
        self.shopping_days = np.random.choice(range(7))
        self.shopping_hours = np.random.choice(range(7, 20))

        self.exercise_days = np.random.choice(range(7))
        self.exercise_hours = np.random.choice(range(7, 20))

        self.work_start_hour = np.random.choice(range(7, 12))
    def __init__(self, env, name, age, rng, infection_timestamp, household, workplace, profession, rho=0.3, gamma=0.21, symptoms=[],
                 test_results=None, sim_days=0):
        self.env = env
        self._events = []
        self.name = f"human:{name}"
        self.rng = rng
        self.profession = profession
        self.death = False

        self.age = age
        self.sex = _get_random_sex(self.rng)
        self.preexisting_conditions = _get_preexisting_conditions(self.age, self.sex, self.rng)

        self.assign_household(household)
        self.workplace = workplace
        self.rho = rho
        self.gamma = gamma
        self.rest_at_home = False # to track mobility due to symptoms

        self.visits = Visits()
        self.travelled_recently = self.rng.rand() > 0.9

        # &carefulness
        if self.rng.rand() < P_CAREFUL_PERSON:
            self.carefulness = (round(self.rng.normal(55, 10)) + self.age/2) / 100
        else:
            self.carefulness = (round(self.rng.normal(25, 10)) + self.age/2) / 100
        self.mask_wearing = _get_mask_wearing(self.carefulness, sim_days, self.rng)

        age_modifier = 1
        if self.age > 40 or self.age < 12:
            age_modifier = 2
        self.has_cold = self.rng.rand() < P_COLD * age_modifier
        self.has_flu = self.rng.rand() < P_FLU * age_modifier
        self.has_app = self.rng.rand() < (P_HAS_APP / age_modifier) + (self.carefulness / 2)
        self.incubation_days = _draw_random_discreet_gaussian(AVG_INCUBATION_DAYS, SCALE_INCUBATION_DAYS, self.rng)

        # Indicates whether this person will show severe signs of illness.
        self.infection_timestamp = infection_timestamp
        self.is_immune = False
        self.recovered_timestamp = datetime.datetime.min
        self.gets_really_sick = self.rng.random() >= 0.8 + (age/100)
        self.gets_extremely_sick = self.gets_really_sick and self.rng.random() >= 0.7 # &severe; 30% of severe cases need ICU
        self.never_recovers = self.rng.random() <= P_NEVER_RECOVERS[min(math.floor(self.age/10),8)]
        self.obs_hospitalized = False
        self.obs_in_icu = False

        # &symptoms, &viral-load
        # probability of being asymptomatic is basically 50%, but a bit less if you're older
        # and a bit more if you're younger
        self.is_asymptomatic = self.rng.rand() > (BASELINE_P_ASYMPTOMATIC - (self.age - 50) * 0.5) / 100
        self.asymptomatic_infection_ratio = ASYMPTOMATIC_INFECTION_RATIO if self.is_asymptomatic else 0.0 # draw a beta with the distribution in documents

        self.recovery_days = _draw_random_discreet_gaussian(AVG_RECOVERY_DAYS, SCALE_RECOVERY_DAYS, self.rng) # make it IQR &recovery
        self.viral_load_plateau_height, self.viral_load_plateau_start, self.viral_load_plateau_end, self.viral_load_recovered = _sample_viral_load_piecewise(rng, age=age)
        self.all_symptoms = _get_all_symptoms(
                          np.ndarray.item(self.viral_load_plateau_start), np.ndarray.item(self.viral_load_plateau_end),
                          np.ndarray.item(self.viral_load_recovered), age=self.age, incubation_days=self.incubation_days,
                                                          really_sick=self.gets_really_sick, extremely_sick=self.gets_extremely_sick,
                          rng=self.rng, preexisting_conditions=self.preexisting_conditions)
        self.all_reported_symptoms = _reported_symptoms(self.all_symptoms, self.rng, self.carefulness)

        # counters and memory
        self.r0 = []
        self.has_logged_symptoms = self.has_app and any(self.symptoms) and rng.rand() < 0.5
        self.has_logged_test = self.has_app and self.test_results and rng.rand() < 0.5
        self.has_logged_info = self.has_app and rng.rand() < 0.5
        self.last_state = self.state
        self.n_infectious_contacts = 0
        self.symptom_start_time = None

        self.obs_age = self.age if self.has_app and self.has_logged_info else None
        self.obs_sex = self.sex if self.has_app and self.has_logged_info else None
        self.obs_preexisting_conditions = self.preexisting_conditions if self.has_app and self.has_logged_info else None
        self.obs_symptoms = self.symptoms if self.has_logged_symptoms else None

        # habits
        self.avg_shopping_time = _draw_random_discreet_gaussian(AVG_SHOP_TIME_MINUTES, SCALE_SHOP_TIME_MINUTES, self.rng)
        self.scale_shopping_time = _draw_random_discreet_gaussian(AVG_SCALE_SHOP_TIME_MINUTES,
                                                                  SCALE_SCALE_SHOP_TIME_MINUTES, self.rng)

        self.avg_exercise_time = _draw_random_discreet_gaussian(AVG_EXERCISE_MINUTES, SCALE_EXERCISE_MINUTES, self.rng)
        self.scale_exercise_time = _draw_random_discreet_gaussian(AVG_SCALE_EXERCISE_MINUTES,
                                                                  SCALE_SCALE_EXERCISE_MINUTES, self.rng)

        self.avg_working_minutes = _draw_random_discreet_gaussian(AVG_WORKING_MINUTES, SCALE_WORKING_MINUTES, self.rng)
        self.scale_working_minutes = _draw_random_discreet_gaussian(AVG_SCALE_WORKING_MINUTES, SCALE_SCALE_WORKING_MINUTES, self.rng)

        self.avg_hospital_hours = _draw_random_discreet_gaussian(AVG_HOSPITAL_HOURS, SCALE_HOSPITAL_HOURS, self.rng)
        self.scale_hospital_hours = _draw_random_discreet_gaussian(AVG_SCALE_HOSPITAL_HOURS, SCALE_SCALE_HOSPITAL_HOURS, self.rng)

        self.avg_misc_time = _draw_random_discreet_gaussian(AVG_MISC_MINUTES, SCALE_MISC_MINUTES, self.rng)
        self.scale_misc_time = _draw_random_discreet_gaussian(AVG_SCALE_MISC_MINUTES, SCALE_SCALE_MISC_MINUTES, self.rng)

        #getting the number of shopping days and hours from a distribution
        self.number_of_shopping_days = _draw_random_discreet_gaussian(AVG_NUM_SHOPPING_DAYS, SCALE_NUM_SHOPPING_DAYS, self.rng)
        self.number_of_shopping_hours = _draw_random_discreet_gaussian(AVG_NUM_SHOPPING_HOURS, SCALE_NUM_SHOPPING_HOURS, self.rng)

        #getting the number of exercise days and hours from a distribution
        self.number_of_exercise_days = _draw_random_discreet_gaussian(AVG_NUM_EXERCISE_DAYS, SCALE_NUM_EXERCISE_DAYS, self.rng)
        self.number_of_exercise_hours = _draw_random_discreet_gaussian(AVG_NUM_EXERCISE_HOURS, SCALE_NUM_EXERCISE_HOURS, self.rng)

        #Multiple shopping days and hours
        self.shopping_days = self.rng.choice(range(7), self.number_of_shopping_days)
        self.shopping_hours = self.rng.choice(range(7, 20), self.number_of_shopping_hours)

        #Multiple exercise days and hours
        self.exercise_days = self.rng.choice(range(7), self.number_of_exercise_days)
        self.exercise_hours = self.rng.choice(range(7, 20), self.number_of_exercise_hours)

        #Limiting the number of hours spent shopping per week
        self.max_shop_per_week = _draw_random_discreet_gaussian(AVG_MAX_NUM_SHOP_PER_WEEK, SCALE_MAX_NUM_SHOP_PER_WEEK, self.rng)
        self.count_shop=0

        #Limiting the number of hours spent exercising per week
        self.max_exercise_per_week = _draw_random_discreet_gaussian(AVG_MAX_NUM_EXERCISE_PER_WEEK, SCALE_MAX_NUM_EXERCISE_PER_WEEK, self.rng)
        self.count_exercise=0

        self.work_start_hour = self.rng.choice(range(7, 12), 3)