From 8566657f81a58d702f0af1880b87472c77f7f1e3 Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Thu, 17 Feb 2022 16:27:20 +0100 Subject: [PATCH] Changed type of short range presence and added tests --- cara/models.py | 3 +- cara/tests/models/test_short_range_model.py | 78 +++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 cara/tests/models/test_short_range_model.py diff --git a/cara/models.py b/cara/models.py index db23fafb..444782b6 100644 --- a/cara/models.py +++ b/cara/models.py @@ -673,6 +673,7 @@ class Expiration(_ExpirationBase): return self.cn * (volume(self.diameter) * (1 - mask.exhale_efficiency(self.diameter))) * 1e-12 + @cached() def jet_origin_concentration(self): def volume(d): return (np.pi * d**3) / 6. @@ -1075,7 +1076,7 @@ class ConcentrationModel: @dataclass(frozen=True) class ShortRangeModel: #: Short range interactions - presence: typing.List[Interval] + presence: typing.List[SpecificInterval] #: Expiration type expirations: typing.List[Expiration] diff --git a/cara/tests/models/test_short_range_model.py b/cara/tests/models/test_short_range_model.py new file mode 100644 index 00000000..7626dce3 --- /dev/null +++ b/cara/tests/models/test_short_range_model.py @@ -0,0 +1,78 @@ +import typing +from unicodedata import decimal + +import numpy as np +import pytest + +from cara import models +from cara.models import ShortRangeModel +from cara.apps.calculator.model_generator import build_expiration +from cara.monte_carlo.data import dilution_factor, short_range_expiration_distributions + + +@pytest.fixture +def concentration_model(): + return models.ConcentrationModel( + room=models.Room(volume=75), + ventilation=models.AirChange( + active=models.SpecificInterval(present_times=((8.5, 12.5), (13.5, 17.5))), + air_exch=30., + ), + infected=models.InfectedPopulation( + number=1, + virus=models.Virus.types['SARS_CoV_2'], + presence=models.SpecificInterval(present_times=((8.5, 12.5), (13.5, 17.5))), + mask=models.Mask.types['No mask'], + activity=models.Activity.types['Light activity'], + expiration=build_expiration({'Speaking': 0.33, 'Breathing': 0.67}).build_model(250000), + host_immunity=0., + ), + evaporation_factor=0.3, + ) + + +activities = ['Breathing', 'Speaking', 'Shouting'] + + +@pytest.fixture +def presences(): + return [models.SpecificInterval((10.5, 11.0)), + models.SpecificInterval((14.5, 15.0)), + models.SpecificInterval((16.5, 17.5)),] + + +@pytest.fixture +def expirations(): + return [short_range_expiration_distributions[activity] for activity in activities] + + +@pytest.fixture +def dilutions(): + return dilution_factor(activities=activities, + distance=np.random.uniform(0.5, 1.5, 250000)) + + +def test_short_range_model_ndarray(concentration_model, presences, expirations, dilutions): + model = ShortRangeModel(presences, expirations, dilutions) + assert isinstance(model._normed_concentration(concentration_model, 10.75), np.ndarray) + assert isinstance(model.short_range_concentration(concentration_model, 14.75), np.ndarray) + assert isinstance(model.normed_exposure_between_bounds(concentration_model, 16.6, 17.7), np.ndarray) + + +@pytest.mark.parametrize( + "time, expected_sr_normed_concentration, expected_concentration", [ + [10.75, 1.1066751695e-07, 110.66751695458098], + [14.75, 3.451543659539623e-07, 345.15431668253206], + [16.75, 3.433877350917482e-07, 343.38772746180666], + ] +) +def test_short_range_model(time, expected_sr_normed_concentration, expected_concentration, + concentration_model, presences, expirations, dilutions): + + model = ShortRangeModel(presences, expirations, dilutions) + np.testing.assert_almost_equal( + model._normed_concentration(concentration_model, time).mean(), expected_sr_normed_concentration + ) + np.testing.assert_almost_equal( + model.short_range_concentration(concentration_model, time).mean(), expected_concentration, decimal=0 + ) \ No newline at end of file