Updated test values with Toronto temperatures.

This commit is contained in:
Luis Aleixo 2021-12-15 14:33:57 +00:00
parent 2df636d556
commit 8470ff42f4
49 changed files with 1969 additions and 14733 deletions

View file

@ -127,7 +127,7 @@ deploy_to_test:
rules:
- if: '$CI_COMMIT_BRANCH == "live/test-cara" && $OPENSHIFT_TEST_BUILD_WEBHOOK_SECRET'
script:
- curl -X POST -k https://openshift-dev.cern.ch:443/apis/build.openshift.io/v1/namespaces/test-cara/buildconfigs/cara-router/webhooks/${OPENSHIFT_TEST_BUILD_WEBHOOK_SECRET}/generic
- curl -X POST -k https://api.paas.okd.cern.ch/apis/build.openshift.io/v1/namespaces/test-cara/buildconfigs/cara-router/webhooks/${OPENSHIFT_TEST_BUILD_WEBHOOK_SECRET}/generic
oci_calculator:

View file

@ -35,7 +35,7 @@ Andre Henriques<sup>1</sup>, Luis Aleixo<sup>1</sup>, Marco Andreini<sup>1</sup>
<sup>5</sup>Information Technology Department, Collaboration, Devices & Applications Group, CERN<br>
<sup>6</sup>Norwegian University of Science and Technology (NTNU)<br>
### citation
### Citation
A. Henriques, M. Andreini, G. Azzopardi, J. Devine, P. Elson, N. Mounet, M. Kongstein, N. Tarocco. CARA - COVID Airborne Risk Assessment tools. CERN (2021).

View file

@ -33,7 +33,7 @@ from .user import AuthenticatedUser, AnonymousUser
# calculator version. If the calculator needs to make breaking changes (e.g. change
# form attributes) then it can also increase its MAJOR version without needing to
# increase the overall CARA version (found at ``cara.__version__``).
__version__ = "3.0.1"
__version__ = "3.2.0"
class BaseRequestHandler(RequestHandler):

View file

@ -305,7 +305,7 @@ class FormData:
# Initializes a ventilation instance as a window if 'natural_ventilation' is selected, or as a HEPA-filter otherwise
if self.ventilation_type == 'natural_ventilation':
if self.window_opening_regime == 'windows_open_periodically':
window_interval = models.PeriodicInterval(self.windows_frequency, self.windows_duration)
window_interval = models.PeriodicInterval(self.windows_frequency, self.windows_duration, min(self.infected_start, self.exposed_start))
else:
window_interval = always_on

View file

@ -1,17 +1,15 @@
import concurrent.futures
import base64
import dataclasses
from datetime import datetime, timedelta
from datetime import datetime
import io
import json
import typing
import urllib
import zlib
import loky
import jinja2
import numpy as np
import qrcode
import json
from cara import models
from ... import monte_carlo as mc
@ -110,10 +108,15 @@ def calculate_report_data(model: models.ExposureModel):
er = np.array(model.concentration_model.infected.emission_rate_when_present()).mean()
exposed_occupants = model.exposed.number
expected_new_cases = np.array(model.expected_new_cases()).mean()
cumulative_doses = np.cumsum([
np.array(model.exposure_between_bounds(float(time1), float(time2))).mean()
for time1, time2 in zip(times[:-1], times[1:])
])
return {
"times": list(times),
"exposed_presence_intervals": [list(interval) for interval in model.exposed.presence.boundaries()],
"cumulative_doses": list(cumulative_doses),
"concentrations": concentrations,
"highest_const": highest_const,
"prob_inf": prob,
@ -123,7 +126,7 @@ def calculate_report_data(model: models.ExposureModel):
}
def generate_qr_code(base_url, calculator_prefix, form: FormData):
def generate_permalink(base_url, calculator_prefix, form: FormData):
form_dict = FormData.to_dict(form, strip_defaults=True)
# Generate the calculator URL arguments that would be needed to re-create this
@ -136,20 +139,9 @@ def generate_qr_code(base_url, calculator_prefix, form: FormData):
qr_url = f"{base_url}/_c/{compressed_args}"
url = f"{base_url}{calculator_prefix}?{args}"
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_H,
box_size=10,
border=4,
)
qr.add_data(qr_url)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white").convert('RGB')
return {
'image': img2base64(_img2bytes(img)),
'link': url,
'qr_url': qr_url,
'shortened': qr_url,
}
@ -313,14 +305,14 @@ class ReportGenerator:
context['alternative_scenarios'] = comparison_report(
alternative_scenarios, scenario_sample_times, executor_factory=executor_factory,
)
context['qr_code'] = generate_qr_code(base_url, self.calculator_prefix, form)
context['permalink'] = generate_permalink(base_url, self.calculator_prefix, form)
context['calculator_prefix'] = self.calculator_prefix
context['scale_warning'] = {
'level': 'yellow-2',
'incidence_rate': 'lower than 25 new cases per 100 000 inhabitants',
'onsite_access': 'of about 8000',
'level': 'orange-3',
'incidence_rate': 'somewhere in between 25 and 100 new cases per 100 000 inhabitants',
'onsite_access': 'of about 5000',
'threshold': ''
}
}
return context
def _template_environment(self) -> jinja2.Environment:

View file

