Merge branch 'remotes/origin/feature/website' into 'feature/dropdown_navbar'
This commit is contained in:
commit
61194be62b
14 changed files with 818 additions and 404 deletions
|
|
@ -136,11 +136,9 @@ p.notes {
|
|||
.card {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
/* CSS styling to avoid page breaks. */
|
||||
.break-after {
|
||||
page-break-after: always;
|
||||
}
|
||||
.break-avoid {
|
||||
#disclaimer {
|
||||
border: 2px solid black;
|
||||
padding: 15px;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
}
|
||||
|
|
@ -154,7 +152,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 {
|
||||
|
|
@ -227,7 +226,7 @@ p.notes {
|
|||
.split>* {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
.header-text {
|
||||
.paragraph-title {
|
||||
text-align: left;
|
||||
}
|
||||
.split>*+* {
|
||||
|
|
|
|||
|
|
@ -365,6 +365,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 +487,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];
|
||||
|
|
|
|||
|
|
@ -1,93 +1,95 @@
|
|||
/* 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();
|
||||
|
||||
|
||||
var time_format = d3.timeFormat('%H:%M');
|
||||
|
||||
// H:M time format for x axis.
|
||||
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] }))
|
||||
// Prepare 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 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');
|
||||
|
||||
var xRange = d3.scaleTime().domain([data[0].hour, data[data.length - 1].hour]);
|
||||
var xTimeRange = d3.scaleLinear().domain([data[0].time, data[data.length - 1].time]);
|
||||
var bisecHour = d3.bisector((d) => { return d.hour; }).left;
|
||||
|
||||
// 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,
|
||||
|
||||
yRange = d3.scaleLinear().range([height - margins.bottom, margins.top]).domain([0., Math.max(...concentrations)]),
|
||||
|
||||
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');
|
||||
var yRange = d3.scaleLinear().domain([0., Math.max(...concentrations)]);
|
||||
|
||||
// Line representing the mean concentration.
|
||||
plot_scenario_data(vis, data, xTimeRange, yRange, '#1f77b4');
|
||||
|
||||
// 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 lineFunc = d3.line();
|
||||
var draw_line = vis.append('svg:path')
|
||||
.attr('stroke', '#1f77b4')
|
||||
.attr('stroke-width', 2)
|
||||
.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³)');
|
||||
|
||||
// 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 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 legendAreaText = vis.append('text')
|
||||
.text('Presence of exposed person(s)')
|
||||
.style('font-size', '15px')
|
||||
.attr('alignment-baseline', 'central');
|
||||
|
||||
// Legend bounding box.
|
||||
vis.append('rect')
|
||||
// Legend bounding
|
||||
var legendBBox = vis.append('rect')
|
||||
.attr('width', 275)
|
||||
.attr('height', 50)
|
||||
.attr('x', width * 1.005)
|
||||
.attr('y', margins.top + 5)
|
||||
.attr('stroke', 'lightgrey')
|
||||
.attr('stroke-width', '2')
|
||||
.attr('rx', '5px')
|
||||
|
|
@ -102,36 +104,148 @@ function draw_concentration_plot(svg_id, times, concentrations, exposed_presence
|
|||
focus.append('circle')
|
||||
.attr('r', 3);
|
||||
|
||||
focus.append('rect')
|
||||
var tooltip_rect = 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.append('text')
|
||||
var tooltip_time = focus.append('text')
|
||||
.attr('id', 'tooltip-time')
|
||||
.attr('x', 18)
|
||||
.attr('y', -2);
|
||||
|
||||
focus.append('text')
|
||||
var tooltip_concentration = focus.append('text')
|
||||
.attr('id', 'tooltip-concentration')
|
||||
.attr('x', 18)
|
||||
.attr('y', 18);
|
||||
|
||||
vis.append('rect')
|
||||
var toolBox = 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);
|
||||
|
||||
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 * .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', '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])
|
||||
|
||||
// Line.
|
||||
lineFunc.defined(d => !isNaN(d.concentration))
|
||||
.x(d => xTimeRange(d.time))
|
||||
.y(d => yRange(d.concentration));
|
||||
draw_line.attr("d", lineFunc(data));
|
||||
|
||||
// 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.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 + ')');
|
||||
|
||||
// Legend on right side.
|
||||
const size = 20;
|
||||
if (plot_div.clientWidth >= 900) {
|
||||
legendLineIcon.attr('x', graph_width + size)
|
||||
.attr('y', margins.top + size);
|
||||
legendLineText.attr('x', graph_width + 3 * size)
|
||||
.attr('y', margins.top + size);
|
||||
legendAreaIcon.attr('x', graph_width + size)
|
||||
.attr('y', margins.top + 1.5 * size);
|
||||
legendAreaText.attr('x', graph_width + 3 * size)
|
||||
.attr('y', margins.top + 2 * size);
|
||||
legendBBox.attr('x', graph_width * 1.005)
|
||||
.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);
|
||||
legendAreaIcon.attr('x', size * 0.50)
|
||||
.attr('y', graph_height * 1.01 + size);
|
||||
legendAreaText.attr('x', 2 * size)
|
||||
.attr('y', graph_height + 1.7 * size);
|
||||
legendBBox.attr('x', 1)
|
||||
.attr('y', graph_height);
|
||||
}
|
||||
|
||||
// ToolBox.
|
||||
toolBox.attr('width', graph_width - margins.right)
|
||||
.attr('height', graph_height);
|
||||
}
|
||||
|
||||
// Draw for the first time to initialize.
|
||||
redraw();
|
||||
|
||||
function mousemove() {
|
||||
if (d3.pointer(event)[0] < graph_width / 2) {
|
||||
tooltip_rect.attr('x', 10)
|
||||
tooltip_time.attr('x', 18)
|
||||
tooltip_concentration.attr('x', 18);
|
||||
}
|
||||
else {
|
||||
tooltip_rect.attr('x', -90)
|
||||
tooltip_time.attr('x', -82)
|
||||
tooltip_concentration.attr('x', -82)
|
||||
}
|
||||
var x0 = xRange.invert(d3.pointer(event, this)[0]),
|
||||
i = bisecHour(data, x0, 1),
|
||||
d0 = data[i - 1],
|
||||
|
|
@ -141,12 +255,17 @@ function draw_concentration_plot(svg_id, times, concentrations, exposed_presence
|
|||
focus.select('#tooltip-time').text('x = ' + time_format(d.hour));
|
||||
focus.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 +290,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);
|
||||
}
|
||||
|
|
@ -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,14 +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">CARA - CALCULATOR 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" id="print-button" 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"><div id="pdf_qrcode"></div></a>
|
||||
<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 %}
|
||||
|
|
@ -59,8 +60,8 @@
|
|||
<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 %}
|
||||
|
|
@ -74,23 +75,26 @@
|
|||
{% 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">
|
||||
{% 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>
|
||||
</div>
|
||||
</div>
|
||||
{% 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 exposed_presence_intervals = {{ exposed_presence_intervals | JSONify }}
|
||||
draw_concentration_plot("#result_plot", times, concentrations, exposed_presence_intervals);
|
||||
draw_concentration_plot("concentration_plot", times, concentrations, exposed_presence_intervals);
|
||||
</script>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -107,12 +111,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">
|
||||
|
|
@ -150,7 +155,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">
|
||||
<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">
|
||||
|
|
@ -160,13 +165,14 @@
|
|||
</div>
|
||||
<div class="collapse show" id="collapseQRcode">
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<a href="{{ permalink.link }}" style="float: left;"><div id="qrcode"></div></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>
|
||||
</p>
|
||||
</span>
|
||||
</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -299,11 +305,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 }}    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 }}    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>
|
||||
|
|
@ -321,7 +329,8 @@
|
|||
{% if form.exposed_lunch_option%}
|
||||
Yes</li>
|
||||
<ul>
|
||||
<li><p class="data_subtext">Start time: {{ form.exposed_lunch_start | minutes_to_time }}    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
|
||||
|
|
@ -346,7 +355,8 @@
|
|||
{% if form.infected_lunch_option%}
|
||||
Yes</li>
|
||||
<ul>
|
||||
<li><p class="data_subtext">Start time: {{ form.infected_lunch_start | minutes_to_time }}    End time: {{ form.infected_lunch_finish | minutes_to_time }}</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
|
||||
|
|
@ -390,7 +400,7 @@
|
|||
|
||||
{% block disclaimer_container %}
|
||||
<br><br><br>
|
||||
<div style="border: 2px solid black; padding: 15px;">
|
||||
<div 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>
|
||||
|
||||
|
|
@ -403,7 +413,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>
|
||||
|
|
@ -433,12 +443,17 @@
|
|||
{% endblock disclaimer_container %}
|
||||
|
||||
<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,
|
||||
|
|
|
|||
|
|
@ -18,11 +18,12 @@
|
|||
|
||||
{% block main %}
|
||||
|
||||
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>
|
||||
<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--narrow container--padding">
|
||||
<img src="/static/images/cara_logo.200x200.png" class="logo">
|
||||
<h1 class="head-center"><b>CARA - </b> COVID Airborne Risk Assessment Calculator</h1>
|
||||
<h1 class="text-center h1-text"><b>CARA - </b> COVID Airborne Risk Assessment Calculator</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
|
@ -59,14 +60,16 @@ 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">Variant:</label>
|
||||
<select id="Variant" name="virus_type" class="col-xl-5 col-lg-7 col-sm-7 col-7">
|
||||
<option value="SARS_CoV_2">SARS-CoV-2 (nominal strain)</option>
|
||||
<option value="SARS_CoV_2_B117">SARS-CoV-2 (Alpha VOC)</option>
|
||||
<option value="SARS_CoV_2_P1">SARS-CoV-2 (Gamma VOC)</option>
|
||||
<option selected value="SARS_CoV_2_B16172">SARS-CoV-2 (Delta VOC)</option>
|
||||
</select>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-4"><label class="col-form-label">Variant:</label></div>
|
||||
<div class="col-sm-6">
|
||||
<select id="Variant" name="virus_type" class="form-control">
|
||||
<option value="SARS_CoV_2">SARS-CoV-2 (nominal strain)</option>
|
||||
<option value="SARS_CoV_2_B117">SARS-CoV-2 (Alpha VOC)</option>
|
||||
<option value="SARS_CoV_2_P1">SARS-CoV-2 (Gamma VOC)</option>
|
||||
<option selected value="SARS_CoV_2_B16172">SARS-CoV-2 (Delta VOC)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr width="80%">
|
||||
|
|
@ -92,7 +95,7 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<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>
|
||||
<label for="room_data_dimensions">Floor area:</label>
|
||||
</div>
|
||||
<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">
|
||||
|
|
@ -100,33 +103,34 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-4">
|
||||
<label for="room_data_dimensions">Ceiling height:</label>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<input type="radio" id="heating_yes" name="room_heating_option" value=1>
|
||||
<label for="heating_yes">Yes</label>
|
||||
|
||||
<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">
|
||||
<label class="col-sm-3">Location:</label>
|
||||
<select id="location_select" form="not-submitted" class="col-sm-7 form-control" 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>
|
||||
<div class="col-sm-4"><label class="col-form-label">Location:</label></div>
|
||||
<div class="col-sm-6 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">
|
||||
<input type="text" name="location_latitude">
|
||||
<input type="text" name="location_longitude">
|
||||
</div>
|
||||
|
||||
<hr width="80%">
|
||||
|
|
@ -141,56 +145,91 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
|
||||
<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>
|
||||
<input type="radio" id="mechanical_ventilation" name="ventilation_type" value="mechanical_ventilation" data-enables="#DIVmechanical_ventilation">
|
||||
<label for="mechanical_ventilation">Mechanical</label>
|
||||
<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">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
Single-sided ventilation is assumed in the model and is typically effective for room depths up to 5.5 m from the opening, or 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">
|
||||
<div class="form-group row">
|
||||
<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 col-sm-5">Air supply flow rate</label>
|
||||
<input type="number" step="any" id="air_supply" class="non_zero form-control col-sm-5" name="air_supply" min="0" placeholder="(m³ / hour)" data-has-radio="#mech_type_air_supply"><br>
|
||||
<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="(m³ / hour)" data-has-radio="#mech_type_air_supply"><br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<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 col-sm-5">Air changes per hour</label>
|
||||
<input type="number" step="any" id="air_changes" class="non_zero form-control col-sm-5" name="air_changes" min="0" placeholder="(h⁻¹) only fresh air" data-has-radio="#mech_type_air_changes"><br>
|
||||
<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="(h⁻¹) only fresh air" data-has-radio="#mech_type_air_changes"><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="DIVnatural_ventilation" class="tabbed" style="display:none">
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-5">Number of windows:</label>
|
||||
<input type="number" id="windows_number" class="non_zero form-control col-sm-5" name="windows_number" min="1"><br>
|
||||
<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" min="1"><br></div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-5">Height of window: </label>
|
||||
<input type="number" step="any" id="window_height" class="non_zero form-control col-sm-5" name="window_height" placeholder="meters" min="0"><br>
|
||||
<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="meters" min="0"><br></div>
|
||||
</div>
|
||||
<div class='sub_title'>Window type:</div>
|
||||
<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>
|
||||
<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> <br>
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-5">Width of window: </label>
|
||||
<input type="number" step="any" id="window_width" class="non_zero disabled form-control col-sm-5" name="window_width" placeholder="meters" min="0" data-has-radio="#window_hinged"><br>
|
||||
<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="meters" min="0" data-has-radio="#window_hinged"><br></div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-5">Opening distance: </label>
|
||||
<input type="number" step="any" id="opening_distance" class="non_zero form-control col-sm-5" name="opening_distance" placeholder="meters" min="0"><br>
|
||||
<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="meters" 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 col-sm-3">Permanently</label><br>
|
||||
<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 col-sm-3">Periodically:</label> <br>
|
||||
<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>
|
||||
|
|
@ -198,11 +237,17 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
</div>
|
||||
|
||||
<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" class="col-form-label">No</label>
|
||||
<input type="radio" id="hepa_yes" name="hepa_option" value=1 onclick="require_fields(this)">
|
||||
<label for="hepa_yes" class="col-form-label">Yes</label>
|
||||
<input type="number" step="any" id="hepa_amount" class="non_zero disabled form-control col-sm-4" 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="(m³ / hour)" min="0" data-has-radio="#hepa_yes">
|
||||
</div>
|
||||
</div>
|
||||
<hr width="80%">
|
||||
|
||||
<b>Face masks:</b>
|
||||
|
|
@ -214,13 +259,13 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
|
||||
<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" required>
|
||||
<label for="mask_on">Yes</label>
|
||||
<input type="radio" id="mask_off" name="mask_wearing_option" value="mask_off" required checked="checked">
|
||||
<label for="mask_on">Yes</label>
|
||||
<input class="ml-2" type="radio" id="mask_off" name="mask_wearing_option" value="mask_off" required 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>
|
||||
<input type="radio" id="mask_type_ffp2" name="mask_type" value="FFP2" onclick="require_fields(this)">
|
||||
<label for="mask_type_1">Type 1</label>
|
||||
<input class="ml-2" type="radio" id="mask_type_ffp2" name="mask_type" value="FFP2" onclick="require_fields(this)">
|
||||
<label for="mask_type_ffp2">FFP2</label><br>
|
||||
<hr width="80%">
|
||||
|
||||
|
|
@ -234,33 +279,34 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
</div><br>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-5 col-form-label">Total number of occupants:</label>
|
||||
<input type="number" id="total_people" class="form-control col-sm-3" name="total_people" min=1 required>
|
||||
<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" min=1 required></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-5 col-form-label">Number of infected people: </label>
|
||||
<input type="number" id="infected_people" class="form-control col-sm-3" name="infected_people" min=1 value=1 required><br>
|
||||
<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>
|
||||
<hr width="80%">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-4">Activity type:</label>
|
||||
|
||||
<select id="activity_type" name="activity_type" class="form-control col-sm-5">
|
||||
<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>
|
||||
<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">Training</option>
|
||||
<option value="gym">Gym</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -269,11 +315,11 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
@ -285,7 +331,7 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<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>
|
||||
<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>
|
||||
|
|
@ -299,8 +345,9 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<hr width="80%">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="tabbed col-form-label col-sm-7">Which month is the event?</label>
|
||||
<select id="event_month" name="event_month" class="form-control col-sm-4" value="January" required>
|
||||
<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>
|
||||
|
|
@ -313,7 +360,8 @@ 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%">
|
||||
|
||||
|
|
@ -333,14 +381,14 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<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 type="radio" id="exposed_lunch_option_no" data-lunch-select="exposed" name="exposed_lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="exposed_lunch_option_no">No</label>
|
||||
<input type="radio" id="exposed_lunch_option_yes" data-lunch-select="exposed" name="exposed_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
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>
|
||||
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>
|
||||
|
|
@ -349,15 +397,15 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
|
||||
<!-- Coffee Options -->
|
||||
<div class="split">
|
||||
<div class="col-sm-5">
|
||||
Coffee Breaks:
|
||||
<div>
|
||||
Coffee Breaks:
|
||||
</div>
|
||||
<div class="col-sm-7">
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
@ -380,15 +428,15 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
<div class="breakBoxInfected" id="DIVinfected_breaks">
|
||||
<b>Infected person(s) breaks:</b>
|
||||
<div class="boxMargin">
|
||||
Lunch break:
|
||||
<input type="radio" id="infected_lunch_option_no" data-lunch-select="infected" name="infected_lunch_option" value=0 onclick="require_fields(this)">
|
||||
<label for="infected_lunch_option_no">No</label>
|
||||
<input type="radio" id="infected_lunch_option_yes" data-lunch-select="infected" name="infected_lunch_option" value=1 checked="checked" onclick="require_fields(this)">
|
||||
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>
|
||||
|
||||
<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">
|
||||
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>
|
||||
|
|
@ -397,15 +445,15 @@ v{{ calculator_version }} <span style="float:right; font-weight:bold">Please sen
|
|||
|
||||
<!-- Coffee Options -->
|
||||
<div class="split">
|
||||
<div class="col-sm-5">
|
||||
Coffee Breaks:
|
||||
<div>
|
||||
Coffee Breaks:
|
||||
</div>
|
||||
<div class="col-sm-7">
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
@ -491,8 +539,11 @@ 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">
|
||||
<button class="btn btn-primary bigButton" type="button" data-toggle="collapse" data-target="#collapseDisclaimer" aria-expanded="false" aria-controls="collapseDisclaimer">
|
||||
<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>
|
||||
|
|
@ -508,7 +559,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>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,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>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
{% 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">
|
||||
<strong>Not Acceptable:</strong>
|
||||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ body {
|
|||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: .1rem;
|
||||
box-shadow: 0 .5rem .5rem rgba(0,0,0,.5);
|
||||
/* box-shadow: 0 .5rem .5rem rgba(0,0,0,.5); */
|
||||
z-index: 1;
|
||||
background: rgb(42, 52, 66);
|
||||
}
|
||||
|
|
@ -64,14 +64,14 @@ body {
|
|||
padding: .2rem;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
/* .nav-link {
|
||||
color: rgb(255, 255, 255)!important;
|
||||
}
|
||||
|
||||
.nav-link.active,
|
||||
.nav-link:hover {
|
||||
color: rgb(45, 138, 241)!important;
|
||||
}
|
||||
} */
|
||||
|
||||
/*============= SPLIT =============*/
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ body {
|
|||
clear: both;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
/* width: 100%; */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -91,7 +91,17 @@ body {
|
|||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 6em;
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
#nat_vent_image {
|
||||
height: 10em;
|
||||
}
|
||||
|
||||
.cara_home_image {
|
||||
height: 18rem;
|
||||
padding: 1rem;
|
||||
border-radius: 1.25rem!important;
|
||||
}
|
||||
|
||||
.container {
|
||||
|
|
@ -107,12 +117,9 @@ body {
|
|||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.header-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.head-center {
|
||||
.paragraph-title {
|
||||
text-align: center;
|
||||
font-size: 2.75vh;
|
||||
}
|
||||
|
||||
.center {
|
||||
|
|
@ -185,10 +192,16 @@ footer img {
|
|||
margin: 1.5rem auto;
|
||||
}
|
||||
|
||||
/*============= REPORT =============*/
|
||||
#report_logo {
|
||||
height: 4em;
|
||||
margin: 1%;
|
||||
}
|
||||
|
||||
/*============= MEDIA QUERIES =============*/
|
||||
|
||||
/* Devices over 640px (xl) */
|
||||
@media screen and (min-width: 40em) {
|
||||
@media (min-width: 40em) {
|
||||
.split {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
|
@ -197,7 +210,7 @@ footer img {
|
|||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.header-text {
|
||||
.paragraph-title {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
|
@ -211,6 +224,36 @@ footer img {
|
|||
|
||||
.logo {
|
||||
float: left;
|
||||
height: 6em;
|
||||
}
|
||||
|
||||
.paragraph-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
#nat_vent_image {
|
||||
height: 15em;
|
||||
}
|
||||
|
||||
.header_text {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#report_logo {
|
||||
height: 6em;
|
||||
margin: 1%;
|
||||
}
|
||||
.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; }
|
||||
|
|
@ -224,11 +267,66 @@ footer img {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
.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:
|
||||
|
||||
|
|
|
|||
BIN
cara/apps/static/images/CARA_1_Vs3_Colour.jpg
Normal file
BIN
cara/apps/static/images/CARA_1_Vs3_Colour.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 954 KiB |
BIN
cara/apps/static/images/nat_vent_dimensions.png
Normal file
BIN
cara/apps/static/images/nat_vent_dimensions.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
|
|
@ -2,23 +2,23 @@
|
|||
|
||||
{% block main %}
|
||||
|
||||
<div class="container container--padding">
|
||||
<div class="container container--padding" style="word-wrap:break-word";>
|
||||
|
||||
<h1>Airborne Transmission of SARS-CoV-2</h1><br>
|
||||
<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>.
|
||||
<br><br>
|
||||
<h1>What is CARA?</h1><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>
|
||||
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 CERN Report: <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.
|
||||
|
|
@ -32,7 +32,7 @@ The methodology of the model is divided into three parts:
|
|||
</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>
|
||||
<br>
|
||||
<h1>What is the aim of CARA?</h1><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>
|
||||
|
|
@ -41,18 +41,17 @@ 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>Main Developers:</h1><br>
|
||||
<h1 class="paragraph-title">Main Developers:</h1><br>
|
||||
{{ text_blocks['Main Developers'] }}
|
||||
<br>
|
||||
<h2>Code Contributors:</h2><br>
|
||||
<h2 class="paragraph-title">Code Contributors:</h2><br>
|
||||
{{ text_blocks['Code Contributors'] }}
|
||||
<br>
|
||||
<h1>Acknowledgements:</h1><br>
|
||||
<h1 class="paragraph-title">Acknowledgements:</h1><br>
|
||||
{{ text_blocks['Acknowledgements'] }}
|
||||
<br>
|
||||
<a id="references_block" style="color:#2f4858"><h1>References:</h1></a><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>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
## 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="paragraph-title">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>
|
||||
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
## Code Contributors
|
||||
|
||||
<h5>Anna Efimova<sup>1</sup>, Anel Massalimova<sup>1</sup>, Cole Austin Coughlin<sup>1</sup></h5><br>
|
||||
<h4 class="paragraph-title">Anna Efimova<sup>1</sup>, Anel Massalimova<sup>1</sup>, Cole Austin Coughlin<sup>1</sup></h4>
|
||||
|
||||
<sup>1</sup>Summer Students programme, 2021, CERN<br>
|
||||
<sup>1</sup>Summer Students, CERN<br>
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
|
|
|
|||
|
|
@ -6,53 +6,68 @@
|
|||
<header class= "bg-light">
|
||||
<div class="container container--narrow container--padding">
|
||||
<img src="/static/images/cara_logo.200x200.png" class="logo">
|
||||
<h1 class="head-center"><b>CARA - </b> COVID Airborne Risk Assessment</h1>
|
||||
<h1 class="text-center h1-text"><b>CARA - </b> COVID Airborne Risk Assessment</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container container--padding">
|
||||
<h2 class="header-text">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 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>
|
||||
|
||||
<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 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>
|
||||
<hr width="95%">
|
||||
</div>
|
||||
|
||||
<h2 class="header-text">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 class="align-self-center">
|
||||
<img src="static/images/CARA_1_Vs3_Colour.jpg" class="cara_home_image">
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h3 class="header-text">Acknowledgements</h3><br>
|
||||
<p>
|
||||
We wish to thank CERN’s 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>
|
||||
<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="header-text">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>
|
||||
</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 CERN’s 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>
|
||||
{% endblock main %}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue