Merge branch 'feature/repeated-events' into 'master'
Provide a table in the report to show the effect of repeating the event See merge request cara/cara!78
This commit is contained in:
commit
6e3b5587a0
5 changed files with 57 additions and 11 deletions
|
|
@ -38,12 +38,8 @@ class ConcentrationModel(RequestHandler):
|
|||
|
||||
class StaticModel(RequestHandler):
|
||||
def get(self):
|
||||
requested_model_config = model_generator.baseline_raw_form_data()
|
||||
form = model_generator.FormData.from_dict(model_generator.baseline_raw_form_data())
|
||||
model = form.build_model(
|
||||
# TODO: This argument to be removed.
|
||||
tmp_raw_form_data=requested_model_config,
|
||||
)
|
||||
model = form.build_model()
|
||||
report = build_report(model, form)
|
||||
self.finish(report)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import base64
|
||||
import dataclasses
|
||||
from datetime import datetime
|
||||
import io
|
||||
from pathlib import Path
|
||||
|
|
@ -13,6 +14,13 @@ from cara import models
|
|||
from .model_generator import FormData
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class RepeatEvents:
|
||||
repeats: int
|
||||
probability_of_infection: float
|
||||
R0: float
|
||||
|
||||
|
||||
def calculate_report_data(model: models.ExposureModel):
|
||||
resolution = 600
|
||||
|
||||
|
|
@ -27,6 +35,17 @@ def calculate_report_data(model: models.ExposureModel):
|
|||
exposed_occupants = model.exposed.number
|
||||
r0 = model.reproduction_rate()
|
||||
|
||||
repeated_events = []
|
||||
for n in [1, 2, 3, 4, 5, 10, 15, 20]:
|
||||
repeat_model = dataclasses.replace(model, repeats=n)
|
||||
repeated_events.append(
|
||||
RepeatEvents(
|
||||
repeats=n,
|
||||
probability_of_infection=repeat_model.infection_probability(),
|
||||
R0=repeat_model.reproduction_rate(),
|
||||
)
|
||||
)
|
||||
|
||||
return {
|
||||
"times": times,
|
||||
"concentrations": concentrations,
|
||||
|
|
@ -36,6 +55,7 @@ def calculate_report_data(model: models.ExposureModel):
|
|||
"exposed_occupants": exposed_occupants,
|
||||
"R0": r0,
|
||||
"scenario_plot_src": embed_figure(plot(times, concentrations)),
|
||||
"repeated_events": repeated_events,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -98,5 +118,7 @@ def build_report(model: models.ExposureModel, form: FormData):
|
|||
undefined=jinja2.StrictUndefined,
|
||||
)
|
||||
env.filters['minutes_to_time'] = minutes_to_time
|
||||
env.filters['float_format'] = "{0:.2f}".format
|
||||
env.filters['int_format'] = "{:0.0f}".format
|
||||
template = env.get_template("report.html.j2")
|
||||
return template.render(**context)
|
||||
return template.render(**context)
|
||||
|
|
|
|||
|
|
@ -46,4 +46,4 @@ p.result_title {
|
|||
|
||||
.discalimer {
|
||||
font-size: 12pt;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
<title>Report | CARA (COVID Airborne Risk Assessment)</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/calculator/static/css/report.css">
|
||||
<link rel="stylesheet" type="text/css" href="/calculator/static/css/report.css">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
</head>
|
||||
|
||||
<body id="body">
|
||||
|
|
@ -124,12 +125,36 @@
|
|||
|
||||
<p class="result_title">Results:</p>
|
||||
<p class="data_text">
|
||||
In this scenario, the estimated probability of one exposed occupant getting infected P(i) is {{ "{0:.2f}".format(prob_inf) }}% and the estimated basic reproduction rate (R0) is {{ "{0:.2f}".format(R0) }}.
|
||||
In this scenario, the estimated probability of one exposed occupant getting infected P(i) is {{ prob_inf | int_format }}% and the estimated basic reproduction rate (R0) is {{ R0 | float_format }}.
|
||||
<p>
|
||||
<p class="data_title">Exposure graph:</p>
|
||||
<img id="scenario_concentration_plot" src="{{ scenario_plot_src }}">
|
||||
|
||||
<br><br><br><br><br><br><br>
|
||||
<p class="data_title">Repeated events:</p>
|
||||
<p class="data_text">
|
||||
The P(i) and R0 if repeating this scenario event - provided the infected person emits the same amount of viruses each day and the exposed person is subject to the same daily exposure time:
|
||||
|
||||
<table class="table table-striped w-auto">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th># of repeated events</th>
|
||||
<th>P(i)</th>
|
||||
<th>R0</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for repeat_event in repeated_events %}
|
||||
<tr>
|
||||
<td>{{ repeat_event.repeats }}</td>
|
||||
<td>{{ repeat_event.probability_of_infection | int_format }}%</td>
|
||||
<td>{{ repeat_event.R0 | float_format }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
|
||||
<br><br><br>
|
||||
<div style="border: 2px solid black; padding: 15px;">
|
||||
<p class="image"> <img <img align="middle" src="/calculator/static/images/disclaimer.jpg" width="40" height="40"><b>Disclaimer:</b><br><br></p>
|
||||
<p class="discalimer">The risk assessment tool simulates the long range airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 infection thereto. The results DO NOT include short-range airborne exposure (where the physical distance plays a factor) nor the other know modes of transmission of SARS-CoV-2. Hence, this model implies that proper physical distancing, good hand hygiene and other barrier measures are ensured.<br><br>
|
||||
|
|
|
|||
|
|
@ -538,6 +538,9 @@ class ExposureModel:
|
|||
#: The population of non-infected people to be used in the model.
|
||||
exposed: Population
|
||||
|
||||
#: The number of times the exposure event is repeated (default 1).
|
||||
repeats: int = 1
|
||||
|
||||
def quanta_exposure(self) -> float:
|
||||
"""The number of virus quanta per meter^3."""
|
||||
exposure = 0.0
|
||||
|
|
@ -548,7 +551,7 @@ class ExposureModel:
|
|||
|
||||
for start, stop in self.exposed.presence.boundaries():
|
||||
exposure += integrate(self.concentration_model.concentration, start, stop)
|
||||
return exposure
|
||||
return exposure * self.repeats
|
||||
|
||||
def infection_probability(self):
|
||||
exposure = self.quanta_exposure()
|
||||
|
|
|
|||
Loading…
Reference in a new issue