diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..de49c2af --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2020-2021 CERN. All rights not expressly granted are reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md index be1f81f9..fd0c2584 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,62 @@ # CARA - COVID Airborne Risk Assessment +CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions. + +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. + +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 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. + +The model used is based on scientific publications relating to airborne transmission of infectious diseases, dose-response exposures and aerosol science, as of February 2021. +It can be used to compare the effectiveness of different airborne-related risk mitigation measures. + +Note that this model applies a deterministic approach, i.e., it is assumed at least one person is infected and shedding viruses into the simulated volume. +Nonetheless, it is also important to understand that the absolute risk of infection is uncertain, as it will depend on the probability that someone infected attends the event. +The model is most useful for comparing the impact and effectiveness of different mitigation measures such as ventilation, filtration, exposure time, physical activity and +the size of the room, only considering long-range airborne transmission of COVID-19 in indoor settings. + +This tool is designed to be informative, allowing the user to adapt different settings and model the relative impact on the estimated infection probabilities. +The objective is to facilitate targeted decision-making and investment through comparisons, rather than a singular determination of absolute risk. +While the SARS-CoV-2 virus is in circulation among the population, the notion of 'zero risk' or 'completely safe scenario' does not exist. +Each event modelled is unique, and the results generated therein are only as accurate as the inputs and assumptions. + +## Authors +CARA was developed by following members of CERN - European Council for Nuclear Research (visit https://home.cern/): + +Andre Henriques1, Marco Andreini1, Gabriella Azzopardi2, James Devine3, Philip Elson4, Nicolas Mounet2, Markus Kongstein Rognlien2,6, Nicola Tarocco5 + +1HSE Unit, Occupational Health & Safety Group, CERN
+2Beams Department, Accelerators and Beam Physics Group, CERN
+3Experimental Physics Department, Safety Office, CERN
+4Beams Department, Controls Group, CERN
+5Information Technology Department, Collaboration, Devices & Applications Group, CERN
+6Norwegian University of Science and Technology
+ +###citation +A. Henriques, M. Andreini, G. Azzopardi, J. Devine, P. Elson, N. Mounet, M. Kongstein, N. Tarocco. CARA - COVID Airborne Risk Assessment tools. CERN (2021). + + ## Applications ### COVID Calculator -A risk assessment tool which simulates the long range airborne spread of the -SARS-CoV-2 virus for space managers. +A risk assessment tool which simulates the long range airborne spread of the SARS-CoV-2 virus for space managers. -You can find the CARA COVID Calculator at https://cara.web.cern.ch/calculator/. -Please see the [COVID Calculator README for detailed usage instructions](cara/apps/calculator/README.md). ### CARA Expert App A tool to interact with various parameters of the CARA model. -This is currently in beta, and can be found at https://cara.web.cern.ch/expert-app. ## Disclaimer -The code and data of this repository are provided to promote reproducible research. -They are not intended for clinical care or commercial use. +CARA has not undergone review, approval or certification by competent authorities, and as a result, it cannot be considered as a fully endorsed and reliable tool, namely in the assessment of potential viral emissions from infected hosts to be modelled. -The software is provided "as is", without warranty of any kind, express or implied, -including but not limited to the warranties of merchantability, fitness for a particular -purpose and non infringement. -In no event shall the authors or copyright holders be liable for any claim, damages -or other liability, whether in an action of contract, tort or otherwise, arising from, -out of or in connection with the software or the use or other dealings in the software. +The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and non-infringement. +In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software. ## Development guide diff --git a/app/cara.ipynb b/app/cara.ipynb index 967bcbbc..01ac0106 100644 --- a/app/cara.ipynb +++ b/app/cara.ipynb @@ -8,7 +8,9 @@ "\n", "

\n", "Airborne Transmission of SARS-CoV-2\n", - "

" + "

\n", + "

\n", + "Please see the CARA homepage for details on the methodology, assumptions and limitations of CARA.

