Compare commits

..

No commits in common. "a147afe76fbf9deac752f373b1503b52ea27eee6" and "1a8dbe7f87af7796e4c491dd7c6ef3f8516fddb5" have entirely different histories.

23 changed files with 722 additions and 723 deletions

View File

@ -41,7 +41,7 @@ class Building(CityObject):
self._floor_area = None
self._roof_type = None
self._internal_zones = None
self._thermal_zones_from_internal_zones = None
self._thermal_zones = None
self._shell = None
self._aliases = []
self._type = 'building'
@ -114,23 +114,26 @@ class Building(CityObject):
:return: [InternalZone]
"""
if self._internal_zones is None:
self._internal_zones = [InternalZone(self.surfaces, self.floor_area, self.volume)]
self._internal_zones = [InternalZone(self.surfaces, self.floor_area)]
return self._internal_zones
@property
def thermal_zones_from_internal_zones(self) -> Union[None, List[ThermalZone]]:
def thermal_zones(self) -> Union[None, List[ThermalZone]]:
"""
Get building thermal zones
For Lod up to 3, there can be more than one thermal zone per internal zone.
In LoD 4, there can be more than one internal zone, and therefore, only one thermal zone per internal zone
:return: [ThermalZone]
"""
if self._thermal_zones_from_internal_zones is None:
self._thermal_zones_from_internal_zones = []
if self._thermal_zones is None:
self._thermal_zones = []
for internal_zone in self.internal_zones:
if internal_zone.thermal_zones_from_internal_zones is None:
self._thermal_zones_from_internal_zones = None
return self._thermal_zones_from_internal_zones
self._thermal_zones_from_internal_zones.append(internal_zone.thermal_zones_from_internal_zones[0])
return self._thermal_zones_from_internal_zones
if internal_zone.thermal_zones is None:
self._thermal_zones = None
return self._thermal_zones
for thermal_zone in internal_zone.thermal_zones:
self._thermal_zones.append(thermal_zone)
return self._thermal_zones
@property
def grounds(self) -> List[Surface]:
@ -618,7 +621,7 @@ class Building(CityObject):
def _calculate_working_hours(self):
_working_hours = {}
for internal_zone in self.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
_working_hours_per_thermal_zone = {}
for schedule in thermal_zone.thermal_control.hvac_availability_schedules:
_working_hours_per_schedule = [0] * len(schedule.values)

View File

@ -1,134 +0,0 @@
"""
Construction thermal parameters
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.city_model_structure.building_demand.layer import Layer
class Construction:
"""
Construction class
"""
def __init__(self):
self._type = None
self._layers = None
self._window_ratio = None
self._window_frame_ratio = None
self._window_g_value = None
self._window_overall_u_value = None
self._window_type = None
@property
def type(self):
"""
Get construction type
:return: str
"""
return self._type
@type.setter
def type(self, value):
"""
Set construction type
:param value: str
"""
self._type = value
@property
def layers(self) -> [Layer]:
"""
Get layers
:return: [layer]
"""
return self._layers
@layers.setter
def layers(self, value):
"""
Set layers
:param value: [layer]
"""
self._layers = value
@property
def window_ratio(self):
"""
Get window ratio
:return: dict
"""
return self._window_ratio
@window_ratio.setter
def window_ratio(self, value):
"""
Set window ratio
:param value: dict
"""
self._window_ratio = value
@property
def window_frame_ratio(self):
"""
Get window frame ratio
:return: float
"""
return self._window_frame_ratio
@window_frame_ratio.setter
def window_frame_ratio(self, value):
"""
Set window frame ratio
:param value: float
"""
self._window_frame_ratio = value
@property
def window_g_value(self):
"""
Get transparent surface g-value
:return: float
"""
return self._window_g_value
@window_g_value.setter
def window_g_value(self, value):
"""
Set transparent surface g-value
:param value: float
"""
self._window_g_value = value
@property
def window_overall_u_value(self):
"""
Get transparent surface overall U-value in W/m2K
:return: float
"""
return self._window_overall_u_value
@window_overall_u_value.setter
def window_overall_u_value(self, value):
"""
Set transparent surface overall U-value in W/m2K
:param value: float
"""
self._window_overall_u_value = value
@property
def window_type(self):
"""
Get transparent surface type, 'window' or 'skylight'
:return: str
"""
return self._window_type
@window_type.setter
def window_type(self, value):
"""
Set transparent surface type, 'window' or 'skylight'
:return: str
"""
self._window_type = value

View File

