From 3ea0d83e21c5dc3cd9f0d0fc8a119e726620500a Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Mon, 12 Sep 2022 17:24:09 +0200 Subject: [PATCH 1/4] Added cloth mask to backend --- caimira/apps/calculator/model_generator.py | 2 +- caimira/apps/templates/base/calculator.form.html.j2 | 7 +++++++ caimira/models.py | 12 ++++++++++++ caimira/monte_carlo/data.py | 5 +++-- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/caimira/apps/calculator/model_generator.py b/caimira/apps/calculator/model_generator.py index 49fb639a..4896e485 100644 --- a/caimira/apps/calculator/model_generator.py +++ b/caimira/apps/calculator/model_generator.py @@ -807,7 +807,7 @@ def baseline_raw_form_data() -> typing.Dict[str, typing.Union[str, float]]: ACTIVITY_TYPES = {'office', 'smallmeeting', 'largemeeting', 'training', 'training_attendee', 'callcentre', 'controlroom-day', 'controlroom-night', 'library', 'workshop', 'lab', 'gym'} MECHANICAL_VENTILATION_TYPES = {'mech_type_air_changes', 'mech_type_air_supply', 'not-applicable'} -MASK_TYPES = {'Type I', 'FFP2'} +MASK_TYPES = {'Type I', 'FFP2', 'Cloth'} MASK_WEARING_OPTIONS = {'mask_on', 'mask_off'} VENTILATION_TYPES = {'natural_ventilation', 'mechanical_ventilation', 'no_ventilation'} VIRUS_TYPES = {'SARS_CoV_2', 'SARS_CoV_2_ALPHA', 'SARS_CoV_2_BETA','SARS_CoV_2_GAMMA', 'SARS_CoV_2_DELTA', 'SARS_CoV_2_OMICRON'} diff --git a/caimira/apps/templates/base/calculator.form.html.j2 b/caimira/apps/templates/base/calculator.form.html.j2 index b1dc9534..4a73a9fb 100644 --- a/caimira/apps/templates/base/calculator.form.html.j2 +++ b/caimira/apps/templates/base/calculator.form.html.j2 @@ -295,6 +295,13 @@ +
+ + +

