Skip to content

Commit

Permalink
added test for dynamic occupancy from input form
Browse files Browse the repository at this point in the history
  • Loading branch information
lrdossan committed Jul 19, 2024
1 parent 15d22ce commit c38f69c
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 7 deletions.
6 changes: 4 additions & 2 deletions caimira/apps/calculator/co2_model_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ def __init__(self, **kwargs):
self.data_registry = DataRegistry()

def validate(self):
# Validate population parameters
self.validate_population_parameters()
# Validate population parameters when static occupancy is defined.
# Dynamic population is validated in the generate_dynamic_occupancy method.
if self.occupancy_format == 'static':
self.validate_population_parameters()

# Validate specific inputs - breaks (exposed and infected)
if self.specific_breaks != {}:
Expand Down
2 changes: 1 addition & 1 deletion caimira/apps/calculator/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
'infected_lunch_option': True,
'infected_lunch_start': '12:30',
'infected_people': 1,
'dynamic_infected_occupancy': '[]',
'dynamic_infected_occupancy': NO_DEFAULT,
'infected_start': '08:30',
'inside_temp': NO_DEFAULT,
'location_latitude': NO_DEFAULT,
Expand Down
6 changes: 4 additions & 2 deletions caimira/apps/calculator/model_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ class VirusFormData(FormData):
_DEFAULTS: typing.ClassVar[typing.Dict[str, typing.Any]] = DEFAULTS

def validate(self):
# Validate population parameters
self.validate_population_parameters()
# Validate population parameters when static occupancy is defined.
# Dynamic population is validated in the generate_dynamic_occupancy method.
if self.occupancy_format == 'static':
self.validate_population_parameters()

validation_tuples = [('activity_type', self.data_registry.population_scenario_activity.keys()),
('mechanical_ventilation_type', MECHANICAL_VENTILATION_TYPES),
Expand Down
4 changes: 2 additions & 2 deletions caimira/apps/calculator/report_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def calculate_report_data(form: VirusFormData, model: models.ExposureModel, exec
# Probabilistic exposure
if form.exposure_option == "p_probabilistic_exposure" and form.occupancy_format == "static":
prob_probabilistic_exposure = np.array(model.total_probability_rule()).mean()
else: prob_probabilistic_exposure = 0
else: prob_probabilistic_exposure = -1
# Expected new cases
if (form.occupancy_format == "static"):
expected_new_cases = np.array(model.expected_new_cases()).mean()
Expand Down Expand Up @@ -479,7 +479,7 @@ def scenario_statistics(
# It means we have data to calculate the total_probability_rule
prob_probabilistic_exposure = model.total_probability_rule()
else:
prob_probabilistic_exposure = 0.
prob_probabilistic_exposure = -1

if (compute_expected_new_cases):
expected_new_cases = np.mean(model.expected_new_cases())
Expand Down
60 changes: 60 additions & 0 deletions caimira/tests/apps/calculator/test_report_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from functools import partial
import os
import time
import json

import numpy as np
import pytest
Expand Down Expand Up @@ -115,3 +116,62 @@ def test_expected_new_cases(baseline_form_with_sr: VirusFormData):

lr_expected_new_cases = alternative_statistics['stats']['Base scenario without short-range interactions']['expected_new_cases']
np.testing.assert_almost_equal(sr_lr_expected_new_cases, lr_expected_new_cases + sr_lr_prob_inf * baseline_form_with_sr.short_range_occupants, 2)


def test_static_vs_dynamic_occupancy_from_form(baseline_form_data, data_registry):
"""
Assert that the results between a static and dynamic occupancy model (from form inputs) are similar.
"""
executor_factory = partial(
concurrent.futures.ThreadPoolExecutor, 1,
)

# By default the baseline form accepts static occupancy
static_occupancy_baseline_form: VirusFormData = VirusFormData.from_dict(baseline_form_data, data_registry)
static_occupancy_model = static_occupancy_baseline_form.build_model()
static_occupancy_report_data = calculate_report_data(static_occupancy_baseline_form, static_occupancy_model, executor_factory)

# Update the initial form data to include dynamic occupancy (please note the 4 coffee and 1 lunch breaks)
baseline_form_data['occupancy_format'] = 'dynamic'
baseline_form_data['dynamic_infected_occupancy'] = json.dumps([
{'total_people': 1, 'start_time': '09:00', 'finish_time': '10:03'},
{'total_people': 0, 'start_time': '10:03', 'finish_time': '10:13'},
{'total_people': 1, 'start_time': '10:13', 'finish_time': '11:16'},
{'total_people': 0, 'start_time': '11:16', 'finish_time': '11:26'},
{'total_people': 1, 'start_time': '11:26', 'finish_time': '12:30'},
{'total_people': 0, 'start_time': '12:30', 'finish_time': '13:30'},
{'total_people': 1, 'start_time': '13:30', 'finish_time': '14:53'},
{'total_people': 0, 'start_time': '14:53', 'finish_time': '15:03'},
{'total_people': 1, 'start_time': '15:03', 'finish_time': '16:26'},
{'total_people': 0, 'start_time': '16:26', 'finish_time': '16:36'},
{'total_people': 1, 'start_time': '16:36', 'finish_time': '18:00'},
])
baseline_form_data['dynamic_exposed_occupancy'] = json.dumps([
{'total_people': 9, 'start_time': '09:00', 'finish_time': '10:03'},
{'total_people': 0, 'start_time': '10:03', 'finish_time': '10:13'},
{'total_people': 9, 'start_time': '10:13', 'finish_time': '11:16'},
{'total_people': 0, 'start_time': '11:16', 'finish_time': '11:26'},
{'total_people': 9, 'start_time': '11:26', 'finish_time': '12:30'},
{'total_people': 0, 'start_time': '12:30', 'finish_time': '13:30'},
{'total_people': 9, 'start_time': '13:30', 'finish_time': '14:53'},
{'total_people': 0, 'start_time': '14:53', 'finish_time': '15:03'},
{'total_people': 9, 'start_time': '15:03', 'finish_time': '16:26'},
{'total_people': 0, 'start_time': '16:26', 'finish_time': '16:36'},
{'total_people': 9, 'start_time': '16:36', 'finish_time': '18:00'},
])
baseline_form_data['total_people'] = 0
baseline_form_data['infected_people'] = 0

dynamic_occupancy_baseline_form: VirusFormData = VirusFormData.from_dict(baseline_form_data, data_registry)
dynamic_occupancy_model = dynamic_occupancy_baseline_form.build_model()
dynamic_occupancy_report_data = calculate_report_data(dynamic_occupancy_baseline_form, dynamic_occupancy_model, executor_factory)

assert (list(sorted(static_occupancy_model.concentration_model.infected.presence.transition_times())) ==
list(dynamic_occupancy_model.concentration_model.infected.number.transition_times))
assert (list(sorted(static_occupancy_model.exposed.presence.transition_times())) ==
list(dynamic_occupancy_model.exposed.number.transition_times))

np.testing.assert_almost_equal(static_occupancy_report_data['prob_inf'], dynamic_occupancy_report_data['prob_inf'], 1)
assert dynamic_occupancy_report_data['expected_new_cases'] == -1
assert dynamic_occupancy_report_data['prob_probabilistic_exposure'] == -1

0 comments on commit c38f69c

Please sign in to comment.