2024-09-22 13:51:59 -04:00
|
|
|
# from hub.city_model_structure.building import Building
|
|
|
|
# from hub.city_model_structure.city import City
|
|
|
|
# import hub.helpers.constants as cte
|
|
|
|
# import copy
|
|
|
|
|
|
|
|
# class RetrofitFactory:
|
|
|
|
# def __init__(self, retrofit_type, city):
|
|
|
|
# self._retrofit_type = retrofit_type
|
|
|
|
# self._city = city
|
|
|
|
|
|
|
|
# def apply_retrofit(self, wall_u_value=None, roof_u_value=None, ground_u_value=None):
|
|
|
|
# for building in self._city.buildings:
|
|
|
|
# self._apply_retrofit_to_building(building, wall_u_value, roof_u_value, ground_u_value)
|
|
|
|
|
|
|
|
# def _apply_retrofit_to_building(self, building: Building, wall_u_value, roof_u_value, ground_u_value):
|
|
|
|
# for thermal_zone in building.thermal_zones_from_internal_zones:
|
|
|
|
# for thermal_boundary in thermal_zone.thermal_boundaries:
|
|
|
|
# if wall_u_value is not None and thermal_boundary.type == cte.WALL and thermal_boundary.u_value > wall_u_value:
|
|
|
|
# self._change_thermal_resistance(thermal_boundary, wall_u_value)
|
|
|
|
# thermal_boundary.u_value = wall_u_value
|
|
|
|
# elif roof_u_value is not None and thermal_boundary.type == cte.ROOF:
|
|
|
|
# self._change_thermal_resistance(thermal_boundary, roof_u_value)
|
|
|
|
# thermal_boundary.u_value = roof_u_value
|
|
|
|
# elif ground_u_value is not None and thermal_boundary.type == cte.GROUND:
|
|
|
|
# self._change_thermal_resistance(thermal_boundary, ground_u_value)
|
|
|
|
# thermal_boundary.u_value = ground_u_value
|
|
|
|
# print("thermal_boundary.u_value",thermal_boundary.u_value, thermal_boundary.type)
|
|
|
|
|
|
|
|
|
|
|
|
# def _change_thermal_resistance(self, thermal_boundary, new_u_value):
|
|
|
|
# old_u_value = thermal_boundary.u_value
|
|
|
|
# new_u_value = new_u_value
|
|
|
|
# if new_u_value < old_u_value:
|
|
|
|
# delta_r = (1 / new_u_value) - (1 / old_u_value)
|
|
|
|
# for layer in thermal_boundary.layers:
|
|
|
|
# if "virtual_no_mass" in layer.material_name.lower():
|
|
|
|
# new_thermal_resistance = layer.thermal_resistance + delta_r
|
|
|
|
# layer.thermal_resistance = new_thermal_resistance
|
|
|
|
# else:
|
|
|
|
# print("New U-value:", new_u_value, "is not less than old U-value:", old_u_value, "for thermal boundary type:", thermal_boundary.type)
|
|
|
|
|
|
|
|
# def enrich(self, wall_u_value=None, roof_u_value=None, ground_u_value=None):
|
|
|
|
# # This method can be expanded to include different retrofit strategies
|
|
|
|
# if self._retrofit_type == 'basic':
|
|
|
|
# self.apply_retrofit(wall_u_value=0.247, roof_u_value=0.138, ground_u_value=0.156)
|
|
|
|
# elif self._retrofit_type == 'advanced':
|
|
|
|
# self.apply_retrofit(wall_u_value=0.11, roof_u_value=0.08, ground_u_value=0.1)
|
|
|
|
# #add option for custom wall only, roof only, ground only, the user choose the values
|
|
|
|
# elif self._retrofit_type == 'custom':
|
|
|
|
# # Use user-defined custom values (if provided)
|
|
|
|
# self.apply_retrofit(wall_u_value=wall_u_value, roof_u_value=roof_u_value, ground_u_value=ground_u_value)
|
|
|
|
# else:
|
|
|
|
# print("Invalid retrofit type:", self._retrofit_type)
|
2024-09-17 00:19:23 -04:00
|
|
|
from hub.city_model_structure.building import Building
|
|
|
|
from hub.city_model_structure.city import City
|
|
|
|
import hub.helpers.constants as cte
|
2024-09-19 23:36:49 -04:00
|
|
|
import copy
|
2024-09-17 00:19:23 -04:00
|
|
|
|
|
|
|
class RetrofitFactory:
|
2024-09-22 13:51:59 -04:00
|
|
|
def __init__(self, retrofit_types, city):
|
|
|
|
"""
|
|
|
|
:param retrofit_types: List of retrofit types to apply. Options are 'construction', 'windows', 'infiltration'.
|
|
|
|
:param city: The City object containing the buildings to retrofit.
|
|
|
|
"""
|
|
|
|
self._retrofit_types = retrofit_types
|
2024-09-17 00:19:23 -04:00
|
|
|
self._city = city
|
|
|
|
|
2024-09-22 13:51:59 -04:00
|
|
|
def apply_construction_retrofit(self, wall_u_value=None, roof_u_value=None, ground_u_value=None):
|
2024-09-17 00:19:23 -04:00
|
|
|
for building in self._city.buildings:
|
2024-09-22 13:51:59 -04:00
|
|
|
self._apply_construction_retrofit_to_building(building, wall_u_value, roof_u_value, ground_u_value)
|
2024-09-17 00:19:23 -04:00
|
|
|
|
2024-09-22 13:51:59 -04:00
|
|
|
def _apply_construction_retrofit_to_building(self, building: Building, wall_u_value, roof_u_value, ground_u_value):
|
2024-09-17 00:37:42 -04:00
|
|
|
for thermal_zone in building.thermal_zones_from_internal_zones:
|
|
|
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
2024-09-19 23:36:49 -04:00
|
|
|
if wall_u_value is not None and thermal_boundary.type == cte.WALL and thermal_boundary.u_value > wall_u_value:
|
2024-09-19 21:10:26 -04:00
|
|
|
self._change_thermal_resistance(thermal_boundary, wall_u_value)
|
2024-09-19 23:36:49 -04:00
|
|
|
thermal_boundary.u_value = wall_u_value
|
2024-09-22 13:51:59 -04:00
|
|
|
elif roof_u_value is not None and thermal_boundary.type == cte.ROOF and thermal_boundary.u_value > roof_u_value:
|
2024-09-19 21:10:26 -04:00
|
|
|
self._change_thermal_resistance(thermal_boundary, roof_u_value)
|
2024-09-17 00:37:42 -04:00
|
|
|
thermal_boundary.u_value = roof_u_value
|
2024-09-22 13:51:59 -04:00
|
|
|
elif ground_u_value is not None and thermal_boundary.type == cte.GROUND and thermal_boundary.u_value > ground_u_value:
|
|
|
|
self._change_thermal_resistance(thermal_boundary, ground_u_value)
|
2024-09-17 00:37:42 -04:00
|
|
|
thermal_boundary.u_value = ground_u_value
|
2024-09-22 13:51:59 -04:00
|
|
|
print("thermal_boundary.u_value", thermal_boundary.u_value, thermal_boundary.type)
|
2024-09-19 21:10:26 -04:00
|
|
|
|
2024-09-22 13:51:59 -04:00
|
|
|
def _change_thermal_resistance(self, thermal_boundary, new_u_value):
|
2024-09-19 23:36:49 -04:00
|
|
|
old_u_value = thermal_boundary.u_value
|
2024-09-19 21:10:26 -04:00
|
|
|
if new_u_value < old_u_value:
|
2024-09-19 23:36:49 -04:00
|
|
|
delta_r = (1 / new_u_value) - (1 / old_u_value)
|
2024-09-19 21:10:26 -04:00
|
|
|
for layer in thermal_boundary.layers:
|
|
|
|
if "virtual_no_mass" in layer.material_name.lower():
|
|
|
|
new_thermal_resistance = layer.thermal_resistance + delta_r
|
|
|
|
layer.thermal_resistance = new_thermal_resistance
|
|
|
|
else:
|
2024-09-19 23:36:49 -04:00
|
|
|
print("New U-value:", new_u_value, "is not less than old U-value:", old_u_value, "for thermal boundary type:", thermal_boundary.type)
|
2024-09-17 00:19:23 -04:00
|
|
|
|
2024-09-22 13:51:59 -04:00
|
|
|
def reduce_infiltration_rate_by_percentage(self, percentage):
|
|
|
|
"""
|
|
|
|
Reduce the infiltration_rate_system_off of each thermal zone by the given percentage.
|
|
|
|
:param percentage: Percentage by which to reduce the infiltration rate (e.g., 20 for 20%)
|
|
|
|
"""
|
|
|
|
for building in self._city.buildings:
|
|
|
|
for thermal_zone in building.thermal_zones_from_internal_zones:
|
|
|
|
old_rate = thermal_zone.infiltration_rate_system_off
|
|
|
|
new_rate = old_rate * (1 - percentage / 100)
|
|
|
|
thermal_zone.infiltration_rate_system_off = new_rate
|
|
|
|
print(f"Reduced infiltration rate from {old_rate} to {new_rate} in thermal zone {thermal_zone}")
|
|
|
|
|
|
|
|
def apply_window_retrofit(self, overall_u_value=None, g_value=None):
|
|
|
|
"""
|
|
|
|
Apply window retrofit by changing window overall U-value and g-value.
|
|
|
|
:param overall_u_value: New overall U-value for the windows (if not None).
|
|
|
|
:param g_value: New g-value (solar heat gain coefficient) for the windows (if not None).
|
|
|
|
"""
|
|
|
|
for building in self._city.buildings:
|
|
|
|
for thermal_zone in building.thermal_zones_from_internal_zones:
|
|
|
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
|
|
|
# Only apply to walls (and roofs if skylights are considered)
|
|
|
|
if thermal_boundary.type in [cte.WALL]: # Add cte.ROOF if skylights are present
|
|
|
|
if hasattr(thermal_boundary, 'thermal_openings') and thermal_boundary.thermal_openings:
|
|
|
|
for opening in thermal_boundary.thermal_openings:
|
|
|
|
if overall_u_value is not None and overall_u_value != 0:
|
|
|
|
old_u_value = opening.overall_u_value
|
|
|
|
opening.overall_u_value = overall_u_value
|
|
|
|
print(f"Changed window overall_u_value from {old_u_value} to {opening.overall_u_value} in opening {opening}")
|
|
|
|
if g_value is not None and g_value != 0:
|
|
|
|
old_g_value = opening.g_value
|
|
|
|
opening.g_value = g_value
|
|
|
|
print(f"Changed window g_value from {old_g_value} to {opening.g_value} in opening {opening}")
|
|
|
|
else:
|
|
|
|
print(f"No thermal openings in thermal boundary {thermal_boundary} of type {thermal_boundary.type}")
|
|
|
|
else:
|
|
|
|
# Skip thermal boundaries that are not walls or roofs
|
|
|
|
continue
|
|
|
|
|
|
|
|
def enrich(self, wall_u_value=None, roof_u_value=None, ground_u_value=None,
|
|
|
|
infiltration_rate_percentage_reduction=None,
|
|
|
|
window_overall_u_value=None, window_g_value=None):
|
|
|
|
"""
|
|
|
|
Apply selected retrofits to the city.
|
|
|
|
"""
|
|
|
|
if 'construction' in self._retrofit_types:
|
|
|
|
self.apply_construction_retrofit(wall_u_value, roof_u_value, ground_u_value)
|
|
|
|
if 'infiltration' in self._retrofit_types and infiltration_rate_percentage_reduction is not None:
|
|
|
|
self.reduce_infiltration_rate_by_percentage(infiltration_rate_percentage_reduction)
|
|
|
|
if 'windows' in self._retrofit_types:
|
|
|
|
self.apply_window_retrofit(overall_u_value=window_overall_u_value, g_value=window_g_value)
|