hub/city_model_structure/building_demand/thermal_boundary.py

405 lines
10 KiB
Python
Raw Normal View History

2020-10-28 13:42:58 -04:00
"""
ThermalBoundary module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Contributors Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
2020-10-28 13:42:58 -04:00
"""
import uuid
from typing import List, TypeVar, Union
from city_model_structure.building_demand.layer import Layer
from city_model_structure.building_demand.thermal_opening import ThermalOpening
from city_model_structure.building_demand.thermal_zone import ThermalZone
from city_model_structure.building_demand.surface import Surface
Polygon = TypeVar('Polygon')
2021-03-16 12:19:35 -04:00
2020-10-28 13:42:58 -04:00
class ThermalBoundary:
"""
ThermalBoundary class
"""
def __init__(self, surface):
2020-10-28 13:42:58 -04:00
self._surface = surface
self._id = None
self._thermal_zones = None
# ToDo: up to at least LOD2 will be just one thermal opening per Thermal boundary only if window_ratio > 0,
# review for LOD3 and LOD4
self._thermal_openings = None
2020-10-28 13:42:58 -04:00
self._layers = None
self._outside_solar_absorptance = None
2020-10-28 13:42:58 -04:00
self._outside_thermal_absorptance = None
self._outside_visible_absorptance = None
self._u_value = None
self._shortwave_reflectance = None
self._construction_name = None
self._hi = 3.5
self._he = 20
2021-03-16 12:19:35 -04:00
self._window_ratio = None
self._refurbishment_measure = None
self._surface_geometry = None
self._thickness = None
self._virtual_internal_surface = None
self._inside_emissivity = None
self._alpha_coefficient = None
self._radiative_coefficient = None
2021-03-16 12:19:35 -04:00
@property
def id(self):
"""
Get thermal zone id, an universally unique identifier randomly generated
:return: str
"""
if self._id is None:
self._id = uuid.uuid4()
return self._id
@property
def surface(self) -> Surface:
"""
Get the surface that belongs to the thermal boundary
:return: Surface
"""
# todo: in LoD4 this property will be a list of surfaces, not only one
return self._surface
2020-10-28 13:42:58 -04:00
@property
2021-08-27 12:51:30 -04:00
def thermal_zones(self) -> List[ThermalZone]:
2020-10-28 13:42:58 -04:00
"""
Get the thermal zones delimited by the thermal boundary
:return: [ThermalZone]
"""
2021-08-27 12:51:30 -04:00
return self._thermal_zones
2020-10-28 13:42:58 -04:00
@thermal_zones.setter
def thermal_zones(self, value):
"""
Set the thermal zones delimited by the thermal boundary
:param value: [ThermalZone]
"""
self._thermal_zones = value
2020-10-28 13:42:58 -04:00
@property
def azimuth(self):
"""
Get the thermal boundary azimuth in radians
2020-10-28 13:42:58 -04:00
:return: float
"""
return self._surface.azimuth
@property
def inclination(self):
"""
Set the thermal boundary inclination in radians
2020-10-28 13:42:58 -04:00
:return: float
"""
return self._surface.inclination
@property
def area(self):
"""
Set the thermal boundary area in square meters
2020-10-28 13:42:58 -04:00
:return: float
"""
# to check the lod without depending on that parameter
if float(self.surface.solid_polygon.area) - float(self.surface.perimeter_polygon.area) < 1e-3:
area = float(self.surface.perimeter_polygon.area) * (1 - float(self.window_ratio))
else:
area = self.surface.solid_polygon.area
return area
@property
def _total_area_including_windows(self):
"""
Get the thermal boundary plus windows area in square meters
:return: float
"""
return self.surface.perimeter_polygon.area
2020-10-28 13:42:58 -04:00
@property
def thickness(self):
2020-10-28 13:42:58 -04:00
"""
Get the thermal boundary thickness in meters
2020-10-28 13:42:58 -04:00
:return: float
"""
if self._thickness is None:
self._thickness = 0.0
if self.layers is not None:
for layer in self.layers:
self._thickness += layer.thickness
return self._thickness
2020-10-28 13:42:58 -04:00
@property
def outside_solar_absorptance(self):
"""
Get thermal boundary outside solar absorptance
:return: float
"""
return self._outside_solar_absorptance
@outside_solar_absorptance.setter
def outside_solar_absorptance(self, value):
"""
Set thermal boundary outside solar absorptance
:param value: float
"""
self._outside_solar_absorptance = value
self._shortwave_reflectance = 1.0 - float(value)
@property
def outside_thermal_absorptance(self):
"""
Get thermal boundary outside thermal absorptance
:return: float
"""
return self._outside_thermal_absorptance
@outside_thermal_absorptance.setter
def outside_thermal_absorptance(self, value):
"""
Set thermal boundary outside thermal absorptance
:param value: float
"""
self._outside_thermal_absorptance = value
@property
def outside_visible_absorptance(self):
"""
Get thermal boundary outside visible absorptance
:return: float
"""
return self._outside_visible_absorptance
@outside_visible_absorptance.setter
def outside_visible_absorptance(self, value):
"""
Set thermal boundary outside visible absorptance
:param value: float
"""
self._outside_visible_absorptance = value
@property
def thermal_openings(self) -> List[ThermalOpening]:
"""
Get thermal boundary thermal openings
:return: [ThermalOpening]
"""
if self._thermal_openings is None:
if float(self.window_ratio) > 0:
thermal_opening = ThermalOpening()
thermal_opening.area = float(self._total_area_including_windows) * float(self.window_ratio)
thermal_opening.hi = self.hi
thermal_opening.he = self.he
self._thermal_openings = [thermal_opening]
else:
self._thermal_openings = []
2020-10-28 13:42:58 -04:00
return self._thermal_openings
@thermal_openings.setter
def thermal_openings(self, value):
"""
Set thermal boundary thermal openings
:param value: [ThermalOpening]
"""
self._thermal_openings = value
@property
def construction_name(self):
"""
Get construction name
:return: str
"""
return self._construction_name
@construction_name.setter
def construction_name(self, value):
"""
Set construction name
:param value: str
"""
self._construction_name = value
2020-10-28 13:42:58 -04:00
@property
def layers(self) -> List[Layer]:
"""
Get thermal boundary layers
:return: [Layers]
"""
return self._layers
@layers.setter
def layers(self, value):
"""
Set thermal boundary layers
:param value: [Layer]
"""
self._layers = value
@property
def type(self):
"""
Get thermal boundary surface type
2020-10-28 13:42:58 -04:00
:return: str
"""
return self._surface.type
@property
def window_ratio(self):
"""
Get thermal boundary window ratio
:return: float
"""
return self._window_ratio
@window_ratio.setter
def window_ratio(self, value):
"""
Set thermal boundary window ratio
:param value: float
"""
self._window_ratio = value
@property
def u_value(self):
"""
Get thermal boundary U-value in W/m2K
2020-10-28 13:42:58 -04:00
internal and external convective coefficient in W/m2K values, can be configured at configuration.ini
:return: float
"""
if self._u_value is None:
h_i = self.hi
h_e = self.he
2020-10-28 13:42:58 -04:00
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)
else:
r_value = r_value + float(layer.material.conductivity) / float(layer.thickness)
self._u_value = 1.0/r_value
except TypeError:
raise Exception('Constructions layers are not initialized') from TypeError
2020-10-28 13:42:58 -04:00
return self._u_value
2021-01-06 16:42:38 -05:00
@u_value.setter
def u_value(self, value):
"""
Set thermal boundary U-value in W/m2K
:param value: float
"""
2021-01-06 16:42:38 -05:00
self._u_value = value
2020-10-28 13:42:58 -04:00
@property
def shortwave_reflectance(self):
"""
Get thermal boundary shortwave reflectance
:return: float
"""
return self._shortwave_reflectance
@shortwave_reflectance.setter
def shortwave_reflectance(self, value):
"""
Set thermal boundary shortwave reflectance
:param value: float
"""
self._shortwave_reflectance = value
self._outside_solar_absorptance = 1.0 - float(value)
@property
def hi(self):
"""
Get internal convective heat transfer coefficient (W/m2K)
:return: float
"""
return self._hi
@hi.setter
def hi(self, value):
"""
Set internal convective heat transfer coefficient (W/m2K)
:param value: internal convective heat transfer coefficient (W/m2K)
"""
self._hi = value
@property
def he(self):
"""
Get external convective heat transfer coefficient (W/m2K)
:return: float
"""
return self._he
@he.setter
def he(self, value):
"""
Set external convective heat transfer coefficient (W/m2K)
:param value: float
"""
self._he = value
@property
def surface_geometry(self):
"""
Raises not implemented error
"""
raise NotImplementedError
@property
def virtual_internal_surface(self) -> Surface:
"""
Get the internal surface of the thermal boundary
:return: Surface
"""
if self._virtual_internal_surface is None:
self._virtual_internal_surface = self.surface.inverse
return self._virtual_internal_surface
# todo: need extract information from construction library or assume them at the beginning of workflows
@property
def inside_emissivity(self):
"""
Get the short wave emissivity factor of the thermal boundary's internal surface (-)
:return: float
"""
return self._inside_emissivity
@inside_emissivity.setter
def inside_emissivity(self, value):
"""
Set short wave emissivity factor of the thermal boundary's internal surface (-)
:param value: float
"""
self._inside_emissivity = value
@property
def alpha_coefficient(self):
"""
Get the long wave emissivity factor of the thermal boundary's internal surface (-)
:return: float
"""
return self._alpha_coefficient
@alpha_coefficient.setter
def alpha_coefficient(self, value):
"""
Set long wave emissivity factor of the thermal boundary's internal surface (-)
:param value: float
"""
self._alpha_coefficient = value
@property
def radiative_coefficient(self):
"""
Get the radiative coefficient of the thermal boundary's external surface (-)
:return: float
"""
return self._radiative_coefficient
@radiative_coefficient.setter
def radiative_coefficient(self, value):
"""
Set radiative coefficient of the thermal boundary's external surface (-)
:param value: float
"""
self._radiative_coefficient = value