Merge branch 'master' of https://gitlab.cern.ch/cara/cara into develop/expert_app_ventilation_temp

This commit is contained in:
Nicolas Mounet 2020-11-10 21:10:37 +01:00
commit 775339cdad
6 changed files with 78 additions and 28 deletions

View file

@ -24,11 +24,14 @@ class FormData:
coffee_duration: int
event_type: str
floor_area: float
hepa_amount: float
hepa_option: bool
infected_people: int
lunch_option: bool
mask_type: str
mask_wearing: str
mechanical_ventilation_type: str
model_version: str
opening_distance: float
recurrent_event_month: str
room_number: str
@ -58,6 +61,7 @@ class FormData:
validation_tuples = [('activity_type', ACTIVITY_TYPES),
('event_type', EVENT_TYPES),
('mechanical_ventilation_type', MECHANICAL_VENTILATION_TYPES),
('mask_type', MASK_TYPES),
('mask_wearing', MASK_WEARING),
('ventilation_type', VENTILATION_TYPES),
('volume_type', VOLUME_TYPES),
@ -89,13 +93,16 @@ class FormData:
coffee_duration=int(form_data['coffee_duration']),
event_type=form_data['event_type'],
floor_area=float(form_data['floor_area']),
hepa_amount=float(form_data['hepa_amount']),
hepa_option=(form_data['hepa_option'] == '1'),
infected_people=int(form_data['infected_people']),
lunch_finish=time_string_to_minutes(form_data['lunch_finish']),
lunch_option=(form_data['lunch_option'] == '1'),
lunch_start=time_string_to_minutes(form_data['lunch_start']),
mask_type=form_data['mask_type'],
mask_wearing=form_data['mask_wearing'],
mechanical_ventilation_type=form_data['mechanical_ventilation_type'],
model_version=form_data['model_version'],
opening_distance=float(form_data['opening_distance']),
recurrent_event_month=form_data['recurrent_event_month'],
room_number=form_data['room_number'],
@ -151,7 +158,7 @@ class FormData:
active=always_on, q_air_mech=self.air_supply)
if self.hepa_option:
hepa = models.HEPAFilter(active=always_on, q_air_mech=250.)
hepa = models.HEPAFilter(active=always_on, q_air_mech=self.hepa_amount)
return models.MultipleVentilation((ventilation,hepa))
else:
return ventilation
@ -228,9 +235,9 @@ def model_from_form(form: FormData) -> models.Model:
# Initializes the virus as SARS_Cov_2
virus = models.Virus.types['SARS_CoV_2']
# Initializes a mask of type 1 if mask wearing is "continuous", otherwise instantiates the mask attribute as
# Initializes the mask type if mask wearing is "continuous", otherwise instantiates the mask attribute as
# the "No mask"-mask
mask = models.Mask.types['Type I' if form.mask_wearing == "continuous" else 'No mask']
mask = models.Mask.types[form.mask_type if form.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.
@ -279,6 +286,7 @@ def baseline_raw_form_data():
'coffee_duration': '10',
'event_type': 'recurrent_event',
'floor_area': '',
'hepa_amount': '250',
'hepa_option': '0',
'infected_finish': '18:00',
'infected_people': '1',
@ -286,8 +294,10 @@ def baseline_raw_form_data():
'lunch_finish': '13:30',
'lunch_option': '1',
'lunch_start': '12:30',
'mask_type': 'Type I',
'mask_wearing': 'removed',
'mechanical_ventilation_type': '',
'model_version': 'BetaV1.1.0',
'opening_distance': '0.2',
'recurrent_event_month': 'January',
'room_number': '123',
@ -307,6 +317,7 @@ def baseline_raw_form_data():
ACTIVITY_TYPES = {'office', 'training', 'workshop'}
EVENT_TYPES = {'single_event', 'recurrent_event'}
MECHANICAL_VENTILATION_TYPES = {'air_changes', 'air_supply', 'not-applicable'}
MASK_TYPES = {'Type I', 'FFP2'}
MASK_WEARING = {'continuous', 'removed'}
VENTILATION_TYPES = {'natural', 'mechanical', 'no-ventilation'}
VOLUME_TYPES = {'room_volume', 'room_dimensions'}

View file

@ -87,8 +87,7 @@ def build_report(model: models.Model, form: FormData):
'model': model,
'request': request,
'form': form,
'creation_date': time,
'model_version': 'Beta v1.0.0',
'creation_date': time,
}
context.update(calculate_report_data(model))

