cara/caimira/tests/models/test_concentration_model.py

276 lines
9.2 KiB
Python
Raw Normal View History

import re
import numpy as np
import numpy.testing as npt
import pytest
from dataclasses import dataclass
import typing
from caimira import models
@dataclass(frozen=True)
class KnownConcentrationModelBase(models._ConcentrationModelBase):
"""
A _ConcentrationModelBase class where all the class methods are
redefined with a value taken from new parameters. Useful for testing.
"""
known_population: models.Population
known_removal_rate: float
known_min_background_concentration: float
known_normalization_factor: float
@property
def population(self) -> models.Population:
return self.known_population
def removal_rate(self, time: float) -> float:
return self.known_removal_rate
def min_background_concentration(self) -> float:
return self.known_min_background_concentration
def normalization_factor(self) -> float:
return self.known_normalization_factor
@pytest.mark.parametrize(
"override_params", [
{'volume': np.array([100, 120])},
{'humidity': np.array([0.5, 0.4])},
{'air_change': np.array([100, 120])},
{'viral_load_in_sputum': np.array([5e8, 1e9])},
]
)
def test_concentration_model_vectorisation(override_params):
defaults = {
'volume': 75,
'humidity': 0.5,
'air_change': 100,
'viral_load_in_sputum': 1e9
}
defaults.update(override_params)
always = models.PeriodicInterval(240, 240) # TODO: This should be a thing on an interval.
c_model = models.ConcentrationModel(
models.Room(defaults['volume'], models.PiecewiseConstant((0., 24.), (293,)), defaults['humidity']),
models.AirChange(always, defaults['air_change']),
models.InfectedPopulation(
number=1,
presence=always,
mask=models.Mask(
factor_exhale=0.95,
η_inhale=0.3,
),
activity=models.Activity(
0.51,
0.75,
),
virus=models.SARSCoV2(
viral_load_in_sputum=defaults['viral_load_in_sputum'],
infectious_dose=50.,
viable_to_RNA_ratio = 0.5,
transmissibility_factor=1.0,
),
expiration=models._ExpirationBase.types['Breathing'],
host_immunity=0.,
),
evaporation_factor=0.3,
)
concentrations = c_model.concentration(10)
assert isinstance(concentrations, np.ndarray)
assert concentrations.shape == (2, )
2021-05-05 19:03:36 +00:00
@pytest.fixture
def simple_conc_model():
interesting_times = models.SpecificInterval(([0.5, 1.], [1.1, 2], [2., 3.]), )
2021-05-05 19:03:36 +00:00
return models.ConcentrationModel(
room = models.Room(75, models.PiecewiseConstant((0., 24.), (293,))),
ventilation = models.AirChange(interesting_times, 100),
infected = models.InfectedPopulation(
number=1,
2021-05-05 19:03:36 +00:00
presence=interesting_times,
mask=models.Mask.types['Type I'],
activity=models.Activity.types['Seated'],
virus=models.Virus.types['SARS_CoV_2'],
expiration=models.Expiration.types['Breathing'],
host_immunity=0.,
),
evaporation_factor=0.3,
)
2021-05-05 19:03:36 +00:00
@pytest.fixture
def dummy_population(simple_conc_model) -> models.Population:
return models.Population(
number=1,
presence=simple_conc_model.infected.presence,
mask=models.Mask.types['Type I'],
activity=models.Activity.types['Seated'],
host_immunity=0.,
)
@pytest.mark.parametrize(
"time, expected_last_state_change", [
[-15., 0.], # Out of range goes to the first state.
[0., 0.],
[0.5, 0.0],
[0.51, 0.5],
[1., 0.5],
[1.05, 1.],
[1.1, 1.],
[1.11, 1.1],
[2., 1.1],
[2.1, 2],
[3., 2],
[15., 3.], # Out of range goes to the last state.
]
)
def test_last_state_change_time(
simple_conc_model: models.ConcentrationModel,
time,
expected_last_state_change,
):
assert simple_conc_model.last_state_change(float(time)) == expected_last_state_change
2021-05-05 19:03:36 +00:00
@pytest.mark.parametrize(
"time, expected_next_state_change", [
[0.0, 0.0],
[0.5, 0.5],
2021-05-05 19:03:36 +00:00
[1, 1],
[1.05, 1.1],
2021-05-06 04:07:33 +00:00
[1.1, 1.1],
[1.11, 2],
2021-05-06 04:07:33 +00:00
[2, 2],
[2.1, 3],
2021-05-05 19:03:36 +00:00
[3, 3],
]
)
def test_next_state_change_time(
simple_conc_model: models.ConcentrationModel,
time,
expected_next_state_change,
):
assert simple_conc_model._next_state_change(float(time)) == expected_next_state_change
2021-05-05 19:03:36 +00:00
def test_next_state_change_time_out_of_range(simple_conc_model: models.ConcentrationModel):
with pytest.raises(
ValueError,
match=re.escape("The requested time (3.1) is greater than last available state change time (3.0)")
2021-05-05 19:03:36 +00:00
):
simple_conc_model._next_state_change(3.1)
def test_first_presence_time(simple_conc_model):
assert simple_conc_model._first_presence_time() == 0.5
def test_integrated_concentration(simple_conc_model):
c1 = simple_conc_model.integrated_concentration(0, 2)
c2 = simple_conc_model.integrated_concentration(0, 1)
c3 = simple_conc_model.integrated_concentration(1, 2)
assert c1 != 0
npt.assert_almost_equal(c1, c2 + c3, decimal=15)
# The expected numbers were obtained via the quad integration of the
# normed_integrated_concentration method with 0 (start) and 2 (stop) as limits.
@pytest.mark.parametrize([
"known_min_background_concentration",
"expected_normed_integrated_concentration"],
[
[0.0, 0.00018533333708996207],
[240.0, 48.000185340695275],
[440.0, 88.00018534069527],
[600., 120.00018534069527],
[1000., 200.0001853407918],
]
)
def test_normed_integrated_concentration_with_background_concentration(
simple_conc_model: models.ConcentrationModel,
dummy_population: models.Population,
known_min_background_concentration: float,
expected_normed_integrated_concentration: float):
known_conc_model = KnownConcentrationModelBase(
room = simple_conc_model.room,
ventilation = simple_conc_model.ventilation,
known_population = dummy_population,
known_removal_rate = 100.,
known_min_background_concentration = known_min_background_concentration,
known_normalization_factor = 10.)
npt.assert_almost_equal(known_conc_model.normed_integrated_concentration(0, 2), expected_normed_integrated_concentration)
# The expected numbers were obtained via the quad integration of the
# normed_integrated_concentration method with 0 (start) and 2 (stop) as limits.
@pytest.mark.parametrize([
"known_removal_rate",
"known_min_background_concentration",
"known_normalization_factor",
"expected_normed_integrated_concentration"],
[
[np.array([0.25, 10]), 0.0, 10., np.array([0.012161005755130391, 0.0017333437605308818])],
[100, np.array([0, 240.0]), 10., np.array([0.00018533333708996207, 48.000185340695275])],
[100, 440.0, np.array([10., 20.]), np.array([88.00018534069527, 44.000185340695275])],
[np.array([10, 100]), np.array([600., 800.]), 10., np.array([120.00173334473946, 160.0001853406953])],
[np.array([50, 100,]), np.array([1000.,1100.]), np.array([10., 20.]), np.array([200.00036800764332, 110.00018534069527])],
]
)
def test_normed_integrated_concentration_vectorisation(
simple_conc_model: models.ConcentrationModel,
dummy_population: models.Population,
known_removal_rate: float,
known_min_background_concentration: float,
known_normalization_factor: float,
expected_normed_integrated_concentration: float):
known_conc_model = KnownConcentrationModelBase(
room = simple_conc_model.room,
ventilation = simple_conc_model.ventilation,
known_population = dummy_population,
known_removal_rate = known_removal_rate,
known_min_background_concentration = known_min_background_concentration,
known_normalization_factor = known_normalization_factor)
integrated_concentration = known_conc_model.normed_integrated_concentration(0, 2)
assert isinstance(integrated_concentration, np.ndarray)
assert integrated_concentration.shape == (2, )
npt.assert_almost_equal(integrated_concentration, expected_normed_integrated_concentration)
@pytest.mark.parametrize([
"known_removal_rate",
"known_min_background_concentration",
"expected_concentration"],
[
[0., 240., 240.],
[0., np.array([240., 240.]), np.array([240., 240.])]
]
)
def test_zero_ventilation_rate(
simple_conc_model: models.ConcentrationModel,
dummy_population: models.Population,
known_removal_rate: float,
known_min_background_concentration: float,
expected_concentration: float):
known_conc_model = KnownConcentrationModelBase(
room = simple_conc_model.room,
ventilation = simple_conc_model.ventilation,
known_population = dummy_population,
known_removal_rate = known_removal_rate,
known_normalization_factor=1.,
known_min_background_concentration = known_min_background_concentration)
normed_concentration = known_conc_model.concentration(1)
npt.assert_almost_equal(normed_concentration, expected_concentration)