" ] }, { diff --git a/cara/__init__.py b/cara/__init__.py index 63a84eb4..8f9d169f 100644 --- a/cara/__init__.py +++ b/cara/__init__.py @@ -1,3 +1,5 @@ +# This module is part of CARA. Please see the repository at +# https://gitlab.cern.ch/cara/cara for details of the license and terms of use. """ Documentation for the CARA package diff --git a/cara/apps/calculator/__init__.py b/cara/apps/calculator/__init__.py index 25c680a0..adcfb7f6 100644 --- a/cara/apps/calculator/__init__.py +++ b/cara/apps/calculator/__init__.py @@ -1,3 +1,6 @@ +# This module is part of CARA. Please see the repository at +# https://gitlab.cern.ch/cara/cara for details of the license and terms of use. + import datetime import base64 import html @@ -12,6 +15,7 @@ import zlib import jinja2 from tornado.web import Application, RequestHandler, StaticFileHandler +from . import markdown_tools from . import model_generator from .report_generator import ReportGenerator from .user import AuthenticatedUser, AnonymousUser @@ -183,6 +187,10 @@ def make_app( loader=loader, ) + template_environment.globals['common_text'] = markdown_tools.extract_rendered_markdown_blocks( + template_environment.get_template('common_text.md.j2') + ) + return Application( urls, debug=debug, diff --git a/cara/apps/calculator/__main__.py b/cara/apps/calculator/__main__.py index 1b9bcce2..0cfafe66 100644 --- a/cara/apps/calculator/__main__.py +++ b/cara/apps/calculator/__main__.py @@ -6,7 +6,7 @@ from tornado.ioloop import IOLoop from . import make_app -def configure_parser(parser): +def configure_parser(parser) -> argparse.ArgumentParser: parser.add_argument( "--no-debug", help="Don't enable debug mode", action="store_false", @@ -20,8 +20,7 @@ def configure_parser(parser): def main(): - parser = argparse.ArgumentParser() - configure_parser(parser) + parser = configure_parser(argparse.ArgumentParser()) args = parser.parse_args() theme_dir = args.theme if theme_dir is not None: diff --git a/cara/apps/calculator/markdown_tools.py b/cara/apps/calculator/markdown_tools.py new file mode 100644 index 00000000..ba964d5c --- /dev/null +++ b/cara/apps/calculator/markdown_tools.py @@ -0,0 +1,73 @@ +import re + +import jinja2 +import mistune + + +HEADER_PATTERN = re.compile(r'\n(#+)(.*)') + + +def _block_headings(contents: str): + """ + Return the headings (and the start/end positions of their blocks) of + markdown, in reverse order. + + Note that a block ends when the next heading is found, even if that heading + is a sub-block of the current one. + + """ + all_block_headings = HEADER_PATTERN.finditer( + '\n' + contents, re.MULTILINE & re.DOTALL + ) + + end_pos = None + for result in list(all_block_headings)[::-1]: + heading = { + 'start_pos': result.end(), + 'end_pos': end_pos, + 'depth': len(result[1]), + 'heading': result[2].strip(), + } + end_pos = result.start() + yield heading + + +def extract_block(block_name: str, contents: str) -> str: + """ + Extract the given header block from the given markdown. + + The result *does not* contain the children headers of the block. + + """ + for block in _block_headings(contents): + if block['heading'] == block_name: + return contents[block['start_pos']: block['end_pos']] + else: + raise ValueError(f"Heading \"{ block_name }\" not found") + + +def extract_headings(contents: str) -> list: + """ + Extract all headers from the given markdown. + + """ + headings = [] + for block in _block_headings(contents): + headings.append(block['heading']) + return headings + + +def extract_rendered_markdown_blocks(template: jinja2.Template) -> dict: + """ + Return a dictionary of all common markdown text blocks, rendered to HTML and + uniquely identified by their headings, from the given Jinja2 template. + + """ + common_text = template.render() + headings = extract_headings(common_text) + text_blocks = {} + for heading in headings: + block = extract_block(heading, common_text) + html_content = mistune.markdown(block, escape=False) + text_blocks[heading] = html_content + return text_blocks diff --git a/cara/apps/calculator/model_generator.py b/cara/apps/calculator/model_generator.py index 6c545152..006ec25c 100644 --- a/cara/apps/calculator/model_generator.py +++ b/cara/apps/calculator/model_generator.py @@ -458,14 +458,10 @@ class FormData: present_intervals = [] - def hours2time(hours: float): - # Convert times like 14.5 to strings, like "14:30" - return f"{int(np.floor(hours)):02d}:{int(np.round((hours % 1) * 60)):02d}" - # def add_interval(start, end): current_time = start - LOG.debug(f"starting time march at {hours2time(current_time/60)} to {hours2time(finish/60)}") + LOG.debug(f"starting time march at {_hours2timestring(current_time/60)} to {_hours2timestring(finish/60)}") # As we step through the breaks. For each break there are 6 important cases # we must cover. Let S=start; E=end; Bs=Break start; Be=Break end: @@ -480,8 +476,8 @@ class FormData: if current_time >= finish: break - LOG.debug(f"handling break {hours2time(current_break[0]/60)}-{hours2time(current_break[1]/60)} " - f" (current time: {hours2time(current_time/60)})") + LOG.debug(f"handling break {_hours2timestring(current_break[0]/60)}-{_hours2timestring(current_break[1]/60)} " + f" (current time: {_hours2timestring(current_time/60)})") break_s, break_e = current_break case1 = finish <= break_s @@ -494,22 +490,22 @@ class FormData: if case1: LOG.debug(f"case 1: interval entirely before break") present_intervals.append((current_time / 60, finish / 60)) - LOG.debug(f" + added interval {hours2time(present_intervals[-1][0])} " - f"- {hours2time(present_intervals[-1][1])}") + LOG.debug(f" + added interval {_hours2timestring(present_intervals[-1][0])} " + f"- {_hours2timestring(present_intervals[-1][1])}") current_time = finish elif case2: LOG.debug(f"case 2: interval straddles start of break") present_intervals.append((current_time / 60, break_s / 60)) - LOG.debug(f" + added interval {hours2time(present_intervals[-1][0])} " - f"- {hours2time(present_intervals[-1][1])}") + LOG.debug(f" + added interval {_hours2timestring(present_intervals[-1][0])} " + f"- {_hours2timestring(present_intervals[-1][1])}") current_time = break_e elif case3: LOG.debug(f"case 3: break entirely inside interval") # We add the bit before the break, but not the bit afterwards, # as it may hit another break. present_intervals.append((current_time / 60, break_s / 60)) - LOG.debug(f" + added interval {hours2time(present_intervals[-1][0])} " - f"- {hours2time(present_intervals[-1][1])}") + LOG.debug(f" + added interval {_hours2timestring(present_intervals[-1][0])} " + f"- {_hours2timestring(present_intervals[-1][1])}") current_time = break_e elif case4: LOG.debug(f"case 4: interval entirely inside break") @@ -652,6 +648,11 @@ WINDOWS_TYPES = {'window_sliding', 'window_hinged', 'not-applicable'} COFFEE_OPTIONS_INT = {'coffee_break_0': 0, 'coffee_break_1': 1, 'coffee_break_2': 2, 'coffee_break_4': 4} +def _hours2timestring(hours: float): + # Convert times like 14.5 to strings, like "14:30" + return f"{int(np.floor(hours)):02d}:{int(np.round((hours % 1) * 60)):02d}" + + def time_string_to_minutes(time: str) -> minutes_since_midnight: """ Converts time from string-format to an integer number of minutes after 00:00 diff --git a/cara/apps/calculator/report_generator.py b/cara/apps/calculator/report_generator.py index b7b1551a..ea22cbb6 100644 --- a/cara/apps/calculator/report_generator.py +++ b/cara/apps/calculator/report_generator.py @@ -1,6 +1,6 @@ import base64 import dataclasses -from datetime import datetime +from datetime import datetime, timedelta import io import typing import zlib @@ -126,18 +126,20 @@ def img2base64(img_data) -> str: def plot(times, concentrations, model: models.ExposureModel): fig = plt.figure() ax = fig.add_subplot(1, 1, 1) - ax.plot(times, concentrations, lw=2, color='#1f77b4', label='Concentration') + datetimes = [datetime(1970, 1, 1) + timedelta(hours=time) for time in times] + ax.plot(datetimes, concentrations, lw=2, color='#1f77b4', label='Concentration') ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) - ax.set_xlabel('Time (hour of day)') + ax.set_xlabel('Time of day') ax.set_ylabel('Concentration ($q/m^3$)') ax.set_title('Concentration of infectious quanta') + ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%H:%M")) # Plot presence of exposed person for i, (presence_start, presence_finish) in enumerate(model.exposed.presence.boundaries()): plt.fill_between( - times, concentrations, 0, + datetimes, concentrations, 0, where=(np.array(times) > presence_start) & (np.array(times) < presence_finish), color="#1f77b4", alpha=0.1, label="Presence of exposed person(s)" if i == 0 else "" @@ -240,19 +242,21 @@ def comparison_plot(scenarios: typing.Dict[str, models.ExposureModel]): if times is None: t_start, t_end = model_start_end(model) times = np.linspace(t_start, t_end, resolution) + datetimes = [datetime(1970, 1, 1) + timedelta(hours=time) for time in times] concentrations = [model.concentration_model.concentration(time) for time in times] if name in dash_styled_scenarios: - ax.plot(times, concentrations, label=name, linestyle='--') + ax.plot(datetimes, concentrations, label=name, linestyle='--') else: - ax.plot(times, concentrations, label=name, linestyle='-', alpha=0.5) + ax.plot(datetimes, concentrations, label=name, linestyle='-', alpha=0.5) # Place a legend outside of the axes itself. ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left') ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) + ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%H:%M")) - ax.set_xlabel('Time (hour of day)') + ax.set_xlabel('Time of day') ax.set_ylabel('Concentration ($q/m^3$)') ax.set_title('Concentration of infectious quanta') diff --git a/cara/apps/calculator/templates/base/calculator.report.html.j2 b/cara/apps/calculator/templates/base/calculator.report.html.j2 index bb4e57a4..27bdacf9 100644 --- a/cara/apps/calculator/templates/base/calculator.report.html.j2 +++ b/cara/apps/calculator/templates/base/calculator.report.html.j2 @@ -293,11 +293,41 @@
{% block disclaimer %}

