From 817ca8f3bfbf002c15a0aadd3f4a92dc01ece197 Mon Sep 17 00:00:00 2001 From: Nicolas Mounet Date: Wed, 5 May 2021 12:45:02 +0200 Subject: [PATCH] ConcentrationModel: _next_state_change used only in concentration function, now; improving docstrings and error handling --- cara/models.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/cara/models.py b/cara/models.py index 521c40c2..8f2a8c42 100644 --- a/cara/models.py +++ b/cara/models.py @@ -644,20 +644,19 @@ class ConcentrationModel: k = (vg * 3600) / h return k + self.virus.decay_constant + self.ventilation.air_exchange( - self.room, self._next_state_change(time)) + self.room, time) @cached() def _concentration_limit(self, time: float) -> _VectorisedFloat: """ Provides a constant that represents the theoretical asymptotic - value reached by the concentration when time goes to infinity. - It's a piecewise constant function - at any time it takes the - value it would have at the end of the current interval. + value reached by the concentration when time goes to infinity, + if all parameters were to stay time-independent. """ V = self.room.volume IVRR = self.infectious_virus_removal_rate(time) - return (self.infected.emission_rate(self._next_state_change(time))) / (IVRR * V) + return (self.infected.emission_rate(time)) / (IVRR * V) @cached() def state_change_times(self): @@ -694,19 +693,32 @@ class ConcentrationModel: @cached() def concentration(self, time: float) -> _VectorisedFloat: - # Note that time is not vectorised. You can only pass a single float - # to this method. + """ + Virus quanta concentration, as a function of time. + The formulas used here assume that all parameters (ventilation, + emission rate) are constant between two state changes - only + the value of these parameters at the next state change, are used. + + Note that time is not vectorised. You can only pass a single float + to this method. + """ if time == 0: return 0.0 - IVRR = self.infectious_virus_removal_rate(time) + try: + IVRR = self.infectious_virus_removal_rate(self._next_state_change(time)) + concentration_limit = self._concentration_limit(self._next_state_change(time)) + except ValueError: + raise ValueError("Concentration cannot be computed at a time" + " larger than last state change (parameters" + " are not defined)") t_last_state_change = self.last_state_change(time) concentration_at_last_state_change = self.concentration(t_last_state_change) delta_time = time - t_last_state_change fac = np.exp(-IVRR * delta_time) - return self._concentration_limit(time) * (1 - fac) + concentration_at_last_state_change * fac + return concentration_limit * (1 - fac) + concentration_at_last_state_change * fac @dataclass(frozen=True)