diff --git a/caimira/apps/calculator/co2_model_generator.py b/caimira/apps/calculator/co2_model_generator.py index de04a666..e8a054ca 100644 --- a/caimira/apps/calculator/co2_model_generator.py +++ b/caimira/apps/calculator/co2_model_generator.py @@ -22,7 +22,7 @@ class CO2FormData(FormData): CO2_data: dict fitting_ventilation_states: list fitting_ventilation_type: str - room_capacity: int + room_capacity: typing.Optional[int] #: The default values for undefined fields. Note that the defaults here #: and the defaults in the html form must not be contradictory. @@ -46,7 +46,7 @@ class CO2FormData(FormData): 'infected_lunch_start': '12:30', 'infected_people': 1, 'infected_start': '08:30', - 'room_capacity': 10, + 'room_capacity': None, 'room_volume': NO_DEFAULT, 'specific_breaks': '{}', 'total_people': NO_DEFAULT, @@ -65,10 +65,11 @@ class CO2FormData(FormData): self.validate_population_parameters() # Validate room capacity - if type(self.room_capacity) is not int: - raise TypeError(f'The room capacity should be a valid integer (> 0). Got {type(self.room_capacity)}.') - if self.room_capacity <= 0: - raise TypeError(f'The room capacity should be a valid integer (> 0). Got {self.room_capacity}.') + if self.room_capacity: + if type(self.room_capacity) is not int: + raise TypeError(f'The room capacity should be a valid integer (> 0). Got {type(self.room_capacity)}.') + if self.room_capacity <= 0: + raise TypeError(f'The room capacity should be a valid integer (> 0). Got {self.room_capacity}.') # Validate specific inputs - breaks (exposed and infected) if self.specific_breaks != {}: diff --git a/caimira/apps/calculator/form_data.py b/caimira/apps/calculator/form_data.py index a0a96b67..7f6c8914 100644 --- a/caimira/apps/calculator/form_data.py +++ b/caimira/apps/calculator/form_data.py @@ -410,6 +410,12 @@ def _safe_int_cast(value) -> int: return int(value) else: raise TypeError(f"Unable to safely cast {value} ({type(value)} type) to int") + + +def _safe_optional_int_cast(value) -> typing.Optional[int]: + if value is None or value == '': + return None + return _safe_int_cast(value) #: Mapping of field name to a callable which can convert values from form @@ -427,6 +433,8 @@ def cast_class_fields(cls): _CAST_RULES_NATIVE_TO_FORM_ARG[_field.name] = time_minutes_to_string elif _field.type is int: _CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = _safe_int_cast + elif _field.type is typing.Optional[int]: + _CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = _safe_optional_int_cast elif _field.type is float: _CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = float elif _field.type is bool: diff --git a/caimira/models.py b/caimira/models.py index 4c4f54a3..3fe58e22 100644 --- a/caimira/models.py +++ b/caimira/models.py @@ -218,7 +218,7 @@ class Room: humidity: _VectorisedFloat = 0.5 #: The maximum occupation of the room - design limit - capacity: float = 10 + capacity: typing.Optional[int] = None @dataclass(frozen=True) @@ -1596,11 +1596,10 @@ class CO2DataModel: the_predictive_CO2 = self.CO2_concentrations_from_params(the_CO2_concentration_model) # Ventilation in L/s - flow_rates_l_s = [vent / 3600 * self.room.volume * 1000 - for vent in ventilation_values] # 1m^3 = 1000L + flow_rates_l_s = [vent / 3600 * self.room.volume * 1000 for vent in ventilation_values] # 1m^3 = 1000L # Ventilation in L/s/person - flow_rates_l_s_p = [flow_rate / self.room.capacity for flow_rate in flow_rates_l_s] + flow_rates_l_s_p = [flow_rate / self.room.capacity for flow_rate in flow_rates_l_s] if self.room.capacity else None return { "exhalation_rate": exhalation_rate,