city_retrofit/hub/imports/retrofit_factory.py

103 lines
6.3 KiB
Python
Raw Normal View History

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
class RetrofitFactory:
2024-09-23 15:53:36 -04:00
def __init__(self, retrofit_data, city):
2024-09-22 13:51:59 -04:00
"""
2024-09-23 15:53:36 -04:00
:param retrofit_data: Dictionary mapping building IDs to their retrofit data.
2024-09-22 13:51:59 -04:00
:param city: The City object containing the buildings to retrofit.
"""
2024-09-23 15:53:36 -04:00
self._retrofit_data = retrofit_data
2024-09-17 00:19:23 -04:00
self._city = city
2024-09-23 15:53:36 -04:00
def enrich(self):
2024-09-17 00:19:23 -04:00
for building in self._city.buildings:
2024-09-23 15:53:36 -04:00
building_id = str(building.name) # Convert ID to string to match JSON keys
if building_id in self._retrofit_data:
print(f"Applying retrofits to building ID {building_id}")
building_retrofit_data = self._retrofit_data[building_id]
retrofit_types = building_retrofit_data.get('retrofit_types', [])
self._apply_retrofits_to_building(building, retrofit_types, building_retrofit_data)
else:
print(f"No retrofit data for building ID {building_id}")
def _apply_retrofits_to_building(self, building, retrofit_types, retrofit_params):
if 'construction' in retrofit_types:
self._apply_construction_retrofit_to_building(building, retrofit_params)
if 'infiltration' in retrofit_types:
self._reduce_infiltration_rate_by_percentage(building, retrofit_params)
if 'windows' in retrofit_types:
self._apply_window_retrofit_to_building(building, retrofit_params)
def _apply_construction_retrofit_to_building(self, building: Building, retrofit_params):
wall_u_value = retrofit_params.get('wall_u_value')
roof_u_value = retrofit_params.get('roof_u_value')
ground_u_value = retrofit_params.get('ground_u_value')
2024-09-17 00:19:23 -04:00
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-23 15:53:36 -04:00
thermal_boundary.u_value = wall_u_value
print(f"Updated wall U-value to {wall_u_value} in building {building.name}")
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-23 15:53:36 -04:00
print(f"Updated roof U-value to {roof_u_value} in building {building.name}")
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-23 15:53:36 -04:00
print(f"Updated ground U-value to {ground_u_value} in building {building.name}")
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
2024-09-23 15:53:36 -04:00
print(f"Increased thermal resistance by {delta_r} in layer {layer.material_name}")
2024-09-19 21:10:26 -04:00
else:
2024-09-23 15:53:36 -04:00
print(f"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-23 15:53:36 -04:00
def _reduce_infiltration_rate_by_percentage(self, building: Building, retrofit_params):
percentage = retrofit_params.get('infiltration_reduction')
if percentage is None:
return
for thermal_zone in building.thermal_zones_from_internal_zones:
thermal_archetype = thermal_zone.parent_internal_zone.thermal_archetype
old_rate = thermal_archetype.infiltration_rate_for_ventilation_system_off
new_rate = old_rate * (1 - percentage / 100)
thermal_archetype.infiltration_rate_for_ventilation_system_off = new_rate
print(f"Reduced infiltration rate from {old_rate} to {new_rate} in building {building.name}")
2024-09-22 13:51:59 -04:00
2024-09-23 15:53:36 -04:00
def _apply_window_retrofit_to_building(self, building: Building, retrofit_params):
overall_u_value = retrofit_params.get('window_u_value')
g_value = retrofit_params.get('window_g_value')
for thermal_zone in building.thermal_zones_from_internal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
if thermal_boundary.type == cte.WALL:
construction_archetype = thermal_boundary._construction_archetype
construction_archetype.window_overall_u_value = overall_u_value
construction_archetype.window_g_value = g_value
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 U-value from {old_u_value} to {opening.overall_u_value} in building {building.name}")
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 building {building.name}")
else:
print(f"No thermal openings in thermal boundary {thermal_boundary} of type {thermal_boundary.type} in building {building.name}")
else:
# Skip thermal boundaries that are not walls
continue