solving bugs from adding thermal_archetypes to the data model

This commit is contained in:
Pilar Monsalvete 2023-08-03 13:49:57 -04:00
parent 4b5c037ffa
commit fe8c79d7c2
11 changed files with 124 additions and 106 deletions

View File

@ -114,7 +114,8 @@ class Building(CityObject):
:return: [InternalZone] :return: [InternalZone]
""" """
if self._internal_zones is None: if self._internal_zones is None:
self._internal_zones = [InternalZone(self.surfaces, self.floor_area, self.volume)] _number_of_storeys = self.eave_height * self.volume / self.floor_area
self._internal_zones = [InternalZone(self.surfaces, self.floor_area, self.volume, _number_of_storeys)]
return self._internal_zones return self._internal_zones
@property @property
@ -258,6 +259,12 @@ class Building(CityObject):
Get building average storey height in meters Get building average storey height in meters
:return: None or float :return: None or float
""" """
if len(self.internal_zones) > 1:
self._average_storey_height = 0
for internal_zone in self.internal_zones:
self._average_storey_height += internal_zone.mean_height / len(self.internal_zones)
else:
self._average_storey_height = self.internal_zones[0].thermal_archetype.average_storey_height
return self._average_storey_height return self._average_storey_height
@average_storey_height.setter @average_storey_height.setter
@ -393,6 +400,7 @@ class Building(CityObject):
""" """
results = {} results = {}
peak_lighting = 0 peak_lighting = 0
peak = 0
for thermal_zone in self.thermal_zones_from_internal_zones: for thermal_zone in self.thermal_zones_from_internal_zones:
lighting = thermal_zone.lighting lighting = thermal_zone.lighting
for schedule in lighting.schedules: for schedule in lighting.schedules:
@ -411,6 +419,7 @@ class Building(CityObject):
""" """
results = {} results = {}
peak_appliances = 0 peak_appliances = 0
peak = 0
for thermal_zone in self.thermal_zones_from_internal_zones: for thermal_zone in self.thermal_zones_from_internal_zones:
appliances = thermal_zone.appliances appliances = thermal_zone.appliances
for schedule in appliances.schedules: for schedule in appliances.schedules:

View File

@ -8,6 +8,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import uuid import uuid
from typing import Union, List from typing import Union, List
from hub.city_model_structure.building_demand.usage import Usage from hub.city_model_structure.building_demand.usage import Usage
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
from hub.city_model_structure.building_demand.thermal_boundary import ThermalBoundary from hub.city_model_structure.building_demand.thermal_boundary import ThermalBoundary
from hub.city_model_structure.attributes.polyhedron import Polyhedron from hub.city_model_structure.attributes.polyhedron import Polyhedron
@ -18,14 +19,16 @@ class InternalZone:
""" """
InternalZone class InternalZone class
""" """
def __init__(self, surfaces, area, volume): def __init__(self, surfaces, area, volume, number_of_storeys=None):
self._surfaces = surfaces self._surfaces = surfaces
self._id = None self._id = None
self._geometry = None self._geometry = None
self._volume = volume self._volume = volume
self._area = area self._area = area
self._number_of_storeys = number_of_storeys
self._thermal_zones_from_internal_zones = None self._thermal_zones_from_internal_zones = None
self._usages = None self._usages = None
self._thermal_archetype = None
self._hvac_system = None self._hvac_system = None
@property @property
@ -75,10 +78,18 @@ class InternalZone:
""" """
return self._area return self._area
@property
def mean_height(self):
"""
Get internal zone mean height in meters
:return: float
"""
return self.volume / self.area
@property @property
def usages(self) -> [Usage]: def usages(self) -> [Usage]:
""" """
Get internal zone usage zones Get usage archetypes
:return: [Usage] :return: [Usage]
""" """
return self._usages return self._usages
@ -86,11 +97,27 @@ class InternalZone:
@usages.setter @usages.setter
def usages(self, value): def usages(self, value):
""" """
Set internal zone usage zones Set usage archetypes
:param value: [Usage] :param value: [Usage]
""" """
self._usages = value self._usages = value
@property
def thermal_archetype(self) -> ThermalArchetype:
"""
Get thermal archetype parameters
:return: ThermalArchetype
"""
return self._thermal_archetype
@thermal_archetype.setter
def thermal_archetype(self, value):
"""
Set thermal archetype parameters
:param value: ThermalArchetype
"""
self._thermal_archetype = value
@property @property
def hvac_system(self) -> Union[None, HvacSystem]: def hvac_system(self) -> Union[None, HvacSystem]:
""" """
@ -123,7 +150,9 @@ class InternalZone:
windows_areas.append(hole.area) windows_areas.append(hole.area)
_thermal_boundary = ThermalBoundary(surface, surface.solid_polygon.area, windows_areas) _thermal_boundary = ThermalBoundary(surface, surface.solid_polygon.area, windows_areas)
_thermal_boundaries.append(_thermal_boundary) _thermal_boundaries.append(_thermal_boundary)
_thermal_zone = ThermalZone(_thermal_boundaries, self, self.volume, self.area) _thermal_zone = ThermalZone(_thermal_boundaries, self, self.volume, self.area, self._number_of_storeys)
for thermal_boundary in _thermal_zone.thermal_boundaries:
thermal_boundary.thermal_zones = [_thermal_zone]
self._thermal_zones_from_internal_zones = [_thermal_zone] self._thermal_zones_from_internal_zones = [_thermal_zone]
return self._thermal_zones_from_internal_zones return self._thermal_zones_from_internal_zones

