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 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 __init__(self, env, name, age, rng, infection_timestamp, household, workplace, rho=0.3, gamma=0.21, symptoms=[], test_results=None): self.env = env self.events = [] self.name = name self.rng = rng self.age = _get_random_age(self.rng) self.sex = _get_random_sex(self.rng) self.preexisting_conditions = _get_preexisting_conditions( self.age, self.sex, self.rng) 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(55, 10)) + self.age / 2 else: self.carefullness = round(self.rng.normal(25, 10)) + self.age / 2 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) 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.recovered_timestamp = datetime.datetime.min self.really_sick = self.is_exposed and self.rng.random() >= 0.9 self.extremely_sick = self.really_sick and self.rng.random( ) >= 0.7 # &severe; 30% of severe cases need ICU self.never_recovers = self.rng.random() >= 0.99 # &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 = 0.0 if self.is_asymptomatic: self.asymptomatic_infection_ratio = ASYMPTOMATIC_INFECTION_RATIO # 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_array = _get_all_symptoms_array( 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.really_sick, extremely_sick=self.extremely_sick, rng=self.rng, preexisting_conditions=self.preexisting_conditions) # 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))