diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c2523851..69624f7b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -67,6 +67,7 @@ test-cern-caimira-py39: .test_openshift_config: stage: test + allow_failure: true image: registry.cern.ch/docker.io/mambaorg/micromamba before_script: - micromamba create --yes -p $HOME/env python=3.9 ruamel.yaml wget -c conda-forge @@ -139,6 +140,13 @@ check_openshift_config_prod: DOCKER_CONTEXT_DIRECTORY: "" extends: .docker-build +.docker-build-docs: + variables: + IMAGE_NAME: caimira-docs + DOCKERFILE_DIRECTORY: "caimira/docs" + DOCKER_CONTEXT_DIRECTORY: "caimira" + extends: .docker-build + # on push to live/caimira-test .docker-build-test: variables: @@ -158,6 +166,14 @@ docker-build-calculator-app-test: rules: - if: $CI_COMMIT_BRANCH == "live/caimira-test" +docker-build-docs-test: + extends: + - .docker-build-docs + variables: + IMAGE_TAG: caimira-test-docs-latest + rules: + - if: $CI_COMMIT_BRANCH == "live/caimira-test" + # on release .docker-build-release: before_script: @@ -179,6 +195,15 @@ docker-build-calculator-app-release: rules: - if: $CI_COMMIT_TAG +docker-build-docs-release: + extends: + - .docker-build-release + - .docker-build-docs + variables: + IMAGE_TAG: caimira-docs-latest + rules: + - if: $CI_COMMIT_TAG + # ################################################################################################### # Deploy to OpenShift .deploy: @@ -217,3 +242,10 @@ deploy-calculator-open-app-test: IMAGE_NAME: calculator-app OPENSHIFT_DEPLOYMENT: calculator-open-app OPENSHIFT_CONTAINER_NAME: calculator-open-app + +deploy-docs-test: + extends: .deploy + variables: + IMAGE_NAME: caimira-docs + OPENSHIFT_DEPLOYMENT: caimira-test-docs + OPENSHIFT_CONTAINER_NAME: caimira-test-docs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f5d45b1..b0c0a4f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# 4.17.5 (November 20, 2024) + +## Features Added +- Mkdocs documentation +- Folder layout adapted + +## Bug Fixes +- N/A + # 4.17.4 (November 05, 2024) ## Features Added diff --git a/README.md b/README.md index f3da12c4..b8857f87 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ Hence, the output from this model is only valid when the other recommended publi The model used is based on scientific publications relating to airborne transmission of infectious diseases, dose-response exposures and aerosol science, as of February 2022. 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, amount and nature of close-range interactions and @@ -23,436 +22,23 @@ The objective is to facilitate targeted decision-making and investment through c 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 -CAiMIRA was developed by following members of CERN - European Council for Nuclear Research (visit https://home.cern/): - -Andre Henriques1, Luis Aleixo1, 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 (NTNU)
- -### Reference and Citation - -**For the use of the CAiMIRA web app** - -CAiMIRA – CERN Airborne Model for Indoor Risk Assessment tool - -[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6520431.svg)](https://doi.org/10.5281/zenodo.6520431) - -© Copyright 2020-2021 CERN. All rights not expressly granted are reserved. - -**For use of the CAiMIRA model** - -Henriques A, Mounet N, Aleixo L, Elson P, Devine J, Azzopardi G, Andreini M, Rognlien M, Tarocco N, Tang J. (2022). Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces. _Interface Focus 20210076_. https://doi.org/10.1098/rsfs.2021.0076 - -Reference on the Short-range expiratory jet model from: -Jia W, Wei J, Cheng P, Wang Q, Li Y. (2022). Exposure and respiratory infection risk via the short-range airborne route. _Building and Environment_ *219*: 109166. -https://doi.org/10.1016/j.buildenv.2022.109166 - -***Open Source Acknowledgments*** - -For a detailed list of the open-source dependencies used in this project along with their respective licenses, please refer to [License Information](open-source-licences/README.md). This includes both the core dependencies specified in the project's requirements and their transitive dependencies. - -The information also features a distribution diagram of licenses and a brief description of each of them. - -## Applications - -### Calculator - -A risk assessment tool which simulates the airborne spread of the SARS-CoV-2 virus for space managers. - - -### CAiMIRA Expert App and CO₂ App - -A tool to interact with various parameters of the CAiMIRA model. - - -## Disclaimer - -CAiMIRA 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. - - -## Running CAiMIRA locally - -The easiest way to run a version of CAiMIRA Calculator is to use docker. A pre-built -image of CAiMIRA is made available at https://gitlab.cern.ch/caimira/caimira/container_registry. -In order to run CAiMIRA locally with docker, run the following: - - $ docker run -it -p 8080:8080 gitlab-registry.cern.ch/caimira/caimira/calculator - -This will start a local version of CAiMIRA, which can be visited at http://localhost:8080/. - - -## Folder structure - -The project contains two different Python packages: - -- `caimira`: Contains all the backend logic and the calculator model. It is the package published in PyPI. -- `cern_caimira`: Imports and uses the backend package (`caimira`) and includes CERN-specific UI implementation. - -The folder layout follows best practices as described [here](https://ianhopkinson.org.uk/2022/02/understanding-setup-py-setup-cfg-and-pyproject-toml-in-python/). - - -## Development guide - -CAiMIRA is also mirrored to Github if you wish to collaborate on development and can be found at: https://github.com/CERN/caimira - -### Installing CAiMIRA in editable mode - -In order to install the CAiMIRA's backend logic, create your own virtualenv and, from the root directory of the project, run: - -``` -cd caimira -pip install -e . -``` - -In order to install the CERN-specific UI version, that links to the previously installed backend, activate your virtualenv and, from the root directory of the project, run: - -``` -cd cern_caimira -pip install -e . -``` - -### Running the Calculator app in development mode - -This example describes how to run the calculator with the CERN-specific UI. In the root directory of the project: - -``` -python -m cern_caimira.apps.calculator -``` - -To run with a specific template theme created: - -``` -python -m cern_caimira.apps.calculator --theme=cern_caimira/src/cern_caimira/apps/templates/{theme} -``` - -To run the entire app in a different `APPLICATION_ROOT` path: - -``` -python -m cern_caimira.apps.calculator --app_root=/myroot -``` - -To run the calculator on a different URL path: - -``` -python -m cern_caimira.apps.calculator --prefix=/mycalc -``` - -Each of these commands will start a local version of CAiMIRA, which can be visited at http://localhost:8080/. - -### How to compile and read the documentation - -In order to generate the documentation, CAiMIRA must be installed first with the `doc` optional dependencies: - -``` -cd caimira -pip install -e .[doc] -``` - -To generate the HTML documentation page, the command `make html` should be executed in the `caimira/src/caimira/calculator/docs` directory. -If any of the `.rst` files under the `caimira/docs` folder is changed, this command should be executed again. - -Then, right click on `caimira/src/caimira/calculator/docs/_build/html/index.html` and select `Open with` your preferred web browser. - -### Running the CAiMIRA Expert-App or CO2-App apps in development mode - -#### Disclaimer - -The `ExpertApplication` and `CO2Application` are no longer actively maintained but will remain in the codebase for legacy purposes. -Please note that the functionality of these applications might be compromised due to deprecation issues. - -#### Running the Applications - -These applications only work within Jupyter notebooks. Attempting to run them outside of a Jupyter environment may result in errors or degraded functionality. - -##### Prerequisites - -Make sure you have the needed dependencies installed: - -``` -pip install notebook jupyterlab -``` - -Running with Visual Studio Code (VSCode): - -1. Ensure you have the following extensions installed in VSCode: `Jupyter` and `Python`. - -2. Open VSCode and navigate to the directory containing the notebook. - -3. Open the notebook (e.g. `caimira/apps/expert/caimira.ipynb`) and run the cells by clicking the `run` button next to each cell. - -### Running the tests - -The project contains test files that separately test the functionality of the `caimira` backend and `cern_caimira` UI. - -To test the `caimira` package, from the root repository of the project: - -``` -cd caimira -pip install -e .[test] -python -m pytest -``` - -To test the `cern_caimira` package, from the root repository of the project: - -``` -cd cern_caimira -pip install -e .[test] -python -m pytest -``` - -### Running the profiler - -CAiMIRA includes a profiler designed to identify performance bottlenecks. The profiler is enabled when the environment variable `CAIMIRA_PROFILER_ENABLED` is set to 1. - -When visiting http://localhost:8080/profiler, you can start a new session and choose between [PyInstrument](https://github.com/joerick/pyinstrument) or [cProfile](https://docs.python.org/3/library/profile.html#module-cProfile). The app includes two different profilers, mainly because they can give different information. - -Keep the profiler page open. Then, in another window, navigate to any page in CAiMIRA, for example generate a new report. Refresh the profiler page, and click on the `Report` link to see the profiler output. - -The sessions are stored in a local file in the `/tmp` folder. To share it across multiple web nodes, a shared storage should be added to all web nodes. The folder can be customized via the environment variable `CAIMIRA_PROFILER_CACHE_DIR`. - -### CAiMIRA API Usage - -From the root directory of the project: - -1. Run the backend API: - - ``` - python -m caimira.api.app - ``` - -2. The Tornado server will run on port `8081`. - -To test the API functionality, you can send a `POST` request to `http://localhost:8081/virus_report` with the required inputs in the request body. For an example of the required inputs, see [the baseline raw form data](https://gitlab.cern.ch/caimira/caimira/blob/master/caimira/src/caimira/calculator/validators/virus/virus_validator.py#L565). - -The response format will be: - -```json -{ - "status": "success", - "message": "Results generated successfully", - "report_data": { - ... - }, - ... -} -``` - -### Building the whole environment for local development - -``` -docker build -f app-config/api-app/Dockerfile -t api-app . -docker build -f app-config/calculator-app/Dockerfile -t calculator-app . -docker build ./app-config/auth-service -t auth-service -``` - -If you are using a computer with ARM CPU (Mac M1/2/3), then add the arg `--platform linux/arm64` to the docker build cmd. - -If you need to debug the Docker build, add the args `--no-cache --progress=plain` to see a more verbose output in your terminal. - -Get the client secret from the CERN Application portal for the `caimira-test` app. See [CERN-SSO-integration](#cern-sso-integration) for more info. -``` -read CLIENT_SECRET -``` - -Define some env vars (copy/paste): -``` -export COOKIE_SECRET=$(openssl rand -hex 50) -export OIDC_SERVER=https://auth.cern.ch/auth -export OIDC_REALM=CERN -export CLIENT_ID=caimira-test -export CLIENT_SECRET=$CLIENT_SECRET -``` - -Run docker compose: -``` -cd app-config -CURRENT_UID=$(id -u):$(id -g) docker compose up -``` - -Then visit http://localhost:8080/. - -### Setting up the application on OpenShift - -The https://cern.ch/caimira application is running on CERN's OpenShift platform. In order to set it up for the first time, we followed the documentation at https://paas.docs.cern.ch/. In particular we: - - * Added the OpenShift application deploy key to the GitLab repository - * Created a Python 3.12 (the highest possible at the time of writing) application in OpenShift - * Configured a generic webhook on OpenShift, and call that from the CI of the GitLab repository - -### Updating the caimira-test.web.cern.ch instance - -We have a replica of https://caimira.web.cern.ch running on http://caimira-test.web.cern.ch. Its purpose is to simulate what will happen when -a feature is merged. To push your changes to caimira-test, simply push your branch to `live/caimira-test` and the CI pipeline will trigger the -deployment. To push to this branch, there is a good chance that you will need to force push - you should always force push with care and -understanding why you are doing it. Syntactically, it will look something like (assuming that you have "upstream" as your remote name, -but it may be origin if you haven't configured it differently): - - git push --force upstream name-of-local-branch:live/caimira-test - - -## OpenShift templates - -### First setup - -First, get the [oc](https://docs.okd.io/3.11/cli_reference/get_started_cli.html) client and then login: - -```console -$ oc login https://api.paas.okd.cern.ch -``` - -Then, switch to the project that you want to update: - -```console -$ oc project caimira-test -``` - -Create a new service account in OpenShift to access GitLab container registry: - -```console -$ oc create serviceaccount gitlabci-deployer -serviceaccount "gitlabci-deployer" created -``` - -Grant `edit` permission to the service account to run `oc set image` from CI an update the tag to deploy: -``` -$ oc policy add-role-to-user edit -z gitlabci-deployer -``` - -Get the service account token for GitLab: -``` -# We will refer to the output of this command as `test-token` -$ oc serviceaccounts get-token gitlabci-deployer -<...test-token...> -``` - -Add the token to GitLab to allow GitLab to access OpenShift and define/change image stream tags. Go to `Settings` -> `CI / CD` -> `Variables` -> click on `Expand` button and create the variable `OPENSHIFT_CAIMIRA_TEST_DEPLOY_TOKEN`: insert the token `<...test-token...>`. - -For CI usage, we also suggest creating a service account: - -```console -oc create sa gitlab-config-checker -``` - -Under ``User Management`` -> ``RoleBindings`` create a new `RoleBinding` to grant `View` access to the `gitlab-config-checker` service account: - -* name: `gitlab-config-checker-view-role` -* role name: `view` -* service account: `gitlab-config-checker` - -To get this new user's authentication token go to ``User Management`` -> ``Service Accounts`` -> `gitlab-config-checker` and locate the token in the newly created secret associated with the user (in this case ``gitlab-config-checker-token-XXXX``). Copy the `token` value from `Data`. - -Create the various configurations: - -```console -$ cd app-config/openshift - -$ oc process -f configmap.yaml | oc create -f - -$ oc process -f services.yaml | oc create -f - -$ oc process -f deployments.yaml | oc create -f - -``` - -Manually create the **route** to access the website, see `routes.example.yaml`. -After having created the route, make sure that you extend the HTTP request timeout annotation: the -report generation can take more time than the default 30 seconds. - -``` -$ oc annotate route caimira-route --overwrite haproxy.router.openshift.io/timeout=60s -``` - -### CERN SSO integration - -The SSO integration uses OpenID credentials configured in [CERN Applications portal](https://application-portal.web.cern.ch/). -How to configure the application: - -* Application Identifier: `caimira-test` -* Homepage: `https://caimira-test.web.cern.ch` -* Administrators: `caimira-dev` -* SSO Registration: - * Protocol: `OpenID (OIDC)` - * Redirect URI: `https://caimira-test.web.cern.ch/auth/authorize` - * Leave unchecked all the other checkboxes -* Define new roles: - * Name: `CERN Users` - * Role Identifier: `external-users` - * Leave unchecked checkboxes - * Minimum Level Of Assurance: `CERN (highest)` - * Assign role to groups: `cern-accounts-primary` e-group - * Name: `External accounts` - * Role Identifier: `admin` - * Leave unchecked checkboxes - * Minimum Level Of Assurance: `Any (no restrictions)` - * Assign role to groups: `caimira-app-external-access` e-group - * Name: `Allowed users` - * Role Identifier: `allowed-users` - * Check `This role is required to access my application` - * Minimum Level Of Assurance:`Any (no restrictions)` - * Assign role to groups: `cern-accounts-primary` and `caimira-app-external-access` e-groups - -Copy the client id and client secret and use it below. - -```console -$ COOKIE_SECRET=$(openssl rand -hex 50) -$ oc create secret generic \ - --from-literal="CLIENT_ID=$CLIENT_ID" \ - --from-literal="CLIENT_SECRET=$CLIENT_SECRET" \ - --from-literal="COOKIE_SECRET=$COOKIE_SECRET" \ - auth-service-secrets -``` - -### External APIs - -- **Geographical location:** -There is one external API call to fetch required information related to the geographical location inserted by a user. -The documentation for this geocoding service is available at https://developers.arcgis.com/rest/geocode/api-reference/geocoding-suggest.htm . -Please note that there is no need for keys on this API call. It is **free-of-charge**. - -- **Humidity and Inside Temperature:** -There is the possibility of using one external API call to fetch information related to a location specified in the UI. The data is related to the inside temperature and humidity taken from an indoor measurement device. Note that the API currently used from ARVE is only available for the `CERN theme` as the authorised sensors are installed at CERN." - -- **ARVE:** - -The ARVE Swiss Air Quality System provides trusted air data for commercial buildings in real-time and analyzes it with the help of AI and machine learning algorithms to create actionable insights. - -Create secret: - -```console -$ read ARVE_CLIENT_ID -$ read ARVE_CLIENT_SECRET -$ read ARVE_API_KEY -$ oc create secret generic \ - --from-literal="ARVE_CLIENT_ID=$ARVE_CLIENT_ID" \ - --from-literal="ARVE_CLIENT_SECRET=$ARVE_CLIENT_SECRET" \ - --from-literal="ARVE_API_KEY=$ARVE_API_KEY" \ - arve-api -``` +## Calculator -- **CERN Data Service:** +The CAiMIRA Calculator can be accessed online [here](https://caimira.web.cern.ch/), provided you have CERN SSO (Single Sign-On) credentials. For local usage, please refer to the [documentation](#documentation) on how to install and run the calculator locally. -The CERN data service collects data from various sources and expose them via a REST API endpoint. +## Documentation -The service is enabled when the environment variable `DATA_SERVICE_ENABLED` is set to 1. +All instructions for installation, deployment, usage, and model assumptions and references can be found in the [official documentation](https://caimira.docs.cern.ch/). -## Update configuration +## Contributing -If you need to **update** existing configuration, then modify this repository and after having logged in, run: +Contributions are welcome on our [GitHub repository](https://github.com/CERN/CAiMIRA). -```console -$ cd app-config/openshift +## Authors & License +Developed by CERN's HSE, Beams, and IT departments, in collaboration with WHO. -$ oc process -f configmap.yaml | oc replace -f - -$ oc process -f services.yaml | oc replace -f - -$ oc process -f deployments.yaml | oc replace -f - -``` +© Copyright 2020-2021 CERN. All rights not expressly granted are reserved.
+Licensed under the Apache License, Version 2.0 -Be aware that if you create/recreate the environment you must manually create a **route** in OpenShift, -specifying the respective annotation to be exposed outside CERN. +See the full [license](caimira/LICENSE) for details. diff --git a/caimira/README.md b/caimira/README.md new file mode 100644 index 00000000..b8857f87 --- /dev/null +++ b/caimira/README.md @@ -0,0 +1,44 @@ +# CAiMIRA - CERN Airborne Model for Risk Assessment + +CAiMIRA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions. + +CAiMIRA models the concentration profile of potential virions in enclosed spaces , both as background (room) concentration and during close-proximity interactions, 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 airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture and a two-stage exhaled jet model, and estimates the risk of COVID-19 infection therein. +The results DO NOT include the other known modes of SARS-CoV-2 transmission, such as fomite or blood-bound. +Hence, the output from this model is only valid when the other recommended public health & safety instructions are observed, such as 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 2022. +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, amount and nature of close-range interactions and +the size of the room, considering both long- and short-range airborne transmission modes 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. + +## Calculator + +The CAiMIRA Calculator can be accessed online [here](https://caimira.web.cern.ch/), provided you have CERN SSO (Single Sign-On) credentials. For local usage, please refer to the [documentation](#documentation) on how to install and run the calculator locally. + +## Documentation + +All instructions for installation, deployment, usage, and model assumptions and references can be found in the [official documentation](https://caimira.docs.cern.ch/). + +## Contributing + +Contributions are welcome on our [GitHub repository](https://github.com/CERN/CAiMIRA). + +## Authors & License + +Developed by CERN's HSE, Beams, and IT departments, in collaboration with WHO. + +© Copyright 2020-2021 CERN. All rights not expressly granted are reserved.
+Licensed under the Apache License, Version 2.0 + +See the full [license](caimira/LICENSE) for details. diff --git a/caimira/docs/Dockerfile b/caimira/docs/Dockerfile new file mode 100644 index 00000000..37784ed6 --- /dev/null +++ b/caimira/docs/Dockerfile @@ -0,0 +1,35 @@ +# Use the conda image to install Python +FROM registry.cern.ch/docker.io/condaforge/mambaforge AS conda + +ARG PYTHON_VERSION=3.12 +RUN mamba create --yes -p /opt/app python=${PYTHON_VERSION} + +# Install system dependencies, including Graphviz +RUN conda install conda-forge::graphviz + +# Copy project files to the container +COPY . /app +WORKDIR /app + +# Install CAiMIRA docs +RUN pip install .[doc] + +# Sphinx directory +WORKDIR /app/docs/sphinx + +# Generate markdown project's documentation +RUN sphinx-build -b markdown . _build/markdown + +# Base docs directory +WORKDIR /app/docs + +# Run the Python script to update markdown files, move it, and generate UML diagram +RUN python3 style_docs.py \ +&& mv sphinx/_build/markdown/index.md mkdocs/docs/code/models.md \ +&& pyreverse -o png -p UML-CAiMIRA --output-directory mkdocs/docs/code ../src/caimira/calculator/models/models.py + +# Mkdocs directory +WORKDIR /app/docs/mkdocs + +# Command to serve the MkDocs site +CMD ["python", "-m", "mkdocs", "serve", "--dev-addr=0.0.0.0:8080"] diff --git a/caimira/docs/mkdocs/docs/LICENSE.md b/caimira/docs/mkdocs/docs/LICENSE.md new file mode 100644 index 00000000..de49c2af --- /dev/null +++ b/caimira/docs/mkdocs/docs/LICENSE.md @@ -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/caimira/docs/mkdocs/docs/assets/caimira_logo.png b/caimira/docs/mkdocs/docs/assets/caimira_logo.png new file mode 100644 index 00000000..12d63798 Binary files /dev/null and b/caimira/docs/mkdocs/docs/assets/caimira_logo.png differ diff --git a/caimira/docs/mkdocs/docs/code/architecture.md b/caimira/docs/mkdocs/docs/code/architecture.md new file mode 100644 index 00000000..0a54bdc7 --- /dev/null +++ b/caimira/docs/mkdocs/docs/code/architecture.md @@ -0,0 +1,7 @@ +## CAiMIRA UML Diagram + +The following diagram describes all the data classes and their relations under the `models.py` file. + +[![CAiMIRA UML diagram](classes_UML-CAiMIRA.png)](classes_UML-CAiMIRA.png) + +CAiMIRA `models.py` file UML diagram. \ No newline at end of file diff --git a/caimira/docs/mkdocs/docs/code/fitting_algorithm.md b/caimira/docs/mkdocs/docs/code/fitting_algorithm.md new file mode 100644 index 00000000..1f5564c6 --- /dev/null +++ b/caimira/docs/mkdocs/docs/code/fitting_algorithm.md @@ -0,0 +1,5 @@ +The CO₂ fitting algorithm represents a significant extension to the CAiMIRA model. The algorithm enhances the model by predicting equivalent **exhalation rates** and **ventilation profiles** based on measured indoor CO₂ concentrations. + +By leveraging these predictions, the algorithm reduces the reliance on user-estimated parameters which are often subject to large uncertainties and best-guess estimates, providing more accurate results. + +For all the details, please refer to [10.17181/CERN.US5U.4OJ4](https://cds.cern.ch/record/2898100). \ No newline at end of file diff --git a/caimira/docs/mkdocs/docs/code/rest_api.md b/caimira/docs/mkdocs/docs/code/rest_api.md new file mode 100644 index 00000000..9026afe2 --- /dev/null +++ b/caimira/docs/mkdocs/docs/code/rest_api.md @@ -0,0 +1,204 @@ +# CAiMIRA REST API + +The API enables third-party applications to interact with the CAiMIRA [backend](https://gitlab.cern.ch/caimira/caimira), making integration easier and more flexible. This page covers the CAiMIRA [package structure](#directory-layout-key-components) and [API usage](#rest-api-overview). + +## Package Overview + +With the implementation of the REST API, the CAiMIRA repository now consists of two distinct Python packages: + +* `caimira`: The core package containing all backend logic. This package will be published to [PyPi](https://pypi.org/) and it is the central engine to process the input data and generate the results. It was designed to be flexible, supporting a wide range of external integrations without being tied to any particular User Interface (UI). + +* `cern_caimira`: A package that extends `caimira` and provides CERN-specific UI implementation. External users typically won't need this. + +By separating the backend logic from the UI, the CAiMIRA project achieves better modularity and flexibility, allowing external users to work with the core functionality without depending on CERN-specific configuration or UI. + +The `app-config` directory at the root of the project is specific to the CERN environment and includes the components necessary for deploying the backend and UI on the [OKD](https://paas.cern.ch/) platform. + +## Directory Layout // Key Components + +* `src/caimira/api`: Contains the REST API implementation, defining the endpoints, request handling, and input/output formats. + * `/app.py` : Entry point for the CAiMIRA backend, powered by the [Tornado](https://www.tornadoweb.org/en/stable/) framework. It sets up the server, defines the routes for handling reports, and starts the Tornado I/O loop. + * `/controller`: Contains the core logic for handling incoming API requests. It interprets user input, interact with models, and send responses back to the client. + * `/routes`: Defines the API endpoints and associate them with the corresponding controller functions. +* `src/caimira/calculator`: contains the core models used in CAiMIRA for processing inputs and generating outputs. + * `/models`: Contains the classes reponsible to define the whole object oriented hierarchical model. + * `/report`: Manages the generation of report data based on the processed input. + * `/store`: Contains the data store and registry. + * `/validators`: Contains validation logic to ensure that input data conforms to expected formats and constraints before processing. + +* `tests/`: Contains unit tests and integration tests for the `caimira` package to ensure it functions correctly. + +## REST API Overview + +The newly implemented REST API allows external applications to interact with CAiMIRA backend programmatically, making it easier to submit data, process it within CAiMIRA's model engine, and retrieve the results. + +### API Structure + +The API is served by the **Tornado** web framework, which provides asynchronous handling for client requests. The API serves requests on a specific port (by default, `8088`), and support standard HTTP methods, such as `POST` for data submission. + +#### Key Features + +* **Input Data Handling**: Accepts well-defined JSON input formats. +* **Report Generation**: Processes input data through CAiMIRA's model and generates detailed reports. +* **Status Codes**: Provides standard HTTP status codes for succes, failure, and validation errors. + +#### Running the API + +To run the API, follow these steps from the root directory of the project: + +1. Install dependencies: + ``` + cd caimira + pip install -e . + ``` + +2. Run the backend: + ``` + python -m caimira.api.app + ``` + The web server will be accessible on port `8088`. + +#### API Endpoints + +As the project is growing, more endpoints targeted to specific tasks will be developed. + +??? "POST **/virus_report** (virus report data generation)" + + * **Description**: Core endpoint that allows users to submit data for the virus report generation. Data is processed by the CAiMIRA engine, and the results are returned in the response. + * **Input**: The body of the request must include the necessary input data in JSON format. Examples of the required input can be found [here](https://gitlab.cern.ch/caimira/caimira/-/blob/master/caimira/src/caimira/calculator/validators/defaults.py?ref_type=heads). + * **Response**: On success (status code `200`), the response will contain the following structure: + + { + "status": "success", + "message": "Results generated successfully", + "report_data": { + ... + } + } + + * **Error Handling**: In case of errors, the API will return appropriate error messages and HTTP status codes, such as `400` for bad requests, `404` for not found, or `500` for internal server errors. + + **Example body**: + + { + "activity_type": "office", + "calculator_version": "NA", + "event_month": "January", + "exposed_finish": "18:00", + "exposed_lunch_finish": "13:30", + "exposed_lunch_start": "12:30", + "exposed_start": "09:00", + "infected_finish": "18:00", + "infected_lunch_finish": "13:30", + "infected_lunch_start": "12:30", + "infected_people": "1", + "infected_start": "09:00", + "inside_temp": "293.", + "location_latitude": 46.20833, + "location_longitude": 6.14275, + "location_name": "Geneva", + "opening_distance": "0.2", + "room_number": "123", + "room_volume": "75", + "simulation_name": "Test", + "total_people": "10", + "ventilation_type": "natural_ventilation", + "virus_type": "SARS_CoV_2_OMICRON", + "volume_type": "room_volume_explicit", + "window_height": "2", + "window_opening_regime": "windows_open_permanently", + "window_type": "window_sliding", + "window_width": "2", + "windows_duration": "10", + "windows_frequency": "60", + "windows_number": "1" + } + + For the full list of accepted inputs and respective values please refer to CAiMIRA's official defaults in GitLab repository [here](https://gitlab.cern.ch/caimira/caimira/-/blob/master/caimira/src/caimira/calculator/validators/co2/co2_validator.py?ref_type=heads#L29). + + ??? note "Example cURL (with the above body)" + + curl -X POST "http://localhost:8088/virus_report" \ + -H "Content-Type: application/json" \ + -d '{ + "activity_type": "office", + "calculator_version": "NA", + "event_month": "January", + "exposed_finish": "18:00", + "exposed_lunch_finish": "13:30", + "exposed_lunch_start": "12:30", + "exposed_start": "09:00", + "infected_finish": "18:00", + "infected_lunch_finish": "13:30", + "infected_lunch_start": "12:30", + "infected_people": "1", + "infected_start": "09:00", + "inside_temp": "293.", + "location_latitude": 46.20833, + "location_longitude": 6.14275, + "location_name": "Geneva", + "opening_distance": "0.2", + "room_number": "123", + "room_volume": "75", + "simulation_name": "Test", + "total_people": "10", + "ventilation_type": "natural_ventilation", + "virus_type": "SARS_CoV_2_OMICRON", + "volume_type": "room_volume_explicit", + "window_height": "2", + "window_opening_regime": "windows_open_permanently", + "window_type": "window_sliding", + "window_width": "2", + "windows_duration": "10", + "windows_frequency": "60", + "windows_number": "1" + }' + + **Note**: The `report_generation_parallelism` can be passed as an argument with integer values. If omitted, `None` will be considered by default. + +??? "POST **/co2_report** (CO2 report data generation)" + + * **Description**: Core endpoint that allows users to submit data for the CO2 report generation. Data is processed by the CAiMIRA engine, and the results are returned in the response. + * The input, response and error handling topics are similar to the previously described `virus_report` section. + + **Example body:** + + { + "CO2_data": "{\"times\":[8,8,8.1,8.1,8.1,8.2,8.2,8.2,8.3,8.3,8.3,8.4,8.4,8.4,8.5,8.5,8.5,8.6,8.6,8.6,8.7,8.7,8.7,8.8,8.8,8.8,8.9,8.9,8.9,9,9,9,9.1,9.1,9.1,9.2,9.2,9.2,9.3,9.3,9.3,9.4,9.4,9.4,9.5,9.5,9.5,9.6,9.6,9.6,9.7,9.7,9.7,9.8,9.8,9.8,9.9,9.9,9.9,10,10,10,10.1,10.1,10.1,10.2,10.2,10.2,10.3,10.3,10.3,10.4,10.4,10.4,10.5,10.5,10.5,10.6,10.6,10.6,10.7,10.7,10.7,10.8,10.8,10.8,10.9,10.9,10.9,11,11,11,11.1,11.1,11.1,11.2,11.2,11.2,11.3,11.3,11.3,11.4,11.4,11.4,11.5,11.5,11.5,11.6,11.6,11.6,11.7,11.7,11.7,11.8,11.8,11.8,11.9,11.9,11.9,12,12,12,12.1,12.1,12.1,12.2,12.2,12.2,12.3,12.3,12.3,12.4,12.4,12.4,12.5,12.5,12.5,12.6,12.6,12.6,12.7,12.7,12.7,12.8,12.8,12.8,12.9,12.9,12.9,13,13,13,13.1,13.1,13.1,13.2,13.2,13.2,13.3,13.3,13.3,13.4,13.4,13.4,13.5,13.5,13.5,13.6,13.6,13.6,13.7,13.7,13.7,13.8,13.8,13.8,13.9,13.9,13.9,14,14,14,14.1,14.1,14.1,14.2,14.2,14.2,14.3,14.3,14.3,14.4,14.4,14.4,14.5,14.5,14.5,14.6,14.6,14.6,14.7,14.7,14.7,14.8,14.8,14.8,14.9,14.9,14.9,15,15,15,15.1,15.1,15.1,15.2,15.2,15.2,15.3,15.3,15.3,15.4,15.4,15.4,15.5,15.5,15.5,15.6,15.6,15.6,15.7,15.7,15.7,15.8,15.8,15.8,15.9,15.9,15.9,16,16,16,16.1,16.1,16.1,16.2,16.2,16.2,16.3,16.3,16.3,16.4,16.4,16.4,16.5,16.5,16.5,16.6,16.6,16.6,16.7,16.7,16.7,16.8,16.8,16.8,16.9,16.9,16.9,17,17,17,17.1,17.1,17.1,17.2,17.2,17.2,17.3,17.3,17.3,17.4,17.4,17.4,17.5,17.5,17.5,17.6,17.6,17.6,17.7,17.7,17.7,17.8,17.8,17.8,17.9,17.9,17.9,18,18,18,18.1,18.1,18.1,18.2,18.2,18.2,18.3,18.3,18.3,18.4,18.4,18.4,18.5,18.5,18.5,18.6,18.6,18.6,18.7,18.7,18.7,18.8,18.8,18.8,18.9,18.9,18.9,19,19,19,19.1,19.1,19.1,19.2,19.2,19.2,19.3,19.3,19.3,19.4,19.4,19.4,19.5,19.5,19.5,19.6,19.6,19.6,19.7,19.7,19.7,19.8,19.8,19.8,19.9,19.9,19.9,20],\"CO2\":[445.2,443.3,440.9,443.4,442.4,444.1,445.2,445.7,448,448,444,442.5,439.3,438.2,441.4,441.2,443.8,445.2,446.5,445.3,452.1,458.8,470.8,478.1,488.3,502.1,522.1,545.5,579.9,616.2,641.2,676.3,701.9,720.5,746.9,765.8,779.1,794.2,810.6,826,838.3,854.4,876.4,886.2,898.4,921.7,942.8,953.8,979,990.3,1002.9,1017.4,1029.4,1041,1051.9,1067.2,1073.5,1079.7,1093.7,1104.8,1125.8,1141.1,1151,1160.1,1176.4,1193.7,1180.1,1015.3,864.7,802.7,774.5,728.3,697.3,676.1,657.6,640.6,606.5,595.9,577.8,553.6,530.2,525,523.2,521.5,512.9,505.3,502.1,502.5,505.2,507.5,509.2,511.3,513.8,520.4,529.1,532.8,530.1,524,521.6,519.1,510.3,510,514.3,518.4,524.6,521,519.4,523.3,527.5,528.3,526.4,527,530,534,535.6,533.5,530.6,522.3,524.2,532,539.1,538.8,526.2,517.5,508,493.7,485.6,479.5,471.6,472.2,468.2,463.1,461,459,456.4,458.6,459.2,463,465.6,468.4,475.2,480.3,489,528,579.6,606.6,611.2,617,635.9,651.1,676.6,696.6,714.6,729.9,744.7,766,788.5,812.1,832.8,854.7,883.9,895.6,910,924.4,944.5,956.8,971.4,981.3,993.6,1004.4,1021.6,1035.2,1043.8,1063.7,1071,1065.6,1065.9,1073.7,1086.4,1093.5,1120.1,1189.3,1202.9,1218.6,1238.5,1250.1,1263.5,1265,1270.1,1281.6,1294.9,1304.2,1315.5,1338.4,1351.5,1353.4,1364,1361.7,1343.3,1329.7,1320.4,1310.5,1313.6,1305.5,1313.4,1307.5,1290,1286.9,1289.3,1276.8,1268.9,1266.1,1264,1271.8,1268.5,1244.5,1206.4,1173.6,1145,1157.2,1194.4,1198.3,1196.1,1182.5,1167.9,1150.4,1132.8,1108.1,1097.4,1099.8,1093.4,1086.8,1086.9,1083.8,1075.5,1059.9,1048.4,1047.4,1042.6,1036.1,1026.9,1022.7,1017.6,1023.5,1021,1017.3,1004.6,908.3,906.5,979.2,955.8,928.9,915.3,914.1,930.1,923.3,921,865.9,860.2,867,869.7,871.4,861.5,862.9,850.4,843.9,839.7,838.1,839.8,849.7,841.6,820.8,825,838.5,853.8,855.6,838.7,818.1,811.7,804.3,794.5,790.6,782,788.6,779.6,804.2,836.9,852.4,856.9,858.1,857.9,856.5,856.7,851.7,849.6,849.2,846,846.8,844.8,842,839,836,833.2,832.6,830.9,825.9,823.6,823.7,818.2,812.4,810.2,808.4,806.7,803,800.2,794.3,790.5,790.4,787.7,783.3,780.5,784,780.9,780.8,777.2,775,768.7,763.6,761.5,757.8,760,762.1,761.6,761.2,761.5,757.5,754.5,752.6,752.1,751.7,748.6,744.3,742.1,737.6,731,732.6,726.8,726.2,726.9,727.1,726.8,728.9,729.9,726.5,724.8,723.9,723,721.1,720.2,721.1]}", + "activity_type": "office", + "exposed_lunch_finish": "13:30", + "exposed_lunch_start": "12:30", + "exposed_start": "08:30", + "fitting_ventilation_states": "[8.5, 17.5]", + "infected_finish": "17:30", + "infected_lunch_finish": "13:30", + "infected_lunch_start": "12:30", + "infected_people": "1", + "infected_start": "08:30", + "room_capacity": "10", + "room_volume": "60", + "total_people": "2" + } + + For the full list of accepted inputs and respective values please refer to CAiMIRA's official defaults in GitLab repository [here](https://gitlab.cern.ch/caimira/caimira/-/blob/master/caimira/src/caimira/calculator/validators/defaults.py?ref_type=heads). + + ??? "**Example cURL** (with the above body)" + + curl -X POST "http://localhost:8088/co2_report" \ + -H "Content-Type: application/json" \ + -d '{ + "CO2_data": "{\"times\":[8,8,8.1,8.1,8.1,8.2,8.2,8.2,8.3,8.3,8.3,8.4,8.4,8.4,8.5,8.5,8.5,8.6,8.6,8.6,8.7,8.7,8.7,8.8,8.8,8.8,8.9,8.9,8.9,9,9,9,9.1,9.1,9.1,9.2,9.2,9.2,9.3,9.3,9.3,9.4,9.4,9.4,9.5,9.5,9.5,9.6,9.6,9.6,9.7,9.7,9.7,9.8,9.8,9.8,9.9,9.9,9.9,10,10,10,10.1,10.1,10.1,10.2,10.2,10.2,10.3,10.3,10.3,10.4,10.4,10.4,10.5,10.5,10.5,10.6,10.6,10.6,10.7,10.7,10.7,10.8,10.8,10.8,10.9,10.9,10.9,11,11,11,11.1,11.1,11.1,11.2,11.2,11.2,11.3,11.3,11.3,11.4,11.4,11.4,11.5,11.5,11.5,11.6,11.6,11.6,11.7,11.7,11.7,11.8,11.8,11.8,11.9,11.9,11.9,12,12,12,12.1,12.1,12.1,12.2,12.2,12.2,12.3,12.3,12.3,12.4,12.4,12.4,12.5,12.5,12.5,12.6,12.6,12.6,12.7,12.7,12.7,12.8,12.8,12.8,12.9,12.9,12.9,13,13,13,13.1,13.1,13.1,13.2,13.2,13.2,13.3,13.3,13.3,13.4,13.4,13.4,13.5,13.5,13.5,13.6,13.6,13.6,13.7,13.7,13.7,13.8,13.8,13.8,13.9,13.9,13.9,14,14,14,14.1,14.1,14.1,14.2,14.2,14.2,14.3,14.3,14.3,14.4,14.4,14.4,14.5,14.5,14.5,14.6,14.6,14.6,14.7,14.7,14.7,14.8,14.8,14.8,14.9,14.9,14.9,15,15,15,15.1,15.1,15.1,15.2,15.2,15.2,15.3,15.3,15.3,15.4,15.4,15.4,15.5,15.5,15.5,15.6,15.6,15.6,15.7,15.7,15.7,15.8,15.8,15.8,15.9,15.9,15.9,16,16,16,16.1,16.1,16.1,16.2,16.2,16.2,16.3,16.3,16.3,16.4,16.4,16.4,16.5,16.5,16.5,16.6,16.6,16.6,16.7,16.7,16.7,16.8,16.8,16.8,16.9,16.9,16.9,17,17,17,17.1,17.1,17.1,17.2,17.2,17.2,17.3,17.3,17.3,17.4,17.4,17.4,17.5,17.5,17.5,17.6,17.6,17.6,17.7,17.7,17.7,17.8,17.8,17.8,17.9,17.9,17.9,18,18,18,18.1,18.1,18.1,18.2,18.2,18.2,18.3,18.3,18.3,18.4,18.4,18.4,18.5,18.5,18.5,18.6,18.6,18.6,18.7,18.7,18.7,18.8,18.8,18.8,18.9,18.9,18.9,19,19,19,19.1,19.1,19.1,19.2,19.2,19.2,19.3,19.3,19.3,19.4,19.4,19.4,19.5,19.5,19.5,19.6,19.6,19.6,19.7,19.7,19.7,19.8,19.8,19.8,19.9,19.9,19.9,20],\"CO2\":[445.2,443.3,440.9,443.4,442.4,444.1,445.2,445.7,448,448,444,442.5,439.3,438.2,441.4,441.2,443.8,445.2,446.5,445.3,452.1,458.8,470.8,478.1,488.3,502.1,522.1,545.5,579.9,616.2,641.2,676.3,701.9,720.5,746.9,765.8,779.1,794.2,810.6,826,838.3,854.4,876.4,886.2,898.4,921.7,942.8,953.8,979,990.3,1002.9,1017.4,1029.4,1041,1051.9,1067.2,1073.5,1079.7,1093.7,1104.8,1125.8,1141.1,1151,1160.1,1176.4,1193.7,1180.1,1015.3,864.7,802.7,774.5,728.3,697.3,676.1,657.6,640.6,606.5,595.9,577.8,553.6,530.2,525,523.2,521.5,512.9,505.3,502.1,502.5,505.2,507.5,509.2,511.3,513.8,520.4,529.1,532.8,530.1,524,521.6,519.1,510.3,510,514.3,518.4,524.6,521,519.4,523.3,527.5,528.3,526.4,527,530,534,535.6,533.5,530.6,522.3,524.2,532,539.1,538.8,526.2,517.5,508,493.7,485.6,479.5,471.6,472.2,468.2,463.1,461,459,456.4,458.6,459.2,463,465.6,468.4,475.2,480.3,489,528,579.6,606.6,611.2,617,635.9,651.1,676.6,696.6,714.6,729.9,744.7,766,788.5,812.1,832.8,854.7,883.9,895.6,910,924.4,944.5,956.8,971.4,981.3,993.6,1004.4,1021.6,1035.2,1043.8,1063.7,1071,1065.6,1065.9,1073.7,1086.4,1093.5,1120.1,1189.3,1202.9,1218.6,1238.5,1250.1,1263.5,1265,1270.1,1281.6,1294.9,1304.2,1315.5,1338.4,1351.5,1353.4,1364,1361.7,1343.3,1329.7,1320.4,1310.5,1313.6,1305.5,1313.4,1307.5,1290,1286.9,1289.3,1276.8,1268.9,1266.1,1264,1271.8,1268.5,1244.5,1206.4,1173.6,1145,1157.2,1194.4,1198.3,1196.1,1182.5,1167.9,1150.4,1132.8,1108.1,1097.4,1099.8,1093.4,1086.8,1086.9,1083.8,1075.5,1059.9,1048.4,1047.4,1042.6,1036.1,1026.9,1022.7,1017.6,1023.5,1021,1017.3,1004.6,908.3,906.5,979.2,955.8,928.9,915.3,914.1,930.1,923.3,921,865.9,860.2,867,869.7,871.4,861.5,862.9,850.4,843.9,839.7,838.1,839.8,849.7,841.6,820.8,825,838.5,853.8,855.6,838.7,818.1,811.7,804.3,794.5,790.6,782,788.6,779.6,804.2,836.9,852.4,856.9,858.1,857.9,856.5,856.7,851.7,849.6,849.2,846,846.8,844.8,842,839,836,833.2,832.6,830.9,825.9,823.6,823.7,818.2,812.4,810.2,808.4,806.7,803,800.2,794.3,790.5,790.4,787.7,783.3,780.5,784,780.9,780.8,777.2,775,768.7,763.6,761.5,757.8,760,762.1,761.6,761.2,761.5,757.5,754.5,752.6,752.1,751.7,748.6,744.3,742.1,737.6,731,732.6,726.8,726.2,726.9,727.1,726.8,728.9,729.9,726.5,724.8,723.9,723,721.1,720.2,721.1]}", + "activity_type": "office", + "exposed_lunch_finish": "13:30", + "exposed_lunch_start": "12:30", + "exposed_start": "08:30", + "fitting_ventilation_states": "[8.5, 17.5]", + "infected_finish": "17:30", + "infected_lunch_finish": "13:30", + "infected_lunch_start": "12:30", + "infected_people": "1", + "infected_start": "08:30", + "room_capacity": "10", + "room_volume": "60", + "total_people": "2" + }' \ No newline at end of file diff --git a/caimira/docs/mkdocs/docs/index.md b/caimira/docs/mkdocs/docs/index.md new file mode 100644 index 00000000..cab09eea --- /dev/null +++ b/caimira/docs/mkdocs/docs/index.md @@ -0,0 +1,28 @@ +# Welcome to CAiMIRA’s documentation! + +This documentation provides comprehensive guidance on the CERN Airborne Model for Risk Assessment ([CAiMIRA](https://caimira.web.cern.ch/)) tool. + +It includes details on the diameter-dependent mathematical model and the code developed based on the underlying published research. It also covers documentation on the code itself, including explanations of the main module (`models.py`), and the recently added REST API feature, providing a through understanding of the CAiMIRA's functionality. + +
+ [![CAiMIRA logo](assets/caimira_logo.png){ width="100" }](https://caimira.web.cern.ch/) +
+ +# Contents: + +* [About](root/about.md) +* [Installation](root/installation.md) +* [Deployment](root/deployment.md) +* [Open Source Acknowledgments](root/open_source_acknowledgments.md) +* [License](LICENSE.md) +* [Physics of the model](root/physics_model.md) +* **Code** + * [Architecture](code/architecture.md) + * [CO₂ Fitting Algorithm](code/fitting_algorithm.md) + * [REST API](code/rest_api.md) + * [models.py](code/models.md) +* **User Interfaces** + * **CAiMIRA Calculator** + * [Quick Guide](user_interfaces/CAiMIRA/quick_guide.md) + * [Full Guide](user_interfaces/CAiMIRA/full_guide.md) + * [ARIA](https://partnersplatform.who.int/aria) diff --git a/caimira/docs/mkdocs/docs/root/about.md b/caimira/docs/mkdocs/docs/root/about.md new file mode 100644 index 00000000..69a0c2f0 --- /dev/null +++ b/caimira/docs/mkdocs/docs/root/about.md @@ -0,0 +1,106 @@ +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. + +For information on the Airborne Transmission of SARS-CoV-2, feel free to check out the special issue on the Interface Focus journal from Royal Society publishing: [Interface Focus: Volume 12, Issue 2](https://royalsocietypublishing.org/toc/rsfs/2022/12/2) and an CERN HSE Seminar: [https://cds.cern.ch/record/2743403](https://cds.cern.ch/record/2743403). + +## What is CAiMIRA? + +CAiMIRA stands for CERN Airborne Model for Indoor Risk Assessment, a tool developed to assess and model the concentration of airborne viruses in enclosed spaces, specifically focusing on the SARS-CoV-2 virus. Originally named CARA (COVID Airborne Risk Assessment), CAiMIRA was first developed in early 2020 to quantify the risk of long-range airborne spread of SARS-CoV-2 in workplaces. Over time, the model has expanded to include short-range transmission, allowing for comprehensive simulations of both background (room) concentration and close-proximity interactions. + +CAiMIRA features applications with varying flexibility in setting input parameters: + +- CAiMIRA Calculator App +- CAiMIRA Expert App (deprecated) + +These applications produce clear and intuitive graphs, enabling users to adjust settings such as room volume, exposure time, activity type, mask-wearing, and ventilation levels. The tool generates reports indicating how users can avoid exceeding critical concentrations and reduce airborne transmission chains in spaces like individual offices, meeting rooms, and laboratories. + +The mathematical and physical model simulates the airborne spread of SARS-CoV-2 in a finite volume, using a homogenous mixture assumption and a two-stage exhaled jet model to estimate the risk of COVID-19 airborne transmission. Results do not account for other SARS-CoV-2 transmission modes, such as fomite or blood-bound transmission, meaning the output is only valid when paired with public health measures like good hand hygiene and barrier practices. + +The model is based on scientific publications on infectious disease transmission, virology, epidemiology, and aerosol science, as of February 2022. Its methodology, mathematical equations, and parameters are detailed in a peer-reviewed publication, Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces. The short-range model component draws from Jia et al. (2022), Exposure and respiratory infection risk via the short-range airborne route. This foundation enables CAiMIRA to compare the effectiveness of different airborne risk mitigation measures. + +CAiMIRA’s methodology is divided into key steps: + +- Estimating the emission rate of virions +- Estimating the removal rate of virions +- Modeling the concentration of virions within a specified volume over time +- Calculating the dose of inhaled infectious viruses during exposure +- Estimating the probability of COVID-19 infection and the potential number of new cases arising from an event + +The model assumes a deterministic approach—at least one individual is infected and shedding virus into the simulated environment. While it calculates the infection probability for specific scenarios, the model's primary utility is in comparing the relative impact of different preventive measures, such as ventilation, filtration, exposure time, physical activity, and close-range interactions. + +Although CAiMIRA allows users to calculate the infection probability for a specific event given pre-set protection measures, its primary function is to facilitate comparisons between different mitigation, helping users decide on measures to reduce airborne infection risks. Examples include: + +- Comparing slight versus full window openings +- Evaluating intermittent versus continuous ventilation +- Assessing the impact of using FFP2 masks over Type I surgical masks or Cloth masks +- Determining maximum occupancy based on HEPA filter use + +This approach supports informed decision-making and optimized investment by showing the relative effectiveness of each measure. Importantly, while CAiMIRA can guide users in reducing risk, it does not provide an absolute “zero risk” or “completely safe scenario”. + +Risk is unique to each event and setting, influenced by variables such as probability of exposure and input assumptions. + +## Collaboration with the World Health Organization (WHO) + +The tool has attracted the attention of many international organisations, including the World Health Organization (WHO) and the United Nations Office at Geneva (UNOG). In June 2021, CERN shared its own approach towards risk assessments for occupational hazards, which was at the time called CARA, to WHO's COVID Expert Panel. + +As a result, WHO has invited CERN to become a member of a multidisciplinary expert group of international experts called ARIA, which will work to define a standardised algorithm to quantify airborne transmission risk in indoor settings. This will ensure that the model inculdes not only the science related to aerosol science but also the virological effects, such as host-pathogen interaction. + +The collaboration takes place within CERNs wide-ranging engagement with other international organisations, promoting shared solutions to societal challenges. + +## Authors + +Andre Henriques1,2, Wei Jia3, Luis Aleixo1, Nicolas Mounet1, Luca Fontana4,5, Alice Simniceanu2,6, James Devine1, Philip Elson1, Gabriella Azzopardi1, Markus Kongstein Rognlien1,7, Marco Andreini1, Nicola Tarocco1, Olivia Keiser2, Yugou Li3, Julian Tang8 + +1CERN (European Organization for Nuclear Research), Geneva, Switzerland
+2Institute of Global Health, University of Geneva, Geneva, Switzerland
+3Department of Mechanical Engineering, University of Hong Kong, Hong Kong SAR, China
+4Strategic Health Operations, Operations Support and Logistic, Health Emergencies Programme, World Health Organization, Geneva, Switzerland
+5Department of Civil and Mechanical Engineering, Università degli studi di Cassino e del Lazio Meridionale (UNICAS), Cassino, Italy
+6Epidemic and Pandemic Preparedness, Health Emergencies Programme, World Health Organization, Geneva, Switzerland
+7Norwegian University of Science and Technology (NTNU), Torgarden, Norway
+8Respiratory Sciences, University of Leicester, Leicester, UK
+ +#### Other contributors + +Anna Efimova1,2, Anel Massalimova1,3, Cole Austin Coughlin1,4, Germain Personne5, Matteo Manzinello6, Elias Sandner1 + +1CERN
+2M.V. Lomonosov Moscow State University
+3National Research Nuclear University "MEPhI"
+4University of Manitoba
+5Université Clermont Auvergne
+6World Health Organization (WHO)
+ +## Reference and Citation + +**For the use of the CAiMIRA web app** + +CAiMIRA – CERN Airborne Model for Indoor Risk Assessment tool + +[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6520431.svg)](https://doi.org/10.5281/zenodo.6520431) + +© Copyright 2020-2021 CERN. All rights not expressly granted are reserved. + +**For use of the CAiMIRA model** + +Henriques A, Mounet N, Aleixo L, Elson P, Devine J, Azzopardi G, Andreini M, Rognlien M, Tarocco N, Tang J. (2022). Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces. _Interface Focus 20210076_. [https://doi.org/10.1098/rsfs.2021.0076](https://doi.org/10.1098/rsfs.2021.0076) + +Reference on the Short-range expiratory jet model from: +Jia W, Wei J, Cheng P, Wang Q, Li Y. (2022). Exposure and respiratory infection risk via the short-range airborne route. _Building and Environment_ *219*: 109166. +[https://doi.org/10.1016/j.buildenv.2022.109166](https://doi.org/10.1016/j.buildenv.2022.109166) + +***Open Source Acknowledgments*** + +For a detailed list of the open-source dependencies used in this project along with their respective licenses, please refer to [Open Source Acknowledgments](open_source_acknowledgments.md). This includes both the core dependencies specified in the project's requirements and their transitive dependencies. + +The information also features a distribution diagram of licenses and a brief description of each of them. + +## Acknowledgements + +We wish to thank CERN at the different Departments working on the project: Occupational Health & Safety and Environmental Protection Unit, Information Technology Department, Beams Department, Experimental Physics Department, Industry, Procurement and Knowledge Transfer Department and International Relations Sector for their support to the study. We also wish to thank our collaborators at the World Health Organization (WHO) for thier endless support to this project, in particular to the members of the ARIA Expert Group. + +## Disclaimer + +CAiMIRA 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. \ No newline at end of file diff --git a/caimira/docs/mkdocs/docs/root/deployment.md b/caimira/docs/mkdocs/docs/root/deployment.md new file mode 100644 index 00000000..82780431 --- /dev/null +++ b/caimira/docs/mkdocs/docs/root/deployment.md @@ -0,0 +1,159 @@ +The [https://cern.ch/caimira](https://cern.ch/caimira) application is running on CERN's OpenShift platform. In order to set it up for the first time, we followed the documentation at [https://paas.docs.cern.ch/](https://paas.docs.cern.ch/). In particular we: + + * Added the OpenShift application deploy key to the GitLab repository + * Created a Python 3.12 (the highest possible at the time of writing) application in OpenShift + * Configured a generic webhook on OpenShift, and call that from the CI of the GitLab repository + +## OpenShift templates + +For the first setup, get the [oc](https://docs.okd.io/3.11/cli_reference/get_started_cli.html) client and then login: + +```console +$ oc login https://api.paas.okd.cern.ch +``` + +Then, switch to the project that you want to update: + +```console +$ oc project caimira-test +``` + +Create a new service account in OpenShift to access GitLab container registry: + +```console +$ oc create serviceaccount gitlabci-deployer +serviceaccount "gitlabci-deployer" created +``` + +Grant `edit` permission to the service account to run `oc set image` from CI an update the tag to deploy: +``` +$ oc policy add-role-to-user edit -z gitlabci-deployer +``` + +Get the service account token for GitLab: +``` +# We will refer to the output of this command as `test-token` +$ oc serviceaccounts get-token gitlabci-deployer +<...test-token...> +``` + +Add the token to GitLab to allow GitLab to access OpenShift and define/change image stream tags. Go to `Settings` -> `CI / CD` -> `Variables` -> click on `Expand` button and create the variable `OPENSHIFT_CAIMIRA_TEST_DEPLOY_TOKEN`: insert the token `<...test-token...>`. + +For CI usage, we also suggest creating a service account: + +```console +oc create sa gitlab-config-checker +``` + +Under ``User Management`` -> ``RoleBindings`` create a new `RoleBinding` to grant `View` access to the `gitlab-config-checker` service account: + +* name: `gitlab-config-checker-view-role` +* role name: `view` +* service account: `gitlab-config-checker` + +To get this new user's authentication token go to ``User Management`` -> ``Service Accounts`` -> `gitlab-config-checker` and locate the token in the newly created secret associated with the user (in this case ``gitlab-config-checker-token-XXXX``). Copy the `token` value from `Data`. + +Create the various configurations: + +```console +$ cd app-config/openshift + +$ oc process -f configmap.yaml | oc create -f - +$ oc process -f services.yaml | oc create -f - +$ oc process -f deployments.yaml | oc create -f - +``` + +Manually create the **route** to access the website, see `routes.example.yaml`. +After having created the route, make sure that you extend the HTTP request timeout annotation: the +report generation can take more time than the default 30 seconds. + +``` +$ oc annotate route caimira-route --overwrite haproxy.router.openshift.io/timeout=60s +``` + +## CERN SSO integration + +The SSO integration uses OpenID credentials configured in [CERN Applications portal](https://application-portal.web.cern.ch/). +How to configure the application: + +* Application Identifier: `caimira-test` +* Homepage: `https://caimira-test.web.cern.ch` +* Administrators: `caimira-dev` +* SSO Registration: + * Protocol: `OpenID (OIDC)` + * Redirect URI: `https://caimira-test.web.cern.ch/auth/authorize` + * Leave unchecked all the other checkboxes +* Define new roles: + * Name: `CERN Users` + * Role Identifier: `external-users` + * Leave unchecked checkboxes + * Minimum Level Of Assurance: `CERN (highest)` + * Assign role to groups: `cern-accounts-primary` e-group + * Name: `External accounts` + * Role Identifier: `admin` + * Leave unchecked checkboxes + * Minimum Level Of Assurance: `Any (no restrictions)` + * Assign role to groups: `caimira-app-external-access` e-group + * Name: `Allowed users` + * Role Identifier: `allowed-users` + * Check `This role is required to access my application` + * Minimum Level Of Assurance:`Any (no restrictions)` + * Assign role to groups: `cern-accounts-primary` and `caimira-app-external-access` e-groups + +Copy the client id and client secret and use it below. + +```console +$ COOKIE_SECRET=$(openssl rand -hex 50) +$ oc create secret generic \ + --from-literal="CLIENT_ID=$CLIENT_ID" \ + --from-literal="CLIENT_SECRET=$CLIENT_SECRET" \ + --from-literal="COOKIE_SECRET=$COOKIE_SECRET" \ + auth-service-secrets +``` + +## Updating OpenShift configuration + +If you need to **update** existing configuration, then modify this repository and after having logged in, run: + +```console +$ cd app-config/openshift + + +$ oc process -f configmap.yaml | oc replace -f - +$ oc process -f services.yaml | oc replace -f - +$ oc process -f deployments.yaml | oc replace -f - +``` + +Be aware that if you create/recreate the environment you must manually create a **route** in OpenShift, +specifying the respective annotation to be exposed outside CERN. + + +## Updating the TEST instance + +We have a replica of [https://caimira.web.cern.ch](https://caimira.web.cern.ch) running on [http://caimira-test.web.cern.ch](http://caimira-test.web.cern.ch). Its purpose is to simulate what will happen when +a feature is merged. To push your changes to caimira-test, simply push your branch to `live/caimira-test` and the CI pipeline will trigger the +deployment. To push to this branch, there is a good chance that you will need to force push - you should always force push with care and +understanding why you are doing it. Syntactically, it will look something like (assuming that you have "upstream" as your remote name, +but it may be origin if you haven't configured it differently): + + git push --force upstream name-of-local-branch:live/caimira-test + +## Deployment Process + +The deployment process varies depending on whether changes are pushed to branches, tags, or the test environment (`live/caimira-test` branch). + +### Branch and Tag-based Deployment + +For branch pushes: + +* All branches (except `live/caimira-test`) trigger the **test** stage in the CI/CD pipeline, ensuring the code passes all necessary tests before it is deployed. + +For tag creation: + +* When a new tag is created, the pipeline skips the previous tests, and it builds `Docker` images, storing them in GitLab's container registry. The images can be manually deployed to the OKD platform for the `PROD` - production environment. + +### OKD Platform Deployment +The `cern_caimira` package, which contains the CERN-specific UI, is deployed directly to the OKD platform. The `caimira package`, which contains the backend logic, is deployed as a standalone API for integration with external services. + +### Versioning and Tags +The repository follows a *semantic versioning* scheme, with tags named according to the `MAJOR.MINOR.PATCH` format (e.g., `v5.0.0`). diff --git a/caimira/docs/mkdocs/docs/root/installation.md b/caimira/docs/mkdocs/docs/root/installation.md new file mode 100644 index 00000000..e0e9ae34 --- /dev/null +++ b/caimira/docs/mkdocs/docs/root/installation.md @@ -0,0 +1,230 @@ +## Docker + +### Using the pre-built image + +The easiest way to run a version of CAiMIRA Calculator is to use docker. A pre-built +image of CAiMIRA is made available at [https://gitlab.cern.ch/caimira/caimira/container_registry](https://gitlab.cern.ch/caimira/caimira/container_registry). +In order to run CAiMIRA locally with docker, run the following: + + $ docker run -it -p 8080:8080 gitlab-registry.cern.ch/caimira/caimira/calculator + +This will start a local version of CAiMIRA, which can be visited at [http://localhost:8080/](http://localhost:8080/). + +### Building the whole environment + +To build the whole environment for local development, from the root directory of the project, run: + +``` +docker build -f app-config/api-app/Dockerfile -t api-app . +docker build -f app-config/calculator-app/Dockerfile -t calculator-app . +docker build ./app-config/auth-service -t auth-service +``` + +If you are using a computer with ARM CPU (Mac M1/2/3), then add the arg `--platform linux/arm64` to the docker build cmd. + +If you need to debug the Docker build, add the args `--no-cache --progress=plain` to see a more verbose output in your terminal. + +Get the client secret from the CERN Application portal for the `caimira-test` app. See [CERN-SSO-integration](deployment.md#cern-sso-integration) for more info. +``` +read CLIENT_SECRET +``` + +Define some env vars (copy/paste): +``` +export COOKIE_SECRET=$(openssl rand -hex 50) +export OIDC_SERVER=https://auth.cern.ch/auth +export OIDC_REALM=CERN +export CLIENT_ID=caimira-test +export CLIENT_SECRET=$CLIENT_SECRET +``` + +Run docker compose: +``` +cd app-config +CURRENT_UID=$(id -u):$(id -g) docker compose up +``` + +Then visit [http://localhost:8080/](http://localhost:8080/). + +## Development mode + +CAiMIRA is mirrored to Github if you wish to collaborate on development and can be found at: [https://github.com/CERN/caimira](https://github.com/CERN/caimira) + +### Folder structure + +The project contains two different Python packages: + +- `caimira`: Contains all the backend logic and the calculator model. It is the package published in PyPI. +- `cern_caimira`: Imports and uses the backend package (`caimira`) and includes CERN-specific UI implementation. + +The folder layout follows best practices as described [here](https://ianhopkinson.org.uk/2022/02/understanding-setup-py-setup-cfg-and-pyproject-toml-in-python/). + +### Installing and running CAiMIRA + +Installing CAiMIRA in editable mode and running the Calculator App. + +#### Installing + +In order to install the CAiMIRA's backend logic, create your own `virtualenv` and, from the root directory of the project, run: + +``` +cd caimira +pip install -e . +``` + +In order to install the CERN-specific UI version, that links to the previously installed backend, activate your `virtualenv` and, from the root directory of the project, run: + +``` +cd cern_caimira +pip install -e . +``` + +#### Running + +This example describes how to run the calculator with the CERN-specific UI. In the root directory of the project: + +``` +python -m cern_caimira.apps.calculator +``` + +To run with a specific template theme created: + +``` +python -m cern_caimira.apps.calculator --theme=cern_caimira/src/cern_caimira/apps/templates/{theme} +``` + +To run the entire app in a different `APPLICATION_ROOT` path: + +``` +python -m cern_caimira.apps.calculator --app_root=/myroot +``` + +To run the calculator on a different URL path: + +``` +python -m cern_caimira.apps.calculator --prefix=/mycalc +``` + +Each of these commands will start a local version of CAiMIRA, which can be visited at [http://localhost:8080/](http://localhost:8080/). + +#### REST API + +To use the REST API, from the root directory of the project: + +1. Run the backend API: + + ``` + python -m caimira.api.app + ``` + +2. The Tornado server will run on port `8081`. + +To test the API functionality, you can send a `POST` request to `http://localhost:8081/virus_report` with the required inputs in the request body. For an example of the required inputs, see [the baseline raw form data](https://gitlab.cern.ch/caimira/caimira/blob/master/caimira/src/caimira/calculator/validators/virus/virus_validator.py#L565). + +The response format will be: + +```json +{ + "status": "success", + "message": "Results generated successfully", + "report_data": { + ... + }, + ... +} +``` + +For further details please refer to the [REST API documentation page](../code/rest_api.md). + +#### Running the Expert-Apps + +The CAiMIRA Expert App and the CO2 App are tools to dynamically interact with various parameters of the CAiMIRA model. + +##### Disclaimer + +The `ExpertApplication` and `CO2Application` are no longer actively maintained but will remain in the codebase for legacy purposes. +Please note that the functionality of these applications might be compromised due to deprecation issues. + +##### Running the Applications + +These applications only work within Jupyter notebooks. Attempting to run them outside of a Jupyter environment may result in errors or degraded functionality. + +Make sure you have the needed dependencies installed: + +``` +pip install notebook jupyterlab +``` + +Running with Visual Studio Code (VSCode): + +1. Ensure you have the following extensions installed in VSCode: `Jupyter` and `Python`. + +2. Open VSCode and navigate to the directory containing the notebook. + +3. Open the notebook (e.g. `caimira/apps/expert/caimira.ipynb`) and run the cells by clicking the `run` button next to each cell. + + +### Installing and running tests + +The project contains test files that separately test the functionality of the `caimira` backend and `cern_caimira` UI. + +To test the `caimira` package, from the root repository of the project: + +``` +cd caimira +pip install -e .[test] +python -m pytest +``` + +To test the `cern_caimira` package, from the root repository of the project: + +``` +cd cern_caimira +pip install -e .[test] +python -m pytest +``` + +### Running the profiler + +CAiMIRA includes a profiler designed to identify performance bottlenecks. The profiler is enabled when the environment variable `CAIMIRA_PROFILER_ENABLED` is set to 1. + +When visiting [http://localhost:8080/profiler](http://localhost:8080/profiler), you can start a new session and choose between [PyInstrument](https://github.com/joerick/pyinstrument) or [cProfile](https://docs.python.org/3/library/profile.html#module-cProfile). The app includes two different profilers, mainly because they can give different information. + +Keep the profiler page open. Then, in another window, navigate to any page in CAiMIRA, for example generate a new report. Refresh the profiler page, and click on the `Report` link to see the profiler output. + +The sessions are stored in a local file in the `/tmp` folder. To share it across multiple web nodes, a shared storage should be added to all web nodes. The folder can be customized via the environment variable `CAIMIRA_PROFILER_CACHE_DIR`. + +### Compiling and viewing the docs + +To compile and view CAiMIRA's documentation, follow these steps: + +1. Install CAiMIRA with Documentation Dependencies + + First, ensure CAiMIRA is installed along with the `doc` dependencies: + + cd caimira + pip install -e .[doc] + +2. Generate Code Documentation in Markdown + + Use `sphinx` with `sphinx_markdown_builder` to generate the documentation in `Markdown` format: + + cd docs/sphinx + sphinx-build -b markdown . _build/markdown + +3. Customize and Organize Documentation + + Run the `style_docs.py` script to apply custom styles, move required files, and generate a UML diagram: + + python style_docs.py \ + && mv sphinx/_build/markdown/index.md mkdocs/docs/code/models.md \ + && pyreverse -o png -p UML-CAiMIRA --output-directory mkdocs/docs ../src/caimira/calculator/models/models.py + +4. Start the documentation server + + To view the documentation locally, use MkDocs to serve it: + + cd ../mkdocs + python -m mkdocs serve --dev-addr=0.0.0.0:8080 + + The documentation can now be accessed at [http://0.0.0.0:8080/](http://0.0.0.0:8080/). diff --git a/caimira/docs/mkdocs/docs/root/open_source_acknowledgments.md b/caimira/docs/mkdocs/docs/root/open_source_acknowledgments.md new file mode 100644 index 00000000..d1850689 --- /dev/null +++ b/caimira/docs/mkdocs/docs/root/open_source_acknowledgments.md @@ -0,0 +1,139 @@ +#### Disclaimer + +The following list includes the open-source dependencies used in this project, along with their respective licenses. It covers both the core dependencies explicitly specified in the project's requirements, as well as their transitive dependencies (dependencies of dependencies). + +Including transitive dependencies is essential to acknowledge the full spectrum of open-source contributions that contribute to the functionality of this project. It also ensures compliance with open-source licenses and recognizes the efforts of all contributors, even those indirectly involved. + +## External Libraries + +??? "Back-end (Python) Dependencies" +??? "Front-end (JavaScript) Dependencies" + + #### jQuery 3.5.1 + + - License: [MIT License](https://github.com/jquery/jquery/blob/main/LICENSE.txt) + + #### jQuery Colorbox + + - License: [MIT License](https://github.com/jackmoore/colorbox/blob/1.6.4/LICENSE.md) + + #### ScrollMagic + + - License: [MIT License](https://github.com/janpaepke/ScrollMagic/blob/v2.0.5/LICENSE.md) + + #### Twitter Bootstrap 4.5.3 + + - License: [MIT License](https://github.com/twbs/bootstrap/blob/v4.5.3/LICENSE) + + #### d3.js + + - License: [ISC License](https://github.com/d3/d3/blob/v7.8.5/LICENSE) + + +??? "Other references" + + #### Rest Countries + + - License: [MP License 2.0](https://gitlab.com/restcountries/restcountries/-/blob/master/LICENSE?ref_type=heads) + + #### WHO COVID-19 Global Data + + - Endpoint: `https://covid19.who.int/WHO-COVID-19-global-data.csv` + + #### ArcGIS Geocode + + - Endpoint: `https://geocode.arcgis.com` + + #### View Hub Resources + + - Endpoint: `https://view-hub.org/resources` + + #### CERN Web Analytics + + - Endpoint: `https://webanalytics.web.cern.ch/` + + #### Zenodo Badge + + - Endpoint: `https://zenodo.org/badge/DOI/10.5281/zenodo.6520431.svg` + - Description: Zenodo itself does not impose any specific license on the content that is deposited. Instead, it allows the depositor to choose the license for their content. This means that the permissiveness of the Zenodo badge (with the DOI) depends entirely on the license chosen by the person depositing the content. + + #### Swiss COVID-19 Data + + - Endpoint: `https://www.covid19.admin.ch/en/epidemiologic/case/d/development?epiRelDev=abs` + + ### External APIs + + - **Geographical location**: + + There is one external API call to fetch required information related to the geographical location inserted by a user. + The documentation for this geocoding service is available at [https://developers.arcgis.com/rest/geocode/api-reference/geocoding-suggest.htm](https://developers.arcgis.com/rest/geocode/api-reference/geocoding-suggest.htm) . + Please note that there is no need for keys on this API call. It is **free-of-charge**. + + - **Humidity and Inside Temperature**: + + For the `CERN theme` as the authorized sensors are installed at CERN. + + - **ARVE**: + + The ARVE Swiss Air Quality System provides trusted air data for commercial buildings in real-time and analyzes it with the help of AI and machine learning algorithms to create actionable insights. Terms and Conditions available here [https://www.arveair.com/terms-and-conditions/](https://www.arveair.com/terms-and-conditions/). + + Create secret: + + $ read ARVE_CLIENT_ID + $ read ARVE_CLIENT_SECRET + $ read ARVE_API_KEY + $ oc create secret generic \ + --from-literal="ARVE_CLIENT_ID=$ARVE_CLIENT_ID" \ + --from-literal="ARVE_CLIENT_SECRET=$ARVE_CLIENT_SECRET" \ + --from-literal="ARVE_API_KEY=$ARVE_API_KEY" \ + arve-api + + - **CERN Data Service**: + + The CERN data service collects data from various sources and expose them via a REST API endpoint. + The service is enabled when the environment variable `DATA_SERVICE_ENABLED` is set to 1. + +### License Distribution + +![License Distribution Pie Chart](license_distribution.png) + +## List of Open Source Licenses + +The list of open-source dependencies provided here includes licenses for both direct dependencies and dependencies of dependencies. This comprehensive list covers a wide range of licenses, each with its own terms and conditions. Below is a summary of the most frequently encountered licenses along with their descriptions and usage: + +1. **MIT License** + - The MIT License is a permissive free software license originating at the Massachusetts Institute of Technology (MIT). It is a short and simple license that allows developers to use, modify, and distribute the software for both commercial and non-commercial purposes. + +2. **Apache License, Version 2.0** + - The Apache License, Version 2.0 is a widely used open-source software license that allows users to use the software for any purpose, to distribute it, to modify it, and to distribute modified versions of the software under the terms of the license. + +3. **Berkeley Software Distribution License (BSDL)** + - The BSD License is a family of permissive free software licenses that allow users to do anything they want with the source code, as long as they include the original copyright and license notice in any copy of the code or substantial portion of it. + +4. **Mozilla Public License 2.0 (MPL)** + - The Mozilla Public License is a free and open-source software license developed and maintained by the Mozilla Foundation. It is a copyleft license, which means that derived works can only be distributed under the same license terms. + +5. **Python Software Foundation Licene (PSFL)** + - The Python Software Foundation License (PSFL) is a BSD-style, permissive software license which is compatible with the GNU General Public License (GPL).[1] Its primary use is for distribution of the Python project software and its documentation. Since the license is permissive, it allows proprietization of the derivations. + +6. **Internet Systems Consourtium License (ISCL)** + - The ISC license is a permissive free software license published by the Internet Software Consortium, now called Internet Systems Consortium (ISC). It is functionally equivalent to the simplified BSD and MIT licenses. + +7. **Historical Permission Notice and Disclaimer License (HPND)** + - The Historical Permission Notice and Disclaimer (HPND) is an open source license, approved by the Open Source Initiative (OSI) and verified as GPL-compatible by the Free Software Foundation. The license can be almost functionally identical to the new, 3-clause BSD License (if the option for the no-promotion clause is exercised), or the MIT License (if the option for the no-promotion clause is not exercised). + +8. **GNU General Public License 2.0 or later (GPL-2.0-or-later)** + + - The GNU General Public License (GPL) is a copyleft license that allows users to modify and distribute software. Any modified versions must also be distributed under the GPL. The "or later" part means that the software can be distributed under any later version of the GPL as well. GPL ensures that software remains free and open-source. + +9. **GNU Lesser General Public License 2.1 or later (LGPL-2.1-or-later)** + + - The GNU Lesser General Public License (LGPL) is a more permissive version of the GPL, specifically intended for software libraries. It allows proprietary software to link to LGPL-licensed libraries without requiring the proprietary software itself to be open-source. Like the GPL, the LGPL requires modifications to the LGPL-licensed software to be released under the LGPL. + +10. **Expat License (also known as MIT License)** + + - The Expat License is an open-source license that is functionally identical to the MIT License. It is a permissive license that allows users to modify and distribute the software. The Expat license is commonly used in projects like XML parsing libraries and other lightweight open-source software. + +11. **Dual License** + + - A dual license means that the software is distributed under two different licenses, and the user can choose which one to comply with. This is commonly used to provide a more permissive license for open-source usage and a more restrictive commercial license for proprietary use. For example, a project may be available under both the MIT License and the GPL. diff --git a/caimira/docs/mkdocs/docs/root/physics_model.md b/caimira/docs/mkdocs/docs/root/physics_model.md new file mode 100644 index 00000000..4fc4e1d1 --- /dev/null +++ b/caimira/docs/mkdocs/docs/root/physics_model.md @@ -0,0 +1,310 @@ +# Physics of the Model + +This page describes the CAiMIRA model and its dependence on the Particles diameter. + +## Context + +The `caimira.calculator.validators` package contains modules responsible for binding all input values from the request to their respective model variables. These modules, `co2.co2_validator` and `virus.virus_validator`, inherit from the parent `form_validator` module, and handle input validation for the CO2 and virus model generators, respectively. +The `caimira.calculator.report` package contains modules responsible for binding all results from the model calculations into the respective output variables in the request output. These modules, `co2_report_data` and `virus_report_data`, handle outputs for the CO2 and virus model, respectively. +The `caimira.models.models` module itself implements the core CAiMIRA methods. A useful feature of the implementation is that we can benefit from vectorization, which allows running multiple parameterization of the model at the same time. + +Unlike other similar models, some of the CAiMIRA variables are considered for a given aerosol diameter $D$, +as the behavior of the virus-laden particles in the room environment and inside the susceptible host (once inhaled) are diameter-dependent. +Here, these variables are identified by their functional dependency on $D$, as for the **emission rate** – $\mathrm{vR}(D)$, **removal rate** – $\mathrm{vRR}(D)$, and **concentration** – $C(t, D)$. + +Despite the outcome of the CAiMIRA results include the entire range of diameters, throughout the model, +most of the variables and parameters are kept in their diameter-dependent form for any possible detailed analysis of intermediate results. +Only the final quantities shown in output, such as the concentration and the dose, are integrated over the diameter distribution. +This is performed thanks to a Monte-Carlo (MC) integration at the level of the dose ($\mathrm{vD^{total}}$) which is computed over a distribution of particle diameters, +from which the average value (i.e. `.mean()` of the numpy array) is then calculated – this is equivalent to an analytical integral over diameters +provided the sample size is large enough. Example of the MC integration over the diameters for the short-range dose: +`(np.array(short_range_jet_exposure* fdep).mean()`. + +It is important to distinguish between 1) Monte-Carlo random variables (which are vectorized independently on its diameter-dependence) and 2) numerical Monte-Carlo integration for the diameter-dependence. +Since the integral of the diameter-dependent variables are solved when computing the dose – $\mathrm{vD^{total}}$ – while performing some of the intermediate calculations, +we normalize the results by *dividing* by the Monte-Carlo variables that are diameter-independent, so that they are not considered in the Monte-Carlo integration (e.g. the **viral load** parameter, or the result of the `caimira.models.models.InfectedPopulation.emission_rate_per_aerosol_per_person_when_present()` method). + +## Expiration + +The **Expiration** class (representing the expiration of aerosols by an infected person) has the Particle – `caimira.models.models.Expiration.particle` – as one of its properties, +which represents the virus-laden aerosol with a vectorized parameter: the particle diameter (assuming a perfect sphere). +For a given aerosol diameter, one `caimira.models.models.Expiration` object provides the aerosol **volume** - $V_p(D)$, multiplied by the **mask outward efficiency** - $η_\mathrm{out}(D)$ to include the filtration capacity, when applicable. + +The BLO model represents the distribution of diameters used in the model. It corresponds to the sum of three log-normal distributions, weighted by the **B**, **L** and **O** modes. +The aerosol diameter distributions are given by the `caimira.models.monte_carlo.data.BLOmodel.distribution()` method. + +The `caimira.models.monte_carlo.data.BLOmodel` class itself contains the method to return the mathematical values of the probability distribution for a given diameter (in microns), +as well as the method to return its integral between the **min** and **max** diameters. +The BLO model is used to provide the probability density function (PDF) of the aerosol diameters for a given **Expiration** type defined in `caimira.models.monte_carlo.data.expiration_distribution()`. +To compute the total concentration of particles per mode (B, L and O), $cn$ in particles/cm3, in other words, the total concentration of aerosols per unit volume of expired air, +an integration of the log-normal distributions is performed over all aerosol diameters. In the code it is used as a scaling factor in the `caimira.models.models.Expiration` class. + +Under the `caimira.calculator.validators.virus.virus_validator` module, when it comes to generate the Expiration model, the diameter property is sampled through the BLO `caimira.models.monte_carlo.data.BLOmodel.distribution()` method, while the value for the $cn$ is given by the `caimira.models.monte_carlo.data.BLOmodel.integrate()` method. +To summarize, the Expiration object contains, as a vectorised float, a sample of diameters following the BLO distribution. Depending on different expiratory types, the contributions from each mode will be different, therefore the resulting distribution also differs from model to model. + +## Emission Rate - vR(D) + +The mathematical equations to calculate $\mathrm{vR}(D)$ are defined in the paper - Henriques, A. et al. [2](#id8) - as follows: + +$\mathrm{vR}(D)_j= \mathrm{vl_{in}} \cdot E_{c,j}(D,f_{\mathrm{amp}},\eta_{\mathrm{out}}(D)) \cdot {\mathrm{BR}}_{\mathrm{k}}$ , + +$E_{c,j}^{\mathrm{total}} = \int_0^{D_{\mathrm{max}}} E_{c,j}(D)\, \mathrm{d}D$ . + +The later integral, which is giving the total volumetric particle emission concentration (in mL/m3 ), is a example of a numerical Monte-Carlo integration over the particle diameters, +since $E_{c,j}(D)$ is a diameter-dependent quantity. $E^{\mathrm{total}}_{c, j}$ is calculated from the mean of the Monte-Carlo sample $E_{c,j}(D)$. +Note that $D_{\mathrm{max}}$ value will differ, depending on the type of exposure (see below). + +In the code, for a given Expiration, we use different methods to perform the calculations *step-by-step*: + +1. Calculate the non aerosol-dependent quantities in the emission rate per person infected, which is the multiplication of the diameter-**independent** variables: `caimira.models.models.InfectedPopulation.emission_rate_per_aerosol_per_person_when_present()`. This corresponds to the $\mathrm{vl_{in}} \cdot \mathrm{BR_{k}}$ part of the $\mathrm{vR}(D)$ equation, together with the fraction of infectious virus, $f_{\mathrm{inf}}$. +2. Calculate the diameter-**dependent** variable `caimira.models.models.InfectedPopulation.aerosols()`, which is the result of $E_{c,j}(D) = N_p(D) \cdot V_p(D) \cdot (1 − η_\mathrm{out}(D))$ (in mL/(m3 .µm)), with $N_p(D)$ being the product of the BLO distribution by the scaling factor $cn$. Note that this result is not integrated over the diameters at this stage, thus the units are still *‘per aerosol diameter’*. +3. Calculate the full emission rate (per person infected), which is the multiplication of the two previous methods, and corresponds to $\mathrm{vR(D)}$: `caimira.models.models._PopulationWithVirus.emission_rate_per_person_when_present()`. + +Note that the diameter-dependence is kept at this stage. Since other parameters downstream in code are also diameter-dependent, the Monte-Carlo integration over the aerosol sizes is computed at the level of the dose $\mathrm{vD^{total}}$. +In case one would like to have intermediate results for emission rate, perform the Monte-Carlo integration of $E_{c, j}^{\mathrm{total}}$ and compute $\mathrm{vR^{total}} =\mathrm{vl_{in}} \cdot f_{\mathrm{inf}} \cdot E_{c, j}^{\mathrm{total}} \cdot \mathrm{BR_k}$. + +## Virus Concentration - C(t, D) + +The estimate of the concentration of virus-laden particles in a given room is based on a two-box exposure model: + +* **Box 1** - long-range exposure: also known as the *background* concentration, corresponds to the exposure of airborne virions where the susceptible (exposed) host is more than 2 m away from the infected host(s), considering the result of a mass balance equation between the emission rate of the infected host(s) and the removal rates from the environmental/virological characteristics. +* **Box 2** - short-range exposure: also known as the *exhaled jet* concentration in close-proximity, corresponds to the exposure of airborne virions where the susceptible (exposed) host is distanced between 0.5 and 2 m from an infected host, considering the result of a two-stage exhaled jet model. + +Note that most of the methods used to calculate the concentration are defined in the superclass `caimira.models.models._ConcentrationModelBase()`, while the specific methods for the long-range virus concentration are part of the subclass `caimira.models.models.ConcentrationModel()`. +The specific removal rate, minimum background concentration and normalization factors will depend on what concentration is being calculated (e.g. viral concentration or CO2 concentration) and are respectively defined in `caimira.models.models._ConcentrationModelBase.removal_rate()`, `caimira.models.models._ConcentrationModelBase.min_background_concentration()` and `caimira.models.models._ConcentrationModelBase.normalization_factor()`. + +### Long-range approach + +The long-range concentration of virus-laden aerosols of a given size $D$, that is based on the mass balance equation between the emission and removal rates, is given by: + +$C_{\mathrm{LR}}(t, D)=\frac{\mathrm{vR}(D) \cdot N_{\mathrm{inf}}}{\lambda_{\mathrm{vRR}}(D) \cdot V_r}-\left (\frac{\mathrm{vR}(D) \cdot N_{\mathrm{inf}}}{\lambda_{\mathrm{vRR}}(D) \cdot V_r}-C_0(D) \right )e^{-\lambda_{\mathrm{vRR}}(D)t}$ , + +and computed, as a function of the exposure time and particle diameter, in the `caimira.models.models._ConcentrationModelBase.concentration()` method. +The long-range concentration, integrated over the exposure time (in piecewise constant steps), $C(D)$, is given by `caimira.models.models._ConcentrationModelBase.integrated_concentration()`. + +In the $C_{\mathrm{LR}}(t, D)$ equation above, the **emission rate** - $\mathrm{vR}(D)$ - and the **viral removal rate** - $\lambda_{\mathrm{vRR}}(D)$, `caimira.models.models.ConcentrationModel.infectious_virus_removal_rate()` - are both diameter-dependent. +One can show that the resulting concentration is always proportional to the emission rate $\mathrm{vR}(D)$. Hence, for computational speed-up purposes +the code computes first a normalized version of the concentration, i.e. divided by the emission rate, before multiplying by $\mathrm{vR}(D)$. + +To summarize, we can split the concentration in two different formulations: + +* Normalized concentration `caimira.models.models._ConcentrationModelBase._normed_concentration()`: $\mathrm{C_\mathrm{LR, normed}}(t, D)$ that computes the concentration without including the emission rate per person infected. +* Concentration `caimira.models.models._ConcentrationModelBase.concentration()` : $C_{\mathrm{LR}}(t, D) = \mathrm{C_\mathrm{LR, normed}}(t, D) \cdot \mathrm{vR}(D)$, where $\mathrm{vR}(D)$ is the result of the `caimira.models.models._PopulationWithVirus.emission_rate_per_person_when_present()` method. + +Note that in order to get the total concentration value in this stage, the final result should be averaged over the particle diameters (i.e. Monte-Carlo integration over diameters, see above). +For the calculator app report, the total concentration (MC integral over the diameter) is performed only when generating the plot. +Otherwise, the diameter-dependence continues until we compute the inhaled dose in the `caimira.models.models.ExposureModel` class. + +The following methods calculate the integrated concentration between two times. They are mostly used when calculating the **dose**: + +* `caimira.models.models._ConcentrationModelBase.normed_integrated_concentration()`, $\mathrm{C_\mathrm{normed}}(D)$ that returns the integrated long-range concentration of viruses in the air, between any two times, normalized by the emission rate per person infected. Note that this method performs the integral between any two times of the previously mentioned `caimira.models.models._ConcentrationModelBase._normed_concentration()` method. +* `caimira.models.models._ConcentrationModelBase.integrated_concentration()`, $C(D)$, that returns the same result as the previous one, but multiplied by the emission rate (per person infected). + +The integral over the exposure times is calculated directly in the class (integrated methods). + +### Short-range approach + +The short-range concentration is the result of a two-stage exhaled jet model developed by Jia, W. et al. [1](#id7) and is expressed as: + +$C_{\mathrm{SR}}(t, D) = C_{\mathrm{LR}} (t, D) + \frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100μm}(t, D))$ , + +where $S(x)$ is the dilution factor due to jet dynamics, as a function of the interpersonal distance $x$ and $C_{0, \mathrm{SR}}(D)$ corresponds to the initial concentration of virions at the mouth/nose outlet during exhalation. +$C_{\mathrm{LR}, 100μm}(t, D)$ is the long-range concentration, calculated in `caimira.models.models._ConcentrationModelBase.concentration()` method but **interpolated** to the diameter range used for close-proximity (from 0 to 100μm). +Note that $C_{0, \mathrm{SR}}(D)$ is constant over time, hence only dependent on the particle diameter distribution. + +For code simplification, we split the $C_{\mathrm{SR}}(t, D)$ equation into two components: + +* short-range component: $\frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100μm}(t, D))$, dealt with in the dataclass `caimira.models.models.ShortRangeModel`. +* long-range component: $C_{\mathrm{LR}} (t, D)$. + +The short-range data class (`caimira.models.models.ShortRangeModel`) models the short-range component of a close-range interaction **concentration** and the respective **dilution_factor**. +Its inputs are the **expiration** definition, the **activity type**, the **presence time**, and the **interpersonal distance** between any two individuals. +When generating a full model, the short-range class is defined with a new **Expiration** distribution, +given that the **min** and **max** diameters for the short-range interactions are different from those used in the long-range concentration (the idea is that very large particles should not be considered in the long-range case as they fall rapidly on the floor, +while they must be in for the short-range case). + +As mentioned in Jia, W. et al. [1](#id7), the jet concentration depends on the **long-range concentration** of viruses. +Here, once again, we shall normalize the short-range concentration to the diameter-independent quantities. +IMPORTANT NOTE: since the susceptible host is physically closer to the infector, the emitted particles are larger in size, +hence a new distribution of diameters should be taken into consideration. +As opposed to $D_{\mathrm{max}} = 30\mathrm{μm}$ for the long-range MC integration, the short-range model will assume a $D_{\mathrm{max}} = 100\mathrm{μm}$. +Very similar to what we did with the **emission rate**, we need to calculate the scaling factor from the probability distribution, $N_p(D)$ - $cn$, as well as the **volume concentration** for those diameters. + +During a given exposure time, multiple short-range interactions can be defined in the model. +In addition, for each individual interaction, the expiration type may be different. + +To calculate the short-range component, we first need to calculate what is the **dilution factor**, that depends on the distance $x$ as a random variable, from a log normal distribution in `caimira.models.monte_carlo.data.short_range_distances()`. +This factor is calculated in a two-stage expiratory jet model, with its transition point defined as follows: + +$\mathrm{xstar}=𝛽_{\mathrm{x1}} (Q_{\mathrm{exh}} \cdot u_{0})^\frac{1}{4} \cdot (\mathrm{tstar} + t_{0})^\frac{1}{2} - x_{0}$, + +where $Q_{\mathrm{exh}}= φ \mathrm{BR}$ is the expired flow rate during the expiration period, in $m^{3} s^{-1}$, φ is the exhalation coefficient +(dimensionless) and represents the ratio between the total period of a breathing cycle and the duration of the exhalation alone. +Assuming the duration of the inhalation part is equal to the exhalation and one starts immediately after the other, φ will always be equal to 2 no matter what is the breating cycle time. $\mathrm{BR}$ is the given exhalation rate. +$u_{0}$ is the expired jet speed (in $m s^{-1}$) given by $u_{0}=\frac{Q_{\mathrm{exh}}}{A_{m}}$, $A_{m}$ being the area of the mouth assuming a perfect circle (average mouth_diameter of 0.02m). +The time of the transition point $\mathrm{tstar}$ is defined as 2s and corresponds to the end of the exhalation period, i.e. when the jet is interrupted. The distance of the virtual origin of the puff-like stage is defined by +$x_{0}=\frac{\textrm{mouth_diameter}}{2𝛽_{\mathrm{r1}}}$ (in m), and the corresponding time is given by $t_{0} = \frac{\sqrt{\pi} \cdot \textrm{mouth_diameter}^3}{8𝛽_{\mathrm{r1}}^2𝛽_{\mathrm{x1}}^2Q_{exh}}$ (in s). +Having the distance for the transition point, we can calculate the dilution factor at the transition point, defined as follows: + +$\mathrm{Sxstar}=2𝛽_{\mathrm{r1}}\frac{(xstar + x_{0})}{\textrm{mouth_diameter}}$. + +The remaining dilution factors, either in the jet- or puff-like stages are calculated as follows: + +$\mathrm{factors}(x)=\begin{cases}\hfil 2𝛽_{\mathrm{r1}}\frac{(x + x_{0})}{\textrm{mouth_diameter}} & \textrm{if } x < \mathrm{xstar},\\\hfil \mathrm{Sxstar} \cdot \biggl(1 + \frac{𝛽_{\mathrm{r2}}(x - xstar)}{𝛽_{\mathrm{r1}}(xstar + x_{0})}\biggl)^3 & \textrm{if } x > \mathrm{xstar}.\end{cases}$ + +The penetration coefficients in the jet-like stage $𝛽_{\mathrm{r1}}$, $𝛽_{\mathrm{r2}}$ and $𝛽_{\mathrm{x1}}$ are defined by the following empirical values 0.18, 0.2, and 2.4 respectively. The dilution factor for each distance $x$ is then stored in the $\mathrm{factors}$ array that is returned by the method. + +Having the dilution factors, the **initial concentration of virions at the mouth/nose**, $C_{0, \mathrm{SR}}(D)$, is calculated as follows: + +$C_{0, \mathrm{SR}}(D) = N_p(D) \cdot V_p(D) \cdot \mathrm{vl_{in}} \cdot 10^{-6}$, +given by `caimira.models.models.Expiration.jet_origin_concentration()`. It computes the same quantity as `caimira.models.models.Expiration.aerosols()`, except for the mask inclusion. As previously mentioned, it is normalized by the **viral load**, which is a diameter-independent property. +Note, the $10^{-6}$ factor corresponds to the conversion from $\mathrm{μm}^{3} \cdot \mathrm{cm}^{-3}$ to $\mathrm{mL} \cdot m^{-3}$. + +Note that similarly to the long-range approach, the MC integral over the diameters is not calculated at this stage. + +For consistency, the long-range concentration parameter, $C_{\mathrm{LR}, 100\mathrm{μm}}(t, D)$ in the `caimira.models.models.ShortRangeModel` class **only**, +shall also be normalized by the **viral load** and **fraction of infectious virus**, since in the short-range model the diameter range is different than at long-range (as mentioned above), +we need to account for that difference. +The former operation is given in method `caimira.models.models.ShortRangeModel._long_range_normed_concentration()`. For the diameter range difference, there are a few options: +one solution would be to recompute the values a second time using $D_{\mathrm{max}} = 100\mathrm{μm}$; +or perform a approximation using linear interpolation, which is possible and more effective in terms of performance. We decided to adopt the interpolation solution. +The set of points with a known value are given by the default expiration particle diameters for long-range, i.e. from 0 to 30 $\mathrm{μm}$. +The set of points we want the interpolated values are given by the short-range expiration particle diameters, i.e. from 0 to 100 $\mathrm{μm}$. + +To summarize, in the code, $C_{\mathrm{SR}}(t, D)$ is computed as follows: + +* calculate the dilution_factor - $S({x})$ - in the method `caimira.models.models.ShortRangeModel.dilution_factor()`, with the distance $x$ as a random variable (log normal distribution in `caimira.models.monte_carlo.data.short_range_distances()`) +* compute $\frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100\mathrm{μm}}(t, D))$ in method `caimira.models.models.ShortRangeModel.normed_concentration()`, +* multiply by the diameter-independent parameters, viral load and $\mathrm{f_{inf}}$, in method `caimira.models.models.ShortRangeModel.short_range_concentration()` +* complete the equation of $C_{\mathrm{SR}}(t, D)$ by adding the long-range concentration from the `caimira.models.models._ConcentrationModelBase.concentration()` (all integrated over $D$), returning the final short-range concentration value for a given time and expiration activity. This is done at the level of the Exposure Model (`caimira.models.models.ExposureModel.concentration()`). + +Note that `caimira.models.models.ShortRangeModel._normed_concentration()` method is different from `caimira.models.models._ConcentrationModelBase._normed_concentration()` and `caimira.models.models._ConcentrationModelBase.concentration()` differs from `caimira.models.models.ExposureModel.concentration()`. + +Unless one is computing the mean concentration values (e.g. for the plots in the report), the diameter-dependence is kept at this stage. Since other parameters downstream in the code are also diameter-dependent, the Monte-Carlo integration over the particle sizes is computed at the level of the dose $\mathrm{vD^{total}}$. +In case one would like to have intermediate results for the initial short-range concentration, this is done at the `caimira.models.models.ExposureModel` class level. + +## Dose - vD + +The term dose refers to the number of viable virions (infectious virus) that will contribute to a potential infection. +It results in a combination of several properties: exposure, inhalation rate, aerosol deposition in the respiratory tract and the effect of protective equipment such as masks. + +The receiving dose, which is inhaled by the exposed host, in infectious virions per unit diameter (diameter-dependence), +is calculated by first integrating the viral concentration profile (for a given particle diameter) over the exposure time and multiplying by scaling factors such as the proportion of virions which are infectious and the deposition fraction, +as well as the inhalation rate and the effect of masks: + +$\mathrm{vD}(D) = \int_{t1}^{t2}C(t, D)\;\mathrm{d}t \cdot \mathrm{BR}_{\mathrm{k}} \cdot f_{\mathrm{dep}}(D) \cdot (1-\eta_{\mathrm{in}})$ . + +where $C(t, D)$ is the concentration value at a given time, which can be either the short- or long-range concentration, $f_{\mathrm{dep}}(D)$ is the (diameter-dependent) deposition fraction in the respiratory tract, $\mathrm{BR}_{\mathrm{k}}$ is the inhalation rate and $\eta_{\mathrm{in}}$ is the inward efficiency of the face mask. + +Given that the calculation is diameter-dependent, to calculate the dose in the model, the code contains different methods that consider the parameters that are dependent on the aerosol size, $D$. +The total dose, at the end of the exposure scenario, results from the sum of the dose accumulated over time, integrated over particle diameters: + +$\mathrm{vD^{total}} = \int_0^{D_{\mathrm{max}}} \mathrm{vD}(D) \, \mathrm{d}D$ . + +This calculation is computed using a Monte-Carlo integration over $D$. As previously described, many different parameters samples are generated using the probability distribution from the $N_p(D)$ equation. +The dose for each of them is then computed, and their **average** value over all samples represents a good approximation of the total dose, provided that the number of samples is large enough. + +### Long-range approach + +Regarding the concentration part of the long-range exposure (concentration integrated over time, $\int_{t1}^{t2}C_{\mathrm{LR}}(t, D)\;\mathrm{d}t$), the respective method is `caimira.models.models.ExposureModel._long_range_normed_exposure_between_bounds()`, +which uses the long-range exposure (concentration) between two bounds (time1 and time2), normalized by the emission rate of the infected population (per person infected), calculated from `caimira.models.models._ConcentrationModelBase.normed_integrated_concentration()`. +The former method filters out the given bounds considering the breaks through the day (i.e. the time intervals during which there is no exposition to the virus) and retrieves the integrated long-range concentration of viruses in the air between any two times. + +After the calculations of the integrated concentration over the time, in order to calculate the final dose, we have to compute the remaining factors in the above equation. +Note that the **Monte-Carlo integration over the diameters is performed at this stage**, where all the diameter-dependent parameters are grouped together to calculate the final average (`np.mean()`). + +Since, in the previous chapters, the quantities where normalised by the emission rate per person infected, one will need to re-incorporate it in the equations before performing the MC integrations over $D$. +For that we need to split $\mathrm{vR}(D)$ (`caimira.models.models._PopulationWithVirus.emission_rate_per_person_when_present()`) in diameter-dependent and diameter-independent quantities: + +$\mathrm{vR}(D) = \mathrm{vR}(D-\mathrm{dependent}) \times \mathrm{vR}(D-\mathrm{independent})$ + +with + +$\mathrm{vR}(D-\mathrm{dependent}) = \mathrm{cn} \cdot V_p(D) \cdot (1 − \mathrm{η_{out}}(D))$ - `caimira.models.models.InfectedPopulation.aerosols()` + +$\mathrm{vR}(D-\mathrm{independent}) = \mathrm{vl_{in}} \cdot \mathrm{f_{inf}} \cdot \mathrm{BR_{k}}$ - `caimira.models.models.InfectedPopulation.emission_rate_per_aerosol_per_person_when_present()` + +In other words, in the code the procedure is the following (all performed in `caimira.models.models.ExposureModel.long_range_deposited_exposure_between_bounds()` method): + +* start re-incorporating the emission rate by first multiplying by the diameter-dependent quantities: $\mathrm{vD_{aerosol}}(D) = (\int_{t1}^{t2}C_{\mathrm{LR}}(t, D)\;\mathrm{d}t \cdot \mathrm{vR}(D-\mathrm{dependent}) \cdot f_{\mathrm{dep}}(D))$, in `caimira.models.models.ExposureModel.long_range_deposited_exposure_between_bounds()` method; +* perform the **MC integration over the diameters**, which is considered equivalent as the mean of the distribution if the sample size is large enough: $\mathrm{vD_{aerosol}} = \mathrm{np.mean}(\mathrm{vD_{aerosol}}(D))$; +* multiply the result with the remaining diameter-independent quantities of the emission rate used previously to normalize: $\mathrm{vD_{emission-rate}} = \mathrm{vD_{aerosol}} \cdot \mathrm{vR}(D-\mathrm{independent})$; +* in order to complete the equation, multiply by the remaining diameter-independent variables in $\mathrm{vD}$ to obtain the total value: $\mathrm{vD^{total}} = \mathrm{vD_{emission-rate}} \cdot \mathrm{BR}_{\mathrm{k}} \cdot (1-\eta_{\mathrm{in}})$; +* in the end, the dose is a vectorized float used in the probability of infection formula. + +**Note**: The aerosol volume concentration (*aerosols*) is introduced because the integrated concentration over the time was previously normalized by the emission rate (per person). +Here, to calculate the integral over the diameters we also need to consider the diameter-dependent variables that are on the emission rate, represented by the aerosol volume concentration which depends on the diameter and on the mask type: + +$\mathrm{aerosols} = \mathrm{cn} \cdot V_p(D) \cdot (1 − \mathrm{η_{out}}(D))$ . +The $\mathrm{cn}$ factor, which represents the total number of aerosols emitted, is introduced here as a scaling factor, as otherwise the Monte-Carlo integral would be normalized to 1 as the probability distribution. + +**Note**: for simplification of the notations, here the dose corresponding exclusively to the long-range contribution is written as $\mathrm{vD_{LR}}(D)= \mathrm{vD}(D)$. + +In the end, the governing method is `caimira.models.models.ExposureModel.deposited_exposure_between_bounds()`, in which the deposited_exposure is equal to long_range_deposited_exposure_between_bounds in the absence of short-range interactions. + +### Short-range approach + +In theory, the dose during a close-proximity interaction (short-range) is simply added to the dose inhaled due to the long-range and may be defined as follows: + +$\mathrm{vD}(D)= \mathrm{vD^{LR}}(D) + \sum\limits_{i=1}^{n} \int_{t1}^{t2}C_{\mathrm{SR}}(t, D)\;\mathrm{d}t \cdot \mathrm{BR}_{\mathrm{k}} \cdot f_{\mathrm{dep}}(D) \cdot (1-\eta_{\mathrm{in}})$ , + +where $\mathrm{vD_{LR}}(D)$ is the long-range, diameter-dependent dose computed previously. + +From above, the short-range concentration: + +$C_{\mathrm{SR}}(t, D) = C_{\mathrm{LR}, 100μm} (t, D) + \frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100μm}(t, D))$ , + +In the code, the method that returns the value for the total dose (independently if it is short- or long-range) is given by `caimira.models.models.ExposureModel.deposited_exposure_between_bounds()`. +For code simplification, we split the $C_{\mathrm{SR}}(t, D)$ equation into two components: + +* short-range component: $\frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100μm}(t, D))$; +* long-range component: $C_{\mathrm{LR}} (t, D)$. + +Similarly as above, first we perform the multiplications by the diameter-dependent variables so that we can profit from the Monte-Carlo integration. Then we multiply the final value by the diameter-independent variables. +The method `caimira.models.models.ShortRangeModel._normed_jet_exposure_between_bounds()` gets the integrated short-range concentration of viruses in the air between the times start and stop, normalized by the **viral load** and **fraction of infectious virus**, +and excluding the **jet dilution** since it is also diameter-independent. +This corresponds to $C_{0, \mathrm{SR}}(D)$. + +The method `caimira.models.models.ShortRangeModel._normed_interpolated_longrange_exposure_between_bounds()` retrieves the integrated short-range concentration due to the background concentration, +normalized by the **viral load**, **fraction of infectious virus** and the **breathing rate**, and excluding the jet **dilution**. +The result is then interpolated to the particle diameter range used in the short-range model (i.e. 100 μm). +This corresponds to $\int_{t1}^{t2} C_{\mathrm{LR}, 100\mathrm{μm}} (t, D)\mathrm{d}t$. +Very similar to the long-range procedure, this method performs the integral of the concentration for the given time boundaries. + +Once we have the integral of the concentration normalized by the diameter-independent quantities, we multiply this result by the remaining diameter-dependent properties to perform the integral +over the particle diameters, including the **fraction deposited** computed with an evaporation factor of 1 (as the aerosols do not have time to evaporate during a short-range interaction). +This operation is performed with the MC intergration using the *mean*, which corresponds to: +$\int_{0}^{D_{max}}C_{\mathrm{SR}}(t, D) \cdot f_{\mathrm{dep}}(D) \;\mathrm{d}D$ . + +Note that in the code we perform the subtraction between the concentration at the jet origin and the long-range concentration of viruses in two steps when we calculate the dose, +since the contribution of the diameter-dependent variable $f_{\mathrm{dep}}$ has to be multiplied separately in substractions: + +integral_over_diameters = $((C_{0, \mathrm{SR}} \cdot f_{\mathrm{dep}}) - (C_{\mathrm{LR}, 100μm} (t, D) \cdot f_{\mathrm{dep}})) \cdot \mathrm{mean()}$ . + +Then, we add the contribution to the result of the diameter-**independent** vectorized properties **in two seperate phases**: + +* multiply by the diameter-independent properties that are dependent on the **activity type** of the different short-range interactions: **breathing rate** and **dilution factor** - within the *for* cycle; +* multiply by the other properties that are **not** dependent on the type of short-range interactions: **viral load**, **fraction of infectious virus** and **inwards mask efficiency**. + +The final operation in the `caimira.models.models.ExposureModel.deposited_exposure_between_bounds()` accounts for the addition of the long-range component of the dose. + +If short-range interactions exist: the long-range component is added to the already calculated short-range component (deposited_exposure), hence completing $C_{\mathrm{SR}}$. +If the are no short-range interactions: the short-range component (deposited_exposure) is zero, hence the result is equal solely to the long-range component $C_{\mathrm{LR}}$. + +## CO2 Concentration + +The estimate of the concentration of CO2 in a given room to indicate the air quality is given by the same approach as for the long-range virus concentration, +$C_{\mathrm{LR}}(t, D)$, where $C_0(D)$ is considered to be the background (outdoor) CO2 concentration (`caimira.models.models.CO2ConcentrationModel.CO2_atmosphere_concentration()`). + +In order to compute the CO2 concentration one should then simply use the `caimira.models.models.CO2ConcentrationModel.concentration()` method. +A fraction of 4.2% of the exhalation rate of the defined activity was considered as supplied to the room (`caimira.models.models.CO2ConcentrationModel.CO2_fraction_exhaled()`). + +Note still that nothing depends on the aerosol diameter $D$ in this case (no particles are involved) - hence in this class all parameters are constant w.r.t $D$. + +Since the CO2 concentration differs from the virus concentration, the specific removal rate, CO2 atmospheric concentration and normalization factors are respectively defined in `caimira.models.models.CO2ConcentrationModel.removal_rate()`, +`caimira.models.models.CO2ConcentrationModel.min_background_concentration()` and `caimira.models.models.CO2ConcentrationModel.normalization_factor()`. + +## References + +* **[1]** Jia, Wei, et al. “Exposure and respiratory infection risk via the short-range airborne route.” Building and environment 219 (2022): 109166. [doi.org/10.1016/j.buildenv.2022.109166](https://doi.org/10.1016/j.buildenv.2022.109166) +* **[2]** Henriques, Andre, et al. “Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces.” Interface Focus 12.2 (2022): 20210076. [doi.org/10.1098/rsfs.2021.0076](https://doi.org/10.1098/rsfs.2021.0076) diff --git a/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/full_guide.md b/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/full_guide.md new file mode 100644 index 00000000..54f82058 --- /dev/null +++ b/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/full_guide.md @@ -0,0 +1,207 @@ +## [CAiMIRA Calculator](https://caimira.web.cern.ch/) + +This guide helps on how to use the calculator app. 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](https://cds.cern.ch/record/2743403) + +The methodology, mathematical equations and parameters of the model are described here in the CERN Report: [CERN-OPEN-2021-004](https://cds.cern.ch/record/2756083) + +??? "Disclaimer" + + CAiMIRA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions. + + CAiMIRA models the concentration profile of virions 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 airborne spread SARS-CoV-2 virus in a finite volume, assuming homogenous mixing for the long-range component and a two-stage jet model for short-range, and estimates the risk of COVID-19 airborne transmission therein. The results DO NOT include other known modes of SARS-CoV-2 transmission, such as contact or fomite. 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, amount and nature of close-range interactions and the size of the room, considering both long- and short-range airborne transmission modes 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. + + CAiMIRA 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. + +### 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". The simulation name has no bearing on the calculation. + +A room number is included, if you do not wish to use a formal room number any reference will do - for example "57/2-004". + +### Virus Data + +Please choose the correct virus strain or any reported Variant of Concern (VOC) from the list. Changing this setting alters the properties of the virus which are used for the simulation. This has a significant effect on the probability of infection. The choices are: + +- **SARS-CoV-2 (nominal strain)**, covering typical strains and variants which are not of concern from an epidemiologic point of view of the virus; +- **SARS-CoV-2 (Alpha VOC)**, first identified in the UK at the end of 2020 which is found to be approximately 1.5x more transmissible compared to the non-VOCs; +- **SARS-CoV-2 (Beta VOC)**, first identified in South Africa in May 2020 which is found to be approximately 1.25x more transmissible compared to the non-VOCs; +- **SARS-CoV-2 (Gamma VOC)**, first identified in Brazil in January 2021 which is found to be approximately 2.2x more transmissible compared to the non-VOCs. +- **SARS-CoV-2 (Delta VOC)**, first identified in India towards the end of 2020 which is found to be approximately 60% more transmissible compared to the ALPHA VOC. +- **SARS-CoV-2 (Omicron VOC)**, first identified in South Africa in November 2021 which is found to be at least 2.53x more transmissible compared to the DELTA VOC. + +The user can modify the selected variant from the default, according to the prevalence of the different variants in the local area, e.g. for [Geneva](https://www.covid19.admin.ch/fr/epidemiologic/virus-variants?detGeo=GE). + +N.B. The transmission data for the Gamma variant has been taken from a study data gathered in Manaus, Brazil where the variant was first observed. The local population in Manaus had very high levels of Covid-19 antibodies (>67%) in recent months. This factor has been taken into account by the authors of the study, via statistical adjustments to the transmission value (i.e. it has been increased, to account for spread in a population with significant acquired Covid-19 immunity). However, this value may be revised in the future as more studies of the Gamma VOC transmission in different geographical locations become available. + +#### Vaccine effectiveness + +The vaccination input corresponds to the vaccine type(s) administrated to the exposed population, assuming every exposed (or the occupant in question) has received the vaccine cocktail selected by the user. The respective vaccine effectiveness values were extracted from data available in [Results of COVID-19 Vaccine Effectiveness Studies: An Ongoing Systematic Review - Updated September 8, 2022](https://view-hub.org/resources), using this [script](https://gitlab.cern.ch/caimira/caimira/-/blob/master/caimira/src/caimira/scripts/data/vaccine_effectiveness.py). + +### Room Data + +Please enter either the room volume (in m³) or both the floor area (m²) and the room height (m). This information is available via GIS Portal ([https://gis.cern.ch/gisportal/](https://gis.cern.ch/gisportal/)). + +#### Room heating system + +The use of central heating (e.g. radiators) reduces relative humidity of the indoor air, which can decrease the decay rate of viral infectivity. If your space is heated with such water radiators, select 'Yes'. If your space does not have such heating, or they are not in use in the period of the simulation (e.g. summer), select 'No'. + +### Ventilation type + +There are three main options: + +#### Mechanical ventilation + +If the room has mechanical ventilation, supplying fresh air from outside (either a local or centralized system), you should select this option. In order to make an accurate calculation you will need to know either the flow rate of fresh air supplied in the room or th total number of air changes per hour with fresh air. + +Please bear in mind that any of the two inputs only consider the supply of fresh air. If a portion of air is recirculated, it shall not be accounted for in the inputs. + +#### Natural ventilation + +Natural ventilation refers to rooms which have openable windows. There are many possibilities to calculate natural ventilation air flows, for simplification this tool assumes a single-sided natural ventilation scheme which is a conservative approach for the purpose of this tool. + +Please choose the type of window (see illustration below): + +- Sliding or side-hung +- Top- or bottom-hung + +![How to determine the window type](img/window_type.PNG) + +Please enter the number, height and width and opening distance of the windows (in m). If there are multiple windows of different sizes, you should take an average. + +The window opening distance (in m) is: + +- In the case of Sliding or Side-Hung option, the length the window is moved open. Window opening distance example (image of open window and measuring tape): + + ![How to measure window opening distance](img/window_opening.png) + +- In case of Top- or Bottom-Hung, the distance between the fixed frame and the movable glazed part when open. + +**Notes**: If you are unsure about the opening distance for the window, it is recommended to choose a conservative value (5 cms, 0.05m or 10cms, 0.10m). If you open the window at different distances throughout the day, choose an average value. +When using natural ventilation, the circulation of air is simulated as a function of the difference between the temperature inside the room and the outside air temperature. The average outdoor temperature for each hour of the day has been computed for every month of the year based on historical data for Geneva, Switzerland. It is therefore very important to enter the correct time and date in the event data section. Finally, you must specify if the windows are open permanently (at all the times), or periodically (in intervals for a certain duration during the course of the day) - e.g. open the window for 10 minutes (duration) every 60 minutes (frequency). + +#### No ventilation + +This option assumes there is neither Mechanical nor Natural ventilation in the simulation. + +#### HEPA filtration + +A HEPA filter is a high efficiency particulate matter filter, which removes small airborne particles from the air. They can be very useful for removing particles with viruses from the air in an enclosed space. The calculator allows you to simulate the installation of a HEPA air filter within the room. The recommended airflow rate for the HEPA filter should correspond to a total air exchange rate of 3 - 6 ACH (the higher the better, even beyond 6). + +### Event data + +Here we capture the information about the event being simulated. First enter the number of occupants in the space, if you have a (small) variation in the number of people, please input the average or consider using the expert tool. Within the number of people occupying the space, you should specify how many are infected. + +In case one would like to simulate an event happening at a given time and location, where the epidemiological situation is known, the tool allows for an estimation of the probability of on-site transmission, considering the chances that a given person in the event is infected. The user will need to select **Probabilistic event**, input the number of inhabitants and the the weekly (7-day rolling average) value of new reported laboratory - ⁠confirmed cases at the event location, as well as the confidence level of these inputs. The 7-day rolling average consists in the average of the previous 3 days to subsequent 3 days, generally reported by the different public health authorities (e.g. in Switzerland [here](https://www.covid19.admin.ch/en/epidemiologic/case/d/development?epiRelDev=abs)). These two inputs need to the related, i.e. the values of reported new cases and the number of inhabitants shall correspond to the a same geographical location. For example: + +- Population of Geneva, CH: 508 000 inhabitants +- New lab reported cases in the canton of Geneva: 1000 (7-day rolling average) + +The confidence level allows for an ascertainment bias to the data. The user can add the following options: + +- High - mandatory population wide surveillance +- Medium - recommended population-wide surveillance +- Low - surveillance only for symptomatic patients + +Depending on the epidemiological situation in the chosen location, the public health surveillance can be more or less active. The confidence level will provide an ascertainment bias to the data collected by the user. +The higher the incidence rate (i.e. new cases / population) the higher are the chances of having at least one infected occupant participating to the event. + +For general and recurrent layout simply select the **Deterministic exposure** option. As an example, for a shared office with 4 people, where one person is infected, we enter 4 occupants and 1 infected person. + +#### Activity type + +There are a few predefined activities in the tool at present. + +- **Office** - All persons seated, talking occasionally (1/3rd of the time, with normal breathing the other 2/3rds of the time). Everyone (exposed and infected occupants) is treated the same in this model. +- **Small meeting** - Less than 10 participants. All persons seated, having a conversation (approximately each occupant is 1/N % of the time talking, where N is the number of occupants). Everyone (exposed and infected occupants) is treated the same in this model. +- **Large Meeting** - 10 or more participants. Similar to a seminar with 'speakers and audience'. Infected occupant(s) is standing and speaking 1/3rd of the time, while the other occupants are seated. +- **Library** - All persons seated, breathing only (not talking), all the time. +- **Call Centre** - All persons seated, all talking simultaneously, all the time. This is a conservative profile, i.e. will show an increased P(i) compared to office/meeting activity. Everyone (exposed and infected occupants) is treated the same in this model. +- **Control Room (day shift)** - All persons seated, all talking 50% of the time. This is a conservative profile, i.e. will show an increased P(i) compared to office/meeting activity. Everyone (exposed and infected occupants) is treated the same in this model. +- **Control Room (night shift)** - All persons seated, all talking 10% of the time. Everyone (exposed and infected occupants) is treated the same in this model. +- **Lab** - Based on a typical lab or technical working area, all persons are doing light activity and talking 50% of the time. Everyone (exposed and infected occupants) is treated the same in this model. +- **Workshop** - Based on a mechanical assembly workshop or equipment installation scenario, all persons are doing moderate activity and talking 50% of the time. This activity is equally applicable to bicycling, or walking on a gradient, in the LHC tunnels. Everyone (exposed and infected occupants) is treated the same in this model. +- **Conference/Training (speaker infected)** - Based on a typical conference/training course scenario. One individual (the speaker/trainer) is standing and talking, with all other individuals seated and talking quietly (whispering). In this case it is assumed that the infected person is the speaker/trainer, because this is the worst case in terms of viral shedding. +- **Conference/Training (attendee infected)** - All individuals seated and breathing. In this case it is assumed that the infected person is not the speaker/trainer. +- **Gym** - All persons are doing heavy exercise and breathing (not talking). Everyone (exposed and infected occupants) is treated the same in this model. + +### Timings + +You should enter the time (hours:minutes) for the start and end of the simulation period (i.e. 8:30 to 17:30 for a typical office day). It is important to enter the correct times for the simulation, in particular when using natural ventilation. It is possible to specify a different time for the entry and exit of both the exposed and infected person, however for most cases (where we do not know apriori which of the occupants is infected), it is recommended to set these to the same values as the activity start and end. + +#### When is the event? + +This is included for completeness in all simulations, however it is of particular relevance to those using natural ventilation because of variations in outside air temperature. + +Only the month is used by the model to retrieve the average outdoor air temperatures for the Geneva region. + +### Breaks + +#### Lunch break + +You have the option to specify a lunch break. This will be useful if you plan to simulate a typical full working day. During the lunch break it is assumed that all occupants will leave the simulated space (to go eat lunch somewhere else - restaurant or break room). If you plan to eat lunch in the same area where you have been working, you should select 'No' even if a lunch break will be taken, since the risk of infection is related to the occupation of the simulated space. See 'Split Breaks' if the occupants do not break at the same time. + +It should also be noted that the infection probabilities presented in the report does not take into account any potential exposures during the break times. + +#### Coffee breaks + +You have the option to choose 0(No breaks), 2 or 4 coffee breaks during the simulated period. It is assumed that all occupants vacate the space during the break period. If coffee breaks are taken in-situ, this option should be set to 'No breaks'. + +When enabled, the breaks are spread equally throughout the day - for example if we simulate the period from 9:00 to 18:00, with a lunch break from 13:00 to 14:00 and considering 2 coffee breaks, the tool will schedule the first coffee break around 11:00 and the second around 16:00. The exact timing of the breaks within the day is not particularly critical to an accurate simulation, so you do not need to be concerned about major differences if you take a coffee break at 10:00 instead of 11:00. The variation of coffee breaks can be altered in 5 minute increments up to 30 minutes in length. Note that this doesn't necessarily have to be a coffee break, it can represent any period where the simulated space is vacated. See 'Split Breaks' if the occupants do not break at the same time. + +It should also be noted that the infection probabilities presented in the report does not take into account any potential exposures during the break times. + +#### Split breaks + +You have the option to specify whether the exposed and infected person(s) break at the same time. If not, then you can input separate breaks. This is particularly different when specifying coffee breaks as they are spread evenly throughout the activity times specified. + +If we take an example where the exposed person(s) activity time is from 9:00 to 18:00 and the infected person(s) is from 10:00 to 17:00, with both having a lunch break from 13:00 to 14:00 and have 2 coffee breaks each, we can have two different results: + +1. Specify the default situation where both exposed and infected persons(s) have their breaks at the same time: in this case the coffee break times are calculated based on the activity time of the exposed - both will have their first coffee break around 11:00 and the second around 16:00. + +2. Specify separate breaks for the infected person(s): in this case the coffee breaks will be calculated based on the different activity times (i.e. exposed from 9:00 to 18:00 and infected from 10:00 to 17:00) - the exposed person(s) will have their first coffee break around 11:00 and the second around 16:00, whereas the infected will have their first coffee break around 11:30 and the second around 15:30. + +### Face masks + +The model allows for a simulation with either a continuous wearing of face masks throughout the duration of the event, or have the removed at all times - i.e. all occupants (infected and exposed alike) wear or not masks for the duration of the simulation. Please bear in mind the user inputs shall be aligned with the current applicable public health & safety instructions. Please check what are the applicable rules, before deciding which assumptions are used for the simulation. + +If you have selected the Conference/Training activity type, this equates to the speaker/trainer and all participants either wearing masks throughout the conference/training (Yes), or removing them when seated/standing at their socially distanced positions within the conference/training room (No). Please confirm what are the applicable rules, before deciding which assumptions are used for the simulation + +For the time being only the Type 1 surgical, FFP2, and Cloth masks can be selected. + +### Report + +When you have entered all the necessary information, please click on the Generate Report button to execute the model. With the implementation of Monte Carlo simulations, the browser might take a few seconds to react. + +The report will open in your web browser. It contains a summary of all the input data, which will allow the simulation to be repeated if required in the future as we improve the model. + +#### Results + +This part of the report shows the P(I) or probability of one exposed person getting infected. It is estimated based on the emission rate of virus into the simulated volume, and the amount which is inhaled by exposed individuals. This probability is valid for the simulation duration - i.e. the start and end time. If you are using the natural ventilation option, the simulation is only valid for the selected month, because the following or preceding month will have a different average temperature profile. The expected number of new cases for the simulation is calculated based on the probability of infection, multiplied by the number of exposed occupants. + +The graph shows the variation in the concentration of virions within the simulated volume. It is determined by: + +- The presence of the infected person, who emits airborne viruses in the volume. +- The emission rate is related to the type of activity of the infected person (sitting, light exercise), their level of vocalisation (breathing, speaking or shouting). +- The accumulation of virions in the volume, which is driven, among other factors, by ventilation (if applicable). + - In a mechanical ventilation scenario, the removal rate is constant, based on fresh airflow supply in and out of the simulated space. + - Under natural ventilation conditions, the effectiveness of ventilation relies upon the hourly temperature difference between the inside and outside air temperature. + - A HEPA filter removes virions from the air at a constant rate and is modelled in the same way as mechanical ventilation, however air passed through a HEPA filter is recycled (i.e. it is not fresh air). + +#### QR code + +At the end of the report you can find a unique QR code / hyperlink for this report. This provides an automatic way to review the calculator form with the corresponding specified parameters. This allows for: + +- sharing reports by either scanning or clicking on the QR code to obtain a shareable link. +- easily regenerating reports with any new versions of the CAiMIRA model released in the future. + +### Conclusion + +This tool provides informative comparisons for COVID-19 airborne risk only - see Disclaimer. If you have any comments on your experience with the app, or feedback for potential improvements, please share them with the development team - [send email](mailto:caimira-dev@cern.ch). \ No newline at end of file diff --git a/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/img/window_opening.png b/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/img/window_opening.png new file mode 100644 index 00000000..5b96b169 Binary files /dev/null and b/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/img/window_opening.png differ diff --git a/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/img/window_type.PNG b/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/img/window_type.PNG new file mode 100644 index 00000000..8d7d7405 Binary files /dev/null and b/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/img/window_type.PNG differ diff --git a/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/quick_guide.md b/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/quick_guide.md new file mode 100644 index 00000000..f80e91ea --- /dev/null +++ b/caimira/docs/mkdocs/docs/user_interfaces/CAiMIRA/quick_guide.md @@ -0,0 +1,46 @@ +## [CAiMIRA Calculator](https://caimira.web.cern.ch/) + +This tool simulates the airborne spread of SARS-CoV-2 virus in a finite volume and estimates the risk of COVID-19 infection. It is based on current scientific data and can be used to compare the effectiveness of different mitigation measures. + +### Virus data + +SARS-CoV-2 covers the original "wild type" strain of the virus and three variants of concern (VOC): +- Alpha (also known as B.1.1.7, first identified in UK, Sept 2020), +- Beta (also known as B.1.351, first identified in South Africa, May 2020). +- Gamma (also known as P.1, first identified in Brazil/Japan, Jan 2021). +- Delta (also known as B.1.617.2, first identified in India, Oct 2020). +- Omicron (also known as B.1.1.529, first identified in South Africa, November 2021). + +Modify the default as necessary, according to local area prevalence e.g. for [Geneva](https://www.covid19.admin.ch/fr/epidemiologic/virus-variants?geo=GE). + +### Ventilation data + +- Mechanical ventilation = the HVAC supply of fresh air. Check the flow rates with the concerned technical department. +- Natural ventilation = the type of window opening. The opening distance is between the fixed frame and movable part when open (commonly used values are window height of 1.6m and window opening between 0.15m and 0.6m). In case of periodic opening, specify the duration (e.g. 10 min) per hour. +- HEPA filtration = the air flow of the device. The following values are based on the different fan velocities of a specific commercial device proposed by the HSE Unit: + - Level 6 (max) = 430 m3/h (noisy), + - Level 5 = 250 m3/h (ok w.r.t. noise, recommended), + - Level 4 = 130 m3/h (silent), + - Level 3 = 95 m3/h (silent). + +### Activity types + +The type of activity applies to both the infected and exposed persons: +- Office = all seated, talking 33% of the time, +- Small meeting (< 10 occ.) = all seated, talking time shared between all persons, +- Large meeting (>= 10 occ.) = speaker is standing and speaking 33% of the time, other occupants are seated, +- Call Centre = all seated, continuous talking, +- Control Room (day shift) = all seated, talking 50% of the time, +- Control Room (night shift) = all seated, talking 10% of the time, +- Library = all seated, no talking, just breathing, +- Laboratory = light physical activity, talking 50% of the time, +- Workshop = moderate physical activity, talking 50% of the time, +- Conference/Training (speaker infected) = speaker/trainer standing and talking, rest seated and talking quietly. Speaker/Trainer assumed infected (worst case scenario), +- Conference/Training (attendee infected) = someone in the audience is infected, all are seated and breathing. +- Gym = heavy exercise, no talking, just breathing. + +### Activity breaks + +If coffee breaks are included, they are spread out evenly throughout the day, in addition to any lunch break (if applicable). + +Refer to the [Full Guide](full_guide.md) for more detailed explanations on how to use this tool. \ No newline at end of file diff --git a/caimira/docs/mkdocs/mkdocs.yml b/caimira/docs/mkdocs/mkdocs.yml new file mode 100644 index 00000000..0ff9de5f --- /dev/null +++ b/caimira/docs/mkdocs/mkdocs.yml @@ -0,0 +1,43 @@ +site_name: CAiMIRA Docs +theme: + name: material + logo: assets/caimira_logo.png + favicon: assets/caimira_logo.png + features: + - content.code.copy + +repo_url: https://gitlab.cern.ch/caimira/caimira + +nav: + - Home: index.md + - About: root/about.md + - Installation: root/installation.md + - Deployment: root/deployment.md + - Open Source Acknowledgments: root/open_source_acknowledgments.md + - License: LICENSE.md + - Physics of the model: root/physics_model.md + - Code: + - Architecture: code/architecture.md + - CO₂ Fitting Algorithm: code/fitting_algorithm.md + - REST API: code/rest_api.md + - models.py: code/models.md + - User Interfaces: + - CAiMIRA Calculator: + - Quick Guide: user_interfaces/CAiMIRA/quick_guide.md + - Full Guide: user_interfaces/CAiMIRA/full_guide.md + - ARIA: https://partnersplatform.who.int/aria + +markdown_extensions: + - pymdownx.arithmatex: + generic: true + - toc: + toc_depth: '1-3' + - admonition + - pymdownx.details + - attr_list + - md_in_html + +extra_javascript: + - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js + + diff --git a/caimira/src/caimira/calculator/docs/Makefile b/caimira/docs/sphinx/Makefile similarity index 100% rename from caimira/src/caimira/calculator/docs/Makefile rename to caimira/docs/sphinx/Makefile diff --git a/caimira/docs/sphinx/conf.py b/caimira/docs/sphinx/conf.py new file mode 100644 index 00000000..a763660d --- /dev/null +++ b/caimira/docs/sphinx/conf.py @@ -0,0 +1,34 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../../src/caimira/calculator')) + +# -- Project information ----------------------------------------------------- + +project = 'CAiMIRA' +copyright = '2024, Andre Henriques et al.' +author = 'Andre Henriques et al.' + +release = '1.0.0' + +# -- General configuration --------------------------------------------------- + +extensions = ['sphinx.ext.autodoc', 'sphinx_markdown_builder'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build/*', 'Thumbs.db', '.DS_Store'] + +add_module_names = False diff --git a/caimira/docs/sphinx/index.rst b/caimira/docs/sphinx/index.rst new file mode 100644 index 00000000..9d4434fa --- /dev/null +++ b/caimira/docs/sphinx/index.rst @@ -0,0 +1,7 @@ +CAiMIRA models +============== + +.. automodule:: models.models + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/caimira/src/caimira/calculator/docs/make.bat b/caimira/docs/sphinx/make.bat similarity index 100% rename from caimira/src/caimira/calculator/docs/make.bat rename to caimira/docs/sphinx/make.bat diff --git a/caimira/docs/style_docs.py b/caimira/docs/style_docs.py new file mode 100644 index 00000000..d278d728 --- /dev/null +++ b/caimira/docs/style_docs.py @@ -0,0 +1,219 @@ + +""" Changes the .md files to contain desired styling """ + +import re +import os +import subprocess +import matplotlib.pyplot as plt +from collections import Counter + +def get_package_info(): + """ + Retrieves package details (name, version, license, and homepage) for each installed package. + Uses pip show to get detailed information. + """ + # Get the list of installed packages using pip freeze + packages = subprocess.check_output(["pip", "freeze"]).decode().splitlines() + + package_details = [] + for package in packages: + package_name = package.split("==")[0] + try: + # Get detailed info about each package + info = subprocess.check_output(["pip", "show", package_name]).decode().splitlines() + + details = { + "name": package_name, + "version": "", + "license": "", + "homepage": "" + } + + for line in info: + if line.startswith("Version:"): + details["version"] = line.split(":", 1)[1].strip() + elif line.startswith("License:"): + details["license"] = line.split(":", 1)[1].strip() + elif line.startswith("Home-page:"): + details["homepage"] = line.split(":", 1)[1].strip() + + # Append the details for the current package + package_details.append(details) + except subprocess.CalledProcessError: + print(f"Error retrieving details for package: {package_name}") + + return package_details + + +def update_markdown_references(md_file_path): + """ + Updates the code markdown file by adding headers for class definitions and modifying internal links. + """ + # Read the original Markdown file + with open(md_file_path, 'r') as file: + md_content = file.read() + + # Regular expression to find all class definitions, including those without parameters + class_pattern = re.compile(r'### \*class\* (\w+)(\(.*\))?') + + # Find all matches for class definitions + class_matches = class_pattern.findall(md_content) + + # For each found class definition + for match in class_matches: + # Class name (e.g., 'Interval' or 'ConcentrationModel') + class_name = match[0] + + # Create the header for this class + header = f"## {class_name} Class\n" + + # Check if the header already exists in the file + if header not in md_content: + # If the header does not exist, insert it before the class definition + md_content = md_content.replace( + f"### *class* {class_name}", header + f"### *class* {class_name}") + + # Replace references like #models.models.ClassName with #className-class + md_content = md_content.replace( + f"#models.models.{class_name}", f"#{class_name.lower()}-class") + + # Write the updated content back to the file + with open(md_file_path, 'w') as file: + file.write(md_content) + print(f"Markdown file '{md_file_path}' updated successfully.") + + +def unify_license(license_str): + """ + Returns an unified license version. + """ + license_map = { + 'MIT': 'MIT', + 'MIT License': 'MIT', + 'MIT license': 'MIT', + 'MIT-CMU': 'MIT', + 'http://www.opensource.org/licenses/mit-license.php': 'MIT', + 'BSD': 'BSD-3-Clause', + 'BSD-3-Clause': 'BSD-3-Clause', + 'BSD 3-Clause License': 'BSD-3-Clause', + 'BSD 3-Clause': 'BSD-3-Clause', + 'BSD-2-Clause': 'BSD-2-Clause', + 'BSD License': 'BSD-3-Clause', + 'new BSD License': 'BSD-3-Clause', + 'Modified BSD License': 'BSD-3-Clause', + 'BSD 2-Clause License': 'BSD-2-Clause', + 'Apache 2.0': 'Apache-2.0', + 'Apache Software License': 'Apache-2.0', + 'Apache 2.0 License': 'Apache-2.0', + 'Apache License, Version 2.0': 'Apache-2.0', + 'Apache 2.0 license': 'Apache-2.0', + 'Apache-2.0': 'Apache-2.0', + 'Apache Software License 2.0': 'Apache-2.0', + 'MPL-2.0': 'MPL-2.0', + 'MPL 2.0': 'MPL-2.0', + 'GPL-2.0-or-later': 'GPL-2.0-or-later', + 'LGPL-2.1-or-later': 'LGPL-2.1-or-later', + 'ISC license': 'ISC', + 'Expat license': 'Expat', + 'MIT OR Apache-2.0': 'Dual License', + 'Dual License': 'Dual License', + 'UNKNOWN': 'Unknown' + } + + return license_map.get(license_str, 'Custom') + + +def add_python_dependencies_section(md_file_path, package_details): + """ + Adds the Python package dependencies section to the Open Source Acknowledgments Markdown file. + """ + # Section header for Python dependencies + dependencies_section = '\n\n' + for package in package_details: + package_url = f"https://pypi.org/project/{package['name']}/{package['version']}/" + package_title = f" #### [{package['name']} {package['version']}]({package_url})" + if package["license"]: + license_text = f" - License: {unify_license(package['license'])}" + else: + license_text = " - License: Unknown" + + dependencies_section += f"{package_title}\n\n{license_text}\n\n" + + # Read the current content of the Markdown file + with open(md_file_path, 'r') as file: + md_content = file.read() + + # Regex to find the "Back-end (Python) Dependencies" section + section_pattern = re.compile( + r'(?<=\?\?\? "Back-end \(Python\) Dependencies")(.*?)(?=\n\?\?\?|\Z)', re.DOTALL) + + match = section_pattern.search(md_content) + if match: + updated_content = md_content[:match.start(1)] + dependencies_section + md_content[match.end(1):] + else: + raise ValueError("Error: '??? \"Back-end (Python) Dependencies\"' section not found in the file.") + + with open(md_file_path, 'w') as file: + file.write(updated_content) + + print(f"Markdown file '{md_file_path}' updated with Python dependencies section.") + + +def generate_license_distribution_pie_chart(package_details, output_image_path): + """ + Generates a pie chart showing the distribution of licenses from the package details. + The chart is saved to the specified output image path. + """ + try: + licenses = [unify_license(pkg["license"]) for pkg in package_details if pkg["license"]] + license_counts = Counter(licenses) + + # Create labels and sizes for the pie chart + labels = list(license_counts.keys()) + sizes = list(license_counts.values()) + + # Create the pie chart + plt.figure(figsize=(8, 8), dpi=300) + plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=140) + plt.axis('equal') + + # Save and show the pie chart + plt.savefig(output_image_path, dpi=300) + plt.close() + + print(f"License distribution pie chart saved to {output_image_path}") + + except Exception as e: + print(f"Error generating license distribution chart: {e}") + + + + +def main(): + # Path to the index.md markdown file to be updated + index_file_path = 'sphinx/_build/markdown/index.md' + + if os.path.isfile(index_file_path): + update_markdown_references(index_file_path) + else: + print(f"File '{index_file_path}' does not exist, skipping update.") + + # Path to the open source acknowledgements markdown file to be updated + acknowledgements_file_path = 'mkdocs/docs/root/open_source_acknowledgments.md' + + if os.path.isfile(acknowledgements_file_path): + # Retrieve package details + package_details = get_package_info() + + # Write the dependencies in the file + add_python_dependencies_section(acknowledgements_file_path, package_details) + + # Generate the pie chart + output_image_path = 'mkdocs/docs/root/license_distribution.png' + generate_license_distribution_pie_chart(package_details, output_image_path) + else: + print(f"File '{acknowledgements_file_path}' does not exist, skipping update.") + + +if __name__ == "__main__": + main() diff --git a/caimira/pyproject.toml b/caimira/pyproject.toml index 9f82c5d5..e1188fd6 100644 --- a/caimira/pyproject.toml +++ b/caimira/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "caimira" -version = "4.17.4" +version = "4.17.5" description = "CAiMIRA - CERN Airborne Model for Indoor Risk Assessment" license = { text = "Apache-2.0" } authors = [ @@ -49,7 +49,10 @@ test = [ ] doc = [ "sphinx", - "sphinx_rtd_theme" + "sphinx_markdown_builder", + "pylint", + "mkdocs", + "mkdocs-material", ] [project.urls] diff --git a/caimira/src/caimira/calculator/docs/UML-CAiMIRA.png b/caimira/src/caimira/calculator/docs/UML-CAiMIRA.png deleted file mode 100644 index 6b91e30b..00000000 Binary files a/caimira/src/caimira/calculator/docs/UML-CAiMIRA.png and /dev/null differ diff --git a/caimira/src/caimira/calculator/docs/caimira.apps.calculator.rst b/caimira/src/caimira/calculator/docs/caimira.apps.calculator.rst deleted file mode 100644 index e1b10080..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.apps.calculator.rst +++ /dev/null @@ -1,45 +0,0 @@ -caimira.apps.calculator package -=============================== - -Submodules ----------- - -caimira.apps.calculator.markdown\_tools module ----------------------------------------------- - -.. automodule:: caimira.apps.calculator.markdown_tools - :members: - :undoc-members: - :show-inheritance: - -caimira.apps.calculator.model\_generator module ------------------------------------------------ - -.. automodule:: caimira.apps.calculator.model_generator - :members: - :undoc-members: - :show-inheritance: - -caimira.apps.calculator.report\_generator module ------------------------------------------------- - -.. automodule:: caimira.apps.calculator.report_generator - :members: - :undoc-members: - :show-inheritance: - -caimira.apps.calculator.user module ------------------------------------ - -.. automodule:: caimira.apps.calculator.user - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.apps.calculator - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.apps.rst b/caimira/src/caimira/calculator/docs/caimira.apps.rst deleted file mode 100644 index 24013a5c..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.apps.rst +++ /dev/null @@ -1,29 +0,0 @@ -caimira.apps package -==================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - caimira.apps.calculator - -Submodules ----------- - -caimira.apps.expert module --------------------------- - -.. automodule:: caimira.apps.expert - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.apps - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.data.rst b/caimira/src/caimira/calculator/docs/caimira.data.rst deleted file mode 100644 index 4a011f08..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.data.rst +++ /dev/null @@ -1,21 +0,0 @@ -caimira.data package -==================== - -Submodules ----------- - -caimira.data.weather module ---------------------------- - -.. automodule:: caimira.data.weather - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.data - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.monte_carlo.rst b/caimira/src/caimira/calculator/docs/caimira.monte_carlo.rst deleted file mode 100644 index 38f81dd4..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.monte_carlo.rst +++ /dev/null @@ -1,37 +0,0 @@ -caimira.monte\_carlo package -============================ - -Submodules ----------- - -caimira.monte\_carlo.data module --------------------------------- - -.. automodule:: caimira.monte_carlo.data - :members: - :undoc-members: - :show-inheritance: - -caimira.monte\_carlo.models module ----------------------------------- - -.. automodule:: caimira.monte_carlo.models - :members: - :undoc-members: - :show-inheritance: - -caimira.monte\_carlo.sampleable module --------------------------------------- - -.. automodule:: caimira.monte_carlo.sampleable - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.monte_carlo - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.rst b/caimira/src/caimira/calculator/docs/caimira.rst deleted file mode 100644 index 0cfac4ec..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.rst +++ /dev/null @@ -1,56 +0,0 @@ -CAiMIRA source code -=================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - caimira.apps - caimira.data - caimira.monte_carlo - caimira.tests - -Submodules ----------- - -caimira.dataclass\_utils module -------------------------------- - -.. automodule:: caimira.dataclass_utils - :members: - :undoc-members: - :show-inheritance: - -caimira.models module ---------------------- - -.. automodule:: caimira.models - :members: - :undoc-members: - :show-inheritance: - -caimira.state module --------------------- - -.. automodule:: caimira.state - :members: - :undoc-members: - :show-inheritance: - -caimira.utils module --------------------- - -.. automodule:: caimira.utils - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.tests.apps.calculator.rst b/caimira/src/caimira/calculator/docs/caimira.tests.apps.calculator.rst deleted file mode 100644 index c5f7eb4e..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.tests.apps.calculator.rst +++ /dev/null @@ -1,53 +0,0 @@ -caimira.tests.apps.calculator package -===================================== - -Submodules ----------- - -caimira.tests.apps.calculator.conftest module ---------------------------------------------- - -.. automodule:: caimira.tests.apps.calculator.conftest - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.apps.calculator.test\_markdown\_tools module ----------------------------------------------------------- - -.. automodule:: caimira.tests.apps.calculator.test_markdown_tools - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.apps.calculator.test\_model\_generator module ------------------------------------------------------------ - -.. automodule:: caimira.tests.apps.calculator.test_model_generator - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.apps.calculator.test\_report\_generator module ------------------------------------------------------------- - -.. automodule:: caimira.tests.apps.calculator.test_report_generator - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.apps.calculator.test\_webapp module -------------------------------------------------- - -.. automodule:: caimira.tests.apps.calculator.test_webapp - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.tests.apps.calculator - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.tests.apps.rst b/caimira/src/caimira/calculator/docs/caimira.tests.apps.rst deleted file mode 100644 index a5f80cbc..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.tests.apps.rst +++ /dev/null @@ -1,29 +0,0 @@ -caimira.tests.apps package -========================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - caimira.tests.apps.calculator - -Submodules ----------- - -caimira.tests.apps.test\_expert\_app module -------------------------------------------- - -.. automodule:: caimira.tests.apps.test_expert_app - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.tests.apps - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.tests.data.rst b/caimira/src/caimira/calculator/docs/caimira.tests.data.rst deleted file mode 100644 index 3ff1c2fc..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.tests.data.rst +++ /dev/null @@ -1,21 +0,0 @@ -caimira.tests.data package -========================== - -Submodules ----------- - -caimira.tests.data.test\_weather module ---------------------------------------- - -.. automodule:: caimira.tests.data.test_weather - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.tests.data - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.tests.models.rst b/caimira/src/caimira/calculator/docs/caimira.tests.models.rst deleted file mode 100644 index f70f7b25..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.tests.models.rst +++ /dev/null @@ -1,53 +0,0 @@ -caimira.tests.models package -============================ - -Submodules ----------- - -caimira.tests.models.test\_concentration\_model module ------------------------------------------------------- - -.. automodule:: caimira.tests.models.test_concentration_model - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.models.test\_exposure\_model module -------------------------------------------------- - -.. automodule:: caimira.tests.models.test_exposure_model - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.models.test\_mask module --------------------------------------- - -.. automodule:: caimira.tests.models.test_mask - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.models.test\_piecewiseconstant module ---------------------------------------------------- - -.. automodule:: caimira.tests.models.test_piecewiseconstant - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.models.test\_short\_range\_model module ------------------------------------------------------ - -.. automodule:: caimira.tests.models.test_short_range_model - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.tests.models - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/caimira.tests.rst b/caimira/src/caimira/calculator/docs/caimira.tests.rst deleted file mode 100644 index 51c8c86f..00000000 --- a/caimira/src/caimira/calculator/docs/caimira.tests.rst +++ /dev/null @@ -1,135 +0,0 @@ -caimira.tests package -===================== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - caimira.tests.apps - caimira.tests.data - caimira.tests.models - -Submodules ----------- - -caimira.tests.conftest module ------------------------------ - -.. automodule:: caimira.tests.conftest - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_caimira module ----------------------------------- - -.. automodule:: caimira.tests.test_caimira - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_dataclass\_utils module -------------------------------------------- - -.. automodule:: caimira.tests.test_dataclass_utils - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_expiration module -------------------------------------- - -.. automodule:: caimira.tests.test_expiration - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_full\_algorithm module ------------------------------------------- - -.. automodule:: caimira.tests.test_full_algorithm - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_infected\_population module ------------------------------------------------ - -.. automodule:: caimira.tests.test_infected_population - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_known\_quantities module --------------------------------------------- - -.. automodule:: caimira.tests.test_known_quantities - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_model module --------------------------------- - -.. automodule:: caimira.tests.test_model - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_monte\_carlo module ---------------------------------------- - -.. automodule:: caimira.tests.test_monte_carlo - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_monte\_carlo\_full\_models module ------------------------------------------------------ - -.. automodule:: caimira.tests.test_monte_carlo_full_models - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_predefined\_distributions module ----------------------------------------------------- - -.. automodule:: caimira.tests.test_predefined_distributions - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_sampleable\_distribution module ---------------------------------------------------- - -.. automodule:: caimira.tests.test_sampleable_distribution - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_state module --------------------------------- - -.. automodule:: caimira.tests.test_state - :members: - :undoc-members: - :show-inheritance: - -caimira.tests.test\_ventilation module --------------------------------------- - -.. automodule:: caimira.tests.test_ventilation - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: caimira.tests - :members: - :undoc-members: - :show-inheritance: diff --git a/caimira/src/caimira/calculator/docs/conf.py b/caimira/src/caimira/calculator/docs/conf.py deleted file mode 100644 index 3982967b..00000000 --- a/caimira/src/caimira/calculator/docs/conf.py +++ /dev/null @@ -1,60 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('..')) - - -# -- Project information ----------------------------------------------------- - -project = 'CAiMIRA' -copyright = '2022, Andre Henriques et al.' -author = 'Andre Henriques et al.' - -# The full version, including alpha/beta/rc tags -release = '4.1.1' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinx.ext.autodoc', 'sphinx_rtd_theme'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'sphinx_rtd_theme' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = False - -html_static_path = [] \ No newline at end of file diff --git a/caimira/src/caimira/calculator/docs/full_diameter_dependence.rst b/caimira/src/caimira/calculator/docs/full_diameter_dependence.rst deleted file mode 100644 index 219eb78f..00000000 --- a/caimira/src/caimira/calculator/docs/full_diameter_dependence.rst +++ /dev/null @@ -1,342 +0,0 @@ -************************* -Diameter-dependent model -************************* - -This section describes the model and its dependence on the Particles diameter. A Unified Modeling Language (UML) diagram describing all the data classes and their relations can be found :ref:`here`, at the bottom of the document. - -Context -======= - - -The :mod:`caimira.apps.calculator.model_generator` module is responsible to bind all the inputs defined in the user interface into the respective model variables. -The :py:mod:`caimira.apps.calculator.report_generator` module is responsible to bind the results from the model calculations into the respective output variables presented in the CAiMIRA report. -The :mod:`caimira.models` module itself implements the core CAiMIRA methods. A useful feature of the implementation is that we can benefit from vectorisation, which allows running multiple parameterizations of the model at the same time. - -Unlike other similar models, some of the CAiMIRA variables are considered for a given aerosol diameter :math:`D`, -as the behavior of the virus-laden particles in the room environment and inside the susceptible host (once inhaled) are diameter-dependent. -Here, these variables are identified by their functional dependency on :math:`D`, as for the **emission rate** -- :math:`\mathrm{vR}(D)`, **removal rate** -- :math:`\mathrm{vRR}(D)`, and **concentration** -- :math:`C(t, D)`. - -Despite the outcome of the CAiMIRA results include the entire range of diameters, throughout the model, -most of the variables and parameters are kept in their diameter-dependent form for any possible detailed analysis of intermediate results. -Only the final quantities shown in output, such as the concentration and the dose, are integrated over the diameter distribution. -This is performed thanks to a Monte-Carlo (MC) integration at the level of the dose (:math:`\mathrm{vD^{total}}`) which is computed over a distribution of particle diameters, -from which the average value (i.e. :code:`.mean()` of the numpy array) is then calculated -- this is equivalent to an analytical integral over diameters -provided the sample size is large enough. Example of the MC integration over the diameters for the dose: -:code:`deposited_exposure += np.array(short_range_exposure * fdep).mean()` - -It is important to distinguish between 1) Monte-Carlo random variables (which are vectorised independently on its diameter-dependence) and 2) numerical Monte-Carlo integration for the diameter-dependence. -Since the integral of the diameter-dependent variables are solved when computing the dose -- :math:`\mathrm{vD^{total}}` -- while performing some of the intermediate calculations, -we normalize the results by *dividing* by the Monte-Carlo variables that are diameter-independent, so that they are not considered in the Monte-Carlo integration (e.g. the **viral load** parameter, or the result of the :meth:`caimira.models.InfectedPopulation.emission_rate_per_aerosol_per_person_when_present` method). - -Expiration -========== - -The **Expiration** class (representing the expiration of aerosols by an infected person) has the `Particle` -- :attr:`caimira.models.Expiration.particle` -- as one of its properties, -which represents the virus-laden aerosol with a vectorised parameter: the particle `diameter` (assuming a perfect sphere). -For a given aerosol diameter, one :class:`caimira.models.Expiration` object provides the aerosol **volume** - :math:`V_p(D)`, multiplied by the **mask outward efficiency** - :math:`η_\mathrm{out}(D)` to include the filtration capacity, when applicable. - -The BLO model represents the distribution of diameters used in the model. It corresponds to the sum of three log-normal distributions, weighted by the **B**, **L** and **O** modes. -The aerosol diameter distributions are given by the :meth:`caimira.monte_carlo.data.BLOmodel.distribution` method. - -The :class:`caimira.monte_carlo.data.BLOmodel` class itself contains the method to return the mathematical values of the probability distribution for a given diameter (in microns), -as well as the method to return its integral between the **min** and **max** diameters. -The BLO model is used to provide the probability density function (PDF) of the aerosol diameters for a given **Expiration** type defined in :meth:`caimira.monte_carlo.data.expiration_distribution`. -To compute the total number concentration of particles per mode (B, L and O), :math:`cn` in particles/cm\ :sup:`3`\, in other words, the total concentration of aerosols per unit volume of expired air, -an integration of the log-normal distributions is performed over all aerosol diameters. In the code it is used as a scaling factor in the :class:`caimira.models.Expiration` class. - -Under the :mod:`caimira.apps.calculator.model_generator`, when it comes to generate the Expiration model, the `diameter` property is sampled through the BLO :meth:`caimira.monte_carlo.data.BLOmodel.distribution` method, while the value for the :math:`cn` is given by the :meth:`caimira.monte_carlo.data.BLOmodel.integrate` method. -To summarize, the Expiration object contains, as a vectorised float, a sample of diameters following the BLO distribution. Depending on different expiratory types, the contributions from each mode will be different, therefore the resulting distribution also differs from model to model. - -Emission Rate - vR(D) -===================== - -The mathematical equations to calculate :math:`\mathrm{vR}(D)` are defined in the paper - Henriques, A. et al. [2]_ - as follows: - -:math:`\mathrm{vR}(D)_j= \mathrm{vl_{in}} \cdot E_{c,j}(D,f_{\mathrm{amp}},\eta_{\mathrm{out}}(D)) \cdot {\mathrm{BR}}_{\mathrm{k}}` , - -:math:`E_{c,j}^{\mathrm{total}} = \int_0^{D_{\mathrm{max}}} E_{c,j}(D)\, \mathrm{d}D` . - -The later integral, which is giving the total volumetric particle emission concentration (in mL/m\ :sup:`3` \), is a example of a numerical Monte-Carlo integration over the particle diameters, -since :math:`E_{c,j}(D)` is a diameter-dependent quantity. :math:`E^{\mathrm{total}}_{c, j}` is calculated from the mean of the Monte-Carlo sample :math:`E_{c,j}(D)`. -Note that :math:`D_{\mathrm{max}}` value will differ, depending on the type of exposure (see below). - -In the code, for a given Expiration, we use different methods to perform the calculations *step-by-step*: - -1. Calculate the non aerosol-dependent quantities in the emission rate per person infected, which is the multiplication of the diameter-**independent** variables: :meth:`caimira.models.InfectedPopulation.emission_rate_per_aerosol_per_person_when_present`. This corresponds to the :math:`\mathrm{vl_{in}} \cdot \mathrm{BR_{k}}` part of the :math:`\mathrm{vR}(D)` equation. -2. Calculate the diameter-**dependent** variable :meth:`caimira.models.InfectedPopulation.aerosols`, which is the result of :math:`E_{c,j}(D) = N_p(D) \cdot V_p(D) \cdot (1 − η_\mathrm{out}(D))` (in mL/(m\ :sup:`3` \.µm)), with :math:`N_p(D)` being the product of the BLO distribution by the scaling factor :math:`cn`. Note that this result is not integrated over the diameters at this stage, thus the units are still *'per aerosol diameter'*. -3. Calculate the full emission rate (per person infected), which is the multiplication of the two previous methods, and corresponds to :math:`\mathrm{vR(D)}`: :meth:`caimira.models._PopulationWithVirus.emission_rate_per_person_when_present`. - -Note that the diameter-dependence is kept at this stage. Since other parameters downstream in code are also diameter-dependent, the Monte-Carlo integration over the aerosol sizes is computed at the level of the dose :math:`\mathrm{vD^{total}}`. -In case one would like to have intermediate results for emission rate, perform the Monte-Carlo integration of :math:`E_{c, j}^{\mathrm{total}}` and compute :math:`\mathrm{vR^{total}} =\mathrm{vl_{in}} \cdot E_{c, j}^{\mathrm{total}} \cdot \mathrm{BR_k}`. - -Virus Concentration - C(t, D) -============================= - -The estimate of the concentration of virus-laden particles in a given room is based on a two-box exposure model: - -* **Box 1** - long-range exposure: also known as the *background* concentration, corresponds to the exposure of airborne virions where the susceptible (exposed) host is more than 2 m away from the infected host(s), considering the result of a mass balance equation between the emission rate of the infected host(s) and the removal rates from the environmental/virological characteristics. -* **Box 2** - short-range exposure: also known as the *exhaled jet* concentration in close-proximity, corresponds to the exposure of airborne virions where the susceptible (exposed) host is distanced between 0.5 and 2 m from an infected host, considering the result of a two-stage exhaled jet model. - -Note that most of the methods used to calculate the concentration are defined in the superclass :meth:`caimira.models._ConcentrationModelBase`, while the specific methods for the long-range virus concentration are part of the subclass :meth:`caimira.models.ConcentrationModel`. -The specific removal rate, minimum background concentration and normalization factors will depend on what concentration is being calculated (e.g. viral concentration or CO\ :sub:`2` concentration) and are respectively defined in :meth:`caimira.models._ConcentrationModelBase.removal_rate`, -:meth:`caimira.models._ConcentrationModelBase.min_background_concentration` and :meth:`caimira.models._ConcentrationModelBase.normalization_factor`. - -Long-range approach -******************* - -The long-range concentration of virus-laden aerosols of a given size :math:`D`, that is based on the mass balance equation between the emission and removal rates, is given by: - -:math:`C_{\mathrm{LR}}(t, D)=\frac{\mathrm{vR}(D) \cdot N_{\mathrm{inf}}}{\lambda_{\mathrm{vRR}}(D) \cdot V_r}-\left (\frac{\mathrm{vR}(D) \cdot N_{\mathrm{inf}}}{\lambda_{\mathrm{vRR}}(D) \cdot V_r}-C_0(D) \right )e^{-\lambda_{\mathrm{vRR}}(D)t}` , - -and computed, as a function of the exposure time and particle diameter, in the :meth:`caimira.models._ConcentrationModelBase.concentration` method. -The long-range concentration, integrated over the exposure time (in piecewise constant steps), :math:`C(D)`, is given by :meth:`caimira.models._ConcentrationModelBase.integrated_concentration`. - -In the :math:`C_{\mathrm{LR}}(t, D)` equation above, the **emission rate** - :math:`\mathrm{vR}(D)` - and the **viral removal rate** - :math:`\lambda_{\mathrm{vRR}}(D)`, :meth:`caimira.models.ConcentrationModel.infectious_virus_removal_rate` - are both diameter-dependent. -One can show that the resulting concentration is always proportional to the emission rate :math:`\mathrm{vR}(D)`. Hence, for computational speed-up purposes -the code computes first a normalized version of the concentration, i.e. divided by the emission rate, before multiplying by :math:`\mathrm{vR}(D)`. - -To summarize, we can split the concentration in two different formulations: - -* Normalized concentration :meth:`caimira.models._ConcentrationModelBase._normed_concentration`: :math:`\mathrm{C_\mathrm{LR, normed}}(t, D)` that computes the concentration without including the emission rate per person infected. -* Concentration :meth:`caimira.models._ConcentrationModelBase.concentration` : :math:`C_{\mathrm{LR}}(t, D) = \mathrm{C_\mathrm{LR, normed}}(t, D) \cdot \mathrm{vR}(D)`, where :math:`\mathrm{vR}(D)` is the result of the :meth:`caimira.models._PopulationWithVirus.emission_rate_per_person_when_present` method. - -Note that in order to get the total concentration value in this stage, the final result should be averaged over the particle diameters (i.e. Monte-Carlo integration over diameters, see above). -For the calculator app report, the total concentration (MC integral over the diameter) is performed only when generating the plot. -Otherwise, the diameter-dependence continues until we compute the inhaled dose in the :class:`caimira.models.ExposureModel` class. - -The following methods calculate the integrated concentration between two times. They are mostly used when calculating the **dose**: - -* :meth:`caimira.models._ConcentrationModelBase.normed_integrated_concentration`, :math:`\mathrm{C_\mathrm{normed}}(D)` that returns the integrated long-range concentration of viruses in the air, between any two times, normalized by the emission rate per person infected. Note that this method performs the integral between any two times of the previously mentioned :meth:`caimira.models._ConcentrationModelBase._normed_concentration` method. -* :meth:`caimira.models._ConcentrationModelBase.integrated_concentration`, :math:`C(D)`, that returns the same result as the previous one, but multiplied by the emission rate (per person infected). - -The integral over the exposure times is calculated directly in the class (integrated methods). - -Short-range approach -******************** - -The short-range concentration is the result of a two-stage exhaled jet model developed by Jia, W. et al. [1]_ and is expressed as: - -:math:`C_{\mathrm{SR}}(t, D) = C_{\mathrm{LR}} (t, D) + \frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100μm}(t, D))` , - -where :math:`S(x)` is the dilution factor due to jet dynamics, as a function of the interpersonal distance :math:`x` and :math:`C_{0, \mathrm{SR}}(D)` corresponds to the initial concentration of virions at the mouth/nose outlet during exhalation. -:math:`C_{\mathrm{LR}, 100μm}(t, D)` is the long-range concentration, calculated in :meth:`caimira.models._ConcentrationModelBase.concentration` method but **interpolated** to the diameter range used for close-proximity (from 0 to 100μm). -Note that :math:`C_{0, \mathrm{SR}}(D)` is constant over time, hence only dependent on the particle diameter distribution. - -For code simplification, we split the :math:`C_{\mathrm{SR}}(t, D)` equation into two components: - -* short-range component: :math:`\frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100μm}(t, D))`, dealt with in the dataclass :class:`caimira.models.ShortRangeModel`. -* long-range component: :math:`C_{\mathrm{LR}} (t, D)`. - -The short-range data class (:class:`caimira.models.ShortRangeModel`) models the short-range component of a close-range interaction **concentration** and the respective **dilution_factor**. -Its inputs are the **expiration** definition, the **activity type**, the **presence time**, and the **interpersonal distance** between any two individuals. -When generating a full model, the short-range class is defined with a new **Expiration** distribution, -given that the **min** and **max** diameters for the short-range interactions are different from those used in the long-range concentration (the idea is that very large particles should not be considered in the long-range case as they fall rapidly on the floor, -while they must be in for the short-range case). - -As mentioned in Jia, W. et al. [1]_, the jet concentration depends on the **long-range concentration** of viruses. -Here, once again, we shall normalize the short-range concentration to the diameter-independent quantities. -IMPORTANT NOTE: since the susceptible host is physically closer to the infector, the emitted particles are larger in size, -hence a new distribution of diameters should be taken into consideration. -As opposed to :math:`D_{\mathrm{max}} = 30\mathrm{μm}` for the long-range MC integration, the short-range model will assume a :math:`D_{\mathrm{max}} = 100\mathrm{μm}`. -Very similar to what we did with the **emission rate**, we need to calculate the scaling factor from the probability distribution, :math:`N_p(D)` - :math:`cn`, as well as the **volume concentration** for those diameters. - -During a given exposure time, multiple short-range interactions can be defined in the model. -In addition, for each individual interaction, the expiration type may be different. - -To calculate the short-range component, we first need to calculate what is the **dilution factor**, that depends on the distance :math:`x` as a random variable, from a log normal distribution in :meth:`caimira.monte_carlo.data.short_range_distances`. -This factor is calculated in a two-stage expiratory jet model, with its transition point defined as follows: - -:math:`\mathrm{xstar}=𝛽_{\mathrm{x1}} (Q_{\mathrm{exh}} \cdot u_{0})^\frac{1}{4} \cdot (\mathrm{tstar} + t_{0})^\frac{1}{2} - x_{0}`, - -where :math:`Q_{\mathrm{exh}}= φ \mathrm{BR}` is the expired flow rate during the expiration period, in :math:`m^{3} s^{-1}`, `φ` is the exhalation coefficient -(dimensionless) and represents the ratio between the total period of a breathing cycle and the duration of the exhalation alone. -Assuming the duration of the inhalation part is equal to the exhalation and one starts immediately after the other, `φ` will always be equal to `2` no matter what is the breating cycle time. :math:`\mathrm{BR}` is the given exhalation rate. -:math:`u_{0}` is the expired jet speed (in :math:`m s^{-1}`) given by :math:`u_{0}=\frac{Q_{\mathrm{exh}}}{A_{m}}`, :math:`A_{m}` being the area of the mouth assuming a perfect circle (average `mouth_diameter` of `0.02m`). -The time of the transition point :math:`\mathrm{tstar}` is defined as `2s` and corresponds to the end of the exhalation period, i.e. when the jet is interrupted. The distance of the virtual origin of the puff-like stage is defined by -:math:`x_{0}=\frac{\textrm{mouth_diameter}}{2𝛽_{\mathrm{r1}}}` (in m), and the corresponding time is given by :math:`t_{0} = \frac{\sqrt{\pi} \cdot \textrm{mouth_diameter}^3}{8𝛽_{\mathrm{r1}}^2𝛽_{\mathrm{x1}}^2Q_{exh}}` (in s). -Having the distance for the transition point, we can calculate the dilution factor at the transition point, defined as follows: - -:math:`\mathrm{Sxstar}=2𝛽_{\mathrm{r1}}\frac{(xstar + x_{0})}{\textrm{mouth_diameter}}`. - -The remaining dilution factors, either in the jet- or puff-like stages are calculated as follows: - -:math:`\mathrm{factors}(x)=\begin{cases}\hfil 2𝛽_{\mathrm{r1}}\frac{(x + x_{0})}{\textrm{mouth_diameter}} & \textrm{if } x < \mathrm{xstar},\\\hfil \mathrm{Sxstar} \cdot \biggl(1 + \frac{𝛽_{\mathrm{r2}}(x - xstar)}{𝛽_{\mathrm{r1}}(xstar + x_{0})}\biggl)^3 & \textrm{if } x > \mathrm{xstar}.\end{cases}` - -The penetration coefficients in the jet-like stage :math:`𝛽_{\mathrm{r1}}`, :math:`𝛽_{\mathrm{r2}}` and :math:`𝛽_{\mathrm{x1}}` are defined by the following empirical values `0.18`, `0.2`, and `2.4` respectively. The dilution factor for each distance :math:`x` is then stored in the :math:`\mathrm{factors}` array that is returned by the method. - -Having the dilution factors, the **initial concentration of virions at the mouth/nose**, :math:`C_{0, \mathrm{SR}}(D)`, is calculated as follows: - -:math:`C_{0, \mathrm{SR}}(D) = N_p(D) \cdot V_p(D) \cdot \mathrm{vl_{in}} \cdot 10^{-6}`, -given by :meth:`caimira.models.Expiration.jet_origin_concentration`. It computes the same quantity as :meth:`caimira.models.Expiration.aerosols`, except for the mask inclusion. As previously mentioned, it is normalized by the **viral load**, which is a diameter-independent property. -Note, the :math:`10^{-6}` factor corresponds to the conversion from :math:`\mathrm{μm}^{3} \cdot \mathrm{cm}^{-3}` to :math:`\mathrm{mL} \cdot m^{-3}`. - -Note that similarly to the `long-range` approach, the MC integral over the diameters is not calculated at this stage. - -For consistency, the long-range concentration parameter, :math:`C_{\mathrm{LR}, 100\mathrm{μm}}(t, D)` in the :class:`caimira.models.ShortRangeModel` class **only**, -shall also be normalized by the **viral load** and, since in the short-range model the diameter range is different than at long-range (as mentioned above), -we need to account for that difference. -The former operation is given in method :meth:`caimira.models.ShortRangeModel._long_range_normed_concentration`. For the diameter range difference, there are a few options: -one solution would be to recompute the values a second time using :math:`D_{\mathrm{max}} = 100\mathrm{μm}`; -or perform a approximation using linear interpolation, which is possible and more effective in terms of performance. We decided to adopt the interpolation solution. -The set of points with a known value are given by the default expiration particle diameters for long-range, i.e. from 0 to 30 :math:`\mathrm{μm}`. -The set of points we want the interpolated values are given by the short-range expiration particle diameters, i.e. from 0 to 100 :math:`\mathrm{μm}`. - -To summarize, in the code, :math:`C_{\mathrm{SR}}(t, D)` is computed as follows: - -* calculate the `dilution_factor` - :math:`S({x})` - in the method :meth:`caimira.models.ShortRangeModel.dilution_factor`, with the distance :math:`x` as a random variable (log normal distribution in :meth:`caimira.monte_carlo.data.short_range_distances`) -* compute :math:`\frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100\mathrm{μm}}(t, D))` in method :meth:`caimira.models.ShortRangeModel.normed_concentration`, -* multiply by the diameter-independent parameter, viral load, in method :meth:`caimira.models.ShortRangeModel.short_range_concentration` -* complete the equation of :math:`C_{\mathrm{SR}}(t, D)` by adding the long-range concentration from the :meth:`caimira.models._ConcentrationModelBase.concentration` (all integrated over :math:`D`), returning the final short-range concentration value for a given time and expiration activity. This is done at the level of the Exposure Model (:meth:`caimira.models.ExposureModel.concentration`). - -Note that :meth:`caimira.models.ShortRangeModel._normed_concentration` method is different from :meth:`caimira.models._ConcentrationModelBase._normed_concentration` and :meth:`caimira.models._ConcentrationModelBase.concentration` differs from :meth:`caimira.models.ExposureModel.concentration`. - -Unless one is computing the mean concentration values (e.g. for the plots in the report), the diameter-dependence is kept at this stage. Since other parameters downstream in the code are also diameter-dependent, the Monte-Carlo integration over the particle sizes is computed at the level of the dose :math:`\mathrm{vD^{total}}`. -In case one would like to have intermediate results for the initial short-range concentration, this is done at the :class:`caimira.models.ExposureModel` class level. - - -Dose - vD -========= - -The term `dose` refers to the number of viable virions (infectious virus) that will contribute to a potential infection. -It results in a combination of several properties: exposure, ratio of viable virions, inhalation rate, aerosol deposition in the respiratory tract and the effect of protective equipment such as masks. - -The receiving dose, which is inhaled by the exposed host, in infectious virions per unit diameter (diameter-dependence), -is calculated by first integrating the viral concentration profile (for a given particle diameter) over the exposure time and multiplying by scaling factors such as the proportion of virions which are infectious and the deposition fraction, -as well as the inhalation rate and the effect of masks: - -:math:`\mathrm{vD}(D) = \int_{t1}^{t2}C(t, D)\;\mathrm{d}t \cdot f_{\mathrm{inf}} \cdot \mathrm{BR}_{\mathrm{k}} \cdot f_{\mathrm{dep}}(D) \cdot (1-\eta_{\mathrm{in}})` . - -where :math:`C(t, D)` is the concentration value at a given time, which can be either the short- or long-range concentration, :math:`f_{\mathrm{inf}}` is the fraction of infectious virus, -:math:`f_{\mathrm{dep}}(D)` is the (diameter-dependent) deposition fraction in the respiratory tract, :math:`\mathrm{BR}_{\mathrm{k}}` is the inhalation rate and :math:`\eta_{\mathrm{in}}` is the inward efficiency of the face mask. - -Given that the calculation is diameter-dependent, to calculate the dose in the model, the code contains different methods that consider the parameters that are dependent on the aerosol size, :math:`D`. -The total dose, at the end of the exposure scenario, results from the sum of the dose accumulated over time, integrated over particle diameters: - -:math:`\mathrm{vD^{total}} = \int_0^{D_{\mathrm{max}}} \mathrm{vD}(D) \, \mathrm{d}D` . - -This calculation is computed using a Monte-Carlo integration over :math:`D`. As previously described, many different parameters samples are generated using the probability distribution from the :math:`N_p(D)` equation. -The dose for each of them is then computed, and their **average** value over all samples represents a good approximation of the total dose, provided that the number of samples is large enough. - -Long-range approach -******************* - -Regarding the concentration part of the long-range exposure (concentration integrated over time, :math:`\int_{t1}^{t2}C_{\mathrm{LR}}(t, D)\;\mathrm{d}t`), the respective method is :meth:`caimira.models.ExposureModel._long_range_normed_exposure_between_bounds`, -which uses the long-range exposure (concentration) between two bounds (time1 and time2), normalized by the emission rate of the infected population (per person infected), calculated from :meth:`caimira.models._ConcentrationModelBase.normed_integrated_concentration`. -The former method filters out the given bounds considering the breaks through the day (i.e. the time intervals during which there is no exposition to the virus) and retrieves the integrated long-range concentration of viruses in the air between any two times. - -After the calculations of the integrated concentration over the time, in order to calculate the final dose, we have to compute the remaining factors in the above equation. -Note that the **Monte-Carlo integration over the diameters is performed at this stage**, where all the diameter-dependent parameters are grouped together to calculate the final average (:code:`np.mean()`). - -Since, in the previous chapters, the quantities where normalised by the emission rate per person infected, one will need to re-incorporate it in the equations before performing the MC integrations over :math:`D`. -For that we need to split :math:`\mathrm{vR}(D)` (:meth:`caimira.models._PopulationWithVirus.emission_rate_per_person_when_present`) in diameter-dependent and diameter-independent quantities: - -:math:`\mathrm{vR}(D) = \mathrm{vR}(D-\mathrm{dependent}) \times \mathrm{vR}(D-\mathrm{independent})` - -with - -:math:`\mathrm{vR}(D-\mathrm{dependent}) = \mathrm{cn} \cdot V_p(D) \cdot (1 − \mathrm{η_{out}}(D))` - :meth:`caimira.models.InfectedPopulation.aerosols` - -:math:`\mathrm{vR}(D-\mathrm{independent}) = \mathrm{vl_{in}} \cdot \mathrm{BR_{k}}` - :meth:`caimira.models.InfectedPopulation.emission_rate_per_aerosol_per_person_when_present` - - -In other words, in the code the procedure is the following (all performed in :meth:`caimira.models.ExposureModel.long_range_deposited_exposure_between_bounds` method): - -* start re-incorporating the emission rate by first multiplying by the diameter-dependent quantities: :math:`\mathrm{vD_{aerosol}}(D) = (\int_{t1}^{t2}C_{\mathrm{LR}}(t, D)\;\mathrm{d}t \cdot \mathrm{vR}(D-\mathrm{dependent}) \cdot f_{\mathrm{dep}}(D))`, in :meth:`caimira.models.ExposureModel.long_range_deposited_exposure_between_bounds` method; - -* perform the **MC integration over the diameters**, which is considered equivalent as the mean of the distribution if the sample size is large enough: :math:`\mathrm{vD_{aerosol}} = \mathrm{np.mean}(\mathrm{vD_{aerosol}}(D))`; -* multiply the result with the remaining diameter-independent quantities of the emission rate used previously to normalize: :math:`\mathrm{vD_{emission-rate}} = \mathrm{vD_{aerosol}} \cdot \mathrm{vR}(D-\mathrm{independent})`; -* in order to complete the equation, multiply by the remaining diameter-independent variables in :math:`\mathrm{vD}` to obtain the total value: :math:`\mathrm{vD^{total}} = \mathrm{vD_{emission-rate}} \cdot \mathrm{BR}_{\mathrm{k}} \cdot (1-\eta_{\mathrm{in}}) \cdot f_{\mathrm{inf}}`; -* in the end, the dose is a vectorized float used in the probability of infection formula. - -**Note**: The aerosol volume concentration (*aerosols*) is introduced because the integrated concentration over the time was previously normalized by the emission rate (per person). -Here, to calculate the integral over the diameters we also need to consider the diameter-dependent variables that are on the emission rate, represented by the aerosol volume concentration which depends on the diameter and on the mask type: - -:math:`\mathrm{aerosols} = \mathrm{cn} \cdot V_p(D) \cdot (1 − \mathrm{η_{out}}(D))` . -The :math:`\mathrm{cn}` factor, which represents the total number of aerosols emitted, is introduced here as a scaling factor, as otherwise the Monte-Carlo integral would be normalized to 1 as the probability distribution. - -**Note**: for simplification of the notations, here the dose corresponding exclusively to the long-range contribution is written as :math:`\mathrm{vD_{LR}}(D)= \mathrm{vD}(D)`. - -In the end, the governing method is :meth:`caimira.models.ExposureModel.deposited_exposure_between_bounds`, in which the `deposited_exposure` is equal to `long_range_deposited_exposure_between_bounds` in the absence of short-range interactions. - -Short-range approach -******************** -In theory, the dose during a close-proximity interaction (`short-range`) is simply added to the dose inhaled due to the long-range and may be defined as follows: - -:math:`\mathrm{vD}(D)= \mathrm{vD^{LR}}(D) + \sum\limits_{i=1}^{n} \int_{t1}^{t2}C_{\mathrm{SR}}(t, D)\;\mathrm{d}t \cdot f_{\mathrm{inf}} \cdot \mathrm{BR}_{\mathrm{k}} \cdot f_{\mathrm{dep}}(D) \cdot (1-\eta_{\mathrm{in}})` , - -where :math:`\mathrm{vD_{LR}}(D)` is the long-range, diameter-dependent dose computed previously. - -From above, the short-range concentration: - -:math:`C_{\mathrm{SR}}(t, D) = C_{\mathrm{LR}, 100μm} (t, D) + \frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100μm}(t, D))` , - -In the code, the method that returns the value for the total dose (independently if it is short- or long-range) is given by :meth:`caimira.models.ExposureModel.deposited_exposure_between_bounds`. -For code simplification, we split the :math:`C_{\mathrm{SR}}(t, D)` equation into two components: - -* short-range component: :math:`\frac{1}{S({x})} \cdot (C_{0, \mathrm{SR}}(D) - C_{\mathrm{LR}, 100μm}(t, D))`; -* long-range component: :math:`C_{\mathrm{LR}} (t, D)`. - -Similarly as above, first we perform the multiplications by the diameter-dependent variables so that we can profit from the Monte-Carlo integration. Then we multiply the final value by the diameter-independent variables. -The method :meth:`caimira.models.ShortRangeModel._normed_jet_exposure_between_bounds` gets the integrated short-range concentration of viruses in the air between the times start and stop, normalized by the **viral load**, -and excluding the **jet dilution** since it is also diameter-independent. -This corresponds to :math:`C_{0, \mathrm{SR}}(D)`. - -The method :meth:`caimira.models.ShortRangeModel._normed_interpolated_longrange_exposure_between_bounds` retrieves the integrated short-range concentration due to the background concentration, -normalized by the **viral load** and the **breathing rate**, and excluding the jet **dilution**. -The result is then interpolated to the particle diameter range used in the short-range model (i.e. 100 μm). -This corresponds to :math:`\int_{t1}^{t2} C_{\mathrm{LR}, 100\mathrm{μm}} (t, D)\mathrm{d}t`. -Very similar to the long-range procedure, this method performs the integral of the concentration for the given time boundaries. - -Once we have the integral of the concentration normalized by the diameter-independent quantities, we multiply this result by the remaining diameter-dependent properties to perform the integral -over the particle diameters, including the **fraction deposited** computed with an evaporation factor of `1` (as the aerosols do not have time to evaporate during a short-range interaction). -This operation is performed with the MC intergration using the *mean*, which corresponds to: -:math:`\int_{0}^{D_{max}}C_{\mathrm{SR}}(t, D) \cdot f_{\mathrm{dep}}(D) \;\mathrm{d}D` . - -Note that in the code we perform the subtraction between the concentration at the jet origin and the `long-range` concentration of viruses in two steps when we calculate the dose, -since the contribution of the diameter-dependent variable :math:`f_{\mathrm{dep}}` has to be multiplied separately in substractions: - -`integral_over_diameters =` :math:`((C_{0, \mathrm{SR}} \cdot f_{\mathrm{dep}}) - (C_{\mathrm{LR}, 100μm} (t, D) \cdot f_{\mathrm{dep}})) \cdot \mathrm{mean()}` . - -Then, we add the contribution to the result of the diameter-**independent** vectorized properties **in two seperate phases**: - -* multiply by the diameter-independent properties that are dependent on the **activity type** of the different short-range interactions: **breathing rate** and **dilution factor** - within the *for* cycle; -* multiply by the other properties that are **not** dependent on the type of short-range interactions: **viral load**, **fraction of infectious virus** and **inwards mask efficiency**. - -The final operation in the :meth:`caimira.models.ExposureModel.deposited_exposure_between_bounds` accounts for the addition of the long-range component of the dose. - -If short-range interactions exist: the long-range component is added to the already calculated short-range component (`deposited_exposure`), hence completing :math:`C_{\mathrm{SR}}`. -If the are no short-range interactions: the short-range component (`deposited_exposure`) is zero, hence the result is equal solely to the long-range component :math:`C_{\mathrm{LR}}`. - - -CO\ :sub:`2` Concentration -===================================== - -The estimate of the concentration of CO\ :sub:`2` in a given room to indicate the air quality is given by the same approach as for the long-range virus concentration, -:math:`C_{\mathrm{LR}}(t, D)`, where :math:`C_0(D)` is considered to be the background (outdoor) CO\ :sub:`2` concentration (:meth:`caimira.models.CO2ConcentrationModel.CO2_atmosphere_concentration`). - -In order to compute the CO\ :sub:`2` concentration one should then simply use the :meth:`caimira.models.CO2ConcentrationModel.concentration` method. -A fraction of 4.2% of the exhalation rate of the defined activity was considered as supplied to the room (:meth:`caimira.models.CO2ConcentrationModel.CO2_fraction_exhaled`). - -Note still that nothing depends on the aerosol diameter :math:`D` in this case (no particles are involved) - hence in this class all parameters are constant w.r.t :math:`D`. - -Since the CO\ :sub:`2` concentration differs from the virus concentration, the specific removal rate, CO\ :sub:`2` atmospheric concentration and normalization factors are respectively defined in :meth:`caimira.models.CO2ConcentrationModel.removal_rate`, -:meth:`caimira.models.CO2ConcentrationModel.min_background_concentration` and :meth:`caimira.models.CO2ConcentrationModel.normalization_factor`. - -.. _caimira-uml-diagram: - -CAiMIRA UML Diagram -=================== - -The following diagram describes all the data classes and their relations under the `models.py` file. Click the diagram to zoom-in. - -.. figure:: ./UML-CAiMIRA.png - :scale: 20 % - :align: center - - CAiMIRA `models.py` file UML diagram. - -REFERENCES -========== - -.. [1] Jia, Wei, et al. "Exposure and respiratory infection risk via the short-range airborne route." Building and environment 219 (2022): 109166. `doi.org/10.1016/j.buildenv.2022.109166 `_ -.. [2] Henriques, Andre, et al. "Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces." Interface Focus 12.2 (2022): 20210076. `doi.org/10.1098/rsfs.2021.0076 `_ diff --git a/caimira/src/caimira/calculator/docs/index.rst b/caimira/src/caimira/calculator/docs/index.rst deleted file mode 100644 index a1fcc2f1..00000000 --- a/caimira/src/caimira/calculator/docs/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. CAiMIRA documentation master file, created by - sphinx-quickstart on Fri Apr 8 10:26:24 2022. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to CAiMIRA's documentation! -=================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - full_diameter_dependence - caimira - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/caimira/src/caimira/calculator/docs/requirements.txt b/caimira/src/caimira/calculator/docs/requirements.txt deleted file mode 100644 index b1b732ea..00000000 --- a/caimira/src/caimira/calculator/docs/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -sphinx==6.2.1 -sphinx-rtd-theme==1.2.2 -pillow==5.4.1 -mock==1.0.1 -commonmark==0.9.1 -recommonmark==0.5.0 diff --git a/cern_caimira/README.md b/cern_caimira/README.md new file mode 100644 index 00000000..b8857f87 --- /dev/null +++ b/cern_caimira/README.md @@ -0,0 +1,44 @@ +# CAiMIRA - CERN Airborne Model for Risk Assessment + +CAiMIRA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions. + +CAiMIRA models the concentration profile of potential virions in enclosed spaces , both as background (room) concentration and during close-proximity interactions, 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 airborne spread SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture and a two-stage exhaled jet model, and estimates the risk of COVID-19 infection therein. +The results DO NOT include the other known modes of SARS-CoV-2 transmission, such as fomite or blood-bound. +Hence, the output from this model is only valid when the other recommended public health & safety instructions are observed, such as 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 2022. +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, amount and nature of close-range interactions and +the size of the room, considering both long- and short-range airborne transmission modes 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. + +## Calculator + +The CAiMIRA Calculator can be accessed online [here](https://caimira.web.cern.ch/), provided you have CERN SSO (Single Sign-On) credentials. For local usage, please refer to the [documentation](#documentation) on how to install and run the calculator locally. + +## Documentation + +All instructions for installation, deployment, usage, and model assumptions and references can be found in the [official documentation](https://caimira.docs.cern.ch/). + +## Contributing + +Contributions are welcome on our [GitHub repository](https://github.com/CERN/CAiMIRA). + +## Authors & License + +Developed by CERN's HSE, Beams, and IT departments, in collaboration with WHO. + +© Copyright 2020-2021 CERN. All rights not expressly granted are reserved.
+Licensed under the Apache License, Version 2.0 + +See the full [license](caimira/LICENSE) for details. diff --git a/cern_caimira/pyproject.toml b/cern_caimira/pyproject.toml index 7c6ddc4e..ecb8c8da 100644 --- a/cern_caimira/pyproject.toml +++ b/cern_caimira/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "cern-caimira" -version = "4.17.4" +version = "4.17.5" description = "CAiMIRA - CERN Airborne Model for Indoor Risk Assessment" license = { text = "Apache-2.0" } authors = [ diff --git a/cern_caimira/src/cern_caimira/apps/calculator/__init__.py b/cern_caimira/src/cern_caimira/apps/calculator/__init__.py index 6afb4745..15d07bb3 100644 --- a/cern_caimira/src/cern_caimira/apps/calculator/__init__.py +++ b/cern_caimira/src/cern_caimira/apps/calculator/__init__.py @@ -135,6 +135,7 @@ def write_error(self, status_code: int, **kwargs) -> None: get_url = template.globals['get_url'], get_calculator_url = template.globals["get_calculator_url"], active_page='Error', + documentation_url = template.globals["documentation_url"], error_id=error_id, status_code=status_code, datetime=datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"), @@ -278,6 +279,7 @@ def get(self): template = template_environment.get_template( "index.html.j2") report = template.render( + documentation_url = template.globals["documentation_url"], user=self.current_user, get_url = template_environment.globals['get_url'], get_calculator_url = template_environment.globals['get_calculator_url'], @@ -458,12 +460,6 @@ def make_app( (get_root_calculator_url(r'/baseline-model/result'), StaticModel), (get_root_calculator_url(r'/api/arve/v1/(.*)/(.*)'), ArveData), # Generic Pages - (get_root_url(r'/about'), GenericExtraPage, { - 'active_page': 'about', - 'filename': 'about.html.j2'}), - (get_root_calculator_url(r'/user-guide'), GenericExtraPage, { - 'active_page': 'calculator/user-guide', - 'filename': 'userguide.html.j2'}), (get_root_url(r'/expert-app'), GenericExtraPage, { 'active_page': 'expert-app', 'filename': 'expert-app.html.j2'}), @@ -510,6 +506,7 @@ def make_app( ) template_environment.globals['get_url']=get_root_url template_environment.globals['get_calculator_url']=get_root_calculator_url + template_environment.globals['documentation_url']='https://caimira.docs.cern.ch' if debug: tornado.log.enable_pretty_logging() diff --git a/cern_caimira/src/cern_caimira/apps/templates/about.html.j2 b/cern_caimira/src/cern_caimira/apps/templates/about.html.j2 deleted file mode 100644 index c503c1bb..00000000 --- a/cern_caimira/src/cern_caimira/apps/templates/about.html.j2 +++ /dev/null @@ -1,77 +0,0 @@ -{% extends "layout.html.j2" %} - -{% block main %} - -
- -

Airborne Transmission of SARS-CoV-2


-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.
-For information on the Airborne Transmission of SARS-CoV-2, feel free to check out the special issue on the Interface Focus journal from Royal Society publishing: Interface Focus: Volume 12, Issue 2 and an CERN HSE Seminar: https://cds.cern.ch/record/2743403.
-

-

What is CAiMIRA?


-CAiMIRA stands for CERN Airborne Model for Indoor Risk Assessment, previously known as CARA - COVID Airborne Risk Assessment, 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. -Since then, the model has evolved and now is capable of simulating the short-range component. CAiMIRA comes with different applications that allow more or less flexibility in the input parameters: - - -The mathematical and physical model simulate the airborne spread of SARS-CoV-2 virus in a finite volume, assuming a homogenous mixture and a two-stage exhaled jet model, and estimates the risk of COVID-19 airborne transmission therein. The results DO NOT include 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 good hand hygiene and other barrier measures.
-

The methodology, mathematical equations and parameters of the model are published here in a peer-reviewed paper: Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces.

-

The short-range component of the model was adapted from Jia et al. (2022) Exposure and respiratory infection risk via the short-range airborne route .

- -The model used is based on scientific publications relating to airborne transmission of infectious diseases, virology, epidemiology and aerosol science. It can be used to compare the effectiveness of different airborne-related risk mitigation measures. - -The tool helps assess the potential dose of infectious airborne viruses in indoor gatherings, with people seated, standing, moving around, while breathing, speaking or shouting/singing. The model is based on the exponential dose-response of disease transmission, which assumes a fixed value for the average infectious dose. -The methodology of the model is divided into five parts: -
    -
  1. Estimating the emission rate of virions;
  2. -
  3. Estimating the removal rate of virions;
  4. -
  5. Modeling the concentration of virions within a given volume, as a function of time;
  6. -
  7. Absorbed dose of infectious viruses, inhaled during the exposure time;
  8. -
  9. Estimating the probability of a COVID-19 infection (or secondary transmission) and the expected number of new cases arising from the event
  10. -
-
-

What is the aim of CAiMIRA?


-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 CAiMIRA is to compare the relative impact of different measures and/or combination of measure. For example: -
    -
  • Compare keeping a window slightly open vs one or two windows open entirely
  • -
  • Compare opening one entire window every 2h for 10 min vs keeping half a window open all day
  • -
  • Compare the effect of an FFP2 with respect to a Type I surgical mask
  • -
  • Adapt the maximum occupancy considering the effect of HEPA filters
  • -
  • Etc…
  • -
- -
-

Collaboration with the World Health Organization (WHO)


-

The tool has attracted the attention of many international organisations, including the World Health Organization (WHO) and the United Nations Office at Geneva (UNOG). -In June 2021, CERN shared its own approach towards risk assessments for occupational hazards, which was at the time called CARA, to WHO's COVID Expert Panel.

-

As a result, WHO has invited CERN to become a member of a multidisciplinary expert group of international experts called ARIA, which will work to define a standardised algorithm to quantify airborne transmission risk in indoor settings. -This will ensure that the model inculdes not only the science related to aerosol science but also the virological effects, such as host-pathogen interaction.

- -The collaboration takes place within CERNs wide-ranging engagement with other international organisations, promoting shared solutions to societal challenges. -

- -

Main code developers:


-{{ text_blocks['Main Developers'] }} -
-

Other contributions from:


-{{ text_blocks['Code Contributors'] }} -
-

References:


-{{ text_blocks['References'] }} -
-

Acknowledgements:


-
- Click to expand -
- {{ text_blocks['Acknowledgements'] }} -
- -
-
-
- -{% endblock main %} diff --git a/cern_caimira/src/cern_caimira/apps/templates/base/calculator.form.html.j2 b/cern_caimira/src/cern_caimira/apps/templates/base/calculator.form.html.j2 index 8410844c..198a0574 100644 --- a/cern_caimira/src/cern_caimira/apps/templates/base/calculator.form.html.j2 +++ b/cern_caimira/src/cern_caimira/apps/templates/base/calculator.form.html.j2 @@ -774,60 +774,15 @@

- Quick Guide:
- This tool simulates the airborne spread SARS-CoV-2 virus in a finite volume and estimates the risk of COVID-19 infection. It is based on current scientific data and can be used to compare the effectiveness of different mitigation measures.
- Virus data:
- SARS-CoV-2 covers the original "wild type" strain of the virus and three variants of concern (VOC):
-
    -
  • Alpha (also known as B.1.1.7, first identified in UK, Sept 2020),
  • -
  • Beta (also known as B.1.351, first identified in South Africa, May 2020).
  • -
  • Gamma (also known as P.1, first identified in Brazil/Japan, Jan 2021).
  • -
  • Delta (also known as B.1.617.2, first identified in India, Oct 2020).
  • -
  • Omicron (also known as B.1.1.529, first identified in South Africa, November 2021).
  • -
- Modify the default as necessary, according to local area prevalence e.g. for Geneva - or Ain (France).
- Ventilation data:
-
    -
  • Mechanical ventilation = the HVAC supply of fresh air. Check the flow rates with the concerned technical department.
  • -
  • Natural ventilation = the type of window opening. The opening distance is between the fixed frame and movable part when open (commonly used values are window height of 1.6m and window opening between 0.15m and 0.6m). In case of periodic opening, specify the duration (e.g. 10 min) per hour.
  • -
  • HEPA filtration = the air flow of the device. The following values are based on the different fan velocities of a specific commercial device proposed by the HSE Unit:
  • -
      -
    • Level 6 (max) = 430 m3/h (noisy),
    • -
    • Level 5 = 250 m3/h (ok w.r.t. noise, recommended),
    • -
    • Level 4 = 130 m3/h (silent),
    • -
    • Level 3 = 95 m3/h (silent).
    • -
    -
- Activity types:
- The type of activity applies to both the infected and exposed persons: -
    -
  • Office = all seated, talking 33% of the time,
  • -
  • Small meeting (< 10 occ.) = all seated, talking time shared between all persons,
  • -
  • Large meeting (>= 10 occ.) = speaker is standing and speaking 33% of the time, other occupants are seated,
  • -
  • Call Centre = all seated, continuous talking,
  • -
  • Control Room (day shift) = all seated, talking 50% of the time,
  • -
  • Control Room (night shift) = all seated, talking 10% of the time,
  • -
  • Library = all seated, no talking, just breathing,
  • -
  • Laboratory = light physical activity, talking 50% of the time,
  • -
  • Workshop = moderate physical activity, talking 50% of the time,
  • -
  • Conference/Training (speaker infected) = speaker/trainer standing and talking, rest seated and talking quietly. - Speaker/Trainer assumed infected (worst case scenario),
  • -
  • Conference/Training (attendee infected) = someone in the audience is infected, all are seated and breathing.
  • -
  • Gym = heavy exercise, no talking, just breathing.
  • -
- Activity breaks:
-
    -
  • If coffee breaks are included, they are spread out evenly throughout the day, - in addition to any lunch break (if applicable).
  • -
- Refer to Calculator App user guide - for more detailed explanations on how to use this tool.
+ Quick Guide: Refer to Calculator App quick user guide. +
+ Full Guide: Refer to Calculator App full user guide. +

About

-
About page for details on methodology, assumptions and limitations of CAiMIRA.
+
About page for details on methodology, assumptions and limitations of CAiMIRA.

Documentation

-
Documentation for CAiMIRA, available here.
+
Documentation for CAiMIRA, available here.

Git

@@ -91,7 +91,7 @@ DOI
© Copyright 2020-2021 CERN. All rights not expressly granted are reserved.
Licensed under the Apache License, Version 2.0
- LICENSE + LICENSE

diff --git a/cern_caimira/src/cern_caimira/apps/templates/base/layout.html.j2 b/cern_caimira/src/cern_caimira/apps/templates/base/layout.html.j2 index 9e743f72..8415b92b 100644 --- a/cern_caimira/src/cern_caimira/apps/templates/base/layout.html.j2 +++ b/cern_caimira/src/cern_caimira/apps/templates/base/layout.html.j2 @@ -44,7 +44,7 @@ @@ -52,11 +52,11 @@ {% block covid_information%} {% endblock covid_information%} - + {% if user.is_authenticated() %}