Implement vectorisation support for the ventilation schemes.

This commit is contained in:
Phil Elson 2021-03-28 07:32:42 +02:00
parent 9b836a6507
commit e4e44bddd5
2 changed files with 51 additions and 12 deletions

View file

@ -44,10 +44,17 @@ else:
from .dataclass_utils import nested_replace
# Define types for items supporting vectorisation. In the future this may be replaced
# by ``np.ndarray[<type>]`` once/if that syntax is supported. Note that vectorization
# implies 1d arrays: multi-dimensional arrays are not supported.
_VectorisedFloat = typing.Union[float, np.ndarray]
_VectorisedInt = typing.Union[int, np.ndarray]
@dataclass(frozen=True)
class Room:
# The total volume of the room
volume: float
#: The total volume of the room
volume: _VectorisedFloat
Time_t = typing.TypeVar('Time_t', float, int)
@ -185,7 +192,7 @@ class _VentilationBase:
def transition_times(self) -> typing.Set[float]:
raise NotImplementedError("Subclass must implement")
def air_exchange(self, room: Room, time: float) -> float:
def air_exchange(self, room: Room, time: float) -> _VectorisedFloat:
"""
Returns the rate at which air is being exchanged in the given room
at a given time (in hours).
@ -224,13 +231,15 @@ class MultipleVentilation(_VentilationBase):
transitions.update(ventilation.transition_times())
return transitions
def air_exchange(self, room: Room, time: float) -> float:
def air_exchange(self, room: Room, time: float) -> _VectorisedFloat:
"""
Returns the rate at which air is being exchanged in the given room
at a given time (in hours).
"""
return sum([ventilation.air_exchange(room, time)
for ventilation in self.ventilations])
return np.array([
ventilation.air_exchange(room, time)
for ventilation in self.ventilations
]).sum(axis=0)
@dataclass(frozen=True)
@ -271,7 +280,7 @@ class WindowOpening(Ventilation):
transitions.update(self.outside_temp.transition_times)
return transitions
def air_exchange(self, room: Room, time: float) -> float:
def air_exchange(self, room: Room, time: float) -> _VectorisedFloat:
# If the window is shut, no air is being exchanged.
if not self.active.triggered(time):
return 0.
@ -356,7 +365,7 @@ class HEPAFilter(Ventilation):
# in m^3/h
q_air_mech: float
def air_exchange(self, room: Room, time: float) -> float:
def air_exchange(self, room: Room, time: float) -> _VectorisedFloat:
# If the HEPA is off, no air is being exchanged.
if not self.active.triggered(time):
return 0.
@ -373,7 +382,7 @@ class HVACMechanical(Ventilation):
# in m^3/h
q_air_mech: float
def air_exchange(self, room: Room, time: float) -> float:
def air_exchange(self, room: Room, time: float) -> _VectorisedFloat:
# If the HVAC is off, no air is being exchanged.
if not self.active.triggered(time):
return 0.
@ -388,9 +397,9 @@ class AirChange(Ventilation):
#: The rate (in h^-1) at which the ventilation exchanges all the air
# of the room (when switched on)
air_exch: float
air_exch: _VectorisedFloat
def air_exchange(self, room: Room, time: float) -> float:
def air_exchange(self, room: Room, time: float) -> _VectorisedFloat:
# No dependence on the room volume.
# If off, no air is being exchanged.
if not self.active.triggered(time):

View file

@ -1,7 +1,8 @@
import dataclasses
import pytest
import numpy as np
import numpy.testing as npt
import pytest
from cara import models
@ -59,3 +60,32 @@ def test_sliding_window(baseline_slidingwindow):
room = models.Room(75)
assert baseline_slidingwindow.discharge_coefficient == 0.6
def test_multiple(baseline_slidingwindow, baseline_hingedwindow):
v = models.MultipleVentilation([baseline_hingedwindow, baseline_slidingwindow])
room = models.Room(75)
t = 1
assert v.air_exchange(room, t) == (
baseline_slidingwindow.air_exchange(room, t) +
baseline_hingedwindow.air_exchange(room, t)
)
def test_multiple_vectorisation():
interval = models.SpecificInterval(((0, 4), (5, 9)))
v1 = models.AirChange(interval, np.arange(10))
v2 = models.AirChange(interval, np.arange(5))
v3 = models.AirChange(interval, 10)
room = models.Room(75)
t_active = 2
t_inactive = 4.5
assert models.MultipleVentilation([v1, v2]).air_exchange(room, t_inactive) == 0
with pytest.raises(ValueError, match='operands could not be broadcast together'):
models.MultipleVentilation([v1, v2]).air_exchange(room, t_active)
r = models.MultipleVentilation([v2, v3]).air_exchange(room, t_active)
assert isinstance(r, np.ndarray)
assert r == np.array([10, 11, 12, 13, 14])