diff --git a/caimira/apps/calculator/model_generator.py b/caimira/apps/calculator/model_generator.py index 981e1e67..664eef2b 100644 --- a/caimira/apps/calculator/model_generator.py +++ b/caimira/apps/calculator/model_generator.py @@ -370,12 +370,10 @@ class FormData: total_people = [infected_population.people_present(stop) + exposed_population.people_present(stop) for _, stop in zip(transition_times[:-1], transition_times[1:])] - population = mc.Population( + population = mc.SimplePopulation( number=models.IntPiecewiseConstant(transition_times=tuple(transition_times), values=tuple(total_people)), presence=None, - mask=models.Mask.types[self.mask_type], activity=activity_distributions[ACTIVITIES[ACTIVITY_TYPES.index(self.activity_type)]['activity']], - host_immunity=0., ) # Builds a CO2 concentration model based on model inputs diff --git a/caimira/apps/expert_co2.py b/caimira/apps/expert_co2.py index ba9d7f63..345f7cf7 100644 --- a/caimira/apps/expert_co2.py +++ b/caimira/apps/expert_co2.py @@ -14,12 +14,10 @@ from .expert import generate_presence_widget, collapsible, ipympl_canvas, Widget baseline_model = models.CO2ConcentrationModel( room=models.Room(volume=120, humidity=0.5, inside_temp=models.PiecewiseConstant((0., 24.), (293.15,))), ventilation=models.HVACMechanical(active=models.PeriodicInterval(period=120, duration=120), q_air_mech=500), - CO2_emitters=models.Population( + CO2_emitters=models.SimplePopulation( number=10, presence=models.SpecificInterval(((8., 12.), (13., 17.))), - mask=models.Mask.types['No mask'], activity=models.Activity.types['Seated'], - host_immunity=0., ), CO2_atmosphere_concentration=440.44, CO2_fraction_exhaled=0.042, diff --git a/caimira/models.py b/caimira/models.py index 4a80307e..e8de7667 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -789,7 +789,7 @@ Activity.types = { @dataclass(frozen=True) -class Population: +class SimplePopulation: """ Represents a group of people all with exactly the same behaviour and situation. @@ -801,17 +801,9 @@ class Population: #: The times in which the people are in the room. presence: typing.Union[None, Interval] - #: The kind of mask being worn by the people. - mask: Mask - #: The physical activity being carried out by the people. activity: Activity - #: The ratio of virions that are inactivated by the person's immunity. - # This parameter considers the potential antibodies in the person, - # which might render inactive some RNA copies (virions). - host_immunity: float - def __post_init__(self): if isinstance(self.number, int): if not isinstance(self.presence, Interval): @@ -841,6 +833,22 @@ class Population: return int(self.number.value(time)) +@dataclass(frozen=True) +class Population(SimplePopulation): + """ + Represents a group of people all with exactly the same behaviour and + situation, considering the usage of mask and a certain host immunity. + + """ + #: The kind of mask being worn by the people. + mask: Mask + + #: The ratio of virions that are inactivated by the person's immunity. + # This parameter considers the potential antibodies in the person, + # which might render inactive some RNA copies (virions). + host_immunity: float + + @dataclass(frozen=True) class _PopulationWithVirus(Population): #: The virus with which the population is infected. @@ -1005,7 +1013,7 @@ class _ConcentrationModelBase: ventilation: _VentilationBase @property - def population(self) -> Population: + def population(self) -> SimplePopulation: """ Population in the room (the emitters of what we compute the concentration of) @@ -1239,7 +1247,7 @@ class CO2ConcentrationModel(_ConcentrationModelBase): Class used for the computation of the CO2 concentration. """ #: Population in the room emitting CO2 - CO2_emitters: Population + CO2_emitters: SimplePopulation #: CO2 concentration in the atmosphere (in ppm) CO2_atmosphere_concentration: float = 440.44 @@ -1248,7 +1256,7 @@ class CO2ConcentrationModel(_ConcentrationModelBase): CO2_fraction_exhaled: float = 0.042 @property - def population(self) -> Population: + def population(self) -> SimplePopulation: return self.CO2_emitters def removal_rate(self, time: float) -> _VectorisedFloat: diff --git a/caimira/tests/models/test_co2_concentration_model.py b/caimira/tests/models/test_co2_concentration_model.py index ad4a348c..ab5562db 100644 --- a/caimira/tests/models/test_co2_concentration_model.py +++ b/caimira/tests/models/test_co2_concentration_model.py @@ -9,12 +9,10 @@ def simple_co2_conc_model(): return models.CO2ConcentrationModel( room=models.Room(200, models.PiecewiseConstant((0., 24.), (293,))), ventilation=models.AirChange(models.PeriodicInterval(period=120, duration=120), 0.25), - CO2_emitters=models.Population( + CO2_emitters=models.SimplePopulation( number=5, presence=models.SpecificInterval((([0., 4.], ))), - mask=models.Mask.types['No mask'], activity=models.Activity.types['Seated'], - host_immunity=0., ), ) diff --git a/caimira/tests/models/test_exposure_model.py b/caimira/tests/models/test_exposure_model.py index 4c48b480..60b0bdef 100644 --- a/caimira/tests/models/test_exposure_model.py +++ b/caimira/tests/models/test_exposure_model.py @@ -40,18 +40,18 @@ halftime = models.PeriodicInterval(120, 60) populations = [ # A simple scalar population. models.Population( - 10, halftime, models.Mask.types['Type I'], - models.Activity.types['Standing'], host_immunity=0., + 10, halftime, models.Activity.types['Standing'], + models.Mask.types['Type I'], host_immunity=0., ), # A population with some array component for η_inhale. models.Population( - 10, halftime, models.Mask(np.array([0.3, 0.35])), - models.Activity.types['Standing'], host_immunity=0. + 10, halftime, models.Activity.types['Standing'], + models.Mask(np.array([0.3, 0.35])), host_immunity=0. ), # A population with some array component for inhalation_rate. models.Population( - 10, halftime, models.Mask.types['Type I'], - models.Activity(np.array([0.51, 0.57]), 0.57), host_immunity=0. + 10, halftime, models.Activity(np.array([0.51, 0.57]), 0.57), + models.Mask.types['Type I'], host_immunity=0. ), ] @@ -212,8 +212,8 @@ def test_exposure_model_integral_accuracy(exposed_time_interval, expected_deposited_exposure, conc_model, sr_model, cases_model): presence_interval = models.SpecificInterval((exposed_time_interval,)) population = models.Population( - 10, presence_interval, models.Mask.types['Type I'], - models.Activity.types['Standing'], 0., + 10, presence_interval, models.Activity.types['Standing'], + models.Mask.types['Type I'], 0., ) model = ExposureModel(conc_model, sr_model, population, cases_model) np.testing.assert_allclose(model.deposited_exposure(), expected_deposited_exposure) @@ -239,8 +239,8 @@ def test_infectious_dose_vectorisation(sr_model, cases_model): presence_interval = models.SpecificInterval(((0., 1.),)) population = models.Population( - 10, presence_interval, models.Mask.types['Type I'], - models.Activity.types['Standing'], 0., + 10, presence_interval, models.Activity.types['Standing'], + models.Mask.types['Type I'], 0., ) model = ExposureModel(cm, sr_model, population, cases_model) inf_probability = model.infection_probability() @@ -302,8 +302,8 @@ def test_probabilistic_exposure_probability(sr_model, exposed_population, cm, pop, AB, cases, probabilistic_exposure_probability): population = models.Population( - exposed_population, models.PeriodicInterval(120, 60), models.Mask.types['Type I'], - models.Activity.types['Standing'], host_immunity=0.,) + exposed_population, models.PeriodicInterval(120, 60), models.Activity.types['Standing'], + models.Mask.types['Type I'], host_immunity=0.,) model = ExposureModel(cm, sr_model, population, models.Cases(geographic_population=pop, geographic_cases=cases, ascertainment_bias=AB),) np.testing.assert_allclose( @@ -402,8 +402,8 @@ def test_diameter_vectorisation_room(diameter_dependent_model, sr_model, cases_m ) def test_host_immunity_vectorisation(sr_model, cases_model, cm, host_immunity, expected_probability): population = models.Population( - 10, halftime, models.Mask(np.array([0.3, 0.35])), - models.Activity.types['Standing'], host_immunity=host_immunity + 10, halftime, models.Activity.types['Standing'], + models.Mask(np.array([0.3, 0.35])), host_immunity=host_immunity ) model = ExposureModel(cm, sr_model, population, cases_model) inf_probability = model.infection_probability()