diff --git a/city_model_structure/building_demand/internal_gain.py b/city_model_structure/building_demand/internal_gain.py index 9245488f..d4e9825e 100644 --- a/city_model_structure/building_demand/internal_gain.py +++ b/city_model_structure/building_demand/internal_gain.py @@ -110,8 +110,10 @@ class InternalGain: @property def schedules(self) -> Union[None, List[Schedule]]: """ - Get internal gain schedule - dataType = fraction + Get internal gain schedules + data type = any number + time step = 1 hour + time range = 1 day :return: [Schedule] """ return self._schedules @@ -119,8 +121,10 @@ class InternalGain: @schedules.setter def schedules(self, value): """ - Set internal gain schedule - dataType = fraction + Set internal gain schedules + data type = any number + time step = 1 hour + time range = 1 day :param value: [Schedule] """ self._schedules = value diff --git a/city_model_structure/building_demand/thermal_zone.py b/city_model_structure/building_demand/thermal_zone.py index c93675cb..597f4742 100644 --- a/city_model_structure/building_demand/thermal_zone.py +++ b/city_model_structure/building_demand/thermal_zone.py @@ -7,8 +7,8 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord """ import uuid -import sys import copy +import numpy from typing import List, Union, TypeVar from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.appliances import Appliances @@ -16,6 +16,7 @@ from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.internal_gain import InternalGain from city_model_structure.building_demand.thermal_control import ThermalControl from city_model_structure.energy_systems.hvac_system import HvacSystem +from city_model_structure.attributes.schedule import Schedule import helpers.constants as cte ThermalBoundary = TypeVar('ThermalBoundary') @@ -26,7 +27,7 @@ class ThermalZone: """ ThermalZone class """ - def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area): + def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage=None): self._id = None self._parent_internal_zone = parent_internal_zone self._footprint_area = footprint_area @@ -41,8 +42,7 @@ class ThermalZone: self._view_factors_matrix = None self._total_floor_area = None - self._usage = None - self._not_detailed_source_mean_annual_internal_gains = None + self._usage = usage self._hours_day = None self._days_year = None self._mechanical_air_change = None @@ -51,6 +51,21 @@ class ThermalZone: self._appliances = None self._internal_gains = None self._thermal_control = None + # example 70-office_30-residential + if usage is None: + self._usage_zones = copy.deepcopy(parent_internal_zone.usage_zones) + else: + values = usage.split('_') + usages = [] + for value in values: + usages.append(value.split('-')) + self._usage_zones = [] + for parent_usage_zone in parent_internal_zone.usage_zones: + for value in usages: + if parent_usage_zone.usage == value[1]: + new_usage_zone = copy.deepcopy(parent_usage_zone) + new_usage_zone.percentage = float(value[0])/100 + self._usage_zones.append(new_usage_zone) @property def id(self): @@ -217,24 +232,15 @@ class ThermalZone: Get thermal zone usage :return: None or str """ - if self._parent_internal_zone.usage_zones is None: - return None if self._usage is None: + if self._parent_internal_zone.usage_zones is None: + return None self._usage = '' for usage_zone in self._parent_internal_zone.usage_zones: - self._usage += str(round(usage_zone.percentage) * 100) + '_' + usage_zone.usage + '_' + self._usage += str(round(usage_zone.percentage) * 100) + '-' + usage_zone.usage + '_' self._usage = self._usage[:-1] return self._usage - @usage.setter - def usage(self, value): - """ - Set thermal zone usage - :param value: str - """ - if value is not None: - self._usage = str(value) - @staticmethod def _get_schedule_of_day(requested_day_type, schedules): for schedule in schedules: @@ -243,158 +249,57 @@ class ThermalZone: return schedule return None - @property - def not_detailed_source_mean_annual_internal_gains(self) -> Union[None, List[InternalGain]]: - """ - Get thermal zone internal gains with unknown energy source - :return: [InternalGain] - """ - if self._parent_internal_zone.usage_zones is None: - return None - if self._not_detailed_source_mean_annual_internal_gains is None: - _grouped_internal_gain = InternalGain() - _grouped_internal_gain.type = 'grouped internal gains for thermal zone' - _average_internal_gain = 0 - _convective_part = 0 - _radiative_part = 0 - _latent_part = 0 - for _usage_zone in self._parent_internal_zone.usage_zones: - if _usage_zone.not_detailed_source_mean_annual_internal_gains is None: - return None - for _internal_gain in _usage_zone.not_detailed_source_mean_annual_internal_gains: - _average_internal_gain += _internal_gain.average_internal_gain - _convective_part += _internal_gain.average_internal_gain * _internal_gain.convective_fraction - _radiative_part += _internal_gain.average_internal_gain * _internal_gain.radiative_fraction - _latent_part += _internal_gain.average_internal_gain * _internal_gain.latent_fraction - - _grouped_internal_gain.average_internal_gain = _average_internal_gain - if _average_internal_gain > 0: - _grouped_internal_gain.convective_fraction = _convective_part / _average_internal_gain - _grouped_internal_gain.radiative_fraction = _radiative_part / _average_internal_gain - _grouped_internal_gain.latent_fraction = _latent_part / _average_internal_gain - - _internal_gains_reference = \ - self._parent_internal_zone.usage_zones[0].not_detailed_source_mean_annual_internal_gains[0] - if _internal_gains_reference.schedules is not None: - day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY] - schedule_of_days = [] - for i_day in range(0, 7): - schedule_of_day = \ - copy.deepcopy(self._get_schedule_of_day(day_types[i_day], _internal_gains_reference.schedules)) - if schedule_of_day is None: - sys.stderr.write(f'Error. Not found requested day type when generating internal gains schedules ' - f'in thermal_zone.\n') - schedule_of_day.day_types = [day_types[i_day]] - new_values = [] - for i_value in range(0, len(_internal_gains_reference.schedules[0].values)): - _new_value = 0 - for _usage_zone in self._parent_internal_zone.usage_zones: - for _internal_gain in _usage_zone.not_detailed_source_mean_annual_internal_gains: - _value = self._get_schedule_of_day(day_types[i_day], _internal_gain.schedules) - if _value is None: - sys.stderr.write(f'Error. Not found requested day type when generating internal gains schedules ' - f'in thermal_zone.\n') - _value = _value.values[i_value] - _new_value += _usage_zone.percentage * _value \ - / len(_usage_zone.not_detailed_source_mean_annual_internal_gains) - new_values.append(_new_value) - schedule_of_day.values = new_values - schedule_of_days.append(schedule_of_day) - _grouped_internal_gain.schedules = schedule_of_days - else: - _grouped_internal_gain.convective_fraction = 0 - _grouped_internal_gain.radiative_fraction = 0 - _grouped_internal_gain.latent_fraction = 0 - - self._not_detailed_source_mean_annual_internal_gains = [_grouped_internal_gain] - return self._not_detailed_source_mean_annual_internal_gains - - @not_detailed_source_mean_annual_internal_gains.setter - def not_detailed_source_mean_annual_internal_gains(self, value): - """ - Set thermal zone internal gains with unknown energy source - :param value: [InternalGain] - """ - self._not_detailed_source_mean_annual_internal_gains = value - @property def hours_day(self) -> Union[None, float]: """ Get thermal zone usage hours per day :return: None or float """ - if self._parent_internal_zone.usage_zones is None: + if self._usage_zones is None: return None if self._hours_day is None: self._hours_day = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: self._hours_day += usage_zone.percentage * usage_zone.hours_day return self._hours_day - @hours_day.setter - def hours_day(self, value): - """ - Set thermal zone usage hours per day - :param value: float - """ - if value is not None: - self._hours_day = float(value) - @property def days_year(self) -> Union[None, float]: """ Get thermal zone usage days per year :return: None or float """ - if self._parent_internal_zone.usage_zones is None: + if self._usage_zones is None: return None if self._days_year is None: self._days_year = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: self._days_year += usage_zone.percentage * usage_zone.days_year return self._days_year - @days_year.setter - def days_year(self, value): - """ - Set thermal zone usage days per year - :param value: float - """ - if value is not None: - self._days_year = float(value) - @property def mechanical_air_change(self) -> Union[None, float]: """ Get thermal zone mechanical air change in air change per hour (ACH) :return: None or float """ - if self._parent_internal_zone.usage_zones is None: + if self._usage_zones is None: return None if self._mechanical_air_change is None: self._mechanical_air_change = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: if usage_zone.mechanical_air_change is None: return None self._mechanical_air_change += usage_zone.percentage * usage_zone.mechanical_air_change return self._mechanical_air_change - @mechanical_air_change.setter - def mechanical_air_change(self, value): - """ - Set thermal zone mechanical air change in air change per hour (ACH) - :param value: float - """ - if value is not None: - self._mechanical_air_change = float(value) - @property def occupancy(self) -> Union[None, Occupancy]: """ Get occupancy in the thermal zone :return: None or Occupancy """ - if self._parent_internal_zone.usage_zones is None: + if self._usage_zones is None: return None if self._occupancy is None: self._occupancy = Occupancy() @@ -402,7 +307,7 @@ class ThermalZone: _convective_part = 0 _radiative_part = 0 _latent_part = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: if usage_zone.occupancy is None: return None _occupancy_density += usage_zone.percentage * usage_zone.occupancy.occupancy_density @@ -415,7 +320,7 @@ class ThermalZone: self._occupancy.sensible_radiative_internal_gain = _radiative_part self._occupancy.latent_internal_gain = _latent_part - _occupancy_reference = self._parent_internal_zone.usage_zones[0].occupancy + _occupancy_reference = self._usage_zones[0].occupancy if _occupancy_reference.occupancy_schedules is not None: _schedules = [] for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)): @@ -423,7 +328,7 @@ class ThermalZone: new_values = [] for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)): _new_value = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: _new_value += usage_zone.percentage * usage_zone.occupancy.occupancy_schedules[i_schedule].values[i_value] new_values.append(_new_value) schedule.values = new_values @@ -431,21 +336,13 @@ class ThermalZone: self._occupancy.occupancy_schedules = _schedules return self._occupancy - @occupancy.setter - def occupancy(self, value): - """ - Set occupancy in the thermal zone - :param value: Occupancy - """ - self._occupancy = value - @property def lighting(self) -> Union[None, Lighting]: """ Get lighting information :return: None or Lighting """ - if self._parent_internal_zone.usage_zones is None: + if self._usage_zones is None: return None if self._lighting is None: self._lighting = Lighting() @@ -453,7 +350,7 @@ class ThermalZone: _convective_part = 0 _radiative_part = 0 _latent_part = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: if usage_zone.lighting is None: return None _lighting_density += usage_zone.percentage * usage_zone.lighting.density @@ -474,7 +371,7 @@ class ThermalZone: self._lighting.radiative_fraction = 0 self._lighting.latent_fraction = 0 - _lighting_reference = self._parent_internal_zone.usage_zones[0].lighting + _lighting_reference = self._usage_zones[0].lighting if _lighting_reference.schedules is not None: _schedules = [] for i_schedule in range(0, len(_lighting_reference.schedules)): @@ -482,7 +379,7 @@ class ThermalZone: new_values = [] for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)): _new_value = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: _new_value += usage_zone.percentage * usage_zone.lighting.schedules[i_schedule].values[i_value] new_values.append(_new_value) schedule.values = new_values @@ -490,21 +387,13 @@ class ThermalZone: self._lighting.schedules = _schedules return self._lighting - @lighting.setter - def lighting(self, value): - """ - Set lighting information - :param value: Lighting - """ - self._lighting = value - @property def appliances(self) -> Union[None, Appliances]: """ Get appliances information :return: None or Appliances """ - if self._parent_internal_zone.usage_zones is None: + if self._usage_zones is None: return None if self._appliances is None: self._appliances = Appliances() @@ -512,7 +401,7 @@ class ThermalZone: _convective_part = 0 _radiative_part = 0 _latent_part = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: if usage_zone.appliances is None: return None _appliances_density += usage_zone.percentage * usage_zone.appliances.density @@ -533,7 +422,7 @@ class ThermalZone: self._appliances.radiative_fraction = 0 self._appliances.latent_fraction = 0 - _appliances_reference = self._parent_internal_zone.usage_zones[0].appliances + _appliances_reference = self._usage_zones[0].appliances if _appliances_reference.schedules is not None: _schedules = [] for i_schedule in range(0, len(_appliances_reference.schedules)): @@ -541,7 +430,7 @@ class ThermalZone: new_values = [] for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)): _new_value = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: _new_value += usage_zone.percentage * usage_zone.appliances.schedules[i_schedule].values[i_value] new_values.append(_new_value) schedule.values = new_values @@ -549,72 +438,62 @@ class ThermalZone: self._appliances.schedules = _schedules return self._appliances - @appliances.setter - def appliances(self, value): - """ - Set appliances information - :param value: Appliances - """ - self._appliances = value - - @staticmethod - def _add_internal_gain(internal_gain_type, _internal_gain): - _internal_gain.average_internal_gain = internal_gain_type.density - _internal_gain.latent_fraction = internal_gain_type.latent_fraction - _internal_gain.radiative_fraction = internal_gain_type.radiative_fraction - _internal_gain.convective_fraction = internal_gain_type.convective_fraction - _internal_gain.schedules = internal_gain_type.schedules - - def get_internal_gains(self) -> List[InternalGain]: + @property + def internal_gains(self) -> Union[None, List[InternalGain]]: """ Calculates and returns the list of all internal gains defined :return: [InternalGain] """ - if self.not_detailed_source_mean_annual_internal_gains is not None: - self._internal_gains = [] - for _internal_gain in self.not_detailed_source_mean_annual_internal_gains: - self._internal_gains.append(_internal_gain) - - if self.occupancy is not None: - if self.occupancy.latent_internal_gain is not None: - _internal_gain = InternalGain() - _internal_gain.type = cte.OCCUPANCY - _total_heat_gain = (self.occupancy.sensible_convective_internal_gain - + self.occupancy.sensible_radiative_internal_gain - + self.occupancy.latent_internal_gain) - _internal_gain.average_internal_gain = _total_heat_gain - if _total_heat_gain > 0: - _internal_gain.latent_fraction = self.occupancy.latent_internal_gain / _total_heat_gain - _internal_gain.radiative_fraction = self.occupancy.sensible_radiative_internal_gain / _total_heat_gain - _internal_gain.convective_fraction = self.occupancy.sensible_convective_internal_gain / _total_heat_gain - else: - _internal_gain.latent_fraction = 0 - _internal_gain.radiative_fraction = 0 - _internal_gain.convective_fraction = 0 - _internal_gain.schedules = self.occupancy.occupancy_schedules - if self._internal_gains is not None: - self._internal_gains.append(_internal_gain) - else: - self._internal_gains = [_internal_gain] - - if self.lighting is not None: + if self._usage_zones is None: + return None + if self._internal_gains is None: _internal_gain = InternalGain() - _internal_gain.type = cte.LIGHTING - self._add_internal_gain(self.lighting, _internal_gain) - if self._internal_gains is not None: - self._internal_gains.append(_internal_gain) - else: - self._internal_gains = [_internal_gain] + _days = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY] + _average_internal_gain = 0 + _convective_fraction = 0 + _radiative_fraction = 0 + _latent_fraction = 0 + _schedules = None + _base_schedule = Schedule() + _base_schedule.type = cte.INTERNAL_GAINS + _base_schedule.time_range = cte.DAY + _base_schedule.time_step = cte.HOUR + _base_schedule.data_type = cte.ANY_NUMBER + _schedules_defined = True + values = numpy.zeros(24, 8) + for usage_zone in self._usage_zones: + for internal_gain in usage_zone.internal_gains: + _average_internal_gain += internal_gain.average_internal_gain * usage_zone.percentage + _convective_fraction += internal_gain.average_internal_gain * usage_zone.percentage \ + * internal_gain.convective_fraction + _radiative_fraction += internal_gain.average_internal_gain * usage_zone.percentage \ + * internal_gain.radiative_fraction + _latent_fraction += internal_gain.average_internal_gain * usage_zone.percentage \ + * internal_gain.latent_fraction + for usage_zone in self._usage_zones: + for internal_gain in usage_zone.internal_gains: + if len(internal_gain.schedules) == 0: + _schedules_defined = False + break + for day, _schedule in enumerate(internal_gain.schedules): + for v, value in enumerate(_schedule.values): + values[v, day] += value * usage_zone.percentage - if self.appliances is not None: - _internal_gain = InternalGain() - _internal_gain.type = cte.APPLIANCES - self._add_internal_gain(self.appliances, _internal_gain) - if self._internal_gains is not None: - self._internal_gains.append(_internal_gain) - else: - self._internal_gains = [_internal_gain] + if _schedules_defined: + _schedules = [] + for day in range(0, len(_days)): + _schedule = copy.deepcopy(_base_schedule) + _schedule.day_types = [_days[day]] + _schedule.values = values[:day] + _schedules.append(_schedule) + _internal_gain.convective_fraction = _convective_fraction / _average_internal_gain + _internal_gain.radiative_fraction = _radiative_fraction / _average_internal_gain + _internal_gain.latent_fraction = _latent_fraction / _average_internal_gain + _internal_gain.average_internal_gain = _average_internal_gain + _internal_gain.type = 'mean_value' + _internal_gain.schedules = _schedules + self._internal_gains = [_internal_gain] return self._internal_gains @property @@ -623,14 +502,14 @@ class ThermalZone: Get thermal control of this thermal zone :return: None or ThermalControl """ - if self._parent_internal_zone.usage_zones is None: + if self._usage_zones is None: return None if self._thermal_control is None: self._thermal_control = ThermalControl() _mean_heating_set_point = 0 _heating_set_back = 0 _mean_cooling_set_point = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: _mean_heating_set_point += usage_zone.percentage * usage_zone.thermal_control.mean_heating_set_point _heating_set_back += usage_zone.percentage * usage_zone.thermal_control.heating_set_back _mean_cooling_set_point += usage_zone.percentage * usage_zone.thermal_control.mean_cooling_set_point @@ -638,7 +517,7 @@ class ThermalZone: self._thermal_control.heating_set_back = _heating_set_back self._thermal_control.mean_cooling_set_point = _mean_cooling_set_point - _thermal_control_reference = self._parent_internal_zone.usage_zones[0].thermal_control + _thermal_control_reference = self._usage_zones[0].thermal_control _types_reference = [] if _thermal_control_reference.hvac_availability_schedules is not None: _types_reference.append([cte.HVAC_AVAILABILITY, _thermal_control_reference.hvac_availability_schedules]) @@ -655,7 +534,7 @@ class ThermalZone: new_values = [] for i_value in range(0, len(_schedule_type[i_schedule].values)): _new_value = 0 - for usage_zone in self._parent_internal_zone.usage_zones: + for usage_zone in self._usage_zones: if _types_reference[i_type][0] == cte.HVAC_AVAILABILITY: _new_value += usage_zone.percentage * \ usage_zone.thermal_control.hvac_availability_schedules[i_schedule].values[i_value] @@ -677,14 +556,6 @@ class ThermalZone: return self._thermal_control - @thermal_control.setter - def thermal_control(self, value): - """ - Set thermal control for this thermal zone - :param value: ThermalControl - """ - self._thermal_control = value - @property def total_floor_area(self): """ diff --git a/city_model_structure/building_demand/usage_zone.py b/city_model_structure/building_demand/usage_zone.py index 74ea89f5..781fbf0f 100644 --- a/city_model_structure/building_demand/usage_zone.py +++ b/city_model_structure/building_demand/usage_zone.py @@ -6,24 +6,23 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributors: Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ import uuid -from typing import List, Union -from city_model_structure.building_demand.internal_gain import InternalGain +from typing import Union, List from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.appliances import Appliances from city_model_structure.building_demand.thermal_control import ThermalControl -import helpers.constants as cte +from city_model_structure.building_demand.internal_gain import InternalGain class UsageZone: """ UsageZone class """ - def __init__(self, not_detailed_source_mean_annual_internal_gains=None): + def __init__(self): self._id = None self._usage = None self._percentage = None - self._not_detailed_source_mean_annual_internal_gains = not_detailed_source_mean_annual_internal_gains + self._internal_gains = None self._hours_day = None self._days_year = None # self._electrical_app_average_consumption_sqm_year = None @@ -32,7 +31,6 @@ class UsageZone: self._lighting = None self._appliances = None self._thermal_control = None - self._internal_gains = None @property def id(self): @@ -78,6 +76,22 @@ class UsageZone: if value is not None: self._percentage = float(value) + @property + def internal_gains(self) -> List[InternalGain]: + """ + Get usage zone internal gains + :return: [InternalGain] + """ + return self._internal_gains + + @internal_gains.setter + def internal_gains(self, value): + """ + Set usage zone internal gains + :param value: [InternalGain] + """ + self._internal_gains = value + @property def hours_day(self) -> Union[None, float]: """ @@ -192,64 +206,3 @@ class UsageZone: :param value: ThermalControl """ self._thermal_control = value - - @property - def internal_gains(self) -> List[InternalGain]: - """ - Calculates and returns the list of all internal gains defined - :return: [InternalGain] - """ - if self._not_detailed_source_mean_annual_internal_gains is not None: - self._internal_gains = [] - for _internal_gain in self._not_detailed_source_mean_annual_internal_gains: - self._internal_gains.append(_internal_gain) - - if self.occupancy is not None: - if self.occupancy.latent_internal_gain is not None: - _internal_gain = InternalGain() - _internal_gain.type = cte.OCCUPANCY - _total_heat_gain = (self.occupancy.sensible_convective_internal_gain - + self.occupancy.sensible_radiative_internal_gain - + self.occupancy.latent_internal_gain) - _internal_gain.average_internal_gain = _total_heat_gain - if _total_heat_gain > 0: - _internal_gain.latent_fraction = self.occupancy.latent_internal_gain / _total_heat_gain - _internal_gain.radiative_fraction = self.occupancy.sensible_radiative_internal_gain / _total_heat_gain - _internal_gain.convective_fraction = self.occupancy.sensible_convective_internal_gain / _total_heat_gain - else: - _internal_gain.latent_fraction = 0 - _internal_gain.radiative_fraction = 0 - _internal_gain.convective_fraction = 0 - _internal_gain.schedules = self.occupancy.occupancy_schedules - if self._internal_gains is not None: - self._internal_gains.append(_internal_gain) - else: - self._internal_gains = [_internal_gain] - - if self.lighting is not None: - _internal_gain = InternalGain() - _internal_gain.type = cte.LIGHTING - self._add_internal_gain(self.lighting, _internal_gain) - if self._internal_gains is not None: - self._internal_gains.append(_internal_gain) - else: - self._internal_gains = [_internal_gain] - - if self.appliances is not None: - _internal_gain = InternalGain() - _internal_gain.type = cte.APPLIANCES - self._add_internal_gain(self.appliances, _internal_gain) - if self._internal_gains is not None: - self._internal_gains.append(_internal_gain) - else: - self._internal_gains = [_internal_gain] - - return self._internal_gains - - @staticmethod - def _add_internal_gain(internal_gain_type, _internal_gain): - _internal_gain.average_internal_gain = internal_gain_type.density - _internal_gain.latent_fraction = internal_gain_type.latent_fraction - _internal_gain.radiative_fraction = internal_gain_type.radiative_fraction - _internal_gain.convective_fraction = internal_gain_type.convective_fraction - _internal_gain.schedules = internal_gain_type.schedules diff --git a/helpers/constants.py b/helpers/constants.py index 40c2c547..1e9f0675 100644 --- a/helpers/constants.py +++ b/helpers/constants.py @@ -51,6 +51,7 @@ CONTROL_TYPE = 'control_type' CONTINUOUS = 'continuous' DISCRETE = 'discrete' CONSTANT = 'constant' +INTERNAL_GAINS = 'internal_gains' # surface types WALL = 'Wall' diff --git a/imports/usage/comnet_usage_parameters.py b/imports/usage/comnet_usage_parameters.py index 7dc9c4e9..3aa1b22b 100644 --- a/imports/usage/comnet_usage_parameters.py +++ b/imports/usage/comnet_usage_parameters.py @@ -4,10 +4,11 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ - +import copy import sys from typing import Dict import pandas as pd +import numpy import helpers.constants as cte from helpers.configuration_helper import ConfigurationHelper as ch @@ -20,6 +21,7 @@ from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.appliances import Appliances from city_model_structure.building_demand.thermal_control import ThermalControl from city_model_structure.attributes.schedule import Schedule +from city_model_structure.building_demand.internal_gain import InternalGain class ComnetUsageParameters: @@ -93,10 +95,10 @@ class ComnetUsageParameters: # occupancy _occupancy = Occupancy() value = data['occupancy'][comnet_usage][0] + _occupancy.occupancy_density = 0 if value != 0: - _occupancy.occupancy_density = value - else: - _occupancy.occupancy_density = 0 + _occupancy.occupancy_density = 1 / value + _occupancy.sensible_convective_internal_gain = data['occupancy'][comnet_usage][1] \ * ch().comnet_occupancy_sensible_convective _occupancy.sensible_radiative_internal_gain = data['occupancy'][comnet_usage][1] \ @@ -276,3 +278,67 @@ class ComnetUsageParameters: usage_zone.hours_day = total / 365 usage_zone.days_year = 365 + + @staticmethod + def _calculate_internal_gains(archetype): + + _DAYS = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY] + _number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10] + + _mean_internal_gain = InternalGain() + _mean_internal_gain.type = 'mean_value_of_internal_gains' + _base_schedule = Schedule() + _base_schedule.type = cte.INTERNAL_GAINS + _base_schedule.time_range = cte.DAY + _base_schedule.time_step = cte.HOUR + _base_schedule.data_type = cte.FRACTION + + _latent_heat_gain = archetype.occupancy.latent_internal_gain + _convective_heat_gain = archetype.occupancy.sensible_convective_internal_gain + _radiative_heat_gain = archetype.occupancy.sensible_radiative_internal_gain + _total_heat_gain = (_latent_heat_gain + _convective_heat_gain + _radiative_heat_gain) + + _schedule_values = numpy.zeros(24, 7) + _sum = 0 + for day, _schedule in enumerate(archetype.occupancy.schedules): + for v, value in enumerate(_schedule.values): + _schedule_values[v, day] = value * _total_heat_gain + _sum += value * _total_heat_gain * _number_of_days_per_type[day] + + _total_heat_gain += archetype.lighting.density + archetype.appliances.density + _latent_heat_gain += archetype.lighting.latent_fraction * archetype.lighting.density\ + + archetype.appliances.latent_fraction * archetype.appliances.density + _radiative_heat_gain = archetype.lighting.radiative_fraction * archetype.lighting.density \ + + archetype.appliances.radiative_fraction * archetype.appliances.density + _convective_heat_gain = archetype.lighting.convective_fraction * archetype.lighting.density \ + + archetype.appliances.convective_fraction * archetype.appliances.density + + for day, _schedule in enumerate(archetype.lighting.schedules): + for v, value in enumerate(_schedule.values): + _schedule_values[v, day] += value * archetype.lighting.density + _sum += value * archetype.lighting.density * _number_of_days_per_type[day] + + for day, _schedule in enumerate(archetype.appliances.schedules): + for v, value in enumerate(_schedule.values): + _schedule_values[v, day] += value * archetype.appliances.density + _sum += value * archetype.appliances.density * _number_of_days_per_type[day] + + _latent_fraction = _latent_heat_gain / _total_heat_gain + _radiative_fraction = _radiative_heat_gain / _total_heat_gain + _convective_fraction = _convective_heat_gain / _total_heat_gain + _average_internal_gain = _sum / _total_heat_gain + + _schedules = [] + for day in range(0, len(_DAYS)): + _schedule = copy.deepcopy(_base_schedule) + _schedule.day_types = [_DAYS[day]] + _schedule.values = _schedule_values[:day] + _schedules.append(_schedule) + + _mean_internal_gain.average_internal_gain = _average_internal_gain + _mean_internal_gain.latent_fraction = _latent_fraction + _mean_internal_gain.convective_fraction = _convective_fraction + _mean_internal_gain.radiative_fraction = _radiative_fraction + _mean_internal_gain.schedules = _schedules + + return [_mean_internal_gain] diff --git a/imports/usage/data_classes/usage_zone_archetype.py b/imports/usage/data_classes/usage_zone_archetype.py index e4d7a9e6..65d73449 100644 --- a/imports/usage/data_classes/usage_zone_archetype.py +++ b/imports/usage/data_classes/usage_zone_archetype.py @@ -13,11 +13,11 @@ class UsageZoneArchetype: """ UsageZoneArchetype class """ - def __init__(self, usage=None, not_detailed_source_mean_annual_internal_gains=None, hours_day=None, days_year=None, + def __init__(self, usage=None, internal_gains=None, hours_day=None, days_year=None, electrical_app_average_consumption_sqm_year=None, mechanical_air_change=None, occupancy=None, lighting=None, appliances=None): self._usage = usage - self._not_detailed_source_mean_annual_internal_gains = not_detailed_source_mean_annual_internal_gains + self._internal_gains = internal_gains self._hours_day = hours_day self._days_year = days_year self._electrical_app_average_consumption_sqm_year = electrical_app_average_consumption_sqm_year @@ -27,12 +27,12 @@ class UsageZoneArchetype: self._appliances = appliances @property - def not_detailed_source_mean_annual_internal_gains(self) -> List[HftInternalGainsArchetype]: + def internal_gains(self) -> List[HftInternalGainsArchetype]: """ Get usage zone internal gains from not detailed heating source in W/m2 :return: [InternalGain] """ - return self._not_detailed_source_mean_annual_internal_gains + return self._internal_gains @property def hours_day(self): diff --git a/imports/usage/hft_usage_interface.py b/imports/usage/hft_usage_interface.py index 241cd5a7..aac00fc3 100644 --- a/imports/usage/hft_usage_interface.py +++ b/imports/usage/hft_usage_interface.py @@ -39,6 +39,9 @@ class HftUsageInterface: @staticmethod def _parse_zone_usage_type(usage, zone_usage_type): + usage_zone_archetype = UsageZone() + usage_zone_archetype.usage = usage + if 'occupancy' in zone_usage_type: _occupancy = Occupancy() _occupancy.occupancy_density = zone_usage_type['occupancy']['occupancyDensity'] #todo: check units @@ -67,19 +70,12 @@ class HftUsageInterface: _schedule.values = _values_float _internal_gain.schedules = [_schedule] - _not_detailed_source_mean_annual_internal_gains = [_internal_gain] - usage_zone_archetype = UsageZone(_not_detailed_source_mean_annual_internal_gains) - else: - usage_zone_archetype = UsageZone() + usage_zone_archetype.internal_gains = [_internal_gain] usage_zone_archetype.hours_day = zone_usage_type['occupancy']['usageHoursPerDay'] usage_zone_archetype.days_year = zone_usage_type['occupancy']['usageDaysPerYear'] usage_zone_archetype.occupancy = _occupancy - else: - usage_zone_archetype = UsageZone() - usage_zone_archetype.usage = usage - if 'endUses' in zone_usage_type: _thermal_control = ThermalControl() if 'space_heating' in zone_usage_type['endUses']: @@ -198,7 +194,7 @@ class HftUsageInterface: _schedule.values = _values_float _internal_gain.schedules = [_schedule] - usage_zone_archetype.not_detailed_source_mean_annual_internal_gains = [_internal_gain] + usage_zone_archetype.internal_gains = [_internal_gain] if 'endUses' in usage_zone_variant: _thermal_control = ThermalControl() @@ -272,10 +268,9 @@ class HftUsageInterface: @staticmethod def _assign_values(usage, archetype): - _not_detailed_source_mean_annual_internal_gains = \ - copy.deepcopy(archetype.internal_gains) - usage_zone = UsageZone(_not_detailed_source_mean_annual_internal_gains) + usage_zone = UsageZone() usage_zone.usage = usage + usage_zone.internal_gains = copy.deepcopy(archetype.internal_gains) usage_zone.mechanical_air_change = archetype.mechanical_air_change usage_zone.occupancy = copy.deepcopy(archetype.occupancy) usage_zone.appliances = copy.deepcopy(archetype.appliances) diff --git a/unittests/test_construction_factory.py b/unittests/test_construction_factory.py index 6ad4b2f0..1a8a0af2 100644 --- a/unittests/test_construction_factory.py +++ b/unittests/test_construction_factory.py @@ -86,8 +86,6 @@ class TestConstructionFactory(TestCase): self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none') self.assertIsNone(thermal_zone.hvac_system, 'thermal_zone hvac_system is not none') self.assertIsNone(thermal_zone.usage, 'thermal_zone usage is not none') - self.assertIsNone(thermal_zone.not_detailed_source_mean_annual_internal_gains, - 'thermal_zone not detailed source internal gains is not none') self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none') self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none') self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none')