Thermal zone concept modified. Now it includes all usage parameters associated to that thermal zone

This commit is contained in:
Pilar 2022-04-06 16:06:55 -04:00
parent 2bc217773e
commit 684238a3ff
22 changed files with 618 additions and 192 deletions

View File

@ -30,7 +30,6 @@ class Building(CityObject):
self._storeys_above_ground = None self._storeys_above_ground = None
self._floor_area = None self._floor_area = None
self._roof_type = None self._roof_type = None
self._storeys = None
self._internal_zones = None self._internal_zones = None
self._shell = None self._shell = None
self._type = 'building' self._type = 'building'

View File

@ -12,28 +12,28 @@ class Appliances:
Appliances class Appliances class
""" """
def __init__(self): def __init__(self):
self._appliances_density = None self._density = None
self._convective_fraction = None self._convective_fraction = None
self._radiative_fraction = None self._radiative_fraction = None
self._latent_fraction = None self._latent_fraction = None
self._schedules = None self._schedules = None
@property @property
def appliances_density(self) -> Union[None, float]: def density(self) -> Union[None, float]:
""" """
Get appliances density in Watts per m2 Get appliances density in Watts per m2
:return: None or float :return: None or float
""" """
return self._appliances_density return self._density
@appliances_density.setter @density.setter
def appliances_density(self, value): def density(self, value):
""" """
Set appliances density in Watts per m2 Set appliances density in Watts per m2
:param value: float :param value: float
""" """
if value is not None: if value is not None:
self._appliances_density = float(value) self._density = float(value)
@property @property
def convective_fraction(self) -> Union[None, float]: def convective_fraction(self) -> Union[None, float]:
@ -90,6 +90,7 @@ class Appliances:
def schedules(self) -> Union[None, List[Schedule]]: def schedules(self) -> Union[None, List[Schedule]]:
""" """
Get schedules Get schedules
dataType = fraction
:return: None or [Schedule] :return: None or [Schedule]
""" """
return self._schedules return self._schedules
@ -98,6 +99,7 @@ class Appliances:
def schedules(self, value): def schedules(self, value):
""" """
Set schedules Set schedules
dataType = fraction
:param value: [Schedule] :param value: [Schedule]
""" """
self._schedules = value self._schedules = value

View File

@ -110,6 +110,7 @@ class InternalGains:
def schedules(self) -> Union[None, List[Schedule]]: def schedules(self) -> Union[None, List[Schedule]]:
""" """
Get internal gain schedule Get internal gain schedule
dataType = fraction
:return: [Schedule] :return: [Schedule]
""" """
return self._schedules return self._schedules
@ -118,6 +119,7 @@ class InternalGains:
def schedules(self, value): def schedules(self, value):
""" """
Set internal gain schedule Set internal gain schedule
dataType = fraction
:param value: [Schedule] :param value: [Schedule]
""" """
self._schedules = value self._schedules = value

View File

@ -120,4 +120,3 @@ class InternalZone:
:param value: [ThermalZone] :param value: [ThermalZone]
""" """
self._thermal_zones = value self._thermal_zones = value

View File

@ -12,28 +12,28 @@ class Lighting:
Lighting class Lighting class
""" """
def __init__(self): def __init__(self):
self._lighting_density = None self._density = None
self._convective_fraction = None self._convective_fraction = None
self._radiative_fraction = None self._radiative_fraction = None
self._latent_fraction = None self._latent_fraction = None
self._schedules = None self._schedules = None
@property @property
def lighting_density(self) -> Union[None, float]: def density(self) -> Union[None, float]:
""" """
Get lighting density in Watts per m2 Get lighting density in Watts per m2
:return: None or float :return: None or float
""" """
return self._lighting_density return self._density
@lighting_density.setter @density.setter
def lighting_density(self, value): def density(self, value):
""" """
Set lighting density in Watts per m2 Set lighting density in Watts per m2
:param value: float :param value: float
""" """
if value is not None: if value is not None:
self._lighting_density = float(value) self._density = float(value)
@property @property
def convective_fraction(self) -> Union[None, float]: def convective_fraction(self) -> Union[None, float]:
@ -90,6 +90,7 @@ class Lighting:
def schedules(self) -> Union[None, List[Schedule]]: def schedules(self) -> Union[None, List[Schedule]]:
""" """
Get schedules Get schedules
dataType = fraction
:return: None or [Schedule] :return: None or [Schedule]
""" """
return self._schedules return self._schedules
@ -98,6 +99,7 @@ class Lighting:
def schedules(self, value): def schedules(self, value):
""" """
Set schedules Set schedules
dataType = fraction
:param value: [Schedule] :param value: [Schedule]
""" """
self._schedules = value self._schedules = value

View File

@ -23,7 +23,7 @@ class Occupancy:
@property @property
def occupancy_density(self) -> Union[None, float]: def occupancy_density(self) -> Union[None, float]:
""" """
Get density in m2 per person Get density in persons per m2
:return: None or float :return: None or float
""" """
return self._occupancy_density return self._occupancy_density
@ -31,7 +31,7 @@ class Occupancy:
@occupancy_density.setter @occupancy_density.setter
def occupancy_density(self, value): def occupancy_density(self, value):
""" """
Set density in m2 per persons Set density in persons per m2
:param value: float :param value: float
""" """
if value is not None: if value is not None:
@ -92,6 +92,7 @@ class Occupancy:
def occupancy_schedules(self) -> Union[None, List[Schedule]]: def occupancy_schedules(self) -> Union[None, List[Schedule]]:
""" """
Get occupancy schedules Get occupancy schedules
dataType = fraction
:return: None or [Schedule] :return: None or [Schedule]
""" """
return self._occupancy_schedules return self._occupancy_schedules
@ -100,6 +101,7 @@ class Occupancy:
def occupancy_schedules(self, value): def occupancy_schedules(self, value):
""" """
Set occupancy schedules Set occupancy schedules
dataType = fraction
:param value: [Schedule] :param value: [Schedule]
""" """
self._occupancy_schedules = value self._occupancy_schedules = value

View File

@ -15,7 +15,7 @@ class Storey:
""" """
Storey class Storey class
""" """
def __init__(self, name, storey_surfaces, neighbours, volume, floor_area): def __init__(self, name, storey_surfaces, neighbours, volume, internal_zone, floor_area):
self._name = name self._name = name
self._storey_surfaces = storey_surfaces self._storey_surfaces = storey_surfaces
self._thermal_boundaries = None self._thermal_boundaries = None
@ -23,6 +23,7 @@ class Storey:
self._thermal_zone = None self._thermal_zone = None
self._neighbours = neighbours self._neighbours = neighbours
self._volume = volume self._volume = volume
self._internal_zone = internal_zone
self._floor_area = floor_area self._floor_area = floor_area
@property @property
@ -86,7 +87,7 @@ class Storey:
:return: ThermalZone :return: ThermalZone
""" """
if self._thermal_zone is None: if self._thermal_zone is None:
self._thermal_zone = ThermalZone(self.thermal_boundaries, self.volume, self.floor_area) self._thermal_zone = ThermalZone(self.thermal_boundaries, self._internal_zone, self.volume, self.floor_area)
return self._thermal_zone return self._thermal_zone
@property @property

View File

@ -99,6 +99,7 @@ class ThermalControl:
def hvac_availability_schedules(self) -> Union[None, List[Schedule]]: def hvac_availability_schedules(self) -> Union[None, List[Schedule]]:
""" """
Get the availability of the conditioning system defined for a thermal zone Get the availability of the conditioning system defined for a thermal zone
dataType = on/off
:return: None or [Schedule] :return: None or [Schedule]
""" """
return self._hvac_availability_schedules return self._hvac_availability_schedules
@ -107,6 +108,7 @@ class ThermalControl:
def hvac_availability_schedules(self, value): def hvac_availability_schedules(self, value):
""" """
Set the availability of the conditioning system defined for a thermal zone Set the availability of the conditioning system defined for a thermal zone
dataType = on/off
:param value: [Schedule] :param value: [Schedule]
""" """
self._hvac_availability_schedules = value self._hvac_availability_schedules = value
@ -115,6 +117,7 @@ class ThermalControl:
def heating_set_point_schedules(self) -> Union[None, List[Schedule]]: def heating_set_point_schedules(self) -> Union[None, List[Schedule]]:
""" """
Get heating set point schedule defined for a thermal zone in Celsius Get heating set point schedule defined for a thermal zone in Celsius
dataType = temperature
:return: None or [Schedule] :return: None or [Schedule]
""" """
return self._heating_set_point_schedules return self._heating_set_point_schedules
@ -123,6 +126,7 @@ class ThermalControl:
def heating_set_point_schedules(self, value): def heating_set_point_schedules(self, value):
""" """
Set heating set point schedule defined for a thermal zone in Celsius Set heating set point schedule defined for a thermal zone in Celsius
dataType = temperature
:param value: [Schedule] :param value: [Schedule]
""" """
self._heating_set_point_schedules = value self._heating_set_point_schedules = value
@ -131,6 +135,7 @@ class ThermalControl:
def cooling_set_point_schedules(self) -> Union[None, List[Schedule]]: def cooling_set_point_schedules(self) -> Union[None, List[Schedule]]:
""" """
Get cooling set point schedule defined for a thermal zone in Celsius Get cooling set point schedule defined for a thermal zone in Celsius
dataType = temperature
:return: None or [Schedule] :return: None or [Schedule]
""" """
return self._cooling_set_point_schedules return self._cooling_set_point_schedules
@ -139,6 +144,7 @@ class ThermalControl:
def cooling_set_point_schedules(self, value): def cooling_set_point_schedules(self, value):
""" """
Set cooling set point schedule defined for a thermal zone in Celsius Set cooling set point schedule defined for a thermal zone in Celsius
dataType = temperature
:param value: [Schedule] :param value: [Schedule]
""" """
self._cooling_set_point_schedules = value self._cooling_set_point_schedules = value

View File

