Merge branch 'feature/caimira_UI' into 'master'

CARA to CAiMIRA full migration

Closes #277

See merge request cara/cara!391
This commit is contained in:
Andre Henriques 2022-09-15 10:43:57 +02:00
commit 3b5c48344b
168 changed files with 1113 additions and 1116 deletions

View file

@ -1,4 +1,4 @@
# This module is part of CARA. Please see the repository at
# This module is part of CAiMIRA. Please see the repository at
# https://gitlab.cern.ch/cara/cara for details of the license and terms of use.
name: CI
@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
env:
PROJECT_ROOT: ./
PROJECT_NAME: cara
PROJECT_NAME: caimira
steps:
- name: Checkout
uses: actions/checkout@v2
@ -45,7 +45,7 @@ jobs:
runs-on: ubuntu-20.04
env:
PROJECT_ROOT: ./
PROJECT_NAME: cara
PROJECT_NAME: caimira
steps:
- name: Checkout
uses: actions/checkout@v2

6
.gitignore vendored
View file

@ -14,8 +14,8 @@ venv
support
# openshift config check folder
app-config/openshift/test-cara
app-config/openshift/cara-prod
app-config/openshift/caimira-test
app-config/openshift/caimira-prod
# documentation build folder
cara/docs/_build
caimira/docs/_build

View file

@ -11,24 +11,24 @@ include:
file: acc_py_devtools/templates/gitlab-ci/python.yml
variables:
project_name: cara
project_name: caimira
PY_VERSION: "3.9"
# ###################################################################################################
# Test code
# A full installation of CARA, tested with pytest.
# A full installation of CAiMIRA, tested with pytest.
test_install:
extends: .acc_py_full_test
# A development installation of CARA tested with pytest.
# A development installation of CAiMIRA tested with pytest.
test_dev:
extends: .acc_py_dev_test
# A development installation of CARA tested with pytest.
# A development installation of CAiMIRA tested with pytest.
test_dev-39:
variables:
PY_VERSION: "3.9"
@ -55,33 +55,41 @@ test_dev-39:
script:
- cd ./app-config/openshift
- oc login ${OC_SERVER} --token="${OC_TOKEN}"
- python ./config-fetch.py ${CARA_INSTANCE} --output-directory ./${CARA_INSTANCE}/actual
- python ./config-generate.py ${CARA_INSTANCE} --output-directory ./${CARA_INSTANCE}/expected
- python ./config-normalise.py ./${CARA_INSTANCE}/actual ./${CARA_INSTANCE}/actual-normed
- python ./config-normalise.py ./${CARA_INSTANCE}/expected ./${CARA_INSTANCE}/expected-normed
- diff -u ./${CARA_INSTANCE}/actual-normed/ ./${CARA_INSTANCE}/expected-normed/
- python ./config-fetch.py ${CAIMIRA_INSTANCE} --output-directory ./${CAIMIRA_INSTANCE}/actual
- python ./config-generate.py ${CAIMIRA_INSTANCE} --output-directory ./${CAIMIRA_INSTANCE}/expected
- python ./config-normalise.py ./${CAIMIRA_INSTANCE}/actual ./${CAIMIRA_INSTANCE}/actual-normed
- python ./config-normalise.py ./${CAIMIRA_INSTANCE}/expected ./${CAIMIRA_INSTANCE}/expected-normed
- diff -u ./${CAIMIRA_INSTANCE}/actual-normed/ ./${CAIMIRA_INSTANCE}/expected-normed/
artifacts:
paths:
- ./app-config/openshift/${CARA_INSTANCE}/actual
- ./app-config/openshift/${CARA_INSTANCE}/expected
- ./app-config/openshift/${CAIMIRA_INSTANCE}/actual
- ./app-config/openshift/${CAIMIRA_INSTANCE}/expected
check_openshift_config_test:
extends: .test_openshift_config
variables:
CARA_INSTANCE: 'test-cara'
BRANCH: 'live/test-cara'
CAIMIRA_INSTANCE: 'caimira-test'
BRANCH: 'live/caimira-test'
OC_SERVER: https://api.paas.okd.cern.ch
OC_TOKEN: "${OPENSHIFT_TEST_CONFIG_CHECKER_TOKEN}"
OC_TOKEN: "${OPENSHIFT_CAIMIRA_TEST_CONFIG_CHECKER_TOKEN}"
check_openshift_config_prod:
extends: .test_openshift_config
variables:
CARA_INSTANCE: 'cara-prod'
CAIMIRA_INSTANCE: 'caimira-prod'
BRANCH: 'master'
OC_SERVER: https://api.paas.okd.cern.ch
OC_TOKEN: "${OPENSHIFT_PROD_CONFIG_CHECKER_TOKEN}"
OC_TOKEN: "${OPENSHIFT_CAIMIRA_PROD_CONFIG_CHECKER_TOKEN}"
oci_calculator:
extends: .image_builder
variables:
IMAGE_NAME: calculator
DOCKERFILE_DIRECTORY: app-config/caimira-public-docker-image
DOCKER_CONTEXT_DIRECTORY: ""
# ###################################################################################################
@ -91,12 +99,12 @@ check_openshift_config_prod:
# Build and push images to the openshift instance, which automatically triggers an application re-deployment.
stage: docker-build
rules:
- if: '$CI_COMMIT_BRANCH == "live/test-cara"'
- if: '$CI_COMMIT_BRANCH == "live/caimira-test"'
variables:
IMAGE_TAG: test-cara-latest
IMAGE_TAG: caimira-test-latest
- if: '$CI_COMMIT_BRANCH == "master"'
variables:
IMAGE_TAG: cara-prod-latest
IMAGE_TAG: caimira-prod-latest
image:
# Based on guidance at https://gitlab.cern.ch/gitlabci-examples/build_docker_image.
name: gitlab-registry.cern.ch/ci-tools/docker-image-builder
@ -116,21 +124,12 @@ auth-service-image_builder:
DOCKER_CONTEXT_DIRECTORY: app-config/auth-service
cara-webservice-image_builder:
caimira-webservice-image_builder:
extends:
- .image_builder
variables:
IMAGE_NAME: cara-webservice
DOCKERFILE_DIRECTORY: app-config/cara-webservice
DOCKER_CONTEXT_DIRECTORY: ""
oci_calculator:
extends:
- .image_builder
variables:
IMAGE_NAME: calculator
DOCKERFILE_DIRECTORY: app-config/cara-public-docker-image
IMAGE_NAME: caimira-webservice
DOCKERFILE_DIRECTORY: app-config/caimira-webservice
DOCKER_CONTEXT_DIRECTORY: ""
@ -141,16 +140,16 @@ oci_calculator:
stage: oc-tag
image: gitlab-registry.cern.ch/paas-tools/openshift-client:latest
rules:
- if: '$CI_COMMIT_BRANCH == "live/test-cara"'
- if: '$CI_COMMIT_BRANCH == "live/caimira-test"'
variables:
OC_PROJECT: "test-cara"
OC_TOKEN: ${OPENSHIFT_TEST_DEPLOY_TOKEN}
IMAGE_TAG: test-cara-latest
OC_PROJECT: "caimira-test"
OC_TOKEN: ${OPENSHIFT_CAIMIRA_TEST_DEPLOY_TOKEN}
IMAGE_TAG: caimira-test-latest
- if: '$CI_COMMIT_BRANCH == "master"'
variables:
OC_PROJECT: "cara-prod"
OC_TOKEN: ${OPENSHIFT_PROD_DEPLOY_TOKEN}
IMAGE_TAG: cara-prod-latest
OC_PROJECT: "caimira-prod"
OC_TOKEN: ${OPENSHIFT_CAIMIRA_PROD_DEPLOY_TOKEN}
IMAGE_TAG: caimira-prod-latest
script:
- oc tag --source=docker ${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_NAME}:latest --token ${OC_TOKEN} --server=https://api.paas.okd.cern.ch -n ${OC_PROJECT}
@ -160,11 +159,11 @@ link_auth-service_with_gitlab_registry:
variables:
IMAGE_NAME: auth-service
link_cara-webservice_with_gitlab_registry:
link_caimira-webservice_with_gitlab_registry:
extends:
- .link_docker_images_with_gitlab_registry
variables:
IMAGE_NAME: cara-webservice
IMAGE_NAME: caimira-webservice
link_calculator_with_gitlab_registry:
extends:
@ -174,18 +173,18 @@ link_calculator_with_gitlab_registry:
# ###################################################################################################
# Trigger build of CARA router on OpenShift
# Trigger build of CAiMIRA router on OpenShift
trigger_cara-router_build_on_openshift:
trigger_caimira-router_build_on_openshift:
stage: deploy
rules:
- if: '$CI_COMMIT_BRANCH == "live/test-cara"'
- if: '$CI_COMMIT_BRANCH == "live/caimira-test"'
variables:
OC_PROJECT: "test-cara"
BUILD_WEBHOOK_SECRET: ${OPENSHIFT_TEST_BUILD_WEBHOOK_SECRET}
OC_PROJECT: "caimira-test"
BUILD_WEBHOOK_SECRET: ${OPENSHIFT_CAIMIRA_TEST_BUILD_WEBHOOK_SECRET}
- if: '$CI_COMMIT_BRANCH == "master"'
variables:
OC_PROJECT: "cara-prod"
BUILD_WEBHOOK_SECRET: ${OPENSHIFT_PROD_BUILD_WEBHOOK_SECRET}
OC_PROJECT: "caimira-prod"
BUILD_WEBHOOK_SECRET: ${OPENSHIFT_CAIMIRA_PROD_BUILD_WEBHOOK_SECRET}
script:
- curl -X POST -k https://api.paas.okd.cern.ch/apis/build.openshift.io/v1/namespaces/${OC_PROJECT}/buildconfigs/cara-router/webhooks/${BUILD_WEBHOOK_SECRET}/generic
- curl -X POST -k https://api.paas.okd.cern.ch/apis/build.openshift.io/v1/namespaces/${OC_PROJECT}/buildconfigs/caimira-router/webhooks/${BUILD_WEBHOOK_SECRET}/generic

View file

@ -17,7 +17,7 @@ build:
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: cara/docs/conf.py
configuration: caimira/docs/conf.py
# If using Sphinx, optionally build your docs in additional formats such as PDF
# formats:

104
README.md
View file

