Merge branch 'key-validation' into 'master'

Key validation

See merge request cara/cara!38
This commit is contained in:
Philip James Elson 2020-11-06 13:52:44 +00:00
commit c308387341
5 changed files with 59 additions and 20 deletions

View file

@ -48,6 +48,17 @@ class FormData:
if value == "":
form_data[key] = "0"
validation_tuples = [('activity_type', ACTIVITY_TYPES),
('event_type', EVENT_TYPES),
('mechanical_ventilation_type', MECHANICAL_VENTILATION_TYPES),
('mask_wearing', MASK_WEARING),
('ventilation_type', VENTILATION_TYPES),
('volume_type', VOLUME_TYPES),
('windows_open', WINDOWS_OPEN)]
for key, valid_set in validation_tuples:
if form_data[key] not in valid_set:
raise ValueError(f"{form_data[key]} is not a valid value for {key}")
return cls(
activity_finish=time_string_to_minutes(form_data['activity_finish']),
activity_start=time_string_to_minutes(form_data['activity_start']),
@ -89,11 +100,14 @@ class FormData:
def ventilation(self) -> models.Ventilation:
# Initializes a ventilation instance as a window if 'natural' is selected, or as a HEPA-filter otherwise
if self.ventilation_type == 'natural':
if self.windows_open == '10 min / 2h':
if self.windows_open == 'interval':
period, duration = 120, 10
elif self.windows_number == 'breaks':
# TODO: Implement windows open in breaks
period, duration = 120, 120
else:
period, duration = 120, 120
# I multiply the opening width by the number of windows to simulate the correct window area
if self.event_type == 'single_event':
month_number = int(self.single_event_date.split('/')[1])
month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][month_number - 1]
@ -103,6 +117,7 @@ class FormData:
inside_temp = models.PiecewiseConstant((0, 24), (293,))
outside_temp = models.GenevaTemperatures[month]
# I multiply the opening width by the number of windows to simulate the correct window area
ventilation = models.WindowOpening(active=models.PeriodicInterval(period=period, duration=duration),
inside_temp=inside_temp, outside_temp=outside_temp, cd_b=0.6,
window_height=self.window_height,
@ -190,8 +205,7 @@ def model_from_form(form: FormData, tmp_raw_form_data) -> models.Model:
# Initializes a mask of type 1 if mask wearing is "continuous", otherwise instantiates the mask attribute as
# the "No mask"-mask
# TODO: figure out the possible values of mask_wearing in the form
mask = models.Mask.types['Type I' if d['mask_wearing'] == "Continuous" else 'No mask']
mask = models.Mask.types['Type I' if d['mask_wearing'] == "continuous" else 'No mask']
# A dictionary containing the mapping of activities listed in the UI to the activity level and expiration level
# of the infected and exposed occupants respectively.
@ -264,6 +278,15 @@ def baseline_raw_form_data():
}
ACTIVITY_TYPES = {'office', 'training', 'workshop'}
EVENT_TYPES = {'single_event', 'recurrent_event'}
MECHANICAL_VENTILATION_TYPES = {'air_changes', 'air_supply'}
MASK_WEARING = {'continuous', 'removed'}
VENTILATION_TYPES = {'natural', 'mechanical'}
VOLUME_TYPES = {'room_volume', 'room_dimensions'}
WINDOWS_OPEN = {'always', 'interval', 'breaks'}
def time_string_to_minutes(time: str) -> int:
"""
Converts time from string-format to an integer number of minutes after 00:00

View file

@ -69,6 +69,15 @@ def plot(times, concentrations):
return fig
def minutes_to_string(minutes: int) -> str:
minute_string = str(minutes % 60)
minute_string = "0" * (2 - len(minute_string)) + minute_string
hour_string = str(minutes // 60)
hour_string = "0" * (2 - len(hour_string)) + hour_string
return f"{hour_string}:{minute_string}"
def build_report(model: models.Model, form: FormData):
now = datetime.now()
time = now.strftime("%d/%m/%Y %H:%M:%S")
@ -76,7 +85,8 @@ def build_report(model: models.Model, form: FormData):
context = {
'model': model,
'request': request,
'request': request,
'form': form,
'creation_date': time,
'model_version': 'Beta v1.0.0',
'simulation_name': form.simulation_name,
@ -94,16 +104,16 @@ def build_report(model: models.Model, form: FormData):
'total_people': form.total_people,
'infected_people': form.infected_people,
'activity_type': form.activity_type,
'activity_start': form.activity_start,
'activity_finish': form.activity_finish,
'exposure_start': '00:00',
'exposure_finish': '01:15',
'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),
'event_type': form.event_type,
'single_event_date': form.single_event_date,
'recurrent_event_month': form.recurrent_event_month,
'lunch_option': form.lunch_option,
'lunch_start': form.lunch_start,
'lunch_finish': form.lunch_finish,
'lunch_start': minutes_to_string(form.lunch_start),
'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']],

View file

@ -41,9 +41,9 @@ Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to
<input type="hidden" id="no_ventilation" name="ventilation_type" value="" />
<div id="DIVmechanical_ventilation" style="display:none">
<input type="radio" id="air_type_supply" name="air_type" value="air_supply" onclick="require_fields(this)">
<input type="radio" id="air_type_supply" name="mechanical_ventilation_type" value="air_supply" onclick="require_fields(this)">
Air supply flow rate &nbsp;&nbsp; <input type="number" step=0.01 id="air_supply" name="air_supply" min="0" placeholder="(m³)"><br>
<input type="radio" id="air_type_changes" name="air_type" value="air_changes" onclick="require_fields(this)">
<input type="radio" id="air_type_changes" name="mechanical_ventilation_type" value="air_changes" onclick="require_fields(this)">
Air changes per hour &nbsp;&nbsp; <input type="number" step=0.01 id="air_changes" name="air_changes" min="0"><br>
</div>
@ -56,8 +56,8 @@ Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to
<label for="always">Always</label>
<input type="radio" id="interval" name="windows_open" value="interval">
<label for="interval">10 min / 2h</label>
<input type="radio" id="breaks" name="windows_open" value="breaks">
<label for="breaks">Breaks</label><br>
<!--input type="radio" id="breaks" name="windows_open" value="breaks">
<label for="breaks">Breaks</label--><br>
</div>
HEPA filtration:

View file

@ -24,7 +24,7 @@
<p class="data_title">Ventilation data:</p>
<ul>
<li><p class="data_text">Mechanical ventilation:
{% if ventilation_type == "mechanical_ventilation"%}
{% if ventilation_type == "mechanical"%}
Yes </p></li>
<ul>
<li><p class="data_subtext">Air supply flow rate: {{ air_supply }}</p></li>
@ -34,7 +34,7 @@
No </li>
{% endif %}
<li><p class="data_text">Natural ventilation:
{% if ventilation_type == "natural_ventilation"%}
{% if ventilation_type == "natural"%}
Yes </p></li>
<ul>
<li><p class="data_subtext">Number of windows: {{ windows_number }}</p></li>
@ -61,7 +61,7 @@
{% endif %}
infected.</p></li>
<li><p class="data_text">Activity type:
{% if activity_type == "office work" %}
{% if activity_type == "office" %}
Office work typical scenario with all persons seated, talking.
{% elif activity_type == "workshop" %}
Workshop = assembly workshop environment, all persons doing light exercise, talking.
@ -74,7 +74,7 @@
</ul>
<li><p class="data_text">Exposure time (presence of infected person):</p></li>
<ul>
<li><p class="data_subtext">Start time: {{ exposure_start }} &nbsp&nbsp End time: {{ exposure_finish }}</p></li>
<li><p class="data_subtext">Start time: {{ infected_start }} &nbsp&nbsp End time: {{ infected_finish }}</p></li>
</ul>
{% if event_type == "single_event"%}
<li><p class="data_text">Single event on {{ single_event_date }}</p></li>

View file

@ -29,7 +29,7 @@ def test_ventilation_window(baseline_form):
cd_b=0.6, window_height=1.6, opening_length=0.6,
)
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
@ -107,3 +107,9 @@ def test_present_intervals(baseline_form):
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))
assert baseline_form.present_interval().present_times == correct
def test_key_validation(baseline_form_data):
baseline_form_data['activity_type'] = 'invalid key'
with pytest.raises(ValueError):
model_generator.FormData.from_dict(baseline_form_data)