@ -9,7 +9,6 @@ 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_zone import ThermalZone
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.energy_systems.hvac_system import HvacSystem
@ -18,13 +17,13 @@ class InternalZone:
"""
InternalZone class
"""
def __init__(self, surfaces, area, volume):
def __init__(self, surfaces, area):
self._surfaces = surfaces
self._id = None
self._geometry = None
self._volume = volume
self._volume = None
self._area = area
self._thermal_zones_from_internal_zones = None
self._thermal_zones = None
self._usages = None
self._hvac_system = None
@ -65,7 +64,7 @@ class InternalZone:
Get internal zone volume in cubic meters
:return: float
"""
return self._volume
return self.geometry.volume
@property
def area(self):
@ -108,29 +107,17 @@ class InternalZone:
self._hvac_system = value
@property
def thermal_zones_from_internal_zones(self) -> Union[None, List[ThermalZone]]:
def thermal_zones(self) -> Union[None, List[ThermalZone]]:
"""
Get building thermal zones as one per internal zone
Get building thermal zones
:return: [ThermalZone]
"""
_thermal_boundaries = []
for surface in self.surfaces:
if surface.holes_polygons is None:
windows_areas = None
else:
windows_areas = []
for hole in surface.holes_polygons:
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)
self._thermal_zones_from_internal_zones = [_thermal_zone]
return self._thermal_zones_from_internal_zones
return self._thermal_zones
@thermal_zones_from_internal_zones.setter
def thermal_zones_from_internal_zones(self, value):
@thermal_zones.setter
def thermal_zones(self, value):
"""
Set city object thermal zones as one per internal zone
Set city object thermal zones
:param value: [ThermalZone]
"""
self._thermal_zones_from_internal_zones = value
self._thermal_zones = value

View File

@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import uuid
from typing import Union
from hub.city_model_structure.building_demand.material import Material
class Layer:
@ -14,17 +14,9 @@ class Layer:
Layer class
"""
def __init__(self):
self._material = None
self._thickness = None
self._id = None
self._name = None
self._conductivity = None
self._specific_heat = None
self._density = None
self._solar_absorptance = None
self._thermal_absorptance = None
self._visible_absorptance = None
self._no_mass = False
self._thermal_resistance = None
@property
def id(self):
@ -36,6 +28,22 @@ class Layer:
self._id = uuid.uuid4()
return self._id
@property
def material(self) -> Material:
"""
Get layer material
:return: Material
"""
return self._material
@material.setter
def material(self, value):
"""
Set layer material
:param value: Material
"""
self._material = value
@property
def thickness(self) -> Union[None, float]:
"""
@ -52,155 +60,3 @@ class Layer:
"""
if value is not None:
self._thickness = float(value)
@property
def name(self):
"""
Get material name
:return: str
"""
return self._name
@name.setter
def name(self, value):
"""
Set material name
:param value: string
"""
self._name = str(value)
@property
def conductivity(self) -> Union[None, float]:
"""
Get material conductivity in W/mK
:return: None or float
"""
return self._conductivity
@conductivity.setter
def conductivity(self, value):
"""
Set material conductivity in W/mK
:param value: float
"""
if value is not None:
self._conductivity = float(value)
@property
def specific_heat(self) -> Union[None, float]:
"""
Get material conductivity in J/kgK
:return: None or float
"""
return self._specific_heat
@specific_heat.setter
def specific_heat(self, value):
"""
Get material conductivity in J/kgK
:param value: float
"""
if value is not None:
self._specific_heat = float(value)
@property
def density(self) -> Union[None, float]:
"""
Get material density in kg/m3
:return: None or float
"""
return self._density
@density.setter
def density(self, value):
"""
Set material density
:param value: float
"""
if value is not None:
self._density = float(value)
@property
def solar_absorptance(self) -> Union[None, float]:
"""
Get material solar absorptance
:return: None or float
"""
return self._solar_absorptance
@solar_absorptance.setter
def solar_absorptance(self, value):
"""
Set material solar absorptance
:param value: float
"""
if value is not None:
self._solar_absorptance = float(value)
@property
def thermal_absorptance(self) -> Union[None, float]:
"""
Get material thermal absorptance
:return: None or float
"""
return self._thermal_absorptance
@thermal_absorptance.setter
def thermal_absorptance(self, value):
"""
Set material thermal absorptance
:param value: float
"""
if value is not None:
self._thermal_absorptance = float(value)
@property
def visible_absorptance(self) -> Union[None, float]:
"""
Get material visible absorptance
:return: None or float
"""
return self._visible_absorptance
@visible_absorptance.setter
def visible_absorptance(self, value):
"""
Set material visible absorptance
:param value: float
"""
if value is not None:
self._visible_absorptance = float(value)
@property
def no_mass(self) -> Union[None, bool]:
"""
Get material no mass flag
:return: None or Boolean
"""
return self._no_mass
@no_mass.setter
def no_mass(self, value):
"""
Set material no mass flag
:param value: Boolean
"""
if value is not None:
self._no_mass = value
@property
def thermal_resistance(self) -> Union[None, float]:
"""
Get material thermal resistance in m2K/W
:return: None or float
"""
return self._thermal_resistance
@thermal_resistance.setter
def thermal_resistance(self, value):
"""
Set material thermal resistance in m2K/W
:param value: float
"""
if value is not None:
self._thermal_resistance = float(value)

View File

