diff --git a/caimira/apps/calculator/defaults.py b/caimira/apps/calculator/defaults.py index a9e9d0f9..22b157aa 100644 --- a/caimira/apps/calculator/defaults.py +++ b/caimira/apps/calculator/defaults.py @@ -19,6 +19,7 @@ DEFAULTS = { 'calculator_version': NO_DEFAULT, 'ceiling_height': 0., 'conditional_probability_plot': False, + 'conditional_probability_viral_loads': False, 'exposed_coffee_break_option': 'coffee_break_0', 'exposed_coffee_duration': 5, 'exposed_finish': '17:30', diff --git a/caimira/apps/calculator/model_generator.py b/caimira/apps/calculator/model_generator.py index ae473ea5..664eef2b 100644 --- a/caimira/apps/calculator/model_generator.py +++ b/caimira/apps/calculator/model_generator.py @@ -35,6 +35,7 @@ class FormData: precise_activity: dict ceiling_height: float conditional_probability_plot: bool + conditional_probability_viral_loads: bool exposed_coffee_break_option: str exposed_coffee_duration: int exposed_finish: minutes_since_midnight @@ -802,6 +803,7 @@ def baseline_raw_form_data() -> typing.Dict[str, typing.Union[str, float]]: 'air_supply': '', 'ceiling_height': '', 'conditional_probability_plot': '0', + 'conditional_probability_viral_loads': '0', 'exposed_coffee_break_option': 'coffee_break_4', 'exposed_coffee_duration': '10', 'exposed_finish': '18:00', diff --git a/caimira/apps/calculator/report_generator.py b/caimira/apps/calculator/report_generator.py index 8297e132..6429729c 100644 --- a/caimira/apps/calculator/report_generator.py +++ b/caimira/apps/calculator/report_generator.py @@ -328,6 +328,18 @@ def non_zero_percentage(percentage: int) -> str: return "99.9%" else: return "{:0.1f}%".format(percentage) + + +def manufacture_viral_load_scenarios_percentiles(model: mc.ExposureModel) -> typing.Dict[str, mc.ExposureModel]: + viral_load = model.concentration_model.infected.virus.viral_load_in_sputum + scenarios = {} + for percentil in (0.01, 0.05, 0.25, 0.5, 0.75, 0.95, 0.99): + vl = np.quantile(viral_load, percentil) + specific_vl_scenario = dataclass_utils.nested_replace(model, + {'concentration_model.infected.virus.viral_load_in_sputum': vl} + ) + scenarios[round(np.log10(vl))] = np.mean(specific_vl_scenario.infection_probability()) + return scenarios def manufacture_alternative_scenarios(form: FormData) -> typing.Dict[str, mc.ExposureModel]: @@ -477,6 +489,7 @@ class ReportGenerator: context.update(report_data) alternative_scenarios = manufacture_alternative_scenarios(form) + context['alternative_viral_load'] = manufacture_viral_load_scenarios_percentiles(model) if form.conditional_probability_viral_loads else None context['alternative_scenarios'] = comparison_report( form, report_data, alternative_scenarios, scenario_sample_times, executor_factory=executor_factory, )