diff --git a/caimira/docs/full_diameter_dependence.rst b/caimira/docs/full_diameter_dependence.rst index 90b10d96..9abb73c6 100644 --- a/caimira/docs/full_diameter_dependence.rst +++ b/caimira/docs/full_diameter_dependence.rst @@ -78,8 +78,8 @@ The estimate of the concentration of virus-laden particles in a given room is ba * **Box 2** - short-range exposure: also known as the *exhaled jet* concentration in close-proximity, corresponds to the exposure of airborne virions where the susceptible (exposed) host is distanced between 0.5 and 2 m from an infected host, considering the result of a two-stage exhaled jet model. Note that most of the methods used to calculate the concentration are defined in the superclass :meth:`caimira.models._ConcentrationModelBase`, while the specific methods for the long-range virus concentration are part of the subclass :meth:`caimira.models.ConcentrationModel`. -The specific removal rate, atmospheric concentration and normalization factors will depend on what concentration is being calculated (e.g. viral concentration or CO2 concentration) and are respectively defined in :meth:`caimira.models._ConcentrationModelBase.removal_rate`, -:meth:`caimira.models._ConcentrationModelBase.atmosphere_concentration` and :meth:`caimira.models._ConcentrationModelBase.normalization_factor`. +The specific removal rate, background concentration and normalization factors will depend on what concentration is being calculated (e.g. viral concentration or CO\ :sub:`2` concentration) and are respectively defined in :meth:`caimira.models._ConcentrationModelBase.removal_rate`, +:meth:`caimira.models._ConcentrationModelBase.background_concentration` and :meth:`caimira.models._ConcentrationModelBase.normalization_factor`. Long-range approach ******************* @@ -317,8 +317,8 @@ The estimate of the concentration of CO\ :sub:`2` in a given room to indicate th Note that in order to calculate the CO\ :sub:`2` concentration one should use the concentration method defined in the superclass - :meth:`caimira.models._ConcentrationModelBase.concentration` - for a dedicated :class:`caimira.models.CO2ConcentrationModel` scenario. A fraction of 4.2% of the exhalation rate of the defined activity was considered as the supplied to the room (:meth:`caimira.models.CO2ConcentrationModel.CO2_fraction_exhaled`). -Since the CO\ :sub:`2` concentration differs from the virus concentration, the specific removal rate, atmospheric concentration and normalization factors are respectively defined in :meth:`caimira.models.CO2ConcentrationModel.removal_rate`, -:meth:`caimira.models.CO2ConcentrationModel.atmosphere_concentration` and :meth:`caimira.models.CO2ConcentrationModel.normalization_factor`. +Since the CO\ :sub:`2` concentration differs from the virus concentration, the specific removal rate, CO\ :sub:`2` atmospheric concentration and normalization factors are respectively defined in :meth:`caimira.models.CO2ConcentrationModel.removal_rate`, +:meth:`caimira.models.CO2ConcentrationModel.background_concentration` and :meth:`caimira.models.CO2ConcentrationModel.normalization_factor`. .. _caimira-uml-diagram: diff --git a/caimira/models.py b/caimira/models.py index b6875d53..e869b7a3 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -957,6 +957,10 @@ class Cases: @dataclass(frozen=True) class _ConcentrationModelBase: + """ + A generic superclass that contains the methods to calculate the + concentration (e.g. viral concentration or CO2 concentration). + """ room: Room ventilation: _VentilationBase @@ -974,9 +978,9 @@ class _ConcentrationModelBase: """ raise NotImplementedError("Subclass must implement") - def atmosphere_concentration(self) -> _VectorisedFloat: + def background_concentration(self) -> _VectorisedFloat: """ - Background concentration in the atmosphere + Background concentration in the scenario (in the same unit as the concentration) """ return 0. @@ -1001,11 +1005,11 @@ class _ConcentrationModelBase: dependence has been solved for. """ if not self.population.person_present(time): - return self.atmosphere_concentration()/self.normalization_factor() + return self.background_concentration()/self.normalization_factor() V = self.room.volume RR = self.removal_rate(time) - return (1. / (RR * V) + self.atmosphere_concentration()/ + return (1. / (RR * V) + self.background_concentration()/ self.normalization_factor()) @method_cache @@ -1077,7 +1081,7 @@ class _ConcentrationModelBase: # The model always starts at t=0, but we avoid running concentration calculations # before the first presence as an optimisation. if time <= self._first_presence_time(): - return self.atmosphere_concentration()/self.normalization_factor() + return self.background_concentration()/self.normalization_factor() next_state_change_time = self._next_state_change(time) RR = self.removal_rate(next_state_change_time) conc_limit = self._normed_concentration_limit(next_state_change_time) @@ -1107,7 +1111,7 @@ class _ConcentrationModelBase: normalized by normalization_factor. """ if stop <= self._first_presence_time(): - return (stop - start)*self.atmosphere_concentration()/self.normalization_factor() + return (stop - start)*self.background_concentration()/self.normalization_factor() state_change_times = self.state_change_times() req_start, req_stop = start, stop total_normed_concentration = 0. @@ -1202,7 +1206,7 @@ class CO2ConcentrationModel(_ConcentrationModelBase): def removal_rate(self, time: float) -> _VectorisedFloat: return self.ventilation.air_exchange(self.room, time) - def atmosphere_concentration(self) -> _VectorisedFloat: + def background_concentration(self) -> _VectorisedFloat: """ Background CO2 concentration in the atmosphere (in ppm) """ diff --git a/caimira/tests/models/test_concentration_model.py b/caimira/tests/models/test_concentration_model.py index 0a22bca2..7f3d5052 100644 --- a/caimira/tests/models/test_concentration_model.py +++ b/caimira/tests/models/test_concentration_model.py @@ -10,7 +10,7 @@ from caimira import models @dataclass(frozen=True) class KnownConcentrationModelBase(models._ConcentrationModelBase): """ - A _ConcentrationModelBase where all the class methods are + A _ConcentrationModelBase class where all the class methods are redefined with a value taken from new parameters. Useful for testing. """ @@ -18,7 +18,7 @@ class KnownConcentrationModelBase(models._ConcentrationModelBase): known_removal_rate: float - known_atmosphere_concentration: float + known_background_concentration: float known_normalization_factor: float @@ -29,8 +29,8 @@ class KnownConcentrationModelBase(models._ConcentrationModelBase): def removal_rate(self, time: float) -> float: return self.known_removal_rate - def atmosphere_concentration(self) -> float: - return self.known_atmosphere_concentration + def background_concentration(self) -> float: + return self.known_background_concentration def normalization_factor(self) -> float: return self.known_normalization_factor @@ -180,7 +180,7 @@ def test_integrated_concentration(simple_conc_model): @pytest.mark.parametrize([ - "known_atmosphere_concentration", + "known_background_concentration", "expected_normed_integrated_concentration"], [ [0.0, 0.00018533333708996207], @@ -190,10 +190,10 @@ def test_integrated_concentration(simple_conc_model): [1000., 200.0001853407918], ] ) -def test_normed_integrated_concentration_with_atmosphere_concentration( +def test_normed_integrated_concentration_with_background_concentration( simple_conc_model: models.ConcentrationModel, dummy_population: models.Population, - known_atmosphere_concentration: float, + known_background_concentration: float, expected_normed_integrated_concentration: float): known_conc_model = KnownConcentrationModelBase( @@ -201,14 +201,14 @@ def test_normed_integrated_concentration_with_atmosphere_concentration( ventilation = simple_conc_model.ventilation, known_population = dummy_population, known_removal_rate = 100., - known_atmosphere_concentration = known_atmosphere_concentration, + known_background_concentration = known_background_concentration, known_normalization_factor = 10.) npt.assert_almost_equal(known_conc_model.normed_integrated_concentration(0, 2), expected_normed_integrated_concentration) @pytest.mark.parametrize([ "known_removal_rate", - "known_atmosphere_concentration", + "known_background_concentration", "known_normalization_factor", "expected_normed_integrated_concentration"], [ @@ -223,7 +223,7 @@ def test_normed_integrated_concentration_vectorisation( simple_conc_model: models.ConcentrationModel, dummy_population: models.Population, known_removal_rate: float, - known_atmosphere_concentration: float, + known_background_concentration: float, known_normalization_factor: float, expected_normed_integrated_concentration: float): @@ -232,7 +232,7 @@ def test_normed_integrated_concentration_vectorisation( ventilation = simple_conc_model.ventilation, known_population = dummy_population, known_removal_rate = known_removal_rate, - known_atmosphere_concentration = known_atmosphere_concentration, + known_background_concentration = known_background_concentration, known_normalization_factor = known_normalization_factor) integrated_concentration = known_conc_model.normed_integrated_concentration(0, 2)