@ -18,6 +18,18 @@
font-size: 9pt;
}
.center_radio {
align-self: center;
}
.start_time, .finish_time {
margin-bottom: 10px;
}
.sub_title {
margin-bottom: 5px;
}
/* -------Tool tip ------- */
.tooltip_text {

View file

@ -56,7 +56,7 @@ p.notes {
margin: 1%
}
#pdf-qr-code {
#pdf_qrcode_aref {
margin-right: 1%;
width: 100pt;
}
@ -102,11 +102,6 @@ p.notes {
border-radius: 5px;
}
.print-button {
margin-left: auto;
margin-right: 1%;
}
/* @media (width: 1200px) { */
@media print {
/* #body {
@ -120,7 +115,7 @@ p.notes {
#link_reproduce_results {
display: none!important;
}
#pdf-qr-code {
#pdf_qrcode_aref {
visibility: inherit!important;
}
.collapse {
@ -138,17 +133,15 @@ p.notes {
.icon_button {
display: none!important;
}
.print-button {
display: none!important;
}
.card {
page-break-inside: avoid;
}
/* CSS styling to avoid page breaks. */
.break-after {
page-break-after: always;
#link-results {
display: none;
}
.break-avoid {
#disclaimer {
border: 2px solid black;
padding: 15px;
page-break-inside: avoid;
}
}
@ -162,7 +155,8 @@ p.notes {
position: relative;
text-align: center;
border-radius: 100px;
z-index: 1
z-index: 1;
-webkit-print-color-adjust: exact!important;
}
.intro-banner-vdo-play-btn i {
@ -235,7 +229,7 @@ p.notes {
.split>* {
flex-basis: 100%;
}
.header-text {
.paragraph-title {
text-align: left;
}
.split>*+* {

View file

@ -236,6 +236,20 @@ function on_ventilation_type_change() {
});
}
function on_wearing_mask_change() {
wearing_mask = $('input[type=radio][name=mask_wearing_option]')
wearing_mask.each(function (index) {
if (this.checked) {
getChildElement($(this)).show();
require_fields(this);
}
else {
getChildElement($(this)).hide();
require_fields(this);
}
})
}
/* -------UI------- */
function show_disclaimer() {
@ -365,6 +379,14 @@ function validate_form(form) {
}
}
if (submit) {
$("#generate_report").prop("disabled", true);
//Add spinner to button
$("#generate_report").html(
`<span id="loading_spinner" class="spinner-border spinner-border-sm mr-2" role="status" aria-hidden="true"></span>Loading...`
);
}
return submit;
}
@ -479,12 +501,17 @@ function parseTimeToMins(cTime) {
return parseInt(time[1]*60) + parseInt(time[2]);
}
// Prevent spinner when clicking on back button
window.onpagehide = function(){
$('loading_spinner').remove();
$("#generate_report").prop("disabled", false).html(`Generate report`);
};
/* -------On Load------- */
$(document).ready(function () {
var url = new URL(decodeURIComponent(window.location.href));
//Pre-fill form with known values
url.searchParams.forEach((value, name) => {
//If element exists
if(document.getElementsByName(name).length > 0) {
var elemObj = document.getElementsByName(name)[0];
@ -545,6 +572,12 @@ $(document).ready(function () {
// Call the function now to handle forward/back button presses in the browser.
on_ventilation_type_change();
// When the mask_wearing_option changes we want to make its respective
// children show/hide.
$("input[type=radio][name=mask_wearing_option]").change(on_wearing_mask_change);
// Call the function now to handle forward/back button presses in the browser.
on_wearing_mask_change();
// Setup the maximum number of people at page load (to handle back/forward),
// and update it when total people is changed.
setMaxInfectedPeople();
@ -598,7 +631,7 @@ $(document).ready(function () {
},
cache: true
},
placeholder: 'Search for a location',
placeholder: 'Geneva, CHE',
minimumInputLength: 1,
templateResult: formatlocation,
templateSelection: formatLocationSelection

View file

@ -1,29 +0,0 @@
function generate_pdf_version(qr_link) {
const pdf_version = this.document.getElementById("body");
// PDF styling
var opt = {
filename: 'myfile.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2, width: 1200, windowWidth: 1200 },
enableLinks: false,
jsPDF: {
unit: 'pt',
format: 'letter',
orientation: 'portrait',
},
pagebreak: { mode: '', avoid: '.break-avoid' },
};
html2pdf().set(opt).from(pdf_version).toPdf().get('pdf').then(function(pdf) {
var totalPages = pdf.internal.getNumberOfPages();
pdf.setPage(1);
pdf.link(530, 25, 60, 60, { url: qr_link }); //Hyperlink to reproduce results
for (i = 1; i <= totalPages; i++) {
pdf.setPage(i);
pdf.setFontSize(10);
pdf.setTextColor(150);
pdf.text('Page ' + i + ' of ' + totalPages, (pdf.internal.pageSize.getWidth() / 2.25), (pdf.internal.pageSize.getHeight() - 10));
}
}).save();
};

View file

@ -1,93 +1,135 @@
/* Generate the concentration plot using d3 library. */
function draw_concentration_plot(svg_id, times, concentrations, exposed_presence_intervals) {
var visBoundingBox = d3.select(svg_id)
.node()
.getBoundingClientRect();
function draw_concentration_plot(svg_id, times, concentrations, cumulative_doses, exposed_presence_intervals) {
console.log(cumulative_doses)
var time_format = d3.timeFormat('%H:%M');
var data = []
times.map((time, index) => data.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': concentrations[index] }))
var data_for_graphs = {
'concentrations': [],
'cumulative_doses': [],
}
times.map((time, index) => data_for_graphs.concentrations.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': concentrations[index]}));
times.map((time, index) => data_for_graphs.cumulative_doses.push({ 'time': time, 'hour': new Date().setHours(Math.trunc(time), (time - Math.trunc(time)) * 60), 'concentration': cumulative_doses[index]}));
var vis = d3.select(svg_id),
width = visBoundingBox.width - 300,
height = visBoundingBox.height,
margins = { top: 30, right: 20, bottom: 50, left: 50 },
// Add main SVG element
var plot_div = document.getElementById(svg_id);
var vis = d3.select(plot_div).append('svg');
// H:M time format for x axis.
xRange = d3.scaleTime().range([margins.left, width - margins.right]).domain([data[0].hour, data[data.length - 1].hour]),
xTimeRange = d3.scaleLinear().range([margins.left, width - margins.right]).domain([data[0].time, data[data.length - 1].time]),
bisecHour = d3.bisector((d) => { return d.hour; }).left,
// H:M time format for x axis.
xRange = d3.scaleTime().domain([data_for_graphs.concentrations[0].hour, data_for_graphs.concentrations[data_for_graphs.concentrations.length - 1].hour]),
xTimeRange = d3.scaleLinear().domain([data_for_graphs.concentrations[0].time, data_for_graphs.concentrations[data_for_graphs.concentrations.length - 1].time]),
bisecHour = d3.bisector((d) => { return d.hour; }).left,
yRange = d3.scaleLinear().range([height - margins.bottom, margins.top]).domain([0., Math.max(...concentrations)]),
yRange = d3.scaleLinear().domain([0., Math.max(...concentrations)]),
yCumulativeRange = d3.scaleLinear().domain([0., Math.max(...cumulative_doses)*1.1]),
xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d)),
yAxis = d3.axisLeft(yRange);
// Plot tittle.
plot_title(vis, width, margins.top, 'Mean concentration of virions');
xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d)),
yAxis = d3.axisLeft(yRange).ticks(4),
yCumulativeAxis = d3.axisRight(yCumulativeRange).ticks(4);
// Line representing the mean concentration.
plot_scenario_data(vis, data, xTimeRange, yRange, '#1f77b4');
var lineFunc = d3.line();
var draw_line = vis.append('svg:path')
.attr('stroke', '#1f77b4')
.attr('stroke-width', 2)
.attr('fill', 'none');
// X axis.
plot_x_axis(vis, height, width, margins, xAxis, 'Time of day');
// Y axis
plot_y_axis(vis, height, width, margins, yAxis, 'Mean concentration (virions/m³)')
var lineCumulative = d3.line();
var draw_cumulative_line = vis.append('svg:path')
.attr('stroke', '#1f77b4')
.attr('stroke-width', 2)
.style("stroke-dasharray", "5 5")
.attr('fill', 'none');
// Area representing the presence of exposed person(s).
exposed_presence_intervals.forEach(b => {
var curveFunc = d3.area()
.x(d => xTimeRange(d.time))
.y0(height - margins.bottom)
.y1(d => yRange(d.concentration));
vis.append('svg:path')
.attr('d', curveFunc(data.filter(d => {
return d.time >= b[0] && d.time <= b[1]
})))
var exposedArea = {};
var drawArea = {};
exposed_presence_intervals.forEach((b, index) => {
exposedArea[index] = d3.area();
drawArea[index] = vis.append('svg:path')
.attr('fill', '#1f77b4')
.attr('fill-opacity', '0.1');
})
});
// Plot tittle.
var plotTitleEl = vis.append('svg:foreignObject')
.attr("background-color", "transparent")
.attr('height', 30)
.style('text-align', 'center')
.html('<b>Mean concentration of virions</b>');
// X axis declaration.
var xAxisEl = vis.append('svg:g')
.attr('class', 'x axis');
// X axis label.
var xAxisLabelEl = vis.append('text')
.attr('class', 'x label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text('Time of day')
// Y axis declaration.
var yAxisEl = vis.append('svg:g')
.attr('class', 'y axis');
// Y axis label.
var yAxisLabelEl = vis.append('svg:text')
.attr('class', 'y label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text('Mean concentration (virions/m³)');
// Y cumulative concentration axis declaration.
var yAxisCumEl = vis.append('svg:g')
.attr('class', 'y axis')
.style('font-size', 14)
.style("stroke-dasharray", "5 5");
// Y cumulated concentration axis label.
var yAxisCumLabelEl = vis.append('svg:text')
.attr('class', 'y label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text('Mean cumulative dose (virions)');
// Legend for the plot elements - line and area.
var size = 20
vis.append('rect')
.attr('x', width + size)
.attr('y', margins.top + size)
var legendLineIcon = vis.append('rect')
.attr('width', 20)
.attr('height', 3)
.style('fill', '#1f77b4');
vis.append('rect')
.attr('x', width + size)
.attr('y', 3 * size)
var legendCumulativeIcon = vis.append('line')
.style("stroke-dasharray", "5 5") //dashed array for line
.attr('stroke-width', '2')
.style("stroke", '#1f77b4');
var legendAreaIcon = vis.append('rect')
.attr('width', 20)
.attr('height', 20)
.attr('fill', '#1f77b4')
.attr('fill-opacity', '0.1');
vis.append('text')
.attr('x', width + 3 * size)
.attr('y', margins.top + size)
var legendLineText = vis.append('text')
.text('Mean concentration')
.style('font-size', '15px')
.attr('alignment-baseline', 'central');
vis.append('text')
.attr('x', width + 3 * size)
.attr('y', margins.top + 2 * size)
var legendCumutiveText = vis.append('text')
.text('Cumulative dose')
.style('font-size', '15px')
.attr('alignment-baseline', 'central');
var legendAreaText = vis.append('text')
.text('Presence of exposed person(s)')
.style('font-size', '15px')
.attr('alignment-baseline', 'central');
// Legend bounding box.
vis.append('rect')
.attr('width', 275)
.attr('height', 50)
.attr('x', width * 1.005)
.attr('y', margins.top + 5)
// Legend bounding
var legendBBox = vis.append('rect')
.attr('width', 255)
.attr('height', 70)
.attr('stroke', 'lightgrey')
.attr('stroke-width', '2')
.attr('rx', '5px')
@ -96,57 +138,239 @@ function draw_concentration_plot(svg_id, times, concentrations, exposed_presence
.attr('fill', 'none');
// Tooltip.
var focus = vis.append('svg:g')
.style('display', 'none');
var focus = {}, tooltip_rect = {}, tooltip_time = {}, tooltip_concentration = {}, toolBox = {};
for (const [concentration, data] of Object.entries(data_for_graphs)) {
focus.append('circle')
.attr('r', 3);
focus[concentration] = vis.append('svg:g')
.style('display', 'none');
focus.append('rect')
.attr('fill', 'white')
.attr('stroke', '#000')
.attr('width', 80)
.attr('height', 50)
.attr('x', 10)
.attr('y', -22)
.attr('rx', 4)
.attr('ry', 4);
focus[concentration].append('circle')
.attr('r', 3);
focus.append('text')
.attr('id', 'tooltip-time')
.attr('x', 18)
.attr('y', -2);
tooltip_rect[concentration] = focus[concentration].append('rect')
.attr('fill', 'white')
.attr('stroke', '#000')
.attr('width', 85)
.attr('height', 50)
.attr('x', 10)
.attr('y', -22)
.attr('rx', 4)
.attr('ry', 4);
focus.append('text')
.attr('id', 'tooltip-concentration')
.attr('x', 18)
.attr('y', 18);
tooltip_time[concentration] = focus[concentration].append('text')
.attr('id', 'tooltip-time')
.attr('x', 18)
.attr('y', -2);
vis.append('rect')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.attr('width', width - margins.right)
.attr('height', height)
.on('mouseover', () => { focus.style('display', null); })
.on('mouseout', () => { focus.style('display', 'none'); })
.on('mousemove', mousemove);
tooltip_concentration[concentration] = focus[concentration].append('text')
.attr('id', 'tooltip-concentration')
.attr('x', 18)
.attr('y', 18);
toolBox[concentration] = vis.append('rect')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.on('mouseover', () => { for (const [concentration, data] of Object.entries(focus)) focus[concentration].style('display', null); })
.on('mouseout', () => { for (const [concentration, data] of Object.entries(focus)) focus[concentration].style('display', 'none'); })
.on('mousemove', mousemove);
}
var graph_width;
var graph_height;
function redraw() {
// Define width and height according to the screen size.
var div_width = plot_div.clientWidth;
var div_height = plot_div.clientHeight;
graph_width = div_width;
graph_height = div_height
if (div_width >= 900) { // For screens with width > 900px legend can be on the graph's right side.
var margins = { top: 30, right: 20, bottom: 50, left: 60 };
div_width = 900;
graph_width = div_width * (2/3);
const svg_margins = {'margin-left': '0rem', 'margin-top': '0rem'};
Object.entries(svg_margins).forEach(([prop,val]) => vis.style(prop,val));
}
else {
var margins = { top: 30, right: 20, bottom: 50, left: 40 };
div_width = div_width * 1.1
graph_width = div_width * .9;
graph_height = div_height * 0.65; // On mobile screen sizes we want the legend to be on the bottom of the graph.
const svg_margins = {'margin-left': '-1rem', 'margin-top': '3rem'};
Object.entries(svg_margins).forEach(([prop,val]) => vis.style(prop,val));
};
// Use the extracted size to set the size of the SVG element.
vis.attr("width", div_width)
.attr('height', div_height);
// SVG components according to the width and height.
// Axis ranges.
xRange.range([margins.left, graph_width - margins.right]);
xTimeRange.range([margins.left, graph_width - margins.right]);
yRange.range([graph_height - margins.bottom, margins.top]);
yCumulativeRange.range([graph_height - margins.bottom, margins.top]);
// Line.
lineFunc.defined(d => !isNaN(d.concentration))
.x(d => xTimeRange(d.time))
.y(d => yRange(d.concentration));
draw_line.attr("d", lineFunc(data_for_graphs.concentrations));
// Cumulative line
lineCumulative.defined(d => !isNaN(d.concentration))
.x(d => xTimeRange(d.time))
.y(d => yCumulativeRange(d.concentration));
draw_cumulative_line.attr("d", lineCumulative(data_for_graphs.cumulative_doses));
// Area.
exposed_presence_intervals.forEach((b, index) => {
exposedArea[index].x(d => xTimeRange(d.time))
.y0(graph_height - margins.bottom)
.y1(d => yRange(d.concentration));
drawArea[index].attr('d', exposedArea[index](data_for_graphs.concentrations.filter(d => {
return d.time >= b[0] && d.time <= b[1]
})));
});
// Title.
plotTitleEl.attr('width', graph_width);
// Axis.
var xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d));
var yAxis = d3.axisLeft(yRange);
xAxisEl.attr('transform', 'translate(0,' + (graph_height - margins.bottom) + ')')
.call(xAxis);
xAxisLabelEl.attr('x', (graph_width + margins.right) / 2)
.attr('y', graph_height * 0.97);
yAxisEl.attr('transform', 'translate(' + margins.left + ',0)').call(yAxis);
yAxisLabelEl.attr('x', (graph_height * 0.9 + margins.bottom) / 2)
.attr('y', (graph_height + margins.left) * 0.9)
.attr('transform', 'rotate(-90, 0,' + graph_height + ')');
yAxisCumEl.attr('transform', 'translate(' + (graph_width - margins.right) + ',0)').call(yCumulativeAxis);
yAxisCumLabelEl.attr('transform', 'rotate(-90, 0,' + graph_height + ')')
.attr('x', (graph_height + margins.bottom) / 2);
if (plot_div.clientWidth >= 900) {
yAxisCumLabelEl.attr('transform', 'rotate(-90, 0,' + graph_height + ')')
.attr('x', (graph_height + margins.bottom) / 2)
.attr('y', 1.71 * graph_width);
}
else {
yAxisCumLabelEl.attr('transform', 'rotate(-90, 0,' + graph_height + ')')
.attr('x', (graph_height + margins.bottom * 0.55) / 2)
.attr('y', graph_width + 290);
}
// Legend on right side.
const size = 20;
if (plot_div.clientWidth >= 900) {
legendLineIcon.attr('x', graph_width + size * 2.5)
.attr('y', margins.top + size);
legendLineText.attr('x', graph_width + 4 * size)
.attr('y', margins.top + size);
legendCumulativeIcon.attr("x1", graph_width + size + 30)
.attr("x2", graph_width + 2 * size + 32)
.attr("y1", 3.5 * size)
.attr("y2", 3.5 * size);
legendCumutiveText.attr('x', graph_width + 2.5 * size + 30)
.attr('y', margins.top + 2 * size);
legendAreaIcon.attr('x', graph_width + size * 2.5)
.attr('y', margins.top + 2.5 * size);
legendAreaText.attr('x', graph_width + 4 * size)
.attr('y', margins.top + 3 * size);
legendBBox.attr('x', graph_width * 1.07)
.attr('y', margins.top * 1.2);
}
// Legend on the bottom.
else {
legendLineIcon.attr('x', size * 0.5)
.attr('y', graph_height * 1.05);
legendLineText.attr('x', 2 * size)
.attr('y', graph_height * 1.05);
legendCumulativeIcon.attr("x1", size * 0.5)
.attr("x2", size * 1.55)
.attr("y1", graph_height * 1.05 + size)
.attr("y2", graph_height * 1.05 + size);
legendCumutiveText.attr('x', 2 * size)
.attr('y', graph_height + 1.65 * size);
legendAreaIcon.attr('x', size * 0.50)
.attr('y', graph_height * 1.09 + size);
legendAreaText.attr('x', 2 * size)
.attr('y', graph_height + 2.7 * size);
legendBBox.attr('x', 1)
.attr('y', graph_height);
}
// ToolBox.
for (const [concentration, data] of Object.entries(data_for_graphs)) {
toolBox[concentration].attr('width', graph_width - margins.right)
.attr('height', graph_height);
}
}
// Draw for the first time to initialize.
redraw();
function mousemove() {
for (const [scenario, data] of Object.entries(data_for_graphs)) {
if (d3.pointer(event)[0] < graph_width / 2) {
tooltip_rect[scenario].attr('x', 10)
tooltip_time[scenario].attr('x', 18)
tooltip_concentration[scenario].attr('x', 18);
}
else {
tooltip_rect[scenario].attr('x', -90)
tooltip_time[scenario].attr('x', -82)
tooltip_concentration[scenario].attr('x', -82)
}
}
// Concentration line
var x0 = xRange.invert(d3.pointer(event, this)[0]),
i = bisecHour(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.hour > d1.hour - x0 ? d1 : d0;
focus.attr('transform', 'translate(' + xRange(d.hour) + ',' + yRange(d.concentration) + ')');
focus.select('#tooltip-time').text('x = ' + time_format(d.hour));
focus.select('#tooltip-concentration').text('y = ' + d.concentration.toFixed(2));
i = bisecHour(data_for_graphs.concentrations, x0, 1),
d0 = data_for_graphs.concentrations[i - 1],
d1 = data_for_graphs.concentrations[i];
if (d1) {
var d = x0 - d0.hour > d1.hour - x0 ? d1 : d0;
focus.concentrations.attr('transform', 'translate(' + xRange(d.hour) + ',' + yRange(d.concentration) + ')');
focus.concentrations.select('#tooltip-time').text('x = ' + time_format(d.hour));
focus.concentrations.select('#tooltip-concentration').text('y = ' + d.concentration.toFixed(2));
}
// Cumulative line
var x0 = xRange.invert(d3.pointer(event, this)[0]),
i = bisecHour(data_for_graphs.cumulative_doses, x0, 1),
d0 = data_for_graphs.cumulative_doses[i - 1],
d1 = data_for_graphs.cumulative_doses[i];
if (d1 && d1.concentration) {
var d = x0 - d0.hour > d1.hour - x0 ? d1 : d0;
focus.cumulative_doses.attr('transform', 'translate(' + xRange(d.hour) + ',' + yCumulativeRange(d.concentration) + ')');
focus.cumulative_doses.select('#tooltip-time').text('x = ' + time_format(d.hour));
focus.cumulative_doses.select('#tooltip-concentration').text('y = ' + d.concentration.toFixed(2));
}
}
// Redraw based on the new size whenever the browser window is resized.
window.addEventListener("resize", redraw);
}
// Generate the alternative scenarios plot using d3 library.
// 'alternative_scenarios' is a dictionary with all the alternative scenarios
// 'times' is a list of times for all the scenarios
function draw_alternative_scenarios_plot(svg_id, width, height, alternative_scenarios, times) {
function draw_alternative_scenarios_plot(concentration_plot_svg_id, alternative_plot_svg_id, times, alternative_scenarios) {
// H:M format
var time_format = d3.timeFormat('%H:%M');
// D3 array of ten categorical colors represented as RGB hexadecimal strings.
@ -171,148 +395,252 @@ function draw_alternative_scenarios_plot(svg_id, width, height, alternative_scen
// We need one scenario to get the time range
var first_scenario = Object.values(data_for_scenarios)[0]
var vis = d3.select(svg_id),
width = width,
height = height,
margins = { top: 30, right: 20, bottom: 50, left: 50 },
// Add main SVG element
var alternative_plot_div = document.getElementById(alternative_plot_svg_id);
var vis = d3.select(alternative_plot_div).append('svg');
// H:M time format for x axis.
xRange = d3.scaleTime().range([margins.left, width - margins.right]).domain([first_scenario[0].hour, first_scenario[first_scenario.length - 1].hour]),
xTimeRange = d3.scaleLinear().range([margins.left, width - margins.right]).domain([times[0], times[times.length - 1]]),
var xRange = d3.scaleTime().domain([first_scenario[0].hour, first_scenario[first_scenario.length - 1].hour]);
var xTimeRange = d3.scaleLinear().domain([times[0], times[times.length - 1]]);
var bisecHour = d3.bisector((d) => { return d.hour; }).left;
yRange = d3.scaleLinear().range([height - margins.bottom, margins.top]).domain([0., highest_concentration]),
xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d)),
yAxis = d3.axisLeft(yRange);
// Plot title.
plot_title(vis, width, margins.top, 'Mean concentration of virions');
var yRange = d3.scaleLinear().domain([0., highest_concentration]);
// Line representing the mean concentration for each scenario.
var lineFuncs = {}, draw_lines = {}, label_icons = {}, label_text = {};
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
var scenario_index = Object.keys(data_for_scenarios).indexOf(scenario_name)
// Line representing the mean concentration.
plot_scenario_data(vis, data, xTimeRange, yRange, colors[scenario_index])
lineFuncs[scenario_name] = d3.line();
draw_lines[scenario_name] = vis.append('svg:path')
.attr("stroke", colors[scenario_index])
.attr('stroke-width', 2)
.attr('fill', 'none');
// Legend for the plot elements - lines.
var size = 20 * (scenario_index + 1)
vis.append('rect')
.attr('x', width + 20)
.attr('y', margins.top + size)
label_icons[scenario_name] = vis.append('rect')
.attr('width', 20)
.attr('height', 3)
.style('fill', colors[scenario_index]);
vis.append('text')
.attr('x', width + 3 * 20)
.attr('y', margins.top + size)
label_text[scenario_name] = vis.append('text')
.text(scenario_name)
.style('font-size', '15px')
.attr('alignment-baseline', 'central');
}
// Plot title.
var plotTitleEl = vis.append('svg:foreignObject')
.attr("background-color", "transparent")
.attr('height', 30)
.style('text-align', 'center')
.html('<b>Mean concentration of virions</b>');
// X axis.
plot_x_axis(vis, height, width, margins, xAxis, "Time of day");
var xAxisEl = vis.append('svg:g')
.attr('class', 'x axis');
// X axis label.
var xAxisLabelEl = vis.append('text')
.attr('class', 'x label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text('Time of day');
// Y axis declaration.
vis.append('svg:g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + margins.left + ',0)')
.call(yAxis);
var yAxisEl = vis.append('svg:g')
.attr('class', 'y axis');
// Y axis label.
vis.append('svg:text')
var yAxisLabelEl = vis.append('svg:text')
.attr('class', 'y label')
.attr('fill', 'black')
.attr('transform', 'rotate(-90, 0,' + height + ')')
.attr('text-anchor', 'middle')
.attr('x', (height + margins.bottom) / 2)
.attr('y', (height + margins.left) * 0.92)
.text('Mean concentration (virions/m³)');
// Legend bounding box.
vis.append('rect')
var legendBBox = vis.append('rect')
.attr('width', 275)
.attr('height', 25 * (Object.keys(data_for_scenarios).length))
.attr('x', width * 1.005)
.attr('y', margins.top + 5)
.attr('stroke', 'lightgrey')
.attr('stroke-width', '2')
.attr('rx', '5px')
.attr('ry', '5px')
.attr('stroke-linejoin', 'round')
.attr('fill', 'none');
// Tooltip.
var focus = {}, tooltip_rect = {}, tooltip_time = {}, tooltip_concentration = {}, toolBox = {};
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
focus[scenario_name] = vis.append('svg:g')
.style('display', 'none');
focus[scenario_name].append('circle')
.attr('r', 3);
tooltip_rect[scenario_name] = focus[scenario_name].append('rect')
.attr('fill', 'white')
.attr('stroke', '#000')
.attr('width', 80)
.attr('height', 50)
.attr('y', -22)
.attr('rx', 4)
.attr('ry', 4);
tooltip_time[scenario_name] = focus[scenario_name].append('text')
.attr('id', 'tooltip-time')
.attr('y', -2);
tooltip_concentration[scenario_name] = focus[scenario_name].append('text')
.attr('id', 'tooltip-concentration')
.attr('y', 18);
toolBox[scenario_name] = vis.append('rect')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.on('mouseover', () => { for (const [scenario_name, data] of Object.entries(focus)) focus[scenario_name].style('display', null); })
.on('mouseout', () => { for (const [scenario_name, data] of Object.entries(focus)) focus[scenario_name].style('display', 'none'); })
.on('mousemove', mousemove);
}
var graph_width;
var graph_height;
function redraw() {
// Define width and height according to the screen size.
var div_width = document.getElementById(concentration_plot_svg_id).clientWidth;
var div_height = document.getElementById(concentration_plot_svg_id).clientHeight;
graph_width = div_width;
graph_height = div_height
if (div_width >= 900) { // For screens with width > 900px legend can be on the graph's right side.
var margins = { top: 30, right: 20, bottom: 50, left: 60 };
div_width = 900;
graph_width = div_width * (2/3);
const svg_margins = {'margin-left': '0rem'};
Object.entries(svg_margins).forEach(([prop,val]) => vis.style(prop,val));
}
else {
var margins = { top: 30, right: 20, bottom: 50, left: 40 };
div_width = div_width * 1.1
graph_width = div_width * .95;
graph_height = div_height * 0.65; // On mobile screen sizes we want the legend to be on the bottom of the graph.
const svg_margins = {'margin-left': '-1rem'};
Object.entries(svg_margins).forEach(([prop,val]) => vis.style(prop,val));
};
// Use the extracted size to set the size of the SVG element.
vis.attr("width", div_width)
.attr('height', div_height);
// SVG components according to the width and height.
// Axis ranges.
xRange.range([margins.left, graph_width - margins.right]);
xTimeRange.range([margins.left, graph_width - margins.right]);
yRange.range([graph_height - margins.bottom, margins.top]);
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
var scenario_index = Object.keys(data_for_scenarios).indexOf(scenario_name)
// Lines.
lineFuncs[scenario_name].defined(d => !isNaN(d.concentration))
.x(d => xTimeRange(d.time))
.y(d => yRange(d.concentration));
draw_lines[scenario_name].attr("d", lineFuncs[scenario_name](data));
// Legend on right side.
var size = 20 * (scenario_index + 1);
if (document.getElementById(concentration_plot_svg_id).clientWidth >= 900) {
label_icons[scenario_name].attr('x', graph_width + 20)
.attr('y', margins.top + size);
label_text[scenario_name].attr('x', graph_width + 3 * 20)
.attr('y', margins.top + size);
}
// Legend on the bottom.
else {
label_icons[scenario_name].attr('x', margins.left * 0.3)
.attr('y', graph_height + size);
label_text[scenario_name].attr('x', margins.left * 1.4)
.attr('y', graph_height + size);
}
}
// Title.
plotTitleEl.attr('width', graph_width);
// Axis.
var xAxis = d3.axisBottom(xRange).tickFormat(d => time_format(d));
var yAxis = d3.axisLeft(yRange);
xAxisEl.attr('transform', 'translate(0,' + (graph_height - margins.bottom) + ')')
.call(xAxis);
xAxisLabelEl.attr('x', (graph_width + margins.right) / 2)
.attr('y', graph_height * 0.97)
yAxisEl.attr('transform', 'translate(' + margins.left + ',0)')
.call(yAxis);
yAxisLabelEl.attr('transform', 'rotate(-90, 0,' + graph_height + ')')
.attr('x', (graph_height * 0.9 + margins.bottom) / 2)
.attr('y', (graph_height + margins.left) * 0.90);
// Legend on right side.
if (document.getElementById(concentration_plot_svg_id).clientWidth >= 900) {
legendBBox.attr('x', graph_width * 1.02)
.attr('y', margins.top * 1.15);
}
// Legend on the bottom.
else {
legendBBox.attr('x', 1)
.attr('y', graph_height * 1.02)
}
// ToolBox.
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
toolBox[scenario_name].attr('width', graph_width - margins.right)
.attr('height', graph_height);
}
}
// Draw for the first time to initialize.
redraw();
function mousemove() {
for (const [scenario_name, data] of Object.entries(data_for_scenarios)) {
if (d3.pointer(event)[0] < graph_width / 2) {
tooltip_rect[scenario_name].attr('x', 10)
tooltip_time[scenario_name].attr('x', 18)
tooltip_concentration[scenario_name].attr('x', 18);
}
else {
tooltip_rect[scenario_name].attr('x', -90)
tooltip_time[scenario_name].attr('x', -82)
tooltip_concentration[scenario_name].attr('x', -82)
}
var x0 = xRange.invert(d3.pointer(event, this)[0]),
i = bisecHour(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.hour > d1.hour - x0 ? d1 : d0;
focus[scenario_name].attr('transform', 'translate(' + xRange(d.hour) + ',' + yRange(d.concentration) + ')');
focus[scenario_name].select('#tooltip-time').text('x = ' + time_format(d.hour));
focus[scenario_name].select('#tooltip-concentration').text('y = ' + d.concentration.toFixed(2));
}
}
// Redraw based on the new size whenever the browser window is resized.
window.addEventListener("resize", redraw);
}
function copy_clipboard(shareable_link) {
// Functions used to build the plots' components
function plot_title(vis, width, margin_top, title) {
vis.append('svg:foreignObject')
.attr('width', width)
.attr('height', margin_top)
.attr('fill', 'none')
.append('xhtml:div')
.style('text-align', 'center')
.html(title);
return vis;
}
function plot_x_axis(vis, height, width, margins, xAxis, label) {
// X axis declaration
vis.append('svg:g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + (height - margins.bottom) + ')')
.call(xAxis);
// X axis label.
vis.append('text')
.attr('class', 'x label')
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.attr('x', (width + margins.right) / 2)
.attr('y', height * 0.97)
.text(label);
return vis;
}
function plot_y_axis(vis, height, width, margins, yAxis, label) {
// Y axis declaration.
vis.append('svg:g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + margins.left + ',0)')
.call(yAxis);
// Y axis label.
vis.append('svg:text')
.attr('class', 'y label')
.attr('fill', 'black')
.attr('transform', 'rotate(-90, 0,' + height + ')')
.attr('text-anchor', 'middle')
.attr('x', (height + margins.bottom) / 2)
.attr('y', (height + margins.left) * 0.92)
.text(label);
return vis;
}
function plot_scenario_data(vis, data, xTimeRange, yRange, line_color) {
var lineFunc = d3.line()
.defined(d => !isNaN(d.concentration))
.x(d => xTimeRange(d.time))
.y(d => yRange(d.concentration))
.curve(d3.curveBasis);
vis.append('svg:path')
.attr('d', lineFunc(data))
.attr("stroke", line_color)
.attr('stroke-width', 2)
.attr('fill', 'none');
return vis;
$("#mobile_link").attr('title', 'Copied!')
.tooltip('_fixTitle')
.tooltip('show');
navigator.clipboard.writeText(shareable_link);
}

View file

@ -2,12 +2,13 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0">
<title>Report | CARA (COVID Airborne Risk Assessment)</title>
<link rel="stylesheet" type="text/css" href="{{ calculator_prefix }}/static/css/report.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="/static/css/style.css">
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="{{ calculator_prefix }}/static/js/report.js" type="application/javascript"></script>
@ -17,15 +18,14 @@
{% block report_header %}
<div id="report-header-div" class="d-flex flex-row">
<img id="cara_logo" src="/static/images/cara_logo.200x200.png" class="d-inline-block align-middle">
<div class="d-flex align-self-center flex-column mr-auto" style="margin-left: 1em;">
<h2 class="text-component-title mb-0">CARA - CALCULATOR REPORT</h1>
<p class="mb-0"> Created {{ creation_date }} using CARA calculator version v{{ form.calculator_version }}</p>
<div id="report-header-div" class="d-flex flex-row" style="margin: 1%">
<img id="report_logo" src="/static/images/cara_logo.200x200.png" class="d-inline-block align-middle mr-3">
<div style="margin-right: -105px" class='align-self-center mr-auto'>
<h2 class="header_text mb-0">REPORT</h1>
<p class="mb-0" id="report_version"> Created {{ creation_date }} using CARA calculator version v{{ form.calculator_version }}</p>
</div>
<button type="button" class="btn btn-outline-dark align-self-center" style="margin-right: -100pt" id="download-pdf" onclick="print()">Print Report</button>
{# To be replaced by "Generate PDF" #}
<img id="pdf-qr-code" class="align-self-center invisible" src="{{ qr_code.image }}"/>
<button type="button" class="btn btn-outline-dark align-self-center" id="download-pdf" style="margin-right: -100pt" onclick="print()">Print Report</button>
<a href="{{ permalink.link }}" style="float: left;" id="pdf_qrcode_aref" class="align-self-center invisible mr-0"><div id="pdf_qrcode"></div></a>
</div>
{% endblock report_header %}
@ -60,38 +60,43 @@
<p class="card-text">
<div class="align-self-center">
<div class="d-flex">
<div style="min-width: 25%">
<div class="split">
<div class="col-md-3">
<div style="text-align:center"><b>Probability of infection (%)</b></div>
<div class="d-flex" style="min-height: 160px">
{% block warning_animation %}
<div class="intro-banner-vdo-play-btn bg-secondary m-auto d-flex align-items-center justify-content-center">
<div class="intro-banner-vdo-play-btn animation-color m-auto d-flex align-items-center justify-content-center">
<b>{{prob_inf | non_zero_percentage}}</b>
<i class="glyphicon glyphicon-play whiteText" aria-hidden="true"></i>
<span class="ripple bg-secondary"></span>
<span class="ripple bg-secondary"></span>
<span class="ripple bg-secondary"></span>
<span class="ripple animation-color"></span>
<span class="ripple animation-color"></span>
<span class="ripple animation-color"></span>
</div>
{% endblock warning_animation %}
</div>
</div>
{% block report_summary %}
<div class="align-self-center alert alert-dark" role="alert">
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
</div>
{% endblock report_summary %}
<div class="col-md-8 pr-0 pl-0 d-flex">
{% block report_summary %}
<div class="align-self-center alert alert-dark mb-0" role="alert">
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
</div>
{% endblock report_summary %}
</div>
</div>
</div>
<br>
{% block report_summary_footnote %}
{% endblock report_summary_footnote %}
</div>
<p id="section1">* The results are based on the parameters and assumptions published in the CERN Open Report <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a>.</p>
<svg id="result_plot" width="900" height="400"></svg>
<div id="concentration_plot" style="height: 400px"></div>
<script type="application/javascript">
var times = {{ times | JSONify }}
var concentrations = {{ concentrations | JSONify }}
var cumulative_doses = {{ cumulative_doses | JSONify }}
var exposed_presence_intervals = {{ exposed_presence_intervals | JSONify }}
draw_concentration_plot("#result_plot", times, concentrations, exposed_presence_intervals);
draw_concentration_plot("concentration_plot", times, concentrations, cumulative_doses, exposed_presence_intervals);
</script>
</p>
</div>
@ -108,12 +113,13 @@
<div class="collapse" id="collapseAlternativeScenarios">
<div class="card-body">
<div>
<svg id="alternative_scenario_plot" width="900" height="400"></svg>
<div id="alternative_scenario_plot" style="height: 400px"></div>
<script type="application/javascript">
var alternative_scenarios = {{ alternative_scenarios.stats | JSONify }}
var times = {{ times | JSONify }}
draw_alternative_scenarios_plot("#alternative_scenario_plot", width=600, height=400, alternative_scenarios, times);
draw_alternative_scenarios_plot("concentration_plot", "alternative_scenario_plot", times, alternative_scenarios);
</script>
<br>
{% block report_scenarios_summary_table %}
<table class="table w-auto">
<thead class="thead-light">
@ -151,7 +157,7 @@
{% endblock report_results %}
{% block report_footer %}
<div class="card bg-light mb-3" id="link_reproduce_results">
<div class="card bg-light mb-3" id="link-results">
<div class="card-header"><strong>Link to reproduce results </strong>
<button class="icon_button p-0 float-right" data-toggle="collapse" href="#collapseQRcode" role="button" aria-expanded="true" aria-controls="collapseQRcode">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-expand" viewBox="0 0 16 16">
@ -161,13 +167,14 @@
</div>
<div class="collapse show" id="collapseQRcode">
<div class="card-body">
<div>
<a href="{{ qr_code.link }}" style="float: left;"><img style="width:250pt;" id="qr_code" src="{{ qr_code.image }}"/></a>
<span style="float: left; min-height: 250pt; line-height: 250pt; vertical-align: middle; display: inline-block;">
<div class="text-center"><button id="mobile_link" class="btn btn-primary btn-sm d-none" data-toggle="tooltip" data-placement="top" title="Copy to clipboard" onclick="copy_clipboard('{{ permalink.link }}');">Click to copy a shareable link</button></div>
<div id="link_reproduce_results" class="split">
<div><a href="{{ permalink.link }}" style="float: left;"><div id="qrcode"></div></a></div>
<div class="align-self-center"><span style="float: left; vertical-align: middle; display: inline-block;">
<p style="display: inline-block; vertical-align: middle; line-height: normal;">
Click the QR code to regenerate the report and get a shareable link.<br>Alternatively, scan to regenerate the report.<br> Mobile-friendly app coming soon!
Click the QR code to regenerate the report and get a shareable link.<br>Alternatively, scan to regenerate the report.<br>
</p>
</span>
</span></div>
</div>
</div>
</div>
@ -293,7 +300,7 @@
{% elif form.activity_type == "workshop" %}
Workshop = assembly workshop environment, all persons doing moderate physical activity, speaking 50% of the time.
{% elif form.activity_type == "training" %}
Training one person (the trainer) standing, speaking, all others seated, speaking quietly (whispering). It is assumed the trainer is the infected person, for the worst case scenario.
Conference/Training one person (the speaker/trainer) standing, talking, all others seated, talking quietly (whispering). It is assumed the speaker/trainer is the infected person, for the worst case scenario.
{% elif form.activity_type == "lab" %}
Laboratory = Lab or technical environment, all persons doing light physical activity, speaking 50% of the time.
{% elif form.activity_type == "gym" %}
@ -302,11 +309,13 @@
</p></li>
<li><p class="data_text">Exposed occupant(s) activity time:</p></li>
<ul>
<li><p class="data_subtext">Start time: {{ form.exposed_start | minutes_to_time }} &nbsp&nbsp End time: {{ form.exposed_finish | minutes_to_time }}</p></li>
<li><p class="data_subtext">Start time: {{ form.exposed_start | minutes_to_time }}</p></li>
<li><p class="data_subtext">End time: {{ form.exposed_finish | minutes_to_time }}</p></li>
</ul>
<li><p class="data_text">Infected occupant(s) activity time:</p></li>
<ul>
<li><p class="data_subtext">Start time: {{ form.infected_start | minutes_to_time }} &nbsp&nbsp End time: {{ form.infected_finish | minutes_to_time }}</p></li>
<li><p class="data_subtext">Start time: {{ form.infected_start | minutes_to_time }}</p></li>
<li><p class="data_subtext">End time: {{ form.infected_finish | minutes_to_time }}</p></li>
</ul>
<li><p class="data_text">Event for the month of {{ form.event_month }}</p></li>
</ul>
@ -324,7 +333,8 @@
{% if form.exposed_lunch_option%}
Yes</li>
<ul>
<li><p class="data_subtext">Start time: {{ form.exposed_lunch_start | minutes_to_time }} &nbsp&nbsp End time: {{ form.exposed_lunch_finish | minutes_to_time }}</p></li>
<li><p class="data_subtext">Start time: {{ form.exposed_lunch_start | minutes_to_time }}</p></li>
<li><p class="data_subtext">End time: {{ form.exposed_lunch_finish | minutes_to_time }}</p></li>
</ul>
{% else%}
No
@ -349,7 +359,8 @@
{% if form.infected_lunch_option%}
Yes</li>
<ul>
<li><p class="data_subtext">Start time: {{ form.infected_lunch_start | minutes_to_time }} &nbsp&nbsp End time: {{ form.infected_lunch_finish | minutes_to_time }}</p></li>
<li><p class="data_subtext">Start time: {{ form.infected_lunch_start | minutes_to_time }}</p></li>
<li><p class="data_subtext">End time: {{ form.infected_lunch_finish | minutes_to_time }}</p></li>
</ul>
{% else%}
No
@ -393,7 +404,7 @@
{% block disclaimer_container %}
<br><br><br>
<div style="border: 2px solid black; padding: 15px;">
<div id="disclaimer" style="border: #dee2e6 1px solid; margin: 1%; padding: 20px" class="rounded">
{% block disclaimer %}
<p class="image"> <img align="middle" src="{{ calculator_prefix }}/static/images/disclaimer.jpg" width="40" height="40"><b>Disclaimer:</b><br><br></p>
@ -406,7 +417,7 @@
The report generated indicates how to avoid exceeding critical concentrations and chains of airborne transmission in spaces such as individual offices, meeting rooms and labs.
</p>
<p>
The risk assessment tool simulates the long-range airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 infection therein.
The risk assessment tool simulates the long-range airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 airborne transmission therein.
The results DO NOT include short-range airborne exposure (where the physical distance is a significant factor) nor the other known modes of SARS-CoV-2 transmission.
Hence, the output from this model is only valid when the other recommended public health & safety instructions are observed, such as adequate physical distancing, good hand hygiene and other barrier measures.
</p>
@ -435,11 +446,31 @@
</div>
{% endblock disclaimer_container %}
<script src="{{ calculator_prefix }}/static/js/pdf.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js" integrity="sha512-CNgIRecGo7nphbeZ04Sc13ka07paqdeTu0WR1IM4kNcpmBAUSHSQX0FslNhTDadL4O5SAGapGt4FodqL8My0mA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
//Enable tooltip
$('[data-toggle="tooltip"]').tooltip();
new QRCode(document.getElementById("qrcode"), {
text: "{{ permalink.shortened }}",
width: 330,
height: 330,
correctLevel : QRCode.CorrectLevel.L
});
new QRCode(document.getElementById("pdf_qrcode"), {
text: "{{ permalink.shortened }}",
width: 133,
height: 133,
correctLevel : QRCode.CorrectLevel.L
});
</script>
</body>
</html>

View file

@ -17,15 +17,17 @@
{% block main %}
<div style="margin: 2em;">
<div class="text-component text-component-page clearfix"></div>
<div style="height: 8em; display: block;"></div>
v{{ calculator_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>
<div>
<img src="/static/images/cara_logo.200x200.png" style="height: 7em; display:inline-block; vertical-align:middle; padding: 1em;">
<h1 style="display:inline-block; vertical-align:middle;"><b>CARA - </b> COVID Airborne Risk Assessment calculator</h1>
</div>
<span class="cara_version">v{{ calculator_version }}</span>
<span class="feedback">Please send feedback to <a href="mailto:CARA-dev@cern.ch">CARA-dev@cern.ch</a></span>
<header class= "bg-light">
<div class="container container--padding">
<div class="d-flex header-height">
<h1 class="align-self-center">Calculator</h1>
<img src="/static/images/cara_logo.200x200.png" class="logo_form align-self-center ml-3">
</div>
</div>
</header>
{% if DEBUG %}
<form id="covid_calculator" name="covid_calculator" onsubmit="return debug_submit(this)" class="form-inline">
@ -36,23 +38,24 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<input type="hidden" name="calculator_version" value="{{ calculator_version }}">
<div class="container-fluid">
<div class="row">
<div class="col-lg-4 col-md-6">
<section>
<div class="container container--padding">
<div class="split">
<div>
<!-- General Options -->
<div class="row">
<label class="col-xl-3 col-lg-4 col-sm-3 col-form-label">Simulation name:</label>
<input type="text" class="col-xl-5 col-lg-7 col-sm-7 col-7" name="simulation_name" placeholder="E.g. Workshop without masks" required>
<div class="form-group">
<b><label class="col-form-label">Simulation name:</label></b>
<input type="text" class="col-sm-10 form-control" name="simulation_name" placeholder="E.g. Workshop without masks" required>
</div>
<div class="row">
<label class="col-xl-3 col-lg-4 col-sm-3 col-form-label">Room number:</label>
<input type="text" class="col-xl-5 col-lg-7 col-sm-7 col-7" name="room_number" placeholder="E.g. 17/R-033" required>
<div class="form-group">
<b><label class="col-form-label">Room number:</label></b>
<input type="text" class="col-sm-10 form-control" name="room_number" placeholder="E.g. 17/R-033" required>
</div>
<hr width="80%">
<b>Virus data:</b>
<div data-tooltip="Choose the SARS-CoV-2 Variant of Concern (VOC).">
@ -75,52 +78,60 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<b>Room data:</b>
<div data-tooltip="The area you wish to study (choose one of the 2 options). Use GIS Portal or measure. Also indicate if a central (radiator-type) heating system is in use.">
<span class="tooltip_text">?</span>
</div><br>
</div>
<br>
<div class="row">
<div class="col-xl-3 col-lg-4 col-sm-3">
<div class="form-group row">
<div class="col-sm-4">
<input type="radio" id="room_data_volume" name="volume_type" value="room_volume_explicit" onclick="require_fields(this)" tabindex="-1" required>
<label class="col-form-label">Room volume:</label>
</div>
<input type="number" step="any" id="room_volume" class="non_zero col-xl-3 col-lg-5 col-md-7 col-sm-3 col-3" name="room_volume" placeholder="Room volume (m³)" min="0" data-has-radio="#room_data_volume">
</div>
<div class="row">
<div class="col-xl-3 col-lg-4 col-sm-3">
<input type="radio" id="room_data_dimensions" name="volume_type" value="room_volume_from_dimensions" onclick="require_fields(this)" tabindex="-1" required>
<label for="room_data_dimensions">Floor area:</label> &nbsp;&nbsp;
<div class="col-sm-6">
<input type="number" step="any" id="room_volume" class="non_zero form-control" name="room_volume" placeholder="Room volume (m³)" min="0" data-has-radio="#room_data_volume">
</div>
<input type="number" step="any" id="floor_area" class="non_zero col-xl-3 col-lg-5 col-md-7 col-sm-3 col-3" name="floor_area" placeholder="Room floor area (m²)" min="0" data-has-radio="#room_data_dimensions">
</div>
<div class="row">
<div class="col-xl-3 col-lg-4 col-sm-3">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <label for="room_data_dimensions">Ceiling height:</label> &nbsp;&nbsp;
</div>
<input type="number" step="any" id="ceiling_height" class="non_zero col-xl-3 col-lg-5 col-md-7 col-sm-3 col-3" name="ceiling_height" placeholder="Room ceiling height (m)" min="0" data-has-radio="#room_data_dimensions">
</div><br>
Central heating system in use:
<input type="radio" id="heating_no" name="room_heating_option" value=0 checked="checked">
<label for="heating_no">No</label>&nbsp;&nbsp;
<input type="radio" id="heating_yes" name="room_heating_option" value=1>
<label for="heating_yes">Yes</label>&nbsp;&nbsp;
<div class="row">
<label class="col-xl-2 col-lg-3 col-sm-2 col-form-label">Location:</label>
<div data-tooltip="The country is shown using a 3-letter code, e.g. CHE for Switzerland.">
<span class="tooltip_text">?</span>
<div class="form-group row">
<div class="col-sm-4">
<input type="radio" id="room_data_dimensions" name="volume_type" value="room_volume_from_dimensions" onclick="require_fields(this)" tabindex="-1" required>
<label for="room_data_dimensions">Floor area:</label>
</div>
<select id="location_select" form="not-submitted" class="col-xl-3 col-lg-7 col-sm-7 col-7" name="location_select" required></select>
<div style="display: none">
<!--
This block allows us to have hidden input values which are retained during forward/back navigation, as per
https://stackoverflow.com/a/6384276/741316
-->
<input type="text" name="location_name" />
<input type="text" name="location_latitude" />
<input type="text" name="location_longitude" />
<div class="col-sm-6">
<input type="number" step="any" id="floor_area" class="non_zero form-control" name="floor_area" placeholder="Room floor area (m²)" min="0" data-has-radio="#room_data_dimensions">
</div>
</div>
<div class="form-group row">
<div class="col-sm-4">
<label for="room_data_dimensions">Ceiling height:</label>
</div>
<div class="col-sm-6">
<input type="number" step="any" id="ceiling_height" class="non_zero form-control" name="ceiling_height" placeholder="Room ceiling height (m)" min="0" data-has-radio="#room_data_dimensions">
</div>
</div>
<div class="split">
<div>Central heating system in use:</div>
<div>
<input class="ml-2" type="radio" id="heating_no" name="room_heating_option" value=0 checked="checked">
<label for="heating_no">No</label>
<input class="ml-2" type="radio" id="heating_yes" name="room_heating_option" value=1>
<label for="heating_yes">Yes</label>
</div>
</div>
<div class="form-group row">
<div class="col-sm-5"><label class="col-form-label">Geographic location:</label></div>
<div class="col-sm-5 align-self-center"><select id="location_select" form="not-submitted" class="form-control" name="location_select" required></select></div>
</div>
<div style="display: none">
<!--
This block allows us to have hidden input values which are retained during forward/back navigation, as per
https://stackoverflow.com/a/6384276/741316
-->
<input type="text" name="location_name" value="Geneva, CHE">
<input type="text" name="location_latitude" value="46.20833">
<input type="text" name="location_longitude" value="6.14275">
</div>
<hr width="80%">
@ -129,70 +140,153 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<b>Ventilation data:</b>
<div data-tooltip="The available means of venting / filtration of indoor spaces.">
<span class="tooltip_text">?</span>
</div><br>
Ventilation type:
</div>
<br>
<div class='sub_title'>Ventilation type:</div>
<div class="split">
<div>
<input type="radio" id="no_ventilation" name="ventilation_type" value="no_ventilation" checked>
<label for="no_ventilation">No ventilation</label>&nbsp;&nbsp;
<input type="radio" id="mechanical_ventilation" name="ventilation_type" value="mechanical_ventilation" data-enables="#DIVmechanical_ventilation">
<label for="mechanical_ventilation">Mechanical</label>&nbsp;&nbsp;
<input type="radio" id="natural_ventilation" name="ventilation_type" value="natural_ventilation" data-enables="#DIVnatural_ventilation">
<label for="no_ventilation">No ventilation</label>
<input class="ml-2" type="radio" id="mechanical_ventilation" name="ventilation_type" value="mechanical_ventilation" data-enables="#DIVmechanical_ventilation">
<label for="mechanical_ventilation">Mechanical</label>
</div>
<div>
<input type="radio" id="natural_ventilation" name="ventilation_type" value="natural_ventilation" data-enables="#DIVnatural_ventilation" data-toggle="modal" data-target="#warning_modal">
<label for="natural_ventilation">Natural</label><br>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="warning_modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Natural Ventilation</h4>
<button type="button" class="close align-self-center" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Single-sided ventilation is assumed in the model and is typically effective for room depths up to a depth 2.5 x the ceiling height.
If these conditions are not met, the air exchange might not be homogenous producing an artificially lower risk further away from the window.
<br>
<br>
<img src="/static/images/nat_vent_dimensions.png" id="nat_vent_image">
</div>
</div>
</div>
</div>
<div id="DIVmechanical_ventilation" class="tabbed" style="display:none">
<input type="radio" id="mech_type_air_supply" name="mechanical_ventilation_type" value="mech_type_air_supply" onclick="require_fields(this)" tabindex="-1">
<label for="mech_type_air_supply">Air supply flow rate</label> &nbsp;&nbsp;
<input type="number" step="any" id="air_supply" class="non_zero" name="air_supply" min="0" placeholder="(m³ / hour)" data-has-radio="#mech_type_air_supply"><br>
<input type="radio" id="mech_type_air_changes" name="mechanical_ventilation_type" value="mech_type_air_changes" onclick="require_fields(this)" tabindex="-1">
<label for="mech_type_air_changes">Air changes per hour</label> &nbsp;&nbsp;
<input type="number" step="any" id="air_changes" class="non_zero" name="air_changes" min="0" placeholder="(h⁻¹) only fresh air" data-has-radio="#mech_type_air_changes"><br>
<div class="split">
<div>
<input type="radio" id="mech_type_air_supply" name="mechanical_ventilation_type" value="mech_type_air_supply" class="center_radio" onclick="require_fields(this)" tabindex="-1">
<label for="mech_type_air_supply" class="col-form-label ml-2">Air supply flow rate</label>
</div>
<div>
<input type="number" step="any" id="air_supply" class="non_zero form-control" name="air_supply" min="0" placeholder="Flow rate (m³ / hour)" data-has-radio="#mech_type_air_supply"><br>
</div>
</div>
<div class="split">
<div>
<input type="radio" id="mech_type_air_changes" name="mechanical_ventilation_type" value="mech_type_air_changes" class="center_radio" onclick="require_fields(this)" tabindex="-1">
<label for="mech_type_air_changes" class="col-form-label ml-2">Air changes per hour</label>
</div>
<div>
<input type="number" step="any" id="air_changes" class="non_zero form-control" name="air_changes" min="0" placeholder="Air exchange (h⁻¹)" data-has-radio="#mech_type_air_changes"><br>
</div>
</div>
</div>
<div id="DIVnatural_ventilation" class="tabbed" style="display:none">
Number of windows: <input type="number" id="windows_number" class="non_zero" name="windows_number" min="1"><br>
Height of window: <input type="number" step="any" id="window_height" class="non_zero" name="window_height" placeholder="meters" min="0"><br>
Window type:
<input type="radio" id="window_sliding" name="window_type" value="window_sliding" onclick="require_fields(this)" checked="checked">
<label for="window_sliding">Sliding / Side-Hung</label>&nbsp;&nbsp;
<input type="radio" id="window_hinged" name="window_type" value="window_hinged" onclick="require_fields(this)">
<label for="window_hinged">Top- or Bottom-Hung</label>&nbsp;&nbsp;<br>
Width of window: <input type="number" step="any" id="window_width" class="non_zero disabled" name="window_width" placeholder="meters" min="0" data-has-radio="#window_hinged"><br>
Opening distance: <input type="number" step="any" id="opening_distance" class="non_zero" name="opening_distance" placeholder="meters" min="0"><br>
Windows open:</span><br>
<span class="tabbed"><input type="radio" id="windows_open_permanently" name="window_opening_regime" value="windows_open_permanently" onclick="require_fields(this)" checked="checked"></span>
<label for="windows_open_permanently">Permanently</label><br>
<span class="tabbed"><input type="radio" id="windows_open_periodically" name="window_opening_regime" value="windows_open_periodically" onclick="require_fields(this)"></span>
<label for="windows_open_periodically">Periodically:</label>&nbsp;&nbsp;
<input type="number" step="any" id="windows_duration" class="non_zero disabled" name="windows_duration" placeholder="Duration (min)" min="1" data-has-radio="#windows_open_periodically"> /
<input type="number" step="any" id="windows_frequency" class="non_zero disabled" name="windows_frequency" placeholder="Frequency (min)" min="1" data-has-radio="#windows_open_periodically">
<div class="split">
<div><label class="col-form-label">Number of windows:</label></div>
<div><input type="number" id="windows_number" class="non_zero form-control" name="windows_number" placeholder="Number (#)" min="1"><br></div>
</div>
<div class="split">
<div><label class="col-form-label">Height of window: </label></div>
<div><input type="number" step="any" id="window_height" class="non_zero form-control" name="window_height" placeholder="Height (m)" min="0"><br></div>
</div>
<div class='sub_title'>Window type:</div>
<input class="ml-2" type="radio" id="window_sliding" name="window_type" value="window_sliding" onclick="require_fields(this)" checked="checked">
<label for="window_sliding">Sliding / Side-Hung</label>
<input class="ml-2" type="radio" id="window_hinged" name="window_type" value="window_hinged" onclick="require_fields(this)">
<label for="window_hinged">Top- or Bottom-Hung</label><br>
<div class="split">
<div><label class="col-form-label">Width of window: </label></div>
<div><input type="number" step="any" id="window_width" class="non_zero disabled form-control" name="window_width" placeholder="Width (m)" min="0" data-has-radio="#window_hinged"><br></div>
</div>
<div class="split">
<div><label class="col-form-label">Opening distance: </label></div>
<div><input type="number" step="any" id="opening_distance" class="non_zero form-control" name="opening_distance" placeholder="Opening distance (m)" min="0"><br></div>
</div>
<div class='sub_title'>Window open:</div>
<div class="form-group row">
<span class="tabbed center_radio"><input type="radio" id="windows_open_permanently" name="window_opening_regime" value="windows_open_permanently" onclick="require_fields(this)" checked="checked"></span>
<label for="windows_open_permanently" class="col-form-label ml-2">Permanently</label><br>
</div>
<div class="form-group row">
<span class="tabbed center_radio"><input type="radio" id="windows_open_periodically" name="window_opening_regime" value="windows_open_periodically" onclick="require_fields(this)"></span>
<label for="windows_open_periodically" class="col-form-label ml-2 mr-2">Periodically:</label><br>
<input type="number" step="any" id="windows_duration" class="non_zero disabled form-control col-sm-4" name="windows_duration" placeholder="Duration (min)" min="1" data-has-radio="#windows_open_periodically">
<input type="number" step="any" id="windows_frequency" class="non_zero disabled form-control col-sm-4" name="windows_frequency" placeholder="Frequency (min)" min="1" data-has-radio="#windows_open_periodically">
</div>
<br>
</div>
HEPA filtration:
<div class='sub_title'>HEPA filtration:</div>
<div class="split">
<div>
<input type="radio" id="hepa_no" name="hepa_option" value=0 onclick="require_fields(this)" checked="checked">
<label for="hepa_no">No</label>&nbsp;&nbsp;
<input type="radio" id="hepa_yes" name="hepa_option" value=1 onclick="require_fields(this)">
<label for="hepa_yes">Yes</label>&nbsp;&nbsp;
<input type="number" step="any" id="hepa_amount" class="non_zero disabled" name="hepa_amount" placeholder="(m³ / hour)" min="0" data-has-radio="#hepa_yes">
<label for="hepa_no" class="col-form-label ml-2">No</label>
<input class="ml-2" type="radio" id="hepa_yes" name="hepa_option" value=1 onclick="require_fields(this)">
<label for="hepa_yes" class="col-form-label ml-2">Yes</label>
</div>
<div>
<input type="number" step="any" id="hepa_amount" class="non_zero disabled form-control" name="hepa_amount" placeholder="Flow rate (m³ / hour)" min="0" data-has-radio="#hepa_yes">
</div>
</div>
<hr width="80%">
<b>Face masks:</b>
<div data-tooltip="Masks worn at workstations or removed when a 2m physical distance is respected and proper venting is ensured.">
<span class="tooltip_text">?</span>
</div><br>
Are masks worn when occupants are at workstations?
<input type="radio" id="mask_on" name="mask_wearing_option" value="mask_on" required>
<label for="mask_on">Yes</label>&nbsp;&nbsp;
<input type="radio" id="mask_off" name="mask_wearing_option" value="mask_off" required checked="checked">
</div>
<br>
<div class='sub_title'>Are masks worn when occupants are at workstations?</div>
<input type="radio" id="mask_on" name="mask_wearing_option" value="mask_on" data-enables="#DIVmasks_used">
<label for="mask_on">Yes</label>
<input class="ml-2" type="radio" id="mask_off" name="mask_wearing_option" value="mask_off" checked="checked">
<label for="mask_off">No</label><br>
Type of masks used:
<input type="radio" id="mask_type_1" name="mask_type" value="Type I" checked="checked" onclick="require_fields(this)">
<label for="mask_type_1">Type 1</label>&nbsp;&nbsp;
<input type="radio" id="mask_type_ffp2" name="mask_type" value="FFP2" onclick="require_fields(this)">
<label for="mask_type_ffp2">FFP2</label><br>
<div id="DIVmasks_used" style="display:none">
<div class='sub_title'>Type of masks used:</div>
<div class='split'>
<div>
<input type="radio" id="mask_type_1" name="mask_type" value="Type I" checked="checked" onclick="require_fields(this)">
<label for="mask_type_1">
Surgical/Type I
<img class="mask_icons" src="/static/images/masks/t1.png">
</label>
</div>
<div>
<input type="radio" id="mask_type_ffp2" name="mask_type" value="FFP2" onclick="require_fields(this)">
<label for="mask_type_ffp2">
Respirator/FFP2
<img class="mask_icons" src="/static/images/masks/ffp2.png">
</label>
</div>
</div>
</div>
<hr width="80%">
</div>
<div class="col-lg-4 col-md-6">
</div>
<div>
<!-- Event Options -->
<b>Event data:</b>
@ -200,42 +294,76 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<span class="tooltip_text">?</span>
</div><br>
<div class="row">
<label class="col-xl-3 col-lg-4 col-sm-3 col-form-label">Total number of occupants:</label>
<input type="number" id="total_people" class="col-lg-4 col-md-5 col-sm-3" name="total_people" min=1 required>
<div class="form-group row">
<div class="col-sm-4"><label class="col-form-label">Total number of occupants:</label></div>
<div class="col-sm-6 align-self-center"><input type="number" id="total_people" class="form-control" name="total_people" placeholder="Number (#)" min=1 required></div>
</div>
<div class="row">
<label class="col-xl-3 col-lg-4 col-sm-3 col-form-label">Number of infected people: </label>
<input type="number" id="infected_people" class="col-lg-4 col-md-5 col-sm-3" name="infected_people" min=1 value=1 required><br>
<div class="form-group row">
<div class="col-sm-4"><label class="col-form-label">Number of infected people: </label></div>
<div class="col-sm-6 align-self-center"><input type="number" id="infected_people" class="form-control" name="infected_people" min=1 value=1 required></div>
</div>
<span id="training_limit_error" class="red_text" hidden>Training activities limited to 1 infected<br></span>
<span id="training_limit_error" class="red_text" hidden>Conference/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="controlroom-day">Control Room - Day shift</option>
<option value="controlroom-night">Control Room - Night shift</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="08:30" required> &nbsp;&nbsp;
Finish: <input type="time" id="exposed_finish" class="finish_time" data-time-group="exposed" data-lunch-break="exposed_lunch" name="exposed_finish" value="17:30" required><br>
Infected person(s) presence:<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="08:30" required> &nbsp;&nbsp;
Finish: <input type="time" id="infected_finish" class="finish_time" data-time-group="infected" data-lunch-break="infected_lunch" name="infected_finish" value="17:30" required><br>
<div class="form-group row">
<div class="col-sm-4"><label class="col-form-label">Activity type:</label></div>
<div class="col-sm-6">
<select id="activity_type" name="activity_type" class="form-control">
<option value="office">Office</option>
<option value="meeting">Meeting</option>
<option value="callcentre">Call Centre</option>
<option value="controlroom-day">Control Room - Day shift</option>
<option value="controlroom-night">Control Room - Night shift</option>
<option value="library">Library</option>
<option value="lab">Laboratory</option>
<option value="workshop">Workshop</option>
<option value="training">Conference/Training</option>
<option value="gym">Gym</option>
</select>
</div>
</div>
<div style=" margin-right:2rem;">
<div class="boxMargin pb-0">
<div class='sub_title'>Exposed person(s) presence:</div>
<div class="split">
<div>
<label class="tabbed mb-0">Start:</label>
<input type="time" id="exposed_start" class="start_time" data-time-group="exposed" data-lunch-break="exposed_lunch" name="exposed_start" value="08:30" required>
</div>
<div>
<label class="tabbed mb-0">Finish:</label>
<input type="time" id="exposed_finish" class="finish_time" data-time-group="exposed" data-lunch-break="exposed_lunch" name="exposed_finish" value="17:30" required>
</div>
</div>
</div>
<br>
<div class="boxMargin pb-0">
<div class='sub_title'>Infected person(s) presence:</div>
<div class="split">
<div>
<label class="tabbed mb-0">Start: </label>
<input type="time" id="infected_start" class="start_time" data-time-group="infected" data-lunch-break="infected_lunch" name="infected_start" value="08:30" required>
</div>
<div>
<label class="tabbed mb-0">Finish: </label>
<input type="time" id="infected_finish" class="finish_time" data-time-group="infected" data-lunch-break="infected_lunch" name="infected_finish" value="17:30" required>
</div>
</div>
</div>
<br>
</div>
<hr width="80%">
Which month is the event?
<select id="event_month" name="event_month" value="January" required>
<div class="form-group row">
<div class="col-sm-4"><label class="col-form-label">Which month is the event?</label></div>
<div class="col-sm-6 align-self-center">
<select id="event_month" name="event_month" class="form-control" value="January" required>
<option value="January">January</option>
<option value="February">February</option>
<option value="March">March</option>
@ -248,7 +376,9 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<option value="October">October</option>
<option value="November">November</option>
<option value="December">December</option>
</select><br>
</select>
</div>
</div>
<hr width="80%">
<span id="activity_breaks">
@ -259,28 +389,44 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
</span><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:&nbsp;&nbsp;
<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>&nbsp;&nbsp;
<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>
<div class="form-check">
<input type="checkbox" id="infected_dont_have_breaks_with_exposed" class="tabbed form-check-input" name="infected_dont_have_breaks_with_exposed" value='1' onclick="toggle_split_breaks()">
<label for="infected_dont_have_breaks_with_exposed" class="form-check-label col-sm-12">Input separate breaks for infected and exposed person(s)</label>
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> &nbsp;&nbsp;
</div><br>
<div class="breakBoxExposed" id="DIVexposed_breaks">
<span id="exposed_break_title" style="display:none;"><b>Exposed person(s) breaks:</b></span>
<div class="boxMargin">
Lunch break:
<input class="ml-2" 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 class="ml-2" 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>
<div class="split">
<div>
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>
</div>
<div>
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>
</div>
</div>
<!-- Coffee Options -->
Coffee Breaks:&nbsp;&nbsp;
<div class="split">
<div>
Coffee Breaks:
</div>
<div>
<input type="radio" id="exposed_coffee_break_0" name="exposed_coffee_break_option" value="coffee_break_0" checked="checked">
<label for="exposed_coffee_break_0" >No breaks</label>&nbsp;&nbsp;
<input type="radio" id="exposed_coffee_break_2" name="exposed_coffee_break_option" value="coffee_break_2">
<label for="exposed_coffee_break_2">2</label>&nbsp;&nbsp;
<input type="radio" id="exposed_coffee_break_4" name="exposed_coffee_break_option" value="coffee_break_4">
<label for="exposed_coffee_break_0" >No breaks</label>
<input class="ml-2" type="radio" id="exposed_coffee_break_2" name="exposed_coffee_break_option" value="coffee_break_2">
<label for="exposed_coffee_break_2">2</label>
<input class="ml-2" type="radio" id="exposed_coffee_break_4" name="exposed_coffee_break_option" value="coffee_break_4">
<label for="exposed_coffee_break_4">4</label><br>
</div>
</div>
<br>
Duration (minutes):
<select id="exposed_coffee_duration" name="exposed_coffee_duration">
@ -295,26 +441,40 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<br>
</div>
<div id="DIVinfected_breaks" style="display:none; float:left; margin-left:10pt;">
<div class="breakBoxInfected" id="DIVinfected_breaks">
<b>Infected person(s) breaks:</b>
<div style="padding:10px; border: 2px solid rgb(47, 52, 66);">
Lunch break:&nbsp;&nbsp;
<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>&nbsp;&nbsp;
<input type="radio" id="infected_lunch_option_yes" data-lunch-select="infected" name="infected_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
<div class="boxMargin">
Lunch break:
<input class="ml-2" 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 class="ml-2" 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"> &nbsp;&nbsp;
<div class="split">
<div>
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">
</div>
<div>
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>
</div>
</div>
<!-- Coffee Options -->
Coffee Breaks:&nbsp;&nbsp;
<div class="split">
<div>
Coffee Breaks:
</div>
<div>
<input type="radio" id="infected_coffee_break_0" name="infected_coffee_break_option" value="coffee_break_0" checked="checked">
<label for="infected_coffee_break_0" >No breaks</label>&nbsp;&nbsp;
<input type="radio" id="infected_coffee_break_2" name="infected_coffee_break_option" value="coffee_break_2">
<label for="infected_coffee_break_2">2</label>&nbsp;&nbsp;
<input type="radio" id="infected_coffee_break_4" name="infected_coffee_break_option" value="coffee_break_4">
<label for="infected_coffee_break_0" >No breaks</label>
<input style="ml-2" type="radio" id="infected_coffee_break_2" name="infected_coffee_break_option" value="coffee_break_2">
<label for="infected_coffee_break_2">2</label>
<input style="ml-2" type="radio" id="infected_coffee_break_4" name="infected_coffee_break_option" value="coffee_break_4">
<label for="infected_coffee_break_4">4</label><br>
</div>
</div>
<br>
Duration (minutes):
<select id="infected_coffee_duration" name="infected_coffee_duration">
@ -331,17 +491,23 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<br style="clear:both;">
<i>Coffee breaks are spread evenly throughout the day.</i><br>
<hr width="80%">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<button type='submit' class="btn btn-primary" id="generate_report">Generate report</button>
</div>
</div>
<br><br>
</div>
</div>
</section>
<div class="center">
<button type='submit' class="btn btn-primary bigButton" id="generate_report">
Generate report
</button>
</div>
<div class="col-lg-4 col-sm-12">
<br><br>
<div class="container container--padding">
<b>Quick Guide:</b><br>
This tool simulates the long range airborne spread SARS-CoV-2 virus in a finite volume and estimates the risk of COVID-19 infection. It is based on current scientific data and can be used to compare the effectiveness of different mitigation measures.<br>
<b>Virus data:</b> <br>
@ -369,17 +535,17 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<b>Activity types:</b><br>
The type of activity applies to both the infected and exposed persons:
<ul>
<li>Office = all seated, speaking 33% of the time,</li>
<li>Meeting = all seated, speaking time shared between all persons,</li>
<li>Call Centre = all seated, continuous speaking,</li>
<li>Control Room (day shift) = all seated, speaking 50% of the time,</li>
<li>Control Room (night shift) = all seated, speaking 10% of the time,</li>
<li>Library = all seated, no speaking, just breathing,</li>
<li>Laboratory = light physical activity, speaking 50% of the time,</li>
<li>Workshop = moderate physical activity, speaking 50% of the time,</li>
<li>Training = trainer standing and speaking, rest seated and speaking quietly.
Trainer assumed infected (worst case scenario),</li>
<li>Gym = heavy exercise, no speaking, just breathing.</li>
<li>Office = all seated, talking 33% of the time,</li>
<li>Meeting = all seated, talking time shared between all persons,</li>
<li>Call Centre = all seated, continuous talking,</li>
<li>Control Room (day shift) = all seated, talking 50% of the time,</li>
<li>Control Room (night shift) = all seated, talking 10% of the time,</li>
<li>Library = all seated, no talking, just breathing,</li>
<li>Laboratory = light physical activity, talking 50% of the time,</li>
<li>Workshop = moderate physical activity, talking 50% of the time,</li>
<li>Conference/Training = speaker/trainer standing and talking, rest seated and talking quietly.
Speaker/Trainer assumed infected (worst case scenario),</li>
<li>Gym = heavy exercise, no talking, just breathing.</li>
</ul>
<b>Activity breaks:</b><br>
<ul>
@ -390,14 +556,18 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
for more detailed explanations on how to use this tool. <br>
</div>
<div class="center container--padding pr-3 pl-3">
<button class="btn btn-primary bigButton">
<a href="{{ calculator_prefix }}/user-guide" class="{{ "nav-link active" if "user-guide" in active_page else "nav-link" }}" style="color:white">User guide</a>
</button>
<button class="btn btn-primary bigButton ml-2" type="button" data-toggle="collapse" data-target="#collapseDisclaimer" aria-expanded="false" aria-controls="collapseDisclaimer">
Disclaimer
</button>
</div>
</div>
<br><br><br><br>
</form>
<div>
<h3>Disclaimer:</h3>
<p>
<div class="collapse container container--padding" id="collapseDisclaimer">
<div class="card card-body">
<p>
CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
</p>
<p>
@ -406,7 +576,7 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
The report generated indicates how to avoid exceeding critical concentrations and chains of airborne transmission in spaces such as individual offices, meeting rooms and labs.
</p>
<p>
The risk assessment tool simulates the long-range airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 infection therein.
The risk assessment tool simulates the long-range airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 airborne transmission therein.
The results DO NOT include short-range airborne exposure (where the physical distance is a significant factor) nor the other known modes of SARS-CoV-2 transmission.
Hence, the output from this model is only valid when the other recommended public health & safety instructions are observed, such as adequate physical distancing, good hand hygiene and other barrier measures.
</p>
@ -429,10 +599,9 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
<p>
CARA has not undergone review, approval or certification by competent authorities, and as a result, it cannot be considered
as a fully endorsed and reliable tool, namely in the assessment of potential viral emissions from infected hosts to be modelled.
</p>
</p> </div>
</div>
<div class="text-component text-component-page clearfix"></div>
<br>
</div>
</form>
{% endblock main %}

View file

@ -1,17 +1,24 @@
{% extends "page.html.j2" %}
{% extends "layout.html.j2" %}
{% block main %}
<div class="container container--padding">
<br><h1>Instructions for use</h1></br>
<p>This is a guide to help you use the calculator app.
If you are using the expert version of the tool, you should look at the expert notes.</p>
<p>For more information on the Airborne Transmission of SARS-CoV-2, feel free to check out the HSE Seminar: <a href="https://cds.cern.ch/record/2743403">https://cds.cern.ch/record/2743403</a></p>
<p>The methodology, mathematical equations and parameters of the model are described here in the CERN Report: <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a></p>
</div>
{% block contents %}
<div class="center">
<button class="btn btn-primary bigButton" type="button" data-toggle="collapse" data-target="#collapseDisclaimer" aria-expanded="false" aria-controls="collapseDisclaimer">
Disclaimer
</button>
</div>
<h1>Instructions for use</h1>
<p>This is a guide to help you use the calculator app.
If you are using the expert version of the tool, you should look at the expert notes.</p>
<p>For more information on the Airborne Transmission of SARS-CoV-2, feel free to check out the HSE Seminar: <a href="https://cds.cern.ch/record/2743403">https://cds.cern.ch/record/2743403</a></p>
<p>The methodology, mathematical equations and parameters of the model are described here in the CERN Report: <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a></p>
<h2>Disclaimer</h2>
<p>
<div class="collapse container container--padding" id="collapseDisclaimer">
<div class="card card-body">
<p>
CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
</p>
<p>
@ -20,7 +27,7 @@ If you are using the expert version of the tool, you should look at the expert
The report generated indicates how to avoid exceeding critical concentrations and chains of airborne transmission in spaces such as individual offices, meeting rooms and labs.
</p>
<p>
The risk assessment tool simulates the long-range airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 infection therein.
The risk assessment tool simulates the long-range airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 airborne transmission therein.
The results DO NOT include short-range airborne exposure (where the physical distance is a significant factor) nor the other known modes of SARS-CoV-2 transmission.
Hence, the output from this model is only valid when the other recommended public health & safety instructions are observed, such as adequate physical distancing, good hand hygiene and other barrier measures.
</p>
@ -43,14 +50,19 @@ If you are using the expert version of the tool, you should look at the expert
<p>
CARA has not undergone review, approval or certification by competent authorities, and as a result, it cannot be considered
as a fully endorsed and reliable tool, namely in the assessment of potential viral emissions from infected hosts to be modelled.
</p>
</p>
</div>
</div>
<h2>How to use this tool</h2>
<div class="container container--padding">
<h1>How to use this tool</h1><br>
<h3>Simulation Name &amp; Room number</h3>
<br>
<p>In order to be able to trace back the simulations in your workplace risk assessments, performed with the tool, you can give each one a unique name - for example "Office use on Tuesday mornings".
The simulation name has no bearing on the calculation.</p>
<p>A room number is included, if you do not wish to use a formal room number any reference will do - for example "57/2-004"</p>
<h3>Virus Data</h3>
<br><h3>Virus Data</h3><br>
<p>Please choose the correct virus strain or any reported Variant of Concern (VOC) from the list.
Changing this setting alters the properties of the virus which are used for the simulation.
This has a significant effect on the probability of infection.
@ -70,25 +82,35 @@ The choices are:</p>
The local population in Manaus had very high levels of Covid-19 antibodies (&gt;67%) in recent months.
This factor has been taken into account by the authors of the study, via statistical adjustments to the transmission value (i.e. it has been increased, to account for spread in a population with significant acquired Covid-19 immunity).
However, this value may be revised in the future as more studies of the Gamma VOC transmission in different geographical locations become available.</p>
<br>
<h3>Room Data</h3>
<br>
<p>Please enter either the room volume (in m³) or both the floor area (m²) and the room height (m).
This information is available via GIS Portal (<a href="https://gis.cern.ch/gisportal/">https://gis.cern.ch/gisportal/</a>).</p>
<br>
<h4>Room heating system</h4>
<br>
<p>The use of central heating (e.g. radiators) reduces relative humidity of the indoor air, which can decrease the decay rate of viral infectivity. If your space is heated with such water radiators, select 'Yes'. If your space does not have such heating, or they are not in use in the period of the simulation (e.g. summer), select 'No'.</p>
<br>
<h3>Ventilation type</h3>
<br>
<p>There are three main options:</p>
<br>
<h4>Mechanical ventilation</h4>
<br>
<p>If the room has mechanical ventilation, suppling fresh air from outside (either a local or centralised system), you should select this option.
In order to make an accurate calculation you will need to know either the flow rate of fresh air supplied in the room or th total number of air changes per hour with fresh air.</p>
<p>Please bear in mind that any of the two inputs only consider the supply of fresh air. If a portion of air is recirculated, it shall not be accounted for in the inputs.</p>
<br>
<h4>Natural ventilation</h4>
<br>
<p>Natural ventilation refers to rooms which have openable windows.
There are many possibilities to calculate natural ventilation air flows, for simplification this tool assumes a single-sided natural ventilation scheme which is a conservative approach for the purpose of this tool.</p>
<p>Please choose the type of window (see illustration below):</p>
<ul>
<li>Sliding or side-hung</li>
<li>Top- or bottom-hung
<img src="static/images/window_type.PNG" alt="Window type" title="How to determine the window type"> </li>
<img src="static/images/window_type.PNG" alt="Window type" title="How to determine the window type" width="100%"></li>
</ul>
<p>Please enter the number, height and width and opening distance of the windows (in m).
If there are multiple windows of different sizes, you should take an average.</p>
@ -96,7 +118,7 @@ If there are multiple windows of different sizes, you should take an average.</p
<ul>
<li>In the case of Sliding or Side-Hung option, the length the window is moved open.
<em>Window opening distance example (image of open window and measuring tape):</em>
<img src="static/images/window_opening.png" alt="Window Opening Distance" title="How to measure window opening distance"></li>
<img src="static/images/window_opening.png" alt="Window Opening Distance" title="How to measure window opening distance" width="70%" style="margin:auto; display:block;"></li>
<li>In case of Top- or Bottom-Hung, the distance between the fixed frame and the movable glazed part when open.</li>
</ul>
<p><strong>Notes</strong>: If you are unsure about the opening distance for the window, it is recommended to choose a conservative value (5 cms, 0.05m or 10cms, 0.10m).
@ -104,48 +126,63 @@ If you open the window at different distances throughout the day, choose an aver
<p>When using natural ventilation, the circulation of air is simulated as a function of the difference between the temperature inside the room and the outside air temperature. The average outdoor temperature for each hour of the day has been computed for every month of the year based on historical data for Geneva, Switzerland.
It is therefore very important to enter the correct time and date in the event data section.
Finally, you must specify if the windows are open permanently (at all the times), or periodically (in intervals for a certain duration and frequency - both in minutes) - e.g. open the window for 10 minutes (duration) every 60 minutes (frequency).</p>
<br>
<h4>No ventilation</h4>
<br>
<p>This option assumes there is neither Mechanical nor Natural ventilation in the simulation.</p>
<br>
<h4>HEPA filtration</h4>
<br>
<p>A HEPA filter is a high efficiency particulate matter filter, which removes small airborne particles from the air.
They can be very useful for removing particles with viruses from the air in an enclosed space.
The calculator allows you to simulate the installation of a HEPA air filter within the room.
The recommended airflow rate for the HEPA filter should correspond to a total air exchange rate of 3 - 6 ACH (the higher the better, even beyond 6).</p>
<br>
<h3>Event Data</h3>
<br>
<p>Here we capture the information about the event being simulated.
First enter the number of occupants in the space, if you have a (small) variation in the number of people, please input the average or consider using the expert tool.
Within the number of people occupying the space, you should specify how many are infected.</p>
<p>As an example, for a shared office with 4 people, where one person is infected, we enter 4 occupants and 1 infected person.</p>
<br>
<h4>Activity type</h4>
<br>
<p>There are a few predefined activities in the tool at present.</p>
<p><strong>Office </strong> = All persons seated, speaking occasionally (1/3rd of the time, with normal breathing the other 2/3rds of the time). Everyone (exposed and infected occupants) is treated the same in this model.
<strong>Meeting</strong> = All persons seated, having a conversation (approximately each occupant is 1/N % of the time speaking, where N is the number of occupants). Everyone (exposed and infected occupants) is treated the same in this model.</p>
<p><strong>Library</strong> = All persons seated, breathing only (not speaking), all the time.</p>
<p><strong>Call Centre</strong> = All persons seated, all speaking simultaneously, all the time. This is a conservative profile, i.e. will show an increased <code>P(i)</code> compared to office/meeting activity. Everyone (exposed and infected occupants) is treated the same in this model.</p>
<p><strong>Control Room (day shift)</strong> = All persons seated, all speaking 50% of the time. This is a conservative profile, i.e. will show an increased <code>P(i)</code> compared to office/meeting activity. Everyone (exposed and infected occupants) is treated the same in this model.</p>
<p><strong>Control Room (night shift)</strong> = All persons seated, all speaking 10% of the time. Everyone (exposed and infected occupants) is treated the same in this model.</p>
<p><strong>Lab</strong> = Based on a typical lab or technical working area, all persons are doing light activity and speaking 50% of the time. Everyone (exposed and infected occupants) is treated the same in this model.</p>
<p><strong>Workshop</strong> = Based on a mechanical assembly workshop or equipment installation scenario, all persons are doing moderate activity and speaking 50% of the time. This activity is equally applicable to bicycling, or walking on a gradient, in the LHC tunnels. Everyone (exposed and infected occupants) is treated the same in this model.</p>
<p><strong>Training</strong> = Based on a typical training course scenario.
One individual (the trainer) is standing and speaking, with all other individuals seated and speaking quietly (whispering).
In this case it is assumed that the infected person is the trainer, because this is the worst case in terms of viral shedding.</p>
<p><strong>Gym</strong> = All persons are doing heavy exercise and breathing (not speaking). Everyone (exposed and infected occupants) is treated the same in this model.</p>
<h3>Timings</h3>
<ul>
<li><strong>Office </strong> = All persons seated, talking occasionally (1/3rd of the time, with normal breathing the other 2/3rds of the time). Everyone (exposed and infected occupants) is treated the same in this model.</li>
<li><strong>Meeting</strong> = All persons seated, having a conversation (approximately each occupant is 1/N % of the time talking, where N is the number of occupants). Everyone (exposed and infected occupants) is treated the same in this model.</li>
<li><strong>Library</strong> = All persons seated, breathing only (not talking), all the time.</li>
<li><strong>Call Centre</strong> = All persons seated, all talking simultaneously, all the time. This is a conservative profile, i.e. will show an increased <code>P(i)</code> compared to office/meeting activity. Everyone (exposed and infected occupants) is treated the same in this model.</li>
<li><strong>Control Room (day shift)</strong> = All persons seated, all talking 50% of the time. This is a conservative profile, i.e. will show an increased <code>P(i)</code> compared to office/meeting activity. Everyone (exposed and infected occupants) is treated the same in this model.</li>
<li><strong>Control Room (night shift)</strong> = All persons seated, all talking 10% of the time. Everyone (exposed and infected occupants) is treated the same in this model.</li>
<li><strong>Lab</strong> = Based on a typical lab or technical working area, all persons are doing light activity and talking 50% of the time. Everyone (exposed and infected occupants) is treated the same in this model.</li>
<li><strong>Workshop</strong> = Based on a mechanical assembly workshop or equipment installation scenario, all persons are doing moderate activity and talking 50% of the time. This activity is equally applicable to bicycling, or walking on a gradient, in the LHC tunnels. Everyone (exposed and infected occupants) is treated the same in this model.</li>
<li><strong>Conference/Training</strong> = Based on a typical conference/training course scenario.
One individual (the speaker/trainer) is standing and talking, with all other individuals seated and talking quietly (whispering).
In this case it is assumed that the infected person is the speaker/trainer, because this is the worst case in terms of viral shedding.</li>
<li><strong>Gym</strong> = All persons are doing heavy exercise and breathing (not talking). Everyone (exposed and infected occupants) is treated the same in this model.</li>
</ul>
<br><h3>Timings</h3>
<p>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 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.</p>
<h4>When is the event?</h4>
<br><h4>When is the event?</h4><br>
<p>This is included for completeness in all simulations, however it is of particular relevance to those using natural ventilation because of variations in outside air temperature.</p>
<p>Only the month is used by the model to retrieve the average outdoor air temperatures for the Geneva region.</p>
<br>
<h3>Breaks</h3>
<br>
<h4>Lunch Break</h4>
<br>
<p>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 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.</p>
<p>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.</p>
<br>
<h4>Coffee Breaks</h4>
<br>
<p>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.
If coffee breaks are taken in-situ, this option should be set to 'No breaks'.</p>
@ -155,7 +192,9 @@ The variation of coffee breaks can be altered in 5 minute increments up to 30 mi
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.</p>
<p>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.</p>
<br>
<h4>Split breaks</h4>
<br>
<p>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.</p>
<p>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:</p>
@ -165,19 +204,25 @@ If not, then you can input separate breaks. This is particularly different when
<li><p>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.</p>
</li>
</ol>
<br>
<h3>Face Masks</h3>
<br>
<p>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 &amp; safety instructions.
Please check what are the applicable rules, before deciding which assumptions are used for the simulation.</p>
<p>If you have selected the Training activity type, this equates to the trainer and all participants either wearing masks throughout the training (Yes), or removing them when seated/standing at their socially distanced positions within the training room (No).
<p>If you have selected the Conference/Training activity type, this equates to the speakr/trainer and all participants either wearing masks throughout the conference/training (Yes), or removing them when seated/standing at their socially distanced positions within the conference/training room (No).
Please confirm what are the applicable rules, before deciding which assumptions are used for the simulation</p>
<p>For the time being only the Type 1 surgical and FFP2 masks can be selected.</p>
<br>
<h2>Generate Report</h2>
<br>
<p>When you have entered all the necessary information, please click on the Generate Report button to execute the model. With the implementation of Monte Carlo simulations, the browser might take a few secounds to react.</p>
<h1>Report</h1>
<br><h1>Report</h1><br>
<p>The report will open in your web browser.
It contains a summary of all the input data, which will allow the simulation to be repeated if required in the future as we improve the model.</p>
<br>
<h2>Results</h2>
<br>
<p>This part of the report shows the <code>P(I)</code> or probability of one exposed person getting infected.
It is estimated based on the emission rate of virus into the simulated volume, and the amount which is inhaled by exposed individuals.
This probability is valid for the simulation duration - i.e. the start and end time.
@ -195,16 +240,20 @@ It is determined by:</p>
</ul>
</li>
</ul>
<br>
<h3>QR code</h3>
<br>
<p>At the end of the report you can find a unique QR code / hyperlink for this report. This provides an automatic way to review the calculator form with the corresponding specified parameters.
This allows for:</p>
<ul>
<li>sharing reports by either scanning or clicking on the QR code to obtain a shareable link.</li>
<li>easily regenerating reports with any new versions of the CARA model released in the future.</li>
</ul>
<br>
<h1>Conclusion</h1>
<br>
<p>This tool provides informative comparisons for COVID-19 (long-range) airborne risk only - see Disclaimer
If you have any comments on your experience with the app, or feedback for potential improvements, please share them with the development team <a href="mailto:cara-dev@cern.ch">Send email</a>.</p>
</div>
{% endblock contents %}
{% endblock main %}

View file

@ -22,46 +22,46 @@
{% endblock warning_animation %}
{% block report_summary %}
<div class="flex-row w-75 align-self-center">
<div class="flex-row align-self-center">
{% if ((prob_inf > 15) or (expected_new_cases >= 1)) %}
<div class="alert alert-danger" role="alert">
<div class="alert alert-danger mb-0" role="alert">
<strong>Not Acceptable:</strong>
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
</div>
{% elif 5 <= prob_inf <= 15 %}
<div class="alert alert-warning" role="alert">
<div class="alert alert-warning mb-0" role="alert">
<strong>Attention:</strong>
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
</div>
{% elif prob_inf < 5 %}
<div class="alert alert-success" role="alert">
<div class="alert alert-success mb-0" role="alert">
<strong>Acceptable:</strong>
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
</div>
{% endif %}
{% if (prob_inf > 5) %}
<br>
{% if scale_warning.level == "green-1" %}
<div class="alert alert-dark" role="alert" style="height:fit-content">
<div class="alert alert-dark mb-0" role="alert" style="height:fit-content">
Note: the current CERN COVID Scale is <b>Green - 1</b>, which means the incidence rate in the local community is <b>{{scale_warning.incidence_rate}}</b>. Align your risk assessment with the guidance and instructions provided by the HSE Unit.
</div>
{% elif scale_warning.level == "yellow-2" %}
<div class="alert alert-dark" role="alert" style="height:fit-content">
<div class="alert alert-dark mb-0" role="alert" style="height:fit-content">
Note: the current CERN COVID Scale is <b>Yellow - 2</b>, which means the incidence rate in the local community is <b>{{scale_warning.incidence_rate}}</b>. There is a reduced chance that asymptomatic or pre-symptomatic infected individuals circulate within the CERN site which, during this stage, corresponds to an average daily on-site access {{scale_warning.onsite_access}}. See with your supervisor if this scenario is acceptable.
</div>
{% elif scale_warning.level == "orange-3" %}
<div class="alert alert-dark" role="alert" style="height:fit-content">
<div class="alert alert-dark mb-0" role="alert" style="height:fit-content">
Warning: the current CERN COVID Scale is <b>Orange - 3</b>, which means the incidence rate in the local community is <b>{{scale_warning.incidence_rate}}</b>. There is a slight chance that asymptomatic or pre-symptomatic infected individuals circulate within the CERN site which, during this stage, corresponds to an average daily on-site access {{scale_warning.onsite_access}}. See with your supervisor if any additional measures can be applied (ALARA).
</div>
{% elif scale_warning.level == "red-4" %}
<div class="alert alert-dark" role="alert" style="height:fit-content">
<div class="alert alert-dark mb-0" role="alert" style="height:fit-content">
Warning: the current CERN COVID Scale is <b>Red - 4</b>, which means the incidence rate in the local community is <b>{{scale_warning.incidence_rate}}</b>. There is a strong chance that asymptomatic or pre-symptomatic infected individuals circulate within the CERN site which, during this stage, corresponds to an average daily on-site access {{scale_warning.onsite_access}}. Please reduce the value below the threshold of <b>{{scale_warning.threshold}}</b>.
</div>
{% else %}
<p><b>Note:</b> The CERN COVID Level is not specified.</p>
{% endif %}
{% endif %}
</div>
{% endblock report_summary %}
@ -120,14 +120,16 @@
<p class="card-text">
Please ensure that this scenario conforms to current COVID-related <a href="https://hse.cern/covid-19-information"> Health & Safety requirements</a>, under the applicable COVID Scale and measures in force at the time of the CARA assessment.</strong> <br>
The results of this simulation are colour coded according to the risk values authorized at CERN (approved in December 2020):
</p>
</p><br>
<div class="d-flex">
<div class="d-flex flex-column justify-content-between">
<div class="alert alert-success ml-3" role="alert">Events with a <strong>P(i) less than 5%</strong> may go ahead without further mitigation measures.</div>
<div class="alert alert-warning ml-3" role="alert">Events with a <strong>P(i) between 5% and 15%</strong> shall be subject to ALARA principles (see footnote) to minimise the risk before proceeding.</div>
<div class="alert alert-danger ml-3 mb-0" role="alert">Events with a <strong>P(i) exceeding 15% or a number of expected new cases that exceeds 1</strong> may not take place until additional measures are in place and a risk reduction has been performed.</div>
<div class="split">
<div class="d-flex flex-column col-xl-8 p-0">
<div class="alert alert-success" role="alert">Events with a <strong>P(i) less than 5%</strong> may go ahead without further mitigation measures.</div>
<div class="alert alert-warning" role="alert">Events with a <strong>P(i) between 5% and 15%</strong> shall be subject to ALARA principles (see footnote) to minimise the risk before proceeding.</div>
<div class="alert alert-danger mb-0" role="alert">Events with a <strong>P(i) exceeding 15% or a number of expected new cases that exceeds 1</strong> may not take place until additional measures are in place and a risk reduction has been performed.</div>
</div>
<div class="col-xl-3 align-self-center text-center"><img id="cern_level" class="rounded" src="{{ calculator_prefix }}/static/images/warning_scale/{{scale_warning.level}}.png"></div>
</div>
<img class="rounded ml-4 align-self-center" src="{{ calculator_prefix }}/static/images/warning_scale/{{scale_warning.level}}.png">
</div>
<br>
<p class="data_text">
@ -145,7 +147,6 @@
</div>
</div>
</div>
<div class="break-avoid fourth_page"></div>
{% endblock report_preamble %}
{% block report_footer %}

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,220 +0,0 @@
/*
Colorbox Core Style:
The following CSS is consistent between example themes and should not be altered.
*/
#colorbox,
#cboxOverlay,
#cboxWrapper {
position: absolute;
top: 0;
left: 0;
z-index: 9999;
overflow: hidden;
-webkit-transform: translate3d(0, 0, 0);
}
#cboxWrapper {
max-width: none;
}
#cboxOverlay {
position: fixed;
width: 100%;
height: 100%;
}
#cboxMiddleLeft,
#cboxBottomLeft {
clear: left;
}
#cboxContent {
position: relative;
}
#cboxLoadedContent {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
#cboxTitle {
margin: 0;
}
#cboxLoadingOverlay,
#cboxLoadingGraphic {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#cboxPrevious,
#cboxNext,
#cboxClose,
#cboxSlideshow {
cursor: pointer;
}
.cboxPhoto {
float: left;
margin: auto;
border: 0;
display: block;
max-width: none;
-ms-interpolation-mode: bicubic;
}
.cboxIframe {
width: 100%;
height: 100%;
display: block;
border: 0;
padding: 0;
margin: 0;
}
#colorbox,
#cboxContent,
#cboxLoadedContent {
box-sizing: content-box;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
}
/*
User Style:
Change the following styles to modify the appearance of Colorbox. They are
ordered & tabbed in a way that represents the nesting of the generated HTML.
*/
#cboxOverlay {
background: #fff;
opacity: 0.9;
filter: alpha(opacity=90);
}
#colorbox {
outline: 0;
}
#cboxContent {
margin-top: 32px;
overflow: visible;
background: #000;
}
.cboxIframe {
background: #fff;
}
#cboxError {
padding: 50px;
border: 1px solid #ccc;
}
#cboxLoadedContent {
background: #000;
padding: 1px;
}
#cboxLoadingGraphic {
background: url(images/loading.gif) no-repeat center center;
}
#cboxLoadingOverlay {
background: #000;
}
#cboxTitle {
position: absolute;
top: -22px;
left: 0;
color: #000;
}
#cboxCurrent {
position: absolute;
top: -22px;
right: 205px;
text-indent: -9999px;
}
/* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */
#cboxPrevious,
#cboxNext,
#cboxSlideshow,
#cboxClose {
border: 0;
padding: 0;
margin: 0;
overflow: visible;
text-indent: -9999px;
width: 20px;
height: 20px;
position: absolute;
top: -20px;
background: url(images/controls.png) no-repeat 0 0;
}
/* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */
#cboxPrevious:active,
#cboxNext:active,
#cboxSlideshow:active,
#cboxClose:active {
outline: 0;
}
#cboxPrevious {
background-position: 0px 0px;
right: 44px;
}
#cboxPrevious:hover {
background-position: 0px -25px;
}
#cboxNext {
background-position: -25px 0px;
right: 22px;
}
#cboxNext:hover {
background-position: -25px -25px;
}
#cboxClose {
background-position: -50px 0px;
right: 0;
}
#cboxClose:hover {
background-position: -50px -25px;
}
.cboxSlideshow_on #cboxPrevious,
.cboxSlideshow_off #cboxPrevious {
right: 66px;
}
.cboxSlideshow_on #cboxSlideshow {
background-position: -75px -25px;
right: 44px;
}
.cboxSlideshow_on #cboxSlideshow:hover {
background-position: -100px -25px;
}
.cboxSlideshow_off #cboxSlideshow {
background-position: -100px 0px;
right: 44px;
}
.cboxSlideshow_off #cboxSlideshow:hover {
background-position: -75px -25px;
}

View file

@ -1,985 +0,0 @@
body {
color: #2f4858;
background: #2f3442; }
main {
background: #ffffff; }
header .site-info__text__name, header .site-info__text__slogan {
color: #fafafa; }
header .site-info__text__name a, header .site-info__text__slogan a {
color: #fafafa;
text-decoration: none; }
header {
background: #2f3442; }
header .nav > li > a, header .nav > li > span {
color: #fffffe; }
header .nav > li > a:after, header .nav > li > span:after {
background: #2d8af1; }
header .cern-search a {
color: #fffffe; }
header .cern-search a:after {
background: #2d8af1; }
header .cern-search #cern-search-overlay {
background: #2f3442; }
header .cern-search #cern-search-overlay .form-item:before {
color: #fffffe; }
header .cern-search #cern-search-overlay .form-item input {
border-color: #fffffe;
color: #fffffe; }
header .navbar-default .navbar-nav > li > a {
color: #fffffe; }
header .navbar-default .navbar-nav > li > a:hover, header .navbar-default .navbar-nav > li > a:focus {
color: #fffffe; }
header .navbar-default .navbar-nav > .open > a, header .navbar-default .navbar-nav > .open > a:hover, header .navbar-default .navbar-nav > .open > a:focus {
color: #fffffe; }
@media (max-width: 767px) {
header .navbar-default .navbar-header button .icon-bar {
background-color: #fffffe; }
header .navbar-default .navbar-nav .open .dropdown-menu > li > a {
color: #fffffe; }
header .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, header .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
color: #fffffe; }
header .navbar-default .navbar-nav .open .dropdown-menu > .active > a, header .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, header .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #fffffe;
background-color: #2f3442; }
header .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, header .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, header .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
color: #fffffe; } }
header .navbar-collapse.collapse.in,
header .navbar-collapse.collapsing {
background: #2f3442; }
header .dropdown-menu {
background: #2f3442;
border-color: #2f3442; }
header .dropdown-menu:before {
border-color: transparent transparent #2f3442 transparent; }
header .dropdown-menu > li > a, header .dropdown-menu > li > span {
background: #2f3442;
color: #fffffe; }
header .dropdown-menu > li > a:before, header .dropdown-menu > li > span:before {
color: #fffffe; }
header .dropdown-menu > li > a:after, header .dropdown-menu > li > span:after {
background: #2d8af1; }
header .dropdown-menu > li > a:hover:before, header .dropdown-menu > li > a.is-active:before, header .dropdown-menu > li > span:hover:before, header .dropdown-menu > li > span.is-active:before {
color: #2d8af1; }
header .dropdown-menu > li > a:hover, header .dropdown-menu > li > a:focus, header .dropdown-menu > li > span:hover, header .dropdown-menu > li > span:focus {
background: #2f3442;
color: #fffffe; }
header .dropdown-menu > li > font {
color: #fffffe; }
.sidebar-left nav ul:not(.pagination):not(.contextual-links), .sidebar-right nav ul:not(.pagination):not(.contextual-links) {
background-color: #2f3442; }
.sidebar-left nav ul:not(.pagination):not(.contextual-links) li a, .sidebar-right nav ul:not(.pagination):not(.contextual-links) li a {
color: #fffffe !important; }
.sidebar-left nav ul:not(.pagination):not(.contextual-links) li a:hover, .sidebar-right nav ul:not(.pagination):not(.contextual-links) li a:hover {
color: #fffffe; }
.sidebar-left nav ul:not(.pagination):not(.contextual-links) li a:hover::before, .sidebar-right nav ul:not(.pagination):not(.contextual-links) li a:hover::before {
color: #2d8af1; }
.sidebar-left nav ul:not(.pagination):not(.contextual-links) li a::after, .sidebar-right nav ul:not(.pagination):not(.contextual-links) li a::after {
color: #2d8af1; }
.sticky-header header {
background: #2f3442 !important; }
.has-header header.menu-expanded {
background: #2f3442 !important; }
.block-language .active-language a {
color: #fffffe; }
.block-language .active-language a:after {
background: #2d8af1; }
.block-language ul.links {
background: #2f3442; }
.block-language ul.links::before {
border-color: transparent transparent #2f3442 transparent; }
.block-language ul.links a {
color: #fffffe; }
.block-language ul.links a:after {
background: #2d8af1; }
.region-content > nav.tabs {
background: #2f3442; }
.region-content > nav.tabs a.is-active {
color: #2f3442; }
main .field--type-text-with-summary .nav-tabs li a,
main .text-component-text.basic_html .nav-tabs li a,
main .text-component-text.restricted_html .nav-tabs li a,
main .text-component-text.cern_full_htm .nav-tabs li a {
color: #105ea9;
background: #fffdfd; }
main .field--type-text-with-summary .nav-tabs li.active a, main .field--type-text-with-summary .nav-tabs li:hover a,
main .text-component-text.basic_html .nav-tabs li.active a,
main .text-component-text.basic_html .nav-tabs li:hover a,
main .text-component-text.restricted_html .nav-tabs li.active a,
main .text-component-text.restricted_html .nav-tabs li:hover a,
main .text-component-text.cern_full_htm .nav-tabs li.active a,
main .text-component-text.cern_full_htm .nav-tabs li:hover a {
background: #f2f6fa;
color: #1161af; }
main .field--type-text-with-summary .tab-content,
main .text-component-text.basic_html .tab-content,
main .text-component-text.restricted_html .tab-content,
main .text-component-text.cern_full_htm .tab-content {
background: #f2f6fa;
color: #1161af; }
body > footer {
background: #2f3442;
color: #fffeee; }
body > footer h2 {
color: #fffeee !important; }
body > footer h2:after {
background: #fffeee !important; }
body > footer a, footer a {
color: #fffefe; }
body > footer a:hover, body > footer a.is-active {
color: #fffefe; }
body > footer nav ul.menu.nav li a:hover:before, body > footer nav ul.menu.nav li a.is-active:before {
color: #2d8af1; }
body > footer nav ul.menu.nav li a:before {
color: #fffefe; }
body > footer nav ul.menu.nav li a:after {
background: #2d8af1; }
body > footer section[id*='followus']:after {
background: #fffeee; }
body > footer section a {
color: #fffefe !important; }
body > footer section a:hover {
color: #0d72ca !important; }
body > footer div[class*="footercolumn1"]:after {
background: #fffeee; }
body > footer .block-custom-wrapper {
color: #fffeee; }
body > footer .block-custom-wrapper .field--name-field-visible-title {
color: #fffeee; }
body > footer .block-custom-wrapper .field--name-field-visible-title:after {
background: #fffeee; }
main .field--type-text-with-summary a,
main .text-component-text.basic_html a,
main .text-component-text.restricted_html a,
main .text-component-text.cern_full_html a,
main .basic-node-full-content-body a,
main .event-node-full-content-body a,
main .faq-node-full-content-body a,
main .event-node-full-content-body a,
main .resources-node-full-content-file a,
main .system-node-full-content-body a,
main .event-node-full-content-body a,
main .news-node-full-content-body a,
main .component-event-item a {
color: #2574b9; }
main .field--type-text-with-summary a:hover,
main .text-component-text.basic_html a:hover,
main .text-component-text.restricted_html a:hover,
main .text-component-text.cern_full_html a:hover,
main .basic-node-full-content-body a:hover,
main .event-node-full-content-body a:hover,
main .faq-node-full-content-body a:hover,
main .event-node-full-content-body a:hover,
main .resources-node-full-content-file a:hover,
main .system-node-full-content-body a:hover,
main .event-node-full-content-body a:hover,
main .news-node-full-content-body a:hover,
main .component-event-item a:hover {
color: #044873; }
main .field--type-text-with-summary ul li::before,
main .text-component-text.basic_html ul li::before,
main .text-component-text.restricted_html ul li::before,
main .text-component-text.cern_full_html ul li::before,
main .basic-node-full-content-body ul li::before,
main .event-node-full-content-body ul li::before,
main .faq-node-full-content-body ul li::before,
main .event-node-full-content-body ul li::before,
main .resources-node-full-content-file ul li::before,
main .system-node-full-content-body ul li::before,
main .event-node-full-content-body ul li::before,
main .news-node-full-content-body ul li::before,
main .component-event-item ul li::before {
color: #292920; }
main .field--type-text-with-summary u,
main .text-component-text.basic_html u,
main .text-component-text.restricted_html u,
main .text-component-text.cern_full_html u,
main .basic-node-full-content-body u,
main .event-node-full-content-body u,
main .faq-node-full-content-body u,
main .event-node-full-content-body u,
main .resources-node-full-content-file u,
main .system-node-full-content-body u,
main .event-node-full-content-body u,
main .news-node-full-content-body u,
main .component-event-item u {
text-decoration-color: #292920; }
main .field--type-text-with-summary table,
main .text-component-text.basic_html table,
main .text-component-text.restricted_html table,
main .text-component-text.cern_full_html table,
main .basic-node-full-content-body table,
main .event-node-full-content-body table,
main .faq-node-full-content-body table,
main .event-node-full-content-body table,
main .resources-node-full-content-file table,
main .system-node-full-content-body table,
main .event-node-full-content-body table,
main .news-node-full-content-body table,
main .component-event-item table {
background: #fefefe; }
main .field--type-text-with-summary table thead th,
main .text-component-text.basic_html table thead th,
main .text-component-text.restricted_html table thead th,
main .text-component-text.cern_full_html table thead th,
main .basic-node-full-content-body table thead th,
main .event-node-full-content-body table thead th,
main .faq-node-full-content-body table thead th,
main .event-node-full-content-body table thead th,
main .resources-node-full-content-file table thead th,
main .system-node-full-content-body table thead th,
main .event-node-full-content-body table thead th,
main .news-node-full-content-body table thead th,
main .component-event-item table thead th {
background: #2f4858;
color: #efefef;
padding: 5px; }
main .field--type-text-with-summary table tbody tr:nth-child(odd),
main .text-component-text.basic_html table tbody tr:nth-child(odd),
main .text-component-text.restricted_html table tbody tr:nth-child(odd),
main .text-component-text.cern_full_html table tbody tr:nth-child(odd),
main .basic-node-full-content-body table tbody tr:nth-child(odd),
main .event-node-full-content-body table tbody tr:nth-child(odd),
main .faq-node-full-content-body table tbody tr:nth-child(odd),
main .event-node-full-content-body table tbody tr:nth-child(odd),
main .resources-node-full-content-file table tbody tr:nth-child(odd),
main .system-node-full-content-body table tbody tr:nth-child(odd),
main .event-node-full-content-body table tbody tr:nth-child(odd),
main .news-node-full-content-body table tbody tr:nth-child(odd),
main .component-event-item table tbody tr:nth-child(odd) {
background-color: #f9f9fa; }
main .field--type-text-with-summary table tbody tr:nth-child(even),
main .text-component-text.basic_html table tbody tr:nth-child(even),
main .text-component-text.restricted_html table tbody tr:nth-child(even),
main .text-component-text.cern_full_html table tbody tr:nth-child(even),
main .basic-node-full-content-body table tbody tr:nth-child(even),
main .event-node-full-content-body table tbody tr:nth-child(even),
main .faq-node-full-content-body table tbody tr:nth-child(even),
main .event-node-full-content-body table tbody tr:nth-child(even),
main .resources-node-full-content-file table tbody tr:nth-child(even),
main .system-node-full-content-body table tbody tr:nth-child(even),
main .event-node-full-content-body table tbody tr:nth-child(even),
main .news-node-full-content-body table tbody tr:nth-child(even),
main .component-event-item table tbody tr:nth-child(even) {
background-color: #e9ecef; }
main .field--type-text-with-summary table tbody td,
main .text-component-text.basic_html table tbody td,
main .text-component-text.restricted_html table tbody td,
main .text-component-text.cern_full_html table tbody td,
main .basic-node-full-content-body table tbody td,
main .event-node-full-content-body table tbody td,
main .faq-node-full-content-body table tbody td,
main .event-node-full-content-body table tbody td,
main .resources-node-full-content-file table tbody td,
main .system-node-full-content-body table tbody td,
main .event-node-full-content-body table tbody td,
main .news-node-full-content-body table tbody td,
main .component-event-item table tbody td {
color: #333333; }
main .field--type-text-with-summary table tfoot td,
main .text-component-text.basic_html table tfoot td,
main .text-component-text.restricted_html table tfoot td,
main .text-component-text.cern_full_html table tfoot td,
main .basic-node-full-content-body table tfoot td,
main .event-node-full-content-body table tfoot td,
main .faq-node-full-content-body table tfoot td,
main .event-node-full-content-body table tfoot td,
main .resources-node-full-content-file table tfoot td,
main .system-node-full-content-body table tfoot td,
main .event-node-full-content-body table tfoot td,
main .news-node-full-content-body table tfoot td,
main .component-event-item table tfoot td {
background-color: #333339;
color: #999999; }
main .field--type-text-with-summary .blockquote,
main .field--type-text-with-summary blockquote,
main .field--type-text-with-summary q,
main .text-component-text.basic_html .blockquote,
main .text-component-text.basic_html blockquote,
main .text-component-text.basic_html q,
main .text-component-text.restricted_html .blockquote,
main .text-component-text.restricted_html blockquote,
main .text-component-text.restricted_html q,
main .text-component-text.cern_full_html .blockquote,
main .text-component-text.cern_full_html blockquote,
main .text-component-text.cern_full_html q,
main .basic-node-full-content-body .blockquote,
main .basic-node-full-content-body blockquote,
main .basic-node-full-content-body q,
main .event-node-full-content-body .blockquote,
main .event-node-full-content-body blockquote,
main .event-node-full-content-body q,
main .faq-node-full-content-body .blockquote,
main .faq-node-full-content-body blockquote,
main .faq-node-full-content-body q,
main .event-node-full-content-body .blockquote,
main .event-node-full-content-body blockquote,
main .event-node-full-content-body q,
main .resources-node-full-content-file .blockquote,
main .resources-node-full-content-file blockquote,
main .resources-node-full-content-file q,
main .system-node-full-content-body .blockquote,
main .system-node-full-content-body blockquote,
main .system-node-full-content-body q,
main .event-node-full-content-body .blockquote,
main .event-node-full-content-body blockquote,
main .event-node-full-content-body q,
main .news-node-full-content-body .blockquote,
main .news-node-full-content-body blockquote,
main .news-node-full-content-body q,
main .component-event-item .blockquote,
main .component-event-item blockquote,
main .component-event-item q {
color: #bbbbbb; }
main .field--type-text-with-summary hr,
main .text-component-text.basic_html hr,
main .text-component-text.restricted_html hr,
main .text-component-text.cern_full_html hr,
main .basic-node-full-content-body hr,
main .event-node-full-content-body hr,
main .faq-node-full-content-body hr,
main .event-node-full-content-body hr,
main .resources-node-full-content-file hr,
main .system-node-full-content-body hr,
main .event-node-full-content-body hr,
main .news-node-full-content-body hr,
main .component-event-item hr {
border-top-color: #cacaca !important; }
.field--type-link a {
color: #2574b9; }
.field--type-link a:hover {
color: #044873; }
.owl-theme .owl-dots .owl-dot span {
background: #dddddd; }
.owl-theme .owl-dots .owl-dot.active span,
.owl-theme .owl-dots .owl-dot:hover span {
background: #2d8af1; }
.owl-theme .owl-dots .owl-dot.active,
.owl-theme .owl-dots .owl-dot:hover {
border-width: 2px;
border-style: solid;
border-color: #2d8af1 !important; }
.component-slider .owl-nav .owl-prev,
.component-slider .owl-nav .owl-next {
color: #0855a0; }
.component-slider .owl-nav .owl-prev:hover,
.component-slider .owl-nav .owl-next:hover {
color: #0855a0; }
.component-slider .owl-nav .owl-prev.disabled,
.component-slider .owl-nav .owl-next.disabled {
color: #bebebe; }
.component-slide figcaption,
.component-slide__caption {
color: #aaaaaa; }
.cern-caption,
figcaption {
color: #aaaaaa !important; }
.cern-caption *,
figcaption * {
color: #aaaaaa !important; }
.field.field--type-entity-reference a {
background: #165e9d;
color: #f2f9ff; }
.field.field--type-entity-reference a:hover {
color: #f2f9ff; }
.field.field--type-entity-reference .field--items .field--item a {
background: #165e9d;
color: #f2f9ff; }
.field.field--type-entity-reference .field--items .field--item a:hover {
color: #f2f9ff; }
.news-node-full-content-tags a {
background-color: #165e9d;
color: #f2f9ff; }
.news-node-full-content-tags a:hover {
color: #f2f9ff; }
.resources-node-full-content-tags a {
background-color: #165e9d;
color: #f2f9ff; }
.resources-node-full-content-tags a:hover {
color: #f2f9ff; }
.event-node-full-content-file .file-link {
background-color: #165e9d; }
.event-node-full-content-file .file-link a {
color: #f2f9ff; }
.event-node-full-content-file .file-link a:hover {
color: #f2f9ff; }
.upper-cern-tag,
.cern-tag {
background-color: #165e9d;
color: #f2f9ff; }
.views-exposed-form .btn.btn-info,
.btn-default {
color: #ececec;
background-color: #0d62b6;
border-color: #063b6f; }
.views-exposed-form .btn.btn-info:focus, .views-exposed-form .btn.btn-info.focus,
.btn-default:focus,
.btn-default.focus {
color: #062d53;
background-color: #696b6c;
border-color: #063b6f; }
.views-exposed-form .btn.btn-info:hover,
.btn-default:hover {
color: #062d53;
background-color: #696b6c;
border-color: #063b6f; }
.views-exposed-form .btn.btn-info:active, .views-exposed-form .btn.btn-info.active,
.btn-default:active,
.btn-default.active {
color: #062d53;
background-color: #696b6c;
border-color: #063b6f;
background-image: none; }
.views-exposed-form .btn.btn-info:active:hover, .views-exposed-form .btn.btn-info:active:focus,
.views-exposed-form .btn.btn-info:active .focus, .views-exposed-form .btn.btn-info.active:hover, .views-exposed-form .btn.btn-info.active:focus,
.views-exposed-form .btn.btn-info.active .focus,
.btn-default:active:hover,
.btn-default:active:focus,
.btn-default:active .focus,
.btn-default.active:hover,
.btn-default.active:focus,
.btn-default.active .focus {
color: #062d53;
background-color: #696b6c;
border-color: #063b6f; }
.views-exposed-form .btn.btn-info .badge,
.btn-default .badge {
color: #ececec;
background-color: #0d62b6; }
.views-exposed-form .btn.btn-info.disabled:hover, .views-exposed-form .btn.btn-info[disabled]:hover, .views-exposed-form .btn.btn-info.disabled:focus, .views-exposed-form .btn.btn-info[disabled]:focus, .views-exposed-form .btn.btn-info.disabled.focus, .views-exposed-form .btn.btn-info[disabled].focus,
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
.btn-default.disabled.focus,
.btn-default[disabled].focus {
background-color: #696b6c;
border-color: #063b6f; }
.open > .dropdown-toggle.btn-default {
color: #062d53;
background-color: #696b6c;
border-color: #063b6f;
background-image: none; }
.open > .dropdown-toggle.btn-default:hover, .open > .dropdown-toggle.btn-default:focus, .open > .dropdown-toggle.btn-default.focus {
color: #062d53;
background-color: #696b6c;
border-color: #063b6f; }
fieldset[disabled] .btn-default:hover,
fieldset[disabled] .btn-default:focus,
fieldset[disabled] .btn-default.focus {
background-color: #696b6c;
border-color: #063b6f; }
.btn-primary {
color: #fbfdff;
background-color: #074888;
border-color: #063b6f; }
.btn-primary:focus,
.btn-primary.focus {
color: #02172a;
background-color: #595959;
border-color: #063b6f; }
.btn-primary:hover {
color: #02172a;
background-color: #595959;
border-color: #063b6f; }
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
color: #02172a;
background-color: #595959;
border-color: #063b6f; }
.btn-primary:active:hover,
.btn-primary.active:hover,
.open > .dropdown-toggle.btn-primary:hover,
.btn-primary:active:focus,
.btn-primary.active:focus,
.open > .dropdown-toggle.btn-primary:focus,
.btn-primary:active.focus,
.btn-primary.active.focus,
.open > .dropdown-toggle.btn-primary.focus {
color: #02172a;
background-color: #595959;
border-color: #063b6f; }
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
background-image: none; }
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled.focus,
.btn-primary[disabled].focus,
fieldset[disabled] .btn-primary.focus {
background-color: #595959;
border-color: #063b6f; }
.btn-primary .badge {
color: #fbfdff;
background-color: #074888; }
.btn-success {
color: #fbfdff;
background-color: #074888;
border-color: #063b6f; }
.btn-success:focus,
.btn-success.focus {
color: #02172a;
background-color: #595959;
border-color: #063b6f; }
.btn-success:hover {
color: #02172a;
background-color: #595959;
border-color: #063b6f; }
.btn-success:active,
.btn-success.active,
.open > .dropdown-toggle.btn-success {
color: #02172a;
background-color: #595959;
border-color: #063b6f; }
.btn-success:active:hover,
.btn-success.active:hover,
.open > .dropdown-toggle.btn-success:hover,
.btn-success:active:focus,
.btn-success.active:focus,
.open > .dropdown-toggle.btn-success:focus,
.btn-success:active.focus,
.btn-success.active.focus,
.open > .dropdown-toggle.btn-success.focus {
color: #02172a;
background-color: #595959;
border-color: #063b6f; }
.btn-success:active,
.btn-success.active,
.open > .dropdown-toggle.btn-success {
background-image: none; }
.btn-success.disabled:hover,
.btn-success[disabled]:hover,
fieldset[disabled] .btn-success:hover,
.btn-success.disabled:focus,
.btn-success[disabled]:focus,
fieldset[disabled] .btn-success:focus,
.btn-success.disabled.focus,
.btn-success[disabled].focus,
fieldset[disabled] .btn-success.focus {
background-color: #595959;
border-color: #063b6f; }
.btn-success .badge {
color: #fbfdff;
background-color: #074888; }
.views-view-grid .views-row .views-col article {
background: #0f5aa4;
color: #e9f5ff; }
.views-view-grid .views-row .views-col article a {
color: #2574b9; }
.views-view-grid .views-row .views-col article a:before {
color: #2d8af1; }
.views-view-grid .views-row .views-col article a:hover {
color: #044873; }
.views-view-grid .views-row .views-col article > h2 a {
color: #fdfeff; }
.views-view-grid .views-row .views-col article > h2 a:hover {
color: #fdfeff; }
.view .view-content table {
background: #fefefe; }
.view .view-content table thead th {
background: #2f4858;
color: #efefef;
padding: 5px; }
.view .view-content table tbody tr:nth-child(odd) {
background-color: #f9f9fa; }
.view .view-content table tbody tr:nth-child(even) {
background-color: #e9ecef; }
.view .view-content table tbody td {
color: #333333; }
.view .view-content table tfoot td {
background-color: #333339;
color: #999999; }
.block-custom-wrapper {
background: #0f5aa4;
color: #e9f5ff; }
.block-custom-wrapper .field--name-field-visible-title {
color: #fdfeff; }
.block-custom-wrapper .field--name-field-visible-title:before {
color: #2d8af1; }
main .block-custom-wrapper .field--type-text-with-summary a,
main .block-custom-wrapper .text-component-text.basic_html a,
main .block-custom-wrapper .text-component-text.restricted_html a,
main .block-custom-wrapper .text-component-text.cern_full_html a {
color: #2574b9; }
main .block-custom-wrapper .field--type-text-with-summary a:hover,
main .block-custom-wrapper .text-component-text.basic_html a:hover,
main .block-custom-wrapper .text-component-text.restricted_html a:hover,
main .block-custom-wrapper .text-component-text.cern_full_html a:hover {
color: #044873; }
.pagination > li a,
.pagination > li span {
-webkit-transition: all 0.3s ease-in-out 0s;
-khtml-transition: all 0.3s ease-in-out 0s;
-moz-transition: all 0.3s ease-in-out 0s;
-ms-transition: all 0.3s ease-in-out 0s;
-o-transition: all 0.3s ease-in-out 0s;
transition: all 0.3s ease-in-out 0s;
color: #2574b9; }
.pagination > li a::before {
color: #2574b9; }
.pagination > li a:hover {
color: #044873; }
.pagination .page__item--previous::before, .pagination .page__item--next::before {
color: #2574b9; }
.pagination .page__item--previous:hover::before, .pagination .page__item--next:hover::before {
color: #044873; }
/* ALL POSIBLE FUTURE PAGE VIEWS */
.view .view-header, .view.event-grid .view-header {
color: #2f4858; }
.view .view-header a, .view.event-grid .view-header a {
color: #2574b9; }
.view .view-header a.active:after, .view.event-grid .view-header a.active:after {
background: #044873; }
.view .view-header a *, .view.event-grid .view-header a * {
color: #2574b9; }
.view .view-header a *:hover, .view.event-grid .view-header a *:hover {
color: #044873; }
.view .view-content *, .view.event-grid .view-content * {
color: #2f4858; }
.view .view-content a, .view.event-grid .view-content a {
color: #2574b9; }
.view .view-content a:hover, .view.event-grid .view-content a:hover {
color: #044873; }
.view .view-content a *, .view.event-grid .view-content a * {
color: #2574b9; }
.view .view-content a *:hover, .view.event-grid .view-content a *:hover {
color: #044873; }
/* ALL EVENTS PAGE VIEWS */
.cern-view-display-page.cern-view-display-feature_events .view-header,
.cern-view-display-page.cern-view-display-past_events .view-header {
color: #2f4858 !important; }
.cern-view-display-page.cern-view-display-feature_events .view-header a,
.cern-view-display-page.cern-view-display-past_events .view-header a {
color: #2574b9 !important; }
.cern-view-display-page.cern-view-display-feature_events .view-content .views-row *,
.cern-view-display-page.cern-view-display-past_events .view-content .views-row * {
color: #2f4858 !important; }
.cern-view-display-page.cern-view-display-feature_events .view-content .views-row .agenda-box-cal-button a.btn,
.cern-view-display-page.cern-view-display-past_events .view-content .views-row .agenda-box-cal-button a.btn {
color: #fbfdff !important; }
.cern-view-display-page.cern-view-display-feature_events .view-content .views-row a:not(.btn),
.cern-view-display-page.cern-view-display-past_events .view-content .views-row a:not(.btn) {
color: #2574b9 !important; }
.cern-view-display-page.cern-view-display-feature_events .view-content .views-row a:not(.btn):hover,
.cern-view-display-page.cern-view-display-past_events .view-content .views-row a:not(.btn):hover {
color: #044873 !important; }
.cern-view-display-page.cern-view-display-feature_events .view-content .views-row a:not(.btn) *,
.cern-view-display-page.cern-view-display-past_events .view-content .views-row a:not(.btn) * {
color: #2574b9 !important; }
.cern-view-display-page.cern-view-display-feature_events .view-content .views-row a:not(.btn) *:hover,
.cern-view-display-page.cern-view-display-past_events .view-content .views-row a:not(.btn) *:hover {
color: #2574b9 !important; }
/* UPCOMING EVENTS */
.cern-view-display-block.cern-view-display-upcoming_events .owl-nav {
position: relative; }
.cern-view-display-block.cern-view-display-upcoming_events .owl-nav .owl-prev:after {
color: #2574b9; }
.cern-view-display-block.cern-view-display-upcoming_events .owl-nav .owl-prev:hover:after {
color: #044873; }
.cern-view-display-block.cern-view-display-upcoming_events .owl-nav .owl-prev.disabled:after {
color: #2f4858; }
.cern-view-display-block.cern-view-display-upcoming_events .owl-nav .owl-next:after {
color: #2574b9; }
.cern-view-display-block.cern-view-display-upcoming_events .owl-nav .owl-next:hover:after {
color: #044873; }
.cern-view-display-block.cern-view-display-upcoming_events .owl-nav .owl-next.disabled:after {
color: #2f4858; }
.cern-view-display-block.cern-view-display-upcoming_events .agenda-box-pattern * {
color: #2f4858 !important; }
.cern-view-display-block.cern-view-display-upcoming_events .agenda-box-pattern a {
color: #2574b9 !important; }
.cern-view-display-block.cern-view-display-upcoming_events .agenda-box-pattern a:hover {
color: #044873 !important; }
.cern-view-display-block.cern-view-display-upcoming_events .agenda-box-pattern a * {
color: #2574b9 !important; }
.cern-view-display-block.cern-view-display-upcoming_events .agenda-box-pattern a *:hover {
color: #2574b9 !important; }
/* News, Taxonomies, search list pages mobile cards*/
@media only screen and (max-width: 767px) {
.cern-view-display-page.cern-view-display-all_news .view-content .views-row .box-pattern a,
.cern-view-display-page.cern-view-display-all_news .view-content .views-row .box-pattern .preview-cards__subtext,
.cern-view-display-page.view-general-search .view-content .views-row .box-pattern a,
.cern-view-display-page.view-general-search .view-content .views-row .box-pattern .preview-cards__subtext,
.cern-view-display-page.cern-view-display-page_taxonomies .view-content .views-row .box-pattern a,
.cern-view-display-page.cern-view-display-page_taxonomies .view-content .views-row .box-pattern .preview-cards__subtext {
color: white !important; }
.cern-view-display-page.cern-view-display-all_news .view-content .views-row .box-pattern a *,
.cern-view-display-page.cern-view-display-all_news .view-content .views-row .box-pattern .preview-cards__subtext *,
.cern-view-display-page.view-general-search .view-content .views-row .box-pattern a *,
.cern-view-display-page.view-general-search .view-content .views-row .box-pattern .preview-cards__subtext *,
.cern-view-display-page.cern-view-display-page_taxonomies .view-content .views-row .box-pattern a *,
.cern-view-display-page.cern-view-display-page_taxonomies .view-content .views-row .box-pattern .preview-cards__subtext * {
color: white !important; } }
/* ALL FAQS */
.cern-view-display-page.cern-view-display-faq_page .view-header {
color: rgba(0, 0, 0, 0.4) !important; }
.cern-view-display-page.cern-view-display-faq_page .view-header a {
color: #2574b9 !important; }
.cern-view-display-page.cern-view-display-faq_page .view-content .views-row * {
color: #2f4858 !important; }
.cern-view-display-page.cern-view-display-faq_page .view-content .views-row span.collapseManager {
color: #2574b9 !important; }
.cern-view-display-page.cern-view-display-faq_page .view-content .views-row a {
color: #2574b9 !important; }
.cern-view-display-page.cern-view-display-faq_page .view-content .views-row a:hover {
color: #044873 !important; }
.cern-view-display-page.cern-view-display-faq_page .view-content .views-row a * {
color: #2574b9 !important; }
.cern-view-display-page.cern-view-display-faq_page .view-content .views-row a *:hover {
color: #2574b9 !important; }
/* ALL Resources PAGE VIEWS */
.cern-view-display-page.cern-view-display-resources .view-header,
.resources-mosaic .view-header {
color: #2f4858 !important; }
.cern-view-display-page.cern-view-display-resources .view-header a,
.resources-mosaic .view-header a {
color: #2574b9 !important; }
.cern-view-display-page.cern-view-display-resources .view-header a.active:after,
.resources-mosaic .view-header a.active:after {
background: #044873 !important; }
.cern-view-display-page.cern-view-display-resources .view-content *,
.resources-mosaic .view-content * {
color: white !important; }
.cern-view-display-page.cern-view-display-resources .view-content a,
.resources-mosaic .view-content a {
color: white !important; }
.cern-view-display-page.cern-view-display-resources .view-content a:hover,
.resources-mosaic .view-content a:hover {
color: white !important; }
.cern-view-display-page.cern-view-display-resources .view-content a *,
.resources-mosaic .view-content a * {
color: white !important; }
.cern-view-display-page.cern-view-display-resources .view-content a *:hover,
.resources-mosaic .view-content a *:hover {
color: white !important; }
.cern-view-display-page.cern-view-display-page_taxonomies .view-content .views-row {
/* .box-pattern.agenda-box-pattern {
* {
color: white !important;
}
} */ }
.cern-view-display-page.cern-view-display-page_taxonomies .view-content .views-row .box-pattern:not(.agenda-box-pattern) * {
color: white !important; }
@media screen and (max-width: 991px) {
.cern-view-display-block.cern-view-display-upcoming_events .owl-item.active .carousel-cern-item.row .views-row .agenda-box-pattern:before,
.events-collision .owl-item.active .carousel-cern-item.row .views-row .agenda-box-pattern:before {
border-color: #2d8af1 !important; } }
@media screen and (min-width: 992px) {
.bubbly-button {
background-color: #2d8af1; }
.bubbly-button:before {
background-image: radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, transparent 20%, #2d8af1 20%, transparent 30%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, transparent 10%, #2d8af1 15%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%); }
.bubbly-button:after {
background-image: radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, transparent 10%, #2d8af1 15%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%), radial-gradient(circle, #2d8af1 20%, transparent 20%); } }
.cern-view-display-more_faq .view-content .views-row > div h3 a:before {
color: #2d8af1 !important; }
main .region-content .block-language {
background: #2f3442; }
main .region-content .block-language a {
color: #fafafa; }
.page-navigation-progress {
background: #2d8af1 !important; }
.page-navigation-progress:after {
border: 4px solid #2d8af1 !important; }
.preview-list-component .preview-list-image {
background-color: #0f5aa4; }
.preview-list-component .preview-list-news-info .preview-list-title a {
color: #2574b9; }
.preview-list-component .preview-list-news-info .preview-list-title a:hover {
color: #044873; }
.preview-list-component .preview-list-news-info .preview-list-title .preview-list-strap, .preview-list-component .preview-list-news-info .preview-list-title .preview-list-news-format, .preview-list-component .preview-list-news-info .preview-list-title .preview-list-date {
color: #2f4858; }
.cern-component-header-blocks .component-header__carousel .owl-dots .owl-dot.active,
.cern-component-header-blocks .component-header__carousel .owl-dots .owl-dot:hover {
border-color: #2d8af1; }
.component-header__carousel .header-block__title .header-block__name__underline {
background: #2f4858; }
.component-call-to-action__wrapper a {
color: #fbfdff; }
.component-call-to-action__wrapper a:hover {
color: #fbfdff; }
.component-division__text {
background: #0f5aa4; }
.component-division__text__link {
color: #fdfeff; }
.component-division__text__link a {
color: #fdfeff; }
.component-division__text__link a:hover {
color: #fdfeff; }
.component-division__text__link a:before {
color: #2d8af1; }
.component-division__text__text {
color: #e9f5ff; }
.component-division__text__text a {
color: #e9f5ff; }
.component-division__text__text a:hover {
color: #e9f5ff; }
.component-related_card, .view .component-related_card {
background: #0f5aa4;
color: #e9f5ff; }
.component-related_card__content__date, .view .component-related_card__content__date {
color: #e9f5ff; }
.component-related_card__content__link a span, .view .component-related_card__content__link a span {
color: #fdfeff; }
.component-related_card__content__link a span:hover, .view .component-related_card__content__link a span:hover {
color: #fdfeff; }
.component-related_card__content__link a:hover, .view .component-related_card__content__link a:hover {
color: #fdfeff; }
.component-related_card__content__link a:before, .view .component-related_card__content__link a:before {
color: #2d8af1; }
.component-related_card__content__text p, .view .component-related_card__content__text p {
color: #e9f5ff; }
.component-preview-cards, .view .component-preview-cards {
background: #0f5aa4;
color: #e9f5ff; }
.component-preview-cards__icon.video, .view .component-preview-cards__icon.video {
color: #e9f5ff; }
.component-preview-cards__icon.image, .view .component-preview-cards__icon.image {
color: #e9f5ff; }
.component-preview-cards__box, .view .component-preview-cards__box {
color: #e9f5ff; }
.component-preview-cards div.preview-card__title, .view .component-preview-cards div.preview-card__title {
color: #fdfeff; }
.component-preview-cards div.preview-card__title h3 a span, .view .component-preview-cards div.preview-card__title h3 a span {
color: #fdfeff; }
.component-preview-cards div.preview-card__title h3 a span:hover, .view .component-preview-cards div.preview-card__title h3 a span:hover {
color: #fdfeff; }
.component-preview-cards div.preview-card__title h3 a:hover, .view .component-preview-cards div.preview-card__title h3 a:hover {
color: #fdfeff; }
.component-preview-cards div.preview-card__title h3 a:before, .view .component-preview-cards div.preview-card__title h3 a:before {
color: #2d8af1; }
.component-preview-cards .preview-card__body *, .view .component-preview-cards .preview-card__body * {
color: #e9f5ff; }
.component-preview-cards .preview-cards__subtext *, .view .component-preview-cards .preview-cards__subtext * {
color: #e9f5ff; }
.component-media-content, .view .component-media-content {
background: #0f5aa4;
color: #e9f5ff; }
.component-media-content__icon, .view .component-media-content__icon {
color: #e9f5ff; }
.component-media-content__title a, .view .component-media-content__title a {
color: #fdfeff; }
.component-media-content__title a:hover, .view .component-media-content__title a:hover {
color: #fdfeff; }
.component-media-content__title a:before, .view .component-media-content__title a:before {
color: #2d8af1; }
.accordion-cern .panel-body p {
color: #2f4858; }
.events-collision .bubbly-button {
color: #2d8af1; }
.events-collision .agenda-box-pattern .agenda-box-pattern__box-wrapper .agenda-box-link h3 a {
color: #2574b9; }
.events-collision .agenda-box-pattern .agenda-box-pattern__box-wrapper .agenda-box-link h3 a:hover {
color: #044873; }
.events-collision .agenda-box-pattern .agenda-box-pattern__box-wrapper .agenda-box-link h3 a::before {
color: #2d8af1; }
.events-collision .agenda-box-pattern .agenda-box-pattern__box-wrapper .agenda-box-content-type, .events-collision .agenda-box-pattern .agenda-box-pattern__box-wrapper .agenda-box-place {
color: #2f4858; }
.events-collision .owl-nav .owl-prev::after,
.events-collision .owl-nav .owl-next::after {
color: #0855a0; }
.events-collision .owl-nav .owl-prev:hover::after,
.events-collision .owl-nav .owl-next:hover::after {
color: #0855a0; }
.events-collision .owl-nav .owl-prev.disabled::after,
.events-collision .owl-nav .owl-next.disabled::after {
color: #bebebe; }
.event-grid .agenda-box-pattern .agenda-box-date-wrapper * {
color: #2f4858; }
.event-grid .agenda-box-pattern .agenda-box-link a {
color: #2574b9; }
.event-grid .agenda-box-pattern .agenda-box-link a:hover {
color: #044873; }
.event-grid .agenda-box-pattern .agenda-box-content-type, .event-grid .agenda-box-pattern .agenda-box-place {
color: #2f4858; }
.event-grid .agenda-box-pattern .agenda-box-cal-wrapper .agenda-box-cal-button a {
color: #fbfdff;
background-color: #074888;
border-color: #063b6f; }
.event-grid .agenda-box-pattern .agenda-box-cal-wrapper .agenda-box-cal-button a:hover {
background-color: #595959; }
.teaser-list-block .views-field a {
color: #2574b9 !important; }
.teaser-list-block .views-field a:before {
color: #2d8af1; }
/*# sourceMappingURL=colors.css.map */

View file

@ -0,0 +1,396 @@
*,
*::before,
*::after {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body,
main,
h1,
h2,
h3,
p {
margin: 0;
}
/*-- Body Reset --*/
body {
/* overflow-x: hidden */
font-family: 'Montserrat', sans-serif;
color: rgb(47, 72, 88);
}
/*============= TOP BAR HEADER =============*/
.dropwown-navbar-colors {
background: rgb(42, 52, 66);
border-color: rgb(42, 52, 66);
}
/*============= NAVIGATION =============*/
.navbar-brand img {
height: 4rem;
}
.navbar {
font-size: 1rem;
font-weight: 600;
letter-spacing: .1rem;
/* box-shadow: 0 .5rem .5rem rgba(0,0,0,.5); */
z-index: 1;
background: rgb(42, 52, 66);
}
.nav {
margin-inline: auto;
width: min(90%, 70.5rem);
}
.nav-item {
padding: .2rem;
}
.header-navbar.nav-link {
color: rgb(255, 255, 255)!important;
}
.header-navbar.nav-link.active,
.header-navbar.nav-link:hover {
color: rgb(45, 138, 241)!important;
}
/*============= SPLIT =============*/
.split {
/* flex: 1; */
clear: both;
display: inline-flex;
flex-direction: column;
width: 100%;
}
/*============= TEXT AND CONTENT =============*/
.header-height {
height: 96px;
}
.logo {
height: 6em;
}
.logo_form {
height: 3em;
}
#nat_vent_image {
height: 10em;
}
.cara_home_image {
height: 18rem;
padding: 1rem;
border-radius: 1.25rem!important;
}
.container {
margin-inline: auto;
width: min(90%, 70.5rem);
}
.container--narrow {
max-width: 44rem;
}
.container--padding {
padding: 2rem 0;
}
.paragraph-title {
text-align: center;
font-size: 2rem;
}
.contributors {
text-align: left;
font-size: 1.25rem;
}
.center {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.bigButton {
width: 18em;
height: 4em;
background: rgb(45, 138, 241);
}
.breakBoxExposed {
float:left;
margin-left:1rem;
margin-right:2rem;
}
.breakBoxInfected {
display:none;
float:left;
margin-left:1rem;
margin-right:2rem;
}
.boxMargin {
padding:10px;
border: 2px solid rgb(47, 52, 66);
}
.disclaimer {
background: rgb(45, 138, 241);
padding: 1.5rem 0;
color: black;
}
.icon-calculator {
background: url(../icons/calculator.svg);
width: 30px;
display: block;
}
.icon-expert {
background: url(../icons/expert.svg);
width: 30px;
display: block;
}
.mask_icons {
height: 4em;
}
/*===== FIXED BACKGROUND IMG =====*/
.fixed-background {
overflow: hidden; /*-- Correction for iOS --*/
}
/*===== INPUT =====*/
/*============= FOOTER =============*/
footer {
background-color: rgb(42, 52, 66);
padding: 1rem 2rem 3rem;
}
footer img {
height: 5.5rem;
margin: 1.5rem auto;
}
/*============= REPORT =============*/
#report_logo {
height: 4em;
margin: 1%;
}
.animation-color {
background-color: #d5d8d9!important;
}
/*============= MEDIA QUERIES =============*/
/* Devices over 640px (xl) */
@media (min-width: 40em) {
.split {
flex-direction: row;
}
.split > * {
flex-basis: 100%;
}
.paragraph-title {
text-align: left;
font-size: 2rem;
}
.developers {
text-align: left;
font-size: 1.5rem;
}
.split > * + * {
margin-left: 2em;
}
.bigButton {
width: 25%;
}
#nat_vent_image {
height: 15em;
}
.header_text {
font-weight: bold;
}
#report_logo {
height: 6em;
margin: 1%;
}
#mobile-app-buttons {
display: none!important;
}
.feedback {
float:right;
font-size:1rem;
font-weight:bold;
}
.cara_version {
float:left;
font-size:1rem;
}
.cara_home_image {
float: right;
}
.navbar .nav-item .dropdown-menu{ display: none; }
.navbar .nav-item:hover .dropdown-menu{ display: block; }
.navbar .nav-item .dropdown-menu{ margin-top:0; }
#apps_section {
display: inline!important;
}
}
@media (max-width: 40em) {
#body {
font-size: .75rem;
padding: 20px 10px;
}
.header_text {
font-size: 1rem;
font-weight: bold;
}
.nav-link {
padding: .5rem .5rem!important;
}
#report_version {
font-size: .5rem;
}
#download-pdf, #pdf_qrcode_aref {
display: none;
}
#cern_level{
height: 15em;
margin-top: 1em;
}
#link_reproduce_results {
display: none;
}
#mobile_link {
display: inline!important;
}
#desktop_logo {
display: none!important;
}
#mobile_logo {
display: block!important;
}
.feedback {
float:right;
font-size:.75rem;
font-weight:bold;
}
.cara_version {
float:left;
font-size:.75rem;
}
.h1-text {
font-size: 1.5rem;
}
}
/* Devices under 768px (md) */
/* @media (max-width: 767.98px) {
} */
/* Large (lg) devices (desktops, 992px and up) */
@media (max-width: 992px) {
#download-pdf {
display: none;
}
#link_reproduce_results {
display: none;
}
#mobile_link {
display: inline!important;
}
}
/*============ BOOTSTRAP BREAK POINTS:
Extra small (xs) devices (portrait phones, less than 576px)
No media query since this is the default in Bootstrap
Small (sm) devices (landscape phones, 576px and up)
@media (min-width: 576px) { ... }
Medium (md) devices (tablets, 768px and up)
@media (min-width: 768px) { ... }
Large (lg) devices (desktops, 992px and up)
@media (min-width: 992px) { ... }
Extra (xl) large devices (large desktops, 1200px and up)
@media (min-width: 1200px) { ... }
=============*/
/* -- Bootstrap Mobile Gutter Fix -- */
/* .row, .container-fluid {
margin-left: 0px !important;
margin-right: 0px !important;
} */
/*-- Fixed Background Image --*/
/* .fixed-background {
position: relative;
width: 100%;
z-index: 1000!important;
}
.fixed-wrap {
clip: rect(0, auto, auto, 0);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -999 !important;
}
.fixed {
z-index: -999!important;
display: block;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
-webkit-transform: translateZ(0);
transform: translateZ(0);
will-change: transform;
} */

View file

@ -0,0 +1,51 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.7551 25.25C18.8259 25.5185 18.5035 25.8388 18.032 25.9657C17.5605 26.0926 17.1197 25.9763 17.0478 25.7067C16.9897 25.4953 17.1831 25.2447 17.5066 25.0883C17.4888 24.7642 17.3935 24.4492 17.2286 24.1696C17.053 23.8773 16.8178 23.6252 16.5383 23.4296C16.0028 23.5265 15.4598 23.5757 14.9157 23.5766C14.6715 23.816 14.4806 24.1041 14.3554 24.4223C14.2405 24.7254 14.2003 25.0517 14.2381 25.3737C14.5911 25.4731 14.8322 25.6908 14.8121 25.9086C14.7867 26.1877 14.3628 26.3759 13.8607 26.3315C13.3586 26.2871 12.9769 26.0238 13.0023 25.7448C13.0224 25.5228 13.2983 25.3568 13.6641 25.3219C13.761 25.0103 13.7806 24.6797 13.7211 24.3589C13.6552 24.0306 13.5232 23.7191 13.3332 23.4434C12.7906 23.3519 12.2577 23.2104 11.7412 23.0205L11.8353 23.066C11.5121 23.2078 11.2236 23.4181 10.9896 23.6823C10.776 23.9281 10.6247 24.2219 10.5488 24.5386C10.8458 24.75 11.0002 25.0365 10.904 25.2384C10.7845 25.4921 10.3205 25.5228 9.86695 25.3071C9.41346 25.0915 9.1439 24.7141 9.26547 24.4614C9.36166 24.2606 9.67562 24.1982 10.0308 24.2923C10.2289 24.0338 10.3607 23.7307 10.4145 23.4096C10.4689 23.0681 10.4505 22.7191 10.3606 22.3852C9.9037 22.1281 9.47005 21.8317 9.06462 21.4993C8.73795 21.536 8.42235 21.6397 8.13754 21.8038C7.85732 21.9682 7.62117 22.1982 7.44937 22.474C7.66079 22.7732 7.71681 23.0914 7.56142 23.2521C7.36691 23.4529 6.91765 23.3334 6.55717 22.9878C6.1967 22.6421 6.06034 22.1939 6.25485 21.992C6.41024 21.8313 6.72737 21.8746 7.03393 22.0776C7.30374 21.8949 7.52505 21.6492 7.67876 21.3619C7.83193 21.0703 7.92401 20.7505 7.94938 20.4221C7.58719 20.0058 7.26246 19.5583 6.97896 19.0849C6.66575 19.0178 6.34232 19.0138 6.02757 19.0732C5.70791 19.136 5.40848 19.2761 5.15546 19.4813C5.26117 19.8333 5.20831 20.1504 5.00852 20.2519C4.75799 20.3788 4.37426 20.1198 4.14593 19.6737C3.91759 19.2276 3.93451 18.7614 4.18504 18.6345C4.38483 18.5288 4.67131 18.6779 4.89436 18.9707C5.20932 18.8859 5.49934 18.7267 5.74004 18.5066C5.98184 18.2785 6.17494 18.0037 6.3077 17.699C6.09935 17.1724 5.94114 16.6273 5.83518 16.071C5.57249 15.9038 5.27933 15.7903 4.97258 15.7369C4.65131 15.6817 4.32138 15.706 4.01168 15.8078C3.98208 16.1725 3.8214 16.4516 3.60046 16.4748C3.32139 16.5055 3.05289 16.1249 2.99792 15.6291C2.94295 15.1333 3.129 14.7031 3.40596 14.6724C3.62901 14.6481 3.84465 14.8838 3.95036 15.238C4.27368 15.2705 4.60007 15.2245 4.90175 15.1037C5.19303 14.9843 5.45834 14.8095 5.68295 14.5889C5.68295 14.5212 5.68295 14.4525 5.68295 14.3859C5.68243 13.9338 5.71529 13.4822 5.78126 13.0349C5.58616 12.7654 5.33657 12.54 5.04869 12.3732C4.76731 12.21 4.44987 12.1192 4.12479 12.1089C3.97045 12.4408 3.72415 12.647 3.50638 12.593C3.23471 12.5243 3.1142 12.074 3.23577 11.5888C3.35733 11.1036 3.67869 10.7632 3.94825 10.8329C4.16601 10.8868 4.28758 11.1839 4.26538 11.5507C4.55759 11.6946 4.88063 11.7647 5.2062 11.7547C5.52797 11.7442 5.84419 11.6679 6.13539 11.5306C6.30498 11.0148 6.5197 10.515 6.77705 10.0369C6.67858 9.71196 6.51251 9.4115 6.28973 9.15526C6.07451 8.911 5.80316 8.72272 5.49902 8.60662C5.24743 8.87301 4.94616 8.98929 4.75905 8.86773C4.52543 8.7155 4.55397 8.25142 4.82565 7.83069C5.09732 7.40995 5.50959 7.19007 5.74532 7.34229C5.93243 7.46386 5.95146 7.78523 5.81192 8.12457C6.04284 8.35434 6.32618 8.52449 6.63751 8.62036C6.96748 8.71808 7.31429 8.74546 7.6555 8.7007C7.80773 8.50513 7.97263 8.31591 8.13965 8.13302L10.0942 10.1363C7.85212 12.7654 7.33732 16.3511 8.76546 19.0648C10.627 22.6019 15.5721 24.2299 19.8724 22.1051C19.3045 22.4738 18.6972 22.7776 18.0616 23.011C17.9159 23.325 17.8374 23.666 17.8312 24.0121C17.8287 24.3364 17.9041 24.6565 18.051 24.9456C18.403 24.916 18.6969 25.0344 18.7551 25.25Z" fill="#BE202E"/>
<path d="M19.8694 22.1125C19.2298 22.5216 17.1283 23.751 14.4517 23.3419C11.1694 22.8366 8.37974 20.0881 7.90722 16.6883C7.41144 13.1026 9.74446 10.5158 10.0912 10.1437L10.1018 10.1564C9.09463 11.2904 8.5243 12.7461 8.49299 14.2624C8.46168 15.7788 8.97144 17.2568 9.9309 18.4314C10.8904 19.6061 12.2368 20.4006 13.7289 20.6726C15.221 20.9446 16.7611 20.6763 18.0734 19.9158L18.2361 19.8174L19.8694 22.1125Z" fill="#69121A"/>
<path d="M19.8787 22.1177C18.2736 23.158 16.3411 23.5694 14.4516 23.2731C12.562 22.9768 10.8482 21.9936 9.63857 20.512C8.42895 19.0303 7.8086 17.1544 7.89637 15.2437C7.98414 13.333 8.77387 11.5219 10.1142 10.1574" stroke="white" stroke-width="0.98" stroke-miterlimit="10"/>
<path d="M14.9854 3.12747C16.6751 3.02124 18.3668 3.30067 19.9326 3.94463C25.6853 6.30097 28.4296 12.8974 26.0638 18.6778C25.4352 20.2204 24.4728 21.6046 23.2455 22.7308" stroke="#0054A6" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M22.8652 17.6651C22.9463 17.6651 23.0121 17.5993 23.0121 17.5182C23.0121 17.437 22.9463 17.3712 22.8652 17.3712C22.784 17.3712 22.7183 17.437 22.7183 17.5182C22.7183 17.5993 22.784 17.6651 22.8652 17.6651Z" fill="#3B9EFF"/>
<path d="M23.0875 16.533C23.1733 16.533 23.2429 16.4635 23.2429 16.3776C23.2429 16.2918 23.1733 16.2222 23.0875 16.2222C23.0017 16.2222 22.9321 16.2918 22.9321 16.3776C22.9321 16.4635 23.0017 16.533 23.0875 16.533Z" fill="#379AF9"/>
<path d="M23.1322 15.3575C23.2233 15.3575 23.2971 15.2836 23.2971 15.1926C23.2971 15.1015 23.2233 15.0276 23.1322 15.0276C23.0411 15.0276 22.9673 15.1015 22.9673 15.1926C22.9673 15.2836 23.0411 15.3575 23.1322 15.3575Z" fill="#3395F4"/>
<path d="M22.9864 14.1523C23.0828 14.1523 23.1609 14.0742 23.1609 13.9778C23.1609 13.8815 23.0828 13.8034 22.9864 13.8034C22.8901 13.8034 22.812 13.8815 22.812 13.9778C22.812 14.0742 22.8901 14.1523 22.9864 14.1523Z" fill="#3090EE"/>
<path d="M22.6521 12.9863C22.7531 12.9863 22.835 12.9044 22.835 12.8034C22.835 12.7024 22.7531 12.6205 22.6521 12.6205C22.5511 12.6205 22.4692 12.7024 22.4692 12.8034C22.4692 12.9044 22.5511 12.9863 22.6521 12.9863Z" fill="#2C8CE9"/>
<path d="M22.1504 11.9144C22.2567 11.9144 22.3428 11.8283 22.3428 11.722C22.3428 11.6157 22.2567 11.5296 22.1504 11.5296C22.0441 11.5296 21.958 11.6157 21.958 11.722C21.958 11.8283 22.0441 11.9144 22.1504 11.9144Z" fill="#2887E3"/>
<path d="M21.4982 10.9469C21.6091 10.9469 21.6991 10.857 21.6991 10.7461C21.6991 10.6352 21.6091 10.5452 21.4982 10.5452C21.3873 10.5452 21.2974 10.6352 21.2974 10.7461C21.2974 10.857 21.3873 10.9469 21.4982 10.9469Z" fill="#2583DE"/>
<path d="M20.7108 10.1002C20.827 10.1002 20.9212 10.0061 20.9212 9.88987C20.9212 9.77369 20.827 9.6795 20.7108 9.6795C20.5947 9.6795 20.5005 9.77369 20.5005 9.88987C20.5005 10.0061 20.5947 10.1002 20.7108 10.1002Z" fill="#217ED8"/>
<path d="M19.8063 9.38465C19.9277 9.38465 20.0262 9.2862 20.0262 9.16477C20.0262 9.04333 19.9277 8.94489 19.8063 8.94489C19.6849 8.94489 19.5864 9.04333 19.5864 9.16477C19.5864 9.2862 19.6849 9.38465 19.8063 9.38465Z" fill="#1D79D3"/>
<path d="M18.804 8.8116C18.9301 8.8116 19.0323 8.70937 19.0323 8.58326C19.0323 8.45715 18.9301 8.35492 18.804 8.35492C18.6779 8.35492 18.5757 8.45715 18.5757 8.58326C18.5757 8.70937 18.6779 8.8116 18.804 8.8116Z" fill="#1A75CD"/>
<path d="M17.7208 8.3963C17.8521 8.3963 17.9586 8.28981 17.9586 8.15845C17.9586 8.02708 17.8521 7.92059 17.7208 7.92059C17.5894 7.92059 17.4829 8.02708 17.4829 8.15845C17.4829 8.28981 17.5894 8.3963 17.7208 8.3963Z" fill="#1670C7"/>
<path d="M16.5716 8.15202C16.7082 8.15202 16.8189 8.04127 16.8189 7.90466C16.8189 7.76804 16.7082 7.65729 16.5716 7.65729C16.435 7.65729 16.3242 7.76804 16.3242 7.90466C16.3242 8.04127 16.435 8.15202 16.5716 8.15202Z" fill="#126BC2"/>
<path d="M15.3745 8.08764C15.5158 8.08764 15.6303 7.9731 15.6303 7.83181C15.6303 7.69052 15.5158 7.57599 15.3745 7.57599C15.2332 7.57599 15.1187 7.69052 15.1187 7.83181C15.1187 7.9731 15.2332 8.08764 15.3745 8.08764Z" fill="#0F67BC"/>
<path d="M14.1506 8.21964C14.2971 8.21964 14.4159 8.10084 14.4159 7.9543C14.4159 7.80776 14.2971 7.68896 14.1506 7.68896C14.004 7.68896 13.8853 7.80776 13.8853 7.9543C13.8853 8.10084 14.004 8.21964 14.1506 8.21964Z" fill="#0B62B7"/>
<path d="M12.9838 8.53878C13.1356 8.53878 13.2587 8.41572 13.2587 8.26393C13.2587 8.11213 13.1356 7.98907 12.9838 7.98907C12.832 7.98907 12.709 8.11213 12.709 8.26393C12.709 8.41572 12.832 8.53878 12.9838 8.53878Z" fill="#075EB1"/>
<path d="M11.9068 9.02407C12.0633 9.02407 12.1901 8.89723 12.1901 8.74077C12.1901 8.5843 12.0633 8.45746 11.9068 8.45746C11.7504 8.45746 11.6235 8.5843 11.6235 8.74077C11.6235 8.89723 11.7504 9.02407 11.9068 9.02407Z" fill="#0459AC"/>
<path d="M10.932 9.66164C11.0937 9.66164 11.2248 9.53054 11.2248 9.36881C11.2248 9.20709 11.0937 9.07599 10.932 9.07599C10.7703 9.07599 10.6392 9.20709 10.6392 9.36881C10.6392 9.53054 10.7703 9.66164 10.932 9.66164Z" fill="#0054A6"/>
<path d="M22.8792 21.9971C23.041 21.9971 23.1721 21.866 23.1721 21.7043C23.1721 21.5425 23.041 21.4114 22.8792 21.4114C22.7175 21.4114 22.5864 21.5425 22.5864 21.7043C22.5864 21.866 22.7175 21.9971 22.8792 21.9971Z" fill="#3B9EFF"/>
<path d="M24.1063 20.3776C24.275 20.3776 24.4118 20.2408 24.4118 20.0721C24.4118 19.9034 24.275 19.7666 24.1063 19.7666C23.9376 19.7666 23.8008 19.9034 23.8008 20.0721C23.8008 20.2408 23.9376 20.3776 24.1063 20.3776Z" fill="#3698F8"/>
<path d="M25.0027 18.4854C25.1778 18.4854 25.3198 18.3434 25.3198 18.1683C25.3198 17.9931 25.1778 17.8511 25.0027 17.8511C24.8275 17.8511 24.6855 17.9931 24.6855 18.1683C24.6855 18.3434 24.8275 18.4854 25.0027 18.4854Z" fill="#3192F0"/>
<path d="M25.4973 16.4029C25.6795 16.4029 25.8271 16.2552 25.8271 16.073C25.8271 15.8909 25.6795 15.7432 25.4973 15.7432C25.3151 15.7432 25.1675 15.8909 25.1675 16.073C25.1675 16.2552 25.3151 16.4029 25.4973 16.4029Z" fill="#2C8CE9"/>
<path d="M25.547 14.3255C25.7356 14.3255 25.8885 14.1727 25.8885 13.9841C25.8885 13.7955 25.7356 13.6426 25.547 13.6426C25.3584 13.6426 25.2056 13.7955 25.2056 13.9841C25.2056 14.1727 25.3584 14.3255 25.547 14.3255Z" fill="#2786E1"/>
<path d="M25.1788 12.3214C25.3744 12.3214 25.533 12.1628 25.533 11.9672C25.533 11.7717 25.3744 11.6131 25.1788 11.6131C24.9833 11.6131 24.8247 11.7717 24.8247 11.9672C24.8247 12.1628 24.9833 12.3214 25.1788 12.3214Z" fill="#227FDA"/>
<path d="M24.417 10.4469C24.619 10.4469 24.7828 10.2832 24.7828 10.0812C24.7828 9.87915 24.619 9.71539 24.417 9.71539C24.215 9.71539 24.0513 9.87915 24.0513 10.0812C24.0513 10.2832 24.215 10.4469 24.417 10.4469Z" fill="#1D79D3"/>
<path d="M23.2988 8.763C23.5079 8.763 23.6773 8.59357 23.6773 8.38455C23.6773 8.17554 23.5079 8.0061 23.2988 8.0061C23.0898 8.0061 22.9204 8.17554 22.9204 8.38455C22.9204 8.59357 23.0898 8.763 23.2988 8.763Z" fill="#1873CB"/>
<path d="M21.8515 7.32636C22.0669 7.32636 22.2416 7.15172 22.2416 6.93628C22.2416 6.72085 22.0669 6.5462 21.8515 6.5462C21.6361 6.5462 21.4614 6.72085 21.4614 6.93628C21.4614 7.15172 21.6361 7.32636 21.8515 7.32636Z" fill="#146DC4"/>
<path d="M20.1034 6.19744C20.3259 6.19744 20.5062 6.01711 20.5062 5.79467C20.5062 5.57223 20.3259 5.39191 20.1034 5.39191C19.881 5.39191 19.7007 5.57223 19.7007 5.79467C19.7007 6.01711 19.881 6.19744 20.1034 6.19744Z" fill="#0F67BC"/>
<path d="M18.0965 5.43847C18.3254 5.43847 18.5109 5.25294 18.5109 5.02408C18.5109 4.79521 18.3254 4.60968 18.0965 4.60968C17.8677 4.60968 17.6821 4.79521 17.6821 5.02408C17.6821 5.25294 17.8677 5.43847 18.0965 5.43847Z" fill="#0A61B5"/>
<path d="M16.0277 5.12326C16.2635 5.12326 16.4547 4.93205 16.4547 4.69618C16.4547 4.46031 16.2635 4.2691 16.0277 4.2691C15.7918 4.2691 15.6006 4.46031 15.6006 4.69618C15.6006 4.93205 15.7918 5.12326 16.0277 5.12326Z" fill="#055AAD"/>
<path d="M13.9881 5.23854C14.231 5.23854 14.4279 5.04165 14.4279 4.79877C14.4279 4.5559 14.231 4.35901 13.9881 4.35901C13.7452 4.35901 13.5483 4.5559 13.5483 4.79877C13.5483 5.04165 13.7452 5.23854 13.9881 5.23854Z" fill="#0054A6"/>
<path d="M22.8459 19.9685C22.9673 19.9685 23.0657 19.8701 23.0657 19.7486C23.0657 19.6272 22.9673 19.5287 22.8459 19.5287C22.7244 19.5287 22.626 19.6272 22.626 19.7486C22.626 19.8701 22.7244 19.9685 22.8459 19.9685Z" fill="#3B9EFF"/>
<path d="M23.5288 18.6175C23.6561 18.6175 23.7592 18.5143 23.7592 18.387C23.7592 18.2597 23.6561 18.1566 23.5288 18.1566C23.4015 18.1566 23.2983 18.2597 23.2983 18.387C23.2983 18.5143 23.4015 18.6175 23.5288 18.6175Z" fill="#3699F9"/>
<path d="M23.973 17.1355C24.1061 17.1355 24.214 17.0276 24.214 16.8945C24.214 16.7614 24.1061 16.6534 23.973 16.6534C23.8398 16.6534 23.7319 16.7614 23.7319 16.8945C23.7319 17.0276 23.8398 17.1355 23.973 17.1355Z" fill="#3294F2"/>
<path d="M24.1524 15.5456C24.2908 15.5456 24.4029 15.4334 24.4029 15.295C24.4029 15.1567 24.2908 15.0445 24.1524 15.0445C24.014 15.0445 23.9019 15.1567 23.9019 15.295C23.9019 15.4334 24.014 15.5456 24.1524 15.5456Z" fill="#2E8EEC"/>
<path d="M24.0428 13.9788C24.187 13.9788 24.3039 13.8619 24.3039 13.7177C24.3039 13.5735 24.187 13.4566 24.0428 13.4566C23.8986 13.4566 23.7817 13.5735 23.7817 13.7177C23.7817 13.8619 23.8986 13.9788 24.0428 13.9788Z" fill="#2A89E6"/>
<path d="M23.6667 12.4915C23.8167 12.4915 23.9384 12.3699 23.9384 12.2199C23.9384 12.0698 23.8167 11.9482 23.6667 11.9482C23.5167 11.9482 23.395 12.0698 23.395 12.2199C23.395 12.3699 23.5167 12.4915 23.6667 12.4915Z" fill="#2684DF"/>
<path d="M23.0415 11.1097C23.1974 11.1097 23.3238 10.9834 23.3238 10.8275C23.3238 10.6716 23.1974 10.5452 23.0415 10.5452C22.8856 10.5452 22.7593 10.6716 22.7593 10.8275C22.7593 10.9834 22.8856 11.1097 23.0415 11.1097Z" fill="#227FD9"/>
<path d="M22.1937 9.86232C22.3554 9.86232 22.4865 9.73122 22.4865 9.5695C22.4865 9.40777 22.3554 9.27667 22.1937 9.27667C22.032 9.27667 21.9009 9.40777 21.9009 9.5695C21.9009 9.73122 22.032 9.86232 22.1937 9.86232Z" fill="#1D79D3"/>
<path d="M21.1408 8.77989C21.3083 8.77989 21.4442 8.64405 21.4442 8.47649C21.4442 8.30893 21.3083 8.1731 21.1408 8.1731C20.9732 8.1731 20.8374 8.30893 20.8374 8.47649C20.8374 8.64405 20.9732 8.77989 21.1408 8.77989Z" fill="#1974CC"/>
<path d="M19.9106 7.89081C20.084 7.89081 20.2246 7.75025 20.2246 7.57685C20.2246 7.40345 20.084 7.26288 19.9106 7.26288C19.7372 7.26288 19.5967 7.40345 19.5967 7.57685C19.5967 7.75025 19.7372 7.89081 19.9106 7.89081Z" fill="#156FC6"/>
<path d="M18.5223 7.22275C18.7015 7.22275 18.8468 7.07745 18.8468 6.89821C18.8468 6.71897 18.7015 6.57367 18.5223 6.57367C18.3431 6.57367 18.1978 6.71897 18.1978 6.89821C18.1978 7.07745 18.3431 7.22275 18.5223 7.22275Z" fill="#1169BF"/>
<path d="M16.9977 6.80407C17.1828 6.80407 17.3328 6.65404 17.3328 6.46896C17.3328 6.28388 17.1828 6.13385 16.9977 6.13385C16.8126 6.13385 16.6626 6.28388 16.6626 6.46896C16.6626 6.65404 16.8126 6.80407 16.9977 6.80407Z" fill="#0D64B9"/>
<path d="M15.4028 6.66554C15.5937 6.66554 15.7485 6.51077 15.7485 6.31986C15.7485 6.12895 15.5937 5.97418 15.4028 5.97418C15.2119 5.97418 15.0571 6.12895 15.0571 6.31986C15.0571 6.51077 15.2119 6.66554 15.4028 6.66554Z" fill="#085FB3"/>
<path d="M13.8566 6.81055C14.0528 6.81055 14.2118 6.65152 14.2118 6.45535C14.2118 6.25918 14.0528 6.10016 13.8566 6.10016C13.6605 6.10016 13.5015 6.25918 13.5015 6.45535C13.5015 6.65152 13.6605 6.81055 13.8566 6.81055Z" fill="#045AAC"/>
<path d="M12.3892 7.21859C12.5912 7.21859 12.7549 7.05483 12.7549 6.85283C12.7549 6.65082 12.5912 6.48706 12.3892 6.48706C12.1872 6.48706 12.0234 6.65082 12.0234 6.85283C12.0234 7.05483 12.1872 7.21859 12.3892 7.21859Z" fill="#0054A6"/>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,14 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<line x1="2.75" y1="22.5" x2="2.75" y2="6" stroke="black" stroke-width="0.5"/>
<path d="M2.5 22.5L27.505 22.5007" stroke="black" stroke-width="0.5"/>
<path d="M3.5234 21.4543C16.625 21.4543 -0.900434 6.85712 26.4628 7.01826" stroke="#BE202E" stroke-width="0.5"/>
<path d="M3.2959 21.4177C16.3975 21.4177 14.6631 9.55249 26.4697 9.55249" stroke="#3B9EFF" stroke-width="0.5"/>
<path d="M3.41309 21.2957C17.2564 22.1692 19.9072 11.9792 26.5723 12.7556" stroke="#69121A" stroke-width="0.5"/>
<rect x="3.7793" y="7.08667" width="6.94336" height="0.292969" stroke="black" stroke-width="0.292969"/>
<circle cx="7.79297" cy="7.23315" r="0.380859" fill="#1D79D3"/>
<rect x="3.7793" y="9.37183" width="6.94336" height="0.292969" stroke="black" stroke-width="0.292969"/>
<circle cx="6.32812" cy="9.51831" r="0.380859" fill="#1D79D3"/>
<rect x="3.7793" y="8.22925" width="6.94336" height="0.292969" stroke="black" stroke-width="0.292969"/>
<circle cx="9.55078" cy="8.37573" r="0.380859" fill="#1D79D3"/>
<path d="M3.39844 15H26.5723" stroke="black" stroke-width="0.5" stroke-dasharray="1 1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -1,36 +1,38 @@
{% extends "page.html.j2" %}
{% extends "layout.html.j2" %}
{% block contents %}
{% block main %}
<h1>Airborne Transmission of SARS-CoV-2</h1><br>
<div class="container container--padding" style="word-wrap:break-word";>
<h1 class="paragraph-title">Airborne Transmission of SARS-CoV-2</h1><br>
Currently, the existing public health measures point to the importance of proper building and environmental engineering control measures, such as proper Indoor Air Quality (IAQ).
This pandemic clearly raised increased awareness on airborne transmission of respiratory viruses in indoor settings.
Out of the main modes of viral transmission, the airborne route of SARS-CoV-2 seems to have a significant importance to the spread of COVID-19 infections world-wide, hence proper guidance to building engineers or facility managers, on how to prevent on-site transmission, is essential.<br>
For information on the Airborne Transmission of SARS-CoV-2, feel free to check out the HSE Seminar: <a href=https://cds.cern.ch/record/2743403>https://cds.cern.ch/record/2743403</a>.<br>
Slides available in <a href=https://indico.cern.ch/event/968258>https://indico.cern.ch/event/968258/</a>.
<h1>What is CARA?</h1><br>
<br><br>
<h1 class="paragraph-title">What is CARA?</h1><br>
CARA stands for COVID Airborne Risk Assessment and was developed in the spring of 2020 to better understand and quantify the risk of long-range airborne spread of SARS-CoV-2 virus in workplaces. CARA comes with different applications that allow more or less flexibility in the input parameters:
<ul>
<li><a href='{{ calculator_prefix }}'>CARA calculator app</a></li>
<li><a href='/expert-app'>CARA expert app</a></li>
</ul>
The mathematical and physical model simulate the long-range airborne spread of SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 infection therein. The results DO NOT include short-range airborne exposure (where the physical distance plays a factor) nor the other known modes of SARS-CoV-2 transmission. Hence, the output from this model is only valid when the other recommended public health & safety instructions are observed, such as adequate physical distancing, good hand hygiene and other barrier measures.<br>
<p>The methodology, mathematical equations and parameters of the model are described here in the CERN Report: <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a>.</p>
The mathematical and physical model simulate the long-range airborne spread of SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture, and estimates the risk of COVID-19 airborne transmission therein. The results DO NOT include short-range airborne exposure (where the physical distance plays a factor) nor the other known modes of SARS-CoV-2 transmission. Hence, the output from this model is only valid when the other recommended public health & safety instructions are observed, such as adequate physical distancing, good hand hygiene and other barrier measures.<br>
<p>The methodology, mathematical equations and parameters of the model are described here in the CARA paper: <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a>.</p>
The model used is based on scientific publications relating to airborne transmission of infectious diseases, virology, epidemiology and aerosol science. It can be used to compare the effectiveness of different airborne-related risk mitigation measures.
The tool helps assess the potential dose of infectious airborne viruses in indoor gatherings, with people seated, standing, moving around, while breathing, speaking or shouting/singing. The model is based on the Wells-Riley model of aerosol disease transmission, which assumes a fixed value for the average infectious dose. The dose-response models for respiratory diseases is more accurate, although since this parameter for SARS-CoV-2 is not known so far, the Wells-Riley method is recommended in the health science community (see <a href="#references_block">References</a>).
The methodology of the model is divided into three parts:
The tool helps assess the potential dose of infectious airborne viruses in indoor gatherings, with people seated, standing, moving around, while breathing, speaking or shouting/singing. The model is based on the exponential dose-response of disease transmission, which assumes a fixed value for the average infectious dose.
The methodology of the model is divided into five parts:
<ol>
<li>Estimating the emission rate of virions.</li>
<li>Modeling the concentration evolution of viruses within a given volume and consequent inhalation dose during the exposure time.</li>
<li>Estimating the probability of a COVID-19 infection, the expected number of new cases arising from the transmission event and the basic reproduction rate (R0).</li>
<li>Estimating the emission rate of virions;</li>
<li>Estimating the removal rate of virions;</li>
<li>Modeling the concentration of virions within a given volume, as a function of time;</li>
<li>Absorbed dose of infectious viruses, inhaled during the exposure time;</li>
<li>Estimating the probability of a COVID-19 infection (or secondary transmission) and the expected number of new cases arising from the event </li>
</ol>
Parts #1 and #3 are mainly based on methods published in scientific papers (see <a href="#references_block">References</a>), and cover the medical aspects, which is not the core competencies of the authors. The heart and soul of CARA lies within the Part #2 and the concentration modelling, which is based on a mass-balance differential equation solved for a constant emission rate and time-dependent exchange rate (e.g. natural ventilation flow rate). Other aspects, e.g., the biological decay of the virus in the air, gravitational settlement of the aerosols, mechanical supply of fresh air, effect of HEPA filtration, among others, are also included.<br>
<h1>What is the aim of CARA?</h1><br>
<br>
<h1 class="paragraph-title">What is the aim of CARA?</h1><br>
Although the user is able to calculate the infection probability of a stand-alone event with a pre-defined set of protection measures, the main utility of CARA is to compare the relative impact of different measures and/or combination of measure. For example:
<ul>
<li>Compare keeping a window slightly open vs one or two windows open entirely</li>
@ -39,17 +41,21 @@ Although the user is able to calculate the infection probability of a stand-alon
<li>Adapt the maximum occupancy considering the effect of HEPA filters</li>
<li>Etc…</li>
</ul>
<h1>Authors:</h1><br>
{{ text_blocks['Authors'] }}
<h1>Acknowledgements:</h1><br>
<h1 class="paragraph-title">Main Developers:</h1><br>
{{ text_blocks['Main Developers'] }}
<br>
<h2 class="paragraph-title">Code Contributors:</h2><br>
{{ text_blocks['Code Contributors'] }}
<br>
<h1 class="paragraph-title">Acknowledgements:</h1><br>
{{ text_blocks['Acknowledgements'] }}
<a id="references_block" style="color:#2f4858"><h1>References:</h1></a><br>
<br>
<a id="references_block" style="color:#2f4858"><h1 class="paragraph-title">References:</h1></a><br>
{{ text_blocks['References'] }}
<div class="text-component text-component-page clearfix"></div>
<br>
</div>
{% endblock contents %}
</div>
{% endblock main %}

View file

@ -1,6 +1,6 @@
## Authors
## Main Developers
<h4>Andre Henriques<sup>1</sup>, Marco Andreini<sup>1</sup>, Gabriella Azzopardi<sup>2</sup>, James Devine<sup>3</sup>, Philip Elson<sup>4</sup>, Nicolas Mounet<sup>2</sup>, Markus Kongstein Rognlien<sup>2,6</sup>, Nicola Tarocco<sup>5</sup></h4><br>
<h4 class="contributors">Andre Henriques<sup>1</sup>, Luis Aleixo<sup>1</sup>, Marco Andreini<sup>1</sup>, Gabriella Azzopardi<sup>2</sup>, James Devine<sup>3</sup>, Philip Elson<sup>4</sup>, Nicolas Mounet<sup>2</sup>, Markus Kongstein Rognlien<sup>2,6</sup>, Nicola Tarocco<sup>5</sup></h4><br>
<sup>1</sup>HSE Unit, Occupational Health & Safety Group, CERN<br>
<sup>2</sup>Beams Department, Accelerators and Beam Physics Group, CERN<br>
@ -9,68 +9,19 @@
<sup>5</sup>Information Technology Department, Collaboration, Devices & Applications Group, CERN<br>
<sup>6</sup>Norwegian University of Science and Technology (NTNU)<br>
## Code Contributors
<h4 class="contributors">Anna Efimova<sup>1,2</sup>, Anel Massalimova<sup>1,3</sup>, Cole Austin Coughlin<sup>1,4</sup></h4>
<sup>1</sup>Summer Students, CERN<br>
<sup>2</sup>M.V. Lomonosov Moscow State University<br>
<sup>3</sup>National Research Nuclear University "MEPhI"<br>
<sup>4</sup>University of Manitoba<br>
## Acknowledgements
We wish to thank CERNs HSE Unit, Beams Department, Experimental Physics Department, Information Technology Department, Industry, Procurement and Knowledge Transfer Department and International Relations Sector for their support to the study. Thanks to Doris Forkel-Wirth, Benoit Delille, Walid Fadel, Olga Beltramello, Letizia Di Giulio, Evelyne Dho, Wayne Salter, Benoit Salvant and colleagues from the COVID working group for providing expert advice and extensively testing the model. Finally, we wish to thank Fabienne Landua and the design service for preparing the illustrations and Alessandro Raimondo, Ana Padua and Manuela Cirilli from the Knowledge Transfer Group for their continuous support. Our compliments towards the work and research performed by world leading scientists in this domain: Prof. Manuel Gameiro, Prof. Shelly Miller, Prof. Linsey Marr, Prof. Jose Jimenez, Dr. Lidia Morawska, Prof Yuguo Li et al. their scientific contribution was indispensable for this project.
We wish to thank CERNs HSE Unit, Beams Department, Experimental Physics Department, Information Technology Department, Industry, Procurement and Knowledge Transfer Department and International Relations Sector for their support to the study. Thanks to Doris Forkel-Wirth, Benoit Delille, Walid Fadel, Olga Beltramello, Letizia Di Giulio, Evelyne Dho, Wayne Salter, Benoit Salvant and colleagues from the COVID working group for providing expert advice and extensively testing the model. Finally, we wish to thank Fabienne Landua and the design service for preparing the illustrations and Alessandro Raimondo, Ana Padua and Manuela Cirilli from the Knowledge Transfer Group for their continuous support. Our compliments towards the work and research performed by world leading scientists in this domain: Dr. Julian Tang, Prof. Manuel Gameiro, Dr. Linsey Marr, Prof. Jose Jimenez, Prof. Lidia Morawska, Prof. Yuguo Li et al. their scientific contribution was indispensable for this project.
## References
[1] Jimenez, J. (2020), COVID-19 Data Dives: Why Arguments Against SARS-CoV-2 Aerosol Transmission Don't Hold Water https://www.medscape.com/viewarticle/934837?src=uc_mscpedt&faf=1.<br>
[2] Jimenez, J. (2020), Summary of the Evidence For and Against the Routes of Transmission of SARS-CoV-2. https://tinyurl.com/aerosol-pros-cons.<br>
[3] Miller SL, Nazaroff WW, Jimenez JL, et al. Transmission of SARS-CoV-2 by inhalation of respiratory aerosol in the Skagit Valley Chorale superspreading event. Indoor Air. 2020;00:110. https://doi.org/10.1111/ina.12751.<br>
[4] Gameiro da Silva, Manuel. (2020). An analysis of the transmission modes of COVID-19 in light of the concepts of Indoor Air Quality. 10.13140/RG.2.2.28663.78240.<br>
[5] Stephanie Taylor, (2019). Optimize Occupant Health, Building Energy Performance and Your Revenue Through Indoor-Air Hydration.<br>
[6] REHVA COVID-19 guidance document, April 3, 2020.<br>
[7] Morawska, L, Milton, D. It Is Time to Address Airborne Transmission of Coronavirus Disease 2019 (COVID-19), Clinical Infectious Diseases, , ciaa939, https://doi.org/10.1093/cid/ciaa939.<br>
[8] Wei, Jianjian & Li, Yuguo. (2015). Enhanced spread of expiratory droplets by turbulence in a cough jet. Building and Environment. 93. 10.1016/j.buildenv.2015.06.018.<br>
[9] Doremalen N et al. (2020). Aerosol and surface stability of HCoV-19 (SARS-CoV-6 2) compared to SARS-CoV-1. doi:10.1101/2020.03.09.20033217.<br>
[10] Bourouiba L., Turbulent Gas Clouds and Respiratory Pathogen Emissions: Potential Implications for Reducing Transmission of COVID-19. JAMA. Published online March 26, 2020. doi:10.1001/jama.2020.4756.<br>
[11] Fauci A. 2020. Transmission of SARS-CoV-2, Citizen by CNN.<br>
[12] Chen W. 9, Zhang N., et al. (2020) Short-range airborne route dominates exposure of respiratory infection during close contact. Building and Environment, Volume 176, 10.1016/j.buildenv.2020.10685.<br>
[13] Office of the Prime Minister and the Ministry of Health, Labor and Welfare of Japan, 2020.<br>
[14] World Health Organization holds news conference on coronavirus outbreak 2/11/2020, min 41:40 - https://youtu.be/edvsh6x_f4Q.<br>
[15] WHO (2020). Transmission of SARS-CoV-2: implications for infection prevention precautions. WHO/2019-nCoV/Sci_Brief/Transmission_modes/2020.3.<br>
[16] Chapin, C. (1912). The sources and modes of infection. The Library of Congress urn:oclc:record:1085180298.<br>
[17] CERN Instruction on COVID-19 Health and Safety Measures, EDMS N. 2370903.<br>
[18] CERN instructions on COVID-19 related health and safety measures Appendix A on HVAC, EDMS N. 2389839.<br>
[19] CDC, Scientific Brief: SARS-CoV-2 and Potential Airborne Transmission. https://www.cdc.gov/coronavirus/2019-ncov/more/scientific-brief-sars-cov-2.html.<br>
[20] Li, Yuguo et al. (2020). Evidence for probable aerosol transmission of SARS-CoV-2 in a poorly ventilated restaurant. 10.1101/2020.04.16.20067728.<br>
[21] Lu J, Gu J, Li K, et al. COVID-19 outbreak associated with air conditioning in restaurant, Guangzhou, China, 2020. Emerg Infect Dis. CDC - Volume 26, Number 7, 10.3201/eid2607.200764.<br>
[22] Shen Y, Li C, Dong H, et al. Community Outbreak Investigation of SARS-CoV-2 Transmission Among Bus Riders in Eastern China. JAMA Intern Med. Published online September 01, 2020. doi:10.1001/jamainternmed.2020.5225.<br>
[23] Park S, Kim Y, Yi S, et al. Coronavirus Disease Outbreak in Call Center, South Korea. Emerging Infectious Diseases. 2020;26(8):1666-1670. doi:10.3201/eid2608.201274.<br>
[24] Liu, Y., Ning, Z., Chen, Y. et al. Aerodynamic analysis of SARS-CoV-2 in two Wuhan hospitals. Nature (2020). 10.1038/s41586-020-2271-3.<br>
25] Twitter @EmmanuelMacron https://twitter.com/EmmanuelMacron/status/1316485827715829762?s=20.<br>
[26] Gao, X., Li, Y. and Leung, G.M., 2009. Ventilation control of indoor transmission of airborne diseases in an urban community. Indoor and Built Environment , 18(3), pp.205 -218.<br>
[27] Zhu S, Jenkins S, Addo K, et al. Ventilation and laboratory confirmed acute respiratory infection (ARI) rates in college residence halls in College Park, Maryland. Environment International. 2020;137:105537. doi:10.1016/j.envint.2020.105537.<br>
[28] Perry J.L., et al. Submicron and Nanoparticulate Matter Removal by HEPA-Rated Media Filters and Packed Beds of Granular Materials. NASA/TM—2016218224.<br>
[29] Julian W. Tang, et al. (2009) A schlieren optical study of the human cough with and without wearing masks for aerosol infection control J . R. Soc. Interface.6S727S736. 10.1098/rsif.2009.0295.focus.<br>
[30] Buonanno, G., et al. (2020) “Estimation of airborne viral emission: Quanta emission rate of SARS-CoV-2 for infetion risk assessment”, https://doi.org/10.1016/j.envint.2020.105794.<br>
[31] Buonanno, G., et al. (2020) “Quantitative assessment of the risk of airborne transmission of SARS-CoV-2 infection: Prospective and retrospective applications ”, https://doi.org/10.1016/j.envint.2020.106112.<br>
[32] Gammaitoni, L. et al. (1997) “Using a mathematical model to evaluate the efficacy of TB control measures.”, Emerg. Infect. Dis. (1997), pp. 335-342, https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2627642.<br>
[33] Huang, J.T., et al. (2007) “Evaluation of the Efficiency of Medical Masks and the Creation of New Medical Masks.”, J. Int. Medical Research, 35: 213 223, https://doi.org/10.1177/147323000703500205.<br>
[34] Morawska, L. et al. (2009), “Size distribution and sites of origin of droplets expelled from the human respiratory tract during expiratory activities”, J. Aerosol Science, 256-269, https://doi.org/10.1016/j.jaerosci.2008.11.002.<br>
[35] Riley, E.C., et al. (1978), “Airborne spread of measles in a suburban elementary school.”, Am. J. Epidemiol. 107, 421432, https://doi.org/10.1093/oxfordjournals.aje.a112560.<br>
[36] Sze To, G.N., Chao, C.Y.H. (2010). “Review and comparison between the Wells-Riley and dose-response approaches to risk assessment of infectious respiratory diseases.” Indoor Air 20, 216. https://doi.org/10.1111/j.1600-0668.2009.00621.x.<br>
[37] Wells, W.F., (1934). “On airborne infection: study II. Droplets and Droplet nuclei.” Am. J. Epidemiol. 20, 611618. https://doi.org/10.1093/oxfordjournals.aje.a118097.<br>
[38] Wells, W.F. (1955). “Airborne contagion and air hygiene. Cambridge, MA: Harvard University Press”, https://doi.org/10.1111/j.1746-1561.1955.tb08015.x.<br>
[39] EL PAIS, An analysis of three Covid-19 outbreaks: how they happened and how they can be avoided. https://english.elpais.com/spanish_news/2020-06-17/an-analysis-of-three-covid-19-outbreaks-how-they-happened-and-how-they-can-be-avoided.html?ssm=TW_CC.<br>
[40] WHO. Avoid the three Cs Be aware of different levels of risk in different settings. https://www.who.int/images/default-source/wpro/countries/malaysia/infographics/three-3cs/final-avoid-the-3-cs-poster.tmb-1920v.jpg?sfvrsn=638335c1_1.<br>
[41] Miller, S. Germicidal Ultraviolet Light (Radiation) for Reducing Disease Transmission. https://shellym80304.files.wordpress.com/2020/05/isiaq-guv-2-compiled.pdf
[42] CDC. How COVID-19 Spreads. https://www.cdc.gov/coronavirus/2019-ncov/prevent-getting-sick/how-covid-spreads.html.<br>
[43] Thomas, Y. et al. (2014). Survival of influenza virus on human fingers. Clin Microbiol Infect ;20: O58O64 10.1111/1469-0691.12312.<br>
[44] Tang, J. (2020). The Guardian, Understanding 'aerosol transmission' could be key to controlling coronavirus. https://www.theguardian.com/commentisfree/2020/oct/28/understanding-aerosol-transmission-key-controlling-coronavirus-wash-hands.<br>
[45] Johnson, G.R. et al. Modality of human expired aerosol size distributions. Journal of Aerosol Science 42 (2011) 839851840, doi:10.1016/j.jaerosci.2011.07.009.<br>
[46] Li, Yuguo (2020). SARS-CoV-2 airborne transmission is opportunistic and ventilation works. University of Hong Kong. COVID-19 zoom conference. https://www.hku.hk/f/upload/21292/HKU%20Covid-19%20Zoom%20conference.pdf.<br>
[47] Marr, L. (2020). Aerosol and Transmission of Respiratory Viruses 101, Airborne Transmission of SARS-CoV-2: A Virtual Workshop. https://www.nationalacademies.org/event/08-26-2020/airborne-transmission-of-sars-cov-2-a-virtual-workshop?s=09 .<br>
[48] Morawska, L. (2006). Droplet fate in indoor environments, or can we prevent the spread of infection?. Indoor Air, Volume: 16, Issue: 5, Pages: 335-347, doi:10.1111/j.1600-0668.2006.00432.x.<br>
[49] Marr, L.C., Tang, J.W., Van Mullekom, J., et al., 2019, Mechanistic insights into the effect of humidity on airborne influenza virus survival, transmission and incidence, J Roy Soc Interface. https://doi.org/10.1098/rsif.2018.0298.<br>
[50] Roy C, Milton D, Airborne Transmission of Communicable Infection — The Elusive Pathway, N Engl J Med 2004; 350:1710-1712, doi: 10.1056/NEJMp04805.<br>
[51] Hui, K. P. Y. et al. (2020), Tropism, replication competence, and innate immune responses of the coronavirus SARS-CoV-2 in human respiratory tract and conjunctiva: an analysis in ex-vivo and in-vitro cultures, Lancet Respir Med, Volume 8, Issue 7, Pages 687-695, doi:10.1016/S2213-2600(20)30193-4.<br>
[52] Morawska, Lidia & Cao, Junji. (2020). Airborne transmission of SARS-CoV-2: The world should face the reality. Environment International. 139. 105730. 10.1016/j.envint.2020.105730.<br>
[53] Milton D.,, A Rosetta Stone for Understanding Infectious Drops and Aerosols, Journal of the Pediatric Infectious Diseases Society, Volume 9, Issue 4, 1 September 2020, Pages 413415, https://doi.org/10.1093/jpids/piaa079.<br>
[54] Leung, N.H.L et al. Respiratory virus shedding in exhaled breath and efficacy of face masks. Nat Med (2020). 10.1038/s41591-020-0843-2.<br>
[55] Asadi, S., Cappa, C.D., Barreda, S. et al. Efficacy of masks and face coverings in controlling outward aerosol particle emission from expiratory activities. Sci Rep 10, 15665 (2020). https://doi.org/10.1038/s41598-020-72798-7.<br>
[56] Endo A, Abbott S et al. Estimating the overdispersion in COVID-19 transmission using outbreak sizes outside China [version 3; peer review: 2 approved]. Wellcome Open Res 2020, 5:67. doi:10.12688/wellcomeopenres.15842.3.<br>
[57] Jin Pan, Charbel Harb, Weinan Leng & Linsey C. Marr (2021) Inward and outward effectiveness of cloth masks, a surgical mask, and a face shield, Aerosol Science and Technology, 55:6, 718-733, doi: 10.1080/02786826.2021.1890687.<br>
[58] C. Makison Booth, M. Clayton, B. Crook, J.M. Gawn, Effectiveness of surgical masks against influenza bioaerosols, Journal of Hospital Infection, Volume 84, Issue 1, 2013, Pages 22-26, https://doi.org/10.1016/j.jhin.2013.02.007.<br>
[59] Riediker, M., Monn, C. (2021). Simulation of SARS-CoV-2 Aerosol Emissions in the Infected Population and Resulting Airborne Exposures in Different Indoor Scenarios. Aerosol Air Qual. Res. 21, 200531. https://doi.org/10.4209/aaqr.2020.08.0531.<br>
Reference list can be found in the CARA paper: <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a>

View file

@ -1,81 +1,69 @@
{% extends "layout.html.j2" %}
{% set active_page="home/" %}
{% block main %}
<div style="height: 8em; display: block;"></div>
<div class="field--item">
<div class="component-row component-row__display__fluidcenter section-navigation effect_none">
<div class="component-row__row">
<div class="component-row__column component-row__center section-has-no-column col-md-12 col-sm-12 col-xs-12">
<div class="box-effects-wrapper ">
<div class="text-component text-component-page clearfix" style="position:relative; " >
<img src="/static/images/cara_logo.200x200.png" style="height:10em; display:inline-block; vertical-align:middle; padding: 1em;">
<h2 class="text-component-title" style="display:inline-block; vertical-align:middle; align:center;">
CARA: COVID Airborne Risk Assessment Tools
</h2>
<h2>Introduction</h2><br>
<div class="text-component-text cern_full_html" >
<p>
CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
It does this by simulating the long-range airborne spread SARS-CoV-2 virus in a finite volume, assuming homogenous mixing, and it estimates the risk of COVID-19 infection therein.
Please see the <a href="/about">About</a> page for more details on the methodology, assumptions and limitations of CARA.
</p>
<p>
The full CARA source code can be accessed freely under an Apache 2.0 open source license from our <a href="https://gitlab.cern.ch/cara/cara">code repository</a>.
It includes detailed instructions on how to run your own version of this tool.
</p>
</div>
<br>
<h2>CARA@CERN</h2><br>
<div class="text-component-text cern_full_html" >
<p>
CARA has been developed by CERN with the intention of allowing members of personnel with roles related to supervision, health & safety or space management to simulate the concerned workplaces on CERN sites.
A hosted <a href="{{ calculator_prefix }}">CERN version of the CARA Covid Calculator</a> is available on this site to members of the CERN personnel.
</p>
</div>
<br>
<h2>Authors</h2>
<div class="text-component-text cern_full_html" >
<p>
<h4>Andre Henriques<sup>1</sup>, Luis Aleixo<sup>1</sup>, Marco Andreini<sup>1</sup>, Gabriella Azzopardi<sup>2</sup>, James Devine<sup>3</sup>, Philip Elson<sup>4</sup>, Nicolas Mounet<sup>2</sup>, Markus Kongstein Rognlien<sup>2,6</sup>, Nicola Tarocco<sup>5</sup></h4><br>
<sup>1</sup>HSE Unit, Occupational Health & Safety Group, CERN<br>
<sup>2</sup>Beams Department, Accelerators and Beam Physics Group, CERN<br>
<sup>3</sup>Experimental Physics Department, Safety Office, CERN<br>
<sup>4</sup>Beams Department, Controls Group, CERN<br>
<sup>5</sup>Information Technology Department, Collaboration, Devices & Applications Group, CERN<br>
<sup>6</sup>Norwegian University of Science and Technology (NTNU)<br>
</p>
<br>
<h3>Acknowledgements:</h3>
<p>
We wish to thank CERNs HSE Unit, Beams Department, Experimental Physics Department, Information Technology Department, Industry, Procurement and Knowledge Transfer Department and International Relations Sector for their support to the study.
Thanks to Doris Forkel-Wirth, Benoit Delille, Walid Fadel, Olga Beltramello, Letizia Di Giulio, Evelyne Dho, Wayne Salter, Benoit Salvant and colleagues from the COVID working group for providing expert advice and extensively testing the model.
Finally, we wish to thank Fabienne Landua and the design service for preparing the illustrations and Alessandro Raimondo, Ana Padua and Manuela Cirilli from the Knowledge Transfer Group for their continuous support.
Our compliments towards the work and research performed by world leading scientists in this domain: Prof. Manuel Gameiro, Prof. Shelly Miller, Prof. Linsey Marr, Prof. Jose Jimenez, Dr. Lidia Morawska, Prof Yuguo Li et al. their scientific contribution was indispensable for this project.
<span style="height: 3vh; display: block;"></span>
</p>
</div>
</div>
</div>
</div>
</div>
{% block main %}
{# <div style="height: 5em; display: block;"></div> #}
<header class= "bg-light">
<div class="container container--padding">
<img src="/static/images/cara_full_text.png" class="logo d-block m-auto" id="desktop_logo">
<img src="/static/images/cara_full_logo.png" class="logo d-none m-auto" id="mobile_logo">
</div>
</header>
<div class="container container--padding">
<div class="d-flex flex-row mb-3 justify-content-around" id="mobile-app-buttons">
<div><a href="{{ calculator_prefix }}" role="button" class="btn btn-outline-primary"><div class="d-flex d-row"><i class="icon-calculator"></i><span class="pl-1">Calculator</div></a></div>
<div><a href="https://cara.web.cern.ch/expert-app" role="button" class="btn btn-outline-secondary"><div class="d-flex d-row"><i class="icon-expert"></i><span class="pl-1">Expert (beta)</div></a></div>
</div>
<div class="split">
<div class="col-sm-8 pl-0">
<h2 class="paragraph-title">Introduction</h2><br>
<div>
<p>
CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
It does this by simulating the long-range airborne spread SARS-CoV-2 virus in a finite volume, assuming homogenous mixing, and it estimates the risk of COVID-19 airborne transmission therein.
Please see the <a href="/about">About</a> page for more details on the methodology, assumptions and limitations of CARA.
</p>
<p>
The full CARA source code can be accessed freely under an Apache 2.0 open source license from our <a href="https://gitlab.cern.ch/cara/cara">code repository</a>.
It includes detailed instructions on how to run your own version of this tool.
</p>
<br>
</div>
</div>
<a class="endof-cern-header-blocks"></a>
<div class="align-self-center">
<img src="static/images/CARA_1_Vs3_Colour.jpg" class="cara_home_image">
</div>
{% endblock main %}
</div>
<br>
<div id="apps_section" class="d-none">
<div class="d-flex flex-row" >
<h2 class="paragraph-title pr-4 align-self-center">Apps:</h2>
<br>
<div class="pr-3"><a href="{{ calculator_prefix }}" role="button" class="btn btn-lg btn-outline-primary"><div class="d-flex d-row"><i class="icon-calculator"></i><span class="pl-2">Calculator</div></a></div>
<br>
<div><a href="https://cara.web.cern.ch/expert-app" role="button" class="btn btn-lg btn-outline-secondary"><div class="d-flex d-row"><i class="icon-expert"></i><span class="pl-2">Expert (beta)</div></a></div>
</div>
<hr width="95%">
</div>
<h2 class="paragraph-title">CARA @ CERN</h2><br>
<div>
<p>
CARA has been developed by CERN with the intention of allowing members of personnel with roles related to supervision, health & safety or space management to simulate the concerned workplaces on CERN sites.
A hosted <a href="{{ calculator_prefix }}">CERN version of the CARA Covid Calculator</a> is available on this site to members of the CERN personnel.
</p>
</div>
<br>
<h3 class="paragraph-title">Acknowledgements</h3><br>
<p>
We wish to thank CERNs HSE Unit, Beams Department, Experimental Physics Department, Information Technology Department, Industry, Procurement and Knowledge Transfer Department and International Relations Sector for their support to the study.
Thanks to Doris Forkel-Wirth, Benoit Delille, Walid Fadel, Olga Beltramello, Letizia Di Giulio, Evelyne Dho, Wayne Salter, Benoit Salvant and colleagues from the COVID working group for providing expert advice and extensively testing the model.
Finally, we wish to thank Fabienne Landua and the design service for preparing the illustrations and Alessandro Raimondo, Ana Padua and Manuela Cirilli from the Knowledge Transfer Group for their continuous support.
Our compliments towards the work and research performed by world leading scientists in this domain: Dr. Julian Tang, Prof. Manuel Gameiro, Dr. Linsey Marr, Prof. Jose Jimenez, Prof. Lidia Morawska, Prof. Yuguo Li et al. - their scientific contribution was indispensable for this project.
<span style="height: 3vh; display: block;"></span>
</p>
</div>
</div>
{% endblock main %}

View file

@ -1,301 +1,97 @@
<!DOCTYPE html>
<html lang="en" dir="ltr"
prefix="content: http://purl.org/rss/1.0/modules/content/ dc: http://purl.org/dc/terms/ foaf: http://xmlns.com/foaf/0.1/ og: http://ogp.me/ns# rdfs: http://www.w3.org/2000/01/rdf-schema# schema: http://schema.org/ sioc: http://rdfs.org/sioc/ns# sioct: http://rdfs.org/sioc/types# skos: http://www.w3.org/2004/02/skos/core# xsd: http://www.w3.org/2001/XMLSchema# "
class=" js">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="MobileOptimized" content="width">
<meta name="HandheldFriendly" content="true">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>
{% block title %}
CARA | COVID Airborne Risk Assessment
{% endblock title %}
</title>
<link rel="stylesheet" media="all" href="/static/css/cern-theme.css">
<link rel="stylesheet" media="all" href="/static/css/cern-theme2.css">
<link rel="stylesheet" media="all" href="/static/css/cern-theme3.css">
<link rel="stylesheet" media="all" href="/static/css/colorbox.css">
<link rel="stylesheet" media="all" href="/static/css/colors.css">
<link rel="stylesheet" media="all" href="/static/css/cern-theme4.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="/static/css/style.css">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600,700&display=swap" rel="stylesheet">
{% block extra_headers %}
{% endblock extra_headers %}
</head>
<body
class="cern-theme-on path-frontpage page-node-type-landing-page has-glyphicons no-admin-toolbar dev-status-ui cern-toolbar has-header toolbar-fixed">
<a href="https://againstcovid19.cern/welcome#main-content" class="visually-hidden focusable skip-link">
Skip to main content
</a>
<div id="cern-global-loading-layout" style="display: none;"><span><span></span></span><span></span></div>
<div id="cern-toolbar" role="group" aria-label="CERN Toolbar" class="user-not-authenticated"
style="top: 0px; opacity: 1;">
<h1>
<a href="https://home.cern/" title="CERN" class="ext" data-extlink="">
CERN
<span>Accelerating science</span>
<svg focusable="false" class="ext" role="img" aria-label="(link is external)" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 80 40">
<metadata>
<sfw xmlns="http://ns.adobe.com/SaveForWeb/1.0/">
<slicesourcebounds y="-8160" x="-8165" width="16389" height="16384" bottomleftorigin="true">
</slicesourcebounds>
<optimizationsettings>
<targetsettings targetsettingsid="0" fileformat="PNG24Format">
<png24format transparency="true" filtered="false" interlaced="false" nomattecolor="false"
mattecolor="#FFFFFF"></png24format>
</targetsettings>
</optimizationsettings>
</sfw>
</metadata>
<title>(link is external)</title>
<path
d="M48 26c-1.1 0-2 0.9-2 2v26H10V18h26c1.1 0 2-0.9 2-2s-0.9-2-2-2H8c-1.1 0-2 0.9-2 2v40c0 1.1 0.9 2 2 2h40c1.1 0 2-0.9 2-2V28C50 26.9 49.1 26 48 26z">
</path>
<path
d="M56 6H44c-1.1 0-2 0.9-2 2s0.9 2 2 2h7.2L30.6 30.6c-0.8 0.8-0.8 2 0 2.8C31 33.8 31.5 34 32 34s1-0.2 1.4-0.6L54 12.8V20c0 1.1 0.9 2 2 2s2-0.9 2-2V8C58 6.9 57.1 6 56 6z">
</path>
</svg></a>
</h1>
<ul>
{% if user.is_authenticated() %}
<li class="signin">
<span>
Signed in as:
<a href="https://cern.ch/users-portal" class="account cern-multiple-mobile-signin ext">
{{ user.username }}
<body>
<nav class="navbar navbar-dark navbar-expand-lg">
<div class="container">
<a href="/" class="navbar-brand"><img src="/static/images/cara_logo_white_text.png" alt="Logo" title="Logo"></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-link"><a href="/" class="{{ "header-navbar nav-link active" if "home/" == active_page else "header-navbar nav-link" }}">HOME</a></li>
<li class="nav-item dropdown p-2">
<a class="nav-link dropdown-toggle {{ "header-navbar nav-link active" if "calculator/" in active_page else "header-navbar nav-link" }}" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
APPS
</a>
</span>
</li>
<li><a href="/auth/logout" class="cern-signout cern-multiple-mobile-signin">Sign out</a></li>
<script>
var AuthUserDomain = "{{ user.domain() }}";
</script>
{% endif %}
<li><a href="https://cern.ch/directory" class="cern-directory ext"title="Search CERN resources and browse the directory" data-extlink="">Directory</a></li>
</ul>
</div>
<div class="dialog-off-canvas-main-canvas" data-off-canvas-main-canvas="">
<header role="banner" style="display: block;">
<img src="/static/images/hse_triangle_right_1.png" style="float:left; height: 65pt; margin-top: 7pt">
<div class="header-wrapper" style="background: rgb(47, 52, 66); clear: none;">
<div class="site-info col-sm-3" style="max-height: 76px;">
<div class="site-info__text col-lg-9 col-md-10 col-sm-9" style="overflow:hidden;">
<a href="/" title="Home" rel="home">
<img src="/static/images/cara_logo_white_text.png" alt="home">
</a>
</div>
</div>
<div class="site-nav col-sm-9 ">
<div class="region region-header">
<nav role="navigation" aria-labelledby="block-cernoverride-main-menu-menu"
id="block-cernoverride-main-menu">
<h2 class="sr-only" id="block-cernoverride-main-menu-menu">Main navigation</h2>
<nav class="navbar navbar-default main-menu">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a href="/" class="{{ "is-active" if "home/" == active_page else "" }}">
Home
</a>
</li>
<li class="dropdown">
<a href="{{ calculator_prefix }}" class="dropdown-toggle {{ "is-active" if "calculator" in active_page else "" }}">
COVID Calculator
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>
<a href="{{ calculator_prefix }}" class="{{ "is-active" if "calculator" == active_page else "" }}">
Calculator
</a>
</li>
<li>
<a href="{{ calculator_prefix }}/user-guide" class="{{ "is-active" if "user-guide" in active_page else "" }}">
User guide
</a>
</li>
</ul>
<li>
<a href="/expert-app" target="_blank">
Expert App (BETA)
</a>
</li>
<li>
<a href="https://hse.cern/covid-19-information">
Covid Information
</a>
</li>
</li>
<li>
<a href="/about" class="{{ "is-active" if "about" == active_page else "" }}">
About
</a>
</li>
</ul>
</div>
</div>
</nav>
</nav>
</div>
</div>
<ul class="dropdown-menu dropwown-navbar-colors" style="min-width: 14rem;" aria-labelledby="navbarDropdown">
<li><a href="{{ calculator_prefix }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">CARA CALCULATOR</a></li>
<li><a href="{{ calculator_prefix }}/user-guide" style="margin-left: 4rem" class="{{ "header-navbar nav-link active" if "user-guide" in active_page else "header-navbar nav-link" }}">USER GUIDE</a></li>
<li><a href="/expert-app" class="{{ "header-navbar nav-link active" if "/expert-app" == active_page else "header-navbar nav-link" }}">EXPERT APP (BETA)</a></li>
</ul>
</li>
<li class="nav-link"><a href="https://hse.cern/covid-19-information" class="header-navbar nav-link">COVID INFORMATION</a></li>
<li class="nav-link"><a href="/about" class="{{ "header-navbar nav-link active" if "about" == active_page else "header-navbar nav-link" }}">ABOUT</a></li>
{% if user.is_authenticated() %}
<li class="nav-item dropdown p-2">
<a class="nav-link active dropdown-toggle d-inline-block" href="https://cern.ch/users-portal" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Signed in as: {{ user.username }}
</a>
<ul class="dropdown-menu dropwown-navbar-colors" style="min-width: 14rem;" aria-labelledby="navbarDropdown">
<li><a href="/auth/logout" class="nav-link ml-2">Sign out</a></li>
</ul>
{# Sent to Piwik for statistics #}
<script>
var AuthUserDomain = "{{ user.domain() }}";
</script>
{% endif %}
</li>
</ul>
</div>
</header>
</div>
</div>
</nav>
<main role="main">
{% block main %}
{% endblock main %}
</main>
<footer role="contentinfo">
<div class="row cern-footer">
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-3 footer-first-col">
<div class="region region-footercolumn1">
<section id="block-disclaimer"
class="block block-block-content block-block-content112ec55d-2622-43e4-9063-e7433079dfb1 clearfix">
<footer>
<div class="container">
<div class="row text-light text-center py-4 justify-content-center">
<h2 class="block-title">Disclaimer</h2>
<div class="field field--name-body field--type-text-with-summary field--label-hidden field--item">
<p><span style="font-size:10px;"><em>CERN strives to deploy its know-how and technologies to help solve
<div class="col-sm-10 col-md-8 col-lg-6">
<img src="/static/images/cara_logo_white_text.png" alt="Logo">
<p><span style="font-size:10px;"><em>CERN strives to deploy its know-how and technologies to help solve
the challenges arising in the local and global fight against COVID-19. As a particle physics
research organisation, CERN is not in a position to advise on medical research, health or health
policy issues. Any initiative is conducted on a best effort and as-is basis, without liability or
warranty.</em></span></p>
</div>
</section>
<p style="font-size:10px;">
CARA is <a href="https://gitlab.cern.ch/cara/cara/-/blob/master/LICENSE" class="ext">Apache 2.0 licensed</a> open-source
software developed at CERN.
You can find the source code at <a href="https://gitlab.cern.ch/cara/cara">https://gitlab.cern.ch/cara/cara</a>,
where we welcome contributions, feature requests and issue reports.
</p>
</div>
</div>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8 footer-second-col">
<div class="row">
<!-- CONTACT US -->
<div class="col-sm-5 col-md-4 col-md-offset-0 col-lg-4 col-lg-offset-0">
<div class="region region-footercolumn2">
<nav role="navigation" aria-labelledby="block-cernoverride-footer-menu" id="block-cernoverride-footer">
<h2 class="visually-hidden" id="block-cernoverride-footer-menu">Footer menu</h2>
<ul class="menu nav">
<li>
<a href="mailto:cara-dev@cern.ch" title="Contact the Task Force" class="mailto"
data-extlink="">Contact<svg focusable="false" class="mailto" role="img"
aria-label="(link sends email)" xmlns="http://www.w3.org/2000/svg" viewBox="0 10 70 20">
<metadata>
<sfw xmlns="http://ns.adobe.com/SaveForWeb/1.0/">
<slicesourcebounds y="-8160" x="-8165" width="16389" height="16384" bottomleftorigin="true">
</slicesourcebounds>
<optimizationsettings>
<targetsettings targetsettingsid="0" fileformat="PNG24Format">
<png24format transparency="true" filtered="false" interlaced="false"
nomattecolor="false" mattecolor="#FFFFFF"></png24format>
</targetsettings>
</optimizationsettings>
</sfw>
</metadata>
<title>(link sends email)</title>
<path
d="M56 14H8c-1.1 0-2 0.9-2 2v32c0 1.1 0.9 2 2 2h48c1.1 0 2-0.9 2-2V16C58 14.9 57.1 14 56 14zM50.5 18L32 33.4 13.5 18H50.5zM10 46V20.3l20.7 17.3C31.1 37.8 31.5 38 32 38s0.9-0.2 1.3-0.5L54 20.3V46H10z">
</path>
</svg></a>
</li>
<li>
<a href="https://gitlab.cern.ch/cara/cara" title="CARA code repository" data-extlink="">
Source code
</a>
</li>
</ul>
</nav>
<p style="font-size:10px;">
CARA is <a href="https://gitlab.cern.ch/cara/cara/-/blob/master/LICENSE" class="ext">Apache 2.0 licensed</a> open-source
software developed at CERN.
You can find the source code at <a href="https://gitlab.cern.ch/cara/cara">https://gitlab.cern.ch/cara/cara</a>,
where we welcome contributions, feature requests and issue reports.
</p>
</div>
</div>
<!-- general info -->
<div class="col-sm-6 col-sm-offset-1 col-md-4 col-md-offset-0 col-lg-4">
<div class=" mb-4">
</div>
</div>
<!-- cern and you -->
<div class="col-sm-6 col-sm-offset-6 col-md-4 col-md-offset-0 col-lg-4 col-lg-offset-0">
<div class=" mb-4">
</div>
</div>
</div>
</div>
<div class="col-xs-1 col-sm-1 col-md-1 col-lg-1 footer-last-logo">
<a href="https://hse.cern/" title="HSE home" target="_blank">
<img src="/static/images/HSE_logo_white.png" alt="HSE home" style="width:450px; margin-left:-300px;">
</a>
</div>
</div>
<div class="copy-wrapper light">
<a href="https://copyright.web.cern.ch/" class="ext" data-extlink="">
Copyright
<svg focusable="false" class="ext" role="img" aria-label="(link is external)" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 80 40">
<metadata>
<sfw xmlns="http://ns.adobe.com/SaveForWeb/1.0/">
<slicesourcebounds y="-8160" x="-8165" width="16389" height="16384" bottomleftorigin="true">
</slicesourcebounds>
<optimizationsettings>
<targetsettings targetsettingsid="0" fileformat="PNG24Format">
<png24format transparency="true" filtered="false" interlaced="false" nomattecolor="false"
mattecolor="#FFFFFF"></png24format>
</targetsettings>
</optimizationsettings>
</sfw>
</metadata>
<title>(link is external)</title>
<path
d="M48 26c-1.1 0-2 0.9-2 2v26H10V18h26c1.1 0 2-0.9 2-2s-0.9-2-2-2H8c-1.1 0-2 0.9-2 2v40c0 1.1 0.9 2 2 2h40c1.1 0 2-0.9 2-2V28C50 26.9 49.1 26 48 26z">
</path>
<path
d="M56 6H44c-1.1 0-2 0.9-2 2s0.9 2 2 2h7.2L30.6 30.6c-0.8 0.8-0.8 2 0 2.8C31 33.8 31.5 34 32 34s1-0.2 1.4-0.6L54 12.8V20c0 1.1 0.9 2 2 2s2-0.9 2-2V8C58 6.9 57.1 6 56 6z">
</path>
</svg></a>
&nbsp;© 2020 - 2021 CERN</div>
</footer>
<script src="/static/js/js_packaged_for_theme.js"></script>
@ -304,35 +100,14 @@
<script src="/static/js/ScrollMagic.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/js/bootstrap.min.js" integrity="sha512-8qmis31OQi6hIRgvkht0s6mCOittjMa9GMqtK9hes5iEQBQE/Ca6yGE5FsW36vyipGoWQswBj/QBm2JR086Rkw==" crossorigin="anonymous"></script>
<script src="/static/js/usage-tracking.js"></script>
<!-- Popper JS -->
<script src="/static/js/popper.min.js"></script>
<!-- Font Awesome -->
<script src="/static/js/all.min.js"></script>
{% block body_scripts %}
{% endblock body_scripts %}
<div id="cboxOverlay" style="display: none;"></div>
<div id="colorbox" class="" role="dialog" tabindex="-1" style="display: none;">
<div id="cboxWrapper">
<div>
<div id="cboxTopLeft" style="float: left;"></div>
<div id="cboxTopCenter" style="float: left;"></div>
<div id="cboxTopRight" style="float: left;"></div>
</div>
<div style="clear: left;">
<div id="cboxMiddleLeft" style="float: left;"></div>
<div id="cboxContent" style="float: left;">
<div id="cboxTitle" style="float: left;"></div>
<div id="cboxCurrent" style="float: left;"></div><button type="button" id="cboxPrevious"></button><button
type="button" id="cboxNext"></button><button type="button" id="cboxSlideshow"></button>
<div id="cboxLoadingOverlay" style="float: left;"></div>
<div id="cboxLoadingGraphic" style="float: left;"></div>
</div>
<div id="cboxMiddleRight" style="float: left;"></div>
</div>
<div style="clear: left;">
<div id="cboxBottomLeft" style="float: left;"></div>
<div id="cboxBottomCenter" style="float: left;"></div>
<div id="cboxBottomRight" style="float: left;"></div>
</div>
</div>
<div style="position: absolute; width: 9999px; visibility: hidden; display: none; max-width: none;"></div>
</div>
</body>
</html>

View file

@ -1,29 +1,29 @@
{% extends "layout.html.j2" %}
{% block main %}
<div style="height: 8em; display: block;"></div>
<div class="field--item">
<div class="component-row component-row__display__fluidcenter section-navigation effect_none">
<div class="component-row__row">
<div class="component-row__column component-row__center section-has-no-column col-md-12 col-sm-12 col-xs-12">
<div class="box-effects-wrapper ">
<div class="text-component text-component-page clearfix">
{% block contents %}
{{ contents }}
{% endblock contents %}
</div>
</div>
</div>
{% block main %}
<div style="height: 8em; display: block;"></div>
<div class="field--item">
<div class="component-row component-row__display__fluidcenter section-navigation effect_none">
<div class="component-row__row">
<div class="component-row__column component-row__center section-has-no-column col-md-12 col-sm-12 col-xs-12">
<div class="box-effects-wrapper ">
<div class="text-component text-component-page clearfix">
{% block contents %}
{{ contents }}
{% endblock contents %}
</div>
</div>
</div>
</div>
</div>
</div>
<a class="endof-cern-header-blocks"></a>
</div>
</div>
<br>
{% endblock main %}
<a class="endof-cern-header-blocks"></a>
</div>
<br>
{% endblock main %}

View file

@ -1,53 +1,32 @@
import numpy as np
from cara import models
from cara.data.weather import wx_data, nearest_wx_station
# TODO: The values in this module to be removed and instead use the cara.data.weather functionality.
MONTH_NAMES = [
'January', 'February', 'March', 'April', 'May', 'June', 'July',
'August', 'September', 'October', 'November', 'December',
]
# Geneva average temperature of each month, hour per hour (from midnight to 11 pm)
Geneva_hourly_temperatures_celsius_per_hour = {
'Jan': [0.2, -0.3, -0.5, -0.9, -1.1, -1.4, -1.5, -1.5, -1.1, 0.1, 1.5,
2.8, 3.8, 4.4, 4.5, 4.4, 4.4, 3.9, 3.1, 2.7, 2.2, 1.7, 1.5, 1.1],
'Feb': [0.9, 0.3, 0.0, -0.5, -0.7, -1.1, -1.2, -1.1, -0.7, 0.8, 2.5,
4.2, 5.4, 6.2, 6.3, 6.2, 6.1, 5.5, 4.5, 4.1, 3.5, 2.8, 2.5, 2.0],
'Mar': [4.2, 3.5, 3.1, 2.5, 2.1, 1.6, 1.5, 1.6, 2.2, 4.0, 6.3, 8.4,
10.0, 11.1, 11.2, 11.1, 11.0, 10.2, 8.9, 8.3, 7.5, 6.7, 6.3, 5.6],
'Apr': [7.4, 6.7, 6.2, 5.5, 5.2, 4.7, 4.5, 4.6, 5.3, 7.2, 9.6, 11.9,
13.7, 14.8, 14.9, 14.8, 14.7, 13.8, 12.4, 11.8, 10.9, 10.1, 9.6, 8.9],
'May': [11.8, 11.1, 10.6, 9.9, 9.5, 8.9, 8.8, 8.9, 9.6, 11.6, 14.2, 16.6,
18.4, 19.6, 19.7, 19.6, 19.4, 18.6, 17.1, 16.5, 15.6, 14.6, 14.2, 13.4],
'Jun': [15.2, 14.4, 13.9, 13.2, 12.7, 12.2, 12.0, 12.1, 12.8, 15.0, 17.7,
20.2, 22.1, 23.3, 23.5, 23.4, 23.2, 22.3, 20.8, 20.1, 19.1, 18.2, 17.7, 16.9],
'Jul': [17.6, 16.7, 16.1, 15.3, 14.9, 14.3, 14.1, 14.2, 15.0, 17.3, 20.2,
23.0, 25.0, 26.3, 26.5, 26.4, 26.2, 25.2, 23.6, 22.8, 21.8, 20.8, 20.2, 19.4],
'Aug': [17.1, 16.2, 15.7, 14.9, 14.5, 13.9, 13.7, 13.8, 14.6, 16.9, 19.7,
22.4, 24.4, 25.6, 25.8, 25.7, 25.5, 24.5, 22.9, 22.2, 21.2, 20.2, 19.7, 18.9],
'Sep': [13.4, 12.7, 12.2, 11.5, 11.2, 10.7, 10.5, 10.6, 11.3, 13.2, 15.6,
17.9, 19.6, 20.8, 20.9, 20.8, 20.7, 19.8, 18.4, 17.8, 16.9, 16.1, 15.6, 14.9],
'Oct': [9.4, 8.8, 8.5, 7.9, 7.6, 7.2, 7.1, 7.2, 7.7, 9.3, 11.2, 13.0,
14.4, 15.3, 15.4, 15.3, 15.2, 14.5, 13.4, 12.9, 12.2, 11.6, 11.2, 10.6],
'Nov': [4.0, 3.6, 3.3, 2.9, 2.6, 2.3, 2.2, 2.2, 2.7, 3.9, 5.5, 6.9, 8.0,
8.7, 8.8, 8.7, 8.7, 8.1, 7.2, 6.8, 6.3, 5.7, 5.5, 5.0],
'Dec': [1.4, 1.0, 0.8, 0.4, 0.2, -0.0, -0.1, -0.1, 0.3, 1.3, 2.6, 3.8,
4.7, 5.2, 5.3, 5.2, 5.2, 4.7, 4.0, 3.7, 3.2, 2.8, 2.6, 2.2]
}
# Toronto average temperature of each month, hour per hour (from midnight to 11 pm)
Toronto_hourly_temperatures_celsius_per_hour = {
"Jan": [ -2.9, -3.0, -3.2, -3.3, -3.3, -3.5, -3.7, -3.8, -3.9, -4.0, -4.1, -4.3, -4.3, -4.3, -4.1, -3.7, -3.2, -2.8, -2.6, -2.3, -2.2, -2.3, -2.6, -2.8],
"Feb": [ -2.4, -2.6, -2.8, -2.9, -2.9, -3.1, -3.3, -3.4, -3.6, -3.8, -3.9, -4.0, -4.3, -4.2, -3.7, -3.2, -2.6, -2.1, -1.7, -1.5, -1.3, -1.4, -1.6, -2.1],
"Mar": [ 1.3, 1.0, 0.7, 0.5, 0.4, 0.1, -0.0, -0.2, -0.4, -0.5, -0.7, -0.8, -0.9, -0.3, 0.4, 1.0, 1.6, 2.0, 2.3, 2.7, 2.7, 2.7, 2.4, 1.9],
"Apr": [ 6.8, 6.5, 6.3, 5.9, 5.7, 5.4, 5.1, 4.9, 4.6, 4.4, 4.2, 4.3, 4.8, 5.5, 6.1, 6.7, 7.1, 7.6, 7.8, 8.1, 8.2, 8.2, 8.0, 7.6 ],
"May": [ 13.0, 12.6, 12.2, 11.8, 11.5, 11.2, 10.8, 10.5, 10.2, 9.9, 9.8, 10.0, 10.9, 11.6, 12.2, 12.7, 13.2, 13.6, 13.9, 14.3, 14.4, 14.3, 14.2, 13.8],
"Jun": [ 18.9, 18.2, 17.8, 17.4, 17.0, 16.6, 16.2, 15.9, 15.6, 15.4, 15.3, 15.8, 16.5, 17.3, 17.9, 18.4, 18.9, 19.4, 19.7, 20.1, 20.3, 20.3, 20.1, 19.7],
"Jul": [ 22.1, 21.4, 20.9, 20.5, 20.0, 19.6, 19.1, 18.9, 18.6, 18.3, 18.1, 18.5, 19.4, 20.3, 21.0, 21.6, 22.2, 22.7, 23.1, 23.4, 23.6, 23.5, 23.3, 22.9],
"Aug": [ 22.0, 21.4, 21.0, 20.7, 20.3, 20.0, 19.6, 19.3, 19.1, 18.8, 18.5, 18.4, 19.4, 20.3, 21.1, 21.7, 22.2, 22.8, 23.1, 23.4, 23.5, 23.3, 23.1, 22.6],
"Sep": [ 18.2, 17.8, 17.4, 17.3, 17.0, 16.6, 16.3, 16.0, 15.8, 15.5, 15.4, 15.0, 15.6, 16.6, 17.5, 18.2, 18.7, 19.2, 19.6, 19.8, 19.7, 19.6, 19.2, 18.6],
"Oct": [ 11.1, 10.9, 10.6, 10.5, 10.2, 10.1, 9.8, 9.7, 9.5, 9.3, 9.2, 9.0, 9.0, 9.7, 10.5, 11.2, 11.7, 12.2, 12.4, 12.6, 12.6, 12.3, 11.8, 11.3],
"Nov": [ 5.3, 5.1, 5.0, 4.7, 4.6, 4.4, 4.3, 4.2, 4.1, 4.0, 3.9, 3.8, 3.7, 4.0, 4.6, 5.2, 5.7, 6.1, 6.2, 6.4, 6.3, 6.0, 5.5, 5.3],
"Dec": [ 0.4, 0.3, 0.2, 0.0, -0.1, -0.2, -0.4, -0.5, -0.6, -0.7, -0.8, -0.8, -0.9, -0.9, -0.6, -0.2, 0.3, 0.7, 0.9, 1.1, 1.1, 0.9, 0.6, 0.5]
}
def get_hourly_temperatures_celsius_per_hour(coordinates):
wx_station_id = nearest_wx_station(
longitude=coordinates[1], latitude=coordinates[0])[0]
# average temperature of each month, hour per hour (from midnight to 11 pm)
return {month.replace(month, MONTH_NAMES[i][:3]):
[t - 273.15 for t in temp] for i, (month, temp)
in enumerate(wx_data()[wx_station_id].items())}
# Load the weather data (temperature in kelvin) for Geneva.
geneva_coordinates = (46.204391, 6.143158)
local_hourly_temperatures_celsius_per_hour = get_hourly_temperatures_celsius_per_hour(
geneva_coordinates)
# Load the weather data (temperature in kelvin) for Toronto.
toronto_coordinates = (43.667, 79.400)
toronto_hourly_temperatures_celsius_per_hour = get_hourly_temperatures_celsius_per_hour(
toronto_coordinates)
# Geneva hourly temperatures as piecewise constant function (in Kelvin).
GenevaTemperatures_hourly = {
month: models.PiecewiseConstant(
@ -56,10 +35,9 @@ GenevaTemperatures_hourly = {
tuple(float(time) for time in range(25)),
tuple(273.15 + np.array(temperatures)),
)
for month, temperatures in Geneva_hourly_temperatures_celsius_per_hour.items()
for month, temperatures in local_hourly_temperatures_celsius_per_hour.items()
}
# Toronto hourly temperatures as piecewise constant function (in Kelvin).
TorontoTemperatures_hourly = {
month: models.PiecewiseConstant(
@ -68,19 +46,17 @@ TorontoTemperatures_hourly = {
tuple(float(time) for time in range(25)),
tuple(273.15 + np.array(temperatures)),
)
for month, temperatures in Toronto_hourly_temperatures_celsius_per_hour.items()
for month, temperatures in toronto_hourly_temperatures_celsius_per_hour.items()
}
# Same Geneva temperatures on a finer temperature mesh (every 6 minutes).
GenevaTemperatures = {
month: GenevaTemperatures_hourly[month].refine(refine_factor=10)
for month, temperatures in Geneva_hourly_temperatures_celsius_per_hour.items()
for month, temperatures in local_hourly_temperatures_celsius_per_hour.items()
}
# Same Toronto temperatures on a finer temperature mesh (every 6 minutes).
TorontoTemperatures = {
month: TorontoTemperatures_hourly[month].refine(refine_factor=10)
for month, temperatures in Toronto_hourly_temperatures_celsius_per_hour.items()
}
for month, temperatures in toronto_hourly_temperatures_celsius_per_hour.items()
}

View file

@ -103,7 +103,6 @@ class Interval:
return True
return False
@dataclass(frozen=True)
class SpecificInterval(Interval):
#: A sequence of times (start, stop), in hours, that the infected person
@ -125,11 +124,14 @@ class PeriodicInterval(Interval):
#: occurring, a value of 0 signifies that the event never happens.
duration: float
#: Time at which the first person (infected or exposed) arrives at the enclosed space.
start: float = 0.0
def boundaries(self) -> BoundarySequence_t:
if self.period == 0 or self.duration == 0:
return tuple()
result = []
for i in np.arange(0, 24, self.period / 60):
for i in np.arange(self.start, 24, self.period / 60):
# NOTE: It is important that the time type is float, not np.float, in
# order to allow hashability (for caching).
result.append((float(i), float(i+self.duration/60)))
@ -343,7 +345,7 @@ class HingedWindow(WindowOpening):
window_width: _VectorisedFloat = 0.0
def __post_init__(self):
if self.window_width is 0.0:
if self.window_width is float(0.0):
raise ValueError('window_width must be set')
@property
@ -925,7 +927,7 @@ class ConcentrationModel:
@method_cache
def normed_integrated_concentration(self, start: float, stop: float) -> _VectorisedFloat:
"""
Get the integrated concentration dose between the times start and stop,
Get the integrated concentration of viruses in the air between the times start and stop,
normalized by the emission rate.
"""
if stop <= self._first_presence_time():
@ -954,7 +956,7 @@ class ConcentrationModel:
def integrated_concentration(self, start: float, stop: float) -> _VectorisedFloat:
"""
Get the integrated concentration dose between the times start and stop.
Get the integrated concentration of viruses in the air between the times start and stop.
"""
return (self.normed_integrated_concentration(start, stop) *
self.infected.emission_rate_when_present())
@ -999,9 +1001,33 @@ class ExposureModel:
+ (0.943/(1 + np.exp(0.508 - 2.58 * np.log(d)))))
return fdep
def _normed_exposure_between_bounds(self, time1: float, time2: float) -> _VectorisedFloat:
"""The number of virions per meter^3 between any two times, normalized
by the emission rate of the infected population"""
exposure = 0.
for start, stop in self.exposed.presence.boundaries():
if stop < time1:
continue
elif start > time2:
break
elif start <= time1 and time2<= stop:
exposure += self.concentration_model.normed_integrated_concentration(time1, time2)
elif start <= time1 and stop < time2:
exposure += self.concentration_model.normed_integrated_concentration(time1, stop)
elif time1 < start and time2 <= stop:
exposure += self.concentration_model.normed_integrated_concentration(start, time2)
elif time1 <= start and stop < time2:
exposure += self.concentration_model.normed_integrated_concentration(start, stop)
return exposure
def exposure_between_bounds(self, time1: float, time2: float) -> _VectorisedFloat:
"""The number of virions per meter^3 between any two times."""
return (self._normed_exposure_between_bounds(time1, time2) *
self.concentration_model.infected.emission_rate_when_present())
def _normed_exposure(self) -> _VectorisedFloat:
"""
The number of virus per meter^3, normalized by the emission rate
The number of virions per meter^3, normalized by the emission rate
of the infected population.
"""
normed_exposure = 0.0
@ -1083,7 +1109,6 @@ class ExposureModel:
return (1 - np.exp(-((inf_aero * (1 - self.exposed.host_immunity))/(infectious_dose *
self.concentration_model.virus.transmissibility_factor)))) * 100
def expected_new_cases(self) -> _VectorisedFloat:
prob = self.infection_probability()
exposed_occupants = self.exposed.number

View file

@ -0,0 +1,15 @@
cd Downloads
git clone https://gitlab.cern.ch/cara/cara.git
cd cara
git lfs install
git lfs pull
if [[ `uname -m` == 'arm64' ]]; then
pip3 install scipy --index-url=https://pypi.anaconda.org/scipy-wheels-nightly/simple
pip3 install Cython
pip3 install -U --no-use-pep517 scikit-learn
fi
pip3 install -e .
echo "############################################"
echo "CARA is now running at http://localhost:8080"
echo "############################################"
python3 -m cara.apps.calculator

View file

@ -0,0 +1,9 @@
git clone https://gitlab.cern.ch/cara/cara.git
cd cara
git lfs install
git lfs pull
pip install -e .
echo "############################################"
echo "CARA is now running at http://localhost:8080"
echo "############################################"
python -m cara.apps.calculator

View file

@ -0,0 +1,15 @@
cd Downloads
git clone https://gitlab.cern.ch/cara/cara.git
cd cara
git lfs install
git lfs pull
if [[ `uname -m` == 'arm64' ]]; then
pip3 install scipy --index-url=https://pypi.anaconda.org/scipy-wheels-nightly/simple
pip3 install Cython
pip3 install -U --no-use-pep517 scikit-learn
fi
pip3 install -e .
echo "############################################"
echo "CARA is now running at http://localhost:8080"
echo "############################################"
python3 -m cara.apps.calculator --theme=cara/apps/calculator/themes/cern

View file

@ -0,0 +1,9 @@
git clone https://gitlab.cern.ch/cara/cara.git
cd cara
git lfs install
git lfs pull
pip install -e .
echo "############################################"
echo "CARA is now running at http://localhost:8080"
echo "############################################"
python -m cara.apps.calculator --theme=cara/apps/calculator/themes/cern

View file

@ -59,7 +59,7 @@ def test_ventilation_slidingwindow(baseline_form: model_generator.FormData):
assert isinstance(baseline_window, models.SlidingWindow)
window = models.SlidingWindow(
active=models.PeriodicInterval(period=120, duration=10),
active=models.PeriodicInterval(period=120, duration=10, start=minutes_since_midnight(9 * 60)),
inside_temp=models.PiecewiseConstant((0, 24), (293,)),
outside_temp=baseline_window.outside_temp,
window_height=1.6, opening_length=0.6,
@ -91,7 +91,7 @@ def test_ventilation_hingedwindow(baseline_form: model_generator.FormData):
assert isinstance(baseline_window, models.HingedWindow)
window = models.HingedWindow(
active=models.PeriodicInterval(period=120, duration=10),
active=models.PeriodicInterval(period=120, duration=10, start=minutes_since_midnight(9 * 60)),
inside_temp=models.PiecewiseConstant((0, 24), (293,)),
outside_temp=baseline_window.outside_temp,
window_height=1.6, window_width=1., opening_length=0.6,
@ -152,7 +152,7 @@ def test_ventilation_window_hepa(baseline_form: model_generator.FormData):
# Now build the equivalent ventilation instance directly, and compare.
window = models.SlidingWindow(
active=models.PeriodicInterval(period=120, duration=10),
active=models.PeriodicInterval(period=120, duration=10, start=minutes_since_midnight(9 * 60)),
inside_temp=models.PiecewiseConstant((0, 24), (293,)),
outside_temp=baseline_window.outside_temp,
window_height=1.6, opening_length=0.6,

View file

@ -4,7 +4,7 @@ import pytest
import tornado.testing
import cara.apps.calculator
from cara.apps.calculator.report_generator import generate_qr_code
from cara.apps.calculator.report_generator import generate_permalink
_TIMEOUT = 20.
@ -97,26 +97,26 @@ class TestOpenApp(tornado.testing.AsyncHTTPTestCase):
assert response.code == 404
async def test_qrcode_urls(http_server_client, baseline_form):
async def test_permalink_urls(http_server_client, baseline_form):
base_url = 'proto://hostname/prefix'
qr_data = generate_qr_code(base_url, "/calculator", baseline_form)
permalink_data = generate_permalink(base_url, "/calculator", baseline_form)
expected = f'{base_url}/calculator?exposed_coffee_break_option={baseline_form.exposed_coffee_break_option}&'
assert qr_data['link'].startswith(expected)
assert permalink_data['link'].startswith(expected)
# We should get a 200 for the link.
response = await http_server_client.fetch(qr_data['link'].replace(base_url, ''))
response = await http_server_client.fetch(permalink_data['link'].replace(base_url, ''))
assert response.code == 200
# And a 302 for the QR url itself. The redirected URL should be the same as
# in the link.
assert qr_data['qr_url'].startswith(base_url)
assert permalink_data['shortened'].startswith(base_url)
response = await http_server_client.fetch(
qr_data['qr_url'].replace(base_url, ''),
permalink_data['shortened'].replace(base_url, ''),
max_redirects=0,
raise_error=False,
)
assert response.code == 302
assert response.headers['Location'] == qr_data['link'].replace(base_url, '')
assert response.headers['Location'] == permalink_data['link'].replace(base_url, '')
async def test_invalid_compressed_url(http_server_client, baseline_form):

View file

@ -55,7 +55,6 @@ populations = [
),
]
def known_concentrations(func):
dummy_room = models.Room(50, 0.5)
dummy_ventilation = models._VentilationBase()

View file

@ -299,7 +299,7 @@ def build_hourly_dependent_model_multipleventilation(month, intervals_open=((7.5
@pytest.mark.parametrize(
"month, temperatures",
data.Geneva_hourly_temperatures_celsius_per_hour.items(),
data.local_hourly_temperatures_celsius_per_hour.items(),
)
@pytest.mark.parametrize(
"time",
@ -314,7 +314,7 @@ def test_concentrations_hourly_dep_temp_vs_constant(month, temperatures, time):
@pytest.mark.parametrize(
"month, temperatures",
data.Geneva_hourly_temperatures_celsius_per_hour.items(),
data.local_hourly_temperatures_celsius_per_hour.items(),
)
@pytest.mark.parametrize(
"time",
@ -338,7 +338,7 @@ def test_concentrations_hourly_dep_multipleventilation():
@pytest.mark.parametrize(
"month_temp_item",
data.Geneva_hourly_temperatures_celsius_per_hour.items(),
data.local_hourly_temperatures_celsius_per_hour.items(),
)
@pytest.mark.parametrize(
"time",
@ -386,8 +386,8 @@ def build_exposure_model(concentration_model):
@pytest.mark.parametrize(
"month, expected_exposure",
[
['Jan', 496.5427],
['Jun', 1898.1354],
['Jan', 503.254087759],
['Jun', 2294.71115639],
],
)
def test_exposure_hourly_dep(month,expected_exposure):
@ -407,8 +407,8 @@ def test_exposure_hourly_dep(month,expected_exposure):
@pytest.mark.parametrize(
"month, expected_exposure",
[
['Jan', 499.6921],
['Jun', 2007.59925],
['Jan', 511.118941481],
['Jun', 2398.90129579],
],
)
def test_exposure_hourly_dep_refined(month,expected_exposure):

View file

@ -281,8 +281,8 @@ def waiting_room_mc():
@pytest.mark.parametrize(
"mc_model, expected_pi, expected_new_cases, expected_dose, expected_ER",
[
["shared_office_mc", 6.03, 0.18, 24.55, 809],
["classroom_mc", 10.0, 1.85, 79.98, 5624],
["shared_office_mc", 6.03, 0.18, 27.22, 809],
["classroom_mc", 9.5, 1.85, 79.98, 5624],
["ski_cabin_mc", 16.0, 0.5, 40.25, 7966],
["skagit_chorale_mc",65.7, 40.0, 241.28, 190422],
["bus_ride_mc", 12.0, 8.0, 63.79, 5419],

View file

@ -62,7 +62,6 @@ pyparsing==2.4.7
pyrsistent==0.18.0
python-dateutil==2.8.2
pyzmq==22.1.0
qrcode==7.2
requests==2.26.0
requests-unixsocket==0.2.0
scikit-learn==0.24.2

View file

@ -0,0 +1,18 @@
# locust
A simple open source load testing tool that allows to define user behavior.
In order to set it up for the first time, we followed the documentation at https://locust.io/. In particular, we:
* Defined a class for the users that will be simulating.
* Defined a ``wait_time`` variable that will make the simulated users wait between the specified seconds after each task executed.
* Decorated our method with ``@Task`` that creates a micro-thread that calls this method.
* Defined the ``self.client`` attribute that makes it possible to make HTTP calls that will be logged by Locust.
To use, uncomment the desired method on ``lucust.py``` file, open the terminal on this folder and run the following command:
``locust -f locust.py --host https://cara.web.cern.ch``
Then, open up a browser and point it to http://localhost:8089.
By default we pointed out the test to our own web server.
``Start swarming`` will trigger the simulation.

View file

@ -0,0 +1,42 @@
from locust import HttpUser, task, between
from gevent.pool import Group
import time
'''
Method no. 1 - Simulation with each single user
running x requests in parallel.
Specify the desired number of parallel requests in
"num_of_parallel_requests" variable (35 by default).
This method was used in simulations with one single
user perfoming 35 requests in parallel.
'''
# num_of_parallel_requests = 35
# class User(HttpUser):
# wait_time = between(0.05, 0.1)
# @task(1)
# def test_api(self):
# group = Group()
# for i in range(0, num_of_parallel_requests):
# group.spawn(lambda:self.client.get("/calculator-open/baseline-model/result"))
# group.join()
# while(1):
# time.sleep(1)
'''
Method no. 2 - Simulation with different users
running x requests concurrently.
With this method, each user is intended to
perform one single request.
This method was used in simulations with different
number of users requesting once at the same time.
'''
# class User(HttpUser):
# @task(1)
# def test_api(self):
# self.client.get("/calculator-open/baseline-model/result")
# while(1):
# time.sleep(1)

View file

@ -20,7 +20,7 @@ REQUIREMENTS: dict = {
'core': [
'dataclasses; python_version < "3.7"',
'ipykernel',
'ipympl != 0.8.0',
'ipympl != 0.8.0, != 0.8.1',
'ipywidgets',
'Jinja2',
'loky',
@ -30,7 +30,6 @@ REQUIREMENTS: dict = {
'numpy',
'psutil',
'python-dateutil',
'qrcode[pil]',
'scipy',
'sklearn',
'timezonefinder',