Implement alternative scenarios infrastructure for the calculator.

This commit is contained in:
Phil Elson 2020-11-20 14:03:18 +01:00
parent 0fdfbd0eaf
commit dd60c0ef23
3 changed files with 84 additions and 2 deletions

View file

@ -384,7 +384,7 @@ def baseline_raw_form_data():
'mask_type': 'Type I',
'mask_wearing': 'removed',
'mechanical_ventilation_type': '',
'model_version': 'BetaV1.1.0',
'model_version': 'v1.1.0',
'opening_distance': '0.2',
'recurrent_event_month': 'January',
'room_number': '123',

View file

@ -3,6 +3,7 @@ import dataclasses
from datetime import datetime
import io
from pathlib import Path
import typing
import jinja2
import matplotlib
@ -99,6 +100,59 @@ def minutes_to_time(minutes: int) -> str:
return f"{hour_string}:{minute_string}"
def manufacture_alternative_scenarios(form: FormData) -> typing.Dict[str, models.ExposureModel]:
scenarios = {}
with_mask = dataclasses.replace(form, mask_wearing='continuous')
without_mask = dataclasses.replace(form, mask_wearing='removed')
scenarios['With mask'] = with_mask.build_model()
scenarios['Without mask'] = without_mask.build_model()
return scenarios
def comparison_plot(scenarios: typing.Dict[str, models.ExposureModel]):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
resolution = 350
times = None
for name, model in scenarios.items():
if times is None:
t_start = min(model.exposed.presence.boundaries()[0][0],
model.concentration_model.infected.presence.boundaries()[0][0])
t_end = max(model.exposed.presence.boundaries()[-1][1],
model.concentration_model.infected.presence.boundaries()[-1][1])
times = np.linspace(t_start, t_end, resolution)
concentrations = [model.concentration_model.concentration(time) for time in times]
ax.plot(times, concentrations, label=name)
ax.legend()
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.set_xlabel('Time (hour of day)')
ax.set_ylabel('Concentration ($q/m^3$)')
ax.set_title('Concentration of infectious quanta')
return fig
def comparison_report(scenarios: typing.Dict[str, models.ExposureModel]):
statistics = {}
for name, model in scenarios.items():
statistics[name] = {
'probability_of_infection': model.infection_probability(),
'expected_new_cases': model.expected_new_cases(),
}
return {
'plot': embed_figure(comparison_plot(scenarios)),
'stats': statistics,
}
def build_report(model: models.ExposureModel, form: FormData):
now = datetime.now()
time = now.strftime("%d/%m/%Y %H:%M:%S")
@ -112,6 +166,8 @@ def build_report(model: models.ExposureModel, form: FormData):
}
context.update(calculate_report_data(model))
alternative_scenarios = manufacture_alternative_scenarios(form)
context['alternative_scenarios'] = comparison_report(alternative_scenarios)
cara_templates = Path(__file__).parent.parent / "templates"
calculator_templates = Path(__file__).parent / "templates"

View file

@ -166,7 +166,33 @@
{% endfor %}
</tbody>
</table>
<p>
</p>
<p class="data_title">Alternative scenarios:</p>
<p class="data_text">
<img id="scenario_concentration_plot" src="{{ alternative_scenarios.plot }}" align="left" />
<table class="table table-striped w-auto">
<thead class="thead-light">
<tr>
<th>Scenario</th>
<th>P(i)</th>
<th>Expected new cases</th>
</tr>
</thead>
<tbody>
{% for scenario_name, scenario_stats in alternative_scenarios.stats.items() %}
<tr>
<td>{{ scenario_name }}</td>
<td>{{ scenario_stats.probability_of_infection | int_format }}%</td>
<td style="text-align:right">{{ scenario_stats.expected_new_cases | float_format }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</p>
<div style="clear: both;">
<br><br><br>
<div style="border: 2px solid black; padding: 15px;">