Skip to content

Commit

Permalink
Exposing more parameters from buildings and linking cases to disease …
Browse files Browse the repository at this point in the history
…def.
  • Loading branch information
djgroen committed Apr 24, 2020
1 parent 4b4842d commit cf54d36
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 28 deletions.
70 changes: 48 additions & 22 deletions flacs/flacs.py
Expand Up @@ -97,14 +97,14 @@ def __init__(self, location, household, ages):
self.age = np.random.choice(91, p=ages) # age in years


def plan_visits(self, e):
def plan_visits(self, e, deterministic=False):
if self.status in ["susceptible","exposed","infectious"]: # recovered people are assumed to be immune.
personal_needs = needs.get_needs(self)
for k,element in enumerate(personal_needs):
nearest_locs = self.home_location.nearest_locations
if nearest_locs[k] and element>0:
location_to_visit = nearest_locs[k]
location_to_visit.register_visit(e, self, element)
location_to_visit.register_visit(e, self, element, deterministic)

def print_needs(self):
print(self.age, needs.get_needs(self))
Expand Down Expand Up @@ -306,6 +306,7 @@ def __init__(self, name, loc_type="park", x=0.0, y=0.0, sqm=400):
self.inf_visit_minutes = 0 # aggregate number of visit minutes by infected people.
self.avg_visit_time = avg_visit_times[lids[loc_type]] # using averages for all visits for now. Can replace with a distribution later.
#print(self.avg_visit_time)
self.visit_probability_counter = 0.5 #counter used for deterministic calculations.

def DecrementNumAgents(self):
self.numAgents -= 1
Expand All @@ -317,7 +318,7 @@ def clear_visits(self):
self.visits = []
self.visit_minutes = 0 # total number of minutes of all visits aggregated.

def register_visit(self, e, person, need):
def register_visit(self, e, person, need, deterministic):
visit_time = self.avg_visit_time
if person.status == "dead":
visit_time = 0.0
Expand All @@ -331,27 +332,52 @@ def register_visit(self, e, person, need):
else:
return

if random.random() < visit_probability:
if deterministic:
self.visit_probability_counter += min(visit_probability, 1)
if self.visit_probability_counter > 1.0:
self.visit_probability_counter -= 1.0
self.visits.append([person, visit_time])
if person.status == "infectious":
self.inf_visit_minutes += visit_time

elif random.random() < visit_probability:
self.visits.append([person, visit_time])
if person.status == "infectious":
self.inf_visit_minutes += visit_time

def evolve(self, e, verbose=True):
def evolve(self, e, verbose=True, deterministic=False):
minutes_opened = 12*60
for v in self.visits:
if v[0].status == "susceptible":
infection_probability = e.contact_rate_multiplier[self.type] * (e.disease.infection_rate/360.0) * (v[1] / minutes_opened) * (self.inf_visit_minutes / self.sqm)
# For Covid-19 this should be 0.07 (infection rate) for 1 infectious person, and 1 susceptible person within 2m for a full day.
# I assume they can do this in a 4m^2 area.
# So 0.07 = x * (24*60/24*60) * (24*60/4) -> 0.07 = x * 360 -> x = 0.07/360 = 0.0002
#if ultraverbose:
# if infection_probability > 0.0:
# print("{} = {} * ({}/360.0) * ({}/{}) * ({}/{})".format(infection_probability, e.contact_rate_multiplier[self.type], e.disease.infection_rate, v[1], minutes_opened, self.inf_visit_minutes, self.sqm))
if random.random() < infection_probability:
v[0].status = "exposed"
v[0].status_change_time = e.time
if verbose:
log_infection(e.time, self.x, self.y, self.type)

# Deterministic mode: only used for warmup.
if deterministic:
inf_counter = 0.5
for v in self.visits:
if v[0].status == "susceptible":
infection_probability = e.contact_rate_multiplier[self.type] * (e.disease.infection_rate/360.0) * (v[1] / minutes_opened) * (self.inf_visit_minutes / self.sqm)
inf_counter += min(infection_probability, 1.0)
if inf_counter > 1.0:
inf_counter -= 1.0
v[0].status = "exposed"
v[0].status_change_time = e.time
if verbose:
log_infection(e.time, self.x, self.y, self.type)

# Used everywhere else
else:
for v in self.visits:
if v[0].status == "susceptible":
infection_probability = e.contact_rate_multiplier[self.type] * (e.disease.infection_rate/360.0) * (v[1] / minutes_opened) * (self.inf_visit_minutes / self.sqm)
# For Covid-19 this should be 0.07 (infection rate) for 1 infectious person, and 1 susceptible person within 2m for a full day.
# I assume they can do this in a 4m^2 area.
# So 0.07 = x * (24*60/24*60) * (24*60/4) -> 0.07 = x * 360 -> x = 0.07/360 = 0.0002
#if ultraverbose:
# if infection_probability > 0.0:
# print("{} = {} * ({}/360.0) * ({}/{}) * ({}/{})".format(infection_probability, e.contact_rate_multiplier[self.type], e.disease.infection_rate, v[1], minutes_opened, self.inf_visit_minutes, self.sqm))
if random.random() < infection_probability:
v[0].status = "exposed"
v[0].status_change_time = e.time
if verbose:
log_infection(e.time, self.x, self.y, self.type)


class Ecosystem:
Expand Down Expand Up @@ -426,7 +452,7 @@ def add_infection(self, x, y, age, day):
selected_house.add_infection_by_age(day, age)


def evolve(self):
def evolve(self, reduce_stochasticity=False):
global num_infections_today
global num_hospitalisations_today
num_infections_today = 0
Expand All @@ -441,7 +467,7 @@ def evolve(self):
for h in self.houses:
for hh in h.households:
for a in hh.agents:
a.plan_visits(self)
a.plan_visits(self, reduce_stochasticity)
a.progress_condition(self.time, self.disease)

# process visits for the current day (spread infection).
Expand All @@ -450,7 +476,7 @@ def evolve(self):
if self.closures[lk] < self.time:
continue
for l in self.locations[lk]:
l.evolve(self)
l.evolve(self, reduce_stochasticity)

# process intra-household infection spread.
for h in self.houses:
Expand Down
3 changes: 2 additions & 1 deletion readers/read_building_csv.py
Expand Up @@ -22,7 +22,7 @@ def apply_building_mapping(mapdict, label):
return category
return "house"

def read_building_csv(e, csvfile, building_type_map="covid_data/building_types_map.yml", house_ratio=1, workspace=10, office_size=1600, household_size=2.6, work_participation_rate=0.5, dumptypesandquit=False):
def read_building_csv(e, csvfile, building_type_map="covid_data/building_types_map.yml", house_ratio=1, workspace=12, office_size=1600, household_size=2.6, work_participation_rate=0.5, dumptypesandquit=False):
"""
house_ratio = number of households per house.
workspace = m2 of office space per worker.
Expand Down Expand Up @@ -91,6 +91,7 @@ def read_building_csv(e, csvfile, building_type_map="covid_data/building_types_m
if row_number % 10000 == 0:
print(row_number, "read", file=sys.stderr)
print(row_number, "read", file=sys.stderr)
print("bounds:", xbound, ybound, file=sys.stderr)
office_sqm_red = office_sqm
while office_sqm_red > 0:
num_locs += 1
Expand Down
6 changes: 3 additions & 3 deletions readers/read_cases_csv.py
Expand Up @@ -16,8 +16,8 @@ def subtract_dates(date1, date2, date_format="%m/%d/%Y"):
return delta.days

def read_cases_csv(e, csvfile, date_format="%m/%d/%Y", start_date="3/18/2020"):
period_to_hosp = 12
period_to_rec = 20
period_to_hosp = e.disease.period_to_hospitalisation
period_to_rec = e.disease.recovery_period

num_infections = 0
if csvfile == "":
Expand All @@ -29,7 +29,7 @@ def read_cases_csv(e, csvfile, date_format="%m/%d/%Y", start_date="3/18/2020"):
for row in cases_reader:
if len(row[3]) > 0:
day = subtract_dates(row[3], start_date, date_format)
if day<0 and day > - (period_to_rec - period_to_hosp):
if day<0 and day > -period_to_rec:
e.add_infection(float(row[0]), float(row[1]), int(row[2]), day-period_to_hosp)
e.add_infections(16, day-period_to_hosp) # 1 hospitalisation per 16.67 infections (0.06 prob).
num_infections += 17
Expand Down
9 changes: 7 additions & 2 deletions run.py
Expand Up @@ -107,7 +107,12 @@
read_building_csv.read_building_csv(e,
building_file,
"{}/building_types_map.yml".format(data_dir),
house_ratio=house_ratio)
house_ratio=house_ratio, workspace=12, office_size=1600, household_size=2.6, work_participation_rate=0.5)
# house ratio: number of households per house placed (higher number adds noise, but reduces runtime
# And then 3 parameters that ONLY affect office placement.
# workspace: m2 per employee on average. (10 in an office setting, but we use 12 as some people work in more spacious environments)
# household size: average size of each household, specified separately here.
# work participation rate: fraction of population in workforce, irrespective of age

print("{}/{}_cases.csv".format(data_dir, location))
# Can only be done after houses are in.
Expand All @@ -119,7 +124,7 @@
e.time = -30
e.print_header(outfile)
for i in range(0, 30):
e.evolve()
e.evolve(reduce_stochasticity=True)
print(e.time)
#e.print_status(outfile)

Expand Down

0 comments on commit cf54d36

Please sign in to comment.