diff --git a/cli.py b/cli.py new file mode 100644 index 00000000..ae26c9ad --- /dev/null +++ b/cli.py @@ -0,0 +1,105 @@ +"""CLI for CHIME.""" + +from argparse import ( + Action, + ArgumentParser, +) +from datetime import datetime + +from pandas import DataFrame + +from penn_chime.defaults import RateLos +from penn_chime.models import Parameters +from penn_chime.utils import build_admissions_df, build_census_df + + +class FromFile(Action): + """From File.""" + + def __call__(self, parser, namespace, values, option_string=None): + with values as f: + parser.parse_args(f.read().split(), namespace) + + +def validator(cast, min_value, max_value): + """Validator.""" + + def validate(string): + """Validate.""" + value = cast(string) + if min_value is not None: + assert value >= min_value + if max_value is not None: + assert value <= max_value + return value + + return validate + + +def parse_args(): + """Parse args.""" + parser = ArgumentParser(description='CHIME') + + parser.add_argument('--file', type=open, action=FromFile) + parser.add_argument( + '--prefix', + type=str, + default=datetime.now().strftime("%Y.%m.%d.%H.%M."), + ) + + for arg, cast, min_value, max_value, help in ( + ('--current-hospitalized', int, 0, None, "Currently Hospitalized COVID-19 Patients (>= 0)"), + ('--doubling-time', float, 0.0, None, "Doubling time before social distancing (days)"), + ('--hospitalized-los', int, 0, None, "Hospitalized Length of Stay (days)"), + ('--hospitalized-rate', float, 0.00001, 1.0, "Hospitalized Rate: 0.00001 - 1.0"), + ('--icu-los', int, 0, None, "ICU Length of Stay (days)"), + ('--icu-rate', float, 0.0, 1.0, "ICU Rate: 0.0 - 1.0"), + ('--known-infected', int, 0, None, + "Currently Known Regional Infections (>=0) (only used to compute detection rate - does not change projections)"), + ('--market_share', float, 0.00001, 1.0, "Hospital Market Share (0.00001 - 1.0)"), + ('--n-days', int, 0, None, "Nuber of days to project >= 0"), + ('--relative-contact-rate', float, 0.0, 1.0, "Social Distancing Reduction Rate: 0.0 - 1.0"), + ('--susceptible', int, 1, None, "Regional Population >= 1"), + ('--ventilated-los', int, 0, None, "Hospitalized Length of Stay (days)"), + ('--ventilated-rate', float, 0.0, 1.0, "Ventilated Rate: 0.0 - 1.0"), + ): + parser.add_argument(arg, type=validator(cast, min_value, max_value)) + return parser.parse_args() + + +def main(): + """Main.""" + a = parse_args() + + p = Parameters( + current_hospitalized=a.current_hospitalized, + doubling_time=a.doubling_time, + known_infected=a.known_infected, + market_share=a.market_share, + relative_contact_rate=a.relative_contact_rate, + susceptible=a.susceptible, + n_days=a.n_days, + hospitalized=RateLos(a.hospitalized_rate, a.hospitalized_los), + icu=RateLos(a.icu_rate, a.icu_los), + ventilated=RateLos(a.ventilated_rate, a.ventilated_los), + ) + + raw_df = DataFrame({ + "Susceptible": p.susceptible_v, + "Infected": p.infected_v, + "Recovered": p.recovered_v, + }) + admits_df = build_admissions_df(p.n_days, *p.dispositions) + census_df = build_census_df(admits_df, *p.lengths_of_stay) + + prefix = a.prefix + for df, name in ( + (raw_df, 'raw'), + (admits_df, 'admits'), + (census_df, 'census'), + ): + df.to_csv(prefix + name + '.csv') + + +if __name__ == '__main__': + main() diff --git a/penn_chime/models.py b/penn_chime/models.py index 07f78c5b..585aea24 100644 --- a/penn_chime/models.py +++ b/penn_chime/models.py @@ -22,7 +22,8 @@ def __init__( icu: RateLos, ventilated: RateLos, - max_y_axis: int + max_y_axis: int = None, + n_days: int = None ): self.current_hospitalized = current_hospitalized self.doubling_time = doubling_time @@ -84,6 +85,13 @@ def __init__( # TODO constrain values np.log2(...) > 0.0 self.doubling_time_t = 1.0 / np.log2(beta * susceptible - gamma + 1) + self.dispositions = None + self.susceptible_v = self.infected_v = self.recovered_v = None + self.hospitalized_v = self.icu_v = self.ventilated_v = None + + if n_days is not None: + self.n_days = n_days + @property def n_days(self): return self._n_days @@ -92,10 +100,6 @@ def n_days(self): def n_days(self, n_days: int): self._n_days = n_days - # s := Susceptible, able to be infected - # i := Infected, currently infected with the virus - # r := Recovered, no longer infected with the virus - s_v, i_v, r_v = sim_sir( self.susceptible, self.infected, diff --git a/settings.cfg b/settings.cfg new file mode 100644 index 00000000..21e54c8d --- /dev/null +++ b/settings.cfg @@ -0,0 +1,13 @@ +--current-hospitalized 6 +--doubling-time 6.0 +--known-infected 157 +--relative-contact-rate 0.0 +--hospitalized-los 7 +--hospitalized-rate 0.05 +--icu-los 9 +--icu-rate 0.02 +--market_share 0.15 +--n-days 60 +--susceptible 4119405 +--ventilated-los 10 +--ventilated-rate 0.01