View File

@ -29,6 +29,14 @@ class ThermalArchetype:
""" """
return self._constructions return self._constructions
@constructions.setter
def constructions(self, value):
"""
Set archetype constructions
:param value: [Construction]
"""
self._constructions = value
@property @property
def average_storey_height(self): def average_storey_height(self):
""" """

View File

@ -7,7 +7,9 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
""" """
import uuid import uuid
import math
from typing import List, Union, TypeVar from typing import List, Union, TypeVar
import logging
from hub.helpers.configuration_helper import ConfigurationHelper as ch from hub.helpers.configuration_helper import ConfigurationHelper as ch
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.city_model_structure.building_demand.layer import Layer from hub.city_model_structure.building_demand.layer import Layer
@ -92,7 +94,7 @@ class ThermalBoundary:
self._thickness = 0.0 self._thickness = 0.0
if self.layers is not None: if self.layers is not None:
for layer in self.layers: for layer in self.layers:
if not layer.material.no_mass: if not layer.no_mass:
self._thickness += layer.thickness self._thickness += layer.thickness
return self._thickness return self._thickness
@ -148,24 +150,21 @@ class ThermalBoundary:
else: else:
_area = self.opaque_area * self.window_ratio / (1-self.window_ratio) _area = self.opaque_area * self.window_ratio / (1-self.window_ratio)
_thermal_opening.area = _area _thermal_opening.area = _area
self._thermal_openings = [_thermal_opening]
for thermal_opening in self._thermal_openings:
thermal_opening.g_value = self._construction_archetype.window_g_value
thermal_opening.overall_u_value = self._construction_archetype.window_overall_u_value
thermal_opening.frame_ratio = self._construction_archetype.window_frame_ratio
thermal_opening.construction_name = self._construction_archetype.window_type
return self._thermal_openings return self._thermal_openings
@property @property
def construction_name(self) -> Union[None, str]: def _construction_archetype(self):
""" construction_archetypes = self.thermal_zones[0].parent_internal_zone.thermal_archetype.constructions
Get construction name for construction_archetype in construction_archetypes:
:return: None or str if str(self.type) == str(construction_archetype.type):
""" return construction_archetype
return self._construction_name return None
@construction_name.setter
def construction_name(self, value):
"""
Set construction name
:param value: str
"""
if value is not None:
self._construction_name = str(value)
@property @property
def layers(self) -> List[Layer]: def layers(self) -> List[Layer]:
@ -173,16 +172,13 @@ class ThermalBoundary:
Get thermal boundary layers Get thermal boundary layers
:return: [Layers] :return: [Layers]
""" """
if self._construction_archetype is not None:
self._layers = self._construction_archetype.layers
else:
logging.error('Layers not defined\n')
raise ValueError('Layers not defined')
return self._layers return self._layers
@layers.setter
def layers(self, value):
"""
Set thermal boundary layers
:param value: [Layer]
"""
self._layers = value
@property @property
def type(self): def type(self):
""" """
@ -209,18 +205,23 @@ class ThermalBoundary:
for window_area in self.windows_areas: for window_area in self.windows_areas:
total_window_area += window_area total_window_area += window_area
self._window_ratio = total_window_area / (self.opaque_area + total_window_area) self._window_ratio = total_window_area / (self.opaque_area + total_window_area)
else:
if self.type in (cte.WALL, cte.ROOF):
if -math.sqrt(2) / 2 < math.sin(self.parent_surface.azimuth) < math.sqrt(2) / 2:
if 0 < math.cos(self.parent_surface.azimuth):
self._window_ratio = \
float(self._construction_archetype.window_ratio['north']) / 100
else:
self._window_ratio = \
float(self._construction_archetype.window_ratio['south']) / 100
elif math.sqrt(2) / 2 <= math.sin(self._parent_surface.azimuth):
self._window_ratio = \
float(self._construction_archetype.window_ratio['east']) / 100
else:
self._window_ratio = \
float(self._construction_archetype.window_ratio['west']) / 100
return self._window_ratio return self._window_ratio
@window_ratio.setter
def window_ratio(self, value):
"""
Set thermal boundary window ratio
:param value: str
"""
if self._window_ratio_to_be_calculated:
raise ValueError('Window ratio cannot be assigned when the windows are defined in the geometry.')
self._window_ratio = float(value)
@property @property
def windows_areas(self) -> [float]: def windows_areas(self) -> [float]:
""" """
@ -245,10 +246,10 @@ class ThermalBoundary:
r_value = 1.0/h_i + 1.0/h_e r_value = 1.0/h_i + 1.0/h_e
try: try:
for layer in self.layers: for layer in self.layers:
if layer.material.no_mass: if layer.no_mass:
r_value += float(layer.material.thermal_resistance) r_value += float(layer.thermal_resistance)
else: else:
r_value += float(layer.thickness) / float(layer.material.conductivity) r_value += float(layer.thickness) / float(layer.conductivity)
self._u_value = 1.0/r_value self._u_value = 1.0/r_value
except TypeError: except TypeError:
raise TypeError('Constructions layers are not initialized') from TypeError raise TypeError('Constructions layers are not initialized') from TypeError

