diff --git a/cara/apps/calculator/model_generator.py b/cara/apps/calculator/model_generator.py index bdb1cf80..720e7179 100644 --- a/cara/apps/calculator/model_generator.py +++ b/cara/apps/calculator/model_generator.py @@ -242,16 +242,35 @@ class FormData: ) return exposed - def coffee_break_times(self) -> typing.Tuple[typing.Tuple[int, int]]: + def _compute_breaks_in_interval(self, start, finish, n_breaks) -> typing.Tuple[typing.Tuple[int, int]]: + break_delay = ((finish - start) - (n_breaks * self.coffee_duration)) // (n_breaks+1) + break_times = [] + end = start + for n in range(n_breaks): + begin = end + break_delay + end = begin + self.coffee_duration + break_times.append((begin, end)) + return tuple(break_times) + + def coffee_break_times(self) -> typing.Tuple[typing.Tuple[int, int]]: if not self.coffee_breaks: return () - coffee_period = (self.activity_finish - self.activity_start) // self.coffee_breaks - coffee_times = [] - for minute in range(self.activity_start, self.activity_finish, coffee_period): - start = minute + coffee_period // 2 - end = start + self.coffee_duration - coffee_times.append((start, end)) - return tuple(coffee_times) + if self.lunch_option: + time_before_lunch = self.lunch_start - self.activity_start + time_after_lunch = self.activity_finish - self.lunch_finish + before_lunch_frac = time_before_lunch / (time_before_lunch + time_after_lunch) + n_morning_breaks = round(self.coffee_breaks * before_lunch_frac) + breaks = ( + self._compute_breaks_in_interval( + self.activity_start, self.lunch_start, n_morning_breaks + ) + + self._compute_breaks_in_interval( + self.lunch_finish, self.activity_finish, self.coffee_breaks - n_morning_breaks + ) + ) + else: + breaks = self._compute_breaks_in_interval(self.activity_start, self.activity_finish, self.coffee_breaks) + return breaks def present_interval(self, start, finish) -> models.Interval: leave_times = [] diff --git a/cara/apps/calculator/templates/report.html.j2 b/cara/apps/calculator/templates/report.html.j2 index 451e60f2..3701f2e2 100644 --- a/cara/apps/calculator/templates/report.html.j2 +++ b/cara/apps/calculator/templates/report.html.j2 @@ -178,4 +178,4 @@ We do not assume responsibility for any injury or damage to persons or property arising out of or related to any use of this app.

- \ No newline at end of file + diff --git a/cara/tests/apps/calculator/test_model_generator.py b/cara/tests/apps/calculator/test_model_generator.py index 64c741c9..57779c6b 100644 --- a/cara/tests/apps/calculator/test_model_generator.py +++ b/cara/tests/apps/calculator/test_model_generator.py @@ -116,7 +116,7 @@ def test_infected_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.0)) + correct = ((10, 10+37/60), (10+52/60, 12.5), (13.5, 15.0)) assert baseline_form.infected_present_interval().present_times == correct @@ -129,9 +129,43 @@ def test_exposed_present_intervals(baseline_form): baseline_form.lunch_finish = 13 * 60 + 30 baseline_form.infected_start = 10 * 60 baseline_form.infected_finish = 15 * 60 - correct = ((9, 11), (11.25, 12.5), (13.5, 15), (15.25, 17.0)) + correct = ((9, 10+37/60), (10+52/60, 12.5), (13.5, 15+7/60), (15+22/60, 17.0)) assert baseline_form.exposed_present_interval().present_times == correct + +def test_coffee_lunch_breaks(baseline_form): + baseline_form.coffee_duration = 30 + baseline_form.coffee_breaks = 4 + baseline_form.activity_start = 9 * 60 + baseline_form.activity_finish = 18 * 60 + baseline_form.lunch_start = 12 * 60 + 30 + baseline_form.lunch_finish = 13 * 60 + 30 + correct = ((9, 9+50/60), (10+20/60, 11+10/60), (11+40/60, 12+30/60), + (13+30/60, 14+40/60), (15+10/60, 16+20/60), (16+50/60, 18)) + np.testing.assert_allclose(baseline_form.exposed_present_interval().present_times, correct, rtol=1e-14) + + +def test_coffee_lunch_breaks_unbalance(baseline_form): + baseline_form.coffee_duration = 30 + baseline_form.coffee_breaks = 2 + baseline_form.activity_start = 9 * 60 + baseline_form.activity_finish = 13 * 60 + 30 + baseline_form.lunch_start = 12 * 60 + 30 + baseline_form.lunch_finish = 13 * 60 + 30 + correct = ((9, 9+50/60), (10+20/60, 11+10/60), (11+40/60, 12+30/60) ) + np.testing.assert_allclose(baseline_form.exposed_present_interval().present_times, correct, rtol=1e-14) + + +def test_coffee_breaks(baseline_form): + baseline_form.coffee_duration = 10 + baseline_form.coffee_breaks = 4 + baseline_form.activity_start = 9 * 60 + baseline_form.activity_finish = 10 * 60 + baseline_form.lunch_option = False + correct = ((9, 9+4/60), (9+14/60, 9+18/60), (9+28/60, 9+32/60), (9+42/60, 9+46/60), (9+56/60, 10)) + np.testing.assert_allclose(baseline_form.exposed_present_interval().present_times, correct, rtol=1e-14) + + def test_key_validation(baseline_form_data): baseline_form_data['activity_type'] = 'invalid key' with pytest.raises(ValueError):