diff --git a/cara/apps/calculator/report_generator.py b/cara/apps/calculator/report_generator.py index 23ad9fb1..a07b1f0b 100644 --- a/cara/apps/calculator/report_generator.py +++ b/cara/apps/calculator/report_generator.py @@ -110,15 +110,15 @@ def calculate_report_data(model: models.ExposureModel): er = np.array(model.concentration_model.infected.emission_rate_when_present()).mean() exposed_occupants = model.exposed.number expected_new_cases = np.array(model.expected_new_cases()).mean() - cumulative_doses = [ - np.array(model.inhaled_exposure_between_bounds(float(time))).mean() - for time in times - ] + cumulative_doses = np.cumsum([ + np.array(model.exposure_between_bounds(float(time1), float(time2))).mean() + for time1, time2 in zip(times[:-1], times[1:]) + ]) return { "times": list(times), "exposed_presence_intervals": [list(interval) for interval in model.exposed.presence.boundaries()], - "cumulative_doses": cumulative_doses, + "cumulative_doses": list(cumulative_doses), "concentrations": concentrations, "highest_const": highest_const, "prob_inf": prob, diff --git a/cara/models.py b/cara/models.py index a86457eb..d75818cb 100644 --- a/cara/models.py +++ b/cara/models.py @@ -877,50 +877,37 @@ class ExposureModel: #: The fraction of viruses actually deposited in the respiratory tract fraction_deposited: _VectorisedFloat = 0.6 - def exposure_between_bounds(self, time: float) -> _VectorisedFloat: - """The number of virions per meter^3 from model start to the given time.""" - boundaries = [] + def exposure_between_bounds(self, time1: float, time2: float) -> _VectorisedFloat: + """The number of virions per meter^3 from model start to the given stop.""" for start, stop in self.exposed.presence.boundaries(): - if start > time: + if start > time2: + result = 0. break - elif time <= stop: - stop = time - boundaries.append([start, stop]) + elif time2 <= stop: + result = self.concentration_model.integrated_concentration(time1, time2) break else: - boundaries.append([start, stop]) + result = self.concentration_model.integrated_concentration(time1, time2) + return result - exposure = 0.0 - for start, stop in boundaries: - exposure += self.concentration_model.integrated_concentration(start, stop) - - return exposure - def exposure(self) -> _VectorisedFloat: - """The number of virions per meter^3 for the full simulation time.""" - if self.exposed.presence.transition_times(): - return self.exposure_between_bounds(max(self.exposed.presence.transition_times())) - else: - return 0 + """The number of virus per meter^3.""" + exposure = 0.0 - def inhaled_exposure_between_bounds(self, time: float) -> _VectorisedFloat: - exposure = self.exposure_between_bounds(time) - - return ( + for start, stop in self.exposed.presence.boundaries(): + exposure += self.concentration_model.integrated_concentration(start, stop) + + return exposure * self.repeats + + def infection_probability(self) -> _VectorisedFloat: + exposure = self.exposure() + + inf_aero = ( self.exposed.activity.inhalation_rate * (1 - self.exposed.mask.inhale_efficiency()) * exposure * self.fraction_deposited ) - def inhaled_exposure(self) -> _VectorisedFloat: - if self.exposed.presence.transition_times(): - return self.inhaled_exposure_between_bounds(max(self.exposed.presence.transition_times())) - else: - return 0 - - def infection_probability(self) -> _VectorisedFloat: - inf_aero = self.inhaled_exposure() - # Probability of infection. return (1 - np.exp(-(inf_aero/self.concentration_model.virus.infectious_dose))) * 100