@ -5,21 +5,28 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
Contributors Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Contributors Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import uuid import uuid
import copy
from typing import List, Union, TypeVar from typing import List, Union, TypeVar
from city_model_structure.building_demand.usage_zone import UsageZone 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_gains import InternalGains
from city_model_structure.attributes.schedule import Schedule from city_model_structure.attributes.schedule import Schedule
from city_model_structure.building_demand.thermal_control import ThermalControl from city_model_structure.building_demand.thermal_control import ThermalControl
from city_model_structure.energy_systems.hvac_system import HvacSystem from city_model_structure.energy_systems.hvac_system import HvacSystem
import helpers.constants as cte
ThermalBoundary = TypeVar('ThermalBoundary') ThermalBoundary = TypeVar('ThermalBoundary')
InternalZone = TypeVar('InternalZone')
class ThermalZone: class ThermalZone:
""" """
ThermalZone class ThermalZone class
""" """
def __init__(self, thermal_boundaries, volume, floor_area): def __init__(self, thermal_boundaries, parent_internal_zone, volume, floor_area):
self._id = None self._id = None
self._parent_internal_zone = parent_internal_zone
self._floor_area = floor_area self._floor_area = floor_area
self._thermal_boundaries = thermal_boundaries self._thermal_boundaries = thermal_boundaries
self._additional_thermal_bridge_u_value = None self._additional_thermal_bridge_u_value = None
@ -29,11 +36,19 @@ class ThermalZone:
self._infiltration_rate_system_off = None self._infiltration_rate_system_off = None
self._volume = volume self._volume = volume
self._ordinate_number = None self._ordinate_number = None
self._usage_zones = None
self._thermal_control = None
self._hvac_system = None
self._view_factors_matrix = None self._view_factors_matrix = 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 @property
def id(self): def id(self):
""" """
@ -168,42 +183,6 @@ class ThermalZone:
if value is not None: if value is not None:
self._ordinate_number = int(value) self._ordinate_number = int(value)
@property
def usage_zones(self) -> [UsageZone]:
"""
Get list of usage zones and the percentage of thermal zone's volume affected by that usage
From internal_zone
:return: [UsageZone]
"""
return self._usage_zones
@usage_zones.setter
def usage_zones(self, values):
"""
Set list of usage zones and the percentage of thermal zone's volume affected by that usage
From internal_zone
:param values: [UsageZone]
"""
self._usage_zones = values
@property
def thermal_control(self) -> Union[None, ThermalControl]:
"""
Get thermal control of this thermal zone
From internal_zone
:return: None or ThermalControl
"""
return self._thermal_control
@thermal_control.setter
def thermal_control(self, value):
"""
Set thermal control for this thermal zone
From internal_zone
:param value: ThermalControl
"""
self._thermal_control = value
@property @property
def hvac_system(self) -> Union[None, HvacSystem]: def hvac_system(self) -> Union[None, HvacSystem]:
""" """
@ -211,16 +190,7 @@ class ThermalZone:
From internal_zone From internal_zone
:return: None or HvacSystem :return: None or HvacSystem
""" """
return self._hvac_system return self._parent_internal_zone.hvac_system
@hvac_system.setter
def hvac_system(self, value):
"""
Set HVAC system installed for this thermal zone
From internal_zone
:param value: HvacSystem
"""
self._hvac_system = value
@property @property
def view_factors_matrix(self): def view_factors_matrix(self):
@ -237,3 +207,449 @@ class ThermalZone:
:param value: [[float]] :param value: [[float]]
""" """
self._view_factors_matrix = value 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
else:
return None
@property
def not_detailed_source_mean_annual_internal_gains(self) -> Union[None, List[InternalGains]]:
"""
Get thermal zone internal gains with unknown energy source
:return: [InternalGains]
"""
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 = InternalGains()
_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.internal_gains is None:
return None
for _internal_gain in _usage_zone.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].internal_gains[0]
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))
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.internal_gains:
_value = self._get_schedule_of_day(day_types[i_day], _internal_gain.schedules)[i_value]
_new_value += _usage_zone.percentage * _value / len(_usage_zone.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: [InternalGains]
"""
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:
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
_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
_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
_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
_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
_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
_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) -> [InternalGains]:
"""
Calculates and returns the list of all internal gains defined
:return: InternalGains
"""
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 = InternalGains()
_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
_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
_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 = InternalGains()
_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 = InternalGains()
_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 = [_thermal_control_reference.hvac_availability_schedules,
_thermal_control_reference.heating_set_point_schedules,
_thermal_control_reference.cooling_set_point_schedules]
for i_type in range(0, len(_types_reference)):
_schedules = []
_schedule_type = _types_reference[i_type]
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 i_type == 0:
_new_value += usage_zone.percentage * \
usage_zone.thermal_control.hvac_availability_schedules[i_schedule].values[i_value]
elif i_type == 1:
_new_value += usage_zone.percentage * \
usage_zone.thermal_control.heating_set_point_schedules[i_schedule].values[i_value]
elif i_type == 2:
_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

View File

@ -6,7 +6,6 @@ Contributors Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
import uuid import uuid
from typing import List, Union from typing import List, Union
import helpers.constants as cte
from city_model_structure.building_demand.internal_gains import InternalGains from city_model_structure.building_demand.internal_gains import InternalGains
from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.occupancy import Occupancy
from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.lighting import Lighting
@ -30,7 +29,6 @@ class UsageZone:
self._occupancy = None self._occupancy = None
self._lighting = None self._lighting = None
self._appliances = None self._appliances = None
self._internal_gains = None
self._thermal_control = None self._thermal_control = None
@property @property
@ -209,50 +207,6 @@ class UsageZone:
""" """
self._appliances = value self._appliances = value
def get_internal_gains(self) -> [InternalGains]:
"""
Calculates and returns the list of all internal gains defined
:return: InternalGains
"""
if self.occupancy is not None:
if self.occupancy.latent_internal_gain is not None:
_internal_gain = InternalGains()
_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
_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
_internal_gain.schedules = self.occupancy.occupancy_schedules
self._internal_gains = [_internal_gain]
if self.lighting is not None:
_internal_gain = InternalGains()
_internal_gain.type = cte.LIGHTING
_internal_gain.average_internal_gain = self.lighting.lighting_density
_internal_gain.latent_fraction = self.lighting.latent_fraction
_internal_gain.radiative_fraction = self.lighting.radiative_fraction
_internal_gain.convective_fraction = self.lighting.convective_fraction
_internal_gain.schedules = self.lighting.schedules
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 = InternalGains()
_internal_gain.type = cte.APPLIANCES
_internal_gain.average_internal_gain = self.appliances.appliances_density
_internal_gain.latent_fraction = self.appliances.latent_fraction
_internal_gain.radiative_fraction = self.appliances.radiative_fraction
_internal_gain.convective_fraction = self.appliances.convective_fraction
_internal_gain.schedules = self.appliances.schedules
if self._internal_gains is not None:
self._internal_gains.append(_internal_gain)
else:
self._internal_gains = [_internal_gain]
return self._internal_gains
@property @property
def thermal_control(self) -> Union[None, ThermalControl]: def thermal_control(self) -> Union[None, ThermalControl]:
""" """

View File

@ -19,6 +19,8 @@ class ExportsFactory:
def __init__(self, export_type, city, path, target_buildings=None): def __init__(self, export_type, city, path, target_buildings=None):
self._city = city self._city = city
self._export_type = '_' + export_type.lower() self._export_type = '_' + export_type.lower()
if isinstance(path, str):
path = Path(path)
self._path = path self._path = path
self._target_buildings = target_buildings self._target_buildings = target_buildings
@ -92,3 +94,10 @@ class ExportsFactory:
:return: None :return: None
""" """
return getattr(self, self._export_type, lambda: None) return getattr(self, self._export_type, lambda: None)
def export_debug(self):
"""
Export the city given to the class using the given export type handler
:return: None
"""
return getattr(self, self._export_type)

View File

@ -1,10 +1,13 @@
""" """
TestOccupancyFactory test and validate the city model structure schedules parameters TestOccupancyFactory test and validate the city model structure schedules parameters
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Soroush Samareh Abolhassani - soroush.samarehabolhassani@mail.concordia.ca Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Contributors Soroush Samareh Abolhassani - soroush.samarehabolhassani@mail.concordia.ca
Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from geomeppy import IDF from geomeppy import IDF
import helpers.constants as cte
class Idf: class Idf:
@ -35,19 +38,19 @@ class Idf:
idf_surfaces = { idf_surfaces = {
# todo: make an enum for all the surface types # todo: make an enum for all the surface types
'Wall': 'wall', cte.WALL: 'wall',
'Ground': 'floor', cte.GROUND: 'floor',
'Roof': 'roof' cte.ROOF: 'roof'
} }
idf_usage = { idf_usage = {
# todo: make an enum for all the usage types # todo: make an enum for all the usage types
'residential': 'residential_building' cte.RESIDENTIAL: 'residential_building'
} }
idf_type_limits = { idf_type_limits = {
'on_off': 'on/off', cte.ON_OFF: 'on/off',
'fraction': 'Fraction', cte.FRACTION: 'Fraction',
'any_number': 'Any Number', cte.ANY_NUMBER: 'Any Number',
'continuous': 'Continuous', 'continuous': 'Continuous',
'discrete': 'Discrete' 'discrete': 'Discrete'
} }
@ -117,8 +120,8 @@ class Idf:
Visible_Absorptance=layer.material.visible_absorptance Visible_Absorptance=layer.material.visible_absorptance
) )
def _add_daily_schedule(self, usage_zone, schedule): def _add_daily_schedule(self, usage, schedule):
_schedule = self._idf.newidfobject(self._COMPACT_SCHEDULE, Name=f'{schedule.type} schedules {usage_zone.usage}') _schedule = self._idf.newidfobject(self._COMPACT_SCHEDULE, Name=f'{schedule.type} schedules {usage}')
_val = schedule.values _val = schedule.values
_schedule.Schedule_Type_Limits_Name = self.idf_type_limits[schedule.data_type.lower()] _schedule.Schedule_Type_Limits_Name = self.idf_type_limits[schedule.data_type.lower()]
_schedule.Field_1 = "Through: 12/31" _schedule.Field_1 = "Through: 12/31"
@ -172,14 +175,12 @@ class Idf:
_schedule.Field_49 = "Until: 24:00" _schedule.Field_49 = "Until: 24:00"
_schedule.Field_50 = _val[23] _schedule.Field_50 = _val[23]
def _add_schedule(self, usage_zone, schedule_type): def _add_schedule(self, usage, new_schedule):
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]: for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
if schedule.Name == f'{schedule_type} schedules {usage_zone.usage}': if schedule.Name == f'{new_schedule.type} schedules {usage}':
return return
for schedule in usage_zone.schedules: if new_schedule.time_range == "day":
if schedule.type == schedule_type: return self._add_daily_schedule(usage, new_schedule)
if schedule.time_range == "day":
return self._add_daily_schedule(usage_zone, schedule)
return return
def _add_construction(self, thermal_boundary): def _add_construction(self, thermal_boundary):
@ -202,12 +203,12 @@ class Idf:
_kwargs[f'Layer_{i + 1}'] = layers[1].material.name _kwargs[f'Layer_{i + 1}'] = layers[1].material.name
self._idf.newidfobject(self._CONSTRUCTION, **_kwargs) self._idf.newidfobject(self._CONSTRUCTION, **_kwargs)
def _add_zone(self, usage_zone): def _add_zone(self, usage_zone, thermal_zone_volume):
for zone in self._idf.idfobjects['ZONE']: for zone in self._idf.idfobjects['ZONE']:
if zone.Name == usage_zone.id: if zone.Name == usage_zone.id:
return return
# todo: what does we need to define a zone in energy plus? # todo: what do we need to define a zone in energy plus?
self._idf.newidfobject(self._ZONE, Name=usage_zone.id, Volume=usage_zone.volume) self._idf.newidfobject(self._ZONE, Name=usage_zone.id, Volume=thermal_zone_volume * usage_zone.percentage)
self._add_heating_system(usage_zone) self._add_heating_system(usage_zone)
def _add_thermostat(self, usage_zone): def _add_thermostat(self, usage_zone):
@ -217,8 +218,8 @@ class Idf:
return thermostat return thermostat
return self._idf.newidfobject(self._THERMOSTAT, return self._idf.newidfobject(self._THERMOSTAT,
Name=thermostat_name, Name=thermostat_name,
Constant_Heating_Setpoint=usage_zone.heating_setpoint, Constant_Heating_Setpoint=usage_zone.thermal_control.mean_heating_set_point,
Constant_Cooling_Setpoint=usage_zone.cooling_setpoint) Constant_Cooling_Setpoint=usage_zone.thermal_control.mean_cooling_set_point)
def _add_heating_system(self, usage_zone): def _add_heating_system(self, usage_zone):
for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]: for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]:
@ -232,14 +233,19 @@ class Idf:
Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {usage_zone.usage}', Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {usage_zone.usage}',
Template_Thermostat_Name=thermostat.Name) Template_Thermostat_Name=thermostat.Name)
def _add_occupancy(self, usage_zone): def _add_occupancy(self, usage_zone, area):
number_of_people = area * usage_zone.occupancy.occupancy_density
fraction_radiant = usage_zone.occupancy.sensible_radiative_internal_gain / \
(usage_zone.occupancy.sensible_radiative_internal_gain +
usage_zone.occupancy.sensible_convective_internal_gain +
usage_zone.occupancy.latent_internal_gain)
self._idf.newidfobject(self._PEOPLE, self._idf.newidfobject(self._PEOPLE,
Name=f'{usage_zone.id}_occupancy', Name=f'{usage_zone.id}_occupancy',
Zone_or_ZoneList_Name=usage_zone.id, Zone_or_ZoneList_Name=usage_zone.id,
Number_of_People_Schedule_Name=f'Occupancy schedules {usage_zone.usage}', Number_of_People_Schedule_Name=f'Occupancy schedules {usage_zone.usage}',
Number_of_People_Calculation_Method="People", Number_of_People_Calculation_Method="People",
Number_of_People=500, # todo: get people from where? Number_of_People=number_of_people,
Fraction_Radiant=0.3, # todo: howto get this from InternalGains Fraction_Radiant=fraction_radiant,
Activity_Level_Schedule_Name=f'Occupancy schedules {usage_zone.usage}' Activity_Level_Schedule_Name=f'Occupancy schedules {usage_zone.usage}'
) )
@ -261,7 +267,7 @@ class Idf:
Zone_or_ZoneList_Name=usage_zone.id, Zone_or_ZoneList_Name=usage_zone.id,
Schedule_Name=f'Infiltration schedules {usage_zone.usage}', Schedule_Name=f'Infiltration schedules {usage_zone.usage}',
Design_Flow_Rate_Calculation_Method='AirChanges/Hour', Design_Flow_Rate_Calculation_Method='AirChanges/Hour',
Air_Changes_per_Hour=0.35, # todo: change it from usage catalog Air_Changes_per_Hour=usage_zone.mechanical_air_change,
Constant_Term_Coefficient=0.606, # todo: change it from usage catalog Constant_Term_Coefficient=0.606, # todo: change it from usage catalog
Temperature_Term_Coefficient=3.6359996E-02, # todo: change it from usage catalog Temperature_Term_Coefficient=3.6359996E-02, # todo: change it from usage catalog
Velocity_Term_Coefficient=0.1177165, # todo: change it from usage catalog Velocity_Term_Coefficient=0.1177165, # todo: change it from usage catalog
@ -275,20 +281,33 @@ class Idf:
""" """
for building in self._city.buildings: for building in self._city.buildings:
for usage_zone in building.usage_zones: for internal_zone in building.internal_zones:
self._add_schedule(usage_zone, "Infiltration") for thermal_zone in internal_zone.thermal_zones:
self._add_schedule(usage_zone, "Lights")
self._add_schedule(usage_zone, "Occupancy")
self._add_schedule(usage_zone, "Refrigeration")
self._add_schedule(usage_zone, "HVAC Avail")
self._add_zone(usage_zone)
self._add_heating_system(usage_zone)
self._add_infiltration(usage_zone)
self._add_occupancy(usage_zone)
for thermal_zone in building.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self._add_construction(thermal_boundary) self._add_construction(thermal_boundary)
for usage_zone in thermal_zone.usage_zones:
usage = usage_zone.usage
usage_zone_area = thermal_zone.floor_area * usage_zone.percentage
# todo: infiltration can be written with two values (system on and system off) in E+? Or just as schedule?
# self._add_schedule(usage, "Infiltration")
for schedule in usage_zone.lighting.schedules:
for day_type in schedule.day_types:
if day_type == cte.MONDAY:
self._add_schedule(usage, schedule)
for schedule in usage_zone.occupancy.occupancy_schedules:
for day_type in schedule.day_types:
if day_type == cte.MONDAY:
self._add_schedule(usage, usage_zone.occupancy.occupancy_schedules)
for schedule in usage_zone.thermal_control.hvac_availability_schedules:
for day_type in schedule.day_types:
if day_type == cte.MONDAY:
self._add_schedule(usage, schedule)
self._add_zone(usage_zone, thermal_zone.volume)
self._add_heating_system(usage_zone)
# self._add_infiltration(usage_zone)
self._add_occupancy(usage_zone, usage_zone_area)
if self._export_type == "Surfaces": if self._export_type == "Surfaces":
self._add_surfaces(building) self._add_surfaces(building)
@ -335,12 +354,14 @@ class Idf:
def _add_surfaces(self, building): def _add_surfaces(self, building):
for thermal_zone in building.thermal_zones: for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries: for boundary in thermal_zone.thermal_boundaries:
idf_surface_type = self.idf_surfaces[boundary.surface.type] idf_surface_type = self.idf_surfaces[boundary.parent_surface.type]
for usage_zone in thermal_zone.usage_zones: for usage_zone in thermal_zone.usage_zones:
surface = self._idf.newidfobject(self._SURFACE, Name=f'{boundary.surface.name}', surface = self._idf.newidfobject(self._SURFACE, Name=f'{boundary.parent_surface.name}',
Surface_Type=idf_surface_type, Zone_Name=usage_zone.id, Surface_Type=idf_surface_type, Zone_Name=usage_zone.id,
Construction_Name=boundary.construction_name) Construction_Name=boundary.construction_name)
coordinates = self._matrix_to_list(boundary.surface.solid_polygon.coordinates, self._city.lower_corner) coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates,
self._city.lower_corner)
surface.setcoords(coordinates) surface.setcoords(coordinates)

View File

@ -20,8 +20,9 @@ class StoreysGeneration:
""" """
StoreysGeneration StoreysGeneration
""" """
def __init__(self, building, divide_in_storeys=False): def __init__(self, building, internal_zone, divide_in_storeys=False):
self._building = building self._building = building
self._internal_zone = internal_zone
self._thermal_zones = [] self._thermal_zones = []
self._divide_in_storeys = divide_in_storeys self._divide_in_storeys = divide_in_storeys
self._floor_area = 0 self._floor_area = 0
@ -39,7 +40,8 @@ class StoreysGeneration:
self._building.storeys_above_ground) self._building.storeys_above_ground)
number_of_storeys = 1 number_of_storeys = 1
if not self._divide_in_storeys or number_of_storeys == 1: if not self._divide_in_storeys or number_of_storeys == 1:
storey = Storey('storey_0', self._building.surfaces, [None, None], self._building.volume, self._floor_area) storey = Storey('storey_0', self._building.surfaces, [None, None], self._internal_zone.volume,
self._internal_zone, self._floor_area)
for thermal_boundary in storey.thermal_boundaries: for thermal_boundary in storey.thermal_boundaries:
if thermal_boundary.type != cte.INTERIOR_WALL or thermal_boundary.type != cte.INTERIOR_SLAB: if thermal_boundary.type != cte.INTERIOR_WALL or thermal_boundary.type != cte.INTERIOR_SLAB:
# external thermal boundary -> only one thermal zone # external thermal boundary -> only one thermal zone
@ -98,13 +100,13 @@ class StoreysGeneration:
surfaces_child.append(ceiling) surfaces_child.append(ceiling)
volume = ceiling.area_above_ground * height volume = ceiling.area_above_ground * height
total_volume += volume total_volume += volume
storeys.append(Storey(name, surfaces_child, neighbours, volume, self._floor_area)) storeys.append(Storey(name, surfaces_child, neighbours, volume, self._internal_zone, self._floor_area))
name = 'storey_' + str(number_of_storeys - 1) name = 'storey_' + str(number_of_storeys - 1)
neighbours = ['storey_' + str(number_of_storeys - 2), None] neighbours = ['storey_' + str(number_of_storeys - 2), None]
volume = self._building.volume - total_volume volume = self._building.volume - total_volume
if volume < 0: if volume < 0:
raise Exception('Error in storeys creation, volume of last storey cannot be lower that 0') raise Exception('Error in storeys creation, volume of last storey cannot be lower that 0')
storeys.append(Storey(name, surfaces_child_last_storey, neighbours, volume, self._floor_area)) storeys.append(Storey(name, surfaces_child_last_storey, neighbours, volume, self._internal_zone, self._floor_area))
for storey in storeys: for storey in storeys:
for thermal_boundary in storey.thermal_boundaries: for thermal_boundary in storey.thermal_boundaries:

View File

@ -234,5 +234,5 @@ class NrelPhysicsInterface:
def _create_storeys(building, archetype): def _create_storeys(building, archetype):
building.average_storey_height = archetype.average_storey_height building.average_storey_height = archetype.average_storey_height
building.storeys_above_ground = archetype.storeys_above_ground building.storeys_above_ground = archetype.storeys_above_ground
thermal_zones = StoreysGeneration(building).thermal_zones thermal_zones = StoreysGeneration(building, building.internal_zones[0]).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -72,8 +72,8 @@ class SanamCustomizedUsageParameters:
_occupancy = Occupancy() _occupancy = Occupancy()
usage_zone.occupancy = _occupancy usage_zone.occupancy = _occupancy
usage_zone.occupancy.occupancy_density = archetype.occupancy.occupancy_density usage_zone.occupancy.occupancy_density = archetype.occupancy.occupancy_density
archetype_mechanical_air_change = float(archetype.mechanical_air_change) * \ archetype_mechanical_air_change = float(archetype.mechanical_air_change) \
float(usage_zone.occupancy.occupancy_density) * cte.METERS_TO_FEET ** 2 \ * float(archetype.occupancy.occupancy_density) \
* cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET ** 3 / volume_per_area * cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET ** 3 / volume_per_area
usage_zone.mechanical_air_change = archetype_mechanical_air_change usage_zone.mechanical_air_change = archetype_mechanical_air_change

View File

@ -12,6 +12,7 @@ from imports.schedules.helpers.schedules_helper import SchedulesHelper
from city_model_structure.attributes.schedule import Schedule from city_model_structure.attributes.schedule import Schedule
from city_model_structure.building_demand.occupancy import Occupancy from city_model_structure.building_demand.occupancy import Occupancy
from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.lighting import Lighting
from city_model_structure.building_demand.thermal_control import ThermalControl
import helpers.constants as cte import helpers.constants as cte
@ -141,3 +142,7 @@ class DoeIdf:
if usage_zone.lighting is None: if usage_zone.lighting is None:
usage_zone.lighting = Lighting() usage_zone.lighting = Lighting()
usage_zone.lighting.schedules = [schedule] usage_zone.lighting.schedules = [schedule]
elif schedule.type == cte.HVAC_AVAILABILITY:
if usage_zone.thermal_control is None:
usage_zone.thermal_control = ThermalControl()
usage_zone.thermal_control.hvac_availability_schedules = [schedule]

View File

@ -64,7 +64,7 @@ class CaUsageParameters(HftUsageInterface):
usage_zone.hours_day = archetype.hours_day usage_zone.hours_day = archetype.hours_day
usage_zone.days_year = archetype.days_year usage_zone.days_year = archetype.days_year
_appliances = Appliances() _appliances = Appliances()
_appliances.appliances_density = archetype.appliances.appliances_density _appliances.density = archetype.appliances.density
usage_zone.appliances = _appliances usage_zone.appliances = _appliances
_control = ThermalControl() _control = ThermalControl()
_control.mean_heating_set_point = archetype.thermal_control.mean_heating_set_point _control.mean_heating_set_point = archetype.thermal_control.mean_heating_set_point

View File

@ -78,7 +78,7 @@ class ComnetUsageParameters:
_lighting.latent_fraction = ch().comnet_lighting_latent _lighting.latent_fraction = ch().comnet_lighting_latent
_lighting.convective_fraction = ch().comnet_lighting_convective _lighting.convective_fraction = ch().comnet_lighting_convective
_lighting.radiative_fraction = ch().comnet_lighting_radiant _lighting.radiative_fraction = ch().comnet_lighting_radiant
_lighting.lighting_density = data['lighting'][comnet_usage][4] _lighting.density = data['lighting'][comnet_usage][4]
# plug loads # plug loads
_appliances = None _appliances = None
@ -87,21 +87,22 @@ class ComnetUsageParameters:
_appliances.latent_fraction = ch().comnet_plugs_latent _appliances.latent_fraction = ch().comnet_plugs_latent
_appliances.convective_fraction = ch().comnet_plugs_convective _appliances.convective_fraction = ch().comnet_plugs_convective
_appliances.radiative_fraction = ch().comnet_plugs_radiant _appliances.radiative_fraction = ch().comnet_plugs_radiant
_appliances.appliances_density = data['plug loads'][comnet_usage][0] _appliances.density = data['plug loads'][comnet_usage][0]
# occupancy # occupancy
_occupancy = Occupancy() _occupancy = Occupancy()
_occupancy.occupancy_density = data['occupancy'][comnet_usage][0] value = data['occupancy'][comnet_usage][0]
if value != 0:
_occupancy.occupancy_density = value
else:
_occupancy.occupancy_density = 0
_occupancy.sensible_convective_internal_gain = data['occupancy'][comnet_usage][1] \ _occupancy.sensible_convective_internal_gain = data['occupancy'][comnet_usage][1] \
* ch().comnet_occupancy_sensible_convective * ch().comnet_occupancy_sensible_convective
_occupancy.sensible_radiative_internal_gain = data['occupancy'][comnet_usage][1] \ _occupancy.sensible_radiative_internal_gain = data['occupancy'][comnet_usage][1] \
* ch().comnet_occupancy_sensible_radiant * ch().comnet_occupancy_sensible_radiant
_occupancy.latent_internal_gain = data['occupancy'][comnet_usage][2] _occupancy.latent_internal_gain = data['occupancy'][comnet_usage][2]
if _occupancy.occupancy_density <= 0: _usage_zone.mechanical_air_change = data['ventilation rate'][comnet_usage][0]
_usage_zone.mechanical_air_change = 0
else:
_usage_zone.mechanical_air_change = data['ventilation rate'][comnet_usage][0] / _occupancy.occupancy_density
schedules_usage = UsageHelper.schedules_key(data['schedules_key'][comnet_usage][0]) schedules_usage = UsageHelper.schedules_key(data['schedules_key'][comnet_usage][0])
@ -225,21 +226,27 @@ class ComnetUsageParameters:
usage_zone.mechanical_air_change = archetype.mechanical_air_change * cte.METERS_TO_FEET ** 2 \ usage_zone.mechanical_air_change = archetype.mechanical_air_change * cte.METERS_TO_FEET ** 2 \
* cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET ** 3 / volume_per_area * cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET ** 3 / volume_per_area
_occupancy = Occupancy() _occupancy = Occupancy()
_occupancy.occupancy_density = archetype.occupancy.occupancy_density * cte.METERS_TO_FEET**2 _occupancy.occupancy_density = archetype.occupancy.occupancy_density / cte.METERS_TO_FEET**2
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain _occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain \
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain * archetype.occupancy.occupancy_density / cte.METERS_TO_FEET**2 \
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain * cte.BTU_H_TO_WATTS
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain \
* archetype.occupancy.occupancy_density / cte.METERS_TO_FEET**2 \
* cte.BTU_H_TO_WATTS
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain \
* archetype.occupancy.occupancy_density / cte.METERS_TO_FEET**2 \
* cte.BTU_H_TO_WATTS
_occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules _occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules
usage_zone.occupancy = _occupancy usage_zone.occupancy = _occupancy
_lighting = Lighting() _lighting = Lighting()
_lighting.lighting_density = archetype.lighting.lighting_density / cte.METERS_TO_FEET**2 _lighting.density = archetype.lighting.density / cte.METERS_TO_FEET ** 2
_lighting.convective_fraction = archetype.lighting.convective_fraction _lighting.convective_fraction = archetype.lighting.convective_fraction
_lighting.radiative_fraction = archetype.lighting.radiative_fraction _lighting.radiative_fraction = archetype.lighting.radiative_fraction
_lighting.latent_fraction = archetype.lighting.latent_fraction _lighting.latent_fraction = archetype.lighting.latent_fraction
_lighting.schedules = archetype.lighting.schedules _lighting.schedules = archetype.lighting.schedules
usage_zone.lighting = _lighting usage_zone.lighting = _lighting
_appliances = Appliances() _appliances = Appliances()
_appliances.appliances_density = archetype.appliances.appliances_density / cte.METERS_TO_FEET**2 _appliances.density = archetype.appliances.density / cte.METERS_TO_FEET ** 2
_appliances.convective_fraction = archetype.appliances.convective_fraction _appliances.convective_fraction = archetype.appliances.convective_fraction
_appliances.radiative_fraction = archetype.appliances.radiative_fraction _appliances.radiative_fraction = archetype.appliances.radiative_fraction
_appliances.latent_fraction = archetype.appliances.latent_fraction _appliances.latent_fraction = archetype.appliances.latent_fraction

View File

@ -125,7 +125,7 @@ class HftUsageInterface:
if 'appliance' in zone_usage_type: if 'appliance' in zone_usage_type:
_appliances = Appliances() _appliances = Appliances()
_appliances.appliances_density = zone_usage_type['appliance']['#text'] #todo: check units _appliances.density = zone_usage_type['appliance']['#text'] #todo: check units
usage_zone_archetype.appliances = _appliances usage_zone_archetype.appliances = _appliances
@ -220,7 +220,7 @@ class HftUsageInterface:
if 'appliance' in usage_zone_variant: if 'appliance' in usage_zone_variant:
_appliances = Appliances() _appliances = Appliances()
_appliances.appliances_density = usage_zone_variant['appliance']['#text'] # todo: check units _appliances.density = usage_zone_variant['appliance']['#text'] # todo: check units
usage_zone_archetype.appliances = _appliances usage_zone_archetype.appliances = _appliances

View File

@ -6,7 +6,6 @@ pandas~=1.2.3
requests~=2.25.1 requests~=2.25.1
esoreader~=1.2.3 esoreader~=1.2.3
geomeppy~=0.11.8 geomeppy~=0.11.8
pathlib~=1.0.1
PyWavefront~=1.3.3 PyWavefront~=1.3.3
xlrd~=2.0.1 xlrd~=2.0.1
openpyxl~=3.0.7 openpyxl~=3.0.7
@ -16,5 +15,4 @@ ply~=3.11
rhino3dm~=7.7.0 rhino3dm~=7.7.0
scipy==1.7.1 scipy==1.7.1
PyYAML==6.0 PyYAML==6.0
yaml~=0.2.5
pyecore~=0.12.2 pyecore~=0.12.2

View File

@ -29,9 +29,11 @@ class TestBuildings(TestCase):
output_path = Path('../unittests/tests_outputs/').resolve() output_path = Path('../unittests/tests_outputs/').resolve()
city = GeometryFactory('citygml', city_file).city city = GeometryFactory('citygml', city_file).city
ConstructionFactory('nrel', city).enrich() ConstructionFactory('nrel', city).enrich()
UsageFactory('ca', city).enrich() UsageFactory('comnet', city).enrich()
SchedulesFactory('doe_idf', city).enrich() # UsageFactory('ca', city).enrich()
# SchedulesFactory('doe_idf', city).enrich()
ExportsFactory('idf', city, output_path).export() ExportsFactory('idf', city, output_path).export()
self.assertEqual(10, len(city.buildings)) self.assertEqual(10, len(city.buildings))
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:

View File

@ -9,7 +9,6 @@ from unittest import TestCase
from imports.geometry_factory import GeometryFactory from imports.geometry_factory import GeometryFactory
from imports.usage_factory import UsageFactory from imports.usage_factory import UsageFactory
from imports.geometry.helpers.geometry_helper import GeometryHelper from imports.geometry.helpers.geometry_helper import GeometryHelper
from imports.construction_factory import ConstructionFactory
class TestUsageFactory(TestCase): class TestUsageFactory(TestCase):
@ -113,14 +112,14 @@ class TestUsageFactory(TestCase):
self.assertIsNone(occupancy.occupants, 'occupancy density is not none') self.assertIsNone(occupancy.occupants, 'occupancy density is not none')
self.assertIsNotNone(usage_zone.lighting, 'lighting is none') self.assertIsNotNone(usage_zone.lighting, 'lighting is none')
lighting = usage_zone.lighting lighting = usage_zone.lighting
self.assertIsNotNone(lighting.lighting_density, 'lighting density is none') self.assertIsNotNone(lighting.density, 'lighting density is none')
self.assertIsNotNone(lighting.latent_fraction, 'lighting latent fraction is none') self.assertIsNotNone(lighting.latent_fraction, 'lighting latent fraction is none')
self.assertIsNotNone(lighting.convective_fraction, 'lighting convective fraction is none') self.assertIsNotNone(lighting.convective_fraction, 'lighting convective fraction is none')
self.assertIsNotNone(lighting.radiative_fraction, 'lighting radiant fraction is none') self.assertIsNotNone(lighting.radiative_fraction, 'lighting radiant fraction is none')
self.assertIsNotNone(lighting.schedules, 'lighting schedule is none') self.assertIsNotNone(lighting.schedules, 'lighting schedule is none')
self.assertIsNotNone(usage_zone.appliances, 'appliances is none') self.assertIsNotNone(usage_zone.appliances, 'appliances is none')
appliances = usage_zone.appliances appliances = usage_zone.appliances
self.assertIsNotNone(appliances.appliances_density, 'appliances density is none') self.assertIsNotNone(appliances.density, 'appliances density is none')
self.assertIsNotNone(appliances.latent_fraction, 'appliances latent fraction is none') self.assertIsNotNone(appliances.latent_fraction, 'appliances latent fraction is none')
self.assertIsNotNone(appliances.convective_fraction, 'appliances convective fraction is none') self.assertIsNotNone(appliances.convective_fraction, 'appliances convective fraction is none')
self.assertIsNotNone(appliances.radiative_fraction, 'appliances radiant fraction is none') self.assertIsNotNone(appliances.radiative_fraction, 'appliances radiant fraction is none')