702 lines
27 KiB
Python
702 lines
27 KiB
Python
"""
|
|
ThermalZone module
|
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
Copyright © 2022 Concordia CERC group
|
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
"""
|
|
import uuid, sys
|
|
import copy
|
|
from typing import List, Union, TypeVar
|
|
from city_model_structure.building_demand.occupancy import Occupancy
|
|
from city_model_structure.building_demand.appliances import Appliances
|
|
from city_model_structure.building_demand.lighting import Lighting
|
|
from city_model_structure.building_demand.internal_gain import InternalGain
|
|
from city_model_structure.attributes.schedule import Schedule
|
|
from city_model_structure.building_demand.thermal_control import ThermalControl
|
|
from city_model_structure.energy_systems.hvac_system import HvacSystem
|
|
import helpers.constants as cte
|
|
|
|
ThermalBoundary = TypeVar('ThermalBoundary')
|
|
InternalZone = TypeVar('InternalZone')
|
|
|
|
|
|
class ThermalZone:
|
|
"""
|
|
ThermalZone class
|
|
"""
|
|
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area):
|
|
self._id = None
|
|
self._parent_internal_zone = parent_internal_zone
|
|
self._footprint_area = footprint_area
|
|
self._thermal_boundaries = thermal_boundaries
|
|
self._additional_thermal_bridge_u_value = None
|
|
self._effective_thermal_capacity = None
|
|
self._indirectly_heated_area_ratio = None
|
|
self._infiltration_rate_system_on = None
|
|
self._infiltration_rate_system_off = None
|
|
self._volume = volume
|
|
self._ordinate_number = None
|
|
self._view_factors_matrix = None
|
|
self._total_floor_area = None
|
|
|
|
self._usage = None
|
|
self._not_detailed_source_mean_annual_internal_gains = None
|
|
self._hours_day = None
|
|
self._days_year = None
|
|
self._mechanical_air_change = None
|
|
self._occupancy = None
|
|
self._lighting = None
|
|
self._appliances = None
|
|
self._internal_gains = None
|
|
self._thermal_control = None
|
|
|
|
@property
|
|
def id(self):
|
|
"""
|
|
Get thermal zone id, an universally unique identifier randomly generated
|
|
:return: str
|
|
"""
|
|
if self._id is None:
|
|
self._id = uuid.uuid4()
|
|
return self._id
|
|
|
|
@property
|
|
def footprint_area(self) -> float:
|
|
"""
|
|
Get thermal zone footprint area in m2
|
|
:return: float
|
|
"""
|
|
return self._footprint_area
|
|
|
|
@property
|
|
def thermal_boundaries(self) -> List[ThermalBoundary]:
|
|
"""
|
|
Get thermal boundaries bounding with the thermal zone
|
|
:return: [ThermalBoundary]
|
|
"""
|
|
return self._thermal_boundaries
|
|
|
|
@property
|
|
def additional_thermal_bridge_u_value(self) -> Union[None, float]:
|
|
"""
|
|
Get thermal zone additional thermal bridge u value W/m2K
|
|
:return: None or float
|
|
"""
|
|
return self._additional_thermal_bridge_u_value
|
|
|
|
@additional_thermal_bridge_u_value.setter
|
|
def additional_thermal_bridge_u_value(self, value):
|
|
"""
|
|
Set thermal zone additional thermal bridge u value W/m2K
|
|
:param value: float
|
|
"""
|
|
if value is not None:
|
|
self._additional_thermal_bridge_u_value = float(value)
|
|
|
|
@property
|
|
def effective_thermal_capacity(self) -> Union[None, float]:
|
|
"""
|
|
Get thermal zone effective thermal capacity in J/m2K
|
|
:return: None or float
|
|
"""
|
|
return self._effective_thermal_capacity
|
|
|
|
@effective_thermal_capacity.setter
|
|
def effective_thermal_capacity(self, value):
|
|
"""
|
|
Set thermal zone effective thermal capacity in J/m2K
|
|
:param value: float
|
|
"""
|
|
if value is not None:
|
|
self._effective_thermal_capacity = float(value)
|
|
|
|
@property
|
|
def indirectly_heated_area_ratio(self) -> Union[None, float]:
|
|
"""
|
|
Get thermal zone indirectly heated area ratio
|
|
:return: None or float
|
|
"""
|
|
return self._indirectly_heated_area_ratio
|
|
|
|
@indirectly_heated_area_ratio.setter
|
|
def indirectly_heated_area_ratio(self, value):
|
|
"""
|
|
Set thermal zone indirectly heated area ratio
|
|
:param value: float
|
|
"""
|
|
if value is not None:
|
|
self._indirectly_heated_area_ratio = float(value)
|
|
|
|
@property
|
|
def infiltration_rate_system_on(self) -> Union[None, Schedule]:
|
|
"""
|
|
Get thermal zone infiltration rate system on in air changes per hour (ACH)
|
|
:return: None or Schedule
|
|
"""
|
|
return self._infiltration_rate_system_on
|
|
|
|
@infiltration_rate_system_on.setter
|
|
def infiltration_rate_system_on(self, value):
|
|
"""
|
|
Set thermal zone infiltration rate system on in air changes per hour (ACH)
|
|
:param value: Schedule
|
|
"""
|
|
self._infiltration_rate_system_on = value
|
|
|
|
@property
|
|
def infiltration_rate_system_off(self) -> Union[None, Schedule]:
|
|
"""
|
|
Get thermal zone infiltration rate system off in air changes per hour (ACH)
|
|
:return: None or Schedule
|
|
"""
|
|
return self._infiltration_rate_system_off
|
|
|
|
@infiltration_rate_system_off.setter
|
|
def infiltration_rate_system_off(self, value):
|
|
"""
|
|
Set thermal zone infiltration rate system on in air changes per hour (ACH)
|
|
:param value: Schedule
|
|
"""
|
|
self._infiltration_rate_system_off = value
|
|
|
|
@property
|
|
def volume(self):
|
|
"""
|
|
Get thermal zone volume
|
|
:return: float
|
|
"""
|
|
return self._volume
|
|
|
|
@property
|
|
def ordinate_number(self) -> Union[None, int]:
|
|
"""
|
|
Get the order in which the thermal_zones need to be enumerated
|
|
:return: None or int
|
|
"""
|
|
return self._ordinate_number
|
|
|
|
@ordinate_number.setter
|
|
def ordinate_number(self, value):
|
|
"""
|
|
Set a specific order of the zones to be called
|
|
:param value: int
|
|
"""
|
|
if value is not None:
|
|
self._ordinate_number = int(value)
|
|
|
|
@property
|
|
def hvac_system(self) -> Union[None, HvacSystem]:
|
|
"""
|
|
Get HVAC system installed for this thermal zone
|
|
From internal_zone
|
|
:return: None or HvacSystem
|
|
"""
|
|
return self._parent_internal_zone.hvac_system
|
|
|
|
@property
|
|
def view_factors_matrix(self):
|
|
"""
|
|
Get thermal zone view factors matrix
|
|
:return: [[float]]
|
|
"""
|
|
return self._view_factors_matrix
|
|
|
|
@view_factors_matrix.setter
|
|
def view_factors_matrix(self, value):
|
|
"""
|
|
Set thermal zone view factors matrix
|
|
:param value: [[float]]
|
|
"""
|
|
self._view_factors_matrix = value
|
|
|
|
@property
|
|
def usage(self) -> Union[None, str]:
|
|
"""
|
|
Get thermal zone usage
|
|
:return: None or str
|
|
"""
|
|
if self._parent_internal_zone.usage_zones is None:
|
|
return None
|
|
if self._usage is 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 = 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:
|
|
for day_type in schedule.day_types:
|
|
if day_type == requested_day_type:
|
|
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:
|
|
return None
|
|
if self._hours_day is None:
|
|
self._hours_day = 0
|
|
for usage_zone in self._parent_internal_zone.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:
|
|
return None
|
|
if self._days_year is None:
|
|
self._days_year = 0
|
|
for usage_zone in self._parent_internal_zone.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:
|
|
return None
|
|
if self._mechanical_air_change is None:
|
|
self._mechanical_air_change = 0
|
|
for usage_zone in self._parent_internal_zone.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:
|
|
return None
|
|
if self._occupancy is None:
|
|
self._occupancy = Occupancy()
|
|
_occupancy_density = 0
|
|
_convective_part = 0
|
|
_radiative_part = 0
|
|
_latent_part = 0
|
|
for usage_zone in self._parent_internal_zone.usage_zones:
|
|
if usage_zone.occupancy is None:
|
|
return None
|
|
_occupancy_density += usage_zone.percentage * usage_zone.occupancy.occupancy_density
|
|
if usage_zone.occupancy.sensible_convective_internal_gain is not None:
|
|
_convective_part += usage_zone.percentage * usage_zone.occupancy.sensible_convective_internal_gain
|
|
_radiative_part += usage_zone.percentage * usage_zone.occupancy.sensible_radiative_internal_gain
|
|
_latent_part += usage_zone.percentage * usage_zone.occupancy.latent_internal_gain
|
|
self._occupancy.occupancy_density = _occupancy_density
|
|
self._occupancy.sensible_convective_internal_gain = _convective_part
|
|
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
|
|
if _occupancy_reference.occupancy_schedules is not None:
|
|
_schedules = []
|
|
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)):
|
|
schedule = copy.deepcopy(_occupancy_reference.occupancy_schedules[i_schedule])
|
|
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:
|
|
_new_value += usage_zone.percentage * usage_zone.occupancy.occupancy_schedules[i_schedule].values[i_value]
|
|
new_values.append(_new_value)
|
|
schedule.values = new_values
|
|
_schedules.append(schedule)
|
|
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:
|
|
return None
|
|
if self._lighting is None:
|
|
self._lighting = Lighting()
|
|
_lighting_density = 0
|
|
_convective_part = 0
|
|
_radiative_part = 0
|
|
_latent_part = 0
|
|
for usage_zone in self._parent_internal_zone.usage_zones:
|
|
if usage_zone.lighting is None:
|
|
return None
|
|
_lighting_density += usage_zone.percentage * usage_zone.lighting.density
|
|
if usage_zone.lighting.convective_fraction is not None:
|
|
_convective_part += usage_zone.percentage * usage_zone.lighting.density \
|
|
* usage_zone.lighting.convective_fraction
|
|
_radiative_part += usage_zone.percentage * usage_zone.lighting.density \
|
|
* usage_zone.lighting.radiative_fraction
|
|
_latent_part += usage_zone.percentage * usage_zone.lighting.density \
|
|
* usage_zone.lighting.latent_fraction
|
|
self._lighting.density = _lighting_density
|
|
if _lighting_density > 0:
|
|
self._lighting.convective_fraction = _convective_part / _lighting_density
|
|
self._lighting.radiative_fraction = _radiative_part / _lighting_density
|
|
self._lighting.latent_fraction = _latent_part / _lighting_density
|
|
else:
|
|
self._lighting.convective_fraction = 0
|
|
self._lighting.radiative_fraction = 0
|
|
self._lighting.latent_fraction = 0
|
|
|
|
_lighting_reference = self._parent_internal_zone.usage_zones[0].lighting
|
|
if _lighting_reference.schedules is not None:
|
|
_schedules = []
|
|
for i_schedule in range(0, len(_lighting_reference.schedules)):
|
|
schedule = copy.deepcopy(_lighting_reference.schedules[i_schedule])
|
|
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:
|
|
_new_value += usage_zone.percentage * usage_zone.lighting.schedules[i_schedule].values[i_value]
|
|
new_values.append(_new_value)
|
|
schedule.values = new_values
|
|
_schedules.append(schedule)
|
|
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:
|
|
return None
|
|
if self._appliances is None:
|
|
self._appliances = Appliances()
|
|
_appliances_density = 0
|
|
_convective_part = 0
|
|
_radiative_part = 0
|
|
_latent_part = 0
|
|
for usage_zone in self._parent_internal_zone.usage_zones:
|
|
if usage_zone.appliances is None:
|
|
return None
|
|
_appliances_density += usage_zone.percentage * usage_zone.appliances.density
|
|
if usage_zone.appliances.convective_fraction is not None:
|
|
_convective_part += usage_zone.percentage * usage_zone.appliances.density \
|
|
* usage_zone.appliances.convective_fraction
|
|
_radiative_part += usage_zone.percentage * usage_zone.appliances.density \
|
|
* usage_zone.appliances.radiative_fraction
|
|
_latent_part += usage_zone.percentage * usage_zone.appliances.density \
|
|
* usage_zone.appliances.latent_fraction
|
|
self._appliances.density = _appliances_density
|
|
if _appliances_density > 0:
|
|
self._appliances.convective_fraction = _convective_part / _appliances_density
|
|
self._appliances.radiative_fraction = _radiative_part / _appliances_density
|
|
self._appliances.latent_fraction = _latent_part / _appliances_density
|
|
else:
|
|
self._appliances.convective_fraction = 0
|
|
self._appliances.radiative_fraction = 0
|
|
self._appliances.latent_fraction = 0
|
|
|
|
_appliances_reference = self._parent_internal_zone.usage_zones[0].appliances
|
|
if _appliances_reference.schedules is not None:
|
|
_schedules = []
|
|
for i_schedule in range(0, len(_appliances_reference.schedules)):
|
|
schedule = copy.deepcopy(_appliances_reference.schedules[i_schedule])
|
|
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:
|
|
_new_value += usage_zone.percentage * usage_zone.appliances.schedules[i_schedule].values[i_value]
|
|
new_values.append(_new_value)
|
|
schedule.values = new_values
|
|
_schedules.append(schedule)
|
|
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) -> [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
|
|
|
|
@property
|
|
def thermal_control(self) -> Union[None, ThermalControl]:
|
|
"""
|
|
Get thermal control of this thermal zone
|
|
:return: None or ThermalControl
|
|
"""
|
|
if self._parent_internal_zone.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:
|
|
_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
|
|
self._thermal_control.mean_heating_set_point = _mean_heating_set_point
|
|
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
|
|
_types_reference = []
|
|
if _thermal_control_reference.hvac_availability_schedules is not None:
|
|
_types_reference.append([cte.HVAC_AVAILABILITY, _thermal_control_reference.hvac_availability_schedules])
|
|
if _thermal_control_reference.heating_set_point_schedules is not None:
|
|
_types_reference.append([cte.HEATING_SET_POINT, _thermal_control_reference.heating_set_point_schedules])
|
|
if _thermal_control_reference.cooling_set_point_schedules is not None:
|
|
_types_reference.append([cte.COOLING_SET_POINT, _thermal_control_reference.cooling_set_point_schedules])
|
|
|
|
for i_type in range(0, len(_types_reference)):
|
|
_schedules = []
|
|
_schedule_type = _types_reference[i_type][1]
|
|
for i_schedule in range(0, len(_schedule_type)):
|
|
schedule = copy.deepcopy(_schedule_type[i_schedule])
|
|
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:
|
|
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]
|
|
elif _types_reference[i_type][0] == cte.HEATING_SET_POINT:
|
|
_new_value += usage_zone.percentage * \
|
|
usage_zone.thermal_control.heating_set_point_schedules[i_schedule].values[i_value]
|
|
elif _types_reference[i_type][0] == cte.COOLING_SET_POINT:
|
|
_new_value += usage_zone.percentage * \
|
|
usage_zone.thermal_control.cooling_set_point_schedules[i_schedule].values[i_value]
|
|
new_values.append(_new_value)
|
|
schedule.values = new_values
|
|
_schedules.append(schedule)
|
|
if i_type == 0:
|
|
self._thermal_control.hvac_availability_schedules = _schedules
|
|
elif i_type == 1:
|
|
self._thermal_control.heating_set_point_schedules = _schedules
|
|
elif i_type == 2:
|
|
self._thermal_control.cooling_set_point_schedules = _schedules
|
|
|
|
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):
|
|
"""
|
|
Get the total floor area of this thermal zone
|
|
:return: float
|
|
"""
|
|
return self._total_floor_area
|
|
|
|
@total_floor_area.setter
|
|
def total_floor_area(self, value):
|
|
"""
|
|
Set the total floor area of this thermal zone
|
|
:param value: float
|
|
"""
|
|
self._total_floor_area = value
|