Disclaimer:

-

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 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.

- The model used is based on scientific publications relating to airborne transmission of infectious diseases, dose-response exposures and aerosol science, as of December 2020 . It can be used to compare the effectiveness of different airborne-related risk mitigation measures.

- Note that this model applies a deterministic approach, i.e., it is assumed at least one person is infected and shedding viruses into the simulated volume. Nonetheless, it is also important to understand that the absolute risk of infection is uncertain, as it will depend on the probability that someone infected attends the event. The model is most useful for comparing the impact and effectiveness of different mitigation measures such as ventilation, filtration, exposure time, physical activity and the size of the room, only considering long-range airborne transmission of COVID-19 in indoor settings.

- This tool is designed to be informative, allowing the user to adapt different settings and model the relative impact on the estimated infection probabilities. The objective is to facilitate targeted decision-making and investment through comparisons, rather than a singular determination of absolute risk. While the SARS-CoV-2 virus is in circulation among the population, the notion of 'zero risk' or a 'completely safe scenario' does not exist. Each event modelled is unique and the results generated therein are only as accurate as the inputs and assumptions. -

+ +

+ CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions. +

+

+ 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. +

+

+ 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 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. +

+

+ The model used is based on scientific publications relating to airborne transmission of infectious diseases, dose-response exposures and aerosol science, as of February 2021. + It can be used to compare the effectiveness of different airborne-related risk mitigation measures. +