View File

@ -29,7 +29,12 @@ class ThermalZone:
ThermalZone class ThermalZone class
""" """
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage_name=None): def __init__(self, thermal_boundaries,
parent_internal_zone,
volume,
footprint_area,
number_of_storeys,
usage_name=None):
self._id = None self._id = None
self._parent_internal_zone = parent_internal_zone self._parent_internal_zone = parent_internal_zone
self._footprint_area = footprint_area self._footprint_area = footprint_area
@ -43,6 +48,7 @@ class ThermalZone:
self._ordinate_number = None self._ordinate_number = None
self._view_factors_matrix = None self._view_factors_matrix = None
self._total_floor_area = None self._total_floor_area = None
self._number_of_storeys = number_of_storeys
self._usage_name = usage_name self._usage_name = usage_name
self._usage_from_parent = False self._usage_from_parent = False
if usage_name is None: if usage_name is None:
@ -58,6 +64,14 @@ class ThermalZone:
self._domestic_hot_water = None self._domestic_hot_water = None
self._usages = None self._usages = None
@property
def parent_internal_zone(self) -> InternalZone:
"""
Get the internal zone to which this thermal zone belongs
:return: InternalZone
"""
return self._parent_internal_zone
@property @property
def usages(self): def usages(self):
""" """
@ -113,83 +127,45 @@ class ThermalZone:
Get thermal zone additional thermal bridge u value per footprint area W/m2K Get thermal zone additional thermal bridge u value per footprint area W/m2K
:return: None or float :return: None or float
""" """
self._additional_thermal_bridge_u_value = self.parent_internal_zone.thermal_archetype.extra_loses_due_to_thermal_bridges
return self._additional_thermal_bridge_u_value return self._additional_thermal_bridge_u_value
@additional_thermal_bridge_u_value.setter
def additional_thermal_bridge_u_value(self, value):
"""
Set thermal zone additional thermal bridge u value per footprint area W/m2K
:param value: float
"""
if value is not None:
self._additional_thermal_bridge_u_value = float(value)
@property @property
def effective_thermal_capacity(self) -> Union[None, float]: def effective_thermal_capacity(self) -> Union[None, float]:
""" """
Get thermal zone effective thermal capacity in J/m3K Get thermal zone effective thermal capacity in J/m3K
:return: None or float :return: None or float
""" """
self._effective_thermal_capacity = self._parent_internal_zone.thermal_archetype.thermal_capacity
return self._effective_thermal_capacity return self._effective_thermal_capacity
@effective_thermal_capacity.setter
def effective_thermal_capacity(self, value):
"""
Set thermal zone effective thermal capacity in J/m3K
:param value: float
"""
if value is not None:
self._effective_thermal_capacity = float(value)
@property @property
def indirectly_heated_area_ratio(self) -> Union[None, float]: def indirectly_heated_area_ratio(self) -> Union[None, float]:
""" """
Get thermal zone indirectly heated area ratio Get thermal zone indirectly heated area ratio
:return: None or float :return: None or float
""" """
self._indirectly_heated_area_ratio = self._parent_internal_zone.thermal_archetype.indirect_heated_ratio
return self._indirectly_heated_area_ratio return self._indirectly_heated_area_ratio
@indirectly_heated_area_ratio.setter
def indirectly_heated_area_ratio(self, value):
"""
Set thermal zone indirectly heated area ratio
:param value: float
"""
if value is not None:
self._indirectly_heated_area_ratio = float(value)
@property @property
def infiltration_rate_system_on(self): def infiltration_rate_system_on(self):
""" """
Get thermal zone infiltration rate system on in air changes per hour (ACH) Get thermal zone infiltration rate system on in air changes per hour (ACH)
:return: None or float :return: None or float
""" """
self._infiltration_rate_system_on = self._parent_internal_zone.thermal_archetype.infiltration_rate_for_ventilation_system_on
return self._infiltration_rate_system_on return self._infiltration_rate_system_on
@infiltration_rate_system_on.setter
def infiltration_rate_system_on(self, value):
"""
Set thermal zone infiltration rate system on in air changes per hour (ACH)
:param value: float
"""
self._infiltration_rate_system_on = value
@property @property
def infiltration_rate_system_off(self): def infiltration_rate_system_off(self):
""" """
Get thermal zone infiltration rate system off in air changes per hour (ACH) Get thermal zone infiltration rate system off in air changes per hour (ACH)
:return: None or float :return: None or float
""" """
self._infiltration_rate_system_off = self._parent_internal_zone.thermal_archetype.infiltration_rate_for_ventilation_system_off
return self._infiltration_rate_system_off return self._infiltration_rate_system_off
@infiltration_rate_system_off.setter
def infiltration_rate_system_off(self, value):
"""
Set thermal zone infiltration rate system on in air changes per hour (ACH)
:param value: float
"""
self._infiltration_rate_system_off = value
@property @property
def volume(self): def volume(self):
""" """
@ -684,12 +660,5 @@ class ThermalZone:
Get the total floor area of this thermal zone Get the total floor area of this thermal zone
:return: float :return: float
""" """
self._total_floor_area = self.footprint_area * self._number_of_storeys
return self._total_floor_area return self._total_floor_area
@total_floor_area.setter
def total_floor_area(self, value):
"""
Set the total floor area of this thermal zone
:param value: float
"""
self._total_floor_area = value

View File

@ -62,11 +62,3 @@ class ThermalZonesCreation:
thermal_zones = StoreysGeneration(building, building.internal_zones[0], thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones_from_internal_zones = thermal_zones building.internal_zones[0].thermal_zones_from_internal_zones = thermal_zones
@staticmethod
def _search_construction_in_archetype(archetype, construction_type):
construction_archetypes = archetype.constructions
for construction_archetype in construction_archetypes:
if str(construction_type) == str(construction_archetype.type):
return construction_archetype
return None

View File

@ -59,6 +59,7 @@ class EilatPhysicsParameters:
@staticmethod @staticmethod
def _assign_values(thermal_archetype, catalog_archetype): def _assign_values(thermal_archetype, catalog_archetype):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges
thermal_archetype.indirect_heated_ratio = 0 thermal_archetype.indirect_heated_ratio = 0
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on

View File

@ -5,8 +5,6 @@ Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from hub.helpers import constants as cte
class ConstructionHelper: class ConstructionHelper:
""" """

View File

@ -46,6 +46,8 @@ class NrcanPhysicsParameters:
continue continue
thermal_archetype = ThermalArchetype() thermal_archetype = ThermalArchetype()
self._assign_values(thermal_archetype, archetype) self._assign_values(thermal_archetype, archetype)
for internal_zone in building.internal_zones:
internal_zone.thermal_archetype = thermal_archetype
@staticmethod @staticmethod
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone): def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
@ -59,13 +61,20 @@ class NrcanPhysicsParameters:
@staticmethod @staticmethod
def _assign_values(thermal_archetype, catalog_archetype): def _assign_values(thermal_archetype, catalog_archetype):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges
thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity
thermal_archetype.indirect_heated_ratio = 0 thermal_archetype.indirect_heated_ratio = 0
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on
thermal_archetype.infiltration_rate_for_ventilation_system_off = catalog_archetype.infiltration_rate_for_ventilation_system_off thermal_archetype.infiltration_rate_for_ventilation_system_off = catalog_archetype.infiltration_rate_for_ventilation_system_off
_constructions = []
for catalog_construction in catalog_archetype.constructions: for catalog_construction in catalog_archetype.constructions:
construction = Construction() construction = Construction()
construction.type = catalog_construction.type
if catalog_construction.window_ratio is not None:
for _orientation in catalog_construction.window_ratio:
if catalog_construction.window_ratio[_orientation] is None:
catalog_construction.window_ratio[_orientation] = 0
construction.window_ratio = catalog_construction.window_ratio construction.window_ratio = catalog_construction.window_ratio
_layers = [] _layers = []
for layer_archetype in catalog_construction.layers: for layer_archetype in catalog_construction.layers:
@ -91,3 +100,5 @@ class NrcanPhysicsParameters:
construction.window_frame_ratio = window_archetype.frame_ratio construction.window_frame_ratio = window_archetype.frame_ratio
construction.window_g_value = window_archetype.g_value construction.window_g_value = window_archetype.g_value
construction.window_overall_u_value = window_archetype.overall_u_value construction.window_overall_u_value = window_archetype.overall_u_value
_constructions.append(construction)
thermal_archetype.constructions = _constructions

