Merge branch 'feature/n_windows' into 'master'

Allow WindowOpening to have more than one window of the given dimensions.

See merge request cara/cara!68
This commit is contained in:
Nicolas Mounet 2020-11-09 08:51:10 +00:00
commit ca7f8745aa
4 changed files with 56 additions and 21 deletions

View file

@ -120,12 +120,9 @@ class FormData:
# Initializes a ventilation instance as a window if 'natural' is selected, or as a HEPA-filter otherwise
if self.ventilation_type == 'natural':
if self.windows_open == 'interval':
period, duration = 120, 10
elif self.windows_number == 'breaks':
# TODO: Implement windows open in breaks
period, duration = 120, 120
window_interval = models.PeriodicInterval(120, 10)
else:
period, duration = 120, 120
window_interval = always_on
if self.event_type == 'single_event':
month_number = int(self.single_event_date.split('/')[1])
@ -136,11 +133,13 @@ class FormData:
inside_temp = models.PiecewiseConstant((0, 24), (293,))
outside_temp = models.GenevaTemperatures[month]
# I multiply the opening width by the number of windows to simulate the correct window area
ventilation = models.WindowOpening(active=models.PeriodicInterval(period=period, duration=duration),
inside_temp=inside_temp, outside_temp=outside_temp, cd_b=0.6,
window_height=self.window_height,
opening_length=self.opening_distance * self.windows_number)
ventilation = models.WindowOpening(
active=window_interval,
inside_temp=inside_temp, outside_temp=outside_temp, cd_b=0.6,
window_height=self.window_height,
opening_length=self.opening_distance,
number_of_windows=self.windows_number,
)
elif self.ventilation_type == "no-ventilation":
ventilation = models.AirChange(active=always_on, air_exch=0.)
else:

View file

@ -51,7 +51,7 @@ Beta v1.0.0 <span style="float:right; font-weight:bold">Please send feedback to
</div>
<div id="DIVnatural_ventilation" style="display:none">
Number of windows: <input type="number" id="windows_number" name="windows_number" min="0"><br>
Number of windows: <input type="number" id="windows_number" name="windows_number" min="1"><br>
Height of window: <input type="number" step=0.01 id="window_height" name="window_height" placeholder="meters" min="0"><br>
Width of window: <input type="number" step=0.01 id="window_width" name="window_width" placeholder="meters" min="0"><br>
Opening distance: <input type="number" step=0.01 id="opening_distance" name="opening_distance" placeholder="meters" min="0"><br>

View file

@ -208,14 +208,24 @@ class WindowOpening(Ventilation):
#: The interval in which the window is open.
active: Interval
inside_temp: PiecewiseConstant #: The temperature inside the room (Kelvin)
outside_temp: PiecewiseConstant #: The temperature outside of the window (Kelvin)
#: The temperature inside the room (Kelvin).
inside_temp: PiecewiseConstant
window_height: float #: The height of the window
#: The temperature outside of the window (Kelvin).
outside_temp: PiecewiseConstant
opening_length: float #: The length of the opening-gap when the window is open
#: The height of the window.
window_height: float
cd_b: float = 0.6 #: Discharge coefficient: what portion effective area is used to exchange air (0 <= cd_b <= 1)
#: The length of the opening-gap when the window is open
opening_length: float
#: 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)
cd_b: float = 0.6
def transition_times(self) -> typing.Set[float]:
transitions = super().transition_times()
@ -228,13 +238,14 @@ class WindowOpening(Ventilation):
if not self.active.triggered(time):
return 0.
inside_temp = self.inside_temp.value(time)
outside_temp = self.outside_temp.value(time)
# Reminder, no dependence on time in the resulting calculation.
temp_delta = abs(self.inside_temp.value(time) -
self.outside_temp.value(time)) / self.outside_temp.value(time)
temp_delta = abs(inside_temp - outside_temp) / outside_temp
root = np.sqrt(9.81 * self.window_height * temp_delta)
return (3600 / (3 * room.volume)) * self.cd_b * self.window_height * self.opening_length * root
window_area = self.window_height * self.opening_length * self.number_of_windows
return (3600 / (3 * room.volume)) * self.cd_b * window_area * root
@dataclass(frozen=True)

View file

@ -0,0 +1,25 @@
import dataclasses
import pytest
from cara import models
@pytest.fixture
def baseline_window():
return models.WindowOpening(
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,
)
def test_number_of_windows(baseline_window):
room = models.Room(75)
two_windows = dataclasses.replace(baseline_window, number_of_windows=2)
one_window_exchange = baseline_window.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