+

+ Note that this model applies a deterministic approach, i.e., it is assumed at least one person is infected and shedding viruses into the simulated volume. + Nonetheless, it is also important to understand that the absolute risk of infection is uncertain, as it will depend on the probability that someone infected attends the event. + The model is most useful for comparing the impact and effectiveness of different mitigation measures such as ventilation, filtration, exposure time, physical activity and + the size of the room, only considering long-range airborne transmission of COVID-19 in indoor settings. +

+

+ This tool is designed to be informative, allowing the user to adapt different settings and model the relative impact on the estimated infection probabilities. + The objective is to facilitate targeted decision-making and investment through comparisons, rather than a singular determination of absolute risk. + While the SARS-CoV-2 virus is in circulation among the population, the notion of 'zero risk' or 'completely safe scenario' does not exist. + Each event modelled is unique, and the results generated therein are only as accurate as the inputs and assumptions. +

+

+ CARA has not undergone review, approval or certification by competent authorities, and as a result, it cannot be considered + as a fully endorsed and reliable tool, namely in the assessment of potential viral emissions from infected hosts to be modelled. +

+ {% endblock disclaimer %}
{% endblock disclaimer_container %} diff --git a/cara/apps/calculator/templates/calculator.form.html.j2 b/cara/apps/calculator/templates/calculator.form.html.j2 index a47e8812..063a1c46 100644 --- a/cara/apps/calculator/templates/calculator.form.html.j2 +++ b/cara/apps/calculator/templates/calculator.form.html.j2 @@ -318,17 +318,41 @@ v{{ calculator_version }} Please sen