View File

@ -61,6 +61,7 @@ class NrelPhysicsParameters:
@staticmethod @staticmethod
def _assign_values(thermal_archetype, catalog_archetype): def _assign_values(thermal_archetype, catalog_archetype):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges
thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity
thermal_archetype.indirect_heated_ratio = catalog_archetype.indirect_heated_ratio thermal_archetype.indirect_heated_ratio = catalog_archetype.indirect_heated_ratio

View File

@ -133,12 +133,11 @@ class TestConstructionFactory(TestCase):
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.id, 'thermal_boundary id is none') self.assertIsNotNone(thermal_boundary.id, 'thermal_boundary id is none')
self.assertIsNotNone(thermal_boundary.parent_surface, 'thermal_boundary surface is none') self.assertIsNotNone(thermal_boundary.parent_surface, 'thermal_boundary surface is none')
self.assertIsNotNone(thermal_boundary.thermal_zones_from_internal_zones, 'thermal_boundary delimits no thermal zone') self.assertIsNotNone(thermal_boundary.thermal_zones, 'thermal_boundary delimits no thermal zone')
self.assertIsNotNone(thermal_boundary.opaque_area, 'thermal_boundary area is none') self.assertIsNotNone(thermal_boundary.opaque_area, 'thermal_boundary area is none')
self.assertIsNotNone(thermal_boundary.thickness, 'thermal_boundary thickness is none') self.assertIsNotNone(thermal_boundary.thickness, 'thermal_boundary thickness is none')
self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type is none') self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type is none')
self.assertIsNotNone(thermal_boundary.thermal_openings, 'thermal_openings is none') self.assertIsNotNone(thermal_boundary.thermal_openings, 'thermal_openings is none')
self.assertIsNotNone(thermal_boundary.construction_name, 'construction_name is none')
self.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none') self.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none')
self.assertIsNone(thermal_boundary.windows_areas, 'windows_areas is not none') self.assertIsNone(thermal_boundary.windows_areas, 'windows_areas is not none')
self.assertIsNotNone(thermal_boundary.u_value, 'u_value is none') self.assertIsNotNone(thermal_boundary.u_value, 'u_value is none')