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
|
2021-03-02 18:57:09 -05:00
|
|
|
Contributors Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
|
2020-10-28 13:42:58 -04:00
|
|
|
"""
|
2021-03-16 12:19:35 -04:00
|
|
|
from typing import List, TypeVar
|
2020-10-28 13:42:58 -04:00
|
|
|
from city_model_structure.attributes.layer import Layer
|
|
|
|
from city_model_structure.attributes.thermal_opening import ThermalOpening
|
2020-11-12 13:50:43 -05:00
|
|
|
from city_model_structure.attributes.surface import Surface
|
2020-10-28 13:42:58 -04:00
|
|
|
|
2021-03-16 12:19:35 -04:00
|
|
|
ThermalZone = TypeVar('ThermalZone')
|
2021-03-16 13:43:59 -04:00
|
|
|
Polygon = TypeVar('Polygon')
|
2021-03-16 12:19:35 -04:00
|
|
|
|
2020-10-28 13:42:58 -04:00
|
|
|
|
|
|
|
class ThermalBoundary:
|
|
|
|
"""
|
|
|
|
ThermalBoundary class
|
|
|
|
"""
|
2021-03-02 18:57:09 -05:00
|
|
|
def __init__(self, surface, delimits):
|
2020-10-28 13:42:58 -04:00
|
|
|
self._surface = surface
|
|
|
|
self._delimits = delimits
|
|
|
|
# ToDo: up to at least LOD2 will be just one thermal opening per Thermal boundary, review for LOD3 and LOD4
|
2021-03-08 18:27:14 -05:00
|
|
|
self._thermal_openings = [ThermalOpening()]
|
2020-10-28 13:42:58 -04:00
|
|
|
self._layers = None
|
2021-01-11 17:11:50 -05:00
|
|
|
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
|
2021-01-11 17:11:50 -05:00
|
|
|
self._shortwave_reflectance = None
|
2020-11-05 11:11:43 -05:00
|
|
|
self._construction_name = None
|
2021-03-02 18:57:09 -05:00
|
|
|
self._hi = None
|
|
|
|
self._he = None
|
2021-03-16 12:19:35 -04:00
|
|
|
self._window_ratio = None
|
2021-03-02 18:57:09 -05:00
|
|
|
self._refurbishment_measure = None
|
2021-03-16 13:43:59 -04:00
|
|
|
self._surface_geometry = None
|
2021-03-16 12:19:35 -04:00
|
|
|
|
2020-11-12 13:50:43 -05:00
|
|
|
@property
|
|
|
|
def surface(self) -> Surface:
|
|
|
|
"""
|
|
|
|
Get the surface that belongs to the thermal boundary
|
|
|
|
:return: Surface
|
|
|
|
"""
|
2021-03-02 18:57:09 -05:00
|
|
|
# todo: in LoD4 this property will be a list of surfaces, not only one
|
2020-11-12 13:50:43 -05:00
|
|
|
return self._surface
|
|
|
|
|
2020-10-28 13:42:58 -04:00
|
|
|
@property
|
|
|
|
def delimits(self) -> List[ThermalZone]:
|
|
|
|
"""
|
|
|
|
Get the thermal zones delimited by the thermal boundary
|
|
|
|
:return: [ThermalZone]
|
|
|
|
"""
|
|
|
|
return self._delimits
|
|
|
|
|
|
|
|
@property
|
|
|
|
def azimuth(self):
|
|
|
|
"""
|
|
|
|
Thermal boundary azimuth in radians
|
|
|
|
:return: float
|
|
|
|
"""
|
|
|
|
return self._surface.azimuth
|
|
|
|
|
|
|
|
@property
|
|
|
|
def inclination(self):
|
|
|
|
"""
|
|
|
|
Thermal boundary inclination in radians
|
|
|
|
:return: float
|
|
|
|
"""
|
|
|
|
return self._surface.inclination
|
|
|
|
|
|
|
|
@property
|
|
|
|
def area(self):
|
|
|
|
"""
|
|
|
|
Thermal boundary area in square meters
|
|
|
|
:return: float
|
|
|
|
"""
|
2021-03-08 18:27:14 -05:00
|
|
|
return self._surface.solid_polygon.area
|
2020-10-28 13:42:58 -04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def area_above_ground(self):
|
|
|
|
"""
|
|
|
|
Thermal boundary area above ground in square meters
|
|
|
|
:return: float
|
|
|
|
"""
|
|
|
|
return self._surface.area_above_ground
|
|
|
|
|
|
|
|
@property
|
|
|
|
def area_below_ground(self):
|
|
|
|
"""
|
|
|
|
Thermal boundary area below ground in square meters
|
|
|
|
:return: float
|
|
|
|
"""
|
|
|
|
return self._surface.area_below_ground
|
|
|
|
|
|
|
|
@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
|
|
|
|
:return: None
|
|
|
|
"""
|
|
|
|
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
|
|
|
|
:return: None
|
|
|
|
"""
|
|
|
|
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
|
|
|
|
:return: None
|
|
|
|
"""
|
|
|
|
self._outside_visible_absorptance = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def thermal_openings(self) -> List[ThermalOpening]:
|
|
|
|
"""
|
|
|
|
Get thermal boundary thermal openings
|
|
|
|
:return: [ThermalOpening]
|
|
|
|
"""
|
|
|
|
return self._thermal_openings
|
|
|
|
|
|
|
|
@thermal_openings.setter
|
|
|
|
def thermal_openings(self, value):
|
|
|
|
"""
|
|
|
|
Set thermal boundary thermal openings
|
|
|
|
:param value: [ThermalOpening]
|
|
|
|
:return: None
|
|
|
|
"""
|
|
|
|
self._thermal_openings = value
|
|
|
|
|
2020-11-05 11:11:43 -05:00
|
|
|
@property
|
|
|
|
def construction_name(self):
|
|
|
|
"""
|
|
|
|
Get construction name
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
return self._construction_name
|
|
|
|
|
|
|
|
@construction_name.setter
|
|
|
|
def construction_name(self, value):
|
|
|
|
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]
|
|
|
|
:return: None
|
|
|
|
"""
|
|
|
|
self._layers = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
"""
|
|
|
|
Thermal boundary surface type
|
|
|
|
: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
|
|
|
|
:return: None
|
|
|
|
"""
|
|
|
|
self._window_ratio = value
|
|
|
|
|
2021-01-06 16:42:38 -05:00
|
|
|
# todo: what if I just want to assign a number??
|
2020-10-28 13:42:58 -04:00
|
|
|
@property
|
|
|
|
def u_value(self):
|
|
|
|
"""
|
2021-01-08 16:08:29 -05:00
|
|
|
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:
|
2021-03-02 18:57:09 -05:00
|
|
|
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')
|
|
|
|
return self._u_value
|
|
|
|
|
2021-01-06 16:42:38 -05:00
|
|
|
@u_value.setter
|
|
|
|
def u_value(self, value):
|
2021-01-08 16:08:29 -05:00
|
|
|
"""
|
|
|
|
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
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
self._shortwave_reflectance = value
|
|
|
|
self._outside_solar_absorptance = 1.0 - float(value)
|
2021-03-02 18:57:09 -05:00
|
|
|
|
|
|
|
@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)
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
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: external convective heat transfer coefficient (W/m2K)
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
self._he = value
|
2021-03-16 13:43:59 -04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def surface_geometry(self) -> Polygon:
|
|
|
|
"""
|
|
|
|
Get the polygon that defines the thermal boundary
|
|
|
|
:return: Polygon
|
|
|
|
"""
|
|
|
|
return self._surface_geometry
|