diff --git a/caimira/models.py b/caimira/models.py index 86808236..f23298f8 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -526,6 +526,9 @@ class Mask: #: Filtration efficiency of masks when inhaling. η_inhale: _VectorisedFloat + #: Filtration efficiency of masks when exhaling. + η_exhale: _VectorisedFloat = 0. + #: Global factor applied to filtration efficiency of masks when exhaling. factor_exhale: float = 1. @@ -541,6 +544,11 @@ class Mask: the leakage through the sides. Diameter is in microns. """ + if self.η_exhale is not 0.: + # For cloth mask we simply return its exhale efficiency distribution value. + # Ref: https://doi.org/10.1080/02786826.2021.1890687 + return self.η_exhale + d = np.array(diameter) intermediate_range1 = np.bitwise_and(0.5 <= d, d < 0.94614) intermediate_range2 = np.bitwise_and(0.94614 <= d, d < 3.) @@ -570,6 +578,10 @@ Mask.types = { 'FFP2': Mask( η_inhale=0.865, # (94% penetration efficiency + 8% max inward leakage -> EN 149) ), + 'Cloth': Mask( # https://doi.org/10.1080/02786826.2021.1890687 + η_inhale=0.35, + η_exhale=0.225, + ), } diff --git a/caimira/monte_carlo/data.py b/caimira/monte_carlo/data.py index 8ad2fcfc..c387dbb0 100644 --- a/caimira/monte_carlo/data.py +++ b/caimira/monte_carlo/data.py @@ -168,8 +168,9 @@ virus_distributions = { # https://doi.org/10.1016/j.jhin.2013.02.007 # https://doi.org/10.4209/aaqr.2020.08.0531 mask_distributions = { - 'Type I': mc.Mask(Uniform(0.25, 0.80)), - 'FFP2': mc.Mask(Uniform(0.83, 0.91)), + 'Type I': mc.Mask(η_inhale=Uniform(0.25, 0.80)), + 'FFP2': mc.Mask(η_inhale=Uniform(0.83, 0.91)), + 'Cloth': mc.Mask(η_inhale=Uniform(0.05, 0.40), η_exhale=Uniform(0.20, 0.50)), } From fa3190f6fb5065352c4bc174df0e4eba00e83cda Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Mon, 12 Sep 2022 17:24:41 +0200 Subject: [PATCH 2/4] added test for cloth mask and missing reference --- caimira/monte_carlo/data.py | 1 + caimira/tests/test_monte_carlo_full_models.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/caimira/monte_carlo/data.py b/caimira/monte_carlo/data.py index c387dbb0..e0eaa09a 100644 --- a/caimira/monte_carlo/data.py +++ b/caimira/monte_carlo/data.py @@ -167,6 +167,7 @@ virus_distributions = { # https://doi.org/10.1080/02786826.2021.1890687 # https://doi.org/10.1016/j.jhin.2013.02.007 # https://doi.org/10.4209/aaqr.2020.08.0531 +# https://doi.org/10.1080/02786826.2021.1890687 mask_distributions = { 'Type I': mc.Mask(η_inhale=Uniform(0.25, 0.80)), 'FFP2': mc.Mask(η_inhale=Uniform(0.83, 0.91)), diff --git a/caimira/tests/test_monte_carlo_full_models.py b/caimira/tests/test_monte_carlo_full_models.py index 0e333526..a62cbb9a 100644 --- a/caimira/tests/test_monte_carlo_full_models.py +++ b/caimira/tests/test_monte_carlo_full_models.py @@ -347,6 +347,8 @@ def test_report_models(mc_model, expected_pi, expected_new_cases, ["Type I", "Jul", 1.663, 0.938, 193.52], ["FFP2", "Jul", 0.523, 0.253, 193.52], ["Type I", "Feb", 0.659, 0.325, 193.52], + ["Cloth", "Feb", 2.665, 1.757, 809.46], + ["Cloth", "Jul", 5.322, 5.086, 798.47], ], ) def test_small_shared_office_Geneva(mask_type, month, expected_pi, From b1b0c07098bba8f8272f81bd5a6f1a9229b256f8 Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Tue, 13 Sep 2022 14:52:47 +0200 Subject: [PATCH 3/4] Added new icon for cloth mask --- caimira/apps/static/images/masks/cloth.png | Bin 0 -> 2189 bytes .../apps/templates/base/calculator.form.html.j2 | 2 +- .../apps/calculator/test_model_generator.py | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 caimira/apps/static/images/masks/cloth.png diff --git a/caimira/apps/static/images/masks/cloth.png b/caimira/apps/static/images/masks/cloth.png new file mode 100644 index 0000000000000000000000000000000000000000..40481b68dcb01794b3a8e6ef9ec8a4d57f8e1766 GIT binary patch literal 2189 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 P00000NkvXXu0mjf@R&MP literal 0 HcmV?d00001 diff --git a/caimira/apps/templates/base/calculator.form.html.j2 b/caimira/apps/templates/base/calculator.form.html.j2 index 4a73a9fb..665527f6 100644 --- a/caimira/apps/templates/base/calculator.form.html.j2 +++ b/caimira/apps/templates/base/calculator.form.html.j2 @@ -299,7 +299,7 @@ diff --git a/caimira/tests/apps/calculator/test_model_generator.py b/caimira/tests/apps/calculator/test_model_generator.py index 1dbb4961..787e7a8e 100644 --- a/caimira/tests/apps/calculator/test_model_generator.py +++ b/caimira/tests/apps/calculator/test_model_generator.py @@ -30,6 +30,7 @@ def test_model_from_dict_invalid(baseline_form_data): [ ["No mask"], ["Type I"], + ["Cloth"], ] ) def test_blend_expiration(mask_type): From beea8a800b8c84c387d233fe8924bd558412c8db Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Tue, 11 Oct 2022 10:39:21 +0200 Subject: [PATCH 4/4] updated inhalation and exhalation values --- caimira/models.py | 11 +++++------ caimira/tests/test_monte_carlo_full_models.py | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/caimira/models.py b/caimira/models.py index f23298f8..4a96be97 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -527,7 +527,7 @@ class Mask: η_inhale: _VectorisedFloat #: Filtration efficiency of masks when exhaling. - η_exhale: _VectorisedFloat = 0. + η_exhale: typing.Union[None, _VectorisedFloat] = None #: Global factor applied to filtration efficiency of masks when exhaling. factor_exhale: float = 1. @@ -544,9 +544,8 @@ class Mask: the leakage through the sides. Diameter is in microns. """ - if self.η_exhale is not 0.: - # For cloth mask we simply return its exhale efficiency distribution value. - # Ref: https://doi.org/10.1080/02786826.2021.1890687 + if self.η_exhale is not None: + # When η_exhale is specified, return it directly return self.η_exhale d = np.array(diameter) @@ -579,8 +578,8 @@ Mask.types = { η_inhale=0.865, # (94% penetration efficiency + 8% max inward leakage -> EN 149) ), 'Cloth': Mask( # https://doi.org/10.1080/02786826.2021.1890687 - η_inhale=0.35, - η_exhale=0.225, + η_inhale=0.225, + η_exhale=0.35, ), } diff --git a/caimira/tests/test_monte_carlo_full_models.py b/caimira/tests/test_monte_carlo_full_models.py index a62cbb9a..9ce540e0 100644 --- a/caimira/tests/test_monte_carlo_full_models.py +++ b/caimira/tests/test_monte_carlo_full_models.py @@ -347,8 +347,8 @@ def test_report_models(mc_model, expected_pi, expected_new_cases, ["Type I", "Jul", 1.663, 0.938, 193.52], ["FFP2", "Jul", 0.523, 0.253, 193.52], ["Type I", "Feb", 0.659, 0.325, 193.52], - ["Cloth", "Feb", 2.665, 1.757, 809.46], - ["Cloth", "Jul", 5.322, 5.086, 798.47], + ["Cloth", "Feb", 2.653, 1.741, 673.10], + ["Cloth", "Jul", 5.322, 5.064, 673.10], ], ) def test_small_shared_office_Geneva(mask_type, month, expected_pi,