- -
-

This software is provided with a disclaimer and code license.


-

+
+

Disclaimer:

+

+ CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions. +

+

+ 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. +

+

+ 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 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. +

+

+ The model used is based on scientific publications relating to airborne transmission of infectious diseases, dose-response exposures and aerosol science, as of February 2021. + It can be used to compare the effectiveness of different airborne-related risk mitigation measures. +

+

+ Note that this model applies a deterministic approach, i.e., it is assumed at least one person is infected and shedding viruses into the simulated volume. + Nonetheless, it is also important to understand that the absolute risk of infection is uncertain, as it will depend on the probability that someone infected attends the event. + The model is most useful for comparing the impact and effectiveness of different mitigation measures such as ventilation, filtration, exposure time, physical activity and + the size of the room, only considering long-range airborne transmission of COVID-19 in indoor settings. +

+

+ This tool is designed to be informative, allowing the user to adapt different settings and model the relative impact on the estimated infection probabilities. + The objective is to facilitate targeted decision-making and investment through comparisons, rather than a singular determination of absolute risk. + While the SARS-CoV-2 virus is in circulation among the population, the notion of 'zero risk' or 'completely safe scenario' does not exist. + Each event modelled is unique, and the results generated therein are only as accurate as the inputs and assumptions. +

+

+ CARA has not undergone review, approval or certification by competent authorities, and as a result, it cannot be considered + as a fully endorsed and reliable tool, namely in the assessment of potential viral emissions from infected hosts to be modelled. +

diff --git a/cara/apps/calculator/templates/userguide.html.j2 b/cara/apps/calculator/templates/userguide.html.j2 index 23755a1b..6407e503 100644 --- a/cara/apps/calculator/templates/userguide.html.j2 +++ b/cara/apps/calculator/templates/userguide.html.j2 @@ -10,16 +10,41 @@ If you are using the expert version of the tool, you should look at the expert

For more information on the Airborne Transmission of SARS-CoV-2, feel free to check out the HSE Seminar: https://cds.cern.ch/record/2743403

The methodology, mathematical equations and parameters of the model are described here: https://edms.cern.ch/ui/file/2566402/1/CARA_Deterministic_parameters_2020.pdf

Disclaimer

-

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 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.

-

The model used is based on scientific publications relating to airborne transmission of infectious diseases, dose-response exposures and aerosol science, as of December 2020 . It can be used to compare the effectiveness of different airborne-related risk mitigation measures.

-

Note that this model applies a deterministic approach, i.e., it is assumed at least one person is infected and shedding viruses into the simulated volume. -Nonetheless, it is also important to understand that the absolute risk of infection is uncertain, as it will depend on the probability that someone infected attends the event. -The model is most useful for comparing the impact and effectiveness of different mitigation measures such as ventilation, filtration, exposure time, physical activity and the size of the room, only considering long-range airborne transmission of COVID-19 in indoor settings.

