Merge branch 'a_bug_in_internal_gains' into 'master'
erased not_detailed_source_mean_annual_internal_gains parameter and changed by internal_gains. During the import, for those catalogs that don't provide that information, the internal_gains are calc... See merge request Guille/hub!20
This commit is contained in:
commit
543b42b0e2
|
@ -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
|
||||
|
|
|
@ -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._usage is None:
|
||||
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 += 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:
|
||||
if self._usage_zones is None:
|
||||
return None
|
||||
if self._internal_gains is 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]
|
||||
_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.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 _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)
|
||||
|
||||
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:
|
||||
_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):
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -48,6 +48,7 @@ CONTROL_TYPE = 'control_type'
|
|||
CONTINUOUS = 'continuous'
|
||||
DISCRETE = 'discrete'
|
||||
CONSTANT = 'constant'
|
||||
INTERNAL_GAINS = 'internal_gains'
|
||||
|
||||
# surface types
|
||||
WALL = 'Wall'
|
||||
|
|
|
@ -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]
|
||||
if value != 0:
|
||||
_occupancy.occupancy_density = value
|
||||
else:
|
||||
_occupancy.occupancy_density = 0
|
||||
if value != 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]
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue
Block a user