Skip to content

Commit

Permalink
Merge branch 'feature/generic_population_class' into 'master'
Browse files Browse the repository at this point in the history
Created a simple population class for the CO2 concentration model

Closes #296

See merge request caimira/caimira!459
  • Loading branch information
nmounet committed Jul 28, 2023
2 parents 68bc8cc + d26218c commit e854efc
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 35 deletions.
4 changes: 1 addition & 3 deletions caimira/apps/calculator/model_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,10 @@ def build_CO2_model(self, sample_size=DEFAULT_MC_SAMPLE_SIZE) -> models.CO2Conce
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
Expand Down
4 changes: 1 addition & 3 deletions caimira/apps/expert_co2.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
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,
Expand Down
32 changes: 20 additions & 12 deletions caimira/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ class Activity:


@dataclass(frozen=True)
class Population:
class SimplePopulation:
"""
Represents a group of people all with exactly the same behaviour and
situation.
Expand All @@ -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):
Expand Down Expand Up @@ -841,6 +833,22 @@ def people_present(self, time: float):
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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
4 changes: 1 addition & 3 deletions caimira/tests/models/test_co2_concentration_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.,
),
)

Expand Down
28 changes: 14 additions & 14 deletions caimira/tests/models/test_exposure_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,18 @@ def _normed_concentration(self, time: float) -> models._VectorisedFloat: # noqa
populations = [
# A simple scalar population.
models.Population(
10, halftime, models.Mask.types['Type I'],
models.Activity.types['Standing'], host_immunity=0.,
10, halftime, activity=models.Activity.types['Standing'],
mask=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, activity=models.Activity.types['Standing'],
mask=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, activity=models.Activity(np.array([0.51, 0.57]), 0.57),
mask=models.Mask.types['Type I'], host_immunity=0.
),
]

Expand Down Expand Up @@ -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)
Expand All @@ -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()
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit e854efc

Please sign in to comment.