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))
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}')
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))
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))
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))
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))
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))
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
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}')
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))
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
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))
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))
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)