diff --git a/caimira/apps/calculator/__init__.py b/caimira/apps/calculator/__init__.py index be8de7ab..74435939 100644 --- a/caimira/apps/calculator/__init__.py +++ b/caimira/apps/calculator/__init__.py @@ -42,7 +42,7 @@ # calculator version. If the calculator needs to make breaking changes (e.g. change # form attributes) then it can also increase its MAJOR version without needing to # increase the overall CAiMIRA version (found at ``caimira.__version__``). -__version__ = "4.15.1" +__version__ = "4.15.2" LOG = logging.getLogger("Calculator") diff --git a/caimira/apps/calculator/defaults.py b/caimira/apps/calculator/defaults.py index 4976d266..e12664eb 100644 --- a/caimira/apps/calculator/defaults.py +++ b/caimira/apps/calculator/defaults.py @@ -73,6 +73,7 @@ 'sensor_in_use': '', 'short_range_option': 'short_range_no', 'short_range_interactions': '[]', + 'short_range_occupants': 0, } # ------------------ Activities ---------------------- diff --git a/caimira/apps/calculator/model_generator.py b/caimira/apps/calculator/model_generator.py index 4a305418..5d6e1a34 100644 --- a/caimira/apps/calculator/model_generator.py +++ b/caimira/apps/calculator/model_generator.py @@ -72,6 +72,7 @@ class VirusFormData(FormData): sensor_in_use: str short_range_option: str short_range_interactions: list + short_range_occupants: int _DEFAULTS: typing.ClassVar[typing.Dict[str, typing.Any]] = DEFAULTS @@ -182,6 +183,13 @@ def validate(self): if total_percentage != 100: raise ValueError(f'The sum of all respiratory activities should be 100. Got {total_percentage}.') + + # Validate number of people with short-range interactions + max_occupants_for_sr = self.total_people - self.infected_people + if self.short_range_occupants > max_occupants_for_sr: + raise ValueError( + f'The total number of occupants having short-range interactions ({self.short_range_occupants}) should be lower than the exposed population ({max_occupants_for_sr}).' + ) def initialize_room(self) -> models.Room: # Initializes room with volume either given directly or as product of area and height @@ -206,7 +214,6 @@ def build_mc_model(self) -> mc.ExposureModel: room = self.initialize_room() ventilation: models._VentilationBase = self.ventilation() infected_population = self.infected_population() - short_range = [] if self.short_range_option == "short_range_yes": for interaction in self.short_range_interactions: @@ -234,6 +241,7 @@ def build_mc_model(self) -> mc.ExposureModel: geographic_cases=self.geographic_cases, ascertainment_bias=CONFIDENCE_LEVEL_OPTIONS[self.ascertainment_bias], ), + exposed_to_short_range=self.short_range_occupants, ) def build_model(self, sample_size=None) -> models.ExposureModel: diff --git a/caimira/apps/calculator/report_generator.py b/caimira/apps/calculator/report_generator.py index fae89ef5..8ae92987 100644 --- a/caimira/apps/calculator/report_generator.py +++ b/caimira/apps/calculator/report_generator.py @@ -431,7 +431,7 @@ def manufacture_alternative_scenarios(form: VirusFormData) -> typing.Dict[str, m scenarios['Neither ventilation nor masks'] = without_mask_or_vent.build_mc_model() else: - no_short_range_alternative = dataclass_utils.replace(form, short_range_interactions=[]) + no_short_range_alternative = dataclass_utils.replace(form, short_range_interactions=[], total_people=form.total_people - form.short_range_occupants) scenarios['Base scenario without short-range interactions'] = no_short_range_alternative.build_mc_model() return scenarios diff --git a/caimira/apps/calculator/static/js/form.js b/caimira/apps/calculator/static/js/form.js index ed28293e..71023c2a 100644 --- a/caimira/apps/calculator/static/js/form.js +++ b/caimira/apps/calculator/static/js/form.js @@ -869,7 +869,7 @@ function validate_sr_parameter(obj, error_message) { if ($(obj).val() == "" || $(obj).val() == null) { if (!$(obj).hasClass("red_border") && !$(obj).prop("disabled")) { var parameter = document.getElementById($(obj).attr('id')); - insertErrorFor(parameter, error_message) + insertErrorFor(parameter, error_message); $(parameter).addClass("red_border"); } return false; @@ -880,6 +880,22 @@ function validate_sr_parameter(obj, error_message) { } } +function validate_sr_people(obj) { + let sr_total_people = document.getElementById($(obj).attr('id')); + let max = document.getElementById("total_people").valueAsNumber - document.getElementById("infected_people").valueAsNumber; + if ($(obj).val() == "" || $(obj).val() == null || sr_total_people.valueAsNumber > max) { + if (!$(obj).hasClass("red_border")) { + insertErrorFor(sr_total_people, "Value must be less or equal than the number of exposed people."); + $(sr_total_people).addClass("red_border"); + } + return false; + } else { + removeErrorFor($(obj)); + $(obj).removeClass("red_border"); + return true; + } +} + function parseValToNumber(val) { return parseInt(val.replace(':',''), 10); } @@ -1084,7 +1100,6 @@ $(document).ready(function () { validateMaxInfectedPeople(); $("#total_people").change(validateMaxInfectedPeople); $("#activity_type").change(validateMaxInfectedPeople); - $("#total_people").change(validateMaxInfectedPeople); $("#infected_people").change(validateMaxInfectedPeople); //Validate all non zero values @@ -1253,7 +1268,8 @@ $(document).ready(function () { let activity = validate_sr_parameter('#sr_expiration_no_' + String(index)[0], "Required input."); let start = validate_sr_parameter('#sr_start_no_' + String(index)[0], "Required input."); let duration = validate_sr_parameter('#sr_duration_no_' + String(index)[0], "Required input."); - if (activity && start && duration) { + let total_people = validate_sr_people('#short_range_occupants'); + if (activity && start && duration && total_people) { if (validate_sr_time('#sr_start_no_' + String(index)) && validate_sr_time('#sr_duration_no_' + String(index))) { document.getElementById('sr_expiration_no_' + String(index)).disabled = true; document.getElementById('sr_start_no_' + String(index)).disabled = true; diff --git a/caimira/apps/templates/base/calculator.form.html.j2 b/caimira/apps/templates/base/calculator.form.html.j2 index 6842ea63..745612e6 100644 --- a/caimira/apps/templates/base/calculator.form.html.j2 +++ b/caimira/apps/templates/base/calculator.form.html.j2 @@ -584,6 +584,16 @@
+- Short-range interactions: {{ form.short_range_interactions|length }} -
Total number of occupants having short-range interactions: {{ form.short_range_occupants }}