From c8f2b32feffb5b3a8c9cf15952069060da7bbb73 Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Tue, 25 Jul 2023 14:56:13 +0200 Subject: [PATCH 1/3] modified CO2 concentration when ventilation is close to 0. (RR) --- caimira/models.py | 20 ++++++++----------- .../tests/models/test_concentration_model.py | 10 +++++++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/caimira/models.py b/caimira/models.py index e8de7667..db62293f 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -1132,23 +1132,21 @@ class _ConcentrationModelBase: return self.min_background_concentration()/self.normalization_factor() next_state_change_time = self._next_state_change(time) - RR = self.removal_rate(next_state_change_time) - # If RR is 0, conc_limit does not play a role but its computation - # would raise an error -> we set it to zero. - try: - conc_limit = self._normed_concentration_limit(next_state_change_time) - except ZeroDivisionError: - conc_limit = 0. t_last_state_change = self.last_state_change(time) conc_at_last_state_change = self._normed_concentration_cached(t_last_state_change) - delta_time = time - t_last_state_change + fac = np.exp(-RR * delta_time) - return conc_limit * (1 - fac) + conc_at_last_state_change * fac + if isinstance(RR, float) and RR == 0: + curr_conc_state = delta_time * self.population.people_present(time) / self.room.volume + else: + curr_conc_state = self._normed_concentration_limit(next_state_change_time) * (1 - fac) + return curr_conc_state + conc_at_last_state_change * fac + def concentration(self, time: float) -> _VectorisedFloat: """ Total concentration as a function of time. The normalization @@ -1260,9 +1258,7 @@ class CO2ConcentrationModel(_ConcentrationModelBase): return self.CO2_emitters def removal_rate(self, time: float) -> _VectorisedFloat: - # Setting minimum air exchange rate to 1e-6 to avoid divisions by - # zero when computing the CO2 concentration. - return np.maximum(1e-6,self.ventilation.air_exchange(self.room, time)) + return self.ventilation.air_exchange(self.room, time) def min_background_concentration(self) -> _VectorisedFloat: """ diff --git a/caimira/tests/models/test_concentration_model.py b/caimira/tests/models/test_concentration_model.py index f8f42106..27703a2f 100644 --- a/caimira/tests/models/test_concentration_model.py +++ b/caimira/tests/models/test_concentration_model.py @@ -252,8 +252,11 @@ def test_normed_integrated_concentration_vectorisation( "known_min_background_concentration", "expected_concentration"], [ - [0., 240., 240.], - [0., np.array([240., 240.]), np.array([240., 240.])] + [0., 240., 240. + 0.5/75], + [0.0001, 240.0, 240. + 0.5/75], + [1e-6, 240.0, 240 + 0.5/75], + [0., np.array([240., 240.]), np.array([240. + 0.5/75, 240. + 0.5/75])], + [np.array([0.0001, 1e-6]), np.array([240., 240.]), np.array([240. + 0.5/75, 240. + 0.5/75])], ] ) def test_zero_ventilation_rate( @@ -272,4 +275,5 @@ def test_zero_ventilation_rate( known_min_background_concentration = known_min_background_concentration) normed_concentration = known_conc_model.concentration(1) - npt.assert_almost_equal(normed_concentration, expected_concentration) + assert normed_concentration == pytest.approx(expected_concentration, abs=1e-6) + \ No newline at end of file From 9712ffc8ae464b59f9674e0973952d9d6a8893b2 Mon Sep 17 00:00:00 2001 From: Nicolas Mounet Date: Tue, 3 Oct 2023 12:05:31 +0200 Subject: [PATCH 2/3] Adapting zero removal rate case to case when RR is an array --- caimira/models.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/caimira/models.py b/caimira/models.py index db62293f..7a14f33f 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -1055,8 +1055,15 @@ class _ConcentrationModelBase: """ V = self.room.volume RR = self.removal_rate(time) - - return (self.population.people_present(time) / (RR * V) + + + if isinstance(RR, np.ndarray): + invRR = np.empty(RR.shape, dtype=np.float64) + invRR[RR == 0.] = np.nan + invRR[RR != 0.] = 1. / RR[RR != 0.] + else: + invRR = np.nan if RR == 0. else 1. / RR + + return (self.population.people_present(time) * invRR / V + self.min_background_concentration()/self.normalization_factor()) @method_cache @@ -1139,11 +1146,16 @@ class _ConcentrationModelBase: delta_time = time - t_last_state_change fac = np.exp(-RR * delta_time) - - if isinstance(RR, float) and RR == 0: - curr_conc_state = delta_time * self.population.people_present(time) / self.room.volume + if isinstance(RR, np.ndarray): + curr_conc_state = np.empty(RR.shape, dtype=np.float64) + curr_conc_state[RR == 0.] = delta_time * self.population.people_present(time) / ( + self.room.volume[RR == 0.] if isinstance(self.room.volume,np.ndarray) else self.room.volume) + curr_conc_state[RR != 0.] = self._normed_concentration_limit(next_state_change_time)[RR != 0.] * (1 - fac[RR != 0.]) else: - curr_conc_state = self._normed_concentration_limit(next_state_change_time) * (1 - fac) + if RR == 0.: + curr_conc_state = delta_time * self.population.people_present(time) / self.room.volume + else: + curr_conc_state = self._normed_concentration_limit(next_state_change_time) * (1 - fac) return curr_conc_state + conc_at_last_state_change * fac From e0a321dd86f2a2eab21e5bbd3679d10e297d2997 Mon Sep 17 00:00:00 2001 From: Nicolas Mounet Date: Tue, 3 Oct 2023 12:35:38 +0200 Subject: [PATCH 3/3] fixing mypy issue --- caimira/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caimira/models.py b/caimira/models.py index 7a14f33f..24ef62e2 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -1061,7 +1061,7 @@ class _ConcentrationModelBase: invRR[RR == 0.] = np.nan invRR[RR != 0.] = 1. / RR[RR != 0.] else: - invRR = np.nan if RR == 0. else 1. / RR + invRR = np.nan if RR == 0. else 1. / RR # type: ignore return (self.population.people_present(time) * invRR / V + self.min_background_concentration()/self.normalization_factor())