Implement alternative scenarios infrastructure for the calculator.
This commit is contained in:
parent
0fdfbd0eaf
commit
dd60c0ef23
3 changed files with 84 additions and 2 deletions
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;">
|
||||
|
|
|
|||
Loading…
Reference in a new issue