forked from s_ranjbar/city_retrofit
solving bugs from adding thermal_archetypes to the data model
This commit is contained in:
parent
4b5c037ffa
commit
fe8c79d7c2
|
@ -114,7 +114,8 @@ class Building(CityObject):
|
|||
:return: [InternalZone]
|
||||
"""
|
||||
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
|
||||
|
||||
@property
|
||||
|
@ -258,6 +259,12 @@ class Building(CityObject):
|
|||
Get building average storey height in meters
|
||||
: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
|
||||
|
||||
@average_storey_height.setter
|
||||
|
@ -393,6 +400,7 @@ class Building(CityObject):
|
|||
"""
|
||||
results = {}
|
||||
peak_lighting = 0
|
||||
peak = 0
|
||||
for thermal_zone in self.thermal_zones_from_internal_zones:
|
||||
lighting = thermal_zone.lighting
|
||||
for schedule in lighting.schedules:
|
||||
|
@ -411,6 +419,7 @@ class Building(CityObject):
|
|||
"""
|
||||
results = {}
|
||||
peak_appliances = 0
|
||||
peak = 0
|
||||
for thermal_zone in self.thermal_zones_from_internal_zones:
|
||||
appliances = thermal_zone.appliances
|
||||
for schedule in appliances.schedules:
|
||||
|
|
|
@ -8,6 +8,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|||
import uuid
|
||||
from typing import Union, List
|
||||
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_boundary import ThermalBoundary
|
||||
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
||||
|
@ -18,14 +19,16 @@ class InternalZone:
|
|||
"""
|
||||
InternalZone class
|
||||
"""
|
||||
def __init__(self, surfaces, area, volume):
|
||||
def __init__(self, surfaces, area, volume, number_of_storeys=None):
|
||||
self._surfaces = surfaces
|
||||
self._id = None
|
||||
self._geometry = None
|
||||
self._volume = volume
|
||||
self._area = area
|
||||
self._number_of_storeys = number_of_storeys
|
||||
self._thermal_zones_from_internal_zones = None
|
||||
self._usages = None
|
||||
self._thermal_archetype = None
|
||||
self._hvac_system = None
|
||||
|
||||
@property
|
||||
|
@ -75,10 +78,18 @@ class InternalZone:
|
|||
"""
|
||||
return self._area
|
||||
|
||||
@property
|
||||
def mean_height(self):
|
||||
"""
|
||||
Get internal zone mean height in meters
|
||||
:return: float
|
||||
"""
|
||||
return self.volume / self.area
|
||||
|
||||
@property
|
||||
def usages(self) -> [Usage]:
|
||||
"""
|
||||
Get internal zone usage zones
|
||||
Get usage archetypes
|
||||
:return: [Usage]
|
||||
"""
|
||||
return self._usages
|
||||
|
@ -86,11 +97,27 @@ class InternalZone:
|
|||
@usages.setter
|
||||
def usages(self, value):
|
||||
"""
|
||||
Set internal zone usage zones
|
||||
Set usage archetypes
|
||||
:param value: [Usage]
|
||||
"""
|
||||
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
|
||||
def hvac_system(self) -> Union[None, HvacSystem]:
|
||||
"""
|
||||
|
@ -123,7 +150,9 @@ class InternalZone:
|
|||
windows_areas.append(hole.area)
|
||||
_thermal_boundary = ThermalBoundary(surface, surface.solid_polygon.area, windows_areas)
|
||||
_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]
|
||||
return self._thermal_zones_from_internal_zones
|
||||
|
||||
|
|
|
@ -29,6 +29,14 @@ class ThermalArchetype:
|
|||
"""
|
||||
return self._constructions
|
||||
|
||||
@constructions.setter
|
||||
def constructions(self, value):
|
||||
"""
|
||||
Set archetype constructions
|
||||
:param value: [Construction]
|
||||
"""
|
||||
self._constructions = value
|
||||
|
||||
@property
|
||||
def average_storey_height(self):
|
||||
"""
|
||||
|
|
|
@ -7,7 +7,9 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
|||
"""
|
||||
|
||||
import uuid
|
||||
import math
|
||||
from typing import List, Union, TypeVar
|
||||
import logging
|
||||
from hub.helpers.configuration_helper import ConfigurationHelper as ch
|
||||
import hub.helpers.constants as cte
|
||||
from hub.city_model_structure.building_demand.layer import Layer
|
||||
|
@ -92,7 +94,7 @@ class ThermalBoundary:
|
|||
self._thickness = 0.0
|
||||
if self.layers is not None:
|
||||
for layer in self.layers:
|
||||
if not layer.material.no_mass:
|
||||
if not layer.no_mass:
|
||||
self._thickness += layer.thickness
|
||||
return self._thickness
|
||||
|
||||
|
@ -148,24 +150,21 @@ class ThermalBoundary:
|
|||
else:
|
||||
_area = self.opaque_area * self.window_ratio / (1-self.window_ratio)
|
||||
_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
|
||||
|
||||
@property
|
||||
def construction_name(self) -> Union[None, str]:
|
||||
"""
|
||||
Get construction name
|
||||
:return: None or str
|
||||
"""
|
||||
return self._construction_name
|
||||
|
||||
@construction_name.setter
|
||||
def construction_name(self, value):
|
||||
"""
|
||||
Set construction name
|
||||
:param value: str
|
||||
"""
|
||||
if value is not None:
|
||||
self._construction_name = str(value)
|
||||
def _construction_archetype(self):
|
||||
construction_archetypes = self.thermal_zones[0].parent_internal_zone.thermal_archetype.constructions
|
||||
for construction_archetype in construction_archetypes:
|
||||
if str(self.type) == str(construction_archetype.type):
|
||||
return construction_archetype
|
||||
return None
|
||||
|
||||
@property
|
||||
def layers(self) -> List[Layer]:
|
||||
|
@ -173,16 +172,13 @@ class ThermalBoundary:
|
|||
Get thermal boundary 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
|
||||
|
||||
@layers.setter
|
||||
def layers(self, value):
|
||||
"""
|
||||
Set thermal boundary layers
|
||||
:param value: [Layer]
|
||||
"""
|
||||
self._layers = value
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
|
@ -209,18 +205,23 @@ class ThermalBoundary:
|
|||
for window_area in self.windows_areas:
|
||||
total_window_area += 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
|
||||
|
||||
@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
|
||||
def windows_areas(self) -> [float]:
|
||||
"""
|
||||
|
@ -245,10 +246,10 @@ class ThermalBoundary:
|
|||
r_value = 1.0/h_i + 1.0/h_e
|
||||
try:
|
||||
for layer in self.layers:
|
||||
if layer.material.no_mass:
|
||||
r_value += float(layer.material.thermal_resistance)
|
||||
if layer.no_mass:
|
||||
r_value += float(layer.thermal_resistance)
|
||||
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
|
||||
except TypeError:
|
||||
raise TypeError('Constructions layers are not initialized') from TypeError
|
||||
|
|
|
@ -29,7 +29,12 @@ class ThermalZone:
|
|||
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._parent_internal_zone = parent_internal_zone
|
||||
self._footprint_area = footprint_area
|
||||
|
@ -43,6 +48,7 @@ class ThermalZone:
|
|||
self._ordinate_number = None
|
||||
self._view_factors_matrix = None
|
||||
self._total_floor_area = None
|
||||
self._number_of_storeys = number_of_storeys
|
||||
self._usage_name = usage_name
|
||||
self._usage_from_parent = False
|
||||
if usage_name is None:
|
||||
|
@ -58,6 +64,14 @@ class ThermalZone:
|
|||
self._domestic_hot_water = 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
|
||||
def usages(self):
|
||||
"""
|
||||
|
@ -113,83 +127,45 @@ class ThermalZone:
|
|||
Get thermal zone additional thermal bridge u value per footprint area W/m2K
|
||||
: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
|
||||
|
||||
@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
|
||||
def effective_thermal_capacity(self) -> Union[None, float]:
|
||||
"""
|
||||
Get thermal zone effective thermal capacity in J/m3K
|
||||
:return: None or float
|
||||
"""
|
||||
self._effective_thermal_capacity = self._parent_internal_zone.thermal_archetype.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
|
||||
def indirectly_heated_area_ratio(self) -> Union[None, float]:
|
||||
"""
|
||||
Get thermal zone indirectly heated area ratio
|
||||
:return: None or float
|
||||
"""
|
||||
self._indirectly_heated_area_ratio = self._parent_internal_zone.thermal_archetype.indirect_heated_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
|
||||
def infiltration_rate_system_on(self):
|
||||
"""
|
||||
Get thermal zone infiltration rate system on in air changes per hour (ACH)
|
||||
: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
|
||||
|
||||
@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
|
||||
def infiltration_rate_system_off(self):
|
||||
"""
|
||||
Get thermal zone infiltration rate system off in air changes per hour (ACH)
|
||||
: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
|
||||
|
||||
@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
|
||||
def volume(self):
|
||||
"""
|
||||
|
@ -684,12 +660,5 @@ class ThermalZone:
|
|||
Get the total floor area of this thermal zone
|
||||
:return: float
|
||||
"""
|
||||
self._total_floor_area = self.footprint_area * self._number_of_storeys
|
||||
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
|
||||
|
|
|
@ -62,11 +62,3 @@ class ThermalZonesCreation:
|
|||
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
|
||||
divide_in_storeys=divide_in_storeys).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
|
||||
|
|
|
@ -59,6 +59,7 @@ class EilatPhysicsParameters:
|
|||
|
||||
@staticmethod
|
||||
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.indirect_heated_ratio = 0
|
||||
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on
|
||||
|
|
|
@ -5,8 +5,6 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
from hub.helpers import constants as cte
|
||||
|
||||
|
||||
class ConstructionHelper:
|
||||
"""
|
||||
|
|
|
@ -46,6 +46,8 @@ class NrcanPhysicsParameters:
|
|||
continue
|
||||
thermal_archetype = ThermalArchetype()
|
||||
self._assign_values(thermal_archetype, archetype)
|
||||
for internal_zone in building.internal_zones:
|
||||
internal_zone.thermal_archetype = thermal_archetype
|
||||
|
||||
@staticmethod
|
||||
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
|
||||
|
@ -59,13 +61,20 @@ class NrcanPhysicsParameters:
|
|||
|
||||
@staticmethod
|
||||
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.thermal_capacity = catalog_archetype.thermal_capacity
|
||||
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_off = catalog_archetype.infiltration_rate_for_ventilation_system_off
|
||||
_constructions = []
|
||||
for catalog_construction in catalog_archetype.constructions:
|
||||
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
|
||||
_layers = []
|
||||
for layer_archetype in catalog_construction.layers:
|
||||
|
@ -91,3 +100,5 @@ class NrcanPhysicsParameters:
|
|||
construction.window_frame_ratio = window_archetype.frame_ratio
|
||||
construction.window_g_value = window_archetype.g_value
|
||||
construction.window_overall_u_value = window_archetype.overall_u_value
|
||||
_constructions.append(construction)
|
||||
thermal_archetype.constructions = _constructions
|
||||
|
|
|
@ -61,6 +61,7 @@ class NrelPhysicsParameters:
|
|||
|
||||
@staticmethod
|
||||
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.thermal_capacity = catalog_archetype.thermal_capacity
|
||||
thermal_archetype.indirect_heated_ratio = catalog_archetype.indirect_heated_ratio
|
||||
|
|
|
@ -133,12 +133,11 @@ class TestConstructionFactory(TestCase):
|
|||
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||
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.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.thickness, 'thermal_boundary thickness 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.construction_name, 'construction_name is none')
|
||||
self.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none')
|
||||
self.assertIsNone(thermal_boundary.windows_areas, 'windows_areas is not none')
|
||||
self.assertIsNotNone(thermal_boundary.u_value, 'u_value is none')
|
||||
|
|
Loading…
Reference in New Issue
Block a user