def disease_evolution(self): if self.is_infected(): self.infection_days_count += 1 if self.disease_severity == DiseaseSeverity.ASYMPTOMATIC: if self.infection_days_count >= self.infection_incubation: self.disease_severity = DiseaseSeverity.LOW self.covid_model.global_count.asymptomatic_count -= 1 self.covid_model.global_count.symptomatic_count += 1 elif self.disease_severity == DiseaseSeverity.LOW: if flip_coin(self.moderate_severity_prob): self.disease_severity = DiseaseSeverity.MODERATE self.covid_model.global_count.moderate_severity_count += 1 if not self.covid_model.reached_hospitalization_limit(): self.covid_model.global_count.total_hospitalized += 1 self.hospitalized = True elif self.disease_severity == DiseaseSeverity.MODERATE: if flip_coin(self.high_severity_prob): self.disease_severity = DiseaseSeverity.HIGH self.covid_model.global_count.moderate_severity_count -= 1 self.covid_model.global_count.high_severity_count += 1 if not self.hospitalized or self.death_mark: self.die() elif self.disease_severity == DiseaseSeverity.HIGH: if self.death_mark: self.die() if self.disease_severity != DiseaseSeverity.DEATH: if self.infection_days_count > self.infection_duration: self.recover()
def check_spreading(self, h1, h2): if h1.is_contagious() and not h2.is_infected(): if flip_coin(self.get_parameter('contagion_probability')): me = self.get_parameter('mask_efficacy') if not h1.is_wearing_mask() or (h1.is_wearing_mask() and not flip_coin(me)): h2.infect()
def invite_friends_to_restaurant(self): shape = self.properties.risk_tolerance * get_parameters().get('typical_restaurant_event_size') event_size = np.random.gamma(shape, 1) logger().debug(f"Restaurant event size of {self} is {event_size}") accepted = [self] for human in self.tribe[TribeSelector.FRIEND]: if human != self and human.personal_decision(Dilemma.ACCEPT_FRIEND_INVITATION_TO_RESTAURANT): accepted.append(human) if len(accepted) >= event_size: break if len(accepted) == 1: return outdoor = flip_coin(linear_rescale(self.properties.risk_tolerance, 0, 0.5)) if flip_coin(linear_rescale(self.work_info.base_income, 0, 1 / 5)): restaurant_type = RestaurantType.FANCY else: restaurant_type = RestaurantType.FAST_FOOD event = self.work_district.get_available_restaurant(len(accepted), outdoor, restaurant_type) if event is not None and not outdoor: event = self.work_district.get_available_restaurant(len(accepted), True, restaurant_type) if event is None: return event.available -= len(accepted) for human in accepted: human.social_event = (self, event)
def check_spreading(self, h1, h2): #print(f"check-spreading in location {self.unique_id} of types {type(self).mro()}") if h1.is_infected(): logger().debug(f"Check to see if {h1} can infect {h2} in {self}") if h1.is_contagious() and not h2.is_infected(): logger().debug(f"contagion_probability = {self.get_parameter('contagion_probability')}") if flip_coin(self.get_parameter('contagion_probability')): me = self.get_parameter('mask_efficacy') if not h1.is_wearing_mask() or (h1.is_wearing_mask() and not flip_coin(me)): if h2.strid not in self.covid_model.global_count.infection_info: self.covid_model.global_count.infection_info[h2.strid] = self logger().debug(f"Infection succeeded - {h1} has infected {h2} in {self} with contagion " f"probability {self.get_parameter('contagion_probability')}") h1.count_infected_humans += 1 h2.infect() else: if h1.is_wearing_mask(): logger().debug(f"Infection failed - infector {h1} wearing mask") if h2.is_wearing_mask(): logger().debug(f"Infection failed - infectee {h2} wearing mask") else: logger().debug(f"Infection failed - {self} didn't pass contagion_probability check with contagion " f"probability {self.get_parameter('contagion_probability')}") else: if not h1.is_contagious(): logger().debug(f"Infection failed - infector {h1} is not contagious") if h2.is_infected(): logger().debug(f"Infection failed - infectee {h2} is already infected")
def factory(covid_model, forced_age): # https://docs.google.com/document/d/14C4utmOi4WiBe7hOVtRt-NgMLh37pr_ntou-xUFAOjk/edit #moderate_severity_probs = [ # 0, # normal_ci(0.000243, 0.000832, 13), # normal_ci(0.00622, 0.0213, 50), # normal_ci(0.0204, 0.07, 437), # normal_ci(0.0253, 0.0868, 733), # normal_ci(0.0486, 0.167, 743), # normal_ci(0.0701, 0.24, 790), # normal_ci(0.0987, 0.338, 560), # normal_ci(0.11, 0.376, 263), # normal_ci(0.11, 0.376, 76) #] moderate_severity_probs = [0.05, 0.10, 0.20, 0.30, 0.40, 0.60, 0.80, 0.99, 0.99, 0.99] high_severity_probs = [0.05, 0.10, 0.20, 0.30, 0.40, 0.60, 0.80, 0.99, 0.99, 0.99] death_probs = [0] * 10 death_probs[2] = 0.003 death_probs[0] = death_probs[2] / 9 death_probs[1] = death_probs[2] / 16 death_probs[3] = death_probs[2] * 4 death_probs[4] = death_probs[2] * 10 death_probs[5] = death_probs[2] * 30 death_probs[6] = death_probs[2] * 90 death_probs[7] = death_probs[2] * 220 death_probs[8] = death_probs[2] * 630 death_probs[9] = death_probs[2] * 1000 if forced_age is None: age = int(np.random.beta(2, 5, 1) * 100) else: age = forced_age index = age // 10 msp = moderate_severity_probs[index] hsp = high_severity_probs[index] mfd = flip_coin(death_probs[index]) if age <= 1: human = Infant(covid_model, age, msp, hsp, mfd) elif age <= 4: human = Toddler(covid_model, age, msp, hsp, mfd) elif age <= 18: human = K12Student(covid_model, age, msp, hsp, mfd) elif age <= 64: human = Adult(covid_model, age, msp, hsp, mfd) else: human = Elder(covid_model, age, msp, hsp, mfd) human.strid = f"human_{Human.count}" Human.count += 1 covid_model.global_count.non_infected_count += 1 if human.immune: covid_model.global_count.immune_count += 1 else: covid_model.global_count.susceptible_count += 1 if flip_coin(get_parameters().get('initial_infection_rate')): human.infect() return human
def disease_evolution(self): # https://media.tghn.org/medialibrary/2020/06/ISARIC_Data_Platform_COVID-19_Report_8JUN20.pdf # https://www.ecdc.europa.eu/en/covid-19/latest-evidence if self.is_infected(): self.infection_days_count += 1 if self.disease_severity == DiseaseSeverity.ASYMPTOMATIC: if self.infection_days_count >= self.infection_incubation: logger().info(f"{self} evolved from ASYMPTOMATIC to LOW") self.disease_severity = DiseaseSeverity.LOW self.covid_model.global_count.asymptomatic_count -= 1 self.covid_model.global_count.symptomatic_count += 1 day = self.covid_model.global_count.day_count if day not in self.covid_model.global_count.new_symptomatic_count: self.covid_model.global_count.new_symptomatic_count[day] = 0 self.covid_model.global_count.new_symptomatic_count[day] += 1 elif self.disease_severity == DiseaseSeverity.LOW: if self.infection_days_count > self.infection_incubation + self.mild_duration: # By the end of this period, either the patient is already with antibodies at # a level sufficient to cure the disease or the symptoms will get worse and he/she # will require hospitalization if self.death_mark or flip_coin(self.moderate_severity_prob): # MODERATE cases requires hospitalization logger().info(f"{self} evolved from LOW to MODERATE") self.disease_severity = DiseaseSeverity.MODERATE self.covid_model.global_count.moderate_severity_count += 1 if not self.covid_model.reached_hospitalization_limit(): self.hospitalize() else: logger().info(f"{self} couldn't be hospitalized (hospitalization limit reached)") else: self.recover() elif self.disease_severity == DiseaseSeverity.MODERATE: if self.infection_days_count >= self.infection_incubation + self.mild_duration + self.hospitalization_duration: if self.death_mark or flip_coin(self.high_severity_prob): logger().info(f"{self} evolved from MODERATE to HIGH") self.disease_severity = DiseaseSeverity.HIGH self.covid_model.global_count.moderate_severity_count -= 1 self.covid_model.global_count.high_severity_count += 1 # If the disease evolves to HIGH and the person could not # be accommodated in a hospital, he/she will die. if not self.hospitalized or self.covid_model.reached_icu_limit(): self.die() else: shape = get_parameters().get('icu_period_duration_shape') scale = get_parameters().get('icu_period_duration_scale') self.icu_duration = np.random.gamma(shape, scale) self.has_been_icu = True logger().debug(f"ICU duration of {self} is {self.icu_duration}") else: self.recover() elif self.disease_severity == DiseaseSeverity.HIGH: if self.infection_days_count >= self.infection_incubation + self.mild_duration +\ self.hospitalization_duration + self.icu_duration: if self.death_mark: self.die() else: self.recover()
def parameter_changed(self): self.mask_user = flip_coin(get_parameters().get('mask_user_rate')) self.isolation_cheater = flip_coin( get_parameters().get('isolation_cheater_rate')) self.immune = flip_coin(get_parameters().get('imune_rate')) if flip_coin(get_parameters().get('weareable_adoption_rate')): self.early_symptom_detection = 1 # number of days else: self.early_symptom_detection = 0
def parameter_changed(self): # When a parameter is changed in the middle of simulation # the user may want to reroll some human's properties self.mask_user = flip_coin(get_parameters().get('mask_user_rate')) self.immune = flip_coin(get_parameters().get('imune_rate')) if flip_coin(get_parameters().get('weareable_adoption_rate')): self.early_symptom_detection = 1 # number of days else: self.early_symptom_detection = 0 self.initialize_individual_properties()
def personal_decision(self, dilemma): if dilemma == Dilemma.GO_TO_WORK_ON_LOCKDOWN: if self.work_info.work_class == WorkClasses.RETAIL: pd = flip_coin(self.properties.risk_tolerance) hd = self.dilemma_history.herding_decision(self, dilemma, TribeSelector.FRIEND, get_parameters().get('min_behaviors_to_copy')) answer = self._standard_decision(pd, hd) logger().debug(f'{self}({self.unique_id}) had risk tolerance of {self.properties.risk_tolerance} in decision to work retail, making a personal decision of {pd} but a herding decision of {hd}') else: answer = False if answer: logger().info(f"{self} decided to get out to work on lockdown") elif dilemma == Dilemma.INVITE_FRIENDS_TO_RESTAURANT: if self.social_event is not None or self.is_symptomatic(): # don't update dilemma_history since it's a compulsory decision return False rt = self.properties.risk_tolerance if SocialPolicy.SOCIAL_DISTANCING in get_parameters().get('social_policies'): rt = rt * rt k = 3 # TODO parameter d = self.covid_model.global_count.infected_count / self.covid_model.global_count.total_population rt = rt * math.exp(-k * d) pd = flip_coin(rt) hd = self.dilemma_history.herding_decision(self,dilemma, TribeSelector.FRIEND, get_parameters().get('min_behaviors_to_copy')) answer = self._standard_decision(pd, hd) logger().debug(f'{self}({self.unique_id}) had risk tolerance of {rt} in decision to invite, making a personal decision of {pd} but a herding decision of {hd} and answer of {answer}') if answer: logger().info(f"{self} decided to invite friends to a restaurant") elif dilemma == Dilemma.ACCEPT_FRIEND_INVITATION_TO_RESTAURANT: if self.social_event is not None or self.is_symptomatic(): # don't update dilemma_history since it's a compulsory decision return False rt = self.properties.risk_tolerance if SocialPolicy.SOCIAL_DISTANCING in get_parameters().get('social_policies'): rt = rt * rt k = 3 # TODO parameter d = self.covid_model.global_count.infected_count / self.covid_model.global_count.total_population rt = rt * math.exp(-k * d) pd = flip_coin(rt) hd = self.dilemma_history.herding_decision(self,dilemma, TribeSelector.FRIEND, get_parameters().get('min_behaviors_to_copy')) answer = self._standard_decision(pd, hd) logger().debug(f'{self}({self.unique_id}) had risk tolerance of {rt} in decision to accept invite, making a personal decision of {pd} but a herding decision of {hd} and answer of {answer}') if answer: logger().info(f"{self} decided to accept an invitation to go to a restaurant") else: assert False for tribe in TribeSelector: self.dilemma_history.history[dilemma][tribe].append(answer) return answer
def spread_infection(self): if len(self.patients) > 0: logger().info(f"{self} is spreading infection patients -> workers") print(f"{self} is spreading infection patients -> workers") for worker in humans: for patient in patients: if not flip_coin(r): continue logger().debug( f"Check to see if patient {patient} can infect worker {worker} in {self}" ) print( f"Check to see if patient {patient} can infect worker {worker} in {self}" ) if not worker.is_infected(): logger().debug( f"contagion_probability = {self.get_parameter('contagion_probability')}" ) if flip_coin( self.get_parameter('contagion_probability')): if worker.strid not in self.covid_model.global_count.infection_info: self.covid_model.global_count.infection_info[ worker.strid] = self logger().debug( f"Infection succeeded - {patient} has infected {worker} in {self} with contagion " f"probability {self.get_parameter('contagion_probability')}" ) print( f"Infection succeeded - {patient} has infected {worker} in {self} with contagion " f"probability {self.get_parameter('contagion_probability')}" ) patient.count_infected_humans += 1 worker.infect(patient) else: logger().debug( f"Infection failed - {self} didn't pass contagion_probability check with contagion " f"probability {self.get_parameter('contagion_probability')}" ) print( f"Infection failed - {self} didn't pass contagion_probability check with contagion " f"probability {self.get_parameter('contagion_probability')}" ) else: logger().debug( f"Infection failed - infectee {worker} is already infected" ) print( f"Infection failed - infectee {worker} is already infected" ) super().spread_infection() # amongst workers only
def _standard_decision(self, pd, hd): if hd is None: return pd else: if flip_coin(self.properties.herding_behavior): return hd else: return pd
def infect_blob(self, blob_num): count = 0 vectors = self.blob_dict[blob_num] for v in vectors: human = self.vector_to_human[tuple(v)] if flip_coin(get_parameters().get('initial_infection_rate')): human.infect(None) count += 1 print(f"infected {count} agents in community {blob_num}")
def spread_infection(self): if len(self.humans) > 0: logger().info(f"{self} is spreading infection amongst {len(self.humans)} humans") for h1 in self.humans: for h2 in self.humans: if h1 != h2: if h1.social_event == h2.social_event or \ flip_coin(0.25 * self.get_parameter('allowed_restaurant_capacity')): self.check_spreading(h1, h2)
def step(self): super().step() # The default behavior for Humans are just stay at home all day. Disease is # evolved in EVENING_AT_HOME if self.is_dead: return if self.covid_model.current_state == SimulationState.EVENING_AT_HOME: self.disease_evolution() if not self.is_infected() and not self.is_dead and flip_coin(get_parameters().get('exogenous_infection_rate')): self.infect(None)
def factory(covid_model, forced_age): # https://docs.google.com/document/d/14C4utmOi4WiBe7hOVtRt-NgMLh37pr_ntou-xUFAOjk/edit moderate_severity_probs = [ 0, normal_cap_ci(0.000243, 0.000832, 13), normal_cap_ci(0.00622, 0.0213, 50), normal_cap_ci(0.0204, 0.07, 437), normal_cap_ci(0.0253, 0.0868, 733), normal_cap_ci(0.0486, 0.167, 743), normal_cap_ci(0.0701, 0.24, 790), normal_cap_ci(0.0987, 0.338, 560), normal_cap_ci(0.11, 0.376, 263), normal_cap_ci(0.11, 0.376, 76) ] high_severity_probs = [0.05, 0.05, 0.05, 0.05, 0.063, 0.122, 0.274, 0.432, 0.709, 0.709] death_probs = [0.002, 0.00006, 0.0003, 0.0008, 0.0015, 0.006, 0.022, 0.051, 0.093, 0.093] if forced_age is None: age = int(np.random.beta(2, 5, 1) * 100) else: age = forced_age index = age // 10 msp = moderate_severity_probs[index] hsp = high_severity_probs[index] mfd = flip_coin(death_probs[index]) if age <= 1: human = Infant(covid_model, age, msp, hsp, mfd) elif age <= 4: human = Toddler(covid_model, age, msp, hsp, mfd) elif age <= 18: human = K12Student(covid_model, age, msp, hsp, mfd) elif age <= 64: human = Adult(covid_model, age, msp, hsp, mfd) else: human = Elder(covid_model, age, msp, hsp, mfd) covid_model.global_count.non_infected_count += 1 if human.immune: covid_model.global_count.immune_count += 1 else: covid_model.global_count.susceptible_count += 1 if flip_coin(get_parameters().get('initial_infection_rate')): human.infect() return human
def personal_decision(self, dilemma): answer = False if dilemma == Dilemma.GO_TO_WORK_ON_LOCKDOWN: if self.work_info.work_class == WorkClasses.RETAIL: pd = flip_coin(self.properties.risk_tolerance) hd = self.dilemma_history.herding_decision(self,dilemma, TribeSelector.FRIEND, get_parameters().get('min_behaviors_to_copy')) answer = self._standard_decision(pd, hd) else: answer = False elif dilemma == Dilemma.INVITE_FRIENDS_TO_RESTAURANT: if self.social_event is not None or self.is_symptomatic(): # don't update dilemma_history since it's a compulsory decision return False rt = self.properties.risk_tolerance if SocialPolicy.SOCIAL_DISTANCING in get_parameters().get('social_policies'): rt = rt * rt k = 3 #TODO parameter d = self.covid_model.global_count.infected_count / self.covid_model.global_count.total_population rt = rt * math.exp(-k * d) pd = flip_coin(rt) hd = self.dilemma_history.herding_decision(self,dilemma, TribeSelector.FRIEND, get_parameters().get('min_behaviors_to_copy')) answer = self._standard_decision(pd, hd) elif dilemma == Dilemma.ACCEPT_FRIEND_INVITATION_TO_RESTAURANT: if self.social_event is not None or self.is_symptomatic(): # don't update dilemma_history since it's a compulsory decision return False rt = self.properties.risk_tolerance if SocialPolicy.SOCIAL_DISTANCING in get_parameters().get('social_policies'): rt = rt * rt k = 3 # TODO parameter d = self.covid_model.global_count.infected_count / self.covid_model.global_count.total_population rt = rt * math.exp(-k * d) pd = flip_coin(rt) hd = self.dilemma_history.herding_decision(self,dilemma, TribeSelector.FRIEND, get_parameters().get('min_behaviors_to_copy')) answer = self._standard_decision(pd, hd) else: assert False for tribe in TribeSelector: self.dilemma_history.history[dilemma][tribe].append(answer) return answer
def disease_evolution(self): # https://media.tghn.org/medialibrary/2020/06/ISARIC_Data_Platform_COVID-19_Report_8JUN20.pdf # https://www.ecdc.europa.eu/en/covid-19/latest-evidence if self.is_infected(): self.infection_days_count += 1 if self.disease_severity == DiseaseSeverity.ASYMPTOMATIC: if self.infection_days_count >= self.infection_incubation: self.disease_severity = DiseaseSeverity.LOW self.covid_model.global_count.asymptomatic_count -= 1 self.covid_model.global_count.symptomatic_count += 1 elif self.disease_severity == DiseaseSeverity.LOW: if self.infection_days_count > self.mild_duration: # By the end of this period, either the pacient is already with antibodies at # a level sufficient to cure the disease or the simptoms will get worse and he/she # will require hospitalization if flip_coin(self.moderate_severity_prob): # MODERATE cases requires hospitalization self.disease_severity = DiseaseSeverity.MODERATE self.covid_model.global_count.moderate_severity_count += 1 if not self.covid_model.reached_hospitalization_limit(): self.covid_model.global_count.total_hospitalized += 1 self.hospitalized = True shape = get_parameters().get('hospitalization_period_duration_shape') scale = get_parameters().get('hospitalization_period_duration_scale') self.hospitalization_duration = np.random.gamma(shape, scale) + self.infection_days_count else: self.recover() elif self.disease_severity == DiseaseSeverity.MODERATE: if self.infection_days_count > self.hospitalization_duration: self.recover() else: if flip_coin(self.high_severity_prob): self.disease_severity = DiseaseSeverity.HIGH self.covid_model.global_count.moderate_severity_count -= 1 self.covid_model.global_count.high_severity_count += 1 # If the disease evolves to HIGH and the person could not # be accomodated in a hospital, he/she will die. if not self.hospitalized or self.death_mark: self.die() elif self.disease_severity == DiseaseSeverity.HIGH: if self.death_mark: self.die()
def create_restaurant_location(self, index, is_bar): if is_bar: bar = Restaurant(normal_cap(100, 20, 50, 200), RestaurantType.BAR, flip_coin(0.5), self.model, 'Restaurant', str(index)) return bar else: if flip_coin(0.5): restaurant_type = RestaurantType.FAST_FOOD rtype = "FASTFOOD" else: restaurant_type = RestaurantType.FANCY rtype = "FANCY" restaurant = Restaurant( normal_cap( get_parameters().params['restaurant_capacity_mean'], get_parameters().params['restaurant_capacity_stdev'], 16, 200), restaurant_type, flip_coin(0.5), self.model, 'Restaurant', str(index)) return restaurant
def vaccinate(self): if self.vaccinated(): return shots_taken = len(self.vaccination_days) if flip_coin(get_parameters().get('vaccine_immunization_rate')[shots_taken]): self.immune = True else: symptom_attenuation = get_parameters().get('vaccine_symptom_attenuation')[shots_taken] self.moderate_severity_prob = self.base_moderate_severity_prob * (1 - symptom_attenuation) self.high_severity_prob = self.base_moderate_severity_prob * (1 - symptom_attenuation) self.vaccination_days.append(self.covid_model.global_count.day_count)
def is_isolated(self): if self.is_symptomatic(): return flip_coin(get_parameters().get('symptomatic_isolation_rate')) if isinstance(self, Adult): for policy in get_parameters().get('social_policies'): if policy in SocialPolicyUtil.locked_work_classes and \ self.work_info.work_class in SocialPolicyUtil.locked_work_classes[policy]: return not self.personal_decision(Dilemma.GO_TO_WORK_ON_LOCKDOWN) elif isinstance(self, K12Student): for policy in get_parameters().get('social_policies'): if policy in SocialPolicyUtil.locked_student_ages: lb, ub = SocialPolicyUtil.locked_student_ages[policy] if lb <= self.age <= ub: return True return False
def __init__(self, unique_id, covid_model, size): super().__init__(unique_id, covid_model) self.size = size self.covid_model = covid_model self.custom_parameters = {} count = 0 for i in range(size): human = Human.factory(covid_model, self) self.covid_model.global_count.non_infected_people.append(human) self.covid_model.global_count.non_infected_count += 1 if human.immune: self.covid_model.global_count.immune_count += 1 else: self.covid_model.global_count.susceptible_count += 1 if not flip_coin(self.get_parameter('initial_infection_rate')): count += 1 else: self.covid_model.global_count.non_infected_people[ count].infect(count)
def main_activity_isolated(self): if self.is_infected(): if self.disease_severity == DiseaseSeverity.MODERATE or \ self.disease_severity == DiseaseSeverity.HIGH: return True if self.is_symptomatic(): ir = get_parameters().get('symptomatic_isolation_rate') if flip_coin(ir): return True if isinstance(self, Adult): for policy in get_parameters().get('social_policies'): if policy in SocialPolicyUtil.locked_work_classes and \ self.work_info.work_class in SocialPolicyUtil.locked_work_classes[policy]: return not self.personal_decision(Dilemma.GO_TO_WORK_ON_LOCKDOWN) elif isinstance(self, K12Student): for policy in get_parameters().get('social_policies'): if policy in SocialPolicyUtil.locked_student_ages: lb, ub = SocialPolicyUtil.locked_student_ages[policy] if self.age >= lb and self.age <= ub: return True return False
def factory(covid_model, location): moderate_severity_probs = [ 0.001, 0.003, 0.012, 0.032, 0.049, 0.102, 0.166, 0.243, 0.273, 0.273 ] high_severity_probs = [ 0.05, 0.05, 0.05, 0.05, 0.063, 0.122, 0.274, 0.432, 0.709, 0.709 ] death_probs = [ 0.002, 0.00006, 0.0003, 0.0008, 0.0015, 0.006, 0.022, 0.051, 0.093, 0.093 ] age = int(np.random.beta(2, 5, 1) * 100) index = age // 10 msp = moderate_severity_probs[index] hsp = high_severity_probs[index] mfd = flip_coin(death_probs[index]) if age <= 1: return Infant(covid_model, location, age, msp, hsp, mfd) if age <= 4: return Toddler(covid_model, location, age, msp, hsp, mfd) if age <= 18: return K12Student(covid_model, location, age, msp, hsp, mfd) if age <= 64: return Adult(covid_model, location, age, msp, hsp, mfd) return Elder(covid_model, location, age, msp, hsp, mfd)
def __init__(self, city, population_size, model): self.work_zones = [ 'GM', 'IC', 'GR', 'CS', 'HC', 'O-1', 'O-2', 'LI', 'HM', 'GI', 'LB', 'WC-1', 'WC-2', 'WC-3', 'RI', 'CC', 'COM-1', 'COM-2', 'CNTY-A-1', 'CNTY-M-1', 'CNTY-C-2' ] self.home_zones = [ 'R-SF', 'R-LD', 'R-TH', 'R-MD', 'CNTY-R-1', 'R-MHC', 'R-HD' ] self.unused_zones = ['PD', 'CNTY-PAD', None] home_low_density_capacity = 20 home_medium_density_capacity = 150 home_high_density_capacity = 450 family_capacity_per_building = { 'R-SF': 1, 'R-LD': home_low_density_capacity, 'R-TH': home_low_density_capacity, 'R-MD': home_medium_density_capacity, 'CNTY-R-1': home_medium_density_capacity, 'R-MHC': home_medium_density_capacity, 'R-HD': home_high_density_capacity } family_capacity = {} self.model = model self.population_size = population_size self.zone_centroid = {} self.work_building_ids = [] self.home_building_ids = [] self.school_building_ids = [] self.restaurant_building_ids = [] self.home_building = {} self.work_building = {} self.school_building = {} self.restaurant_building = {} self.restaurant_distances = {} self.school_distances = {} self.work_zone_distances = {} self.restaurant_roulette = {} self.school_roulette = {} self.work_zone_roulette = {} self.sigma = get_parameters( ).params['real_sites_roulette_rescale_sigma'] self.kappa = get_parameters( ).params['real_sites_roulette_rescale_kappa'] home_district = District('HomeDistrict', model, '', '') work_district = District('WorkDistrict', model, '', '') school_district = District('SchoolDistrict', model, '', '') restaurant_district = District('RestaurantDistrict', model, '', '') with open(f'mesa-geo/examples/GeoSIR/{city}/neighborhoods.geojson' ) as json_file: self.neighborhoods = json.load(json_file) self.neighborhoods_count = len(self.neighborhoods['features']) print( f"Total number of neighboorhoods: {self.neighborhoods_count}") with open(f'mesa-geo/examples/GeoSIR/{city}/schools.geojson' ) as json_file: self.schools = json.load(json_file) self.schools_count = len(self.schools['features']) for school in self.schools['features']: bid = str(school['properties']['OBJECTID']) self.school_building_ids.append(bid) self.school_building[bid] = HomogeneousBuilding( 1000000, model, 'School', bid) school_district.locations.append(self.school_building[bid]) print(f"Total number of schools: {self.schools_count}") with open(f'mesa-geo/examples/GeoSIR/{city}/zoning.geojson' ) as json_file: self.buildings = json.load(json_file) print( f"Total number of buildings: {len(self.buildings['features'])}" ) self.all_zones_coordinates = [] for building in self.buildings['features']: bid = str(building['properties']['OBJECTID']) self.zone_centroid[bid] = self.compute_centroid(building) zone = building['properties']['PLANZONE'] if building['geometry']['type'] == 'Polygon': self.all_zones_coordinates.append( building['geometry']['coordinates'][0]) elif building['geometry']['type'] == 'MultiPolygon': for v in building['geometry']['coordinates']: self.all_zones_coordinates.append(v[0]) else: assert False if zone in self.work_zones: self.work_building_ids.append(bid) self.work_building[bid] = HomogeneousBuilding( 1000000, model, 'Work', bid) work_district.locations.append(self.work_building[bid]) elif zone in self.home_zones: family_capacity[bid] = family_capacity_per_building[zone] self.home_building_ids.append(bid) self.home_building[bid] = HomogeneousBuilding( family_capacity[bid], model, 'Home', bid) home_district.locations.append(self.home_building[bid]) elif zone not in self.unused_zones: print(f"Unknown zone type: {zone}") exit() self.restaurants = self.create_geo_restaurants(self.buildings) self.restaurants_count = len(self.restaurants['features']) for restaurant in self.restaurants['features']: bid_int = restaurant['properties']['OBJECTID'] bid = str(bid_int) self.restaurant_building_ids.append(bid) self.restaurant_building[bid] = self.create_restaurant_location( bid_int, flip_coin(0.1)) restaurant_district.locations.append(self.restaurant_building[bid]) print(f"Total number of restaurants: {self.restaurants_count}") with open('restaurants.geojson', 'w') as fp: json.dump(self.restaurants, fp) distance_cache_file = f'mesa-geo/examples/GeoSIR/{city}/distances_{self.sigma}_{self.kappa}.json' if os.path.isfile(distance_cache_file): with open(distance_cache_file) as json_file: table = json.load(json_file) self.restaurant_distances = table['restaurant_distances'] self.school_distances = table['school_distances'] self.work_zone_distances = table['work_zone_distances'] self.restaurant_roulette = table['restaurant_roulette'] self.school_roulette = table['school_roulette'] self.work_zone_roulette = table['work_zone_roulette'] else: self.compute_restaurant_distances() self.compute_school_distances() self.compute_work_zone_distances() table = {} table['restaurant_distances'] = self.restaurant_distances table['school_distances'] = self.school_distances table['work_zone_distances'] = self.work_zone_distances table['restaurant_roulette'] = self.restaurant_roulette table['school_roulette'] = self.school_roulette table['work_zone_roulette'] = self.work_zone_roulette with open(distance_cache_file, 'w') as json_file: json.dump(table, json_file) family_factory = FamilyFactory(model) family_factory.factory(population_size) model.global_count.total_population = family_factory.human_count print(f"Total number of families: {len(family_factory.families)}") #count_family = 0 for family in family_factory.families: #if count_family % 1000 == 0: print(f"{count_family} {datetime.datetime.now()}") #count_family += 1 assert len(self.home_building_ids) > 0 home_bid = random_selection(self.home_building_ids) selected_home_build = self.home_building[home_bid] home_unit = BuildingUnit(10, model, home_bid, '', contagion_probability=beta_range( 0.021, 0.12)) family_capacity[home_bid] -= 1 if family_capacity[home_bid] == 0: self.home_building_ids.remove(home_bid) selected_home_build.locations.append(home_unit) for human in family: # Home human.home_district = home_district home_district.allocation[human] = [selected_home_build] home_unit.allocation.append(human) selected_home_build.allocation[human] = home_unit assert home_district.get_buildings(human)[0].get_unit( human) == home_unit home_unit.humans.append(human) # Work if isinstance(human, Adult): human.work_district = work_district #work_bid = random_selection(self.work_building_ids) work_bid = roulette_selection( self.work_zone_distances[home_bid]['work_zone_bid'], self.work_zone_distances[home_bid]['distance'], roulette=self.work_zone_roulette[home_bid]) selected_work_building = self.work_building[work_bid] work_unit = selected_work_building.locations[-1] if selected_work_building.locations and\ len(work_unit.allocation) < work_unit.capacity else None if work_unit is None: work_unit = BuildingUnit( 10, model, work_bid, '', contagion_probability=beta_range(0.007, 0.06)) selected_work_building.locations.append(work_unit) work_district.allocation[human] = [selected_work_building] work_unit.allocation.append(human) selected_work_building.allocation[human] = work_unit assert work_district.get_buildings(human)[0].get_unit( human) == work_unit # School if isinstance(human, K12Student): human.school_district = school_district #work_bid = random_selection(self.school_building_ids) school_bid = roulette_selection( self.school_distances[home_bid]['school_bid'], self.school_distances[home_bid]['distance'], roulette=self.school_roulette[home_bid]) selected_school_building = self.school_building[school_bid] school_unit = selected_school_building.locations[-1] if selected_school_building.locations and\ len(school_unit.allocation) < school_unit.capacity else None if school_unit is None: school_unit = BuildingUnit( 20, model, school_bid, '', contagion_probability=beta_range(0.014, 0.08)) selected_school_building.locations.append(school_unit) school_district.allocation[human] = [ selected_school_building ] school_unit.allocation.append(human) selected_school_building.allocation[human] = school_unit assert school_district.get_buildings(human)[0].get_unit( human) == school_unit # Restaurants if isinstance(human, Adult): #bids = [random_selection(self.restaurant_building_ids) for i in range(10)] bids = roulette_selection( self.restaurant_distances[work_bid]['restaurant_bid'], self.restaurant_distances[work_bid]['distance'], 10, roulette=self.restaurant_roulette[work_bid]) human.preferred_restaurants = [ self.restaurant_building[bid] for bid in bids ]
def is_wearing_mask(self): mur = get_parameters().get('mask_user_rate') return flip_coin(mur)
def setup_city_layout(model, population_size): work_building_capacity = 20 office_capacity = 10 work_building_occupacy_rate = 0.5 appartment_building_capacity = 20 appartment_capacity = 5 appartment_building_occupacy_rate = 0.5 school_capacity = 50 classroom_capacity = 20 school_occupacy_rate = 0.5 # Build empty districts # https://docs.google.com/document/d/1imCNXOyoyecfD_sVNmKpmbWVB6xqP-FWlHELAyOg1Vs/edit home_district = build_district( "Home", model, population_size, appartment_building_capacity, appartment_capacity, appartment_building_occupacy_rate, beta_range(0.021, 0.12)) # normal_ci(0.021, 0.12, 10) work_district = build_district( "Work", model, population_size, work_building_capacity, office_capacity, work_building_occupacy_rate, beta_range(0.007, 0.06)) # normal_ci(0.007, 0.06, 10) school_district = build_district( "School", model, population_size, school_capacity, classroom_capacity, school_occupacy_rate, beta_range(0.014, 0.08)) # normal_ci(0.014, 0.08, 10) home_district.debug = model.debug work_district.debug = model.debug school_district.debug = model.debug # Add Restaurants to work_district for i in range( get_parameters().params['restaurant_count_per_work_district']): if flip_coin(0.5): restaurant_type = RestaurantType.FAST_FOOD rtype = "FASTFOOD" else: restaurant_type = RestaurantType.FANCY rtype = "FANCY" restaurant = Restaurant( normal_cap(get_parameters().params['restaurant_capacity_mean'], get_parameters().params['restaurant_capacity_stdev'], 16, 200), restaurant_type, flip_coin(0.5), model, '', rtype + '-' + str(i)) work_district.locations.append(restaurant) for i in range(2): bar = Restaurant(normal_cap(100, 20, 50, 200), RestaurantType.BAR, flip_coin(0.5), model, '', 'BAR-' + str(i)) work_district.locations.append(bar) # print(home_district) # print(work_district) # print(school_district) # Build families family_factory = FamilyFactory(model) family_factory.factory(population_size) model.global_count.total_population = family_factory.human_count # print(family_factory) age_group_sets = { Infant: [], Toddler: [], K12Student: [], Adult: [], Elder: [] } # Allocate buildings to people all_adults = [] all_students = [] for family in family_factory.families: adults = [human for human in family if isinstance(human, Adult)] students = [human for human in family if isinstance(human, K12Student)] home_district.allocate(family, True, True, True) work_district.allocate(adults) school_district.allocate(students, True) for human in family: age_group_sets[type(human)].append(human) human.home_district = home_district home_district.get_buildings(human)[0].get_unit( human).humans.append(human) for adult in adults: adult.work_district = work_district all_adults.append(adult) for student in students: student.school_district = school_district all_students.append(student) # Set tribes adult_rf = HomophilyRelationshipFactory(model, all_adults) student_rf = HomophilyRelationshipFactory(model, all_students) # exit() count = 0 for family in family_factory.families: for human in family: count += 1 human.tribe[TribeSelector.AGE_GROUP] = age_group_sets[type(human)] human.tribe[TribeSelector.FAMILY] = family if isinstance(human, Adult): human.unique_id = "Adult" + str(count) human.tribe[ TribeSelector.COWORKER] = work_district.get_buildings( human)[0].get_unit(human).allocation t1 = adult_rf.build_tribe(human, human.tribe[TribeSelector.COWORKER], 1, office_capacity) t2 = adult_rf.build_tribe(human, human.tribe[TribeSelector.AGE_GROUP], 1, 20) human.tribe[TribeSelector.FRIEND] = t1 for h in t2: if h not in human.tribe[TribeSelector.FRIEND]: human.tribe[TribeSelector.FRIEND].append(h) elif isinstance(human, K12Student): human.unique_id = "K12Student" + str(count) human.tribe[ TribeSelector.CLASSMATE] = school_district.get_buildings( human)[0].get_unit(human).allocation t1 = student_rf.build_tribe( human, human.tribe[TribeSelector.CLASSMATE], 1, classroom_capacity) t2 = student_rf.build_tribe( human, human.tribe[TribeSelector.AGE_GROUP], 1, 20) human.tribe[TribeSelector.FRIEND] = t1 for h in t2: if h not in human.tribe[TribeSelector.FRIEND]: human.tribe[TribeSelector.FRIEND].append(h) elif isinstance(human, Elder): human.unique_id = "Elder" + str(count) elif isinstance(human, Infant): human.unique_id = "Infant" + str(count) elif isinstance(human, Toddler): human.unique_id = "Toddler" + str(count)
def is_contagious(self): if self.is_infected() and self.infection_days_count >= self.infection_latency: if self.is_symptomatic() or flip_coin(get_parameters().get('asymptomatic_contagion_probability')): return True return False
def setup_grid_layout(model, population_size, home_grid_height, home_grid_width, work_height, work_width, school_height, school_width): #Makes a grid of homogeneous home districts, overlaid by school and work districts. #home_grid_height is the number of home districts high the grid is, and #home_grid_width is the nmber of home districts wide the grid is #school height and work height are how many home districts high a school #district and work are respectively, and the same for their length. #each begins in grid 0,0 and cover the orignal home district grid. #Persons assigned to the home districts are also assigned to the school #and work districts that cover them. The parameters determine the amount #of leakage across groups of people. With parameters (10,10,1,1,1,1) you get 100 #completely separated districts with no leakage. With parameters (6,6,2,2,3,3) you #get a grid where every one is connected to everyone else, but there is a #degree of separation. For example, a person in home district (0,0) can be infected #by a person in (5,5) but it would be bridged by three infections, slowing the #virus down. Larger sizes for work and school districts enable faster spread. Fastest #spread occurs with parameters (1,1,1,1,1,1) or equivalently (10,10, 10,10,10,10) #or any of the same number #Since this is just a way to allocate human interactions, no label is needed and #the grid need not be saved, for interactions to occur, although this inforamtion #may be useful for visualizations. work_building_capacity = 20 office_capacity = 10 work_building_occupacy_rate = 0.5 appartment_building_capacity = 20 appartment_capacity = 5 appartment_building_occupacy_rate = 0.5 school_capacity = 50 classroom_capacity = 20 school_occupacy_rate = 0.5 # Build empty districts # https://docs.google.com/document/d/1imCNXOyoyecfD_sVNmKpmbWVB6xqP-FWlHELAyOg1Vs/edit home_districts = [] work_districts = [] school_districts = [] school_map = {} work_map = {} school_grid_height = math.ceil(home_grid_height / school_height) school_grid_width = math.ceil(home_grid_width / school_width) work_grid_height = math.ceil(home_grid_height / work_height) work_grid_width = math.ceil(home_grid_width / work_width) for hw in range(home_grid_width): for hh in range(home_grid_height): home_district = build_district( f"Home ({hh},{hw})", model, population_size, appartment_building_capacity, appartment_capacity, appartment_building_occupacy_rate, beta_range(0.021, 0.12)) # normal_ci(0.021, 0.12, 10) home_district.debug = model.debug home_districts.append(home_district) home_number = hw * home_grid_height + hh assert home_number == len(home_districts) - 1 sh = hh // school_height sw = hw // school_width school_number = sw * school_grid_height + sh school_map[home_number] = school_number wh = hh // work_height ww = hw // work_width work_number = ww * work_grid_height + wh work_map[home_number] = work_number for ww in range(work_grid_width): for wh in range(work_grid_height): work_district = build_district( f"Work ({wh},{ww})", model, population_size, work_building_capacity, office_capacity, work_building_occupacy_rate, beta_range(0.007, 0.06)) # normal_ci(0.007, 0.06, 10) # Add Restaurants to work_district for i in range(get_parameters(). params['restaurant_count_per_work_district']): if flip_coin(0.5): restaurant_type = RestaurantType.FAST_FOOD rtype = "FASTFOOD" else: restaurant_type = RestaurantType.FANCY rtype = "FANCY" restaurant = Restaurant( normal_cap( get_parameters().params['restaurant_capacity_mean'], get_parameters().params['restaurant_capacity_stdev'], 16, 200), restaurant_type, flip_coin(0.5), model, '', rtype + '-' + str(i) + f"({wh},{ww})") work_district.locations.append(restaurant) for i in range(2): bar = Restaurant(normal_cap(100, 20, 50, 200), RestaurantType.BAR, flip_coin(0.5), model, '', 'BAR-' + str(i) + f"({wh},{ww})") work_district.locations.append(bar) work_district.debug = model.debug work_districts.append(work_district) for sw in range(school_grid_width): for sh in range(school_grid_height): school_district = build_district( f"School ({sh},{sw})", model, population_size, school_capacity, classroom_capacity, school_occupacy_rate, beta_range(0.014, 0.08)) # normal_ci(0.014, 0.08, 10) school_district.debug = model.debug school_districts.append(school_district) #print ("work_map") #print (work_map) #print ("school_map") #print (school_map) # Build families family_factory = FamilyFactory(model) family_factory.factory(population_size) model.global_count.total_population = family_factory.human_count # print(family_factory) age_group_sets = { Infant: [], Toddler: [], K12Student: [], Adult: [], Elder: [] } # Allocate buildings to people #print ("home_districts") #print (home_districts) #print ("work_districts") #print (work_districts) #print ("school_districts") #print (school_districts) all_adults = [] all_students = [] for family in family_factory.families: adults = [human for human in family if isinstance(human, Adult)] students = [human for human in family if isinstance(human, K12Student)] home_district_num = np.random.randint(0, len(home_districts)) #print("home_district_num") #print(home_district_num) home_district = home_districts[home_district_num] work_district = work_districts[work_map[home_district_num]] school_district = school_districts[school_map[home_district_num]] home_district.allocate(family, True, True, True) work_district.allocate(adults) school_district.allocate(students, True) for human in family: age_group_sets[type(human)].append(human) human.home_district = home_district home_district.get_buildings(human)[0].get_unit( human).humans.append(human) for adult in adults: adult.work_district = work_district all_adults.append(adult) for student in students: student.school_district = school_district all_students.append(student) # Set tribes adult_rf = HomophilyRelationshipFactory(model, all_adults) student_rf = HomophilyRelationshipFactory(model, all_students) # exit() count = 0 for family in family_factory.families: for human in family: work_district = human.work_district school_district = human.school_district count += 1 human.tribe[TribeSelector.AGE_GROUP] = age_group_sets[type(human)] human.tribe[TribeSelector.FAMILY] = family if isinstance(human, Adult): human.unique_id = "Adult" + str(count) #print(work_district.get_buildings(human)) #print(work_district.get_buildings(human)) #print(workd_district.get_buildings(human)[0].get_unit(human)) #print(workd_district.get_buildings(human)[0].get_unit(human)) human.tribe[ TribeSelector.COWORKER] = work_district.get_buildings( human)[0].get_unit(human).allocation t1 = adult_rf.build_tribe(human, human.tribe[TribeSelector.COWORKER], 1, office_capacity) t2 = adult_rf.build_tribe(human, human.tribe[TribeSelector.AGE_GROUP], 1, 20) human.tribe[TribeSelector.FRIEND] = t1 for h in t2: if h not in human.tribe[TribeSelector.FRIEND]: human.tribe[TribeSelector.FRIEND].append(h) elif isinstance(human, K12Student): human.unique_id = "K12Student" + str(count) human.tribe[ TribeSelector.CLASSMATE] = school_district.get_buildings( human)[0].get_unit(human).allocation t1 = student_rf.build_tribe( human, human.tribe[TribeSelector.CLASSMATE], 1, classroom_capacity) t2 = student_rf.build_tribe( human, human.tribe[TribeSelector.AGE_GROUP], 1, 20) human.tribe[TribeSelector.FRIEND] = t1 for h in t2: if h not in human.tribe[TribeSelector.FRIEND]: human.tribe[TribeSelector.FRIEND].append(h) elif isinstance(human, Elder): human.unique_id = "Elder" + str(count) elif isinstance(human, Infant): human.unique_id = "Infant" + str(count) elif isinstance(human, Toddler): human.unique_id = "Toddler" + str(count)
def spread_infection(self): for h1 in self.humans: for h2 in self.humans: if h1 != h2: if flip_coin(self.spreading_rate / len(self.humans)): self.check_spreading(h1, h2)
def test_flip_coin(): assert type(base.flip_coin(0.5)) == bool with pytest.raises(TypeError): base.flip_coin("50")