""" Greenery catalog SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ import xmltodict from pathlib import Path from catalog_factories.catalog import Catalog from catalog_factories.data_models.construction.window import Window from catalog_factories.data_models.construction.material import Material from catalog_factories.data_models.construction.layer import Layer from catalog_factories.data_models.construction.construction import Construction from catalog_factories.data_models.construction.content import Content from catalog_factories.data_models.construction.archetype import Archetype from catalog_factories.construction.construction_helpers import nrel_to_function, reference_standard_to_construction_period class NrelCatalog(Catalog): def __init__(self, path): archetypes_path = str(Path(path / 'us_archetypes.xml').resolve()) constructions_path = str(Path(path / 'us_constructions.xml').resolve()) with open(constructions_path) as xml: self._constructions = xmltodict.parse(xml.read(), force_list=('material', 'window', 'construction')) with open(archetypes_path) as xml: self._archetypes = xmltodict.parse(xml.read(), force_list=('archetype', 'construction')) self._catalog_windows = [] self._catalog_materials = [] self._catalog_constructions = [] self._catalog_archetypes = [] windows = self._constructions['library']['windows']['window'] for window in windows: frame_ratio = window['frame_ratio'] g_value = window['shgc'] overall_u_value = float(window['conductivity']) / float(window['thickness']) construction_name = window['@name'] self._catalog_windows.append(Window(frame_ratio, g_value, overall_u_value, construction_name)) materials = self._constructions['library']['materials']['material'] for material in materials: material_id = material['@id'] name = material['@name'] solar_absorptance = material['solar_absorptance'] thermal_absorptance = material['thermal_absorptance'] visible_absorptance = material['visible_absorptance'] no_mass = True thermal_resistance = None, conductivity = None, density = None, specific_heat = None if material['no_mass'] == 'true': no_mass = True thermal_resistance = material['thermal_resistance'] else: conductivity = material['conductivity'] density = material['density'] specific_heat = material['specific_heat'] _material = Material(material_id, name, solar_absorptance, thermal_absorptance, visible_absorptance, no_mass, thermal_resistance, conductivity, density, specific_heat) self._catalog_materials.append(_material) constructions = self._constructions['library']['constructions']['construction'] for construction in constructions: construction_id = construction['@id'] construction_type = construction['@type'] name = construction['@name'] layers = [] for layer in construction['layers']['layer']: layer_id = layer['@id'] name = layer['@name'] material_id = layer['material'] thickness = layer['thickness'] for material in self._materials: if material_id == material.id: layers.append(Layer(layer_id, name, material, thickness)) break self._catalog_constructions.append(Construction(construction_id, construction_type, name, layers)) archetypes = self._archetypes['archetypes']['archetype'] for archetype in archetypes: archetype_id = archetype['@id'] function = nrel_to_function[archetype['@building_type']] construction_period = reference_standard_to_construction_period[archetype['reference_standard']] average_storey_height = archetype['average_storey_height'] number_of_storeys = archetype['number_of_storeys'] thermal_capacity = archetype['thermal_capacity'] extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_to_thermal_bridges'] indirect_heated_ratio = archetype['indirect_heated_ratio'] infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off'] infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on'] archetype_constructions = [] for archetype_construction in archetype['constructions']['construction']: for construction in self._constructions: if construction.id == archetype_construction['@id']: window_ratio = archetype_construction['window_ratio'] window = archetype_construction['window'] _construction = Construction(construction.id, construction.type, construction.name, construction.layers, window_ratio, window) archetype_constructions.append(_construction) self._catalog_archetypes.append(Archetype(archetype_id, function, archetype_constructions, construction_period, average_storey_height, number_of_storeys, thermal_capacity, extra_loses_due_to_thermal_bridges, indirect_heated_ratio, infiltration_rate_for_ventilation_system_off, infiltration_rate_for_ventilation_system_on)) # store the full catalog data model in self._content self._content = Content(self._catalog_archetypes, self._catalog_constructions, self._catalog_materials, self._catalog_windows) @property def names(self, category=None): """ Get the catalog elements names :parm: optional category filter """ if category is None: _names = {'archetypes': [], 'constructions': [], 'materials': [], 'windows': []} for archetype in self._content.archetypes: _names['archetypes'].append(archetype.name) for construction in self._content.constructions: _names['constructions'].append(construction.name) for material in self._content.materials: _names['materials'].append(material.name) for window in self._content.windows: _names['windows'].append(window.name) else: _names = {category: []} if category.lower() == 'archetypes': for archetype in self._content.archetypes: _names[category].append(archetype.name) elif category.lower() == 'constructions': for construction in self._content.constructions: _names[category].append(construction.name) elif category.lower() == 'materials': for material in self._content.materials: _names[category].append(material.name) elif category.lower() == 'windows': for window in self._content.windows: _names[category].append(window.name) else: raise ValueError(f'Unknown category [{category}]') return _names def entries(self, category=None): """ Get the catalog elements :parm: optional category filter """ if category is None: return self._content else: if category.lower() == 'archetypes': return self._content.archetypes elif category.lower() == 'constructions': return self._content.constructions elif category.lower() == 'materials': return self._content.materials elif category.lower() == 'windows': return self._content.windows else: raise ValueError(f'Unknown category [{category}]') def get_entry(self, name): """ Get one catalog element by names :parm: entry name """ for entry in self._content.archetypes: if entry.name.lower() == name.lower(): return entry for entry in self._content.constructions: if entry.name.lower() == name.lower(): return entry for entry in self._content.materials: if entry.name.lower() == name.lower(): return entry for entry in self._content.windows: if entry.name.lower() == name.lower(): return entry raise IndexError(f"{name} doesn't exists in the catalog") pass