Implement vectorisation support for the ventilation schemes.
This commit is contained in:
parent
9b836a6507
commit
e4e44bddd5
2 changed files with 51 additions and 12 deletions
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
Loading…
Reference in a new issue