@ -1,8 +1,8 @@
# CARA - COVID Airborne Risk Assessment
# CAiMIRA - CERN Airborne Model for Risk Assessment
CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
CAiMIRA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
CARA models the concentration profile of potential virions in enclosed spaces , both as background (room) concentration and during close-proximity interations, with clear and intuitive graphs.
CAiMIRA models the concentration profile of potential virions in enclosed spaces , both as background (room) concentration and during close-proximity interations, 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.
@ -24,7 +24,7 @@ While the SARS-CoV-2 virus is in circulation among the population, the notion of
Each event modelled is unique, and the results generated therein are only as accurate as the inputs and assumptions.
## Authors
CARA was developed by following members of CERN - European Council for Nuclear Research (visit https://home.cern/):
CAiMIRA was developed by following members of CERN - European Council for Nuclear Research (visit https://home.cern/):
Andre Henriques<sup>1</sup>, Luis Aleixo<sup>1</sup>, Marco Andreini<sup>1</sup>, Gabriella Azzopardi<sup>2</sup>, James Devine<sup>3</sup>, Philip Elson<sup>4</sup>, Nicolas Mounet<sup>2</sup>, Markus Kongstein Rognlien<sup>2,6</sup>, Nicola Tarocco<sup>5</sup>
@ -37,15 +37,15 @@ Andre Henriques<sup>1</sup>, Luis Aleixo<sup>1</sup>, Marco Andreini<sup>1</sup>
### Reference and Citation
**For the use of the CARA web app**
**For the use of the CAiMIRA web app**
CARA COVID Airborne Risk Assessment tool
CAiMIRA CERN Airborne Model for Indoor Risk Assessment tool
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6520432.svg)](https://doi.org/10.5281/zenodo.6520432)
© Copyright 2020-2021 CERN. All rights not expressly granted are reserved.
**For use of the CARA model**
**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
@ -55,80 +55,80 @@ https://doi.org/10.1016/j.buildenv.2022.109166
## Applications
### COVID Calculator
### Calculator
A risk assessment tool which simulates the airborne spread of the SARS-CoV-2 virus for space managers.
### CARA Expert App
### CAiMIRA Expert App
A tool to interact with various parameters of the CARA model.
A tool to interact with various parameters of the CAiMIRA model.
## Disclaimer
CARA has not undergone review, approval or certification by competent authorities, and as a result, it cannot be considered as a fully endorsed and reliable tool, namely in the assessment of potential viral emissions from infected hosts to be modelled.
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 CARA locally
## Running CAiMIRA locally
The easiest way to run a version of CARA Calculator is to use docker. A pre-built
image of CARA is made available at https://gitlab.cern.ch/cara/cara/container_registry.
In order to run cara locally with docker, run the following:
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/cara/cara/container_registry.
In order to run CAiMIRA locally with docker, run the following:
$ docker run -it -p 8080:8080 gitlab-registry.cern.ch/cara/cara/calculator
This will start a local version of CARA, which can be visited at http://localhost:8080/.
This will start a local version of CAiMIRA, which can be visited at http://localhost:8080/.
## Development guide
CARA is also mirrored to Github if you wish to collaborate on development and can be found at: https://github.com/CERN/cara
CAiMIRA is also mirrored to Github if you wish to collaborate on development and can be found at: https://github.com/CERN/caimira
### Installing CARA in editable mode
### Installing CAiMIRA in editable mode
```
pip install -e . # At the root of the repository
```
### Running the COVID calculator app in development mode
### Running the Calculator app in development mode
```
python -m cara.apps.calculator
python -m caimira.apps.calculator
```
To run with the CERN theme:
```
python -m cara.apps.calculator --theme=cara/apps/templates/cern
python -m caimira.apps.calculator --theme=caimira/apps/templates/cern
```
To run the calculator on a different URL path:
```
python -m cara.apps.calculator --prefix=/mycalc
python -m caimira.apps.calculator --prefix=/mycalc
```
### How to compile and read the documentation
In order to generate the documentation, CARA must be installed first with the `doc` dependencies:
In order to generate the documentation, CAiMIRA must be installed first with the `doc` dependencies:
```
pip install -e .[doc]
```
To generate the HTML documentation page, the command `make html` should be executed in the `cara/docs` directory.
If any of the `.rst` files under the `cara/docs` folder is changed, this command should be executed again.
To generate the HTML documentation page, the command `make html` should be executed in the `caimira/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 `cara/docs/_build/html/index.html` and select `Open with` your preferred web browser.
Then, right click on `caimira/docs/_build/html/index.html` and select `Open with` your preferred web browser.
### Running the CARA Expert-App app in development mode
### Running the CAiMIRA Expert-App app in development mode
```
voila cara/apps/expert/cara.ipynb --port=8080
voila caimira/apps/expert/caimira.ipynb --port=8080
```
Then visit http://localhost:8080.
@ -138,7 +138,7 @@ Then visit http://localhost:8080.
```
pip install -e .[test]
pytest ./cara
pytest ./caimira
```
### Building the whole environment for local development
@ -146,12 +146,12 @@ pytest ./cara
**Simulate the docker build that takes place on openshift with:**
```
s2i build file://$(pwd) --copy --keep-symlinks --context-dir ./app-config/nginx/ centos/nginx-112-centos7 cara-nginx-app
docker build . -f ./app-config/cara-webservice/Dockerfile -t cara-webservice
s2i build file://$(pwd) --copy --keep-symlinks --context-dir ./app-config/nginx/ centos/nginx-112-centos7 caimira-nginx-app
docker build . -f ./app-config/caimira-webservice/Dockerfile -t caimira-webservice
docker build ./app-config/auth-service -t auth-service
```
Get the client secret from the CERN Application portal for the `cara-test` app. See [CERN-SSO-integration](#CERN-SSO-integration) for more info.
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
```
@ -161,7 +161,7 @@ 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=cara-test
export CLIENT_ID=caimira-test
export CLIENT_SECRET
```
@ -175,21 +175,21 @@ Then visit http://localhost:8080/.
### Setting up the application on openshift
The https://cern.ch/cara application is running on CERN's OpenShift platform. In order to set it up for the first time, we followed the documentation at https://cern.service-now.com/service-portal?id=kb_article&n=KB0004498. In particular we:
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://cern.service-now.com/service-portal?id=kb_article&n=KB0004498. In particular we:
* Added the OpenShift application deploy key to the GitLab repository
* Created a Python 3.6 (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 test-cara.web.cern.ch instance
### Updating the caimira-test.web.cern.ch instance
We have a replica of https://cara.web.cern.ch running on http://test-cara.web.cern.ch. Its purpose is to simulate what will happen when
a feature is merged. To push your changes to test-cara, simply push your branch to `live/test-cara` and the CI pipeline will trigger the
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/test-cara
git push --force upstream name-of-local-branch:live/caimira-test
## OpenShift templates
@ -205,7 +205,7 @@ $ oc login https://api.paas.okd.cern.ch
Then, switch to the project that you want to update:
```console
$ oc project cara-test
$ oc project caimira-test
```
Create a new service account in OpenShift to use GitLab container registry:
@ -221,17 +221,17 @@ $ 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_TEST_DEPLOY_TOKEN`: insert the token `<...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...>`.
Then, create the webhook secret to be able to trigger automatic builds from GitLab.
Create and store the secret. Copy the secret above and add it to the GitLab project under `CI /CD` -> `Variables` with the name `OPENSHIFT_TEST_WEBHOOK_SECRET`.
Create and store the secret. Copy the secret above and add it to the GitLab project under `CI /CD` -> `Variables` with the name `OPENSHIFT_CAIMIRA_TEST_WEBHOOK_SECRET`.
```console
$ WEBHOOKSECRET=$(openssl rand -hex 50)
$ oc create secret generic \
--from-literal="WebHookSecretKey=$WEBHOOKSECRET" \
gitlab-cara-webhook-secret
gitlab-caimira-webhook-secret
```
For CI usage, we also suggest creating a service account:
@ -256,8 +256,8 @@ $ cd app-config/openshift
$ oc process -f configmap.yaml | oc create -f -
$ oc process -f services.yaml | oc create -f -
$ oc process -f imagestreams.yaml | oc create -f -
$ oc process -f buildconfig.yaml --param GIT_BRANCH='live/test-cara' | oc create -f -
$ oc process -f deploymentconfig.yaml --param PROJECT_NAME='cara-test' | oc create -f -
$ oc process -f buildconfig.yaml --param GIT_BRANCH='live/caimira-test' | oc create -f -
$ oc process -f deploymentconfig.yaml --param PROJECT_NAME='caimira-test' | oc create -f -
```
### CERN SSO integration
@ -265,12 +265,12 @@ $ oc process -f deploymentconfig.yaml --param PROJECT_NAME='cara-test' | oc cre
The SSO integration uses OpenID credentials configured in [CERN Applications portal](https://application-portal.web.cern.ch/).
How to configure the application:
* Application Identifier: `cara-test`
* Homepage: `https://test-cara.web.cern.ch`
* Administrators: `cara-dev`
* Application Identifier: `caimira-test`
* Homepage: `https://caimira-test.web.cern.ch`
* Administrators: `caimira-dev`
* SSO Registration:
* Protocol: `OpenID (OIDC)`
* Redirect URI: `https://test-cara.web.cern.ch/auth/authorize`
* Redirect URI: `https://caimira-test.web.cern.ch/auth/authorize`
* Leave unchecked all the other checkboxes
* Define new roles:
* Name: `CERN Users`
@ -282,12 +282,12 @@ How to configure the application:
* Role Identifier: `admin`
* Leave unchecked checkboxes
* Minimum Level Of Assurance: `Any (no restrictions)`
* Assign role to groups: `cara-app-external-access` e-group
* 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 `cara-app-external-access` e-groups
* 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.
@ -318,8 +318,8 @@ $ cd app-config/openshift
$ oc process -f configmap.yaml | oc replace -f -
$ oc process -f services.yaml | oc replace -f -
$ oc process -f imagestreams.yaml | oc replace -f -
$ oc process -f buildconfig.yaml --param GIT_BRANCH='live/test-cara' | oc replace -f -
$ oc process -f deploymentconfig.yaml --param PROJECT_NAME='cara-test' | oc replace -f -
$ oc process -f buildconfig.yaml --param GIT_BRANCH='live/caimira-test' | oc replace -f -
$ oc process -f deploymentconfig.yaml --param PROJECT_NAME='caimira-test' | oc replace -f -
```
Be aware that if you create/recreate the environment you must manually create a **route** in OpenShift,

View file

@ -0,0 +1,21 @@
FROM registry.cern.ch/docker.io/library/python:3.9
# Copy just the requirements.txt initially, allowing Docker effectively to cache the build (good for dev).
COPY ./requirements.txt /tmp/requirements.txt
RUN python -m venv /opt/caimira/app
RUN sed '/\.\[/d' -i /tmp/requirements.txt && /opt/caimira/app/bin/pip install -r /tmp/requirements.txt
RUN apt-get update && apt-get install -y nginx
# Now that we have done the installation of the dependencies, copy the caimira source.
COPY ./ /opt/caimira/src
COPY ./app-config/caimira-public-docker-image/run_caimira.sh /opt/caimira/start.sh
# To ensure that we have installed the full requirements, re-run the pip install.
# In the best case this will be a no-op.
RUN cd /opt/caimira/src/ && /opt/caimira/app/bin/pip install -r /opt/caimira/src/requirements.txt
RUN /opt/caimira/app/bin/jupyter trust /opt/caimira/src/caimira/apps/expert/*.ipynb
COPY ./app-config/caimira-public-docker-image/nginx.conf /opt/caimira/nginx.conf
EXPOSE 8080
ENTRYPOINT ["/bin/sh", "-c", "/opt/caimira/start.sh"]

View file

@ -37,7 +37,7 @@ http {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
root /opt/cara/src;
root /opt/caimira/src;
# Load configuration files for the default server block.
include /opt/app-root/etc/nginx.default.d/*.conf;

View file

@ -1,16 +1,16 @@
echo 'CARA is running on http://localhost:8080'
echo 'CAiMIRA is running on http://localhost:8080'
echo 'Please see https://gitlab.cern.ch/cara/cara for terms of use.'
# Run a proxy for the apps (listening on 8080).
nginx -c /opt/cara/nginx.conf
nginx -c /opt/caimira/nginx.conf
# Run the expert app in the background.
cd /opt/cara/src/cara
/opt/cara/app/bin/python -m voila /opt/cara/src/cara/apps/expert/cara.ipynb \
cd /opt/caimira/src/caimira
/opt/caimira/app/bin/python -m voila /opt/caimira/src/caimira/apps/expert/caimira.ipynb \
--port=8082 --no-browser --base_url=/voila-server/ \
--Voila.tornado_settings 'allow_origin=*' \
>> /var/log/expert-app.log 2>&1 &
# Run the calculator in the foreground.
/opt/cara/app/bin/python -m cara.apps.calculator --port 8081 --no-debug
/opt/caimira/app/bin/python -m caimira.apps.calculator --port 8081 --no-debug

View file

@ -3,7 +3,7 @@ FROM registry.cern.ch/docker.io/condaforge/mambaforge as conda
RUN mamba create --yes -p /opt/app python=3.9
COPY . /opt/app-source
RUN cd /opt/app-source && conda run -p /opt/app python -m pip install -r ./requirements.txt .[app]
COPY app-config/cara-webservice/app.sh /opt/app/bin/cara-app.sh
COPY app-config/caimira-webservice/app.sh /opt/app/bin/caimira-app.sh
RUN cd /opt/app \
&& find -name '*.a' -delete \
&& rm -rf /opt/app/conda-meta \
@ -22,15 +22,15 @@ FROM registry.cern.ch/docker.io/library/debian
COPY --from=conda /opt/app /opt/app
ENV PATH=/opt/app/bin/:$PATH
# Make a convenient location to the installed CARA package (i.e. a directory called cara in the CWD).
# Make a convenient location to the installed CAiMIRA package (i.e. a directory called caimira in the CWD).
# It is important that this directory is also writable by a non-root user.
RUN mkdir -p /scratch \
&& chmod a+wx /scratch
# Set the HOME directory to something that anybody can write to (to support non root users, such as on openshift).
ENV HOME=/scratch
WORKDIR /scratch
RUN CARA_INIT_FILE=$(/opt/app/bin/python -c "import cara; print(cara.__file__)") \
&& ln -s $(dirname ${CARA_INIT_FILE}) /scratch/cara
RUN CAIMIRA_INIT_FILE=$(/opt/app/bin/python -c "import caimira; print(caimira.__file__)") \
&& ln -s $(dirname ${CAIMIRA_INIT_FILE}) /scratch/caimira
CMD [ \
"cara-app.sh" \
"caimira-app.sh" \
]

View file

@ -0,0 +1,26 @@
#!/bin/bash
if [[ "$APP_NAME" == "caimira-webservice" ]]; then
args=("$@")
if [ "$DEBUG" != "true" ] && [[ ! "${args[@]}" =~ "--no-debug" ]]; then
args+=("--no-debug")
fi
if [ ! -z "$CAIMIRA_THEME" ]; then
args+=("--theme=${CAIMIRA_THEME}")
fi
if [ ! -z "$CAIMIRA_CALCULATOR_PREFIX" ]; then
args+=("--prefix=${CAIMIRA_CALCULATOR_PREFIX}")
fi
echo "Starting the caimira webservice with: python -m caimira.apps.calculator ${args[@]}"
python -m caimira.apps.calculator "${args[@]}"
elif [[ "$APP_NAME" == "caimira-voila" ]]; then
echo "Starting the voila service"
voila caimira/apps/expert/ --port=8080 --no-browser --base_url=/voila-server/ --tornado_settings 'allow_origin=*'
else
echo "No APP_NAME specified"
exit 1
fi

View file

@ -1,21 +0,0 @@
FROM registry.cern.ch/docker.io/library/python:3.9
# Copy just the requirements.txt initially, allowing Docker effectively to cache the build (good for dev).
COPY ./requirements.txt /tmp/requirements.txt
RUN python -m venv /opt/cara/app
RUN sed '/\.\[/d' -i /tmp/requirements.txt && /opt/cara/app/bin/pip install -r /tmp/requirements.txt
RUN apt-get update && apt-get install -y nginx
# Now that we have done the installation of the dependencies, copy the cara source.
COPY ./ /opt/cara/src
COPY ./app-config/cara-public-docker-image/run_cara.sh /opt/cara/start.sh
# To ensure that we have installed the full requirements, re-run the pip install.
# In the best case this will be a no-op.
RUN cd /opt/cara/src/ && /opt/cara/app/bin/pip install -r /opt/cara/src/requirements.txt
RUN /opt/cara/app/bin/jupyter trust /opt/cara/src/cara/apps/expert/*.ipynb
COPY ./app-config/cara-public-docker-image/nginx.conf /opt/cara/nginx.conf
EXPOSE 8080
ENTRYPOINT ["/bin/sh", "-c", "/opt/cara/start.sh"]

View file

@ -1,26 +0,0 @@
#!/bin/bash
if [[ "$APP_NAME" == "cara-webservice" ]]; then
args=("$@")
if [ "$DEBUG" != "true" ] && [[ ! "${args[@]}" =~ "--no-debug" ]]; then
args+=("--no-debug")
fi
if [ ! -z "$CARA_THEME" ]; then
args+=("--theme=${CARA_THEME}")
fi
if [ ! -z "$CARA_CALCULATOR_PREFIX" ]; then
args+=("--prefix=${CARA_CALCULATOR_PREFIX}")
fi
echo "Starting the cara webservice with: python -m cara.apps.calculator ${args[@]}"
python -m cara.apps.calculator "${args[@]}"
elif [[ "$APP_NAME" == "cara-voila" ]]; then
echo "Starting the voila service"
voila cara/apps/expert/ --port=8080 --no-browser --base_url=/voila-server/ --tornado_settings 'allow_origin=*'
else
echo "No APP_NAME specified"
exit 1
fi

View file

@ -1,26 +1,26 @@
version: "3.8"
services:
cara-app:
image: cara-webservice
caimira-app:
image: caimira-webservice
environment:
- APP_NAME=cara-voila
- APP_NAME=caimira-voila
user: ${CURRENT_UID:?"Please run as follows 'CURRENT_UID=$(id -u):$(id -g) docker-compose up'"}
cara-webservice:
image: cara-webservice
caimira-webservice:
image: caimira-webservice
environment:
- COOKIE_SECRET
- APP_NAME=cara-webservice
- CARA_CALCULATOR_PREFIX=/calculator-cern
- CARA_THEME=cara/apps/templates/cern
- APP_NAME=caimira-webservice
- CAIMIRA_CALCULATOR_PREFIX=/calculator-cern
- CAIMIRA_THEME=caimira/apps/templates/cern
user: ${CURRENT_UID}
cara-calculator-open:
image: cara-webservice
caimira-calculator-open:
image: caimira-webservice
environment:
- COOKIE_SECRET
- APP_NAME=cara-webservice
- CARA_CALCULATOR_PREFIX=/calculator-open
- APP_NAME=caimira-webservice
- CAIMIRA_CALCULATOR_PREFIX=/calculator-open
user: ${CURRENT_UID}
auth-service:
@ -33,16 +33,16 @@ services:
- CLIENT_SECRET
user: ${CURRENT_UID}
cara-router:
image: cara-nginx-app
caimira-router:
image: caimira-nginx-app
ports:
- "8080:8080"
depends_on:
cara-webservice:
caimira-webservice:
condition: service_started
cara-calculator-open:
caimira-calculator-open:
condition: service_started
cara-app:
caimira-app:
condition: service_started
auth-service:
condition: service_started

View file

@ -70,7 +70,7 @@ http {
# Pass the request on to the webservice. Most likely the URI won't
# exist so we get a 404 from that service instead (good as the 404
# pages are consistent).
proxy_pass http://cara-webservice:8080/$request_uri;
proxy_pass http://caimira-webservice:8080/$request_uri;
}
location /voila-server/ {
@ -81,21 +81,21 @@ http {
error_page 401 = @error401;
error_page 404 = @proxy_404_error_handler;
# cara-app is the name of the voila server in each of docker-compose,
# test-cara.web.cern.ch and cara.web.cern.ch.
proxy_pass http://cara-app:8080/voila-server/;
# caimira-app is the name of the voila server in each of docker-compose,
# caimira-test.web.cern.ch and caimira.web.cern.ch.
proxy_pass http://caimira-app:8080/voila-server/;
}
rewrite ^/expert-app$ /voila-server/voila/render/cara.ipynb last;
rewrite ^/expert-app$ /voila-server/voila/render/caimira.ipynb last;
rewrite ^/(files/static)/(.*)$ /voila-server/voila/$1/$2 last;
# Before implementing the nginx router we could access /voila/render/cara.ipynb.
# Before implementing the nginx router we could access /voila/render/caimira.ipynb.
# Redirect this (and all other) URLs to the new scheme.
absolute_redirect off;
rewrite ^/voila/(.*)$ /voila-server/voila/$1 redirect;
location / {
# By default we have no authentication.
proxy_pass http://cara-webservice:8080;
proxy_pass http://caimira-webservice:8080;
}
location /calculator {
@ -107,14 +107,14 @@ http {
auth_request /auth/probe;
error_page 401 = @error401;
# cara-webservice is the name of the tornado server (for the calculator)
# in each of docker-compose, test-cara.web.cern.ch and cara.web.cern.ch.
proxy_pass http://cara-webservice:8080/calculator-cern;
# caimira-webservice is the name of the tornado server (for the calculator)
# in each of docker-compose, caimira-test.web.cern.ch and caimira.web.cern.ch.
proxy_pass http://caimira-webservice:8080/calculator-cern;
}
location /calculator-open {
# Public open calculator
proxy_pass http://cara-calculator-open:8080/calculator-open;
proxy_pass http://caimira-calculator-open:8080/calculator-open;
}
}
}

View file

@ -2,21 +2,21 @@
kind: "Template"
apiVersion: template.openshift.io/v1
metadata:
name: "cara-application"
name: "caimira-application"
creationTimestamp: null
annotations:
description: "CARA build config OpenShift template."
tags: "cara-application"
description: "CAiMIRA build config OpenShift template."
tags: "caimira-application"
labels:
template: "cara-application"
template: "caimira-application"
objects:
-
kind: BuildConfig
apiVersion: build.openshift.io/v1
metadata:
name: cara-router
name: caimira-router
labels:
template: "cara-application"
template: "caimira-application"
spec:
source:
type: Git
@ -24,15 +24,13 @@
ref: ${GIT_BRANCH}
uri: ${GIT_REPO}
contextDir: app-config/nginx
sourceSecret:
name: sshdeploykey
postCommit: {}
resources: {}
runPolicy: Serial
output:
to:
kind: ImageStreamTag
name: 'cara-router:latest'
name: 'caimira-router:latest'
strategy:
sourceStrategy:
from:
@ -46,13 +44,13 @@
- type: ConfigChange
- generic:
secretReference:
name: gitlab-cara-webhook-secret
name: gitlab-caimira-webhook-secret
type: Generic
nodeSelector: null
parameters:
- name: GIT_REPO
description: The GIT repo URL
value: 'ssh://git@gitlab.cern.ch:7999/cara/cara.git'
value: 'https://gitlab.cern.ch/cara/cara.git'
- name: GIT_BRANCH
description: The name of the GIT branch to use when building the app, e.g. `live/test-cara` in TEST, `master` in prod
description: The name of the GIT branch to use when building the app, e.g. `live/caimira-test` in TEST, `master` in prod
required: true

View file

@ -6,10 +6,10 @@ import typing
def configure_parser(parser: argparse.ArgumentParser) -> None:
parser.description = "Fetch the openshift config for CARA"
parser.description = "Fetch the openshift config for CAiMIRA"
parser.set_defaults(handler=handler)
parser.add_argument(
"instance", choices=['cara-prod', 'test-cara'],
"instance", choices=['caimira-prod', 'caimira-test'],
help="Pick the instance for which you want to fetch the config",
)
parser.add_argument(
@ -53,10 +53,10 @@ def fetch_config(output_directory: pathlib.Path):
def handler(args: argparse.ArgumentParser) -> None:
login_server = 'https://api.paas.okd.cern.ch:443'
if args.instance == 'cara-prod':
project_name = 'cara-prod'
elif args.instance == 'test-cara':
project_name = 'test-cara'
if args.instance == 'caimira-prod':
project_name = 'caimira-prod'
elif args.instance == 'caimira-test':
project_name = 'caimira-test'
actual_login_server = get_oc_server()
if actual_login_server != login_server:

View file

@ -8,7 +8,7 @@ def configure_parser(parser: argparse.ArgumentParser) -> None:
parser.description = "Generate the config files which can be later submitted to openshift"
parser.set_defaults(handler=handler)
parser.add_argument(
"instance", choices=['cara-prod', 'test-cara'],
"instance", choices=['caimira-prod', 'caimira-test'],
help="Pick the instance for which you want to generate the config",
)
parser.add_argument(
@ -38,14 +38,14 @@ def generate_config(output_directory: pathlib.Path, project_name: str, hostname:
def handler(args: argparse.ArgumentParser) -> None:
if args.instance == 'cara-prod':
project_name = 'cara-prod'
if args.instance == 'caimira-prod':
project_name = 'caimira-prod'
branch = 'master'
hostname = 'cara.web.cern.ch'
elif args.instance == 'test-cara':
project_name = 'test-cara'
branch = 'live/test-cara'
hostname = 'test-cara.web.cern.ch'
hostname = 'caimira.web.cern.ch'
elif args.instance == 'caimira-test':
project_name = 'caimira-test'
branch = 'live/caimira-test'
hostname = 'caimira-test.web.cern.ch'
generate_config(pathlib.Path(args.output_directory), project_name, hostname, branch)

View file

@ -2,12 +2,12 @@
kind: "Template"
apiVersion: template.openshift.io/v1
metadata:
name: "cara-configuration"
name: "caimira-configuration"
annotations:
description: "CARA configuration OpenShift template."
tags: "cara-configuration"
description: "CAiMIRA configuration OpenShift template."
tags: "caimira-configuration"
labels:
template: "cara-configuration"
template: "caimira-configuration"
objects:
-
apiVersion: v1

View file

@ -2,12 +2,12 @@
kind: "Template"
apiVersion: template.openshift.io/v1
metadata:
name: "cara-application"
name: "caimira-application"
annotations:
description: "CARA application OpenShift template."
tags: "cara-application"
description: "CAiMIRA application OpenShift template."
tags: "caimira-application"
labels:
template: "cara-application"
template: "caimira-application"
objects:
-
apiVersion: apps.openshift.io/v1
@ -72,21 +72,21 @@
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: cara-app
labels: {app: cara-app}
name: caimira-app
labels: {app: caimira-app}
spec:
replicas: 1
template:
metadata:
labels:
app: cara-app
app: caimira-app
spec:
containers:
- name: cara-webservice
- name: caimira-webservice
env:
- name: APP_NAME
value: cara-voila
image: '${PROJECT_NAME}/cara-webservice'
value: caimira-voila
image: '${PROJECT_NAME}/caimira-webservice'
ports:
- containerPort: 8080
protocol: TCP
@ -113,33 +113,33 @@
type: Rolling
test: false
selector:
app: cara-app
app: caimira-app
triggers:
- type: ConfigChange
- type: ImageChange
imageChangeParams:
automatic: true
containerNames:
- cara-webservice
- caimira-webservice
from:
kind: ImageStreamTag
name: 'cara-webservice:latest'
name: 'caimira-webservice:latest'
namespace: ${PROJECT_NAME}
-
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: cara-router
name: caimira-router
spec:
replicas: 1
template:
metadata:
labels:
app: cara-router
app: caimira-router
spec:
containers:
- name: cara-router
image: '${PROJECT_NAME}/cara-router'
- name: caimira-router
image: '${PROJECT_NAME}/caimira-router'
ports:
- containerPort: 8080
protocol: TCP
@ -166,35 +166,35 @@
type: Rolling
test: false
selector:
app: cara-router
app: caimira-router
triggers:
- type: ImageChange
imageChangeParams:
automatic: true
containerNames:
- cara-router
- caimira-router
from:
kind: ImageStreamTag
name: 'cara-router:latest'
name: 'caimira-router:latest'
namespace: ${PROJECT_NAME}
- type: ConfigChange
-
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: cara-webservice
name: caimira-webservice
labels:
image: cara-webservice
app: cara-webservice
image: caimira-webservice
app: caimira-webservice
spec:
replicas: 1
template:
metadata:
labels:
app: cara-webservice
app: caimira-webservice
spec:
containers:
- name: cara-webservice
- name: caimira-webservice
env:
- name: COOKIE_SECRET
valueFrom:
@ -204,12 +204,12 @@
- name: REPORT_PARALLELISM
value: '3'
- name: APP_NAME
value: cara-webservice
- name: CARA_CALCULATOR_PREFIX
value: caimira-webservice
- name: CAIMIRA_CALCULATOR_PREFIX
value: /calculator-cern
- name: CARA_THEME
value: cara/apps/templates/cern
image: '${PROJECT_NAME}/cara-webservice'
- name: CAIMIRA_THEME
value: caimira/apps/templates/cern
image: '${PROJECT_NAME}/caimira-webservice'
ports:
- containerPort: 8080
protocol: TCP
@ -250,41 +250,41 @@
type: Rolling
test: false
selector:
app: cara-webservice
app: caimira-webservice
triggers:
- type: ImageChange
imageChangeParams:
automatic: true
containerNames:
- cara-webservice
- caimira-webservice
from:
kind: ImageStreamTag
name: 'cara-webservice:latest'
name: 'caimira-webservice:latest'
namespace: ${PROJECT_NAME}
- type: ConfigChange
-
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: cara-calculator-open
name: caimira-calculator-open
labels:
image: cara-webservice
app: cara-calculator-open
image: caimira-webservice
app: caimira-calculator-open
spec:
replicas: 1
template:
metadata:
labels:
app: cara-calculator-open
app: caimira-calculator-open
spec:
containers:
- name: cara-calculator-open
- name: caimira-calculator-open
env:
- name: APP_NAME
value: cara-webservice
- name: CARA_CALCULATOR_PREFIX
value: caimira-webservice
- name: CAIMIRA_CALCULATOR_PREFIX
value: /calculator-open
image: '${PROJECT_NAME}/cara-webservice'
image: '${PROJECT_NAME}/caimira-webservice'
ports:
- containerPort: 8080
protocol: TCP
@ -315,21 +315,21 @@
type: Rolling
test: false
selector:
app: cara-calculator-open
app: caimira-calculator-open
triggers:
- type: ConfigChange
- type: ImageChange
imageChangeParams:
automatic: true
containerNames:
- cara-calculator-open
- caimira-calculator-open
from:
kind: ImageStreamTag
name: 'cara-webservice:latest'
name: 'caimira-webservice:latest'
namespace: ${PROJECT_NAME}
- type: ConfigChange
parameters:
- name: PROJECT_NAME
description: The name of this project, e.g. test-cara
description: The name of this project, e.g. caimira-test
required: true

View file

@ -2,13 +2,13 @@
kind: "Template"
apiVersion: template.openshift.io/v1
metadata:
name: "cara-imagestreams"
name: "caimira-imagestreams"
creationTimestamp: null
annotations:
description: "CARA imagestreams OpenShift template."
tags: "cara-imagestreams"
description: "CAiMIRA imagestreams OpenShift template."
tags: "caimira-imagestreams"
labels:
template: "cara-application"
template: "caimira-application"
objects:
-
kind: ImageStream
@ -22,7 +22,7 @@
kind: ImageStream
apiVersion: image.openshift.io/v1
metadata:
name: cara-router
name: caimira-router
spec:
lookupPolicy:
local: False
@ -30,7 +30,15 @@
kind: ImageStream
apiVersion: image.openshift.io/v1
metadata:
name: cara-webservice
name: caimira-webservice
spec:
lookupPolicy:
local: False
-
kind: ImageStream
apiVersion: image.openshift.io/v1
metadata:
name: calculator
spec:
lookupPolicy:
local: False

View file

@ -2,21 +2,21 @@
kind: "Template"
apiVersion: template.openshift.io/v1
metadata:
name: "cara-route"
name: "caimira-route"
creationTimestamp: null
annotations:
description: "CARA route OpenShift template."
tags: "cara-route"
description: "CAiMIRA route OpenShift template."
tags: "caimira-route"
labels:
template: "cara-route"
template: "caimira-route"
objects:
-
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: cara-route
name: caimira-route
labels:
app: "cara-route"
app: "caimira-route"
spec:
host: ${HOST}
port:
@ -26,12 +26,12 @@
termination: edge
to:
kind: Service
name: cara-router
name: caimira-router
weight: 100
wildcardPolicy: None
parameters:
- name: HOST
description: The hostname of the site, e.g. test-cara.web.cern.ch
description: The hostname of the site, e.g. caimira-test.web.cern.ch
required: true

View file

@ -2,13 +2,13 @@
kind: "Template"
apiVersion: template.openshift.io/v1
metadata:
name: "cara-services"
name: "caimira-services"
creationTimestamp: null
annotations:
description: "CARA services OpenShift template."
tags: "cara-services"
description: "CAiMIRA services OpenShift template."
tags: "caimira-services"
labels:
template: "cara-services"
template: "caimira-services"
objects:
-
apiVersion: v1
@ -32,8 +32,8 @@
kind: Service
metadata:
labels:
app: cara-app
name: cara-app
app: caimira-app
name: caimira-app
spec:
ports:
- name: 8080-tcp
@ -41,7 +41,7 @@
protocol: TCP
targetPort: 8080
selector:
deploymentconfig: cara-app
deploymentconfig: caimira-app
sessionAffinity: 'None'
type: 'ClusterIP'
-
@ -49,8 +49,8 @@
kind: Service
metadata:
labels:
app: cara-router
name: cara-router
app: caimira-router
name: caimira-router
spec:
ports:
- name: 8080-tcp
@ -58,7 +58,7 @@
protocol: TCP
targetPort: 8080
selector:
deploymentconfig: cara-router
deploymentconfig: caimira-router
sessionAffinity: 'None'
type: 'ClusterIP'
-
@ -66,8 +66,8 @@
kind: Service
metadata:
labels:
app: cara-webservice
name: cara-webservice
app: caimira-webservice
name: caimira-webservice
spec:
ports:
- name: 8080-tcp
@ -75,7 +75,7 @@
protocol: TCP
targetPort: 8080
selector:
deploymentconfig: cara-webservice
deploymentconfig: caimira-webservice
sessionAffinity: 'None'
type: 'ClusterIP'
-
@ -83,8 +83,8 @@
kind: Service
metadata:
labels:
app: cara-calculator-open
name: cara-calculator-open
app: caimira-calculator-open
name: caimira-calculator-open
spec:
ports:
- name: 8080-tcp
@ -92,6 +92,6 @@
protocol: TCP
targetPort: 8080
selector:
deploymentconfig: cara-calculator-open
deploymentconfig: caimira-calculator-open
sessionAffinity: 'None'
type: 'ClusterIP'

View file

@ -1,7 +1,7 @@
# This module is part of CARA. Please see the repository at
# This module is part of CAiMIRA. Please see the repository at
# https://gitlab.cern.ch/cara/cara for details of the license and terms of use.
"""
Documentation for the CARA package
Documentation for the CAiMIRA package
"""

View file

@ -1,4 +1,4 @@
# This module is part of CARA. Please see the repository at
# This module is part of CAiMIRA. Please see the repository at
# https://gitlab.cern.ch/cara/cara for details of the license and terms of use.
import asyncio
@ -31,7 +31,7 @@ from .user import AuthenticatedUser, AnonymousUser
# Effectively, if the model increases its MAJOR version then so too should this
# calculator version. If the calculator needs to make breaking changes (e.g. change
# form attributes) then it can also increase its MAJOR version without needing to
# increase the overall CARA version (found at ``cara.__version__``).
# increase the overall CAiMIRA version (found at ``caimira.__version__``).
__version__ = "4.2"
@ -40,7 +40,7 @@ class BaseRequestHandler(RequestHandler):
"""Called at the beginning of a request before `get`/`post`/etc."""
# Read the secure cookie which exists if we are in an authenticated
# context (though not if the cara webservice is running standalone).
# context (though not if the caimira webservice is running standalone).
session = json.loads(self.get_secure_cookie('session') or 'null')
if session:
@ -60,7 +60,7 @@ class BaseRequestHandler(RequestHandler):
contents = (
f'Unfortunately an error occurred when processing your request. '
f'Please let us know about this issue with as much detail as possible at '
f'<a href="mailto:CARA-dev@cern.ch">CARA-dev@cern.ch</a>, reporting status '
f'<a href="mailto:CAiMIRA-dev@cern.ch">CAiMIRA-dev@cern.ch</a>, reporting status '
f'code {status_code}, the error id of "{error_id}" and the time of the '
f'request ({datetime.datetime.utcnow()}).<br><br><br><br>'
)
@ -269,9 +269,9 @@ def make_app(
(calculator_prefix + r'/static/(.*)', StaticFileHandler, {'path': calculator_static_dir}),
]
cara_templates = Path(__file__).parent.parent / "templates"
caimira_templates = Path(__file__).parent.parent / "templates"
calculator_templates = Path(__file__).parent / "templates"
templates_directories = [cara_templates, calculator_templates]
templates_directories = [caimira_templates, calculator_templates]
if theme_dir:
templates_directories.insert(0, theme_dir)
loader = jinja2.FileSystemLoader([str(path) for path in templates_directories])

View file

@ -8,13 +8,13 @@ import json
import numpy as np
from cara import models
from cara import data
import cara.data.weather
import cara.monte_carlo as mc
from caimira import models
from caimira import data
import caimira.data.weather
import caimira.monte_carlo as mc
from .. import calculator
from cara.monte_carlo.data import activity_distributions, virus_distributions, mask_distributions, short_range_distances
from cara.monte_carlo.data import expiration_distribution, expiration_BLO_factors, expiration_distributions, short_range_expiration_distributions
from caimira.monte_carlo.data import activity_distributions, virus_distributions, mask_distributions, short_range_distances
from caimira.monte_carlo.data import expiration_distribution, expiration_BLO_factors, expiration_distributions, short_range_expiration_distributions
LOG = logging.getLogger(__name__)
@ -330,7 +330,7 @@ class FormData:
"""
month = MONTH_NAMES.index(self.event_month) + 1
timezone = cara.data.weather.timezone_at(
timezone = caimira.data.weather.timezone_at(
latitude=self.location_latitude, longitude=self.location_longitude,
)
# We choose the first of the month for the current year.
@ -351,7 +351,7 @@ class FormData:
month = MONTH_NAMES.index(self.event_month) + 1
wx_station = self.nearest_weather_station()
temp_profile = cara.data.weather.mean_hourly_temperatures(wx_station[0], month)
temp_profile = caimira.data.weather.mean_hourly_temperatures(wx_station[0], month)
_, utc_offset = self.tz_name_and_utc_offset()
@ -359,7 +359,7 @@ class FormData:
# result the first data value may no longer be a midnight, and the hours
# no longer ordered modulo 24).
source_times = np.arange(24) + utc_offset
times, temp_profile = cara.data.weather.refine_hourly_data(
times, temp_profile = caimira.data.weather.refine_hourly_data(
source_times,
temp_profile,
npts=24*10, # 10 steps per hour => 6 min steps
@ -418,9 +418,9 @@ class FormData:
else:
return models.MultipleVentilation((ventilation, infiltration_ventilation))
def nearest_weather_station(self) -> cara.data.weather.WxStationRecordType:
def nearest_weather_station(self) -> caimira.data.weather.WxStationRecordType:
"""Return the nearest weather station (which has valid data) for this form"""
return cara.data.weather.nearest_wx_station(
return caimira.data.weather.nearest_wx_station(
longitude=self.location_longitude, latitude=self.location_latitude
)

View file

@ -11,8 +11,8 @@ import zlib
import jinja2
import numpy as np
from cara import models
from cara.apps.calculator import markdown_tools
from caimira import models
from caimira.apps.calculator import markdown_tools
from ... import monte_carlo as mc
from .model_generator import FormData, _DEFAULT_MC_SAMPLE_SIZE
from ... import dataclass_utils

View file

@ -53,11 +53,6 @@ p.notes {
font-size: 13px;
}
#cara_logo {
height: 150px;
margin: 1%
}
#pdf_qrcode_aref {
margin-right: 1%;
width: 100pt;
@ -86,11 +81,7 @@ p.notes {
border-radius: 5px;
}
/* @media (width: 1200px) { */
@media print {
/* #body {
min-width: 1200px;
} */
#results,
#rules,
#data {

View file

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View file

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View file

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View file

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 115 KiB

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -11,7 +11,7 @@ import matplotlib.patches as patches
from matplotlib import pyplot as plt
import numpy as np
from cara import data, models, state
from caimira import data, models, state
def collapsible(widgets_to_collapse: typing.List, title: str, start_collapsed=False):
@ -850,7 +850,7 @@ baseline_model = models.ExposureModel(
)
class CARAStateBuilder(state.StateBuilder):
class CAIMIRAStateBuilder(state.StateBuilder):
# Note: The methods in this class must correspond to the *type* of the data classes.
# For example, build_type__VentilationBase is called when dealing with ConcentrationModel
# types as it has a ventilation: _VentilationBase field.
@ -928,7 +928,7 @@ class ExpertApplication(Controller):
def build_new_model(self) -> state.DataclassInstanceState[models.ExposureModel]:
default_model = state.DataclassInstanceState(
models.ExposureModel,
state_builder=CARAStateBuilder(),
state_builder=CAIMIRAStateBuilder(),
)
default_model.dcs_update_from(baseline_model)
# For the time-being, we have to initialise the select states. Careful

View file

@ -7,7 +7,7 @@
"<div style=\"text-align: center;\" align=\"center\" >\n",
"<img src=\"./files/static/images/header_image.png\" style=\"height:5em\"></img></div>\n",
"<p style=\"text-align: center;\">\n",
"Please see the <a href=\"https://cara.web.cern.ch/\">CARA homepage</a> for details on the methodology, assumptions and limitations of CARA.</p>"
"Please see the <a href=\"https://caimira.web.cern.ch/\">CAiMIRA homepage</a> for details on the methodology, assumptions and limitations of CAiMIRA.</p>"
]
},
{
@ -21,9 +21,9 @@
},
"outputs": [],
"source": [
"import cara.apps\n",
"import caimira.apps\n",
"\n",
"app = cara.apps.ExpertApplication()\n",
"app = caimira.apps.ExpertApplication()\n",
"app.widget"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View file

@ -81,7 +81,7 @@ body {
}
.logo {
height: 6em;
height: 4em;
}
.logo_form {
@ -92,7 +92,7 @@ body {
height: 10em;
}
.cara_home_image {
.caimira_home_image {
height: 18rem;
padding: 1rem;
border-radius: 1.25rem!important;
@ -258,11 +258,11 @@ footer img {
font-size:1rem;
font-weight:bold;
}
.cara_version {
.caimira_version {
float:left;
font-size:1rem;
}
.cara_home_image {
.caimira_home_image {
float: right;
}
@ -314,7 +314,7 @@ footer img {
font-size:.75rem;
font-weight:bold;
}
.cara_version {
.caimira_version {
float:left;
font-size:.75rem;
}

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

Before

Width:  |  Height:  |  Size: 954 KiB

After

Width:  |  Height:  |  Size: 954 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

View file

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 264 KiB

View file

@ -1,4 +1,4 @@
if (document.location.hostname == "test-cara.web.cern.ch") {
if (document.location.hostname == "caimira-test.web.cern.ch") {
var _paq = _paq || [];
if (typeof AuthUserDomain !== 'undefined') {
_paq.push(["setCustomVariable", 1, "AuthUserDomain", AuthUserDomain, "visit"]);
@ -18,7 +18,7 @@ if (document.location.hostname == "test-cara.web.cern.ch") {
g.src = u + "piwik.js";
s.parentNode.insertBefore(g, s);
})();
} else if (document.location.hostname == "cara.web.cern.ch") {
} else if (document.location.hostname == "caimira.web.cern.ch") {
var _paq = _paq || [];
if (typeof AuthUserDomain !== 'undefined') {
_paq.push(["setCustomVariable", 1, "AuthUserDomain", AuthUserDomain, "visit"]);

View file

@ -10,16 +10,16 @@ This pandemic clearly raised increased awareness on airborne transmission of res
Out of the main modes of viral transmission, the airborne route of SARS-CoV-2 seems to have a significant importance to the spread of COVID-19 infections world-wide, hence proper guidance to building engineers or facility managers, on how to prevent on-site transmission, is essential.<br>
For information on the Airborne Transmission of SARS-CoV-2, feel free to check out the special issue on the Interface Focus journal from Royal Society publishing: <a href=https://royalsocietypublishing.org/toc/rsfs/2022/12/2>Interface Focus: Volume 12, Issue 2</a> and an CERN HSE Seminar: <a href=https://cds.cern.ch/record/2743403>https://cds.cern.ch/record/2743403</a>.<br>
<br><br>
<h1 class="paragraph-title">What is CARA?</h1><br>
CARA stands for COVID Airborne Risk Assessment and was developed in the spring of 2020 to better understand and quantify the risk of long-range airborne spread of SARS-CoV-2 virus in workplaces.
Since then, the model has evolved and now is capable of simulating the short-range component. CARA comes with different applications that allow more or less flexibility in the input parameters:
<h1 class="paragraph-title">What is CAiMIRA?</h1><br>
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:
<ul>
<li><a href='{{ calculator_prefix }}'>CARA calculator app</a></li>
<li><a href='/expert-app'>CARA expert app</a></li>
<li><a href='{{ calculator_prefix }}'>CAiMIRA calculator app</a></li>
<li><a href='/expert-app'>CAiMIRA expert app</a></li>
</ul>
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.<br>
<p>The methodology, mathematical equations and parameters of the model are published here in the CARA paper: <a href="https://doi.org/10.1098/rsfs.2021.0076"> Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces</a>.</p>
<p>The methodology, mathematical equations and parameters of the model are published here in a peer-reviewed paper: <a href="https://doi.org/10.1098/rsfs.2021.0076"> Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces</a>.</p>
<p>The short-range component of the model was adapted from <i>Jia et al. (2022)</i> <a href="https://doi.org/10.1016/j.buildenv.2022.109166"> Exposure and respiratory infection risk via the short-range airborne route</a> .</p>
The model used is based on scientific publications relating to airborne transmission of infectious diseases, virology, epidemiology and aerosol science. It can be used to compare the effectiveness of different airborne-related risk mitigation measures.
@ -34,8 +34,8 @@ The methodology of the model is divided into five parts:
<li>Estimating the probability of a COVID-19 infection (or secondary transmission) and the expected number of new cases arising from the event </li>
</ol>
<br>
<h1 class="paragraph-title">What is the aim of CARA?</h1><br>
Although the user is able to calculate the infection probability of a stand-alone event with a pre-defined set of protection measures, the main utility of CARA is to compare the relative impact of different measures and/or combination of measure. For example:
<h1 class="paragraph-title">What is the aim of CAiMIRA?</h1><br>
Although the user is able to calculate the infection probability of a stand-alone event with a pre-defined set of protection measures, the main utility of CAiMIRA is to compare the relative impact of different measures and/or combination of measure. For example:
<ul>
<li>Compare keeping a window slightly open vs one or two windows open entirely</li>
<li>Compare opening one entire window every 2h for 10 min vs keeping half a window open all day</li>

View file

@ -18,13 +18,13 @@
{% block main %}
<span class="cara_version">v{{ calculator_version }}</span>
<span class="feedback">Please send feedback to <a href="mailto:CARA-dev@cern.ch">CARA-dev@cern.ch</a></span>
<span class="caimira_version">v{{ calculator_version }}</span>
<span class="feedback">Please send feedback to <a href="mailto:CAiMIRA-dev@cern.ch">CAiMIRA-dev@cern.ch</a></span>
<header class= "bg-light">
<div class="container container--padding">
<div class="d-flex header-height">
<h1 class="align-self-center">Calculator</h1>
<img src="/static/images/cara_logo.200x200.png" class="logo_form align-self-center ml-3">
<img src="/static/images/caimira_logo.200x200.png" class="logo_form align-self-center ml-3">
</div>
</div>
</header>
@ -625,7 +625,7 @@
<li>If coffee breaks are included, they are spread out evenly throughout the day,
in addition to any lunch break (if applicable).</li>
</ul>
Refer to <a href="{{ calculator_prefix }}/user-guide"> COVID Calculator App user guide </a>
Refer to <a href="{{ calculator_prefix }}/user-guide"> Calculator App user guide </a>
for more detailed explanations on how to use this tool. <br>
</div>

View file

@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0">
<title>Report | CARA (COVID Airborne Risk Assessment)</title>
<title>Report | CAiMIRA (CERN Airborne Model for Indoor Risk Assessment)</title>
<link rel="stylesheet" type="text/css" href="{{ calculator_prefix }}/static/css/report.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
@ -16,7 +16,7 @@
<body id="body">
<!-- MODEL REPR - Available in the developer tools once the report is generated. Useful to re-create the model using an interpreter that has CARA installed:
<!-- MODEL REPR - Available in the developer tools once the report is generated. Useful to re-create the model using an interpreter that has CAiMIRA installed:
{{ model_repr }}
@ -25,10 +25,10 @@
{% block report_header %}
<div id="report-header-div" class="d-flex flex-row" style="margin: 1%">
<a href="/" class="align-self-center"><img id="report_logo" src="/static/images/cara_logo.200x200.png" class="d-inline-block align-middle mr-3"></a>
<a href="/" class="align-self-center"><img id="report_logo" src="/static/images/caimira_logo.200x200.png" class="d-inline-block align-middle mr-3"></a>
<div style="margin-right: -105px" class='align-self-center mr-auto'>
<h2 class="header_text mb-0"><a href="{{ permalink.shortened }}" style="color: #2f4858">REPORT - {{ form.simulation_name }}</a></h2>
<p class="mb-0" id="report_version"> Created {{ creation_date }} using CARA calculator version v{{ form.calculator_version }}</p>
<p class="mb-0" id="report_version"> Created {{ creation_date }} using CAiMIRA calculator version v{{ form.calculator_version }}</p>
</div>
<!-- Export CVS Concentration Button and Print Report Button -->
<button type="button" class="btn btn-outline-dark align-self-center" id="export-csv" data-toggle="modal" data-target="#modalCSV">Export Data</button>

View file

@ -4,8 +4,8 @@
{% block main %}
<header class= "bg-light">
<div class="container container--padding">
<img src="/static/images/cara_full_text.png" class="logo d-block m-auto" id="desktop_logo">
<img src="/static/images/cara_full_logo.png" class="logo d-none m-auto" id="mobile_logo">
<img src="/static/images/caimira_full_text.png" class="logo d-block m-auto" id="desktop_logo">
<img src="/static/images/caimira_full_logo.png" class="logo d-none m-auto" id="mobile_logo">
</div>
</header>
@ -18,19 +18,19 @@
<h2 class="paragraph-title">Introduction</h2><br>
<div>
<p>
CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
CAiMIRA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
It does this by simulating the 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.
Please see the <a href="/about">About</a> page for more details on the methodology, assumptions and limitations of CARA.
Please see the <a href="/about">About</a> page for more details on the methodology, assumptions and limitations of CAiMIRA.
</p>
<p>
The full CARA source code can be accessed freely under an Apache 2.0 open source license from our <a href="https://gitlab.cern.ch/cara/cara">code repository</a>.
The full CAiMIRA source code can be accessed freely under an Apache 2.0 open source license from our <a href="https://gitlab.cern.ch/cara/cara">code repository</a>.
It includes detailed instructions on how to run your own version of this tool.
</p>
<br>
</div>
</div>
<div class="align-self-center">
<img src="static/images/CARA_1_Vs3_Colour.jpg" class="cara_home_image">
<img src="static/images/CAiMIRA_1_Vs3_Colour.jpg" class="caimira_home_image">
</div>
</div>
<br>
@ -46,14 +46,14 @@
<hr width="95%">
</div>
{% block cara_at_cern %}
{% endblock cara_at_cern %}
{% block caimira_at_cern %}
{% endblock caimira_at_cern %}
<br>
<div>
<h2 class="paragraph-title">Reference & Citation</h2><br>
<p>
<b>For use of the CARA model:</b><br>
<b>For use of the CAiMIRA model:</b><br>
<ul>
<li> 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.
@ -67,9 +67,9 @@
</li>
</ul>
</ul>
<b>For use of the CARA web app:</b><br>
<b>For use of the CAiMIRA web app:</b><br>
<ul>
<li>CARA COVID Airborne Risk Assessment tool</li>
<li>CAiMIRA CERN Airborne Model for Indoor Risk Assessment tool</li>
<a href="https://doi.org/10.5281/zenodo.6520432"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.6520432.svg" alt="DOI"></a><br>
© Copyright 2020-2021 CERN. All rights not expressly granted are reserved.<br>
Licensed under the Apache License, Version 2.0<br>

View file

@ -8,7 +8,7 @@
<title>
{% block title %}
CARA | COVID Airborne Risk Assessment
CAiMIRA | CERN Airborne Model for Indoor Risk Assessment
{% endblock title %}
</title>
@ -26,7 +26,7 @@
<nav class="navbar navbar-dark navbar-expand-lg">
<div class="container">
<a href="/" class="navbar-brand"><img src="/static/images/cara_logo_white_text.png" alt="Logo" title="Logo"></a>
<a href="/" class="navbar-brand"><img src="/static/images/caimira_logo_white_text.png" alt="Logo" title="Logo"></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
@ -41,14 +41,14 @@
Apps
</a>
<ul class="dropdown-menu dropwown-navbar-colors text-right" style="min-width: 12rem;" aria-labelledby="navbarDropdown">
<li><a href="{{ calculator_prefix }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">CARA Calculator</a></li>
<li><a href="{{ calculator_prefix }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">Calculator</a></li>
<li><a href="{{ calculator_prefix }}/user-guide" style="margin-left: 2rem" class="{{ "header-navbar nav-link active" if "user-guide" in active_page else "header-navbar nav-link" }}">User Guide</a></li>
<li><a href="/expert-app" class="{{ "header-navbar nav-link active" if "/expert-app" == active_page else "header-navbar nav-link" }}">Expert app (beta)</a></li>
</ul>
</li>
</div>
<div id="mobile_calculator_option">
<li class="nav-link"><a href="{{ calculator_prefix }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">CARA Calculator</a></li>
<li class="nav-link"><a href="{{ calculator_prefix }}" class="{{ "header-navbar nav-link active" if "calculator/" == active_page else "header-navbar nav-link" }}">Calculator</a></li>
<li class="nav-link"><a href="{{ calculator_prefix }}/user-guide" class="{{ "header-navbar nav-link active" if "user-guide" in active_page else "header-navbar nav-link" }}">User Guide</a></li>
</div>
{% block covid_information%}
@ -83,14 +83,14 @@
<div class="row text-light text-center py-4 justify-content-center">
<div class="col-sm-10 col-md-8 col-lg-6">
<img src="/static/images/cara_logo_white_text.png" alt="Logo">
<img src="/static/images/caimira_logo_white_text.png" alt="Logo">
<p><span style="font-size:10px;"><em>CERN strives to deploy its know-how and technologies to help solve
the challenges arising in the local and global fight against COVID-19. As a particle physics
research organisation, CERN is not in a position to advise on medical research, health or health
policy issues. Any initiative is conducted on a best effort and as-is basis, without liability or
warranty.</em></span></p>
<p style="font-size:10px;">
CARA is <a href="https://gitlab.cern.ch/cara/cara/-/blob/master/LICENSE" class="ext">Apache 2.0 licensed</a> open-source
CAiMIRA is <a href="https://gitlab.cern.ch/cara/cara/-/blob/master/LICENSE" class="ext">Apache 2.0 licensed</a> open-source
software developed at CERN.
You can find the source code at <a href="https://gitlab.cern.ch/cara/cara">https://gitlab.cern.ch/cara/cara</a>,
where we welcome contributions, feature requests and issue reports.

View file

@ -218,13 +218,13 @@ It is determined by:</p>
This allows for:</p>
<ul>
<li>sharing reports by either scanning or clicking on the QR code to obtain a shareable link.</li>
<li>easily regenerating reports with any new versions of the CARA model released in the future.</li>
<li>easily regenerating reports with any new versions of the CAiMIRA model released in the future.</li>
</ul>
<br>
<h1>Conclusion</h1>
<br>
<p>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 <a href="mailto:cara-dev@cern.ch">Send email</a>.</p>
<p>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 - <a href="mailto:caimira-dev@cern.ch">send email</a>.</p>
</div>
{% endblock main %}

View file

@ -166,7 +166,7 @@
<div class="collapse show" id="collapseRules">
<div class="card-body">
<p class="card-text">
Please ensure that this scenario conforms to current COVID-related <a href="https://hse.cern/covid-19-information"> Health & Safety requirements</a>, under the applicable COVID Scale and measures in force at the time of the CARA assessment.</strong> <br>
Please ensure that this scenario conforms to current COVID-related <a href="https://hse.cern/covid-19-information"> Health & Safety requirements</a>, under the applicable COVID Scale and measures in force at the time of the CAiMIRA assessment.</strong> <br>
The results of this simulation are colour coded according to the risk values authorized at CERN (approved in December 2020):
</p><br>
<div class="d-flex">
@ -204,7 +204,7 @@
{% block disclaimer %}
{{ super() }}
<p>
At CERN, CARA is intended for Members of Personnel with roles related to Supervision, Health & Safety or Space Management, in order to simulate the concerned workplaces on CERN sites.
At CERN, CAiMIRA is intended for Members of Personnel with roles related to Supervision, Health & Safety or Space Management, in order to simulate the concerned workplaces on CERN sites.
</p>
{% endblock disclaimer %}

View file

@ -0,0 +1,11 @@
{% extends "base/index.html.j2" %}
{% block caimira_at_cern %}
<h2 class="paragraph-title">CAiMIRA @ CERN</h2><br>
<div>
<p>
CAiMIRA has been developed by CERN with the intention of allowing members of personnel with roles related to supervision, health & safety or space management to simulate the concerned workplaces on CERN sites.
A hosted <a href="{{ calculator_prefix }}">CERN version of the CAiMIRA Calculator</a> is available on this site to members of the CERN personnel.
</p>
</div>
{% endblock caimira_at_cern %}

View file

@ -25,10 +25,10 @@ We wish to thank CERNs HSE Unit, Beams Department, Experimental Physics Depar
## Disclaimer
<p>
CARA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
CAiMIRA is a risk assessment tool developed to model the concentration of viruses in enclosed spaces, in order to inform space-management decisions.
</p>
<p>
CARA models the concentration profile of virions in enclosed spaces with clear and intuitive graphs.
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.
</p>
@ -54,10 +54,10 @@ We wish to thank CERNs HSE Unit, Beams Department, Experimental Physics Depar
Each event modelled is unique, and the results generated therein are only as accurate as the inputs and assumptions.
</p>
<p>
CARA has not undergone review, approval or certification by competent authorities, and as a result, it cannot be considered
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.
</p>
## References
Reference list can be found in the CARA paper: <a href="https://cds.cern.ch/record/2756083"> CERN-OPEN-2021-004</a>
Relevant literature references can be found in the paper: <a href="https://cds.cern.ch/record/2756083">Modelling airborne transmission of SARS-CoV-2 using CARA: risk assessment for enclosed spaces</a>.

View file

@ -1,6 +1,6 @@
import numpy as np
from cara import models
from cara.data.weather import wx_data, nearest_wx_station
from caimira import models
from caimira.data.weather import wx_data, nearest_wx_station
MONTH_NAMES = [
'January', 'February', 'March', 'April', 'May', 'June', 'July',

View file

Before

Width:  |  Height:  |  Size: 690 KiB

After

Width:  |  Height:  |  Size: 690 KiB

View file

@ -0,0 +1,45 @@
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:

View file

@ -1,5 +1,5 @@
cara.apps package
=================
caimira.apps package
====================
Subpackages
-----------
@ -7,15 +7,15 @@ Subpackages
.. toctree::
:maxdepth: 4
cara.apps.calculator
caimira.apps.calculator
Submodules
----------
cara.apps.expert module
-----------------------
caimira.apps.expert module
--------------------------
.. automodule:: cara.apps.expert
.. automodule:: caimira.apps.expert
:members:
:undoc-members:
:show-inheritance:
@ -23,7 +23,7 @@ cara.apps.expert module
Module contents
---------------
.. automodule:: cara.apps
.. automodule:: caimira.apps
:members:
:undoc-members:
:show-inheritance:

View file

@ -1,13 +1,13 @@
cara.data package
=================
caimira.data package
====================
Submodules
----------
cara.data.weather module
------------------------
caimira.data.weather module
---------------------------
.. automodule:: cara.data.weather
.. automodule:: caimira.data.weather
:members:
:undoc-members:
:show-inheritance:
@ -15,7 +15,7 @@ cara.data.weather module
Module contents
---------------
.. automodule:: cara.data
.. automodule:: caimira.data
:members:
:undoc-members:
:show-inheritance:

View file

@ -0,0 +1,37 @@
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:

56
caimira/docs/caimira.rst Normal file
View file

@ -0,0 +1,56 @@
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:

View file

@ -0,0 +1,53 @@
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:

View file

@ -0,0 +1,29 @@
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:

View file

@ -0,0 +1,21 @@
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:

View file

@ -0,0 +1,53 @@
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:

View file

@ -0,0 +1,135 @@
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:

View file

@ -17,7 +17,7 @@ sys.path.insert(0, os.path.abspath('..'))
# -- Project information -----------------------------------------------------
project = 'CARA'
project = 'CAiMIRA'
copyright = '2022, Andre Henriques et al.'
author = 'Andre Henriques et al.'

View file

@ -2,21 +2,21 @@
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<cara-uml-diagram>`, at the bottom of the document.
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<caimira-uml-diagram>`, at the bottom of the document.
Context
=======
The :mod:`cara.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:`cara.apps.calculator.report_generator` module is responsible to bind the results from the model calculations into the respective output variables presented in the CARA report.
The :mod:`cara.models` module itself implements the core CARA 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.
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 CARA variables are considered for a given aerosol diameter :math:`D`,
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 CARA results include the entire range of diameters, throughout the model,
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,
@ -26,25 +26,25 @@ provided the sample size is large enough. Example of the MC integration over the
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:`cara.models.InfectedPopulation.emission_rate_per_aerosol_when_present` method).
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_when_present` method).
Expiration
==========
The **Expiration** class (representing the expiration of aerosols by an infected person) has the `Particle` -- :attr:`cara.models.Expiration.particle` -- as one of its properties,
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:`cara.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.
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:`cara.monte_carlo.data.BLOmodel.distribution` method.
The aerosol diameter distributions are given by the :meth:`caimira.monte_carlo.data.BLOmodel.distribution` method.
The :class:`cara.monte_carlo.data.BLOmodel` class itself contains the method to return the mathematical values of the probability distribution for a given diameter (in microns),
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:`cara.monte_carlo.data.expiration_distribution`.
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:`cara.models.Expiration` class.
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:`cara.apps.calculator.model_generator`, when it comes to generate the Expiration model, the `diameter` property is sampled through the BLO :meth:`cara.monte_carlo.data.BLOmodel.distribution` method, while the value for the :math:`cn` is given by the :meth:`cara.monte_carlo.data.BLOmodel.integrate` method.
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)
@ -62,9 +62,9 @@ Note that :math:`D_{\mathrm{max}}` value will differ, depending on the type of e
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, which is the multiplication of the diameter-**independent** variables: :meth:`cara.models.InfectedPopulation.emission_rate_per_aerosol_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:`cara.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, which is the multiplication of the two previous methods, and corresponds to :math:`\mathrm{vR(D)}`: :meth:`cara.models._PopulationWithVirus.emission_rate_when_present`.
1. Calculate the non aerosol-dependent quantities in the emission rate, which is the multiplication of the diameter-**independent** variables: :meth:`caimira.models.InfectedPopulation.emission_rate_per_aerosol_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, which is the multiplication of the two previous methods, and corresponds to :math:`\mathrm{vR(D)}`: :meth:`caimira.models._PopulationWithVirus.emission_rate_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}`.
@ -84,26 +84,26 @@ The long-range concentration of virus-laden aerosols of a given size :math:`D`,
: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:`cara.models.ConcentrationModel.concentration` method.
The long-range concentration, integrated over the exposure time (in piecewise constant steps), :math:`C(D)`, is given by :meth:`cara.models.ConcentrationModel.integrated_concentration`.
and computed, as a function of the exposure time and particle diameter, in the :meth:`caimira.models.ConcentrationModel.concentration` method.
The long-range concentration, integrated over the exposure time (in piecewise constant steps), :math:`C(D)`, is given by :meth:`caimira.models.ConcentrationModel.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:`cara.models.ConcentrationModel.infectious_virus_removal_rate` - are both diameter-dependent.
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:`cara.models.ConcentrationModel._normed_concentration`: :math:`\mathrm{C_\mathrm{LR, normed}}(t, D)` that computes the concentration without including the emission rate.
* Concentration :meth:`cara.models.ConcentrationModel.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:`cara.models._PopulationWithVirus.emission_rate_when_present` method.
* Normalized concentration :meth:`caimira.models.ConcentrationModel._normed_concentration`: :math:`\mathrm{C_\mathrm{LR, normed}}(t, D)` that computes the concentration without including the emission rate.
* Concentration :meth:`caimira.models.ConcentrationModel.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_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:`cara.models.ExposureModel` class.
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:`cara.models.ConcentrationModel.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. Note that this method performs the integral between any two times of the previously mentioned :meth:`cara.models.ConcentrationModel._normed_concentration` method.
* :meth:`cara.models.ConcentrationModel.integrated_concentration`, :math:`C(D)`, that returns the same result as the previous one, but multiplied by the emission rate.
* :meth:`caimira.models.ConcentrationModel.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. Note that this method performs the integral between any two times of the previously mentioned :meth:`caimira.models.ConcentrationModel._normed_concentration` method.
* :meth:`caimira.models.ConcentrationModel.integrated_concentration`, :math:`C(D)`, that returns the same result as the previous one, but multiplied by the emission rate.
The integral over the exposure times is calculated directly in the class (integrated methods).
@ -115,15 +115,15 @@ The short-range concentration is the result of a two-stage exhaled jet model dev
: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:`cara.models.ConcentrationModel.concentration` method but **interpolated** to the diameter range used for close-proximity (from 0 to 100μm).
:math:`C_{\mathrm{LR}, 100μm}(t, D)` is the long-range concentration, calculated in :meth:`caimira.models.ConcentrationModel.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:`cara.models.ShortRangeModel`.
* 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:`cara.models.ShortRangeModel`) models the short-range component of a close-range interaction **concentration** and the respective **dilution_factor**.
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,
@ -143,15 +143,15 @@ To calculate the short-range component, we first need to calculate what is the *
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:`cara.models.Expiration.jet_origin_concentration`. It computes the same quantity as :meth:`cara.models.Expiration.aerosols`, except for the mask inclusion. As previously mentioned, it is normalized by the **viral load**, which is a diameter-independent property.
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:`cara.models.ShortRangeModel` class **only**,
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:`cara.models.ShortRangeModel._long_range_normed_concentration`. For the diameter range difference, there are a few options:
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}`.
@ -159,15 +159,15 @@ The set of points we want the interpolated values are given by the short-range e
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:`cara.models.ShortRangeModel.dilution_factor`, with the distance :math:`x` as a random variable (log normal distribution in :meth:`cara.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:`cara.models.ShortRangeModel.normed_concentration`,
* multiply by the diameter-independent parameter, viral load, in method :meth:`cara.models.ShortRangeModel.short_range_concentration`
* complete the equation of :math:`C_{\mathrm{SR}}(t, D)` by adding the long-range concentration from the :meth:`cara.models.ConcentrationModel.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:`cara.models.ExposureModel.concentration`).
* 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.ConcentrationModel.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:`cara.models.ShortRangeModel._normed_concentration` method is different from :meth:`cara.models.ConcentrationModel._normed_concentration` and :meth:`cara.models.ConcentrationModel.concentration` differs from :meth:`cara.models.ExposureModel.concentration`.
Note that :meth:`caimira.models.ShortRangeModel._normed_concentration` method is different from :meth:`caimira.models.ConcentrationModel._normed_concentration` and :meth:`caimira.models.ConcentrationModel.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:`cara.models.ExposureModel` class level.
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
@ -196,28 +196,28 @@ The dose for each of them is then computed, and their **average** value over all
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:`cara.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, calculated from :meth:`cara.models.ConcentrationModel.normed_integrated_concentration`.
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, calculated from :meth:`caimira.models.ConcentrationModel.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, 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:`cara.models._PopulationWithVirus.emission_rate_when_present`) in diameter-dependent and diameter-independent quantities:
For that we need to split :math:`\mathrm{vR}(D)` (:meth:`caimira.models._PopulationWithVirus.emission_rate_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:`cara.models.InfectedPopulation.aerosols`
: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:`cara.models.InfectedPopulation.emission_rate_per_aerosol_when_present`
:math:`\mathrm{vR}(D-\mathrm{independent}) = \mathrm{vl_{in}} \cdot \mathrm{BR_{k}}` - :meth:`caimira.models.InfectedPopulation.emission_rate_per_aerosol_when_present`
In other words, in the code the procedure is the following (all performed in :meth:`cara.models.ExposureModel.long_range_deposited_exposure_between_bounds` method):
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:`cara.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})`;
@ -232,7 +232,7 @@ The :math:`\mathrm{cn}` factor, which represents the total number of aerosols em
**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:`cara.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.
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
********************
@ -246,18 +246,18 @@ 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:`cara.models.ExposureModel.deposited_exposure_between_bounds`.
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:`cara.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**,
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:`cara.models.ShortRangeModel._normed_interpolated_longrange_exposure_between_bounds` retrieves the integrated short-range concentration due to the background concentration,
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`.
@ -278,24 +278,24 @@ Then, we add the contribution to the result of the diameter-**independent** vect
* 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:`cara.models.ExposureModel.deposited_exposure_between_bounds` accounts for the addition of the long-range component of the dose.
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}}`.
.. _cara-uml-diagram:
.. _caimira-uml-diagram:
CARA 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-CARA.png
.. figure:: ./UML-CAiMIRA.png
:scale: 20 %
:align: center
CARA `models.py` file UML diagram.
CAiMIRA `models.py` file UML diagram.
REFERENCES
==========

View file

@ -1,17 +1,17 @@
.. CARA documentation master file, created by
.. 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 CARA's documentation!
================================
Welcome to CAiMIRA's documentation!
===================================
.. toctree::
:maxdepth: 2
:caption: Contents:
full_diameter_dependence
cara
caimira
Indices and tables

Some files were not shown because too many files have changed in this diff Show more