View file

@ -15,7 +15,6 @@ function on_ventilation_type_change() {
});
}
function getChildElement(elem) {
// Get the element named in the given element's data-enables attribute.
return $("#" + elem.data("enables"));
@ -63,6 +62,18 @@ function require_fields(obj) {
case "lunch_option_yes":
require_lunch(true);
break;
case "mask_on":
require_mask(true);
break;
case "mask_off":
require_mask(false);
break;
case "hepa_yes":
require_hepa(true);
break;
case "hepa_no":
require_hepa(false);
break;
default:
break;
}
@ -122,9 +133,18 @@ function require_recurrent_event(option) {
function require_lunch(option) {
$("#lunch_start").prop('required', option);
$("#mask_ffp2").prop('required', option);
}
function require_lunch(option) {
$("#mask_type1").prop('required', option);
$("#lunch_finish").prop('required', option);
}
function require_hepa(option) {
$("#hepa_amount").prop('required', option);
}
function setMaxInfectedPeople() {
$("#infected_people").attr("max", $("#total_people").val());
}
@ -136,7 +156,6 @@ $(function () {
});
});
function show_disclaimer() {
var dots = document.getElementById("dots");
var moreText = document.getElementById("more");
@ -203,8 +222,7 @@ function parseValToNumber(obj) {
return parseInt(obj.val().replace(':',''), 10);
}
/* ------ On Load ---------- */
/* -------On Load------- */
$(document).ready(function () {
// When the document is ready, deal with the fact that we may be here
// as a result of a forward/back browser action. If that is the case, update
@ -230,7 +248,6 @@ $(document).ready(function () {
if (radioValue.val()) {
require_fields(radioValue.get(0));
}
});
/* -------Debugging------- */

View file

@ -1,6 +1,8 @@
{% extends "layout.html.j2" %}
{% set MODEL_VERSION="BetaV1.1.0" %}
{% set CALCULATOR_ACTIVE=1 %}
{% set DEBUG=False %}
{% block extra_headers %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" integrity="sha512-aOG0c6nPNzGk+5zjwyJaoRUgCdOrfSDhmMID2u4+OIslr0GjpLKo7Xm0Ao3xmpM4T8AmIouRkqwj1nrdVsLKEQ==" crossorigin="anonymous">
@ -18,10 +20,16 @@
<div class="text-component text-component-page clearfix"></div>
<div style="height: 8em; display: block;"></div>
Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to <a href="mailto:CARA-dev@cern.ch">CARA-dev@cern.ch</a></span>
{{ MODEL_VERSION }} <span style="float:right; font-weight:bold">Please send feedback to <a href="mailto:CARA-dev@cern.ch">CARA-dev@cern.ch</a></span>
<h1> <p><b>CARA</b> Covid Airborne Risk Assessment tool</p></h1>
{% if DEBUG %}
<form id="covid_calculator" name="covid_calculator" onsubmit="return debug_submit(this)">
{% else %}
<form id="covid_calculator" name="covid_calculator" action="/calculator/report" onsubmit="return validate_form(this)" method="POST">
{% endif %}
<input type="hidden" name="model_version" value={{ MODEL_VERSION }}></input>
<div style="width: 33%; float:left;">
@ -63,11 +71,20 @@ Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to
</div>
HEPA filtration:
<input type="radio" id="hepa_filter" name="hepa_option" value=1>
<label for="hepa_filter">Yes</label>
<input type="radio" id="hepa_filter" name="hepa_option" value=0 checked="checked">
<label for="hepa_filter">No</label>
<input type="radio" id="hepa_no" name="hepa_option" value=0 onclick="require_fields(this)" checked="checked">
<label for="hepa_no">No</label>
<input type="radio" id="hepa_yes" name="hepa_option" value=1 onclick="require_fields(this)">
<label for="hepa_yes">Yes</label>
<input type="number" step=0.01 id="hepa_amount" name="hepa_amount" placeholder="(m³ / hour)" min="0">
<hr width="80%">
<b>Face masks:</b><br>
Are masks worn when occupants are at workstations?
<input type="radio" id="mask_on" name="mask_wearing" value="continuous" required>Yes
<input type="radio" id="mask_off" name="mask_wearing" value="removed" required checked="checked">No<br>
Type of masks used:
<input type="radio" id="mask_type1" name="mask_type" value="Type I" checked="checked" onclick="require_fields(this)">Type 1
<input type="radio" id="mask_ffp2" name="mask_type" value="FFP2" onclick="require_fields(this)">FFP2<br>
<hr width="80%">
</div>
@ -79,6 +96,7 @@ Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to
Total number of occupants: <input type="number" id="total_people" name="total_people" min=1 required><br>
Number of infected people: <input type="number" id="infected_people" name="infected_people" min=1 required><br>
<hr width="80%">
Activity type: <select id="activity_type" name="activity_type">
<option value="office">Office/Meeting</option>
<option value="workshop">Workshop</option>
@ -91,8 +109,8 @@ Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to
Start: <input type="time" id="infected_start" name="infected_start" value="09:00" required> &nbsp;&nbsp;
Finish: <input type="time" id="infected_finish" class="finish_time" name="infected_finish" value="18:00" required>
<span id="infected_time_error" class="red_text" hidden>Finish time must be after start</span><br>
<hr width="80%">
When is the event?<br>
<input type="radio" id="event_type_single" name="event_type" value="single_event" onclick="require_fields(this)" required></input>
<label for="event_type_single">Single event</label> &nbsp;&nbsp;
@ -116,6 +134,7 @@ Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to
<option value="December">December</option>
</select><br>
<hr width="80%">
<!-- Lunch Options -->
Lunch break:
<input type="radio" id="lunch_option_no" name="lunch_option" value=0 checked="checked" onclick="require_fields(this)">
@ -147,13 +166,8 @@ Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to
<option value="30">30</option>
</select><br>
Coffee breaks are spread evenly throughout the day.
<br>
<hr width="80%">
Face masks: <br>
Are masks worn when occupants are at workstations? <br>
<input type="radio" id="continuous" name="mask_wearing" value="continuous" required>Yes
<input type="radio" id="removed" name="mask_wearing" value="removed" required checked="checked">No
</div>
<div style="width: 33%; float:left;">

View file

@ -13,7 +13,7 @@
<h1>Output from CARA - COVID Airborne Risk Assessment tool</h1>
<p class=subtitle> Created {{ creation_date }} using model version {{ model_version }}</p><br>
<p class=subtitle> Created {{ creation_date }} using model version {{ form.model_version }}</p><br>
<p>Simulation Name: {{ form.simulation_name }}</p>
<p>Room Number: {{ form.room_number }}</p>
@ -55,7 +55,11 @@
No </p></li>
{% endif %}
<li><p class="data_text">HEPA Filtration: {{ 'Yes' if form.hepa_option else 'No' }}</li>
<!--TODO: X type of filter with y flow rate (default model assumption) ? This was in the output doc..? -->
{% if form.hepa_option %}
<ul>
<li><p class="data_text">HEPA amount: {{ form.hepa_amount }}</p></li>
</ul>
{% endif %}
</ul>
<p class="data_title">Event data:</p>
@ -112,10 +116,10 @@
<p class="data_title">Mask wearing:</p>
<ul>
<li><p class="data_text">Masks worn at workstations?
{{ "No" if form.mask_wearing == "removed" else "Yes" }}
</p></li>
<li><p class="data_text">Mask type: Type 1</p></li>
<li><p class="data_text">Masks worn at workstations? {{ 'Yes' if form.mask_wearing == "continuous" else 'No' }} </p></li>
{% if form.mask_wearing == "continuous" %}
<li><p class="data_text">Mask type: {{ form.mask_type }}</p></li>
{% endif %}
</ul>
<p class="result_title">Results:</p>

View file

@ -338,6 +338,11 @@ Mask.types = {
η_leaks=0.15, # (Huang 2007)
η_inhale=0.3, # (Browen 2010)
),
'FFP2': Mask(
η_exhale=0.95, # (same outward effect as type 1 - Asadi 2020)
η_leaks=0.15, # (same outward effect as type 1 - Asadi 2020)
η_inhale=0.865, # (94% penetration efficiency + 8% max inward leakage -> EN 149)
),
}