Removing _MaskBase and old Mask class, which is replaced by MeasuredMask
This commit is contained in:
parent
3226bb04e8
commit
d5fb86d694
1 changed files with 28 additions and 72 deletions
100
cara/models.py
100
cara/models.py
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue