added default number of infected population and made few UI changes

This commit is contained in:
Luis Aleixo 2022-10-03 16:49:54 +01:00
parent 10d743c149
commit c9134679fd
9 changed files with 53 additions and 45 deletions

View file

@ -114,7 +114,7 @@ class FormData:
'infected_lunch_finish': '13:30',
'infected_lunch_option': True,
'infected_lunch_start': '12:30',
'infected_people': _NO_DEFAULT,
'infected_people': 1,
'infected_start': '08:30',
'inside_temp': _NO_DEFAULT,
'location_latitude': _NO_DEFAULT,

View file

@ -131,7 +131,7 @@ def calculate_report_data(form: FormData, model: models.ExposureModel) -> typing
])
prob = np.array(model.infection_probability()).mean()
prob_specific_event = np.array(model.total_probability_rule()).mean()
prob_probabilistic_exposure = np.array(model.total_probability_rule()).mean()
er = np.array(model.concentration_model.infected.emission_rate_when_present()).mean()
exposed_occupants = model.exposed.number
expected_new_cases = np.array(model.expected_new_cases()).mean()
@ -148,7 +148,7 @@ def calculate_report_data(form: FormData, model: models.ExposureModel) -> typing
"cumulative_doses": list(cumulative_doses),
"long_range_cumulative_doses": list(long_range_cumulative_doses),
"prob_inf": prob,
"prob_specific_event": prob_specific_event,
"prob_probabilistic_exposure": prob_probabilistic_exposure,
"emission_rate": er,
"exposed_occupants": exposed_occupants,
"expected_new_cases": expected_new_cases,
@ -274,13 +274,13 @@ def manufacture_alternative_scenarios(form: FormData) -> typing.Dict[str, mc.Exp
return scenarios
def scenario_statistics(mc_model: mc.ExposureModel, sample_times: typing.List[float], specific_event: bool):
def scenario_statistics(mc_model: mc.ExposureModel, sample_times: typing.List[float], probabilistic_exposure: bool):
model = mc_model.build_model(size=_DEFAULT_MC_SAMPLE_SIZE)
if (specific_event):
if (probabilistic_exposure):
# It means we have data to calculate the total_probability_rule
prob_specific_event = np.array(model.total_probability_rule()).mean()
prob_probabilistic_exposure = np.array(model.total_probability_rule()).mean()
else:
prob_specific_event = 0.
prob_probabilistic_exposure = 0.
return {
'probability_of_infection': np.mean(model.infection_probability()),
@ -289,7 +289,7 @@ def scenario_statistics(mc_model: mc.ExposureModel, sample_times: typing.List[fl
np.mean(model.concentration(time))
for time in sample_times
],
'prob_specific_event': prob_specific_event,
'prob_probabilistic_exposure': prob_probabilistic_exposure,
}
@ -312,16 +312,16 @@ def comparison_report(
statistics = {}
if (form.short_range_option == "short_range_yes" and form.exposure_option == "p_probabilistic_exposure"):
specific_event = True
probabilistic_exposure = True
else:
specific_event = False
probabilistic_exposure = False
with executor_factory() as executor:
results = executor.map(
scenario_statistics,
scenarios.values(),
[sample_times] * len(scenarios),
[specific_event] * len(scenarios),
[probabilistic_exposure] * len(scenarios),
timeout=60,
)

View file

@ -66,7 +66,7 @@
content: attr(data-tooltip);
padding: 10px 18px;
min-width: 50px;
max-width: 200px;
max-width: 220px;
width: max-content;
width: -moz-max-content;
border-radius: 6px;
@ -113,4 +113,4 @@
transition-delay: 0.5s; /* Starting after the grow effect */
transition-duration: 0.2s;
transform: translateX(-50%) scaleY(1);
}
}

View file

@ -63,9 +63,11 @@ function require_fields(obj) {
break;
case "p_probabilistic_exposure":
require_population(true);
require_infected(false);
break;
case "p_deterministic_exposure":
require_population(false);
require_infected(true);
break;
case "mask_on":
require_mask(true);
@ -184,6 +186,10 @@ function require_population(option) {
require_input_field("#ascertainment_bias", option);
}
function require_infected(option) {
require_input_field("#infected_people", option);
}
function require_mask(option) {
$("#mask_type_1").prop('required', option);
$("#mask_type_ffp2").prop('required', option);
@ -281,7 +287,7 @@ function on_hepa_option_change() {
})
}
function on_p_recurrent_change() {
function on_exposure_change() {
p_recurrent = $('input[type=radio][name=exposure_option]')
p_recurrent.each(function (index) {
if (this.checked) {
@ -569,6 +575,8 @@ function validate_form(form) {
// Validate cases < population
if ($("#p_probabilistic_exposure").prop('checked')) {
// Set number of infected people as 1
$("#infected_people").val(1);
var geographicPopulationObj = document.getElementById("geographic_population");
var geographicCasesObj = document.getElementById("geographic_cases");
removeErrorFor(geographicCasesObj);
@ -913,9 +921,9 @@ $(document).ready(function () {
// When the exposure_option changes we want to make its respective
// children show/hide.
$("input[type=radio][name=exposure_option]").change(on_p_recurrent_change);
$("input[type=radio][name=exposure_option]").change(on_exposure_change);
// Call the function now to handle forward/back button presses in the browser.
on_p_recurrent_change();
on_exposure_change();
// When the mask_wearing_option changes we want to make its respective
// children show/hide.

View file

@ -303,8 +303,9 @@
<!-- Event Options -->
<b>Event data:</b>
<div data-tooltip="The total no. of occupants in the room. Probabilistic exposure occurring at a given time and location (e.g. meeting or conference), considering the incidence rate in the area.
Indicate the population in a given location and the rolling 7-day average of new reported cases. Specify the confidence level of the data.">
<div data-tooltip="The total no. of occupants in the room.
Deterministic exposure: add no. occupants that are infected.
Probabilistic exposure: event at a given time & location (e.g. meeting or conference), considering the incidence rate in that area.">
<span class="tooltip_text">?</span>
</div><br>
@ -314,26 +315,29 @@
</div>
<div class="form-group mb-1">
<input type="radio" id="p_deterministic_exposure" name="exposure_option" value="p_deterministic_exposure" checked="checked">
<input type="radio" id="p_deterministic_exposure" name="exposure_option" value="p_deterministic_exposure" checked="checked" data-enables="#DIVp_deterministic_exposure">
<label for="p_deterministic_exposure">Deterministic exposure</label>
</div>
<div class="form-group">
<input type="radio" id="p_probabilistic_exposure" name="exposure_option" value="p_probabilistic_exposure" data-enables="#DIVp_probabilistic_exposure">
<label for="p_probabilistic_exposure">Probabilistic exposure (incidence rate)</label>
</div>
<div id="DIVp_probabilistic_exposure" class="tabbed" style="display: none">
<div id="DIVp_deterministic_exposure" class="tabbed" style="display: none">
<div class="form-group row">
<div class="col-sm-4"><label class="col-form-label">Number of infected people: </label></div>
<div class="col-sm-6 pl-0 align-self-center"><input type="number" id="infected_people" class="form-control" name="infected_people" min=1 value=1 required></div>
<div class="col-sm-6 pl-0 align-self-center"><input type="number" id="infected_people" class="form-control" name="infected_people" min=1 value=1></div>
</div>
</div>
<div id="DIVp_probabilistic_exposure" class="tabbed" style="display: none">
<div class="form-group row">
<div class="col-sm-4"><label class="col-form-label">Population:</label></div>
<div class="col-sm-6 pl-0 align-self-center"><input type="number" step="any" id="geographic_population" class="non_zero form-control" name="geographic_population" placeholder="Inhabitants (#)" min="0"></div>
</div>
<div class="form-group row">
<div class="col-sm-4"><label class="col-form-label">New confirmed cases (weekly):</label></div>
<div class="col-sm-6 pl-0 align-self-center"><input type="number" step="any" id="geographic_cases" class="non_zero form-control" name="geographic_cases" placeholder="Cases (#7-day average sum)" min="0"></div>
<div class="col-sm-6 pl-0 align-self-center"><input type="number" step="any" id="geographic_cases" class="non_zero form-control" name="geographic_cases" placeholder="Cases (#7-day rolling average)" min="0"></div>
</div>
<div class="form-group row">
<div class="col-sm-4"><label class="col-form-label">Confidence level:</label></div>

View file

@ -57,7 +57,7 @@
{% if form.short_range_option == "short_range_yes" %}
{% set scenario = alternative_scenarios.stats.values() | first %}
{% set long_range_prob_inf = scenario.probability_of_infection %}
{% set long_range_prob_specific_event = scenario.prob_specific_event if form.exposure_option == 'p_probabilistic_exposure' %}
{% set long_range_prob_probabilistic_exposure = scenario.prob_probabilistic_exposure if form.exposure_option == 'p_probabilistic_exposure' %}
{% else %}
{% set long_range_prob_inf = prob_inf %}
{% endif %}
@ -131,7 +131,7 @@
In this scenario, assuming <b>short-range interactions</b> occur, the <b>probability of one exposed occupant getting infected can go as high as {{ prob_inf | non_zero_percentage }}</b>.
</div>
{% endif %}
{% block specific_event_probability %}
{% block probabilistic_exposure_probability %}
{% if form.exposure_option == "p_probabilistic_exposure" %}
<br>
<div class="align-self-center alert alert-dark mb-0" role="alert">
@ -143,18 +143,15 @@
with {{ form.total_people }} occupants</b>, is
{% if form.short_range_option == 'short_range_yes' %}:
<ul>
<li><b>{{ long_range_prob_specific_event | non_zero_percentage }}</b>, assuming all occupants are exposed equally (i.e. without short-range interactions).</li>
<li><b>{{ prob_specific_event | non_zero_percentage }}</b>, assuming short-range interactions occur.</li>
<li><b>{{ long_range_prob_probabilistic_exposure | non_zero_percentage }}</b>, assuming all occupants are exposed equally (i.e. without short-range interactions).</li>
<li><b>{{ prob_probabilistic_exposure | non_zero_percentage }}</b>, assuming short-range interactions occur.</li>
</ul>
{% else %}
<b>{{ prob_specific_event | non_zero_percentage }}</b>.
<b>{{ prob_probabilistic_exposure | non_zero_percentage }}</b>.
{% endif %}
{% if prob_specific_event > prob_inf %}
<p>The probability of infection is larger than above which signifies that the chosen number of infected occupants in the form was underestimated.</p>
{% endif %}
</div>
{% endif %}
{% endblock %}
{% endblock probabilistic_exposure_probability %}
</div>
{% endblock report_summary %}
</div>

View file

@ -113,24 +113,23 @@ The recommended airflow rate for the HEPA filter should correspond to a total ai
<p>Here we capture the information about the event being simulated.
First enter the number of occupants in the space, if you have a (small) variation in the number of people, please input the average or consider using the expert tool.
Within the number of people occupying the space, you should specify how many are infected.</p>
<p>As an example, for a shared office with 4 people, where one person is infected, we enter 4 occupants and 1 infected person.</p><br/>
<p>In case one would like to simulate an event happening at a given time and location, where the epidemiological situation is known, the tool allows for an estimation of the probability of on-site transmission, considering the chances that a given person in the event is infected.
The user will need to select <b>Specific event</b>, input the number of inhabitants and the the weekly (7-day rolling average) value of new reported laboratory - confirmed cases at the event location, as well as the confidence level of these inputs.
The user will need to select <b>Probabilistic event</b>, input the number of inhabitants and the the weekly (7-day rolling average) value of new reported laboratory - confirmed cases at the event location, as well as the confidence level of these inputs.
The 7-day rolling average consists in the average of the previous 3 days to subsequent 3 days, generally reported by the different public health authorities (e.g. in Switzerland <a href="https://www.covid19.admin.ch/en/epidemiologic/case/d/development?epiRelDev=abs">here</a>).
These two inputs need to the related, i.e. the values of reported new cases and the number of inhabitants shall correspond to the a same geographical location. For example:</p>
<ul>
<li>Population of Geneva, CH: 508 000 inhabitants</li>
<li>New reported cases in the canton of Geneva: 1000 (7-day rolling avg)</li>
<li>New lab reported cases in the canton of Geneva: 1000 (7-day rolling avg)</li>
</ul>
<p>The confidence level allows for an ascertainment bias to the data. The user can add the following options:</p>
<ul>
<li>High - mandatory population wide surveillance</li>
<li>Medium - recommended population wide surveillance</li>
<li>Low - surveillance only for sympotmatic patients</li>
<li>Medium - recommended population-wide surveillance</li>
<li>Low - surveillance only for symptomatic patients</li>
</ul>
<p>Depending on the epidemiological situation in the choosen location, the public health surveillance can be more or less active. The confidence level will provide an ascertainment bias to the data collected by the user.</p>
<p>The higher the incidence rate (i.e. new cases / population) the higher are the chances of having at least one infected occupant participating to the event.
For general and recurrent layout simply select the <b>Recurrent exposure</b> option.</p>
<p>The higher the incidence rate (i.e. new cases / population) the higher are the chances of having at least one infected occupant participating to the event.</p><br>
<p>For general and recurrent layout simply select the <b>Deterministic exposure</b> option. As an example, for a shared office with 4 people, where one person is infected, we enter 4 occupants and 1 infected person.</p><br/>
<br>
<h4>Activity type</h4>
<br>

View file

@ -88,9 +88,9 @@
</div>
{% endif %}
{% block specific_event_probability %}
{% block probabilistic_exposure_probability %}
{{ super() }}
{% endblock specific_event_probability %}
{% endblock probabilistic_exposure_probability %}
{% if (prob_inf > 2) %}
<br>

View file

@ -266,16 +266,16 @@ def test_prob_meet_infected_person(pop, cases, AB, exposed, infected, prob_meet_
@pytest.mark.parametrize(
"population, cm, pop, cases, AB, specific_event_probability",[
"population, cm, pop, cases, AB, probabilistic_exposure_probability",[
[populations[1], known_concentrations(lambda t: 36.),
100000, 68, 5, 2.24124],
[populations[0], known_concentrations(lambda t: 36.),
100000, 68, 5, 1.875652],
])
def test_specific_event_probability(population, cm,
pop, AB, cases, specific_event_probability):
def test_probabilistic_exposure_probability(population, cm,
pop, AB, cases, probabilistic_exposure_probability):
model = ExposureModel(cm, (), population, models.Cases(geographic_population=pop,
geographic_cases=cases, ascertainment_bias=AB))
np.testing.assert_allclose(
model.total_probability_rule(), specific_event_probability, rtol=0.05
model.total_probability_rule(), probabilistic_exposure_probability, rtol=0.05
)