Revert "Automate infected breaks DIV creation in JS"
This reverts commit c8fb1b68f65e41575ba698814e6d835cc3bf389f
This commit is contained in:
parent
bada12692b
commit
ad82e73c27
7 changed files with 436 additions and 242 deletions
|
|
@ -121,7 +121,7 @@ In this case it is assumed that the infected person is the trainer, because this
|
|||
|
||||
You should enter the time (hours:minutes) for the start and end of the simulation period (i.e. 8:30 to 17:30 for a typical office day).
|
||||
It is important to enter the correct times for the simulation, in particular when using natural ventilation.
|
||||
It is possible to specify a different time for the entry and exit of the infected person, however for most cases (where we do not know apriori which of the occupants is infected), it is recommended to set these to the same values as the activity start and end.
|
||||
It is possible to specify a different time for the entry and exit of both the exposed and infected person, however for most cases (where we do not know apriori which of the occupants is infected), it is recommended to set these to the same values as the activity start and end.
|
||||
|
||||
#### When is the event?
|
||||
|
||||
|
|
@ -131,17 +131,17 @@ Only the month is used by the model to retrieve the average outdoor air temperat
|
|||
|
||||
### Breaks
|
||||
|
||||
#### Lunch
|
||||
#### Lunch Break
|
||||
|
||||
You have the option to specify a lunch break.
|
||||
This will be useful if you plan to simulate a typical full working day.
|
||||
During the lunch break it is assumed that all occupants will leave the simulated space (to go an eat lunch, somewhere else - restaurant or break room).
|
||||
During the lunch break it is assumed that all occupants will leave the simulated space (to go eat lunch somewhere else - restaurant or break room).
|
||||
If you plan to eat lunch in the same area where you have been working, you should select 'No' even if a lunch break will be taken, since the risk of infection is related to the occupation of the simulated space.
|
||||
See 'Split Breaks' if the occupants do not break at the same time.
|
||||
|
||||
It should also be noted that the infection probabilities presented in the report does not take into account any potential exposures during the break times.
|
||||
|
||||
|
||||
### Coffee Breaks
|
||||
#### Coffee Breaks
|
||||
|
||||
You have the option to choose 0(No breaks), 2 or 4 coffee breaks during the simulated period.
|
||||
It is assumed that all occupants vacate the space during the break period.
|
||||
|
|
@ -151,10 +151,22 @@ When enabled, the breaks are spread equally throughout the day - for example if
|
|||
The exact timing of the breaks within the day is not particularly critical to an accurate simulation, so you do not need to be concerned about major differences if you take a coffee break at 10:00 instead of 11:00.
|
||||
The variation of coffee breaks can be altered in 5 minute increments up to 30 minutes in length.
|
||||
Note that this doesn't necessarily have to be a coffee break, it can represent any period where the simulated space is vacated.
|
||||
|
||||
See 'Split Breaks' if the occupants do not break at the same time.
|
||||
|
||||
It should also be noted that the infection probabilities presented in the report does not take into account any potential exposures during the break times.
|
||||
|
||||
#### Face Masks
|
||||
#### Split breaks
|
||||
|
||||
You have the option to specify whether the exposed and infected person(s) break at the same time.
|
||||
If not, then you can input separate breaks. This is particularly different when specifying coffee breaks as they are spread evenly throughout the activity times specified.
|
||||
|
||||
If we take an example where the exposed person(s) activity time is from 9:00 to 18:00 and the infected person(s) is from 10:00 to 17:00, with both having a lunch break from 13:00 to 14:00 and have 2 coffee breaks each, we can have two different results:
|
||||
|
||||
1. Specify the default situtaion where both exposed and infected persons(s) have their breaks at the same time: in this case the coffee break times are calculated based on the activity time of the exposed - both will have their first coffee break around 11:00 and the second around 16:00.
|
||||
|
||||
2. Specify separate breaks for the infected person(s): in this case the coffee breaks will be calculated based on the different activity times (i.e. exposed from 9:00 to 18:00 and infected from 10:00 to 17:00) - the exposed person(s) will have their first coffee break around 11:00 and the second around 16:00, whereas the infected will have their first coffee break around 11:30 and the second around 15:30.
|
||||
|
||||
### Face Masks
|
||||
|
||||
The model allows for a simulation with either a continuous wearing of face masks throughout the duration of the event, or have the removed at all times - i.e. all occupants (infected and exposed alike) wear or not masks for the duration of the simulation.
|
||||
Please bear in mind the user inputs shall be aligned with the current applicable public health & safety instructions.
|
||||
|
|
|
|||
|
|
@ -15,24 +15,30 @@ LOG = logging.getLogger(__name__)
|
|||
@dataclass
|
||||
class FormData:
|
||||
# Number of minutes after 00:00
|
||||
activity_start: int
|
||||
activity_finish: int
|
||||
lunch_start: int
|
||||
lunch_finish: int
|
||||
infected_start: int
|
||||
exposed_finish: int
|
||||
exposed_lunch_finish: int
|
||||
exposed_lunch_start: int
|
||||
exposed_start: int
|
||||
infected_finish: int
|
||||
infected_lunch_finish: int #Used if infected_dont_have_breaks_with_exposed
|
||||
infected_lunch_start: int #Used if infected_dont_have_breaks_with_exposed
|
||||
infected_start: int
|
||||
|
||||
activity_type: str
|
||||
air_changes: float
|
||||
air_supply: float
|
||||
ceiling_height: float
|
||||
coffee_breaks: int
|
||||
coffee_duration: int
|
||||
exposed_coffee_breaks: int
|
||||
exposed_coffee_duration: int
|
||||
exposed_lunch_option: bool
|
||||
floor_area: float
|
||||
hepa_amount: float
|
||||
hepa_option: bool
|
||||
infected_coffee_breaks: int #Used if infected_dont_have_breaks_with_exposed
|
||||
infected_coffee_duration: int #Used if infected_dont_have_breaks_with_exposed
|
||||
infected_dont_have_breaks_with_exposed: bool
|
||||
infected_lunch_option: bool #Used if infected_dont_have_breaks_with_exposed
|
||||
infected_people: int
|
||||
lunch_option: bool
|
||||
mask_type: str
|
||||
mask_wearing: str
|
||||
mechanical_ventilation_type: str
|
||||
|
|
@ -58,12 +64,12 @@ class FormData:
|
|||
# Take a copy of the form data so that we can mutate it.
|
||||
form_data = form_data.copy()
|
||||
|
||||
valid_na_values = ['windows_open', 'window_type', 'mechanical_ventilation_type']
|
||||
valid_na_values = ['windows_open', 'window_type', 'mechanical_ventilation_type', 'infected_dont_have_breaks_with_exposed']
|
||||
for name in valid_na_values:
|
||||
if not form_data.get(name, ''):
|
||||
form_data[name] = 'not-applicable'
|
||||
|
||||
for name in ['lunch_start', 'lunch_finish']:
|
||||
for name in ['exposed_lunch_start', 'exposed_lunch_finish', 'infected_lunch_start', 'infected_lunch_finish']:
|
||||
if not form_data.get(name, ''):
|
||||
form_data[name] = '00:00'
|
||||
|
||||
|
|
@ -78,34 +84,42 @@ class FormData:
|
|||
form_data[key] = "0"
|
||||
|
||||
time_attributes = [
|
||||
'activity_start', 'activity_finish', 'lunch_start',
|
||||
'lunch_finish', 'infected_start', 'infected_finish',
|
||||
'exposed_lunch_start', 'exposed_lunch_finish', 'exposed_start', 'exposed_finish',
|
||||
'infected_lunch_start', 'infected_lunch_finish', 'infected_start', 'infected_finish',
|
||||
]
|
||||
for attr_name in time_attributes:
|
||||
form_data[attr_name] = time_string_to_minutes(form_data[attr_name])
|
||||
|
||||
boolean_attributes = [
|
||||
'hepa_option', 'lunch_option',
|
||||
'hepa_option', 'exposed_lunch_option', 'infected_lunch_option', 'infected_dont_have_breaks_with_exposed',
|
||||
]
|
||||
for attr_name in boolean_attributes:
|
||||
form_data[attr_name] = form_data[attr_name] == '1'
|
||||
|
||||
instance = cls(
|
||||
activity_finish=form_data['activity_finish'],
|
||||
activity_start=form_data['activity_start'],
|
||||
activity_type=form_data['activity_type'],
|
||||
air_changes=float(form_data['air_changes']),
|
||||
air_supply=float(form_data['air_supply']),
|
||||
ceiling_height=float(form_data['ceiling_height']),
|
||||
coffee_breaks=int(form_data['coffee_breaks']),
|
||||
coffee_duration=int(form_data['coffee_duration']),
|
||||
exposed_coffee_breaks=int(form_data['exposed_coffee_breaks']),
|
||||
exposed_coffee_duration=int(form_data['exposed_coffee_duration']),
|
||||
exposed_finish=form_data['exposed_finish'],
|
||||
exposed_lunch_finish=form_data['exposed_lunch_finish'],
|
||||
exposed_lunch_option=form_data['exposed_lunch_option'],
|
||||
exposed_lunch_start=form_data['exposed_lunch_start'],
|
||||
exposed_start=form_data['exposed_start'],
|
||||
floor_area=float(form_data['floor_area']),
|
||||
hepa_amount=float(form_data['hepa_amount']),
|
||||
hepa_option=form_data['hepa_option'],
|
||||
infected_coffee_breaks=int(form_data['infected_coffee_breaks']),
|
||||
infected_coffee_duration=int(form_data['infected_coffee_duration']),
|
||||
infected_dont_have_breaks_with_exposed=form_data['infected_dont_have_breaks_with_exposed'],
|
||||
infected_finish=form_data['infected_finish'],
|
||||
infected_lunch_finish=form_data['infected_lunch_finish'],
|
||||
infected_lunch_option=form_data['infected_lunch_option'],
|
||||
infected_lunch_start=form_data['infected_lunch_start'],
|
||||
infected_people=int(form_data['infected_people']),
|
||||
lunch_finish=form_data['lunch_finish'],
|
||||
lunch_option=form_data['lunch_option'],
|
||||
lunch_start=form_data['lunch_start'],
|
||||
infected_start=form_data['infected_start'],
|
||||
mask_type=form_data['mask_type'],
|
||||
mask_wearing=form_data['mask_wearing'],
|
||||
mechanical_ventilation_type=form_data['mechanical_ventilation_type'],
|
||||
|
|
@ -125,18 +139,21 @@ class FormData:
|
|||
window_width=float(form_data['window_width']),
|
||||
windows_number=int(form_data['windows_number']),
|
||||
windows_open=form_data['windows_open'],
|
||||
infected_start=form_data['infected_start'],
|
||||
infected_finish=form_data['infected_finish'],
|
||||
)
|
||||
instance.validate()
|
||||
return instance
|
||||
|
||||
def validate(self):
|
||||
# Validate time intervals selected by user
|
||||
time_intervals = [
|
||||
['activity_start', 'activity_finish'],
|
||||
['lunch_start', 'lunch_finish'],
|
||||
['exposed_start', 'exposed_finish'],
|
||||
['infected_start', 'infected_finish'],
|
||||
]
|
||||
if self.exposed_lunch_option:
|
||||
time_intervals.append(['exposed_lunch_start', 'exposed_lunch_finish'])
|
||||
if self.infected_dont_have_breaks_with_exposed and self.infected_lunch_option:
|
||||
time_intervals.append(['infected_lunch_start', 'infected_lunch_finish'])
|
||||
|
||||
for start_name, end_name in time_intervals:
|
||||
start = getattr(self, start_name)
|
||||
end = getattr(self, end_name)
|
||||
|
|
@ -295,42 +312,67 @@ class FormData:
|
|||
)
|
||||
return exposed
|
||||
|
||||
def _compute_breaks_in_interval(self, start, finish, n_breaks) -> models.BoundarySequence_t:
|
||||
break_delay = ((finish - start) - (n_breaks * self.coffee_duration)) // (n_breaks+1)
|
||||
def _compute_breaks_in_interval(self, start, finish, n_breaks, duration) -> models.BoundarySequence_t:
|
||||
break_delay = ((finish - start) - (n_breaks * duration)) // (n_breaks+1)
|
||||
break_times = []
|
||||
end = start
|
||||
for n in range(n_breaks):
|
||||
begin = end + break_delay
|
||||
end = begin + self.coffee_duration
|
||||
end = begin + duration
|
||||
break_times.append((begin, end))
|
||||
return tuple(break_times)
|
||||
|
||||
def lunch_break_times(self) -> models.BoundarySequence_t:
|
||||
def exposed_lunch_break_times(self) -> models.BoundarySequence_t:
|
||||
result = []
|
||||
if self.lunch_option:
|
||||
result.append((self.lunch_start, self.lunch_finish))
|
||||
if self.exposed_lunch_option:
|
||||
result.append((self.exposed_lunch_start, self.exposed_lunch_finish))
|
||||
return tuple(result)
|
||||
|
||||
def coffee_break_times(self) -> models.BoundarySequence_t:
|
||||
if not self.coffee_breaks:
|
||||
return ()
|
||||
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
|
||||
)
|
||||
)
|
||||
def infected_lunch_break_times(self) -> models.BoundarySequence_t:
|
||||
if self.infected_dont_have_breaks_with_exposed:
|
||||
result = []
|
||||
if self.infected_lunch_option:
|
||||
result.append((self.infected_lunch_start, self.infected_lunch_finish))
|
||||
return tuple(result)
|
||||
else:
|
||||
breaks = self._compute_breaks_in_interval(self.activity_start, self.activity_finish, self.coffee_breaks)
|
||||
return self.exposed_lunch_break_times()
|
||||
|
||||
def _coffee_break_times(self, activity_start, activity_finish, coffee_breaks, coffee_duration, lunch_start, lunch_finish) -> models.BoundarySequence_t:
|
||||
time_before_lunch = lunch_start - activity_start
|
||||
time_after_lunch = activity_finish - lunch_finish
|
||||
before_lunch_frac = time_before_lunch / (time_before_lunch + time_after_lunch)
|
||||
n_morning_breaks = round(coffee_breaks * before_lunch_frac)
|
||||
breaks = (
|
||||
self._compute_breaks_in_interval(
|
||||
activity_start, lunch_start, n_morning_breaks, coffee_duration
|
||||
)
|
||||
+ self._compute_breaks_in_interval(
|
||||
lunch_finish, activity_finish, coffee_breaks - n_morning_breaks, coffee_duration
|
||||
)
|
||||
)
|
||||
return breaks
|
||||
|
||||
def exposed_coffee_break_times(self) -> models.BoundarySequence_t:
|
||||
if not self.exposed_coffee_breaks:
|
||||
return ()
|
||||
if self.exposed_lunch_option:
|
||||
breaks = self._coffee_break_times(self.exposed_start, self.exposed_finish, self.exposed_coffee_breaks, self.exposed_coffee_duration, self.exposed_lunch_start, self.exposed_lunch_finish)
|
||||
else:
|
||||
breaks = self._compute_breaks_in_interval(self.exposed_start, self.exposed_finish, self.exposed_coffee_breaks, self.exposed_coffee_duration)
|
||||
return breaks
|
||||
|
||||
def infected_coffee_break_times(self) -> models.BoundarySequence_t:
|
||||
if self.infected_dont_have_breaks_with_exposed:
|
||||
if not self.infected_coffee_breaks:
|
||||
return ()
|
||||
if self.infected_lunch_option:
|
||||
breaks = self._coffee_break_times(self.infected_start, self.infected_finish, self.infected_coffee_breaks, self.infected_coffee_duration, self.infected_lunch_start, self.infected_lunch_finish)
|
||||
else:
|
||||
breaks = self._compute_breaks_in_interval(self.infected_start, self.infected_finish, self.infected_coffee_breaks, self.infected_coffee_duration)
|
||||
return breaks
|
||||
else:
|
||||
return self.exposed_coffee_break_times()
|
||||
|
||||
def present_interval(
|
||||
self,
|
||||
start: int,
|
||||
|
|
@ -433,13 +475,13 @@ class FormData:
|
|||
def infected_present_interval(self) -> models.Interval:
|
||||
return self.present_interval(
|
||||
self.infected_start, self.infected_finish,
|
||||
breaks=self.lunch_break_times() + self.coffee_break_times(),
|
||||
breaks=self.infected_lunch_break_times() + self.infected_coffee_break_times(),
|
||||
)
|
||||
|
||||
def exposed_present_interval(self) -> models.Interval:
|
||||
return self.present_interval(
|
||||
self.activity_start, self.activity_finish,
|
||||
breaks=self.lunch_break_times() + self.coffee_break_times(),
|
||||
self.exposed_start, self.exposed_finish,
|
||||
breaks=self.exposed_lunch_break_times() + self.exposed_coffee_break_times(),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -497,23 +539,29 @@ def model_from_form(form: FormData) -> models.ExposureModel:
|
|||
def baseline_raw_form_data():
|
||||
# Note: This isn't a special "baseline". It can be updated as required.
|
||||
return {
|
||||
'activity_finish': '18:00',
|
||||
'activity_start': '09:00',
|
||||
'activity_type': 'office',
|
||||
'air_changes': '',
|
||||
'air_supply': '',
|
||||
'ceiling_height': '',
|
||||
'coffee_breaks': '4',
|
||||
'coffee_duration': '10',
|
||||
'exposed_coffee_breaks': '4',
|
||||
'exposed_coffee_duration': '10',
|
||||
'exposed_finish': '18:00',
|
||||
'exposed_lunch_finish': '13:30',
|
||||
'exposed_lunch_option': '1',
|
||||
'exposed_lunch_start': '12:30',
|
||||
'exposed_start': '09:00',
|
||||
'floor_area': '',
|
||||
'hepa_amount': '250',
|
||||
'hepa_option': '0',
|
||||
'infected_coffee_breaks': '4',
|
||||
'infected_coffee_duration': '10',
|
||||
'infected_dont_have_breaks_with_exposed': '1',
|
||||
'infected_finish': '18:00',
|
||||
'infected_lunch_finish': '13:30',
|
||||
'infected_lunch_option': '1',
|
||||
'infected_lunch_start': '12:30',
|
||||
'infected_people': '1',
|
||||
'infected_start': '09:00',
|
||||
'lunch_finish': '13:30',
|
||||
'lunch_option': '1',
|
||||
'lunch_start': '12:30',
|
||||
'mask_type': 'Type I',
|
||||
'mask_wearing': 'removed',
|
||||
'mechanical_ventilation_type': '',
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ p.data_title {
|
|||
|
||||
p.data_text {
|
||||
padding-left: 30px;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
p.data_subtext {
|
||||
|
|
|
|||
|
|
@ -67,11 +67,13 @@ function require_fields(obj) {
|
|||
case "mask_off":
|
||||
require_mask(false);
|
||||
break;
|
||||
case "lunch_option_no":
|
||||
require_lunch(false);
|
||||
case "exposed_lunch_option_no":
|
||||
case "infected_lunch_option_no":
|
||||
require_lunch($(obj).attr('id'), false);
|
||||
break;
|
||||
case "lunch_option_yes":
|
||||
require_lunch(true);
|
||||
case "exposed_lunch_option_yes":
|
||||
case "infected_lunch_option_yes":
|
||||
require_lunch($(obj).attr('id'), true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -144,26 +146,28 @@ function require_venting(option) {
|
|||
set_disabled_status("#windows_frequency", !option);
|
||||
}
|
||||
|
||||
function require_lunch(option) {
|
||||
$("#lunch_start").prop('required', option);
|
||||
$("#lunch_finish").prop('required', option);
|
||||
function require_lunch(id, option) {
|
||||
var activity = $(document.getElementById(id)).data('lunch-select');
|
||||
var startObj = $(".start_time[data-lunch-for='"+activity+"']")[0];
|
||||
var startID = '#'+$(startObj).attr('id');
|
||||
var finishObj = $(".finish_time[data-lunch-for='"+activity+"']")[0];
|
||||
var finishID = '#'+$(finishObj).attr('id');
|
||||
|
||||
var lunchStartObj = document.getElementById("lunch_start");
|
||||
var lunchFinishObj = document.getElementById("lunch_finish");
|
||||
if (option) {
|
||||
if (lunchStartObj.value === "") {
|
||||
lunchStartObj.value = "12:30";
|
||||
}
|
||||
if (lunchFinishObj.value === "") {
|
||||
lunchFinishObj.value = "13:30";
|
||||
}
|
||||
require_input_field(startID, option);
|
||||
require_input_field(finishID, option);
|
||||
set_disabled_status(startID, !option);
|
||||
set_disabled_status(finishID, !option);
|
||||
|
||||
if (!option) {
|
||||
$(finishID).removeClass("red_border finish_time_error lunch_break_error");
|
||||
removeErrorFor(finishObj);
|
||||
}
|
||||
else {
|
||||
lunchStartObj.value = "";
|
||||
lunchFinishObj.value = "";
|
||||
$("#lunch_finish").removeClass("red_border finish_time_error lunch_break_error");
|
||||
$("#lunch_finish").removeClass("red_border finish_time_error lunch_break_error");
|
||||
removeErrorFor(lunchFinishObj);
|
||||
if (startObj.value === "" && finishObj.value === "") {
|
||||
startObj.value = "12:30";
|
||||
finishObj.value = "13:30";
|
||||
}
|
||||
validateLunchBreak($(startObj).data('time-group'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -253,6 +257,12 @@ $("[data-has-radio]").on('change', function(event){
|
|||
$($(this).data("has-radio")).click();
|
||||
});
|
||||
|
||||
function toggle_split_breaks() {
|
||||
$("#DIVinfected_breaks").toggle(this.checked);
|
||||
$("#exposed_break_title").toggle(this.checked);
|
||||
require_lunch("infected_lunch_option_yes", document.getElementById("infected_dont_have_breaks_with_exposed").checked);
|
||||
}
|
||||
|
||||
/* -------Form validation------- */
|
||||
function validate_form(form) {
|
||||
var submit = true;
|
||||
|
|
@ -276,31 +286,34 @@ function validate_form(form) {
|
|||
});
|
||||
}
|
||||
|
||||
//Validate breaks length < activity length
|
||||
if (submit) {
|
||||
var activityBreaksObj= document.getElementById("activity_breaks");
|
||||
removeErrorFor(activityBreaksObj);
|
||||
//Check if breaks length >= activity length
|
||||
$("[data-lunch-for]").each(function() {
|
||||
if (submit) {
|
||||
var activity = $(this).data('lunch-for')
|
||||
var activityBreaksObj= document.getElementById("activity_breaks");
|
||||
removeErrorFor(activityBreaksObj);
|
||||
|
||||
var lunch_mins = 0;
|
||||
if (document.getElementById('lunch_option_yes').checked) {
|
||||
var lunch_start = document.getElementById("lunch_start");
|
||||
var lunch_finish = document.getElementById("lunch_finish");
|
||||
lunch_mins = parseTimeToMins(lunch_finish.value) - parseTimeToMins(lunch_start.value);
|
||||
}
|
||||
if (document.getElementById(activity+"_lunch_option_yes").checked) {
|
||||
var lunch_mins = 0;
|
||||
var lunch_start = document.getElementById(activity+"_lunch_start");
|
||||
var lunch_finish = document.getElementById(activity+"_lunch_finish");
|
||||
lunch_mins = parseTimeToMins(lunch_finish.value) - parseTimeToMins(lunch_start.value);
|
||||
}
|
||||
|
||||
var coffee_breaks = parseInt(document.querySelector('input[name="coffee_breaks"]:checked').value);
|
||||
var coffee_duration = parseInt(document.getElementById("break_duration").value);
|
||||
var coffee_mins = coffee_breaks * coffee_duration;
|
||||
|
||||
var activity_start = document.getElementById("activity_start");
|
||||
var activity_finish = document.getElementById("activity_finish");
|
||||
var activity_mins = parseTimeToMins(activity_finish.value) - parseTimeToMins(activity_start.value);
|
||||
var coffee_breaks = parseInt(document.querySelector('input[name="'+activity+'_coffee_breaks"]:checked').value);
|
||||
var coffee_duration = parseInt(document.getElementById(activity+"_coffee_duration").value);
|
||||
var coffee_mins = coffee_breaks * coffee_duration;
|
||||
|
||||
var activity_start = document.getElementById(activity+"_start");
|
||||
var activity_finish = document.getElementById(activity+"_finish");
|
||||
var activity_mins = parseTimeToMins(activity_finish.value) - parseTimeToMins(activity_start.value);
|
||||
|
||||
if ((lunch_mins + coffee_mins) >= activity_mins) {
|
||||
insertErrorFor(activityBreaksObj, "Length of breaks >= Length of activity");
|
||||
submit = false;
|
||||
if ((lunch_mins + coffee_mins) >= activity_mins) {
|
||||
insertErrorFor(activityBreaksObj, "Length of breaks >= Length of "+activity+" presence");
|
||||
submit = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//Validate all non zero values
|
||||
$("input[required].non_zero").each(function() {
|
||||
|
|
@ -369,7 +382,6 @@ function isValidDateOrEmpty(date) {
|
|||
}
|
||||
|
||||
function validateFinishTime(obj) {
|
||||
|
||||
var groupID = $(obj).data('time-group');
|
||||
var startObj = $(".start_time[data-time-group='"+groupID+"']")[0];
|
||||
var finishObj = $(".finish_time[data-time-group='"+groupID+"']")[0];
|
||||
|
|
@ -392,6 +404,10 @@ function validateFinishTime(obj) {
|
|||
}
|
||||
|
||||
function validateLunchBreak(lunchGroup) {
|
||||
//Valid if lunch break not selected
|
||||
if(document.getElementById(lunchGroup+"_option_no").checked)
|
||||
return true;
|
||||
|
||||
var lunchStartObj = $(".start_time[data-time-group='"+lunchGroup+"']")[0];
|
||||
var lunchFinishObj = $(".finish_time[data-time-group='"+lunchGroup+"']")[0];
|
||||
|
||||
|
|
@ -402,7 +418,7 @@ function validateLunchBreak(lunchGroup) {
|
|||
removeErrorFor(lunchFinishObj);
|
||||
var valid = validateLunchTime(lunchStartObj) & validateLunchTime(lunchFinishObj);
|
||||
if (!valid) {
|
||||
insertErrorFor(lunchFinishObj, "Lunch break must be within activity times");
|
||||
insertErrorFor(lunchFinishObj, "Lunch break must be within presence times");
|
||||
}
|
||||
|
||||
return valid;
|
||||
|
|
@ -410,7 +426,6 @@ function validateLunchBreak(lunchGroup) {
|
|||
|
||||
//Check if exposed/infected lunch time within exposed/infected presence times
|
||||
function validateLunchTime(obj) {
|
||||
|
||||
var activityGroup = $(obj).data('lunch-for');
|
||||
var activityStart = parseValToNumber($(".start_time[data-time-group='"+activityGroup+"']")[0].value);
|
||||
var activityFinish = parseValToNumber($(".finish_time[data-time-group='"+activityGroup+"']")[0].value);
|
||||
|
|
@ -446,6 +461,13 @@ $(document).ready(function () {
|
|||
// Call the function now to handle forward/back button presses in the browser.
|
||||
on_ventilation_type_change();
|
||||
|
||||
// Chrome fix - on back button infected break DIV not shown
|
||||
if (document.getElementById("infected_dont_have_breaks_with_exposed").checked) {
|
||||
$("#DIVinfected_breaks").show();
|
||||
$("#exposed_break_title").show();
|
||||
require_lunch("infected_lunch_option_yes", true);
|
||||
}
|
||||
|
||||
//Check all radio buttons previously selected
|
||||
$("input[type=radio]:checked").each(function() {require_fields(this)});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "layout.html.j2" %}
|
||||
|
||||
{% set MODEL_VERSION="v1.2.1" %}
|
||||
{% set MODEL_VERSION="v1.3.0" %}
|
||||
{% set DEBUG=False %}
|
||||
{% set active_page="calculator/" %}
|
||||
|
||||
|
|
@ -134,73 +134,122 @@
|
|||
<span id="training_limit_error" class="red_text" hidden>Training activities limited to 1 infected<br></span>
|
||||
<hr width="80%">
|
||||
|
||||
Activity type: <select id="activity_type" name="activity_type">
|
||||
<option value="office">Office</option>
|
||||
<option value="meeting">Meeting</option>
|
||||
<option value="callcentre">Call Centre</option>
|
||||
<option value="library">Library</option>
|
||||
<option value="lab">Laboratory</option>
|
||||
<option value="workshop">Workshop</option>
|
||||
<option value="training">Training</option>
|
||||
<option value="gym">Gym</option>
|
||||
</select><br>
|
||||
Start: <input type="time" id="activity_start" class="start_time" data-time-group="activity" data-lunch-break="lunch_activity" name="activity_start" value="09:00" required>
|
||||
Finish: <input type="time" id="activity_finish" class="finish_time" data-time-group="activity" data-lunch-break="lunch_activity" name="activity_finish" value="18:00" required><br>
|
||||
Activity type:
|
||||
<select id="activity_type" name="activity_type">
|
||||
<option value="office">Office</option>
|
||||
<option value="meeting">Meeting</option>
|
||||
<option value="callcentre">Call Centre</option>
|
||||
<option value="library">Library</option>
|
||||
<option value="lab">Laboratory</option>
|
||||
<option value="workshop">Workshop</option>
|
||||
<option value="training">Training</option>
|
||||
<option value="gym">Gym</option>
|
||||
</select><br>
|
||||
Exposed person(s) presence: <br>
|
||||
<span class="tabbed">Start: </span><input type="time" id="exposed_start" class="start_time" data-time-group="exposed" data-lunch-break="exposed_lunch" name="exposed_start" value="09:00" required>
|
||||
Finish: <input type="time" id="exposed_finish" class="finish_time" data-time-group="exposed" data-lunch-break="exposed_lunch" name="exposed_finish" value="18:00" required><br>
|
||||
Infected person(s) presence: <br>
|
||||
Start: <input type="time" id="infected_start" class="start_time" data-time-group="infected" name="infected_start" value="09:00" required>
|
||||
Finish: <input type="time" id="infected_finish" class="finish_time" data-time-group="infected" name="infected_finish" value="18:00" required><br>
|
||||
<span class="tabbed">Start: </span><input type="time" id="infected_start" class="start_time" data-time-group="infected" data-lunch-break="infected_lunch" name="infected_start" value="09:00" required>
|
||||
Finish: <input type="time" id="infected_finish" class="finish_time" data-time-group="infected" data-lunch-break="infected_lunch" name="infected_finish" value="18:00" required><br>
|
||||
<hr width="80%">
|
||||
|
||||
<label>Which month is the event?</label>
|
||||
<select id="event_month" name="event_month" value="January" required>
|
||||
<option value="January">January</option>
|
||||
<option value="February">February</option>
|
||||
<option value="March">March</option>
|
||||
<option value="April">April</option>
|
||||
<option value="May">May</option>
|
||||
<option value="June">June</option>
|
||||
<option value="July">July</option>
|
||||
<option value="August">August</option>
|
||||
<option value="September">September</option>
|
||||
<option value="October">October</option>
|
||||
<option value="November">November</option>
|
||||
<option value="December">December</option>
|
||||
Which month is the event?
|
||||
<select id="event_month" name="event_month" value="January" required>
|
||||
<option value="January">January</option>
|
||||
<option value="February">February</option>
|
||||
<option value="March">March</option>
|
||||
<option value="April">April</option>
|
||||
<option value="May">May</option>
|
||||
<option value="June">June</option>
|
||||
<option value="July">July</option>
|
||||
<option value="August">August</option>
|
||||
<option value="September">September</option>
|
||||
<option value="October">October</option>
|
||||
<option value="November">November</option>
|
||||
<option value="December">December</option>
|
||||
</select><br>
|
||||
<hr width="80%">
|
||||
|
||||
<span id="activity_breaks">
|
||||
<b>Activity breaks:</b>
|
||||
<div data-tooltip="Input breaks that, by default, are the same for infected/exposed person(s) unless specified otherwise.">
|
||||
<span class="tooltip_text">?</span>
|
||||
</div>
|
||||
</span><br>
|
||||
<!-- Lunch Options -->
|
||||
Lunch break:
|
||||
<input type="radio" id="lunch_option_no" name="lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="lunch_option_no">No</label>
|
||||
<input type="radio" id="lunch_option_yes" name="lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
<label for="lunch_option_yes">Yes</label><br>
|
||||
|
||||
<div id="DIVlunch_break">
|
||||
Start: <input type="time" id="lunch_start" class="start_time" data-time-group="lunch_activity" data-lunch-for="activity" name="lunch_start" value="12:30" required>
|
||||
Finish: <input type="time" id="lunch_finish" class="finish_time" data-time-group="lunch_activity" data-lunch-for="activity" name="lunch_finish" value="13:30" required><br>
|
||||
<!-- Lunch Options -->
|
||||
<input type="checkbox" id="infected_dont_have_breaks_with_exposed" name="infected_dont_have_breaks_with_exposed" value='1' onclick="toggle_split_breaks()">
|
||||
<label for="infected_dont_have_breaks_with_exposed">Input separate breaks for infected and exposed person(s)</label><br>
|
||||
<div id="DIVexposed_breaks" style="float:left; margin-left:10pt;">
|
||||
<span id="exposed_break_title" style="display:none;"><b>Exposed person(s) breaks:</b></span>
|
||||
<div style="padding:10px; border: 2px solid rgb(47, 52, 66);">
|
||||
Lunch break:
|
||||
<input type="radio" id="exposed_lunch_option_no" data-lunch-select="exposed" name="exposed_lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="exposed_lunch_option_no">No</label>
|
||||
<input type="radio" id="exposed_lunch_option_yes" data-lunch-select="exposed" name="exposed_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
<label for="exposed_lunch_option_yes">Yes</label><br>
|
||||
|
||||
Start: <input type="time" id="exposed_lunch_start" class="start_time" data-time-group="exposed_lunch" data-lunch-for="exposed" data-has-radio="#exposed_lunch_option_yes" name="exposed_lunch_start" value="12:30" required>
|
||||
Finish: <input type="time" id="exposed_lunch_finish" class="finish_time" data-time-group="exposed_lunch" data-lunch-for="exposed" data-has-radio="#exposed_lunch_option_yes" name="exposed_lunch_finish" value="13:30" required><br>
|
||||
|
||||
<!-- Coffee Options -->
|
||||
Coffee Breaks:
|
||||
<input type="radio" id="exposed_coffee_break_0" name="exposed_coffee_breaks" value="0" checked="checked">
|
||||
<label for="exposed_coffee_break_0" >No breaks</label>
|
||||
<input type="radio" id="exposed_coffee_break_2" name="exposed_coffee_breaks" value="2">
|
||||
<label for="exposed_coffee_break_2">2</label>
|
||||
<input type="radio" id="exposed_coffee_break_4" name="exposed_coffee_breaks" value="4">
|
||||
<label for="exposed_coffee_break_4">4</label><br>
|
||||
|
||||
Duration (minutes):
|
||||
<select id="exposed_coffee_duration" name="exposed_coffee_duration">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="30">30</option>
|
||||
</select><br>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<!-- Coffee Options -->
|
||||
Coffee Breaks:
|
||||
<input type="radio" id="coffee_break_0" name="coffee_breaks" value="0" checked="checked">
|
||||
<label for="coffee_break_0" >No breaks</label>
|
||||
<input type="radio" id="coffee_break_2" name="coffee_breaks" value="2">
|
||||
<label for="coffee_break_2">2</label>
|
||||
<input type="radio" id="coffee_break_4" name="coffee_breaks" value="4">
|
||||
<label for="coffee_break_4">4</label><br>
|
||||
<div id="DIVinfected_breaks" style="display:none; float:left; margin-left:10pt;">
|
||||
<b>Infected person(s) breaks:</b>
|
||||
<div style="padding:10px; border: 2px solid rgb(47, 52, 66);">
|
||||
Lunch break:
|
||||
<input type="radio" id="infected_lunch_option_no" data-lunch-select="infected" name="infected_lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="infected_lunch_option_no">No</label>
|
||||
<input type="radio" id="infected_lunch_option_yes" data-lunch-select="infected" name="infected_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
<label for="infected_lunch_option_yes">Yes</label><br>
|
||||
|
||||
Start: <input type="time" id="infected_lunch_start" class="start_time" data-time-group="infected_lunch" data-lunch-for="infected" data-has-radio="#infected_lunch_option_yes" name="infected_lunch_start" value="12:30">
|
||||
Finish: <input type="time" id="infected_lunch_finish" class="finish_time" data-time-group="infected_lunch" data-lunch-for="infected" data-has-radio="#infected_lunch_option_yes" name="infected_lunch_finish" value="13:30"><br>
|
||||
|
||||
Duration (minutes): <select id="break_duration" name="coffee_duration">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="30">30</option>
|
||||
</select><br>
|
||||
Coffee breaks are spread evenly throughout the day.<br>
|
||||
<!-- Coffee Options -->
|
||||
Coffee Breaks:
|
||||
<input type="radio" id="infected_coffee_break_0" name="infected_coffee_breaks" value="0" checked="checked">
|
||||
<label for="infected_coffee_break_0" >No breaks</label>
|
||||
<input type="radio" id="infected_coffee_break_2" name="infected_coffee_breaks" value="2">
|
||||
<label for="infected_coffee_break_2">2</label>
|
||||
<input type="radio" id="infected_coffee_break_4" name="infected_coffee_breaks" value="4">
|
||||
<label for="infected_coffee_break_4">4</label><br>
|
||||
|
||||
Duration (minutes):
|
||||
<select id="infected_coffee_duration" name="infected_coffee_duration">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="30">30</option>
|
||||
</select><br>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<br style="clear:both;">
|
||||
<i>Coffee breaks are spread evenly throughout the day.</i><br>
|
||||
<hr width="80%">
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@
|
|||
</p></li>
|
||||
<li><p class="data_text">Exposed occupant(s) activity time:</p></li>
|
||||
<ul>
|
||||
<li><p class="data_subtext">Start time: {{ form.activity_start | minutes_to_time }}    End time: {{ form.activity_finish | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">Start time: {{ form.exposed_start | minutes_to_time }}    End time: {{ form.exposed_finish | minutes_to_time }}</p></li>
|
||||
</ul>
|
||||
<li><p class="data_text">Infected occupant(s) activity time:</p></li>
|
||||
<ul>
|
||||
|
|
@ -127,28 +127,58 @@
|
|||
</ul>
|
||||
|
||||
<p class="data_title">Break data:</p>
|
||||
{% if form.infected_dont_have_breaks_with_exposed %}
|
||||
<p style="padding-left:15px;"> Exposed occupant(s):</p>
|
||||
{% endif %}
|
||||
<ul>
|
||||
<li><p class="data_text">Lunch break:
|
||||
{% if form.lunch_option%}
|
||||
{% if form.exposed_lunch_option%}
|
||||
Yes</li>
|
||||
<ul>
|
||||
<li> Start: {{ form.lunch_start | minutes_to_time }}    End: {{ form.lunch_finish | minutes_to_time }}</p></li>
|
||||
<li><p class="data_subtext">Start time: {{ form.exposed_lunch_start | minutes_to_time }}    End time: {{ form.exposed_lunch_finish | minutes_to_time }}
|
||||
</ul>
|
||||
{% else%}
|
||||
No</li>
|
||||
No
|
||||
{% endif %}
|
||||
<li><p class="data_text">Coffee breaks: {{ form.coffee_breaks }}
|
||||
{% if form.coffee_breaks > 0 %}
|
||||
each of {{ form.coffee_duration }} minutes duration
|
||||
</p></li>
|
||||
<li><p class="data_text">Coffee breaks: {{ form.exposed_coffee_breaks }}
|
||||
{% if form.exposed_coffee_breaks > 0 %}
|
||||
each of {{ form.exposed_coffee_duration }} minutes duration
|
||||
</p></li>
|
||||
<ul>
|
||||
{%- for start_time, end_time in form.coffee_break_times() %}
|
||||
{%- for start_time, end_time in form.exposed_coffee_break_times() %}
|
||||
<li><p class="data_subtext">Coffee break {{ loop.index }}: Start: {{ start_time | minutes_to_time }}    End: {{ end_time | minutes_to_time }}</p></li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
{% if form.infected_dont_have_breaks_with_exposed %}
|
||||
<p style="padding-left:15px;"> Infected occupant(s):</p>
|
||||
<ul>
|
||||
<li><p class="data_text">Lunch break:
|
||||
{% if form.infected_lunch_option%}
|
||||
Yes</li>
|
||||
<ul>
|
||||
<li><p class="data_subtext">Start time: {{ form.infected_lunch_start | minutes_to_time }}    End time: {{ form.infected_lunch_finish | minutes_to_time }}
|
||||
</ul>
|
||||
{% else%}
|
||||
No
|
||||
{% endif %}
|
||||
</p></li>
|
||||
<li><p class="data_text">Coffee breaks: {{ form.infected_coffee_breaks }}
|
||||
{% if form.infected_coffee_breaks > 0 %}
|
||||
each of {{ form.infected_coffee_duration }} minutes duration
|
||||
</p></li>
|
||||
<ul>
|
||||
{%- for start_time, end_time in form.infected_coffee_break_times() %}
|
||||
<li><p class="data_subtext">Coffee break {{ loop.index }}: Start: {{ start_time | minutes_to_time }}    End: {{ end_time | minutes_to_time }}</p></li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<p class="data_title">Mask wearing:</p>
|
||||
<ul>
|
||||
<li><p class="data_text">Masks worn at workstations? {{ 'Yes' if form.mask_wearing == "continuous" else 'No' }} </p></li>
|
||||
|
|
|
|||
|
|
@ -133,12 +133,13 @@ def test_ventilation_window_hepa(baseline_form):
|
|||
|
||||
|
||||
def test_infected_present_intervals(baseline_form):
|
||||
baseline_form.coffee_duration = 15
|
||||
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
|
||||
baseline_form.infected_dont_have_breaks_with_exposed = False
|
||||
baseline_form.exposed_coffee_duration = 15
|
||||
baseline_form.exposed_coffee_breaks = 2
|
||||
baseline_form.exposed_start = 9 * 60
|
||||
baseline_form.exposed_finish = 17 * 60
|
||||
baseline_form.exposed_lunch_start = 12 * 60 + 30
|
||||
baseline_form.exposed_lunch_finish = 13 * 60 + 30
|
||||
baseline_form.infected_start = 10 * 60
|
||||
baseline_form.infected_finish = 15 * 60
|
||||
correct = ((10, 10+37/60), (10+52/60, 12.5), (13.5, 15.0))
|
||||
|
|
@ -146,85 +147,117 @@ def test_infected_present_intervals(baseline_form):
|
|||
|
||||
|
||||
def test_exposed_present_intervals(baseline_form):
|
||||
baseline_form.coffee_duration = 15
|
||||
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
|
||||
baseline_form.exposed_coffee_duration = 15
|
||||
baseline_form.exposed_coffee_breaks = 2
|
||||
baseline_form.exposed_start = 9 * 60
|
||||
baseline_form.exposed_finish = 17 * 60
|
||||
baseline_form.exposed_lunch_start = 12 * 60 + 30
|
||||
baseline_form.exposed_lunch_finish = 13 * 60 + 30
|
||||
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_present_intervals_common_breaks(baseline_form):
|
||||
baseline_form.infected_dont_have_breaks_with_exposed = False
|
||||
baseline_form.infected_coffee_duration = baseline_form.exposed_coffee_duration = 15
|
||||
baseline_form.infected_coffee_breaks = baseline_form.exposed_coffee_breaks = 2
|
||||
baseline_form.exposed_lunch_start = baseline_form.infected_lunch_start = 12 * 60 + 30
|
||||
baseline_form.exposed_lunch_finish = baseline_form.infected_lunch_finish = 13 * 60 + 30
|
||||
baseline_form.exposed_start = 9 * 60
|
||||
baseline_form.exposed_finish = 17 * 60
|
||||
baseline_form.infected_start = 9 * 60
|
||||
baseline_form.infected_finish = 16 * 60
|
||||
correct_exposed = ((9, 10+37/60), (10+52/60, 12.5), (13.5, 15+7/60), (15+22/60, 17.0))
|
||||
correct_infected = ((9, 10+37/60), (10+52/60, 12.5), (13.5, 15+7/60), (15+22/60, 16.0))
|
||||
assert baseline_form.exposed_present_interval().present_times == correct_exposed
|
||||
assert baseline_form.infected_present_interval().present_times == correct_infected
|
||||
|
||||
|
||||
def test_present_intervals_split_breaks(baseline_form):
|
||||
baseline_form.infected_dont_have_breaks_with_exposed = True
|
||||
baseline_form.infected_coffee_duration = baseline_form.exposed_coffee_duration = 15
|
||||
baseline_form.infected_coffee_breaks = baseline_form.exposed_coffee_breaks = 2
|
||||
baseline_form.infected_lunch_start = baseline_form.exposed_lunch_start = 12 * 60 + 30
|
||||
baseline_form.infected_lunch_finish = baseline_form.exposed_lunch_finish = 13 * 60 + 30
|
||||
baseline_form.exposed_start = 9 * 60
|
||||
baseline_form.exposed_finish = 17 * 60
|
||||
baseline_form.infected_start = 9 * 60
|
||||
baseline_form.infected_finish = 16 * 60
|
||||
correct_exposed = ((9, 10+37/60), (10+52/60, 12.5), (13.5, 15+7/60), (15+22/60, 17.0))
|
||||
correct_infected = ((9, 10+37/60), (10+52/60, 12.5), (13.5, 14+37/60), (14+52/60, 16.0))
|
||||
assert baseline_form.exposed_present_interval().present_times == correct_exposed
|
||||
assert baseline_form.infected_present_interval().present_times == correct_infected
|
||||
|
||||
|
||||
def test_exposed_present_intervals_starting_with_lunch(baseline_form):
|
||||
baseline_form.coffee_breaks = 0
|
||||
baseline_form.activity_start = baseline_form.lunch_start = 13 * 60
|
||||
baseline_form.activity_finish = 18 * 60
|
||||
baseline_form.lunch_finish = 14 * 60
|
||||
baseline_form.exposed_coffee_breaks = 0
|
||||
baseline_form.exposed_start = baseline_form.exposed_lunch_start = 13 * 60
|
||||
baseline_form.exposed_finish = 18 * 60
|
||||
baseline_form.exposed_lunch_finish = 14 * 60
|
||||
correct = ((14.0, 18.0), )
|
||||
assert baseline_form.exposed_present_interval().present_times == correct
|
||||
|
||||
|
||||
def test_exposed_present_intervals_ending_with_lunch(baseline_form):
|
||||
baseline_form.coffee_breaks = 0
|
||||
baseline_form.activity_start = 11 * 60
|
||||
baseline_form.activity_finish = baseline_form.lunch_start = 13 * 60
|
||||
baseline_form.lunch_finish = 14 * 60
|
||||
baseline_form.exposed_coffee_breaks = 0
|
||||
baseline_form.exposed_start = 11 * 60
|
||||
baseline_form.exposed_finish = baseline_form.exposed_lunch_start = 13 * 60
|
||||
baseline_form.exposed_lunch_finish = 14 * 60
|
||||
correct = ((11.0, 13.0),)
|
||||
assert baseline_form.exposed_present_interval().present_times == correct
|
||||
|
||||
|
||||
def test_exposed_present_lunch_end_before_beginning(baseline_form):
|
||||
baseline_form.coffee_breaks = 0
|
||||
baseline_form.lunch_start = 14 * 60
|
||||
baseline_form.lunch_finish = 13 * 60
|
||||
baseline_form.exposed_coffee_breaks = 0
|
||||
baseline_form.exposed_lunch_start = 14 * 60
|
||||
baseline_form.exposed_lunch_finish = 13 * 60
|
||||
with pytest.raises(ValueError):
|
||||
baseline_form.validate()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def coffee_break_between_1045_and_1115(baseline_form):
|
||||
baseline_form.coffee_breaks = 1
|
||||
baseline_form.coffee_duration = 30
|
||||
baseline_form.activity_start = 10 * 60
|
||||
baseline_form.activity_finish = 12 * 60
|
||||
baseline_form.lunch_option = False
|
||||
baseline_form.exposed_coffee_breaks = 1
|
||||
baseline_form.exposed_coffee_duration = 30
|
||||
baseline_form.exposed_start = 10 * 60
|
||||
baseline_form.exposed_finish = 12 * 60
|
||||
baseline_form.exposed_lunch_option = False
|
||||
|
||||
coffee_breaks = baseline_form.coffee_break_times()
|
||||
coffee_breaks = baseline_form.exposed_coffee_break_times()
|
||||
assert coffee_breaks == ((10.75 * 60, 11.25 * 60),)
|
||||
return baseline_form
|
||||
|
||||
|
||||
def test_present_before_coffee(coffee_break_between_1045_and_1115):
|
||||
breaks = coffee_break_between_1045_and_1115.coffee_break_times()
|
||||
breaks = coffee_break_between_1045_and_1115.exposed_coffee_break_times()
|
||||
interval = coffee_break_between_1045_and_1115.present_interval(
|
||||
10.5 * 60, 11 * 60, breaks=breaks)
|
||||
assert interval.boundaries() == ((10.5, 10.75),)
|
||||
|
||||
|
||||
def test_present_after_coffee(coffee_break_between_1045_and_1115):
|
||||
breaks = coffee_break_between_1045_and_1115.coffee_break_times()
|
||||
breaks = coffee_break_between_1045_and_1115.exposed_coffee_break_times()
|
||||
interval = coffee_break_between_1045_and_1115.present_interval(
|
||||
11 * 60, 11.5 * 60, breaks=breaks)
|
||||
assert interval.boundaries() == ((11.25, 11.5),)
|
||||
|
||||
|
||||
def test_present_when_coffee_starts(coffee_break_between_1045_and_1115):
|
||||
breaks = coffee_break_between_1045_and_1115.coffee_break_times()
|
||||
breaks = coffee_break_between_1045_and_1115.exposed_coffee_break_times()
|
||||
interval = coffee_break_between_1045_and_1115.present_interval(
|
||||
10.75 * 60, 11.5 * 60, breaks=breaks)
|
||||
assert interval.boundaries() == ((11.25, 11.5),)
|
||||
|
||||
|
||||
def test_present_when_coffee_ends(coffee_break_between_1045_and_1115):
|
||||
breaks = coffee_break_between_1045_and_1115.coffee_break_times()
|
||||
breaks = coffee_break_between_1045_and_1115.exposed_coffee_break_times()
|
||||
interval = coffee_break_between_1045_and_1115.present_interval(
|
||||
10.5 * 60, 11.25 * 60, breaks=breaks)
|
||||
assert interval.boundaries() == ((10.5, 10.75), )
|
||||
|
||||
|
||||
def test_present_only_for_coffee_ends(coffee_break_between_1045_and_1115):
|
||||
breaks = coffee_break_between_1045_and_1115.coffee_break_times()
|
||||
breaks = coffee_break_between_1045_and_1115.exposed_coffee_break_times()
|
||||
interval = coffee_break_between_1045_and_1115.present_interval(
|
||||
10.75 * 60, 11.25 * 60, breaks=breaks)
|
||||
assert interval.boundaries() == ()
|
||||
|
|
@ -248,17 +281,17 @@ def assert_boundaries(interval, boundaries_in_time_string_form):
|
|||
|
||||
@pytest.fixture
|
||||
def breaks_every_25_mins_for_20_mins(baseline_form):
|
||||
baseline_form.coffee_breaks = 4
|
||||
baseline_form.coffee_duration = 20
|
||||
baseline_form.activity_start = time2mins("10:00")
|
||||
baseline_form.activity_finish = time2mins("14:10")
|
||||
baseline_form.lunch_start = time2mins("11:55")
|
||||
baseline_form.lunch_finish = time2mins("12:15")
|
||||
baseline_form.lunch_option = True
|
||||
baseline_form.exposed_coffee_breaks = 4
|
||||
baseline_form.exposed_coffee_duration = 20
|
||||
baseline_form.exposed_start = time2mins("10:00")
|
||||
baseline_form.exposed_finish = time2mins("14:10")
|
||||
baseline_form.exposed_lunch_start = time2mins("11:55")
|
||||
baseline_form.exposed_lunch_finish = time2mins("12:15")
|
||||
baseline_form.exposed_lunch_option = True
|
||||
|
||||
breaks = baseline_form.coffee_break_times() + baseline_form.lunch_break_times()
|
||||
breaks = baseline_form.exposed_coffee_break_times() + baseline_form.exposed_lunch_break_times()
|
||||
interval = baseline_form.present_interval(
|
||||
baseline_form.activity_start, baseline_form.activity_finish, breaks=breaks,
|
||||
baseline_form.exposed_start, baseline_form.exposed_finish, breaks=breaks,
|
||||
)
|
||||
|
||||
assert_boundaries(interval, [
|
||||
|
|
@ -273,7 +306,7 @@ def breaks_every_25_mins_for_20_mins(baseline_form):
|
|||
|
||||
|
||||
def test_present_after_two_breaks_for_small_interval(breaks_every_25_mins_for_20_mins):
|
||||
breaks = breaks_every_25_mins_for_20_mins.coffee_break_times() + breaks_every_25_mins_for_20_mins.lunch_break_times()
|
||||
breaks = breaks_every_25_mins_for_20_mins.exposed_coffee_break_times() + breaks_every_25_mins_for_20_mins.exposed_lunch_break_times()
|
||||
# The first two breaks start at 10:25 and 11:10.
|
||||
interval = breaks_every_25_mins_for_20_mins.present_interval(
|
||||
time2mins("11:35"), time2mins("11:40"), breaks=breaks,
|
||||
|
|
@ -283,7 +316,7 @@ def test_present_after_two_breaks_for_small_interval(breaks_every_25_mins_for_20
|
|||
|
||||
|
||||
def test_present_only_during_second_break(breaks_every_25_mins_for_20_mins):
|
||||
breaks = breaks_every_25_mins_for_20_mins.coffee_break_times() + breaks_every_25_mins_for_20_mins.lunch_break_times()
|
||||
breaks = breaks_every_25_mins_for_20_mins.exposed_coffee_break_times() + breaks_every_25_mins_for_20_mins.exposed_lunch_break_times()
|
||||
# The first two breaks start at 10:25 and 11:10.
|
||||
interval = breaks_every_25_mins_for_20_mins.present_interval(
|
||||
time2mins("11:15"), time2mins("11:20"), breaks=breaks
|
||||
|
|
@ -294,18 +327,19 @@ def test_present_only_during_second_break(breaks_every_25_mins_for_20_mins):
|
|||
|
||||
def test_valid_no_lunch(baseline_form):
|
||||
# Check that it is valid to have a 0 length lunch if no lunch is selected.
|
||||
baseline_form.lunch_option = False
|
||||
baseline_form.lunch_start = 0
|
||||
baseline_form.lunch_finish = 0
|
||||
baseline_form.exposed_lunch_option = False
|
||||
baseline_form.exposed_lunch_start = 0
|
||||
baseline_form.exposed_lunch_finish = 0
|
||||
assert baseline_form.validate() is None
|
||||
|
||||
|
||||
def test_no_breaks(baseline_form):
|
||||
# Check that the times are correct in the absence of breaks.
|
||||
baseline_form.lunch_option = False
|
||||
baseline_form.coffee_breaks = 0
|
||||
baseline_form.activity_start = 9 * 60
|
||||
baseline_form.activity_finish = 17 * 60
|
||||
baseline_form.infected_dont_have_breaks_with_exposed = False
|
||||
baseline_form.exposed_lunch_option = False
|
||||
baseline_form.exposed_coffee_breaks = 0
|
||||
baseline_form.exposed_start = 9 * 60
|
||||
baseline_form.exposed_finish = 17 * 60
|
||||
baseline_form.infected_start = 10 * 60
|
||||
baseline_form.infected_finish = 15 * 60
|
||||
exposed_correct = ((9, 17),)
|
||||
|
|
@ -315,34 +349,34 @@ def test_no_breaks(baseline_form):
|
|||
|
||||
|
||||
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
|
||||
baseline_form.exposed_coffee_duration = 30
|
||||
baseline_form.exposed_coffee_breaks = 4
|
||||
baseline_form.exposed_start = 9 * 60
|
||||
baseline_form.exposed_finish = 18 * 60
|
||||
baseline_form.exposed_lunch_start = 12 * 60 + 30
|
||||
baseline_form.exposed_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
|
||||
baseline_form.exposed_coffee_duration = 30
|
||||
baseline_form.exposed_coffee_breaks = 2
|
||||
baseline_form.exposed_start = 9 * 60
|
||||
baseline_form.exposed_finish = 13 * 60 + 30
|
||||
baseline_form.exposed_lunch_start = 12 * 60 + 30
|
||||
baseline_form.exposed_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
|
||||
baseline_form.exposed_coffee_duration = 10
|
||||
baseline_form.exposed_coffee_breaks = 4
|
||||
baseline_form.exposed_start = 9 * 60
|
||||
baseline_form.exposed_finish = 10 * 60
|
||||
baseline_form.exposed_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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue