Removing _MaskBase and old Mask class, which is replaced by MeasuredMask

This commit is contained in:
Nicolas Mounet 2021-05-30 19:28:51 +02:00
parent 947bd013e0
commit fa0550233c

View file

@ -472,61 +472,25 @@ Virus.types = {
@dataclass(frozen=True)
class _MaskBase:
"""
Represents the filtration of aerosols by a mask, both inward and
outward.
The nature of the various mask models means that it is expected
for subclasses of _MaskBase to exist.
"""
class Mask:
#: Filtration efficiency of masks when inhaling.
η_inhale: _VectorisedFloat
#: Global factor applied to filtration efficiency of masks when exhaling.
factor_exhale: _VectorisedFloat = 1.
#: Pre-populated examples of Masks.
types: typing.ClassVar[typing.Dict[str, "_MaskBase"]]
types: typing.ClassVar[typing.Dict[str, "Mask"]]
def exhale_efficiency(self, diameter: float) -> _VectorisedFloat:
# Overall exhale efficiency, including the effect of the leaks.
raise NotImplementedError("Subclass must implement")
def inhale_efficiency(self) -> _VectorisedFloat:
# Overall inhale efficiency, including the effect of the leaks.
raise NotImplementedError("Subclass must implement")
@dataclass(frozen=True)
class Mask(_MaskBase):
#: Filtration efficiency.
η_exhale: _VectorisedFloat
#: Leakage through side of masks.
η_leaks: _VectorisedFloat
#: Filtration efficiency of masks when inhaling.
η_inhale: _VectorisedFloat
def exhale_efficiency(self, diameter: float) -> _VectorisedFloat:
# Overall efficiency with the effect of the leaks for aerosol emission
# Gammaitoni et al (1997). Diameter is in cm.
if diameter < 3e-4:
eta_out = 0.
else:
eta_out = self.η_exhale * (1 - self.η_leaks)
return eta_out
def inhale_efficiency(self) -> _VectorisedFloat:
# Overall inhale efficiency, including the effect of the leaks.
return self.η_inhale
@dataclass(frozen=True)
class MeasuredMask(_MaskBase):
#: Filtration efficiency of masks when inhaling.
η_inhale: _VectorisedFloat
def exhale_efficiency(self, diameter: float) -> _VectorisedFloat:
# See CERN-OPEN-2021-004 (doi: 10.17181/CERN.1GDQ.5Y75), and Ref.
# therein (Asadi 2020).
# Obtained from measurements of filtration efficiency and of
# the leakage through the sides.
# Diameter is in cm.
"""
Overall exhale efficiency, including the effect of the leaks.
See CERN-OPEN-2021-004 (doi: 10.17181/CERN.1GDQ.5Y75), and Ref.
therein (Asadi 2020).
Obtained from measurements of filtration efficiency and of
the leakage through the sides.
Diameter is in cm.
"""
if diameter < 0.5e-4:
eta_out = 0.
elif diameter < 0.94614e-4:
@ -535,29 +499,21 @@ class MeasuredMask(_MaskBase):
eta_out = 0.0509 * diameter * 1e4 + 0.664
else:
eta_out = 0.8167
return eta_out
return eta_out*self.factor_exhale
def inhale_efficiency(self) -> _VectorisedFloat:
# Overall inhale efficiency, including the effect of the leaks.
"""
Overall inhale efficiency, including the effect of the leaks.
"""
return self.η_inhale
_MaskBase.types = {
'No mask': Mask(0, 0, 0),
Mask.types = {
'No mask': Mask(0, 0),
'Type I': Mask(
η_exhale=0.95,
η_leaks=0.15, # (Huang 2007)
η_inhale=0.3, # (Browen 2010)
),
'FFP2': Mask(
η_exhale=0.95, # (same outward effect as type 1 - Asadi 2020)
η_leaks=0.15, # (same outward effect as type 1 - Asadi 2020)
η_inhale=0.865, # (94% penetration efficiency + 8% max inward leakage -> EN 149)
),
'Type I measured': MeasuredMask(
η_inhale=0.5, # (CERN-OPEN-2021-004)
),
'FFP2 measured': MeasuredMask(
'FFP2': Mask(
η_inhale=0.865, # (94% penetration efficiency + 8% max inward leakage -> EN 149)
),
}
@ -569,10 +525,10 @@ class _ExpirationBase:
Represents the expiration of aerosols by a person.
Subclasses of _ExpirationBase represent different models.
"""
#: Pre-populated examples of Masks.
#: Pre-populated examples of Expirations.
types: typing.ClassVar[typing.Dict[str, "_ExpirationBase"]]
def aerosols(self, mask: _MaskBase):
def aerosols(self, mask: Mask):
# total volume of aerosols expired per volume of air (mL/cm^3).
raise NotImplementedError("Subclass must implement")
@ -589,7 +545,7 @@ class Expiration(_ExpirationBase):
ejection_factor: typing.Tuple[float, ...]
particle_sizes: typing.Tuple[float, ...] = (0.8e-4, 1.8e-4, 3.5e-4, 5.5e-4) # In cm.
def aerosols(self, mask: _MaskBase):
def aerosols(self, mask: Mask):
def volume(diameter):
return (4 * np.pi * (diameter/2)**3) / 3
total = 0
@ -617,7 +573,7 @@ class MultipleExpiration(_ExpirationBase):
raise ValueError("expirations and weigths should contain the"
"same number of elements")
def aerosols(self, mask: _MaskBase):
def aerosols(self, mask: Mask):
return np.array([
weight * expiration.aerosols(mask) / sum(self.weights)
for weight,expiration in zip(self.weights,self.expirations)
@ -665,7 +621,7 @@ class Population:
presence: Interval
#: The kind of mask being worn by the people.
mask: _MaskBase
mask: Mask
#: The physical activity being carried out by the people.
activity: Activity