diff --git a/cara/apps/calculator/model_generator.py b/cara/apps/calculator/model_generator.py index 5a26afd0..6946d44f 100644 --- a/cara/apps/calculator/model_generator.py +++ b/cara/apps/calculator/model_generator.py @@ -83,8 +83,32 @@ class FormData: return model_from_form(self, tmp_raw_form_data) def ventilation(self) -> models.Ventilation: - # TODO - pass + # 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 == '10 min / 2h': + period, duration = 120, 10 + else: + period, duration = 120, 120 + # I multiply the opening width by the number of windows to simulate the correct window area + if self.event_type == 'single_event': + month_number = int(self.single_event_date.split('/')[1]) + month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][month_number - 1] + else: + month = self.recurrent_event_month[:3] + + inside_temp = models.PiecewiseConstant((0, 24), (293,)) + outside_temp = models.GenevaTemperatures[month] + + 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) + else: + q_air_mech = self.air_changes * self.room_volume + self.air_supply + ventilation = models.HEPAFilter(active=models.PeriodicInterval(period=120, duration=120), + q_air_mech=q_air_mech) + + return ventilation def present_interval(self) -> models.Interval: coffee_period = (self.activity_finish - self.activity_start) // self.coffee_breaks @@ -143,36 +167,18 @@ def model_from_form(form: FormData, tmp_raw_form_data) -> models.Model: d['lunch_finish'] = '13:00' # Initializes room with volume either given directly or as product of area and height - if d['volume_type'] == 'room_volume': - volume = int(d['room_volume']) + if form.volume_type == 'room_volume': + volume = form.room_volume else: - volume = int(float(d['floor_area']) * form.ceiling_height) + volume = form.floor_area * form.ceiling_height room = models.Room(volume=volume) - # Initializes a ventilation instance as a window if 'natural' is selected, or as a HEPA-filter otherwise - if d['ventilation_type'] == 'natural': - if d['windows_open'] == 'always': - period, duration = 120, 120 - else: - period, duration = 15, 120 - # 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=models.PiecewiseConstant((0, 24), (293, )), - # TODO: This should be based on the month etc. - outside_temp=models.PiecewiseConstant((0, 24), (283, )), - cd_b=0.6, - window_height=float(d['window_height']), - opening_length=float(d['opening_distance']) * int(d['windows_number'])) - else: - q_air_mech = float(d['air_changes']) if d['air_type'] == 'air_changes' else float(d['air_supply']) - ventilation = models.HEPAFilter(active=models.PeriodicInterval(period=120, duration=120), - q_air_mech=q_air_mech) - # Initializes the virus as SARS_Cov_2 virus = models.Virus.types['SARS_CoV_2'] # Initializes a mask of type 1 if mask wearing is "continuous", otherwise instantiates the mask attribute as # the "No mask"-mask + # TODO: figure out the possible values of mask_wearing in the form mask = models.Mask.types['Type I' if d['mask_wearing'] == "Continuous" else 'No mask'] # A dictionary containing the mapping of activities listed in the UI to the activity level and expiration level @@ -183,19 +189,19 @@ def model_from_form(form: FormData, tmp_raw_form_data) -> models.Model: 'Training': (('Light exercise', 'Talking'), ('Seated', 'Whispering')), 'Workshop': (('Light exercise', 'Talking'), ('Light exercise', 'Talking'))} - (infected_activity, infected_expiration), (exposed_activity, exposed_expiration) = activity_dict[d['activity_type']] + (infected_activity, infected_expiration), (exposed_activity, exposed_expiration) = activity_dict[form.activity_type.capitalize()] # Converts these strings to Activity and Expiration instances infected_activity, exposed_activity = models.Activity.types[infected_activity], models.Activity.types[exposed_activity] infected_expiration, exposed_expiration = models.Expiration.types[infected_expiration], models.Expiration.types[exposed_expiration] - infected_occupants = int(d['infected_people']) + infected_occupants = form.infected_people # Defines the number of exposed occupants as the total number of occupants minus the number of infected occupants - exposed_occupants = int(d['total_people']) - infected_occupants + exposed_occupants = form.total_people - infected_occupants # Initializes and returns a model with the attributes defined above return models.Model( room=room, - ventilation=ventilation, + ventilation=form.ventilation(), infected=models.InfectedPerson( virus=virus, presence=form.present_interval(), diff --git a/cara/tests/apps/calculator/test_model_generator.py b/cara/tests/apps/calculator/test_model_generator.py index a13018cc..06a0dde2 100644 --- a/cara/tests/apps/calculator/test_model_generator.py +++ b/cara/tests/apps/calculator/test_model_generator.py @@ -1,7 +1,8 @@ import pytest from cara.apps.calculator import model_generator - +from cara import models +import numpy as np @pytest.fixture def baseline_form_data(): @@ -20,9 +21,23 @@ def test_model_from_dict(baseline_form_data): def test_ventilation(baseline_form): - ventilation = baseline_form.ventilation() - # TODO: - # assert ventilation == cara.models.Ventilation() + room = models.Room(75) + window = models.WindowOpening( + active=models.PeriodicInterval(period=120, duration=10), + inside_temp=models.PiecewiseConstant((0, 24), (293,)), + outside_temp=models.GenevaTemperatures['Dec'], + cd_b=0.6, window_height=1.6, opening_length=0.6, + ) + baseline_form.ventilation_type = 'natural' + baseline_form.windows_open = '10 min / 2h' + baseline_form.event_type = 'recurrent_event' + baseline_form.recurrent_event_month = 'December' + baseline_form.window_height = 1.6 + baseline_form.opening_distance = 0.6 + + ts = np.linspace(8, 16, 100) + np.testing.assert_allclose([window.air_exchange(room, t) for t in ts], + [baseline_form.ventilation().air_exchange(room, t) for t in ts]) def test_present_intervals(baseline_form):