city_retrofit/imports/construction/nrel_physics_interface.py

241 lines
13 KiB
Python
Raw Normal View History

2021-01-05 15:01:36 -05:00
"""
Nrel-based interface, it reads format defined within the CERC team based on NREL structure
and enriches the city with archetypes and materials
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
2021-01-05 15:01:36 -05:00
"""
import xmltodict
2022-03-08 19:19:52 -05:00
from imports.construction.data_classes.building_achetype import BuildingArchetype as nba
from imports.construction.data_classes.thermal_boundary_archetype import ThermalBoundaryArchetype as ntba
from imports.construction.data_classes.thermal_opening_archetype import ThermalOpeningArchetype as ntoa
from imports.construction.data_classes.layer_archetype import LayerArchetype as nla
from imports.construction.helpers.storeys_generation import StoreysGeneration
2021-01-05 15:01:36 -05:00
2021-01-06 16:42:38 -05:00
class NrelPhysicsInterface:
2021-01-05 15:01:36 -05:00
"""
2021-01-06 16:42:38 -05:00
NrelPhysicsInterface abstract class
2021-01-05 15:01:36 -05:00
"""
2021-08-26 13:27:43 -04:00
2021-01-05 15:01:36 -05:00
def __init__(self, base_path, constructions_file='us_constructions.xml',
archetypes_file='us_archetypes.xml'):
2021-01-06 16:42:38 -05:00
self._building_archetypes = []
2021-01-05 15:01:36 -05:00
# load construction Library, CERC-NREL format
path = str(base_path / constructions_file)
with open(path) as xml:
self._library = xmltodict.parse(xml.read(), force_list='layer')
# load archetypes Library, CERC-NREL format
path = str(base_path / archetypes_file)
with open(path) as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list='layer')
for archetype in self._archetypes['archetypes']['archetype']:
2021-01-06 16:42:38 -05:00
archetype_keys = {}
2021-01-05 15:01:36 -05:00
for key, value in archetype.items():
if key[0] == '@':
2021-01-06 16:42:38 -05:00
archetype_keys[key] = value
2021-01-05 15:01:36 -05:00
average_storey_height = archetype['average_storey_height']['#text']
units = archetype['average_storey_height']['@units']
if units != 'm':
raise Exception(f'average storey height units = {units}, expected meters')
2021-01-05 15:01:36 -05:00
storeys_above_ground = archetype['number_of_storeys']['#text']
2021-08-26 13:27:43 -04:00
effective_thermal_capacity = float(archetype['thermal_capacity']['#text']) * 1000
units = archetype['thermal_capacity']['@units']
if units != 'kJ/K m2':
raise Exception(f'thermal capacity units = {units}, expected kJ/K m2')
2021-01-05 15:01:36 -05:00
additional_thermal_bridge_u_value = archetype['extra_loses_due_to_thermal_bridges']['#text']
units = archetype['extra_loses_due_to_thermal_bridges']['@units']
if units != 'W/K m2':
raise Exception(f'extra loses due to thermal bridges units = {units}, expected W/K m2')
2021-01-05 15:01:36 -05:00
indirectly_heated_area_ratio = archetype['indirect_heated_ratio']['#text']
# todo: check how infiltration rate is used in the model
2021-01-05 15:01:36 -05:00
infiltration_rate_system_off = archetype['infiltration_rate_for_ventilation_system_off']['#text']
units = archetype['infiltration_rate_for_ventilation_system_off']['@units']
if units != 'ACH':
raise Exception(f'infiltration rate for ventilation when system off units = {units}, expected ACH')
2021-01-05 15:01:36 -05:00
infiltration_rate_system_on = archetype['infiltration_rate_for_ventilation_system_on']['#text']
units = archetype['infiltration_rate_for_ventilation_system_on']['@units']
if units != 'ACH':
raise Exception(f'infiltration rate for ventilation when system on units = {units}, expected ACH')
2021-01-05 15:01:36 -05:00
thermal_boundary_archetypes = []
for construction in archetype['constructions']['construction']:
2021-01-05 15:01:36 -05:00
construction_type = construction['@type']
construction_id = construction['@id']
c_lib = self._search_construction_type('construction', construction_id)
construction_name = c_lib['@name']
layers = []
if 'layers' in c_lib:
for current_layer in c_lib['layers']['layer']:
material_lib = self._search_construction_type('material', current_layer['material'])
name = material_lib['@name']
solar_absorptance = material_lib['solar_absorptance']['#text']
thermal_absorptance = material_lib['thermal_absorptance']['#text']
visible_absorptance = material_lib['visible_absorptance']['#text']
no_mass = 'no_mass' in material_lib
if no_mass:
2021-08-26 13:27:43 -04:00
thermal_resistance = material_lib['thermal_resistance']['#text']
units = material_lib['thermal_resistance']['@units']
if units != 'm2 K/W':
raise Exception(f'thermal resistance units = {units}, expected m2 K/W')
layer = nla(name, solar_absorptance, thermal_absorptance, visible_absorptance, no_mass=no_mass,
2022-03-08 19:19:52 -05:00
thermal_resistance=thermal_resistance)
2021-01-05 15:01:36 -05:00
else:
thickness = current_layer['thickness']['#text']
units = current_layer['thickness']['@units']
if units != 'm':
raise Exception(f'thickness units = {units}, expected m')
2021-01-05 15:01:36 -05:00
conductivity = material_lib['conductivity']['#text']
units = material_lib['conductivity']['@units']
if units != 'W/m K':
raise Exception(f'conductivity units = {units}, expected W/m K')
2021-01-05 15:01:36 -05:00
specific_heat = material_lib['specific_heat']['#text']
units = material_lib['specific_heat']['@units']
if units != 'J/kg K':
raise Exception(f'specific_heat units = {units}, expected J/kg K')
2021-01-05 15:01:36 -05:00
density = material_lib['density']['#text']
units = material_lib['density']['@units']
if units != 'kg/m3':
raise Exception(f'density units = {units}, expected kg/m3')
layer = nla(name, solar_absorptance, thermal_absorptance, visible_absorptance, thickness=thickness,
2022-03-08 19:19:52 -05:00
conductivity=conductivity, specific_heat=specific_heat, density=density)
2021-01-05 15:01:36 -05:00
layers.append(layer)
2021-01-06 16:42:38 -05:00
thermal_opening = None
2021-01-05 15:01:36 -05:00
window_ratio = 0
if 'window' in construction and construction['window'] is not None:
window_ratio = construction['window_ratio']['#text']
w_lib = self._search_construction_type('window', construction['window'])
2022-04-04 22:41:34 -04:00
window_construction_name = w_lib['@name']
2021-01-05 15:01:36 -05:00
frame_ratio = w_lib['frame_ratio']['#text']
if 'conductivity' in w_lib:
conductivity = w_lib['conductivity']['#text']
units = w_lib['conductivity']['@units']
if units != 'W/m K':
raise Exception(f'conductivity units = {units}, expected W/m K')
2021-01-05 15:01:36 -05:00
thickness = w_lib['thickness']['#text']
units = w_lib['thickness']['@units']
if units != 'm':
raise Exception(f'thickness units = {units}, expected m')
2021-01-05 15:01:36 -05:00
g_value = w_lib['solar_transmittance_at_normal_incidence']['#text']
back_side_solar_transmittance_at_normal_incidence = \
2021-08-26 13:27:43 -04:00
w_lib['back_side_solar_transmittance_at_normal_incidence']['#text']
2021-01-05 15:01:36 -05:00
front_side_solar_transmittance_at_normal_incidence = \
2021-08-26 13:27:43 -04:00
w_lib['front_side_solar_transmittance_at_normal_incidence']['#text']
thermal_opening = ntoa(conductivity=conductivity, frame_ratio=frame_ratio, g_value=g_value,
thickness=thickness, back_side_solar_transmittance_at_normal_incidence=
back_side_solar_transmittance_at_normal_incidence,
front_side_solar_transmittance_at_normal_incidence=
2022-04-04 22:41:34 -04:00
front_side_solar_transmittance_at_normal_incidence,
construction_name=window_construction_name)
2021-01-05 15:01:36 -05:00
else:
overall_u_value = w_lib['overall_u_value']['#text']
units = w_lib['overall_u_value']['@units']
if units != 'W/m2 K':
raise Exception(f'overall U-value units = {units}, expected W/m2 K')
2021-01-05 15:01:36 -05:00
g_value = w_lib['g_value']
thermal_opening = ntoa(frame_ratio=frame_ratio, g_value=g_value, overall_u_value=overall_u_value)
2021-01-05 15:01:36 -05:00
if 'outside_thermal_absorptance' in c_lib:
outside_solar_absorptance = c_lib['outside_solar_absorptance']['#text']
outside_thermal_absorptance = c_lib['outside_thermal_absorptance']['#text']
outside_visible_absorptance = c_lib['outside_visible_absorptance']['#text']
thermal_boundary_archetype = ntba(construction_type, window_ratio, construction_name, layers, thermal_opening,
outside_solar_absorptance, outside_thermal_absorptance,
outside_visible_absorptance)
2021-01-05 15:01:36 -05:00
else:
if 'overall_u_value' in c_lib:
overall_u_value = c_lib['overall_u_value']['#text']
units = c_lib['overall_u_value']['@units']
if units != 'W/m2 K':
raise Exception(f'overall U-value units = {units}, expected W/m2 K')
2022-03-08 19:19:52 -05:00
if 'outside_solar_absorptance' in c_lib:
outside_solar_absorptance = c_lib['outside_solar_absorptance']['#text']
thermal_boundary_archetype = ntba(construction_type, window_ratio, construction_name, layers,
thermal_opening, outside_solar_absorptance=outside_solar_absorptance,
overall_u_value=overall_u_value)
else:
thermal_boundary_archetype = ntba(construction_type, window_ratio, construction_name, layers,
thermal_opening, overall_u_value=overall_u_value)
2021-01-05 15:01:36 -05:00
else:
thermal_boundary_archetype = ntba(construction_type, window_ratio, construction_name, layers,
thermal_opening)
2021-01-05 15:01:36 -05:00
thermal_boundary_archetypes.append(thermal_boundary_archetype)
building_archetype = nba(archetype_keys, average_storey_height, storeys_above_ground,
effective_thermal_capacity, additional_thermal_bridge_u_value,
indirectly_heated_area_ratio, infiltration_rate_system_off,
infiltration_rate_system_on, thermal_boundary_archetypes)
2021-01-06 16:42:38 -05:00
self._building_archetypes.append(building_archetype)
2021-01-05 15:01:36 -05:00
def _search_construction_type(self, construction_type, construction_id):
for c_lib in self._library['library'][construction_type + 's'][construction_type]:
if construction_id == c_lib['@id']:
return c_lib
raise Exception('Archetype definition contains elements that does not exist in the library')
2021-01-06 16:42:38 -05:00
@staticmethod
def _search_construction_in_archetype(building_archetype, construction_type):
for thermal_boundary in building_archetype.thermal_boundary_archetypes:
if thermal_boundary.boundary_type == construction_type:
return thermal_boundary
raise Exception('Construction type not found')
# 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
def enrich_buildings(self):
2021-08-26 13:27:43 -04:00
"""
Raise not implemented error
"""
2021-01-06 16:42:38 -05:00
raise NotImplementedError
@staticmethod
def _create_storeys(building, archetype):
building.average_storey_height = archetype.average_storey_height
building.storeys_above_ground = archetype.storeys_above_ground
thermal_zones = StoreysGeneration(building).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones