""" 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 © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ import xmltodict 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 class NrelPhysicsInterface: """ NrelPhysicsInterface abstract class """ def __init__(self, base_path, constructions_file='us_constructions.xml', archetypes_file='us_archetypes.xml'): self._building_archetypes = [] # 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']: archetype_keys = {} for key, value in archetype.items(): if key[0] == '@': archetype_keys[key] = value 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') storeys_above_ground = archetype['number_of_storeys']['#text'] 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') 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') indirectly_heated_area_ratio = archetype['indirect_heated_ratio']['#text'] # todo: check how infiltration rate is used in the model 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') 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') thermal_boundary_archetypes = [] for construction in archetype['constructions']['construction']: 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: 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, thermal_resistance=thermal_resistance) else: thickness = current_layer['thickness']['#text'] units = current_layer['thickness']['@units'] if units != 'm': raise Exception(f'thickness units = {units}, expected m') 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') 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') 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, conductivity=conductivity, specific_heat=specific_heat, density=density) layers.append(layer) thermal_opening = None 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']) window_construction_name = w_lib['@name'] 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') thickness = w_lib['thickness']['#text'] units = w_lib['thickness']['@units'] if units != 'm': raise Exception(f'thickness units = {units}, expected m') g_value = w_lib['solar_transmittance_at_normal_incidence']['#text'] back_side_solar_transmittance_at_normal_incidence = \ w_lib['back_side_solar_transmittance_at_normal_incidence']['#text'] front_side_solar_transmittance_at_normal_incidence = \ 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= front_side_solar_transmittance_at_normal_incidence, construction_name=window_construction_name) 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') g_value = w_lib['g_value'] thermal_opening = ntoa(frame_ratio=frame_ratio, g_value=g_value, overall_u_value=overall_u_value, construction_name=window_construction_name) 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) 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') 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) else: thermal_boundary_archetype = ntba(construction_type, window_ratio, construction_name, layers, thermal_opening) 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) self._building_archetypes.append(building_archetype) 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') @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): """ Raise not implemented error """ 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