@ -0,0 +1,193 @@
"""
Material module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from typing import Union
class Material:
"""
Material class
"""
def __init__(self):
self._id = None
self._name = None
self._conductivity = None
self._specific_heat = None
self._density = None
self._solar_absorptance = None
self._thermal_absorptance = None
self._visible_absorptance = None
self._no_mass = False
self._thermal_resistance = None
@property
def id(self):
"""
Get material id
:return: str
"""
return self._id
@id.setter
def id(self, value):
"""
Set material id
:param value: str
"""
self._id = value
@property
def name(self):
"""
Get material name
:return: str
"""
return self._name
@name.setter
def name(self, value):
"""
Set material name
:param value: string
"""
self._name = str(value)
@property
def conductivity(self) -> Union[None, float]:
"""
Get material conductivity in W/mK
:return: None or float
"""
return self._conductivity
@conductivity.setter
def conductivity(self, value):
"""
Set material conductivity in W/mK
:param value: float
"""
if value is not None:
self._conductivity = float(value)
@property
def specific_heat(self) -> Union[None, float]:
"""
Get material conductivity in J/kgK
:return: None or float
"""
return self._specific_heat
@specific_heat.setter
def specific_heat(self, value):
"""
Get material conductivity in J/kgK
:param value: float
"""
if value is not None:
self._specific_heat = float(value)
@property
def density(self) -> Union[None, float]:
"""
Get material density in kg/m3
:return: None or float
"""
return self._density
@density.setter
def density(self, value):
"""
Set material density
:param value: float
"""
if value is not None:
self._density = float(value)
@property
def solar_absorptance(self) -> Union[None, float]:
"""
Get material solar absorptance
:return: None or float
"""
return self._solar_absorptance
@solar_absorptance.setter
def solar_absorptance(self, value):
"""
Set material solar absorptance
:param value: float
"""
if value is not None:
self._solar_absorptance = float(value)
@property
def thermal_absorptance(self) -> Union[None, float]:
"""
Get material thermal absorptance
:return: None or float
"""
return self._thermal_absorptance
@thermal_absorptance.setter
def thermal_absorptance(self, value):
"""
Set material thermal absorptance
:param value: float
"""
if value is not None:
self._thermal_absorptance = float(value)
@property
def visible_absorptance(self) -> Union[None, float]:
"""
Get material visible absorptance
:return: None or float
"""
return self._visible_absorptance
@visible_absorptance.setter
def visible_absorptance(self, value):
"""
Set material visible absorptance
:param value: float
"""
if value is not None:
self._visible_absorptance = float(value)
@property
def no_mass(self) -> Union[None, bool]:
"""
Get material no mass flag
:return: None or Boolean
"""
return self._no_mass
@no_mass.setter
def no_mass(self, value):
"""
Set material no mass flag
:param value: Boolean
"""
if value is not None:
self._no_mass = value
@property
def thermal_resistance(self) -> Union[None, float]:
"""
Get material thermal resistance in m2K/W
:return: None or float
"""
return self._thermal_resistance
@thermal_resistance.setter
def thermal_resistance(self, value):
"""
Set material thermal resistance in m2K/W
:param value: float
"""
if value is not None:
self._thermal_resistance = float(value)

View File

@ -1,126 +0,0 @@
"""
Thermal archetype module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.city_model_structure.building_demand.construction import Construction
class ThermalArchetype:
"""
ThermalArchetype class
"""
def __init__(self):
self._constructions = None
self._average_storey_height = None
self._thermal_capacity = None
self._extra_loses_due_to_thermal_bridges = None
self._indirect_heated_ratio = None
self._infiltration_rate_for_ventilation_system_off = None
self._infiltration_rate_for_ventilation_system_on = None
@property
def constructions(self) -> [Construction]:
"""
Get archetype constructions
:return: [Construction]
"""
return self._constructions
@property
def average_storey_height(self):
"""
Get average storey height in m
:return: float
"""
return self._average_storey_height
@average_storey_height.setter
def average_storey_height(self, value):
"""
Set average storey height in m
:param value: float
"""
self._average_storey_height = value
@property
def thermal_capacity(self):
"""
Get thermal capacity in J/m3K
:return: float
"""
return self._thermal_capacity
@thermal_capacity.setter
def thermal_capacity(self, value):
"""
Set thermal capacity in J/m3K
:param value: float
"""
self._thermal_capacity = value
@property
def extra_loses_due_to_thermal_bridges(self):
"""
Get extra loses due to thermal bridges in W/m2K
:return: float
"""
return self._extra_loses_due_to_thermal_bridges
@extra_loses_due_to_thermal_bridges.setter
def extra_loses_due_to_thermal_bridges(self, value):
"""
Set extra loses due to thermal bridges in W/m2K
:param value: float
"""
self._extra_loses_due_to_thermal_bridges = value
@property
def indirect_heated_ratio(self):
"""
Get indirect heated area ratio
:return: float
"""
return self._indirect_heated_ratio
@indirect_heated_ratio.setter
def indirect_heated_ratio(self, value):
"""
Set indirect heated area ratio
:param value: float
"""
self._indirect_heated_ratio = value
@property
def infiltration_rate_for_ventilation_system_off(self):
"""
Get infiltration rate for ventilation system off in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_off
@infiltration_rate_for_ventilation_system_off.setter
def infiltration_rate_for_ventilation_system_off(self, value):
"""
Set infiltration rate for ventilation system off in ACH
:param value: float
"""
self._infiltration_rate_for_ventilation_system_off = value
@property
def infiltration_rate_for_ventilation_system_on(self):
"""
Get infiltration rate for ventilation system on in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_on
@infiltration_rate_for_ventilation_system_on.setter
def infiltration_rate_for_ventilation_system_on(self, value):
"""
Set infiltration rate for ventilation system on in ACH
:param value: float
"""
self._infiltration_rate_for_ventilation_system_on = value

View File

@ -221,44 +221,16 @@ class ThermalZone:
Get thermal zone view factors matrix
:return: [[float]]
"""
# todo: review method if windows not in window_ratio but in geometry
if self._view_factors_matrix is None:
total_area = 0
for thermal_boundary in self.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in self.thermal_boundaries:
values = []
for thermal_boundary_2 in self.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in self.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in self.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in self.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in self.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
self._view_factors_matrix = view_factors_matrix
return self._view_factors_matrix
@view_factors_matrix.setter
def view_factors_matrix(self, value):
"""
Set thermal zone view factors matrix
:param value: [[float]]
"""
self._view_factors_matrix = value
@property
def usage_name(self) -> Union[None, str]:
"""

