Skip to content

Commit e9b4fbf

Browse files
code is in, have to reset x axis
1 parent 1404983 commit e9b4fbf

File tree

2 files changed

+109
-4
lines changed

2 files changed

+109
-4
lines changed

src/penn_chime/models.py

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ def __init__(self, p: Parameters):
3232
for key, d in p.dispositions.items()
3333
}
3434

35+
self._rates = rates
36+
self._lengths_of_stay = lengths_of_stay
37+
3538
# Note: this should not be an integer.
3639
# We're appoximating infected from what we do know.
3740
# TODO market_share > 0, hosp_rate > 0
@@ -44,8 +47,9 @@ def __init__(self, p: Parameters):
4447
detection_probability = (
4548
p.known_infected / infected if infected > 1.0e-7 else None
4649
)
47-
intrinsic_growth_rate = \
48-
(2.0 ** (1.0 / p.doubling_time) - 1.0) if p.doubling_time > 0.0 else 0.0
50+
51+
# (2.0 ** (1.0 / p.doubling_time) - 1.0) if p.doubling_time > 0.0 else 0.0
52+
intrinsic_growth_rate = self._intrinsic_growth_rate(p.doubling_time)
4953

5054
gamma = 1.0 / recovery_days
5155

@@ -77,7 +81,6 @@ def __init__(self, p: Parameters):
7781
admits_df = build_admits_df(dispositions_df)
7882
census_df = build_census_df(admits_df, lengths_of_stay)
7983

80-
8184
self.susceptible = susceptible
8285
self.infected = infected
8386
self.recovered = recovered
@@ -94,11 +97,113 @@ def __init__(self, p: Parameters):
9497
self.dispositions_df = dispositions_df
9598
self.admits_df = admits_df
9699
self.census_df = census_df
100+
101+
if p.n_days_since_first_hospitalized is not None and p.doubling_time is None:
102+
# optimize doubling_time
103+
argmin_dt = None
104+
min_loss = 2.0**99
105+
censes = dict()
106+
for dt in np.linspace(1,15,29):
107+
censes[dt] = self.run_projection(p, dt)
108+
self.census_df = censes[dt] # log it into state for loss
109+
loss_dt = self.loss_dt(p)
110+
if loss_dt < min_loss:
111+
min_loss = loss_dt
112+
argmin_dt = dt
113+
self.census_df = censes[dt]
114+
p.doubling_time = argmin_dt
115+
#
116+
# update all state dependent on doubling time.
117+
intrinsic_growth_rate = self._intrinsic_growth_rate(p.doubling_time)
118+
gamma = 1 / recovery_days
119+
beta = self._beta(intrinsic_growth_rate, gamma, susceptible, p.relative_contact_rate)
120+
r_t = beta / gamma * susceptible
121+
r_naught = (intrinsic_growth_rate + gamma) / gamma
122+
doubling_time_t = 1.0 / np.log2(beta * susceptible - gamma + 1)
123+
raw_df = sim_sir_df(
124+
susceptible,
125+
infected,
126+
recovered,
127+
beta,
128+
gamma,
129+
p.n_days
130+
)
131+
dispositions_df = build_dispositions_df(raw_df, rates, p.market_share)
132+
admits_df = build_admits_df(dispositions_df)
133+
census_df = build_census_df(admits_df, lengths_of_stay)
134+
135+
self.intrinsic_growth_rate = intrinsic_growth_rate
136+
self.gamma = gamma
137+
self.beta = beta
138+
self.r_t = r_t
139+
self.r_naught = r_naught
140+
self.doubling_time_t = doubling_time_t
141+
self.raw_df = raw_df
142+
self.dispositions_df = dispositions_df
143+
self.admits_df = admits_df
144+
self.census_df = census_df
145+
97146
self.daily_growth = daily_growth_helper(p.doubling_time)
98147
self.daily_growth_t = daily_growth_helper(doubling_time_t)
99148

100149
return None
101150

151+
def run_projection(self, p: Parameters, doubling_time: float) -> pd.DataFrame:
152+
intrinsic_growth_rate = self._intrinsic_growth_rate(doubling_time)
153+
154+
recovery_days = p.recovery_days
155+
market_share = p.market_share
156+
initial_i = 1 / p.hospitalized.rate / market_share
157+
158+
S, I, R = self.susceptible, self.infected, self.recovered
159+
160+
# mean recovery rate (inv_recovery_days)
161+
gamma = 1 / recovery_days
162+
163+
# contact rate
164+
beta = (intrinsic_growth_rate + gamma) / S
165+
166+
n_days = p.n_days
167+
168+
raw_df = sim_sir_df(S,I,R,beta,gamma,n_days)
169+
170+
dispositions_df = build_dispositions_df(raw_df, self._rates, p.market_share)
171+
admits_df = build_admits_df(dispositions_df)
172+
census_df = build_census_df(admits_df, self._lengths_of_stay)
173+
return census_df
174+
175+
def loss_dt(self, p: Parameters) -> float:
176+
"""Squared error: predicted_current_hospitalized vs. actual current hospitalized
177+
178+
gets prediction of current hospitalized from a census_df which
179+
is dependent on a given doubling_time in state.
180+
"""
181+
# get the predicted number of hospitalized today
182+
predicted_current_hospitalized = self.census_df.hospitalized.loc[p.n_days_since_first_hospitalized]
183+
184+
# compare against actual / user inputted number
185+
# we shall optimize squared distance
186+
return (p.current_hospitalized - predicted_current_hospitalized) ** 2
187+
188+
189+
@staticmethod
190+
def _intrinsic_growth_rate(doubling_time: Optional[float]) -> float:
191+
if doubling_time is not None:
192+
return (2.0 ** (1.0 / doubling_time) - 1.0) if doubling_time > 0.0 else 0.0
193+
return 0.0
194+
195+
@staticmethod
196+
def _beta(
197+
intrinsic_growth_rate: float,
198+
gamma: float,
199+
susceptible: float,
200+
relative_contact_rate: float) -> float:
201+
return (
202+
(intrinsic_growth_rate + gamma)
203+
/ susceptible
204+
* (1.0 - relative_contact_rate)
205+
)
206+
102207
###################
103208
## MODEL FUNCS ##
104209
###################

src/penn_chime/presentation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ def display_sidebar(st, d: Constants) -> Parameters:
278278

279279
st.sidebar.markdown("### Spread and Contact Parameters [ℹ]({docs_url}/what-is-chime/parameters)"
280280
.format(docs_url=DOCS_URL))
281-
if st.sidebar.checkbox("I know the number of date of the first hospitalized case in the region."):
281+
if st.sidebar.checkbox("I know the date of the first hospitalized case in the region."):
282282
date_first_hospitalized = date_first_hospitalized_input()
283283
doubling_time = None
284284
else:

0 commit comments

Comments
 (0)