Improving implementation of Hinged and Sliding window (as subclasses of WindowOpening). Changed cd_b into discharge_coefficient everywhere.

This commit is contained in:
Nicolas Mounet 2020-12-01 08:22:51 +01:00
parent 7e0e8a4e20
commit 44a3204bef
7 changed files with 70 additions and 59 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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)

View file

@ -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),

View file

@ -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,

View file

@ -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),)),

View file

@ -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