class AgeGroup: def __init__(self, subgroupstats, name=None): self.name = name self.stats = subgroupstats # Variables to store state changes # Probability states if self.name is not None: self.isolated = ProbState(14, name=f"{self.name}: isolated") else: self.isolated = ProbState(14) self.h_noncrit = ProbState(8) self.h_post_icu = ProbState(6) self.h_icu = ProbState(10) self.h_icu_vent = ProbState(10) self.recovered = ProbState(1000) self.deceased = ProbState(1000) self.isolated.add_exit_state(self.recovered, 1) self.isolated.normalize_states_over_period() self.h_noncrit.add_exit_state(self.recovered, 1) self.h_noncrit.normalize_states_over_period() self.h_icu.add_exit_state(self.deceased, self.stats.p_icu_death) self.h_icu.add_exit_state(self.h_post_icu, self.stats.p_icu_recovery) self.h_icu.normalize_states_over_period() self.h_icu_vent.add_exit_state(self.deceased, self.stats.p_icu_death) self.h_icu_vent.add_exit_state(self.h_post_icu, self.stats.p_icu_recovery) self.h_icu_vent.normalize_states_over_period() self.h_post_icu.add_exit_state(self.recovered, 1) self.h_post_icu.normalize_states_over_period() # Add N people to the list of infected def apply_infections(self, infections): inf_float = float(infections) self.isolated.store_pending(inf_float * self.stats.p_selfisolate) self.h_noncrit.store_pending(inf_float * self.stats.p_nevercrit) self.h_icu.store_pending(inf_float * self.stats.p_icu_nonvent) self.h_icu_vent.store_pending(inf_float * self.stats.p_icu_vent) def calculate_redistributions(self): self.isolated.pass_downstream() self.h_noncrit.pass_downstream() self.h_icu.pass_downstream() self.h_icu_vent.pass_downstream() def apply_pending(self): self.isolated.apply_pending() self.h_noncrit.apply_pending() self.h_icu.apply_pending() self.h_icu_vent.apply_pending() self.recovered.apply_pending() self.deceased.apply_pending()
class ScenarioDrivenModel: def __init__(self, scenario): if isinstance(scenario, str): self.scenario = EpiScenario(scenario) elif isinstance(scenario, EpiScenario): self.scenario = scenario self.modelname = self.scenario.modelname self.total_days = 0 self.r0 = self.scenario.parameters['initial_r0'] self.beta = None self.population = self.scenario.totalpop self.susceptible = ProbState(period=0, count=self.scenario.init_susceptible, name='susceptible') self.incubating = ProbState(period=self.scenario.incubation_period, count=self.scenario.init_infected, name='incubating') self.infectious = ProbState(period=self.scenario.prediagnosis, count=self.scenario.init_infectious, name='infectious') self.isolated_holding = ProbState(period=90, name='isolated_holding') self.incubating.add_exit_state(self.infectious, 1) self.incubating.normalize_states_over_period() self.infectious.add_exit_state(self.isolated_holding, 1) self.infectious.normalize_states_over_period() self.subgroups = dict() for key, value in self.scenario.subgrouprates.items(): self.subgroups[key] = AgeGroup(value, name=key) # self.fitness = None def run(self): self.run_r0_set(self.scenario.r0_date_offsets, self.scenario.r0_values) def set_r0(self, value): self.r0 = value def run_r0_set(self, date_offsets, r0_values): self.scenario.hospital_door_aggregator = [] day_counter = 0 for itr in range(0, len(date_offsets)): self.set_r0(r0_values[itr]) self.beta = calc_beta(r0_values[itr], self.infectious.period) while day_counter < date_offsets[itr]: self.step_day() day_counter += 1 self.scenario.hospital_door_aggregator.append( self.scenario.hospital_door_aggregator[-1]) def step_day(self): new_infections = calc_infected(self.population, self.beta, self.susceptible.count, self.infectious.count) #print(f"Day {self.total_days} infections: {new_infections} = {self.beta} * {self.susceptible.count} * {self.infectious.count} / {self.population}") self.susceptible.store_pending(-new_infections) self.incubating.store_pending(new_infections) self.incubating.pass_downstream() self.infectious.pass_downstream() diagnosed = self.isolated_holding.pending if len(self.scenario.hospital_door_aggregator) == 0: diagnagg = diagnosed else: diagnagg = self.scenario.hospital_door_aggregator[-1] + diagnosed self.scenario.hospital_door_aggregator.append(diagnagg) self.isolated_holding.pending = 0 subpop_out = [] for key, agegroup in self.subgroups.items(): subpop = diagnosed * agegroup.stats.pop_dist subpop_out.append(subpop) agegroup.apply_infections(subpop) agegroup.calculate_redistributions() self.susceptible.apply_pending() self.incubating.apply_pending() self.infectious.apply_pending() for key, agegroup in self.subgroups.items(): agegroup.apply_pending() self.total_days += 1 def gather_sums(self): time_increments = len(self.susceptible.domain) self.scenario.out_susceptible = self.susceptible.domain self.scenario.out_incubating = self.incubating.domain self.scenario.out_infectious = self.infectious.domain self.scenario.sum_isolated = [0] * time_increments self.scenario.sum_noncrit = [0] * time_increments self.scenario.sum_icu = [0] * time_increments self.scenario.sum_icu_vent = [0] * time_increments self.scenario.sum_recovered = [0] * time_increments self.scenario.sum_deceased = [0] * time_increments self.scenario.sum_hospitalized = [0] * time_increments for key, value in self.subgroups.items(): self.scenario.sum_isolated = np.add(self.scenario.sum_isolated, value.isolated.domain) self.scenario.sum_noncrit = np.add(self.scenario.sum_noncrit, value.h_noncrit.domain) self.scenario.sum_icu = np.add(self.scenario.sum_icu, value.h_icu.domain) self.scenario.sum_icu_vent = np.add(self.scenario.sum_icu_vent, value.h_icu_vent.domain) self.scenario.sum_recovered = np.add(self.scenario.sum_recovered, value.recovered.domain) self.scenario.sum_deceased = np.add(self.scenario.sum_deceased, value.deceased.domain) self.scenario.sum_hospitalized = np.add(self.scenario.sum_hospitalized, self.scenario.sum_icu) self.scenario.sum_hospitalized = np.add(self.scenario.sum_hospitalized, self.scenario.sum_noncrit) self.scenario.sum_hospitalized = np.add(self.scenario.sum_hospitalized, self.scenario.sum_icu_vent) self.scenario.fitset = dict() cursor = self.scenario.initial_date stoptime = cursor + timedelta(self.total_days) itr = 0 while cursor < stoptime: if cursor not in self.scenario.fitset: self.scenario.fitset[cursor] = dict() self.scenario.fitset[cursor][ 'current_hosp'] = self.scenario.sum_hospitalized[itr] self.scenario.fitset[cursor][ 'total_hosp'] = self.scenario.hospital_door_aggregator[itr] self.scenario.fitset[cursor][ 'total_deceased'] = self.scenario.sum_deceased[itr] itr += 1 cursor += ONEDAY def save_results(self, iteration): result = dict() result['iteration'] = iteration result['fitness'] = self.scenario.fitness result['scenario'] = self.scenario.parameters result['modelname'] = self.modelname result['total_days'] = self.total_days result['totalpop'] = self.population result['sum_isolated'] = self.scenario.sum_isolated result['sum_noncrit'] = self.scenario.sum_noncrit result['sum_icu'] = self.scenario.sum_icu result['sum_icu_vent'] = self.scenario.sum_icu_vent result['sum_recovered'] = self.scenario.sum_recovered result['sum_deceased'] = self.scenario.sum_deceased with open(f"best_fit{iteration}", "w") as bfi: json.dump(result, bfi) def actual_curves(self): cursor = self.scenario.initial_date finaldate = cursor + timedelta(self.total_days) act_hosp = [] act_death = [] while cursor < finaldate: if cursor in COLORADO_ACTUAL: act_hosp.append(COLORADO_ACTUAL[cursor]['hospitalized']) act_death.append(COLORADO_ACTUAL[cursor]['deceased']) else: act_hosp.append(None) act_death.append(None) cursor += ONEDAY act_death.append(None) act_hosp.append(None) return act_hosp, act_death def generate_png(self): hospitalized = self.scenario.hospital_door_aggregator startdate = self.scenario.initial_date time_domain = [startdate] cursor = startdate for _ in range(0, self.total_days): cursor += ONEDAY time_domain.append(cursor) # time_domain = np.linspace(0, model.total_days, model.total_days + 1) fig = plt.figure(facecolor='w') # ax = fig.add_subplot(111, axis_bgcolor='#dddddd', axisbelow=True) ax = fig.add_subplot(111, axisbelow=True) ### Vertical line indicating today plt.axvline(x=datetime.today(), alpha=.5, lw=2, label='Today') #------------- # Actual numbers, displayed when GA fitting #------------- act_hosp, act_death = self.actual_curves() ### Actual Hospitalized, as specified in the constants ax.plot(time_domain, act_hosp, color=(0, 0, .5), alpha=1, lw=2, label='Actual Hospitalized', linestyle='-') ### Actual Deaths, as specified in the constants ax.plot(time_domain, act_death, color=(0, 0, .5), alpha=1, lw=2, label='Actual Deaths', linestyle='-') #------------- # Basic SEIR #------------- ### Susceptible line, usually too tall # ax.plot(time_domain, self.scenario.out_susceptible, label='Susceptible', color=(0, 0, 1), alpha=.5, lw=2, linestyle='-') ### Exposed: pre-symptomatic, not infectious yet # ax.plot(time_domain, self.scenario.incubating, label='Exposed', color=TABLEAU_ORANGE, alpha=0.1, lw=2, linestyle='-') ### Infectious patients, not isolated # ax.plot(time_domain, self.scenario.infectious, label='Infected', color=TABLEAU_RED, alpha=0.5, lw=2, linestyle='-') ### Recovered/immune, usually too tall # ax.plot(time_domain, self.scenario.sum_recovered, label='Recovered', color=(0, .5, 0), alpha=.5, lw=2, linestyle='--') ### Infected, isolated at home # ax.plot(time_domain, self.scenario.sum_isolated, label='Home Iso', color=TAB_COLORS[8], alpha=.5, lw=2, linestyle='-') ### Deceased ax.plot(time_domain, self.scenario.sum_deceased, label='Deceased', color=(.25, .25, 0), alpha=.5, lw=2, linestyle='--') #------------- # Hospital Capacities #------------- # ax.plot(time_domain, self.scenario.sum_floor, label='Floor Beds', color=TABLEAU_BLUE, alpha=1, lw=2, linestyle='--') # ax.plot(time_domain, self.scenario.sum_icu, label='ICU Beds', color=TABLEAU_GREEN, alpha=1, lw=2, linestyle='--') # ax.plot(time_domain, self.scenario.sum_vent, label='ICU + Vent Beds', color=TABLEAU_RED, alpha=1, lw=2, linestyle='--') ax.plot(time_domain, hospitalized, label='Total Hospitalized', color=(1, 0, 0), alpha=.25, lw=2, linestyle='-') #------------- # Hospital Capacities - DH Specific #------------- # ax.plot(time_domain, [86] * (self.total_days + 1) , label='Supply - DH ICU Beds' , color=(1, 0, 0), alpha=1, lw=1, linestyle='-') # ax.plot(time_domain, [229] * (self.total_days + 1), label='Supply - DH Total Beds', color=(0, 0, 1), alpha=1, lw=1, linestyle='-') #------------- # Hospital Capacities - Denver County #------------- # ax.plot(time_domain, [695] * (self.total_days + 1) , label='Supply - 5C ICU Beds' , color=(1, 0, 0), alpha=1, lw=1, linestyle='-') # ax.plot(time_domain, [5907] * (self.total_days + 1), label='Supply - 5C Total Beds', color=(0, 0, 1), alpha=1, lw=1, linestyle='-') # ax.plot(time_domain, [1043] * (self.total_days + 1), label='Supply - 5C ICU Beds' , color=(1, 0, 0), alpha=1, lw=1, linestyle='-') # ax.plot(time_domain, [8861] * (self.total_days + 1), label='Supply - 5C Total Beds', color=(0, 0, 1), alpha=1, lw=1, linestyle='-') #------------- # Hospital Capacities - Five County #------------- # ax.plot(time_domain, [255] * (self.total_days + 1) , label='Supply - 5C ICU Beds' , color=(1, 0, 0), alpha=1, lw=1, linestyle='-') # ax.plot(time_domain, [1000] * (self.total_days + 1), label='Supply - 5C Total Beds', color=(0, 0, 1), alpha=1, lw=1, linestyle='-') # ax.plot(time_domain, [1043] * (self.total_days + 1), label='Supply - 5C ICU Beds' , color=(1, 0, 0), alpha=1, lw=1, linestyle='-') # ax.plot(time_domain, [4135] * (self.total_days + 1), label='Supply - 5C Total Beds', color=(0, 0, 1), alpha=1, lw=1, linestyle='-') # ------------ # Hospital Capacities - Five County - 50% # ------------ # ax.plot(time_domain, [348] * (model.total_days + 1) , label='Supply - 5County ICU', color=(0, 0, 1), alpha=1, lw=1, linestyle='--') # ax.plot(time_domain, [2954] * (model.total_days + 1), label='Supply - 5County Tot', color=(1, 0, 0), alpha=1, lw=1, linestyle='-') # ax.plot(time_domain, [521] * (model.total_days + 1) , label='1.5x 5County ICU' , color=(0, 0, 1), alpha=1, lw=1, linestyle='--') # ax.plot(time_domain, [4430] * (model.total_days + 1), label='1.5x 5County Tot' , color=(1, 0, 0), alpha=1, lw=1, linestyle='-') #make pretty # set the style of the axes and the text color plt.rcParams['axes.edgecolor'] = '#333F4B' plt.rcParams['axes.linewidth'] = 0.8 plt.rcParams['xtick.color'] = '#333F4B' plt.rcParams['ytick.color'] = '#333F4B' plt.rcParams['text.color'] = '#333F4B' # set axis ax.tick_params(axis='both', which='major', labelsize=12) ax.set_xlabel('Days') ax.set_ylabel('Number') chart_title = self.modelname plt.title(chart_title, fontsize=14) # ax.set_ylim(0,1.2) ax.yaxis.set_tick_params(length=4) ax.xaxis.set_tick_params(length=4) # ax.grid(b=True, which='minor', c='w', lw=1, ls='--') ax.grid() legend = ax.legend() legend.get_frame().set_alpha(0.5) for spine in ('top', 'right', 'bottom', 'left'): ax.spines[spine].set_visible(False) return plt def generate_csv(self): chart_title = self.modelname outfilename = "_".join( chart_title.replace("|", " ").replace(":", " ").replace(".", " ").split()) # Write a CSV to this directory with open(f"{outfilename}.csv", 'w') as outfile: for itr in range(0, len(self.scenario.out_susceptible)): outfile.write(f"{self.scenario.out_susceptible[itr]:.6f}, " f"{self.scenario.out_incubating[itr]:.6f}, " f"{self.scenario.out_infectious[itr]:.6f}, " f"{self.scenario.sum_isolated[itr]:.6f}, " f"{self.scenario.sum_noncrit[itr]:.6f}, " f"{self.scenario.sum_icu[itr]:.6f}, " f"{self.scenario.sum_icu_vent[itr]:.6f}, " f"{self.scenario.sum_recovered[itr]:.6f}, " f"{self.scenario.sum_deceased[itr]:.6f}, " f"{self.scenario.sum_hospitalized[itr]:.6f}\n")
class PathsByAge: def __init__(self, subgroupstats, name=None): self.name = name self.stats = subgroupstats # Variables to store state changes # Probability states self.isolated = ProbState(TIMINGS['days home isolation'], name=f"{self.name}: isolated") self.nevercrit = ProbState(TIMINGS['days noncrit'], name=f"{self.name}: nevercrit") self.pre_icu = ProbState(TIMINGS['days preicu'], name=f"{self.name}: pre_icu") self.icu_novent = ProbState(TIMINGS['days icu nonvent'], name=f"{self.name}: icu") self.icu_vent = ProbState(TIMINGS['days icu vent'], name=f"{self.name}: icu_vent") self.post_icu = ProbState(TIMINGS['days posticu'], name=f"{self.name}: post_icu") # Recovered and dead are presumed permanent self.recovered = ProbState(1000, name=f"{self.name}: recovered") self.deceased = ProbState(1000, name=f"{self.name}: deceased") self.isolated.add_exit_state(self.recovered, 1) self.isolated.normalize_states_over_period() self.nevercrit.add_exit_state(self.recovered, 1) self.nevercrit.normalize_states_over_period() self.pre_icu.add_exit_state(self.icu_novent, self.stats.p_icu_nonvent) self.pre_icu.add_exit_state(self.icu_vent, self.stats.p_icu_vent) self.pre_icu.normalize_states_over_period() self.icu_novent.add_exit_state(self.deceased, self.stats.p_icu_death) self.icu_novent.add_exit_state(self.post_icu, self.stats.p_icu_recovery) self.icu_novent.normalize_states_over_period() self.icu_vent.add_exit_state(self.deceased, self.stats.p_icu_death) self.icu_vent.add_exit_state(self.post_icu, self.stats.p_icu_recovery) self.icu_vent.normalize_states_over_period() self.post_icu.add_exit_state(self.recovered, 1) self.post_icu.normalize_states_over_period() def get_floor_counts(self): retval = [] for itr in range(0, len(self.nevercrit.domain)): val = self.nevercrit.domain[itr] + self.pre_icu.domain[ itr] + self.post_icu.domain[itr] retval.append(val) return retval def get_icu_counts(self): retval = [] for itr in range(0, len(self.icu_novent.domain)): val = self.icu_novent.domain[itr] + self.icu_vent.domain[itr] retval.append(val) return retval # Add N people to the list of infected def apply_infections(self, infections): inf_float = float(infections) n_isolated = inf_float * self.stats.p_selfisolate n_nevercrit = inf_float * self.stats.p_nevercrit n_pre_icu = inf_float * self.stats.p_pre_icu n_icu_vent = inf_float * self.stats.p_urgent_icu_vent n_icu_novent = inf_float * self.stats.p_urgent_icu_novent # print(f"Storing infections {self.name}: {n_nevercrit}, {n_pre_icu}, {n_icu_vent}, {n_icu_novent}") self.isolated.store_pending(n_isolated) self.nevercrit.store_pending(n_nevercrit) self.pre_icu.store_pending(n_pre_icu) self.icu_vent.store_pending(n_icu_vent) self.icu_novent.store_pending(n_icu_novent) def calculate_redistributions(self): self.isolated.pass_downstream() # self.ed_to_floor.pass_downstream() # self.ed_to_icu.pass_downstream() self.nevercrit.pass_downstream() self.pre_icu.pass_downstream() self.icu_novent.pass_downstream() self.icu_vent.pass_downstream() self.post_icu.pass_downstream() def apply_pending(self): self.isolated.apply_pending() # self.ed_to_floor.apply_pending() # self.ed_to_icu.apply_pending() self.nevercrit.apply_pending() self.pre_icu.apply_pending() self.icu_novent.apply_pending() self.icu_vent.apply_pending() self.post_icu.apply_pending() self.recovered.apply_pending() self.deceased.apply_pending()
class HospFloorModel: def __init__(self, scenario): if isinstance(scenario, str): self.scenario = EpiScenario(scenario) elif isinstance(scenario, EpiScenario): self.scenario = scenario self.modelname = self.scenario.modelname self.total_days = 0 self.r0 = self.scenario.parameters['initial_r0'] self.beta = None self.population = self.scenario.totalpop self.susceptible = ProbState(period=0, count=self.scenario.init_susceptible, name='susceptible') self.incubating = ProbState(period=self.scenario.incubation_period, count=self.scenario.init_infected, name='incubating') self.infectious = ProbState(period=self.scenario.prediagnosis, count=self.scenario.init_infectious, name='infectious') self.isolated_holding = ProbState(period=90, name='isolated_holding') self.incubating.add_exit_state(self.infectious, 1) self.incubating.normalize_states_over_period() self.infectious.add_exit_state(self.isolated_holding, 1) self.infectious.normalize_states_over_period() self.subgroups = dict() for key, value in self.scenario.subgrouprates.items(): self.subgroups[key] = PathsByAge(value, name=key) self.fitness = None def run(self): self.run_r0_set(self.scenario.r0_date_offsets, self.scenario.r0_values) def set_r0(self, value): self.r0 = value def run_r0_set(self, date_offsets, r0_values): day_counter = 0 for itr in range(0, len(date_offsets)): self.set_r0(r0_values[itr]) self.beta = calc_beta(self.r0, self.dayspergen) print(f"{self.beta} = {calc_beta(self.r0, self.dayspergen)})") while day_counter < date_offsets[itr]: self.step_day() day_counter += 1 def step_day(self): new_infections = self.beta * self.susceptible.count * self.infectious.count / self.population # print(f"Day {self.total_days} infections: {new_infections} = {self.beta} * {self.susceptible.count} * {self.infectious.count} / {self.population}") self.susceptible.store_pending(-new_infections) self.incubating.store_pending(new_infections) self.incubating.pass_downstream() self.infectious.pass_downstream() diagnosed = self.isolated_holding.pending self.isolated_holding.pending = 0 subpop_out = [] for key, agegroup in self.subgroups.items(): subpop = diagnosed * agegroup.stats.pop_dist subpop_out.append(subpop) agegroup.apply_infections(subpop) agegroup.calculate_redistributions() self.susceptible.apply_pending() self.incubating.apply_pending() self.infectious.apply_pending() for key, agegroup in self.subgroups.items(): agegroup.apply_pending() self.total_days += 1 def gather_sums(self): self.scenario.out_susceptible = self.susceptible.domain self.scenario.out_incubating = self.incubating.domain self.scenario.out_infectious = self.infectious.domain time_increments = len(self.susceptible.domain) self.scenario.sum_isolated = [0] * time_increments self.scenario.sum_floor = [0] * time_increments self.scenario.sum_icu = [0] * time_increments self.scenario.sum_vent = [0] * time_increments self.scenario.sum_recovered = [0] * time_increments self.scenario.sum_deceased = [0] * time_increments self.scenario.sum_hospitalized = [0] * time_increments for key, value in self.subgroups.items(): self.scenario.sum_isolated = np.add(self.scenario.sum_isolated, value.isolated.domain) self.scenario.sum_floor = np.add(self.scenario.sum_floor, value.get_floor_counts()) self.scenario.sum_icu = np.add(self.scenario.sum_icu, value.get_icu_counts()) self.scenario.sum_vent = np.add(self.scenario.sum_vent, value.icu_vent.domain) self.scenario.sum_recovered = np.add(self.scenario.sum_recovered, value.recovered.domain) self.scenario.sum_deceased = np.add(self.scenario.sum_deceased, value.deceased.domain) self.scenario.sum_hospitalized = np.add(self.scenario.sum_hospitalized, self.scenario.sum_floor) self.scenario.sum_hospitalized = np.add(self.scenario.sum_hospitalized, self.scenario.sum_icu) def calculate_fit(self, ideal): initial_offset = (ideal['start'] - self.scenario.initial_date).days fitcount = (ideal['end'] - ideal['start']).days final_offset = initial_offset + fitcount + 1 cursor = initial_offset fitcur = 0 hosp = self.scenario.sum_hospitalized dead = self.scenario.sum_deceased hosp_sum = 0 hosp_r2 = 0 dead_sum = 0 dead_r2 = 0 while cursor < final_offset: hosp_sum += hosp[cursor] dead_sum += hosp[cursor] hosp_r2 += (hosp[cursor] - ideal['hospitalized'][fitcur])**2 dead_r2 += (dead[cursor] - ideal['deceased'][fitcur])**2 fitcur += 1 cursor += 1 hosp_hold = math.sqrt(hosp_r2) dead_hold = math.sqrt(dead_r2) hosp_avg = hosp_sum / fitcount dead_avg = dead_sum / fitcount self.scenario.fitness = (hosp_hold / hosp_avg) + (dead_hold / dead_avg) def save_results(self, iteration): result = dict() result['iteration'] = iteration result['fitness'] = self.fitness result['scenario'] = self.scenario.parameters result['modelname'] = self.modelname result['total_days'] = self.total_days result['totalpop'] = self.population result['sum_isolated'] = self.scenario.sum_isolated result['sum_noncrit'] = self.scenario.sum_noncrit result['sum_icu'] = self.scenario.sum_icu result['sum_icu_vent'] = self.scenario.sum_icu_vent result['sum_recovered'] = self.scenario.sum_recovered result['sum_deceased'] = self.scenario.sum_deceased with open(f"best_fit{iteration}", "w") as bfi: json.dump(result, bfi) def actual_curves(self): cursor = self.scenario.initial_date finaldate = cursor + timedelta(self.scenario.maxdays) act_hosp = [] act_death = [] while cursor < finaldate: if cursor in COLORADO_ACTUAL: act_hosp.append(COLORADO_ACTUAL[cursor]['hospitalized']) act_death.append(COLORADO_ACTUAL[cursor]['deaths']) else: act_hosp.append(None) act_death.append(None) cursor += ONEDAY act_death.append(None) act_hosp.append(None) return act_hosp, act_death def generate_png(self): startdate = self.scenario.initial_date time_domain = [startdate] cursor = startdate for _ in range(0, self.total_days): cursor += ONEDAY time_domain.append(cursor) # time_domain = np.linspace(0, model.total_days, model.total_days + 1) fig = plt.figure(facecolor='w') # ax = fig.add_subplot(111, axis_bgcolor='#dddddd', axisbelow=True) ax = fig.add_subplot(111, axisbelow=True) ### Lines for comparison to actual act_hosp, act_death = self.actual_curves() ### Actual Hospitalized, as specified in the constants ax.plot(time_domain, act_hosp, color=(0, 0, .5), alpha=1, lw=2, label='Actual Hospitalized', linestyle='-') ### Actual Deaths, as specified in the constants ax.plot(time_domain, act_death, color=(0, 0, .5), alpha=1, lw=2, label='Actual Deaths', linestyle='-') ### Susceptible line, usually too tall # ax.plot(time_domain, self.scenario.susceptible, color=(0, 0, 1), alpha=.5, lw=2, label='Susceptible', linestyle='-') ### Recovered/immune, usually too tall # ax.plot(time_domain, self.scenario.sum_recovered, color=(0, .5, 0), alpha=.5, lw=2, label='Recovered', linestyle='--') ### Infected patients who aren't infectious yet # ax.plot(time_domain, self.scenario.incubating, color=TABLEAU_ORANGE, alpha=0.1, lw=2, label='Exposed', linestyle='-') ### Infectious patients who don't know they have it # ax.plot(time_domain, self.scenario.infectious, color=TABLEAU_RED, alpha=0.5, lw=2, label='Infected', linestyle='-') ### Known and unknown infected, isolated at home # ax.plot(time_domain, self.scenario.sum_isolated, color=TAB_COLORS[8], alpha=.5, lw=2, label='Home Iso', linestyle='-') ### Hospital floor patients ax.plot(time_domain, self.scenario.sum_floor, color=TABLEAU_BLUE, alpha=1, lw=2, label='Noncrit', linestyle='--') ### Non-ventilated ICU patients ax.plot(time_domain, self.scenario.sum_icu, color=TABLEAU_GREEN, alpha=1, lw=2, label='ICU', linestyle='--') ### Ventilated ICU patients ax.plot(time_domain, self.scenario.sum_vent, color=TABLEAU_RED, alpha=1, lw=2, label='ICU + Ventilator', linestyle='--') ### Total hospitalized in all areas ax.plot(time_domain, self.scenario.sum_hospitalized, color=(1, 0, 0), alpha=.25, lw=2, label='Total Hospitalized', linestyle='-') ### Deceased ax.plot(time_domain, self.scenario.sum_deceased, color=(0, 0, 0), alpha=.5, lw=2, label='Dead', linestyle=':') ### Max non-icu capacity # ax.plot(time_domain, [229] * (self.total_days + 1), color=(0, 0, 1), alpha=1, lw=1, label='229 Floor beds', linestyle='-') ### Max ICU capacity # ax.plot(time_domain, [86] * (self.total_days + 1), color=(1, 0, 0), alpha=1, lw=1, label='86 ICU units', linestyle='-') ### Vertical line indicating today plt.axvline(x=datetime.today(), alpha=.5, lw=2, label='Today') ax.set_xlabel('Days') ax.set_ylabel('Number') chart_title = self.modelname plt.title(chart_title, fontsize=14) # ax.set_ylim(0,1.2) ax.yaxis.set_tick_params(length=4) ax.xaxis.set_tick_params(length=4) # ax.grid(b=True, which='minor', c='w', lw=1, ls='--') ax.grid() legend = ax.legend() legend.get_frame().set_alpha(0.5) for spine in ('top', 'right', 'bottom', 'left'): ax.spines[spine].set_visible(False) return plt def generate_csv(self): chart_title = self.modelname outfilename = "_".join( chart_title.replace("|", " ").replace(":", " ").replace(".", " ").split()) # Write a CSV to this directory with open(f"{outfilename}.csv", 'w') as outfile: for itr in range(0, len(self.scenario.out_susceptible)): outfile.write(f"{self.scenario.out_susceptible[itr]:.6f}, " f"{self.scenario.out_incubating[itr]:.6f}, " f"{self.scenario.out_infectious[itr]:.6f}, " f"{self.scenario.sum_isolated[itr]:.6f}, " f"{self.scenario.sum_floor[itr]:.6f}, " f"{self.scenario.sum_icu[itr]:.6f}, " f"{self.scenario.sum_vent[itr]:.6f}, " f"{self.scenario.sum_recovered[itr]:.6f}, " f"{self.scenario.sum_deceased[itr]:.6f}, " f"{self.scenario.sum_hospitalized[itr]:.6f}\n")
class AgeAdjustedModel: def __init__(self): self.r0 = 2.65 self.total_days = 0 self.population = POP_DENVER self.beta = None self.susceptible = ProbState(period=0, count=self.population - 1, name='susceptible') self.incubating = ProbState(period=3, name='incubating') self.infectious = ProbState(period=3.8, count=1, name='infectious') self.isolated_holding = ProbState(period=90, name='isolated_holding') self.incubating.add_exit_state(self.infectious, 1) self.incubating.normalize_states_over_period() self.infectious.add_exit_state(self.isolated_holding, 1) self.infectious.normalize_states_over_period() self.subgroups = dict() for key, value in AGE_DISTRIBUTION.items(): self.subgroups[key] = AgeGroup(SubgroupRates(ICD[key], value), name=key) self.sum_isolated = None self.sum_noncrit = None self.sum_icu = None self.sum_icu_vent = None self.sum_recovered = None self.sum_deceased = None def gather_sums(self): # print(f"base:{len(self.susceptible.domain)}") self.sum_isolated = [0] * len(self.susceptible.domain) self.sum_noncrit = [0] * len(self.susceptible.domain) self.sum_icu = [0] * len(self.susceptible.domain) self.sum_icu_vent = [0] * len(self.susceptible.domain) self.sum_recovered = [0] * len(self.susceptible.domain) self.sum_deceased = [0] * len(self.susceptible.domain) # print(f"final isolated 0-9:{len(self.subgroups['0-9'].isolated.domain)} {self.subgroups['0-9'].isolated.pending}, {self.subgroups['0-9'].isolated.count}") for key, value in self.subgroups.items(): # print(f"adding isolated {key}: {self.sum_isolated} {value.isolated.domain}") self.sum_isolated = np.add(self.sum_isolated, value.isolated.domain) self.sum_noncrit = np.add(self.sum_noncrit, value.h_noncrit.domain) self.sum_icu = np.add(self.sum_icu, value.h_icu.domain) self.sum_icu_vent = np.add(self.sum_icu_vent, value.h_icu_vent.domain) self.sum_recovered = np.add(self.sum_recovered, value.recovered.domain) self.sum_deceased = np.add(self.sum_deceased, value.deceased.domain) def reset(self): self.total_days = 0 self.susceptible.reset() self.susceptible.count = self.population - 1 self.incubating.reset() self.infectious.reset() self.infectious.count = 1 self.subgroups = dict() for key, value in AGE_DISTRIBUTION.items(): self.subgroups[key] = AgeGroup(SubgroupRates(ICD[key], value), name=key) def set_r0(self, value): self.r0 = value def set_population(self, value): self.population = value def run_period(self, days): # Integrate the SIR equations over the time grid, t. for _ in range(0, days): self.step_day() def run_r0_set(self, date_offsets, r0_values): self.reset() day_counter = 0 for itr in range(0, len(date_offsets)): self.set_r0(r0_values[itr]) self.beta = calc_beta(self.r0, self.dayspergen) while day_counter < date_offsets[itr]: self.step_day() day_counter += 1 def step_day(self): new_infections = self.beta * self.susceptible.count * self.infectious.count / self.population # print(f"Day {self.total_days}, {self.beta} * {self.susceptible.count} * {self.infectious.count} / {self.population} = {new_infections}") self.susceptible.store_pending(-new_infections) self.incubating.store_pending(new_infections) self.incubating.pass_downstream() self.infectious.pass_downstream() diagnosed = self.isolated_holding.pending self.isolated_holding.pending = 0 for key, agegroup in self.subgroups.items(): subpop = diagnosed * agegroup.stats.pop_dist agegroup.apply_infections(subpop) agegroup.calculate_redistributions() self.susceptible.apply_pending() self.incubating.apply_pending() self.infectious.apply_pending() for key, agegroup in self.subgroups.items(): agegroup.apply_pending() self.total_days += 1