diff --git a/cara/apps/calculator/README.md b/cara/apps/calculator/README.md
index ebd0c04d..27f095f5 100644
--- a/cara/apps/calculator/README.md
+++ b/cara/apps/calculator/README.md
@@ -31,6 +31,20 @@ The simulation name has no bearing on the calculation.
A room number is included, if you do not wish to use a formal room number any reference will do - for example "57/2-004"
+### Virus Data
+
+Please choose the correct virus strain or any reported Variant of Concern (VOC) from the list.
+Changing this setting alters the properties of the virus which are used for the simulation.
+This has a significant effect on the probability of infection.
+The choices are:
+ * `SARS-CoV-2 (nominal strain)`, covering typical strains and varaints which are not of concern from an epidemiologic point of view of the virus;
+ * `SARS-CoV-2 (B.1.1.7)`, the VOC first identified in the UK at the end of 2020 which is found to be approximately 1.5x more transmissible compared to the non-VOCs;
+ * `SARS-CoV-2 (P.1)`, the VOC first identified in Brazil in January 2021 which is found to be approximately 2.25x more transmissible compared to the non-VOCs.
+
+The user can base their choice according to the prevalence of the different variants in the local area. Access to this information can be found here:
+ * Geneva: https://www.covid19.admin.ch/fr/epidemiologic/virus-variants?detGeo=GE
+ * Ain (France): https://www.santepubliquefrance.fr/dossiers/coronavirus-covid-19/covid-19-cartographie-des-variants-en-france-donnees-par-region-et-par-departement
+
### Room Data
Please enter either the room volume (in m³) or both the floor area (m²) and the room height (m).
diff --git a/cara/apps/calculator/model_generator.py b/cara/apps/calculator/model_generator.py
index 0bbacc69..42949fdb 100644
--- a/cara/apps/calculator/model_generator.py
+++ b/cara/apps/calculator/model_generator.py
@@ -49,6 +49,7 @@ class FormData:
simulation_name: str
total_people: int
ventilation_type: str
+ virus_type: str
volume_type: str
windows_duration: float
windows_frequency: float
@@ -130,6 +131,7 @@ class FormData:
('mask_type', MASK_TYPES),
('mask_wearing_option', MASK_WEARING_OPTIONS),
('ventilation_type', VENTILATION_TYPES),
+ ('virus_type', VIRUS_TYPES),
('volume_type', VOLUME_TYPES),
('window_opening_regime', WINDOWS_OPENING_REGIMES),
('window_type', WINDOWS_TYPES)]
@@ -204,8 +206,8 @@ class FormData:
return mask
def infected_population(self) -> models.InfectedPopulation:
- # Initializes the virus as SARS_Cov_2
- virus = models.Virus.types['SARS_CoV_2']
+ # Initializes the virus
+ virus = models.Virus.types[self.virus_type]
scenario_activity_and_expiration = {
'office': (
@@ -545,6 +547,7 @@ def baseline_raw_form_data():
'simulation_name': 'Test',
'total_people': '10',
'ventilation_type': 'natural_ventilation',
+ 'virus_type': 'SARS_CoV_2',
'volume_type': 'room_volume_explicit',
'windows_duration': '',
'windows_frequency': '',
@@ -561,6 +564,7 @@ MECHANICAL_VENTILATION_TYPES = {'mech_type_air_changes', 'mech_type_air_supply',
MASK_TYPES = {'Type I', 'FFP2'}
MASK_WEARING_OPTIONS = {'mask_on', 'mask_off'}
VENTILATION_TYPES = {'natural_ventilation', 'mechanical_ventilation', 'no_ventilation'}
+VIRUS_TYPES = {'SARS_CoV_2', 'SARS_CoV_2_B117', 'SARS_CoV_2_P1'}
VOLUME_TYPES = {'room_volume_explicit', 'room_volume_from_dimensions'}
WINDOWS_OPENING_REGIMES = {'windows_open_permanently', 'windows_open_periodically', 'not-applicable'}
WINDOWS_TYPES = {'window_sliding', 'window_hinged', 'not-applicable'}
diff --git a/cara/apps/calculator/templates/calculator.form.html.j2 b/cara/apps/calculator/templates/calculator.form.html.j2
index bbe85dbb..0b641e19 100644
--- a/cara/apps/calculator/templates/calculator.form.html.j2
+++ b/cara/apps/calculator/templates/calculator.form.html.j2
@@ -1,6 +1,6 @@
{% extends "layout.html.j2" %}
-{% set MODEL_VERSION="v1.4.1" %}
+{% set MODEL_VERSION="v1.5.0" %}
{% set DEBUG=False %}
{% set active_page="calculator/" %}
@@ -41,6 +41,19 @@
Simulation name:
Room number:
+
+ Virus data:
+
+ ?
+
+ Variant:
+
+
+
Room data:
?
@@ -257,35 +270,46 @@
Quick Guide:
This tool simulates the long range airborne spread SARS-CoV-2 virus in a finite volume and estimates the risk of COVID-19 infection. It is based on current scientific data and can be used to compare the effectiveness of different mitigation measures.
+ Virus data:
+ SARS-CoV-2 covers typical strains of the virus and two variants of concern (VOC):
+
+
B.1.1.7 (first identified in UK, Dec 2020),
+
P.1 (first identified in Brazil/Japan, Jan 2021).
+
+ Choose variant according to local area prevalence, e.g. for Geneva
+ or Ain (France). Ventilation data:
Mechanical ventilation = the HVAC supply of fresh air. Check the flow rates with the concerned technical department.
Natural ventilation = the type of window opening. The opening distance is between the fixed frame and movable part when open (commonly used values are window height of 1.6m and window opening between 0.15m and 0.6m). In case of periodic opening, specify the duration (e.g. for 10 min) and frequency (e.g. every 60 min).
HEPA filtration = the air flow of the device. The following values are based on the different fan velocities of a specific commercial device proposed by the HSE Unit:
Activity types:
The type of activity applies to both the infected and exposed persons:
-
Office = Typical office scenario with all persons seated, in conversation (talking 33% of the time, otherwise breathing normally).
-
Meeting = Typical meeting scenario with all persons seated, in conversation (talking time is shared equally between all persons).
-
Call Centre = A conservative assumption for office spaces, assumes all occupants are seated and talking continuously.
-
Library = assumes all occupants are seated, breathing and not talking.
-
Laboratory = Typical lab scenario with all persons doing light physical activity and talking 50% of the time.
-
Workshop = Typical mechanical assembly workshop or equipment installation scenario with all persons doing moderate activity and talking 50% of the time.
-
Training = Training course scenario. One person (Trainer) standing, talking, all others seated, talking quietly (whispering). It is assumed the Trainer is the infected person, for the worst case scenario.
-
Gym = Included for comparison purposes only, all persons are doing heavy exercise and breathing (no talking).
+
Office = all seated, talking 33% of the time,
+
Meeting = all seated, talking time shared between all persons,
+
Call Centre = all seated, continuous talking,
+
Library = all seated, no talking, just breathing,
+
Laboratory = light physical activity, talking 50% of the time,
+
Workshop = moderate physical activity, talking 50% of the time,
+
Training = trainer standing and talking, rest seated and talking quietly.
+ Trainer assumed infected (worst case scenario),
+
Gym = heavy exercise, no talking, just breathing.
Activity breaks:
-
If coffee breaks are included, they are spread out evenly throughout the day, in addition to any lunch break (if applicable).
+
If coffee breaks are included, they are spread out evenly throughout the day,
+ in addition to any lunch break (if applicable).
@@ -210,7 +219,7 @@ In this scenario, the estimated probability of one exposed occupant getting infe
See the footnotes for more details on the ALARA principles.
{% elif (prob_inf < 5) %}
This level of risk is within acceptable parameters, no further actions are required.
-{% endif %}
+{% endif %}
Exposure graph:
diff --git a/cara/apps/expert.py b/cara/apps/expert.py
index a1eefd76..31903b79 100644
--- a/cara/apps/expert.py
+++ b/cara/apps/expert.py
@@ -226,6 +226,7 @@ class ModelWidgets(View):
self.widget.children += (self._build_ventilation(node.concentration_model.ventilation),)
self.widget.children += (self._build_infected(node.concentration_model.infected),)
self.widget.children += (self._build_exposed(node),)
+ self.widget.children += (self._build_infectivity(node.concentration_model.infected),)
def _build_exposed(self, node):
return collapsible([widgets.HBox([
@@ -457,6 +458,27 @@ class ModelWidgets(View):
)
return w
+ def _build_infectivity(self,node):
+ return collapsible([widgets.HBox([
+ self._build_virus(node.virus),
+ ])], title="Virus variant")
+
+ def _build_virus(self, node):
+ virus = node.dcs_instance()
+ for name, virus_ in models.Virus.types.items():
+ if virus == virus_:
+ break
+ virus_choice = widgets.Select(options=list(models.Virus.types.keys()), value=name)
+
+ def on_virus_change(change):
+ node.dcs_select(change['new'])
+ virus_choice.observe(on_virus_change, names=['value'])
+
+ return widget_group(
+ [[widgets.Label("Virus"), virus_choice]]
+ )
+
+
def present(self):
return self.widget
@@ -499,6 +521,12 @@ class CARAStateBuilder(state.StateBuilder):
choices=models.Mask.types,
)
+ def build_type_Virus(self, _: dataclasses.Field):
+ return state.DataclassStatePredefined(
+ models.Virus,
+ choices=models.Virus.types,
+ )
+
def build_type__VentilationBase(self, _: dataclasses.Field):
s: state.DataclassStateNamed = state.DataclassStateNamed(
states={
diff --git a/cara/models.py b/cara/models.py
index c8f97d6c..4cd98365 100644
--- a/cara/models.py
+++ b/cara/models.py
@@ -384,12 +384,23 @@ class Virus:
Virus.types = {
'SARS_CoV_2': Virus(
halflife=1.1,
- viral_load_in_sputum=10e8,
+ viral_load_in_sputum=1e9,
# No data on coefficient for SARS-CoV-2 yet.
# It is somewhere between 0.001 and 0.01 to have a 50% chance
# to cause infection. i.e. 1000 or 100 SARS-CoV viruses to cause infection.
coefficient_of_infectivity=0.02,
),
+ 'SARS_CoV_2_B117': Virus(
+ # also called VOC-202012/01
+ halflife=1.1,
+ viral_load_in_sputum=1e9,
+ coefficient_of_infectivity=1/30.,
+ ),
+ 'SARS_CoV_2_P1': Virus(
+ halflife=1.1,
+ viral_load_in_sputum=1e9,
+ coefficient_of_infectivity=0.045,
+ ),
}