From aafc6f3b9f4339eed311c6a35cc8da6795160ef9 Mon Sep 17 00:00:00 2001 From: markus Date: Fri, 6 Nov 2020 15:30:43 +0100 Subject: [PATCH 1/3] use infected_start/finish to calculate present_intervals and coffee_times --- cara/apps/calculator/model_generator.py | 32 +++++++++++++------ .../apps/calculator/test_model_generator.py | 10 +++--- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/cara/apps/calculator/model_generator.py b/cara/apps/calculator/model_generator.py index efef71a9..4986d2dc 100644 --- a/cara/apps/calculator/model_generator.py +++ b/cara/apps/calculator/model_generator.py @@ -3,6 +3,7 @@ from dataclasses import dataclass import typing from cara import models +from typing import List, Tuple @dataclass @@ -12,6 +13,8 @@ class FormData: activity_finish: int lunch_start: int lunch_finish: int + infected_start: int + infected_finish: int activity_type: str air_changes: float @@ -40,6 +43,7 @@ class FormData: window_width: float windows_number: int windows_open: str + coffee_times: List[Tuple[int, int]] @classmethod def from_dict(cls, form_data: typing.Dict) -> "FormData": @@ -90,7 +94,10 @@ class FormData: window_height=float(form_data['window_height']), window_width=float(form_data['window_width']), windows_number=int(form_data['windows_number']), - windows_open=form_data['windows_open'] + windows_open=form_data['windows_open'], + infected_start=time_string_to_minutes(form_data['infected_start']), + infected_finish=time_string_to_minutes(form_data['infected_finish']), + coffee_times=[] ) # TODO: Remove the tmp_raw_form_data usage. @@ -142,8 +149,11 @@ class FormData: leave_times = [self.lunch_start] enter_times = [self.lunch_finish] for minute in range(self.activity_start, self.activity_finish, coffee_period): - leave_times.append(minute + coffee_period // 2) - enter_times.append(minute + coffee_period // 2 + self.coffee_duration) + start = minute + coffee_period // 2 + end = start + self.coffee_duration + self.coffee_times.append((start, end)) + leave_times.append(start) + enter_times.append(end) # These lists represent the times where the infected person leaves or enters the room, respectively, sorted in # reverse order. Note that these lists allows the person to "leave" when they should not even be present in the @@ -154,20 +164,20 @@ class FormData: # This loop iterates through the lists above, populating present_intervals with (enter, leave) intervals # representing the infected person entering and leaving the room. Note that if one of the evenly spaced coffee- # breaks happens to coincide with the lunch-break, it is simply ignored. - is_present = True present_intervals = [] - time = self.activity_start - while time < self.activity_finish: + time = self.infected_start + is_present = True + while time < self.infected_finish: if is_present: if not leave_times: - present_intervals.append((time / 60, self.activity_finish / 60)) + present_intervals.append((time / 60, self.infected_finish / 60)) break - if leave_times[-1] < time: + if leave_times[-1] <= time: leave_times.pop() else: new_time = leave_times.pop() - present_intervals.append((time / 60, min(new_time, self.activity_finish) / 60)) + present_intervals.append((time / 60, min(new_time, self.infected_finish) / 60)) is_present = False time = new_time @@ -250,12 +260,14 @@ def baseline_raw_form_data(): 'air_changes': '', 'air_supply': '', 'ceiling_height': '', - 'coffee_breaks': '5', + 'coffee_breaks': '2', 'coffee_duration': '10', 'coffee_option': '1', 'event_type': 'single_event', 'floor_area': '', 'hepa_option': '0', + 'infected_finish': '15:00', + 'infected_start': '10:00', 'infected_people': '1', 'lunch_finish': '13:30', 'lunch_option': '1', diff --git a/cara/tests/apps/calculator/test_model_generator.py b/cara/tests/apps/calculator/test_model_generator.py index 040ed5df..48ec0c13 100644 --- a/cara/tests/apps/calculator/test_model_generator.py +++ b/cara/tests/apps/calculator/test_model_generator.py @@ -85,14 +85,14 @@ def test_ventilation_window_hepa(baseline_form): ventilation = models.MultipleVentilation((window,hepa)) baseline_form.ventilation_type = 'natural' - baseline_form.windows_open = '10 min / 2h' + baseline_form.windows_open = 'interval' baseline_form.event_type = 'recurrent_event' baseline_form.recurrent_event_month = 'December' baseline_form.window_height = 1.6 baseline_form.opening_distance = 0.6 baseline_form.hepa_option = True - ts = np.linspace(8, 16, 100) + ts = np.linspace(9, 17, 100) np.testing.assert_allclose([ventilation.air_exchange(room, t) for t in ts], [baseline_form.ventilation().air_exchange(room, t) for t in ts]) @@ -100,12 +100,14 @@ def test_ventilation_window_hepa(baseline_form): def test_present_intervals(baseline_form): baseline_form.coffee_duration = 15 baseline_form.coffee_option = True - baseline_form.coffee_breaks = 4 + baseline_form.coffee_breaks = 2 baseline_form.activity_start = 9 * 60 baseline_form.activity_finish = 17 * 60 baseline_form.lunch_start = 12 * 60 + 30 baseline_form.lunch_finish = 13 * 60 + 30 - correct = ((9, 10), (10.25, 12), (12.25, 12.5), (13.5, 14), (14.25, 16), (16.25, 17)) + baseline_form.infected_start = 10 * 60 + baseline_form.infected_finish = 15 * 60 + correct = ((10, 11), (11.25, 12.5), (13.5, 15)) assert baseline_form.present_interval().present_times == correct From 3b597a24670a9a5d5dffb8e514c921287a96763b Mon Sep 17 00:00:00 2001 From: markus Date: Fri, 6 Nov 2020 15:39:06 +0100 Subject: [PATCH 2/3] replace hard-coded values --- cara/apps/calculator/report_generator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cara/apps/calculator/report_generator.py b/cara/apps/calculator/report_generator.py index 22f84977..6b17e4ea 100644 --- a/cara/apps/calculator/report_generator.py +++ b/cara/apps/calculator/report_generator.py @@ -106,8 +106,8 @@ def build_report(model: models.Model, form: FormData): 'activity_type': form.activity_type, 'activity_start': minutes_to_string(form.activity_start), 'activity_finish': minutes_to_string(form.activity_finish), - 'infected_start': minutes_to_string(826), - 'infected_finish': minutes_to_string(827), + 'infected_start': minutes_to_string(form.infected_start), + 'infected_finish': minutes_to_string(form.infected_finish), 'event_type': form.event_type, 'single_event_date': form.single_event_date, 'recurrent_event_month': form.recurrent_event_month, @@ -116,7 +116,7 @@ def build_report(model: models.Model, form: FormData): 'lunch_finish': minutes_to_string(form.lunch_finish), 'coffee_breaks': form.coffee_breaks, 'coffee_duration': form.coffee_duration, - 'coffee_times': [['00:00','00:00'], ['00:00','00:00'], ['00:00','00:00'], ['00:00','00:00']], + 'coffee_times': [[minutes_to_string(start), minutes_to_string(finish)] for start, finish in form.coffee_times], 'mask_wearing': form.mask_wearing, } From 73abcf8596aeb6de0d762406a2752ad6267ae494 Mon Sep 17 00:00:00 2001 From: Phil Elson Date: Fri, 6 Nov 2020 16:12:59 +0100 Subject: [PATCH 3/3] Implement the coffee break method. --- cara/apps/calculator/model_generator.py | 21 +++++++++++-------- cara/apps/calculator/report_generator.py | 2 +- .../apps/calculator/test_model_generator.py | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/cara/apps/calculator/model_generator.py b/cara/apps/calculator/model_generator.py index 4986d2dc..a610a866 100644 --- a/cara/apps/calculator/model_generator.py +++ b/cara/apps/calculator/model_generator.py @@ -3,7 +3,6 @@ from dataclasses import dataclass import typing from cara import models -from typing import List, Tuple @dataclass @@ -43,7 +42,6 @@ class FormData: window_width: float windows_number: int windows_open: str - coffee_times: List[Tuple[int, int]] @classmethod def from_dict(cls, form_data: typing.Dict) -> "FormData": @@ -97,7 +95,6 @@ class FormData: windows_open=form_data['windows_open'], infected_start=time_string_to_minutes(form_data['infected_start']), infected_finish=time_string_to_minutes(form_data['infected_finish']), - coffee_times=[] ) # TODO: Remove the tmp_raw_form_data usage. @@ -144,16 +141,22 @@ class FormData: else: return ventilation - def present_interval(self) -> models.Interval: + def coffee_break_times(self) -> typing.Tuple[typing.Tuple[int, int]]: coffee_period = (self.activity_finish - self.activity_start) // self.coffee_breaks - leave_times = [self.lunch_start] - enter_times = [self.lunch_finish] + coffee_times = [] for minute in range(self.activity_start, self.activity_finish, coffee_period): start = minute + coffee_period // 2 end = start + self.coffee_duration - self.coffee_times.append((start, end)) - leave_times.append(start) - enter_times.append(end) + coffee_times.append((start, end)) + return tuple(coffee_times) + + def present_interval(self) -> models.Interval: + leave_times = [self.lunch_start] + enter_times = [self.lunch_finish] + + for coffee_start, coffee_end in self.coffee_break_times(): + leave_times.append(coffee_start) + enter_times.append(coffee_end) # These lists represent the times where the infected person leaves or enters the room, respectively, sorted in # reverse order. Note that these lists allows the person to "leave" when they should not even be present in the diff --git a/cara/apps/calculator/report_generator.py b/cara/apps/calculator/report_generator.py index 6b17e4ea..7c230296 100644 --- a/cara/apps/calculator/report_generator.py +++ b/cara/apps/calculator/report_generator.py @@ -116,7 +116,7 @@ def build_report(model: models.Model, form: FormData): 'lunch_finish': minutes_to_string(form.lunch_finish), 'coffee_breaks': form.coffee_breaks, 'coffee_duration': form.coffee_duration, - 'coffee_times': [[minutes_to_string(start), minutes_to_string(finish)] for start, finish in form.coffee_times], + 'coffee_times': [[minutes_to_string(start), minutes_to_string(finish)] for start, finish in form.coffee_break_times()], 'mask_wearing': form.mask_wearing, } diff --git a/cara/tests/apps/calculator/test_model_generator.py b/cara/tests/apps/calculator/test_model_generator.py index 48ec0c13..f6eb739c 100644 --- a/cara/tests/apps/calculator/test_model_generator.py +++ b/cara/tests/apps/calculator/test_model_generator.py @@ -107,7 +107,7 @@ def test_present_intervals(baseline_form): baseline_form.lunch_finish = 13 * 60 + 30 baseline_form.infected_start = 10 * 60 baseline_form.infected_finish = 15 * 60 - correct = ((10, 11), (11.25, 12.5), (13.5, 15)) + correct = ((10, 11), (11.25, 12.5), (13.5, 15.0)) assert baseline_form.present_interval().present_times == correct