Improving implementation of Hinged and Sliding window (as subclasses of WindowOpening). Changed cd_b into discharge_coefficient everywhere.
This commit is contained in:
parent
7e0e8a4e20
commit
44a3204bef
7 changed files with 70 additions and 59 deletions
|
|
@ -141,9 +141,9 @@ class FormData:
|
|||
inside_temp = models.PiecewiseConstant((0, 24), (293,))
|
||||
outside_temp = data.GenevaTemperatures[month]
|
||||
|
||||
ventilation = models.WindowOpening(
|
||||
ventilation = models.SlidingWindow(
|
||||
active=window_interval,
|
||||
inside_temp=inside_temp, outside_temp=outside_temp, cd_b=0.6,
|
||||
inside_temp=inside_temp, outside_temp=outside_temp,
|
||||
window_height=self.window_height,
|
||||
opening_length=self.opening_distance,
|
||||
number_of_windows=self.windows_number,
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ baseline_model = models.ExposureModel(
|
|||
active=models.PeriodicInterval(period=120, duration=15),
|
||||
inside_temp=models.PiecewiseConstant((0,24),(293.15,)),
|
||||
outside_temp=models.PiecewiseConstant((0,24),(283.15,)),
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
discharge_coefficient=0.6, window_height=1.6, opening_length=0.6,
|
||||
),
|
||||
infected=models.InfectedPopulation(
|
||||
number=1,
|
||||
|
|
|
|||
|
|
@ -189,45 +189,25 @@ class WindowOpening(Ventilation):
|
|||
#: The temperature outside of the window (Kelvin).
|
||||
outside_temp: PiecewiseConstant
|
||||
|
||||
#: The height of the window.
|
||||
#: The height of the window (m).
|
||||
window_height: float
|
||||
|
||||
#: The length of the opening-gap when the window is open
|
||||
#: The length of the opening-gap when the window is open (m).
|
||||
opening_length: float
|
||||
|
||||
#: The type of the window ('sliding' or 'hinged')
|
||||
window_type: str = 'sliding'
|
||||
|
||||
#: The width of the window (used only to get cd_b of a hinged window).
|
||||
window_width: float = None
|
||||
#: Discharge coefficient: what portion effective area is
|
||||
#: used to exchange air (0 <= discharge_coefficient <= 1).
|
||||
discharge_coefficient: float = None
|
||||
|
||||
#: The number of windows of the given dimensions.
|
||||
number_of_windows: int = 1
|
||||
|
||||
#: Discharge coefficient: what portion effective area is
|
||||
#: used to exchange air (0 <= cd_b <= 1). Overrides the value
|
||||
#: obtained from the window parameters
|
||||
cd_b: float = None
|
||||
|
||||
#: Minimum difference between inside and outside temperature
|
||||
#: Minimum difference between inside and outside temperature (K).
|
||||
min_deltaT: float = 0.1
|
||||
|
||||
@property
|
||||
def _cd_b(self):
|
||||
if self.cd_b is not None:
|
||||
return self.cd_b
|
||||
elif self.window_type == 'sliding':
|
||||
return 0.6
|
||||
elif self.window_type == 'hinged':
|
||||
window_ratio = self.window_width / self.window_height
|
||||
M = (0.06 if window_ratio < 0.5 else 0.048 if window_ratio < 1 else
|
||||
0.04 if window_ratio < 2 else 0.038)
|
||||
cd_max = (0.612 if window_ratio < 0.5 else 0.589 if window_ratio < 1
|
||||
else 0.563 if window_ratio < 2 else 0.548)
|
||||
window_angle = np.arccos(1-self.opening_length**2/(2.*self.window_height**2))
|
||||
return cd_max*(1-np.exp(-M*window_angle))
|
||||
else:
|
||||
raise ValueError("Unknown window type; please specify cd_b")
|
||||
def cd_b(self) -> float:
|
||||
return self.discharge_coefficient
|
||||
|
||||
def transition_times(self) -> typing.Set[float]:
|
||||
transitions = super().transition_times()
|
||||
|
|
@ -252,7 +232,30 @@ class WindowOpening(Ventilation):
|
|||
temp_gradient = (inside_temp - outside_temp) / outside_temp
|
||||
root = np.sqrt(9.81 * self.window_height * temp_gradient)
|
||||
window_area = self.window_height * self.opening_length * self.number_of_windows
|
||||
return (3600 / (3 * room.volume)) * self._cd_b * window_area * root
|
||||
return (3600 / (3 * room.volume)) * self.cd_b * window_area * root
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SlidingWindow(WindowOpening):
|
||||
@property
|
||||
def cd_b(self) -> float:
|
||||
return 0.6
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HingedWindow(WindowOpening):
|
||||
#: Window width (m).
|
||||
window_width: float = None
|
||||
|
||||
@property
|
||||
def cd_b(self) -> float:
|
||||
window_ratio = self.window_width / self.window_height
|
||||
M = (0.06 if window_ratio < 0.5 else 0.048 if window_ratio < 1 else
|
||||
0.04 if window_ratio < 2 else 0.038)
|
||||
cd_max = (0.612 if window_ratio < 0.5 else 0.589 if window_ratio < 1
|
||||
else 0.563 if window_ratio < 2 else 0.548)
|
||||
window_angle = np.arccos(1-self.opening_length**2/(2.*self.window_height**2))
|
||||
return cd_max*(1-np.exp(-M*window_angle))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ def test_blend_expiration():
|
|||
|
||||
def test_ventilation_window(baseline_form):
|
||||
room = models.Room(75)
|
||||
window = models.WindowOpening(
|
||||
window = models.SlidingWindow(
|
||||
active=models.PeriodicInterval(period=120, duration=10),
|
||||
inside_temp=models.PiecewiseConstant((0, 24), (293,)),
|
||||
outside_temp=data.GenevaTemperatures['Dec'],
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
window_height=1.6, opening_length=0.6,
|
||||
)
|
||||
baseline_form.ventilation_type = 'natural'
|
||||
baseline_form.windows_open = 'interval'
|
||||
|
|
@ -82,11 +82,11 @@ def test_ventilation_airchanges(baseline_form):
|
|||
|
||||
def test_ventilation_window_hepa(baseline_form):
|
||||
room = models.Room(75)
|
||||
window = models.WindowOpening(
|
||||
window = models.SlidingWindow(
|
||||
active=models.PeriodicInterval(period=120, duration=10),
|
||||
inside_temp=models.PiecewiseConstant((0, 24), (293,)),
|
||||
outside_temp=data.GenevaTemperatures['Dec'],
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
window_height=1.6, opening_length=0.6,
|
||||
)
|
||||
hepa = models.HEPAFilter(
|
||||
active=models.PeriodicInterval(period=120, duration=120),
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ def baseline_model():
|
|||
active=models.PeriodicInterval(period=120, duration=120),
|
||||
inside_temp=models.PiecewiseConstant((0,24),(293,)),
|
||||
outside_temp=models.PiecewiseConstant((0,24),(283,)),
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
discharge_coefficient=0.6, window_height=1.6, opening_length=0.6,
|
||||
),
|
||||
infected=models.InfectedPopulation(
|
||||
number=1,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ def baseline_periodic_window():
|
|||
active=models.PeriodicInterval(period=120, duration=15),
|
||||
inside_temp=models.PiecewiseConstant((0,24),(293,)),
|
||||
outside_temp=models.PiecewiseConstant((0,24),(283,)),
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
discharge_coefficient=0.6, window_height=1.6, opening_length=0.6,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ def test_multiple_ventilation_HEPA_window(baseline_periodic_hepa, time, expected
|
|||
room = models.Room(volume=68.)
|
||||
tempOutside = models.PiecewiseConstant((0., 1., 2.5),(273.15, 283.15))
|
||||
tempInside = models.PiecewiseConstant((0., 24.),(293.15,))
|
||||
window = models.WindowOpening(active=models.SpecificInterval([(1 / 60, 24.)]),
|
||||
window = models.SlidingWindow(active=models.SpecificInterval([(1 / 60, 24.)]),
|
||||
inside_temp=tempInside,outside_temp=tempOutside,
|
||||
window_height=1.,opening_length=0.6)
|
||||
vent = models.MultipleVentilation([window, baseline_periodic_hepa])
|
||||
|
|
@ -146,7 +146,7 @@ def test_multiple_ventilation_HEPA_window(baseline_periodic_hepa, time, expected
|
|||
def test_multiple_ventilation_HEPA_window_transitions(baseline_periodic_hepa):
|
||||
tempOutside = models.PiecewiseConstant((0., 1., 2.5),(273.15, 283.15))
|
||||
tempInside = models.PiecewiseConstant((0., 24.),(293.15,))
|
||||
window = models.WindowOpening(active=models.SpecificInterval([(1 / 60, 24.)]),
|
||||
window = models.SlidingWindow(active=models.SpecificInterval([(1 / 60, 24.)]),
|
||||
inside_temp=tempInside,outside_temp=tempOutside,
|
||||
window_height=1.,opening_length=0.6)
|
||||
vent = models.MultipleVentilation([window, baseline_periodic_hepa])
|
||||
|
|
@ -264,7 +264,7 @@ def test_piecewiseconstant_transition_times():
|
|||
def test_windowopening(time, expected_value):
|
||||
tempOutside = models.PiecewiseConstant((0,10,24),(273.15,283.15))
|
||||
tempInside = models.PiecewiseConstant((0,24),(293.15,))
|
||||
w = models.WindowOpening(active=models.SpecificInterval([(0,24)]),
|
||||
w = models.SlidingWindow(active=models.SpecificInterval([(0,24)]),
|
||||
inside_temp=tempInside,outside_temp=tempOutside,
|
||||
window_height=1.,opening_length=0.6)
|
||||
npt.assert_allclose(w.air_exchange(models.Room(volume=68),time),
|
||||
|
|
@ -293,7 +293,7 @@ def build_hourly_dependent_model(month, intervals_open=((7.5, 8.5),),
|
|||
active=models.SpecificInterval(intervals_open),
|
||||
inside_temp=models.PiecewiseConstant((0,24),(293,)),
|
||||
outside_temp=outside_temp,
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
discharge_coefficient=0.6, window_height=1.6, opening_length=0.6,
|
||||
),
|
||||
infected=models.InfectedPopulation(
|
||||
number=1,
|
||||
|
|
@ -314,7 +314,7 @@ def build_constant_temp_model(outside_temp, intervals_open=((7.5, 8.5),)):
|
|||
active=models.SpecificInterval(intervals_open),
|
||||
inside_temp=models.PiecewiseConstant((0,24),(293,)),
|
||||
outside_temp=models.PiecewiseConstant((0,24),(outside_temp,)),
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
discharge_coefficient=0.6, window_height=1.6, opening_length=0.6,
|
||||
),
|
||||
infected=models.InfectedPopulation(
|
||||
number=1,
|
||||
|
|
@ -334,7 +334,7 @@ def build_hourly_dependent_model_multipleventilation(month, intervals_open=((7.5
|
|||
active=models.SpecificInterval(intervals_open),
|
||||
inside_temp=models.PiecewiseConstant((0,24),(293,)),
|
||||
outside_temp=data.GenevaTemperatures[month],
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
discharge_coefficient=0.6, window_height=1.6, opening_length=0.6,
|
||||
),
|
||||
models.HEPAFilter(
|
||||
active=models.SpecificInterval(((0,24),)),
|
||||
|
|
|
|||
|
|
@ -7,20 +7,30 @@ from cara import models
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def baseline_window():
|
||||
return models.WindowOpening(
|
||||
def baseline_slidingwindow():
|
||||
return models.SlidingWindow(
|
||||
active=models.SpecificInterval(((0, 4), (5, 9))),
|
||||
inside_temp=models.PiecewiseConstant((0, 24), (293,)),
|
||||
outside_temp=models.PiecewiseConstant((0, 24), (283,)),
|
||||
cd_b=0.6, window_height=1.6, opening_length=0.6,
|
||||
window_height=1.6, opening_length=0.6,
|
||||
)
|
||||
|
||||
|
||||
def test_number_of_windows(baseline_window):
|
||||
room = models.Room(75)
|
||||
two_windows = dataclasses.replace(baseline_window, number_of_windows=2)
|
||||
@pytest.fixture
|
||||
def baseline_hingedwindow():
|
||||
return models.HingedWindow(
|
||||
active=models.SpecificInterval(((0, 4), (5, 9))),
|
||||
inside_temp=models.PiecewiseConstant((0, 24), (293,)),
|
||||
outside_temp=models.PiecewiseConstant((0, 24), (283,)),
|
||||
window_height=1.6, opening_length=0.6, window_width=1.,
|
||||
)
|
||||
|
||||
one_window_exchange = baseline_window.air_exchange(room, 1)
|
||||
|
||||
def test_number_of_windows(baseline_slidingwindow):
|
||||
room = models.Room(75)
|
||||
two_windows = dataclasses.replace(baseline_slidingwindow, number_of_windows=2)
|
||||
|
||||
one_window_exchange = baseline_slidingwindow.air_exchange(room, 1)
|
||||
two_window_exchange = two_windows.air_exchange(room, 1)
|
||||
assert one_window_exchange != 0
|
||||
assert one_window_exchange * 2 == two_window_exchange
|
||||
|
|
@ -35,17 +45,15 @@ def test_number_of_windows(baseline_window):
|
|||
[4., 0.00779945967],
|
||||
],
|
||||
)
|
||||
def test_hinged_window(baseline_window,window_width,expected_cd_b):
|
||||
def test_hinged_window(baseline_hingedwindow,window_width,expected_cd_b):
|
||||
room = models.Room(75)
|
||||
hinged_window = dataclasses.replace(baseline_window, cd_b=None,
|
||||
window_type='hinged',window_width=window_width)
|
||||
hinged_window = dataclasses.replace(baseline_hingedwindow,
|
||||
window_width=window_width)
|
||||
|
||||
npt.assert_allclose(hinged_window._cd_b, expected_cd_b, rtol=1e-8)
|
||||
npt.assert_allclose(hinged_window.cd_b, expected_cd_b, rtol=1e-8)
|
||||
|
||||
|
||||
def test_sliding_window(baseline_window):
|
||||
def test_sliding_window(baseline_slidingwindow):
|
||||
room = models.Room(75)
|
||||
sliding_window = dataclasses.replace(baseline_window, cd_b=None,
|
||||
window_type='sliding')
|
||||
|
||||
assert sliding_window._cd_b == 0.6
|
||||
assert baseline_slidingwindow.cd_b == 0.6
|
||||
|
|
|
|||
Loading…
Reference in a new issue