View File

@ -335,7 +335,7 @@ class EnergyAde:
def _thermal_zones(self, building, city):
thermal_zones = []
for internal_zone in building.internal_zones:
for index, thermal_zone in enumerate(internal_zone.thermal_zones_from_internal_zones):
for index, thermal_zone in enumerate(internal_zone.thermal_zones):
usages = []
for usage in internal_zone.usages:
usages.append({'@xlink:href': f'#GML_{usage.id}'})

View File

@ -510,9 +510,9 @@ class Idf:
for building in self._city.buildings:
print('building name', building.name)
for internal_zone in building.internal_zones:
if internal_zone.thermal_zones_from_internal_zones is None:
if internal_zone.thermal_zones is None:
continue
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
self._add_construction(thermal_boundary)
if thermal_boundary.parent_surface.vegetation is not None:
@ -556,7 +556,7 @@ class Idf:
self._add_dhw(thermal_zone, building.name)
if self._export_type == "Surfaces":
if building.name in self._target_buildings or building.name in self._adjacent_buildings:
if building.internal_zones[0].thermal_zones_from_internal_zones is not None:
if building.internal_zones[0].thermal_zones is not None:
self._add_surfaces(building, building.name)
else:
self._add_pure_geometry(building, building.name)
@ -611,7 +611,7 @@ class Idf:
num_stories=int(building.storeys_above_ground))
for surface in self._idf.idfobjects[self._SURFACE]:
for thermal_zone in building.thermal_zones_from_internal_zones:
for thermal_zone in building.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
if surface.Type == self.idf_surfaces[boundary.surface.type]:
surface.Construction_Name = boundary.construction_name
@ -664,7 +664,7 @@ class Idf:
idf_surface.setcoords(coordinates)
if self._lod >= 3:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
self._add_windows_by_vertices(boundary)
else:
@ -674,7 +674,7 @@ class Idf:
def _add_surfaces(self, building, zone_name):
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
idf_surface_type = self.idf_surfaces[boundary.parent_surface.type]
outside_boundary_condition = 'Outdoors'
@ -711,7 +711,7 @@ class Idf:
if self._lod >= 3:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
self._add_windows_by_vertices(boundary)
else:

View File

@ -44,7 +44,7 @@ class InselMonthlyEnergyBalance:
self._insel_files_paths.append(building.name + '.insel')
file_name_out = building.name + '.out'
output_path = Path(self._path / file_name_out).resolve()
if building.thermal_zones_from_internal_zones is None:
if building.thermal_zones is None:
logging.warning('Building %s has missing values. Monthly Energy Balance cannot be processed', building.name)
self._contents.append(
@ -126,7 +126,7 @@ class InselMonthlyEnergyBalance:
# todo: this method and the insel model have to be reviewed for more than one internal zone
internal_zone = building.internal_zones[0]
thermal_zone = internal_zone.thermal_zones_from_internal_zones[0]
thermal_zone = internal_zone.thermal_zones[0]
parameters.append(f'{thermal_zone.indirectly_heated_area_ratio} % BP(6) Indirectly heated area ratio')
parameters.append(f'{thermal_zone.effective_thermal_capacity / 3600 / building.average_storey_height}'
f' % BP(7) Effective heat capacity (Wh/m2K)')
@ -139,7 +139,7 @@ class InselMonthlyEnergyBalance:
for i, usage in enumerate(internal_zone.usages):
percentage_usage = usage.percentage
parameters.append(f'{internal_zone.thermal_zones_from_internal_zones[0].total_floor_area * percentage_usage} '
parameters.append(f'{internal_zone.thermal_zones[0].total_floor_area * percentage_usage} '
f'% BP(11) #1 Area of zone {i + 1} (m2)')
total_internal_gain = 0
for i_gain in usage.internal_gains:
@ -169,11 +169,11 @@ class InselMonthlyEnergyBalance:
infiltration_day = 0
for value in schedule.values:
if value == 0:
infiltration_day += internal_zone.thermal_zones_from_internal_zones[0].infiltration_rate_system_off / 24
infiltration_day += internal_zone.thermal_zones[0].infiltration_rate_system_off / 24
ventilation_day += 0
else:
ventilation_value = usage.mechanical_air_change * value
infiltration_value = internal_zone.thermal_zones_from_internal_zones[0].infiltration_rate_system_off * value
infiltration_value = internal_zone.thermal_zones[0].infiltration_rate_system_off * value
if ventilation_value >= infiltration_value:
ventilation_day += ventilation_value / 24
infiltration_day += 0

View File

@ -65,7 +65,7 @@ class LoadsCalculation:
"""
heating_load_transmitted = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_heating_set_point
heating_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature,
ground_temperature)
@ -78,7 +78,7 @@ class LoadsCalculation:
"""
cooling_load_transmitted = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_cooling_set_point
cooling_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature,
ground_temperature)
@ -91,7 +91,7 @@ class LoadsCalculation:
"""
heating_ventilation_load = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_heating_set_point
heating_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature)
return heating_ventilation_load
@ -103,7 +103,7 @@ class LoadsCalculation:
"""
cooling_ventilation_load = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_cooling_set_point
cooling_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature)
return cooling_ventilation_load
@ -117,7 +117,7 @@ class LoadsCalculation:
cooling_load_lighting = 0
cooling_load_equipment_sensible = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
cooling_load_occupancy_sensible += (thermal_zone.occupancy.sensible_convective_internal_gain
+ thermal_zone.occupancy.sensible_radiative_internal_gain) \
* thermal_zone.footprint_area
@ -139,7 +139,7 @@ class LoadsCalculation:
"""
cooling_load_radiation = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
radiation = thermal_boundary.parent_surface.global_irradiance[cte.HOUR][irradiance_format][hour]

View File

@ -1,72 +0,0 @@
"""
Thermal zones creation module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class ThermalZonesCreation:
"""
PeakLoads class
"""
def __init__(self, building=None):
self._building = building
# todo: ATTENTION!!
# try:
# thermal_boundary.window_ratio = catalog_construction.window_ratio
# except ValueError:
# # This is the normal operation way when the windows are defined in the geometry
# continue
# # The agreement is that the layers are defined from outside to inside
# external_layer = catalog_construction.layers[0]
# external_surface = thermal_boundary.parent_surface
# external_surface.short_wave_reflectance = 1 - external_layer.material.solar_absorptance
# external_surface.long_wave_emittance = 1 - external_layer.material.solar_absorptance
# internal_layer = catalog_construction.layers[len(catalog_construction.layers) - 1]
# internal_surface = thermal_boundary.internal_surface
# internal_surface.short_wave_reflectance = 1 - internal_layer.material.solar_absorptance
# internal_surface.long_wave_emittance = 1 - internal_layer.material.solar_absorptance
# if thermal_boundary.type in (cte.WALL, cte.ROOF):
# if catalog_construction.window is not None:
# if -math.sqrt(2) / 2 < math.sin(thermal_boundary.parent_surface.azimuth) < math.sqrt(2) / 2:
# if 0 < math.cos(thermal_boundary.parent_surface.azimuth):
# thermal_boundary.window_ratio = \
# float(catalog_construction.window_ratio['north']) / 100
# else:
# thermal_boundary.window_ratio = \
# float(catalog_construction.window_ratio['south']) / 100
# elif math.sqrt(2) / 2 <= math.sin(thermal_boundary.parent_surface.azimuth):
# thermal_boundary.window_ratio = \
# float(catalog_construction.window_ratio['east']) / 100
# else:
# thermal_boundary.window_ratio = \
# float(catalog_construction.window_ratio['west']) / 100
@property
def thermal_zones_from_storeys(self):
"""
Create and get thermal zones as 1 per each storey
:return: [ThermalZone]
"""
raise NotImplementedError
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
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

View File

@ -6,13 +6,15 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import logging
import math
import hub.helpers.constants as cte
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.construction import Construction
from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class EilatPhysicsParameters:
@ -33,7 +35,7 @@ class EilatPhysicsParameters:
eilat_catalog = ConstructionCatalogFactory('eilat').catalog
for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_eilat_construction_function.keys():
logging.error(f'Building %s has an unknown building function %s', building.name, building.function)
logging.error(f'Building %s has an unknown building function %s', building.name, building.function )
continue
function = Dictionaries().hub_function_to_eilat_construction_function[building.function]
try:
@ -44,8 +46,29 @@ class EilatPhysicsParameters:
f'[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, self._climate_zone)
continue
thermal_archetype = ThermalArchetype()
self._assign_values(thermal_archetype, archetype)
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:
if building.internal_zones[0].thermal_zones is None:
self._create_storeys(building, archetype, self._divide_in_storeys)
if self._divide_in_storeys:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
else:
number_of_storeys = int(building.eave_height / building.average_storey_height)
thermal_zone = building.internal_zones[0].thermal_zones[0]
thermal_zone.total_floor_area = thermal_zone.footprint_area * number_of_storeys
else:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
for internal_zone in building.internal_zones:
self._assign_values(internal_zone.thermal_zones, archetype)
for thermal_zone in internal_zone.thermal_zones:
self._calculate_view_factors(thermal_zone)
@staticmethod
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
@ -58,43 +81,133 @@ class EilatPhysicsParameters:
raise KeyError('archetype not found')
@staticmethod
def _assign_values(thermal_archetype, catalog_archetype):
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
thermal_archetype.infiltration_rate_for_ventilation_system_off = catalog_archetype.infiltration_rate_for_ventilation_system_off
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
def _assign_values(self, thermal_zones, archetype):
for thermal_zone in thermal_zones:
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
effective_thermal_capacity = 0
for catalog_construction in catalog_archetype.constructions:
construction = Construction()
construction.window_ratio = catalog_construction.window_ratio
_layers = []
thermal_zone.indirectly_heated_area_ratio = 0
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
for thermal_boundary in thermal_zone.thermal_boundaries:
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
thermal_boundary.construction_name = construction_archetype.name
try:
thermal_boundary.window_ratio = 0
if thermal_boundary.type in (cte.WALL, cte.ROOF):
if construction_archetype.window is not None:
if -math.sqrt(2) / 2 < math.sin(thermal_boundary.parent_surface.azimuth) < math.sqrt(2) / 2:
if 0 < math.cos(thermal_boundary.parent_surface.azimuth):
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['north']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['south']) / 100
elif math.sqrt(2) / 2 <= math.sin(thermal_boundary.parent_surface.azimuth):
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['east']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['west']) / 100
except ValueError:
# This is the normal operation way when the windows are defined in the geometry
continue
thermal_boundary.layers = []
total_thickness = 0
for layer_archetype in catalog_construction.layers:
for layer_archetype in construction_archetype.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
total_thickness += layer_archetype.thickness
material = Material()
archetype_material = layer_archetype.material
layer.name = archetype_material.name
layer.no_mass = archetype_material.no_mass
material.name = archetype_material.name
material.id = archetype_material.id
material.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
layer.thermal_resistance = archetype_material.thermal_resistance
material.thermal_resistance = archetype_material.thermal_resistance
else:
layer.density = archetype_material.density
layer.conductivity = archetype_material.conductivity
layer.specific_heat = archetype_material.specific_heat
material.density = archetype_material.density
material.conductivity = archetype_material.conductivity
material.specific_heat = archetype_material.specific_heat
effective_thermal_capacity += archetype_material.specific_heat \
* archetype_material.density * layer_archetype.thickness
layer.solar_absorptance = archetype_material.solar_absorptance
layer.thermal_absorptance = archetype_material.thermal_absorptance
layer.visible_absorptance = archetype_material.visible_absorptance
_layers.append(layer)
construction.layers = _layers
material.solar_absorptance = archetype_material.solar_absorptance
material.thermal_absorptance = archetype_material.thermal_absorptance
material.visible_absorptance = archetype_material.visible_absorptance
layer.material = material
thermal_boundary.layers.append(layer)
effective_thermal_capacity = effective_thermal_capacity / total_thickness
# The agreement is that the layers are defined from outside to inside
external_layer = construction_archetype.layers[0]
external_surface = thermal_boundary.parent_surface
external_surface.short_wave_reflectance = 1 - external_layer.material.solar_absorptance
external_surface.long_wave_emittance = 1 - external_layer.material.solar_absorptance
internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1]
internal_surface = thermal_boundary.internal_surface
internal_surface.short_wave_reflectance = 1 - internal_layer.material.solar_absorptance
internal_surface.long_wave_emittance = 1 - internal_layer.material.solar_absorptance
if catalog_construction.window is not None:
window_archetype = catalog_construction.window
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
for thermal_opening in thermal_boundary.thermal_openings:
if construction_archetype.window is not None:
window_archetype = construction_archetype.window
thermal_opening.construction_name = window_archetype.name
thermal_opening.frame_ratio = window_archetype.frame_ratio
thermal_opening.g_value = window_archetype.g_value
thermal_opening.overall_u_value = window_archetype.overall_u_value
thermal_archetype.thermal_capacity = effective_thermal_capacity
thermal_zone.effective_thermal_capacity = effective_thermal_capacity
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -6,13 +6,15 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import logging
import math
import hub.helpers.constants as cte
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.construction import Construction
from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class NrcanPhysicsParameters:
@ -33,7 +35,7 @@ class NrcanPhysicsParameters:
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_nrcan_construction_function.keys():
logging.error(f'Building %s has an unknown building function %s', building.name, building.function)
logging.error(f'Building %s has an unknown building function %s', building.name, building.function )
continue
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
try:
@ -44,8 +46,29 @@ class NrcanPhysicsParameters:
f'[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, self._climate_zone)
continue
thermal_archetype = ThermalArchetype()
self._assign_values(thermal_archetype, archetype)
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:
if building.internal_zones[0].thermal_zones is None:
self._create_storeys(building, archetype, self._divide_in_storeys)
if self._divide_in_storeys:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
else:
number_of_storeys = int(building.eave_height / building.average_storey_height)
thermal_zone = building.internal_zones[0].thermal_zones[0]
thermal_zone.total_floor_area = thermal_zone.footprint_area * number_of_storeys
else:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
for internal_zone in building.internal_zones:
self._assign_values(internal_zone.thermal_zones, archetype)
for thermal_zone in internal_zone.thermal_zones:
self._calculate_view_factors(thermal_zone)
@staticmethod
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
@ -58,36 +81,126 @@ class NrcanPhysicsParameters:
raise KeyError('archetype not found')
@staticmethod
def _assign_values(thermal_archetype, catalog_archetype):
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
for catalog_construction in catalog_archetype.constructions:
construction = Construction()
construction.window_ratio = catalog_construction.window_ratio
_layers = []
for layer_archetype in catalog_construction.layers:
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
def _assign_values(self, thermal_zones, archetype):
for thermal_zone in thermal_zones:
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
thermal_zone.indirectly_heated_area_ratio = 0
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
for thermal_boundary in thermal_zone.thermal_boundaries:
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
thermal_boundary.construction_name = construction_archetype.name
try:
thermal_boundary.window_ratio = 0
if thermal_boundary.type in ( cte.WALL, cte.ROOF):
if construction_archetype.window is not None:
if -math.sqrt(2) / 2 < math.sin(thermal_boundary.parent_surface.azimuth) < math.sqrt(2) / 2:
if 0 < math.cos(thermal_boundary.parent_surface.azimuth):
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['north']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['south']) / 100
elif math.sqrt(2) / 2 <= math.sin(thermal_boundary.parent_surface.azimuth):
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['east']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['west']) / 100
except ValueError:
# This is the normal operation way when the windows are defined in the geometry
continue
thermal_boundary.layers = []
for layer_archetype in construction_archetype.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
material = Material()
archetype_material = layer_archetype.material
layer.name = archetype_material.name
layer.no_mass = archetype_material.no_mass
material.name = archetype_material.name
material.id = archetype_material.id
material.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
layer.thermal_resistance = archetype_material.thermal_resistance
material.thermal_resistance = archetype_material.thermal_resistance
else:
layer.density = archetype_material.density
layer.conductivity = archetype_material.conductivity
layer.specific_heat = archetype_material.specific_heat
layer.solar_absorptance = archetype_material.solar_absorptance
layer.thermal_absorptance = archetype_material.thermal_absorptance
layer.visible_absorptance = archetype_material.visible_absorptance
_layers.append(layer)
construction.layers = _layers
material.density = archetype_material.density
material.conductivity = archetype_material.conductivity
material.specific_heat = archetype_material.specific_heat
material.solar_absorptance = archetype_material.solar_absorptance
material.thermal_absorptance = archetype_material.thermal_absorptance
material.visible_absorptance = archetype_material.visible_absorptance
layer.material = material
thermal_boundary.layers.append(layer)
# The agreement is that the layers are defined from outside to inside
external_layer = construction_archetype.layers[0]
external_surface = thermal_boundary.parent_surface
external_surface.short_wave_reflectance = 1 - external_layer.material.solar_absorptance
external_surface.long_wave_emittance = 1 - external_layer.material.solar_absorptance
internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1]
internal_surface = thermal_boundary.internal_surface
internal_surface.short_wave_reflectance = 1 - internal_layer.material.solar_absorptance
internal_surface.long_wave_emittance = 1 - internal_layer.material.solar_absorptance
if catalog_construction.window is not None:
window_archetype = catalog_construction.window
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
for thermal_opening in thermal_boundary.thermal_openings:
if construction_archetype.window is not None:
window_archetype = construction_archetype.window
thermal_opening.construction_name = window_archetype.name
thermal_opening.frame_ratio = window_archetype.frame_ratio
thermal_opening.g_value = window_archetype.g_value
thermal_opening.overall_u_value = window_archetype.overall_u_value
# todo: verify windows
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -8,11 +8,11 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
import logging
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.construction import Construction
from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class NrelPhysicsParameters:
@ -44,8 +44,28 @@ class NrelPhysicsParameters:
f' and climate zone {self._climate_zone}\n')
continue
thermal_archetype = ThermalArchetype()
self._assign_values(thermal_archetype, archetype)
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:
if building.internal_zones[0].thermal_zones is None:
self._create_storeys(building, archetype, self._divide_in_storeys)
if self._divide_in_storeys:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
else:
number_of_storeys = int(building.eave_height / building.average_storey_height)
thermal_zone = building.internal_zones[0].thermal_zones[0]
thermal_zone.total_floor_area = thermal_zone.footprint_area * number_of_storeys
else:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
for internal_zone in building.internal_zones:
self._assign_values(internal_zone.thermal_zones, archetype)
for thermal_zone in internal_zone.thermal_zones:
self._calculate_view_factors(thermal_zone)
@staticmethod
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
@ -60,36 +80,111 @@ class NrelPhysicsParameters:
raise KeyError('archetype not found')
@staticmethod
def _assign_values(thermal_archetype, catalog_archetype):
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
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
for catalog_construction in catalog_archetype.constructions:
construction = Construction()
construction.window_ratio = catalog_construction.window_ratio
_layers = []
for layer_archetype in catalog_construction.layers:
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
def _assign_values(self, thermal_zones, archetype):
for thermal_zone in thermal_zones:
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
thermal_zone.indirectly_heated_area_ratio = archetype.indirect_heated_ratio
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
for thermal_boundary in thermal_zone.thermal_boundaries:
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
thermal_boundary.construction_name = construction_archetype.name
try:
thermal_boundary.window_ratio = construction_archetype.window_ratio
except ValueError:
# This is the normal operation way when the windows are defined in the geometry
continue
thermal_boundary.layers = []
for layer_archetype in construction_archetype.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
material = Material()
archetype_material = layer_archetype.material
layer.name = archetype_material.name
layer.no_mass = archetype_material.no_mass
material.name = archetype_material.name
material.id = archetype_material.id
material.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
layer.thermal_resistance = archetype_material.thermal_resistance
material.thermal_resistance = archetype_material.thermal_resistance
else:
layer.density = archetype_material.density
layer.conductivity = archetype_material.conductivity
layer.specific_heat = archetype_material.specific_heat
layer.solar_absorptance = archetype_material.solar_absorptance
layer.thermal_absorptance = archetype_material.thermal_absorptance
layer.visible_absorptance = archetype_material.visible_absorptance
_layers.append(layer)
construction.layers = _layers
material.density = archetype_material.density
material.conductivity = archetype_material.conductivity
material.specific_heat = archetype_material.specific_heat
material.solar_absorptance = archetype_material.solar_absorptance
material.thermal_absorptance = archetype_material.thermal_absorptance
material.visible_absorptance = archetype_material.visible_absorptance
layer.material = material
thermal_boundary.layers.append(layer)
# The agreement is that the layers are defined from outside to inside
external_layer = construction_archetype.layers[0]
external_surface = thermal_boundary.parent_surface
external_surface.short_wave_reflectance = 1 - external_layer.material.solar_absorptance
external_surface.long_wave_emittance = 1 - external_layer.material.solar_absorptance
internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1]
internal_surface = thermal_boundary.internal_surface
internal_surface.short_wave_reflectance = 1 - internal_layer.material.solar_absorptance
internal_surface.long_wave_emittance = 1 - internal_layer.material.solar_absorptance
if catalog_construction.window is not None:
window_archetype = catalog_construction.window
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
for thermal_opening in thermal_boundary.thermal_openings:
if construction_archetype.window is not None:
window_archetype = construction_archetype.window
thermal_opening.construction_name = window_archetype.name
thermal_opening.frame_ratio = window_archetype.frame_ratio
thermal_opening.g_value = window_archetype.g_value
thermal_opening.overall_u_value = window_archetype.overall_u_value
# todo: verify windows
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -45,12 +45,12 @@ class InselMonthlyEnergyBalance:
domestic_hot_water_demand = []
lighting_demand = []
appliances_demand = []
if building.internal_zones[0].thermal_zones_from_internal_zones is None:
if building.internal_zones[0].thermal_zones is None:
domestic_hot_water_demand = [0] * 12
lighting_demand = [0] * 12
appliances_demand = [0] * 12
else:
thermal_zone = building.internal_zones[0].thermal_zones_from_internal_zones[0]
thermal_zone = building.internal_zones[0].thermal_zones[0]
area = thermal_zone.total_floor_area
cold_water = building.cold_water_temperature[cte.MONTH]['epw']
peak_flow = thermal_zone.domestic_hot_water.peak_flow

View File

@ -58,7 +58,7 @@ class CityObject(Models):
self.wall_area = wall_area
window_ratio = 0
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
window_ratio = thermal_boundary.window_ratio
break

View File

@ -106,7 +106,7 @@ class TestConstructionFactory(TestCase):
self.assertIsNotNone(building.shell, 'building shell is none')
def _check_thermal_zones(self, internal_zone):
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none')
self.assertIsNotNone(thermal_zone.footprint_area, 'thermal_zone floor area is none')
self.assertTrue(len(thermal_zone.thermal_boundaries) > 0, 'thermal_zone thermal_boundaries not defined')
@ -133,7 +133,7 @@ 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')
@ -184,7 +184,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -202,7 +202,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -220,7 +220,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -238,7 +238,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -256,7 +256,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -277,7 +277,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -299,7 +299,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -321,7 +321,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')

View File

@ -115,7 +115,7 @@ class TestExports(TestCase):
self.assertIsNotNone(building.basement_heated, f'building {building.name} basement_heated is none')
for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.area, f'internal zone {internal_zone.id} area is none')
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, f'thermal zone {thermal_zone.id} '
f'indirectly_heated_area_ratio is none')
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, f'thermal zone {thermal_zone.id} '

View File

@ -38,7 +38,7 @@ class TestGeometryFactory(TestCase):
self.assertIsNot(len(internal_zone.usages), 0, 'no building usages defined')
for usage in internal_zone.usages:
self.assertIsNotNone(usage.id, 'usage id is none')
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_zone(thermal_zone)
def _check_buildings(self, city):
@ -46,7 +46,7 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(building.internal_zones, 'no internal zones created')
for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.usages, 'usage zones are not defined')
self.assertIsNotNone(internal_zone.thermal_zones_from_internal_zones, 'thermal zones are not defined')
self.assertIsNotNone(internal_zone.thermal_zones, 'thermal zones are not defined')
self.assertIsNone(building.basement_heated, 'building basement_heated is not none')
self.assertIsNone(building.attic_heated, 'building attic_heated is not none')
self.assertIsNotNone(building.average_storey_height, 'building average_storey_height is none')
@ -105,7 +105,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet':
for building in city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_extra_thermal_zone(thermal_zone)
# usage factory called first
city = self._get_citygml(file)
@ -117,7 +117,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet':
for building in city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_extra_thermal_zone(thermal_zone)
def _test_pluto(self, file):
@ -135,7 +135,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet':
for building in city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_extra_thermal_zone(thermal_zone)
# usage factory called first
city = self._get_citygml(file)
@ -147,7 +147,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet':
for building in city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_extra_thermal_zone(thermal_zone)
def test_enrichment(self):

View File

@ -120,7 +120,6 @@ class TestExports(TestCase):
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
print(self._output_path)
try:
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
except Exception:

View File

@ -62,7 +62,7 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(building.internal_zones, 'building internal zones is none')
for internal_zone in building.internal_zones:
self.assertIsNone(internal_zone.usages, 'usage zones are defined')
self.assertIsNone(internal_zone.thermal_zones_from_internal_zones, 'thermal zones are defined')
self.assertIsNone(internal_zone.thermal_zones, 'thermal zones are defined')
self.assertIsNone(building.basement_heated, 'building basement_heated is not none')
self.assertIsNone(building.attic_heated, 'building attic_heated is not none')
self.assertIsNone(building.terrains, 'building terrains is not none')

View File

@ -115,7 +115,7 @@ class TestExports(TestCase):
self.assertIsNotNone(building.basement_heated, f'building {building.name} basement_heated is none')
for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.area, f'internal zone {internal_zone.id} area is none')
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, f'thermal zone {thermal_zone.id} '
f'indirectly_heated_area_ratio is none')
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, f'thermal zone {thermal_zone.id} '