-

This tool is designed to be informative, allowing the user to adapt different settings and model the relative impact on the estimated infection probabilities. -The objective is to facilitate targeted decision-making and investment through comparisons, rather than a singular determination of absolute risk. While the SARS-CoV-2 virus is in circulation among the population, the notion of 'zero risk' or a 'completely safe scenario' does not exist. -Each event modelled is unique and the results generated therein are only as accurate as the inputs and assumptions.

+ +

+ CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions. +

+

+ 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. +

+

+ 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 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. +

+

+ The model used is based on scientific publications relating to airborne transmission of infectious diseases, dose-response exposures and aerosol science, as of February 2021. + It can be used to compare the effectiveness of different airborne-related risk mitigation measures. +

+

+ Note that this model applies a deterministic approach, i.e., it is assumed at least one person is infected and shedding viruses into the simulated volume. + Nonetheless, it is also important to understand that the absolute risk of infection is uncertain, as it will depend on the probability that someone infected attends the event. + The model is most useful for comparing the impact and effectiveness of different mitigation measures such as ventilation, filtration, exposure time, physical activity and + the size of the room, only considering long-range airborne transmission of COVID-19 in indoor settings. +

+

+ This tool is designed to be informative, allowing the user to adapt different settings and model the relative impact on the estimated infection probabilities. + The objective is to facilitate targeted decision-making and investment through comparisons, rather than a singular determination of absolute risk. + While the SARS-CoV-2 virus is in circulation among the population, the notion of 'zero risk' or 'completely safe scenario' does not exist. + Each event modelled is unique, and the results generated therein are only as accurate as the inputs and assumptions. +

+

+ CARA has not undergone review, approval or certification by competent authorities, and as a result, it cannot be considered + as a fully endorsed and reliable tool, namely in the assessment of potential viral emissions from infected hosts to be modelled. +

+

How to use this tool

Simulation Name & Room number

In order to be able to trace back the simulations in your workplace risk assessments, performed with the tool, you can give each one a unique name - for example "Office use on Tuesday mornings". diff --git a/cara/apps/calculator/themes/cern/templates/calculator.report.html.j2 b/cara/apps/calculator/themes/cern/templates/calculator.report.html.j2 index f4c93509..4d6769f8 100644 --- a/cara/apps/calculator/themes/cern/templates/calculator.report.html.j2 +++ b/cara/apps/calculator/themes/cern/templates/calculator.report.html.j2 @@ -85,9 +85,7 @@ {% block disclaimer %} {{ super() }}

- CARA is made available for internal CERN use only. - It is intended for Members of Personnel with roles related to Supervision, Health & Safety or Space Management, in order to simulate the concerned workplaces on CERN sites. - For use outside of this scope, it has to be performed under a pre-defined framework and licence agreement issued by CERN Knowledge Transfer (kt@cern.ch). + At CERN, CARA is intended for Members of Personnel with roles related to Supervision, Health & Safety or Space Management, in order to simulate the concerned workplaces on CERN sites.

