From bf45490dfc6b2e6314a6fdc8713451df469e0deb Mon Sep 17 00:00:00 2001 From: Nicolas Mounet Date: Tue, 9 Mar 2021 08:38:47 +0000 Subject: [PATCH] Renaming variant into B117, and avoid calling it UK variant in forms and reports. Change its viral load back to std value, and increase infectivity to 1/30 --- cara/apps/calculator/README.md | 14 +++++ cara/apps/calculator/model_generator.py | 8 ++- .../templates/calculator.form.html.j2 | 54 +++++++++++++------ cara/apps/calculator/templates/report.html.j2 | 15 ++++-- cara/apps/expert.py | 28 ++++++++++ cara/models.py | 13 ++++- 6 files changed, 111 insertions(+), 21 deletions(-) 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):
+ + Choose variant according to local area prevalence, e.g. for Geneva + or Ain (France).
Ventilation data:
Activity types:
The type of activity applies to both the infected and exposed persons: Activity breaks:
- Refer to COVID Calculator App user guide for more detailed explanations on how to use this tool.
+ Refer to COVID Calculator App user guide + for more detailed explanations on how to use this tool.




diff --git a/cara/apps/calculator/templates/report.html.j2 b/cara/apps/calculator/templates/report.html.j2 index 8552cc31..4e9eabf8 100644 --- a/cara/apps/calculator/templates/report.html.j2 +++ b/cara/apps/calculator/templates/report.html.j2 @@ -20,7 +20,7 @@

Created {{ creation_date }} using model version {{ form.model_version }}


Applicable rules:
- Please ensure that this scenario conforms to current CERN HSE rules (minimum ventilation requirements, mask wearing and the maximum number of people permitted in a space).

+ Please ensure that this scenario conforms to current
CERN HSE rules (minimum ventilation requirements, mask wearing and the maximum number of people permitted in a space).
The results of this simulation are colour coded according to the risk values authorized at CERN (approved in December 2020):

-

Simulation:

+

Simulation:

Simulation Name: {{ form.simulation_name }}

Room Number: {{ form.room_number }}

Input data:

@@ -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, + ), }