Merge branch 'feature/report_reformulation' into 'master'
Feature/report reformulation See merge request cara/cara!234
|
|
@ -33,7 +33,7 @@ from .user import AuthenticatedUser, AnonymousUser
|
|||
# calculator version. If the calculator needs to make breaking changes (e.g. change
|
||||
# form attributes) then it can also increase its MAJOR version without needing to
|
||||
# increase the overall CARA version (found at ``cara.__version__``).
|
||||
__version__ = "2.0.0"
|
||||
__version__ = "2.1.0"
|
||||
|
||||
|
||||
class BaseRequestHandler(RequestHandler):
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ def _img2bytes(figure):
|
|||
def _figure2bytes(figure):
|
||||
# Draw the image
|
||||
img_data = io.BytesIO()
|
||||
figure.savefig(img_data, format='png', bbox_inches="tight")
|
||||
figure.savefig(img_data, format='png', bbox_inches="tight", transparent=True)
|
||||
return img_data
|
||||
|
||||
|
||||
|
|
@ -388,7 +388,7 @@ class ReportGenerator:
|
|||
context['qr_code'] = generate_qr_code(base_url, self.calculator_prefix, form)
|
||||
context['calculator_prefix'] = self.calculator_prefix
|
||||
context['scale_warning'] = {
|
||||
'level': 'Yellow - 2',
|
||||
'level': 'yellow-2',
|
||||
'incidence_rate': 'lower than 25 new cases per 100 000 inhabitants',
|
||||
'onsite_access': 'of about 8000',
|
||||
'threshold': ''
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ h1 {
|
|||
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
font-size: 13pt;
|
||||
padding-bottom: 15pt;
|
||||
font-size: 17px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
p.data_italic {
|
||||
|
|
@ -35,20 +35,30 @@ p.data_subtext {
|
|||
|
||||
p.result_title {
|
||||
font-weight: bold;
|
||||
font-size: 15pt;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
p.image {
|
||||
text-align: center;
|
||||
font-size: 13pt;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
p.disclaimer {
|
||||
font-size: 12pt;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
p.notes {
|
||||
font-size: 10pt;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#cara_logo {
|
||||
height: 150px;
|
||||
margin: 1%
|
||||
}
|
||||
|
||||
#pdf-qr-code {
|
||||
margin-right: 1%;
|
||||
width: 100pt;
|
||||
}
|
||||
|
||||
.red_bkg {
|
||||
|
|
@ -69,19 +79,172 @@ p.notes {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
.warning_image_png {
|
||||
margin-bottom: 1rem;
|
||||
padding-left: 30px;
|
||||
border-radius: .25rem
|
||||
.icon_button {
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.warning_text {
|
||||
height:fit-content;
|
||||
align-self: center;
|
||||
margin-left: 5%
|
||||
.icon_button:focus {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
/* Flexbox layouts */
|
||||
.flex {
|
||||
display: flex;
|
||||
.nav-tabs .nav-item .nav-link.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-item .nav-link {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.tabs-div {
|
||||
margin: 1%;
|
||||
border: #DFDFDF 1px solid;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.print-button {
|
||||
margin-left: auto;
|
||||
margin-right: 1%;
|
||||
}
|
||||
|
||||
/* @media (width: 1200px) { */
|
||||
@media print {
|
||||
/* #body {
|
||||
min-width: 1200px;
|
||||
} */
|
||||
#results,
|
||||
#rules,
|
||||
#data {
|
||||
display: contents!important;
|
||||
}
|
||||
#link_reproduce_results {
|
||||
display: none!important;
|
||||
}
|
||||
#pdf-qr-code {
|
||||
visibility: inherit!important;
|
||||
}
|
||||
.collapse {
|
||||
display: block!important;
|
||||
}
|
||||
.tab-content {
|
||||
border-top: none!important;
|
||||
}
|
||||
.nav-tabs {
|
||||
display: none!important;
|
||||
}
|
||||
.tabs-div {
|
||||
border: none!important;
|
||||
}
|
||||
.icon_button {
|
||||
display: none!important;
|
||||
}
|
||||
.print-button {
|
||||
display: none!important;
|
||||
}
|
||||
.card {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
/* CSS styling to avoid page breaks. */
|
||||
.break-after {
|
||||
page-break-after: always;
|
||||
}
|
||||
.break-avoid {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* CSS for the animation */
|
||||
|
||||
.intro-banner-vdo-play-btn {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
border-radius: 100px;
|
||||
z-index: 1
|
||||
}
|
||||
|
||||
.intro-banner-vdo-play-btn i {
|
||||
line-height: 56px;
|
||||
font-size: 30px
|
||||
}
|
||||
|
||||
.intro-banner-vdo-play-btn .ripple {
|
||||
position: absolute;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
z-index: -1;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
opacity: 0;
|
||||
margin: -80px 0 0 -80px;
|
||||
border-radius: 100px;
|
||||
-webkit-animation: ripple 1.8s infinite;
|
||||
animation: ripple 1.8s infinite
|
||||
}
|
||||
|
||||
@-webkit-keyframes ripple {
|
||||
0% {
|
||||
opacity: 1;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0)
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1)
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
0% {
|
||||
opacity: 1;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0)
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1)
|
||||
}
|
||||
}
|
||||
|
||||
.intro-banner-vdo-play-btn .ripple:nth-child(2) {
|
||||
animation-delay: .3s;
|
||||
-webkit-animation-delay: .3s
|
||||
}
|
||||
|
||||
.intro-banner-vdo-play-btn .ripple:nth-child(3) {
|
||||
animation-delay: .6s;
|
||||
-webkit-animation-delay: .6s
|
||||
}
|
||||
|
||||
.split {
|
||||
/* flex: 1; */
|
||||
clear: both;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 40em) {
|
||||
.split {
|
||||
flex-direction: row;
|
||||
}
|
||||
.split>* {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
.header-text {
|
||||
text-align: left;
|
||||
}
|
||||
.split>*+* {
|
||||
margin-left: 2em;
|
||||
}
|
||||
.bigButton {
|
||||
width: 25%;
|
||||
}
|
||||
.logo {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
29
cara/apps/calculator/static/js/pdf.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
function generate_pdf_version(qr_link) {
|
||||
const pdf_version = this.document.getElementById("body");
|
||||
|
||||
// PDF styling
|
||||
var opt = {
|
||||
filename: 'myfile.pdf',
|
||||
image: { type: 'jpeg', quality: 0.98 },
|
||||
html2canvas: { scale: 2, width: 1200, windowWidth: 1200 },
|
||||
enableLinks: false,
|
||||
jsPDF: {
|
||||
unit: 'pt',
|
||||
format: 'letter',
|
||||
orientation: 'portrait',
|
||||
},
|
||||
pagebreak: { mode: '', avoid: '.break-avoid' },
|
||||
};
|
||||
html2pdf().set(opt).from(pdf_version).toPdf().get('pdf').then(function(pdf) {
|
||||
var totalPages = pdf.internal.getNumberOfPages();
|
||||
pdf.setPage(1);
|
||||
pdf.link(530, 25, 60, 60, { url: qr_link }); //Hyperlink to reproduce results
|
||||
|
||||
for (i = 1; i <= totalPages; i++) {
|
||||
pdf.setPage(i);
|
||||
pdf.setFontSize(10);
|
||||
pdf.setTextColor(150);
|
||||
pdf.text('Page ' + i + ' of ' + totalPages, (pdf.internal.pageSize.getWidth() / 2.25), (pdf.internal.pageSize.getHeight() - 10));
|
||||
}
|
||||
}).save();
|
||||
};
|
||||
|
|
@ -26,11 +26,11 @@ function draw_concentration_plot(svg_id, times, concentrations, exposed_presence
|
|||
|
||||
// Plot tittle.
|
||||
vis.append('svg:foreignObject')
|
||||
.attr("background-color", "transparent")
|
||||
.attr('width', width)
|
||||
.attr('height', margins.top)
|
||||
.append('xhtml:body')
|
||||
.style('text-align', 'center')
|
||||
.html('Mean concentration of virions');
|
||||
.html('<b>Mean concentration of virions</b>');
|
||||
|
||||
// Line representing the mean concentration.
|
||||
var lineFunc = d3.line()
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
<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">
|
||||
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
<script src="{{ calculator_prefix }}/static/js/report.js" type="application/javascript"></script>
|
||||
|
||||
|
|
@ -18,27 +17,174 @@
|
|||
|
||||
{% block report_header %}
|
||||
|
||||
<div style="position:relative; text-align:center; margin-left:-200pt; max-height:180pt; margin-bottom: 1em;">
|
||||
<img src="/static/images/cara_logo_text.png" style="height:150px; display:inline-block; vertical-align:middle; object-fit:cover;">
|
||||
<h1 style="display:inline; vertical-align:middle; margin-left:1em;">Report</h1>
|
||||
<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>
|
||||
<button type="button" class="btn btn-outline-dark align-self-center" style="margin-right: -100pt" id="download-pdf" onclick="print()">Print Report</button>
|
||||
{# To be replaced by "Generate PDF" #}
|
||||
<img id="pdf-qr-code" class="align-self-center invisible" src="{{ qr_code.image }}"/>
|
||||
</div>
|
||||
|
||||
<p class=subtitle> Created {{ creation_date }} using CARA calculator version v{{ form.calculator_version }}</p><br>
|
||||
|
||||
{% endblock report_header %}
|
||||
|
||||
<div class="tabs-div">
|
||||
<ul class="nav nav-tabs" role="tablist" style="margin: 0.5% 0% 0% 1%">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="results-tab" data-toggle="tab" href="#results" role="tab" aria-controls="results" aria-selected="true">Results</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="data-tab" data-toggle="tab" href="#data" role="tab" aria-controls="data" aria-selected="false">Input Data</a>
|
||||
</li>
|
||||
{% block report_preamble_navtab %}
|
||||
{% endblock report_preamble_navtab %}
|
||||
</ul>
|
||||
|
||||
{% block report_preamble %}
|
||||
<div class="tab-content" style="border-top: #dee2e6 1px solid; margin-top: -1px" >
|
||||
|
||||
{% endblock report_preamble %}
|
||||
<div class="tab-pane show active" id="results" role="tabpanel" aria-labelledby="results-tab" style="padding: 1%">
|
||||
|
||||
{% block report_results %}
|
||||
<div class="card bg-light mb-3" id="results-div">
|
||||
<div class="card-header"><strong>Results </strong>
|
||||
<button class="icon_button p-0 float-right" data-toggle="collapse" href="#collapseResults" role="button" aria-expanded="true" aria-controls="collapseResults">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-expand" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="collapse show" id="collapseResults">
|
||||
<div class="card-body">
|
||||
<p class="card-text">
|
||||
<div class="align-self-center">
|
||||
<div class="d-flex">
|
||||
|
||||
<div style="min-width: 25%">
|
||||
<div style="text-align:center"><b>Probability of infection (%)</b></div>
|
||||
<div class="d-flex" style="min-height: 160px">
|
||||
{% block warning_animation %}
|
||||
<div class="intro-banner-vdo-play-btn bg-secondary m-auto d-flex align-items-center justify-content-center">
|
||||
<b>{{prob_inf | non_zero_percentage}}</b>
|
||||
<i class="glyphicon glyphicon-play whiteText" aria-hidden="true"></i>
|
||||
<span class="ripple bg-secondary"></span>
|
||||
<span class="ripple bg-secondary"></span>
|
||||
<span class="ripple bg-secondary"></span>
|
||||
</div>
|
||||
{% endblock warning_animation %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block report_summary %}
|
||||
<div class="align-self-center alert alert-dark" role="alert">
|
||||
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
|
||||
</div>
|
||||
{% endblock report_summary %}
|
||||
</div>
|
||||
{% 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>
|
||||
<script type="application/javascript">
|
||||
var times = {{times}}
|
||||
var concentrations = {{concentrations}}
|
||||
var exposed_presence_intervals = {{exposed_presence_intervals}}
|
||||
draw_concentration_plot("#result_plot", times, concentrations, exposed_presence_intervals);
|
||||
</script>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header"><strong>Alternative scenarios</strong>
|
||||
<button class="icon_button p-0 float-right" data-toggle="collapse" href="#collapseAlternativeScenarios" role="button" aria-expanded="false" aria-controls="collapseAlternativeScenarios">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-expand" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="collapse" id="collapseAlternativeScenarios">
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<img id="scenario_concentration_plot" src="{{ alternative_scenarios.plot }}" />
|
||||
|
||||
{% block report_scenarios_summary_table %}
|
||||
<table class="table w-auto">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>Scenario</th>
|
||||
<th>P(I)</th>
|
||||
<th>Expected new cases</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for scenario_name, scenario_stats in alternative_scenarios.stats.items() %}
|
||||
<tr>
|
||||
<td> {{ scenario_name }}</td>
|
||||
<td> {{ scenario_stats.probability_of_infection | non_zero_percentage }}</td>
|
||||
<td style="text-align:right">{{ scenario_stats.expected_new_cases | float_format }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock report_scenarios_summary_table %}
|
||||
</div>
|
||||
<br/>
|
||||
<p class="data_text"> <strong> Notes for alternative scenarios: </strong><br>
|
||||
<ol>
|
||||
<li>This graph shows the concentration of infectious quanta in the air. The filtration of Type I and FFP2 masks, if worn, applies not only to the emission rate but also to the individual exposure (i.e. inhalation).
|
||||
For this reason, scenarios with different types of mask will show the same concentration on the graph but have different absorbed doses and infection probabilities.</li>
|
||||
<li>If you have selected more sophisticated options, such as HEPA filtration or FFP2 masks, this will be indicated in the plot as the "base scenario", representing the inputs inserted in the form.<br>
|
||||
The other alternative scenarios shown for comparison will not include either HEPA filtration or FFP2 masks.</li>
|
||||
</ol>
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock report_results %}
|
||||
|
||||
{% block report_footer %}
|
||||
<div class="card bg-light mb-3" id="link_reproduce_results">
|
||||
<div class="card-header"><strong>Link to reproduce results </strong>
|
||||
<button class="icon_button p-0 float-right" data-toggle="collapse" href="#collapseQRcode" role="button" aria-expanded="true" aria-controls="collapseQRcode">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-expand" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="collapse show" id="collapseQRcode">
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<a href="{{ qr_code.link }}" style="float: left;"><img style="width:250pt;" id="qr_code" src="{{ qr_code.image }}"/></a>
|
||||
<span style="float: left; min-height: 250pt; line-height: 250pt; vertical-align: middle; display: inline-block;">
|
||||
<p style="display: inline-block; vertical-align: middle; line-height: normal;">
|
||||
Click the QR code to regenerate the report and get a shareable link.<br>Alternatively, scan to regenerate the report.<br> Mobile-friendly app coming soon!
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
{% endblock report_footer %}
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="data" role="tabpanel" aria-labelledby="data-tab" style="padding: 1%">
|
||||
{% block simulation_overview %}
|
||||
<p><strong>Simulation:</strong></p>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header"><strong>Simulation:</strong></div>
|
||||
<div class="card-body">
|
||||
<p>Simulation Name: {{ form.simulation_name }}</p>
|
||||
<p>Room Number: {{ form.room_number }}</p>
|
||||
|
||||
<p class="data_title">Input data:</p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="card">
|
||||
<div class="card-header"> <strong>Input data:</strong></div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><p class="data_text">Virus variant:
|
||||
{% if form.virus_type == "SARS_CoV_2" %}
|
||||
|
|
@ -46,7 +192,7 @@
|
|||
{% elif form.virus_type == "SARS_CoV_2_B117" %}
|
||||
<a href="https://www.ecdc.europa.eu/en/publications-data/covid-19-risk-assessment-spread-new-sars-cov-2-variants-eueea">SARS-CoV-2 (Alpha VOC) </a>
|
||||
{% elif form.virus_type == "SARS_CoV_2_P1" %}
|
||||
<a href="https://github.com/CADDE-CENTRE/Novel-SARS-CoV-2-P1-Lineage-in-Brazil/blob/main/manuscript/FINAL_P1_MANUSCRIPT_25-02-2021_combined.pdf">SARS-CoV-2 (Gamma VOC)</a>
|
||||
<a href="https://doi.org/10.1126/science.abh2644">SARS-CoV-2 (Gamma VOC)</a>
|
||||
{% elif form.virus_type == "SARS_CoV_2_B16172" %}
|
||||
<a href="https://www.bmj.com/content/373/bmj.n1513">SARS-CoV-2 (Delta VOC)</a>
|
||||
{% endif %}
|
||||
|
|
@ -54,8 +200,12 @@
|
|||
<li><p class="data_text">Room Volume: {{ model.concentration_model.room.volume }} m³</p></li>
|
||||
<li><p class="data_text">Room Central Heating: {{ "On" if form.room_heating_option else "Off" }}</p></li>
|
||||
</ul>
|
||||
|
||||
<p class="data_title">Ventilation data:</p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="card">
|
||||
<div class="card-header"><strong>Ventilation data:</strong></div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><p class="data_text">Mechanical ventilation:
|
||||
{% if form.ventilation_type == "mechanical_ventilation" %}
|
||||
|
|
@ -106,8 +256,12 @@
|
|||
</ul>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<p class="data_title">Event data:</p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="card">
|
||||
<div class="card-header"><strong>Event data:</strong></div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><p class="data_text">Number of attendees and infected people: {{ form.total_people }} in attendance, of whom {{ form.infected_people }}
|
||||
{{ "is" if form.infected_people == 1 else "are" }}
|
||||
|
|
@ -146,8 +300,12 @@
|
|||
</ul>
|
||||
<li><p class="data_text">Event for the month of {{ form.event_month }}</p></li>
|
||||
</ul>
|
||||
|
||||
<p class="data_title">Break data:</p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="card">
|
||||
<div class="card-header"><strong>Break data:</strong></div>
|
||||
<div class="card-body">
|
||||
{% if form.infected_dont_have_breaks_with_exposed %}
|
||||
<p style="padding-left:15px;"> Exposed occupant(s):</p>
|
||||
{% endif %}
|
||||
|
|
@ -173,9 +331,9 @@
|
|||
</ul>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
{% if form.infected_dont_have_breaks_with_exposed %}
|
||||
<p style="padding-left:15px;"> Infected occupant(s):</p>
|
||||
|
||||
<ul>
|
||||
<li><p class="data_text">Lunch break:
|
||||
{% if form.infected_lunch_option%}
|
||||
|
|
@ -198,85 +356,30 @@
|
|||
</ul>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<i>Same breaks taken by the exposed and infected persons.</i>
|
||||
{% endif %}
|
||||
|
||||
<p class="data_title">Mask wearing:</p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="card">
|
||||
<div class="card-header"><strong>Mask wearing:</strong></div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><p class="data_text">Masks worn at workstations? {{ 'Yes' if form.mask_wearing_option == "mask_on" else 'No' }} </p></li>
|
||||
{% if form.mask_wearing_option == "mask_on" %}
|
||||
<li><p class="data_text">Mask type: {{ form.mask_type }}</p></li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
|
||||
{% endblock simulation_overview %}
|
||||
|
||||
{% block report_results %}
|
||||
<p class="result_title">Results:</p>
|
||||
<p class="data_text">
|
||||
{% block report_summary %}
|
||||
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><a href="#section1">[*]</a> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>.
|
||||
{% endblock report_summary %}
|
||||
<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>
|
||||
</p>
|
||||
|
||||
<svg id="result_plot" width="900" height="400"></svg>
|
||||
<script type="application/javascript">
|
||||
var times = {{times}}
|
||||
var concentrations = {{concentrations}}
|
||||
var exposed_presence_intervals = {{exposed_presence_intervals}}
|
||||
draw_concentration_plot("#result_plot", times, concentrations, exposed_presence_intervals);
|
||||
</script>
|
||||
|
||||
<p class="data_title">Alternative scenarios:</p>
|
||||
<p class="data_text">
|
||||
<img id="scenario_concentration_plot" src="{{ alternative_scenarios.plot }}" align="left" />
|
||||
|
||||
{% block report_scenarios_summary_table %}
|
||||
<table class="table w-auto">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>Scenario</th>
|
||||
<th>P(I)</th>
|
||||
<th>Expected new cases</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for scenario_name, scenario_stats in alternative_scenarios.stats.items() %}
|
||||
<tr>
|
||||
<td> {{ scenario_name }}</td>
|
||||
<td> {{ scenario_stats.probability_of_infection | non_zero_percentage }}</td>
|
||||
<td style="text-align:right">{{ scenario_stats.expected_new_cases | float_format }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock report_scenarios_summary_table %}
|
||||
</p>
|
||||
<div style="clear: both;">
|
||||
|
||||
<p class="data_text"> <strong> Notes for alternative scenarios: </strong><br>
|
||||
<ol>
|
||||
<li>This graph shows the concentration of virions in the air. The filtration of Type I and FFP2 masks, if worn, applies not only to the emission rate but also to the individual exposure (i.e. inhalation).
|
||||
For this reason, scenarios with different types of mask will show the same concentration on the graph but have different absorbed doses and infection probabilities.</li>
|
||||
<li>If you have selected more sophisticated options, such as HEPA filtration or FFP2 masks, alternatives will be indicated in the plot as the "base scenario with/without...", representing a variation on the inputs inserted in the form.<br>
|
||||
The other alternative scenarios shown for comparison will not include either HEPA filtration or FFP2 masks.</li>
|
||||
</ol>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
{% endblock report_results %}
|
||||
|
||||
{% block report_footer %}
|
||||
<div>
|
||||
<a href="{{ qr_code.link }}" style="float: left;"><img style="width:250pt;" id="qr_code" src="{{ qr_code.image }}"/></a>
|
||||
<span style="float: left; min-height: 250pt; line-height: 250pt; vertical-align: middle; display: inline-block;">
|
||||
<p style="display: inline-block; vertical-align: middle; line-height: normal;">
|
||||
Click the QR code to regenerate the report and get a shareable link.<br>Alternatively, scan to regenerate the report.<br> Mobile-friendly app coming soon!
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
<br>
|
||||
{% endblock simulation_overview %}
|
||||
</div>
|
||||
{% block report_preamble %}
|
||||
{% endblock report_preamble %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block disclaimer_container %}
|
||||
<br><br><br>
|
||||
|
|
@ -288,7 +391,7 @@
|
|||
CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
|
||||
</p>
|
||||
<p>
|
||||
CARA models the concentration profile of potential virions in enclosed spaces with clear and intuitive graphs.
|
||||
CARA models the concentration profile of potential infectious viruses in enclosed spaces with clear and intuitive graphs.
|
||||
The user can set a number of parameters, including room volume, exposure time, activity type, mask-wearing and ventilation.
|
||||
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>
|
||||
|
|
@ -321,6 +424,12 @@
|
|||
{% endblock disclaimer %}
|
||||
</div>
|
||||
{% endblock disclaimer_container %}
|
||||
{% endblock report_footer %}
|
||||
|
||||
<script src="{{ calculator_prefix }}/static/js/pdf.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,60 +1,72 @@
|
|||
{% extends "base/calculator.report.html.j2" %}
|
||||
|
||||
{% block report_preamble_navtab %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="rules-tab" data-toggle="tab" href="#rules" role="tab" aria-controls="rules" aria-selected="false">Applicable Rules</a>
|
||||
</li>
|
||||
{% endblock report_preamble_navtab %}
|
||||
|
||||
{% block report_preamble %}
|
||||
<p><strong>Applicable rules: <br>
|
||||
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):
|
||||
<ul><li>Events with a <span class="green_bkg">P(i) less than 5%</span> may go ahead without further mitigation measures.</li>
|
||||
<li>Events with a <span class="yellow_bkg">P(i) between 5% and 15%</span> shall be subject to ALARA principles (see footnote) to minimise the risk before proceeding.</li>
|
||||
<li>Events with a <span class="red_bkg">P(i) exceeding 15% or a number of expected new cases that exceeds 1</span> may not take place until additional measures are in place and a risk reduction has been performed.</li>
|
||||
</ul>
|
||||
</p>
|
||||
{% endblock report_preamble %}
|
||||
{% block warning_animation %}
|
||||
{% if ((prob_inf > 15) or (expected_new_cases >= 1)) %} {% set warning_color= 'bg-danger' %}
|
||||
{% elif (5 <= prob_inf <= 15) %} {% set warning_color = 'bg-warning' %}
|
||||
{% elif (prob_inf < 5) %} {% set warning_color = 'bg-success' %}
|
||||
{% endif %}
|
||||
|
||||
<div class="intro-banner-vdo-play-btn {{warning_color}} m-auto d-flex align-items-center justify-content-center">
|
||||
<b>{{prob_inf | non_zero_percentage}}</b>
|
||||
<i class="glyphicon glyphicon-play whiteText" aria-hidden="true"></i>
|
||||
<span class="ripple {{warning_color}}"></span>
|
||||
<span class="ripple {{warning_color}}"></span>
|
||||
<span class="ripple {{warning_color}}"></span>
|
||||
</div>
|
||||
{% endblock warning_animation %}
|
||||
|
||||
{% block report_summary %}
|
||||
<span
|
||||
<div class="flex-row w-75 align-self-center">
|
||||
{% if ((prob_inf > 15) or (expected_new_cases >= 1)) %}
|
||||
class="red_bkg"><strong>Not Acceptable:</strong>
|
||||
{% elif 5 <= prob_inf <= 15 %}
|
||||
class="yellow_bkg"><strong> Attention:</strong>
|
||||
{% elif prob_inf < 5 %}
|
||||
class="green_bkg">Acceptable:
|
||||
{% endif %}
|
||||
</span>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<strong>Not Acceptable:</strong>
|
||||
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
|
||||
|
||||
{{ super() }}
|
||||
</div>
|
||||
{% elif 5 <= prob_inf <= 15 %}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<strong>Attention:</strong>
|
||||
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
|
||||
</div>
|
||||
{% elif prob_inf < 5 %}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<strong>Acceptable:</strong>
|
||||
Taking into account the uncertainties tied to the model variables, in this scenario, the <b>probability of one exposed occupant getting infected is {{ prob_inf | non_zero_percentage }}</b> and the <b>expected number of new cases is {{ expected_new_cases | float_format }}</b>*.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if (prob_inf > 5) %}
|
||||
<div class="flex" style="width:60%; align-self:center">
|
||||
{% if scale_warning.level == "Green - 1" %}
|
||||
<img class="warning_image_png" src="{{ calculator_prefix }}/static/images/warning_scale/Level1.png">
|
||||
<div class="alert alert-dark warning_text" role="alert">
|
||||
{% if scale_warning.level == "green-1" %}
|
||||
<div class="alert alert-dark" role="alert" style="height:fit-content">
|
||||
Note: the current CERN COVID Scale is <b>Green - 1</b>, which means the incidence rate in the local community is <b>{{scale_warning.incidence_rate}}</b>. Align your risk assessment with the guidance and instructions provided by the HSE Unit.
|
||||
</div>
|
||||
{% elif scale_warning.level == "Yellow - 2" %}
|
||||
<img class="warning_image_png" src="{{ calculator_prefix }}/static/images/warning_scale/Level2.png">
|
||||
<div class="alert alert-dark warning_text" role="alert">
|
||||
{% elif scale_warning.level == "yellow-2" %}
|
||||
<div class="alert alert-dark" role="alert" style="height:fit-content">
|
||||
Note: the current CERN COVID Scale is <b>Yellow - 2</b>, which means the incidence rate in the local community is <b>{{scale_warning.incidence_rate}}</b>. There is a reduced chance that asymptomatic or pre-symptomatic infected individuals circulate within the CERN site which, during this stage, corresponds to an average daily on-site access {{scale_warning.onsite_access}}. See with your supervisor if this scenario is acceptable.
|
||||
</div>
|
||||
{% elif scale_warning.level == "Orange - 3" %}
|
||||
<img class="warning_image_png" src="{{ calculator_prefix }}/static/images/warning_scale/Level3.png">
|
||||
<div class="alert alert-dark warning_text" role="alert">
|
||||
{% elif scale_warning.level == "orange-3" %}
|
||||
<div class="alert alert-dark" role="alert" style="height:fit-content">
|
||||
Warning: the current CERN COVID Scale is <b>Orange - 3</b>, which means the incidence rate in the local community is <b>{{scale_warning.incidence_rate}}</b>. There is a slight chance that asymptomatic or pre-symptomatic infected individuals circulate within the CERN site which, during this stage, corresponds to an average daily on-site access {{scale_warning.onsite_access}}. See with your supervisor if any additional measures can be applied (ALARA).
|
||||
</div>
|
||||
{% elif scale_warning.level == "Red - 4" %}
|
||||
<img class="warning_image_png" src="{{ calculator_prefix }}/static/images/warning_scale/Level4.png">
|
||||
<div class="alert alert-dark warning_text" role="alert">
|
||||
{% elif scale_warning.level == "red-4" %}
|
||||
<div class="alert alert-dark" role="alert" style="height:fit-content">
|
||||
Warning: the current CERN COVID Scale is <b>Red - 4</b>, which means the incidence rate in the local community is <b>{{scale_warning.incidence_rate}}</b>. There is a strong chance that asymptomatic or pre-symptomatic infected individuals circulate within the CERN site which, during this stage, corresponds to an average daily on-site access {{scale_warning.onsite_access}}. Please reduce the value below the threshold of <b>{{scale_warning.threshold}}</b>.
|
||||
</div>
|
||||
{% else %}
|
||||
<p><b>Note:</b> The CERN COVID Level is not specified.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock report_summary %}
|
||||
|
||||
{% block report_summary_footnote %}
|
||||
{% if ((prob_inf > 15) or (expected_new_cases >= 1)) %}
|
||||
This exceeds the authorised risk threshold or number of expected new cases.
|
||||
The risk level must be reduced before this activity can be undertaken.
|
||||
|
|
@ -64,11 +76,10 @@
|
|||
{% elif (prob_inf < 5) %}
|
||||
This level of risk is within acceptable parameters, no further actions are required.
|
||||
{% endif %}
|
||||
{% endblock report_summary %}
|
||||
|
||||
{% endblock report_summary_footnote %}
|
||||
|
||||
{% block report_scenarios_summary_table %}
|
||||
<table class="table w-auto">
|
||||
<table class="table w-auto" style="height: fit-content;">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>Scenario</th>
|
||||
|
|
@ -94,8 +105,31 @@
|
|||
</table>
|
||||
{% endblock report_scenarios_summary_table %}
|
||||
|
||||
|
||||
{% block report_footer %}
|
||||
{% block report_preamble %}
|
||||
<div class="tab-pane" id="rules" role="tabpanel" aria-labelledby="rules-tab" style="padding: 1%">
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header"><strong>Applicable rules </strong>
|
||||
<button class="icon_button p-0 float-right" data-toggle="collapse" href="#collapseRules" role="button" aria-expanded="true" aria-controls="collapseRules">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-expand" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="collapse show" id="collapseRules">
|
||||
<div class="card-body">
|
||||
<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>
|
||||
<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>
|
||||
<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">
|
||||
<strong> Footnotes for ALARA: </strong><br>
|
||||
ALARA stands for As Low As Reasonably Achievable. It can be summarised based on 3 main points:
|
||||
|
|
@ -105,10 +139,17 @@
|
|||
<li>Optimisation - the personal doses and collective doses have to be kept as low as reasonably achievable (ALARA).</li>
|
||||
</ol>
|
||||
For more information, please refer to <a href="https://cds.cern.ch/record/1533023/files/CERN-2013-001-p415.pdf"> this document from CERN HSE </a> and <a href="https://www.cdc.gov/nceh/radiation/safety.html#:~:text=ALARA%20stands%20for%20%E2%80%9Cas%20low,time%2C%20distance%2C%20and%20shielding."> this publication from the CDC.</a>
|
||||
<br><br>
|
||||
<br>
|
||||
</p>
|
||||
{{ super() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="break-avoid fourth_page"></div>
|
||||
{% endblock report_preamble %}
|
||||
|
||||
{% block report_footer %}
|
||||
{{ super() }}
|
||||
{% endblock report_footer %}
|
||||
|
||||
{% block disclaimer %}
|
||||
|
|
@ -118,6 +159,5 @@
|
|||
</p>
|
||||
{% endblock disclaimer %}
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||