{% endblock disclaimer %} diff --git a/cara/apps/static/css/colors.css b/cara/apps/static/css/colors.css index 73c62e29..c7ced46d 100644 --- a/cara/apps/static/css/colors.css +++ b/cara/apps/static/css/colors.css @@ -136,9 +136,9 @@ body > footer { color: #fffeee !important; } body > footer h2:after { background: #fffeee !important; } - body > footer nav ul.menu.nav li a { + body > footer a, footer a { color: #fffefe; } - body > footer nav ul.menu.nav li a:hover, body > footer nav ul.menu.nav li a.is-active { + body > footer a:hover, body > footer a.is-active { color: #fffefe; } body > footer nav ul.menu.nav li a:hover:before, body > footer nav ul.menu.nav li a.is-active:before { color: #2d8af1; } diff --git a/cara/apps/templates/common_text.md.j2 b/cara/apps/templates/common_text.md.j2 new file mode 100644 index 00000000..e69de29b diff --git a/cara/apps/templates/index.html.j2 b/cara/apps/templates/index.html.j2 index 9713067c..2e814fd1 100644 --- a/cara/apps/templates/index.html.j2 +++ b/cara/apps/templates/index.html.j2 @@ -16,44 +16,51 @@

CARA: COVID Airborne Risk Assessment Tools

-
- -

Please try out the CARA COVID calculator here. - Your feedback is most welcome at CARA-dev@cern.ch

- - - + +

Introduction


+
+

+ 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 about page for more details on the methodology, assumptions and limitations of CARA. +

+

+ The full CARA source code can be accessed freely under an Apache 2.0 open source license from our code repository. + It includes detailed instructions on how to run your own version of this tool. +

-

Authors:


+
+

CARA@CERN


-

Andre Henriques1, Gabriella Azzopardi2, James Devine3, Philip Elson4, Nicolas Mounet2, Markus Kongstein Rognlien2, Nicola Tarocco5


+ 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 CERN version of the CARA Covid Calculator is available on this site to members of the CERN personnel. +

+
+ +
+

Authors

+
+

+

Andre Henriques1, Marco Andreini1, Gabriella Azzopardi2, James Devine3, Philip Elson4, Nicolas Mounet2, Markus Kongstein Rognlien2, Nicola Tarocco5


1HSE Unit, Occupational Health & Safety Group, CERN
2Beams Department, Accelerators and Beam Physics Group, CERN
3Experimental Physics Department, Safety Office, CERN
4Beams Department, Controls Group, CERN
5Information Technology Department, Collaboration, Devices & Applications Group, CERN
-

-

Acknowledgements:


+
+

Acknowledgements:

- We thank CERN’s HSE Unit, Beams Department, Experimental Physics Department and Information Technology Department for their continuous support. - Thanks to Doris Forkel-Wirth, Olga Beltramello, Letizia Di Giulio, Evelyne Dho and the other members of the office occupancy working group for providing expert advice and extensively testing the tool. - We thank Fabienne Landua and the Design and Visual Identity Service for preparing the logo. - Thanks also to colleagues like Oriol Rios, Marco Andreini, Lina Dimovasili for the technical discussions and advice. - Many thanks to 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 – their contribution was indispensable for this project. - + 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. +

- -

Intended Users:

-

- CARA is made available for internal CERN use only. It is intended for Members of Personnel with roles related to Supervision, Health & Safety or Space Management, in order to simulate the concerned workplaces on CERN sites. For use outside of this scope, please contact CERN Knowledge Transfer (kt@cern.ch). - -

-
diff --git a/cara/apps/templates/layout.html.j2 b/cara/apps/templates/layout.html.j2 index e7658ad2..be46f836 100644 --- a/cara/apps/templates/layout.html.j2 +++ b/cara/apps/templates/layout.html.j2 @@ -193,7 +193,6 @@ policy issues. Any initiative is conducted on a best effort and as-is basis, without liability or warranty.

- @@ -231,9 +230,22 @@ +
  • + + Source code + +
  • + +

    + CARA is Apache 2.0 licensed open-source + software developed at CERN. + You can find the source code at https://gitlab.cern.ch/cara/cara, + where we welcome contributions, feature requests and issue reports. +

    + @@ -282,9 +294,7 @@ d="M56 6H44c-1.1 0-2 0.9-2 2s0.9 2 2 2h7.2L30.6 30.6c-0.8 0.8-0.8 2 0 2.8C31 33.8 31.5 34 32 34s1-0.2 1.4-0.6L54 12.8V20c0 1.1 0.9 2 2 2s2-0.9 2-2V8C58 6.9 57.1 6 56 6z"> -  © - 2020 - CERN +  © 2020 - 2021 CERN diff --git a/cara/models.py b/cara/models.py index 0c04eac0..0572c8f3 100644 --- a/cara/models.py +++ b/cara/models.py @@ -1,3 +1,5 @@ +# This module is part of CARA. Please see the repository at +# https://gitlab.cern.ch/cara/cara for details of the license and terms of use. """ This module implements the core CARA models. diff --git a/cara/tests/apps/calculator/test_markdown_tools.py b/cara/tests/apps/calculator/test_markdown_tools.py new file mode 100644 index 00000000..8b913067 --- /dev/null +++ b/cara/tests/apps/calculator/test_markdown_tools.py @@ -0,0 +1,30 @@ +import textwrap + +import jinja2 +import pytest + +import cara.apps.calculator.markdown_tools as md_tools + + +@pytest.fixture +def example_template(): + return jinja2.Environment().from_string(textwrap.dedent(""" + # A header + + Some *text* + + {% block using_jinja_blocks %} + # Another header + + Some more **text**. + {% endblock %} + + """)) + + +def test_extract_blocks(example_template): + blocks = md_tools.extract_rendered_markdown_blocks(example_template) + assert 'A header' in blocks + assert blocks['A header'] == '

    Some text

    \n' + assert 'Another header' in blocks + assert blocks['Another header'] == '

    Some more text.

    \n' diff --git a/cara/tests/apps/calculator/test_model_generator.py b/cara/tests/apps/calculator/test_model_generator.py index 58c34092..6c5050e4 100644 --- a/cara/tests/apps/calculator/test_model_generator.py +++ b/cara/tests/apps/calculator/test_model_generator.py @@ -3,6 +3,7 @@ import dataclasses import pytest from cara.apps.calculator import model_generator +from cara.apps.calculator.model_generator import _hours2timestring from cara.apps.calculator.model_generator import minutes_since_midnight from cara import models from cara import data @@ -272,13 +273,8 @@ def time2mins(time: str) -> minutes_since_midnight: return minutes_since_midnight(int(time.split(':')[0]) * 60 + int(time.split(':')[1])) -def hours2time(hours: float): - # Convert times like 14.5 to strings, like "14:30" - return f"{int(np.floor(hours)):02d}:{int(np.round((hours % 1) * 60)):02d}" - - def assert_boundaries(interval, boundaries_in_time_string_form): - boundaries = [(hours2time(start), hours2time(end)) + boundaries = [(_hours2timestring(start), _hours2timestring(end)) for start, end in interval.boundaries()] assert boundaries == boundaries_in_time_string_form diff --git a/cara/tests/apps/calculator/test_webapp.py b/cara/tests/apps/calculator/test_webapp.py index 97589339..3c133684 100644 --- a/cara/tests/apps/calculator/test_webapp.py +++ b/cara/tests/apps/calculator/test_webapp.py @@ -26,6 +26,11 @@ async def test_calculator_form(http_server_client): assert response.code == 200 +async def test_user_guide(http_server_client): + resp = await http_server_client.fetch('/calculator/user-guide') + assert resp.code == 200 + + class TestBasicApp(tornado.testing.AsyncHTTPTestCase): def get_app(self): return cara.apps.calculator.make_app() diff --git a/setup.py b/setup.py index ab2a021a..e99d3185 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,5 @@ +# This module is part of CARA. Please see the repository at +# https://gitlab.cern.ch/cara/cara for details of the license and terms of use. """ setup.py for CARA. @@ -59,6 +61,7 @@ setup( classifiers=[ "Programming Language :: Python :: 3", "Operating System :: OS Independent", + "License :: OSI Approved :: Apache Software License", # Apache 2.0 ], install_requires=REQUIREMENTS['core'], @@ -73,11 +76,9 @@ setup( 'all': [req for reqs in REQUIREMENTS.values() for req in reqs], }, package_data={'cara': [ - 'apps/templates/*.j2', - 'apps/calculator/templates/*.j2', - 'apps/calculator/*', - 'apps/calculator/*/*', - 'apps/calculator/*/*/*', - 'apps/calculator/*/*/*/*', + 'apps/*/*', + 'apps/*/*/*', + 'apps/*/*/*/*', + 'apps/*/*/*/*/*', ]}, )