From 6b86dae410d1a653510611ebb34d9406084ac92e Mon Sep 17 00:00:00 2001 From: guille Date: Fri, 8 Apr 2022 14:14:04 -0400 Subject: [PATCH] complete coding for nrel catalog factory (Need to be tested) --- catalogs/construction/construction_helpers.py | 27 +++ catalogs/construction/nrel_catalog.py | 195 ++++++++++++++++-- .../data_models/construction/archetype.py | 9 + catalogs/data_models/construction/window.py | 51 +---- 4 files changed, 227 insertions(+), 55 deletions(-) create mode 100644 catalogs/construction/construction_helpers.py diff --git a/catalogs/construction/construction_helpers.py b/catalogs/construction/construction_helpers.py new file mode 100644 index 00000000..7ad3fd39 --- /dev/null +++ b/catalogs/construction/construction_helpers.py @@ -0,0 +1,27 @@ +from helpers import constants as cte + +nrel_to_function = { + 'residential': cte.RESIDENTIAL, + 'midrise apartment': cte.MID_RISE_APARTMENT, + 'high-rise apartment': cte.HIGH_RISE_APARTMENT, + 'small office': cte.SMALL_OFFICE, + 'medium office': cte.MEDIUM_OFFICE, + 'large office': cte.LARGE_OFFICE, + 'primary school': cte.PRIMARY_SCHOOL, + 'secondary school': cte.SECONDARY_SCHOOL, + 'stand-alone retail': cte.STAND_ALONE_RETAIL, + 'hospital': cte.HOSPITAL, + 'outpatient healthcare': cte.OUT_PATIENT_HEALTH_CARE, + 'strip mall': cte.STRIP_MALL, + 'supermarket': cte.SUPERMARKET, + 'warehouse': cte.WAREHOUSE, + 'quick service restaurant': cte.QUICK_SERVICE_RESTAURANT, + 'full service restaurant': cte.FULL_SERVICE_RESTAURANT, + 'small hotel': cte.SMALL_HOTEL, + 'large hotel': cte.LARGE_HOTEL +} + +reference_standard_to_construction_period = { + 'ASHRAE 90.1_2004': '2004 - 2009', + 'ASHRAE 189.1_2009': '2009 - PRESENT' +} \ No newline at end of file diff --git a/catalogs/construction/nrel_catalog.py b/catalogs/construction/nrel_catalog.py index ac346c68..4b33cbd6 100644 --- a/catalogs/construction/nrel_catalog.py +++ b/catalogs/construction/nrel_catalog.py @@ -4,31 +4,200 @@ 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 catalogs.catalog import Catalog +from catalogs.data_models.construction.window import Window +from catalogs.data_models.construction.material import Material +from catalogs.data_models.construction.layer import Layer +from catalogs.data_models.construction.construction import Construction +from catalogs.data_models.construction.content import Content +from catalogs.data_models.construction.archetype import Archetype +from catalogs.construction.construction_helpers import nrel_to_function, reference_standard_to_construction_period class NrelCatalog(Catalog): def __init__(self, path): - archetypes = str(Path(path / 'us_archetypes.xml').resolve()) - constructions = str(Path(path / 'us_constructions.xml').resolve()) - with open(constructions) as xml: - self._constructions = xmltodict.parse(xml.read()) - with open(archetypes) as xml: - self._archetypes = xmltodict.parse(xml.read()) - self._windows = [] - self._materials = [] - self._constructions = [] - self._archetypes = [] + 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): - nam + """ + 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): - pass + """ + 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 - diff --git a/catalogs/data_models/construction/archetype.py b/catalogs/data_models/construction/archetype.py index bd5db1e8..44c8647e 100644 --- a/catalogs/data_models/construction/archetype.py +++ b/catalogs/data_models/construction/archetype.py @@ -19,6 +19,7 @@ class Archetype: infiltration_rate_for_ventilation_system_on): self._id = archetype_id + self._name = f'{function} {construction_period}' self._function = function self._construction_period = construction_period self._constructions = constructions @@ -38,6 +39,14 @@ class Archetype: """ return self._id + @property + def name(self): + """ + Get archetype name + :return: str + """ + return self._name + def function(self): """ Get archetype function diff --git a/catalogs/data_models/construction/window.py b/catalogs/data_models/construction/window.py index ba702152..1f57f112 100644 --- a/catalogs/data_models/construction/window.py +++ b/catalogs/data_models/construction/window.py @@ -6,73 +6,40 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ class Window: - def __init__(self): - self._frame_ratio = None - self._g_value = None - self._overall_u_value = None - self._construction_name = None + def __init__(self, frame_ratio, g_value, overall_u_value, construction_name): + self._frame_ratio = frame_ratio + self._g_value = g_value + self._overall_u_value = overall_u_value + self._construction_name = construction_name @property def frame_ratio(self): """ Get window frame ratio - :return: None or float + :return: float """ return self._frame_ratio - @frame_ratio.setter - def frame_ratio(self, value): - """ - Set window frame ratio - :param value: float - """ - if value is not None: - self._frame_ratio = float(value) - @property def g_value(self): """ Get thermal opening g-value - :return: None or float + :return: float """ return self._g_value - @g_value.setter - def g_value(self, value): - """ - Set thermal opening g-value - :param value: float - """ - if value is not None: - self._g_value = float(value) - @property def overall_u_value(self): """ Get thermal opening overall U-value in W/m2K - :return: None or float + :return: float """ return self._overall_u_value - @overall_u_value.setter - def overall_u_value(self, value): - """ - Set thermal opening overall U-value in W/m2K - :param value: float - """ - if value is not None: - self._overall_u_value = float(value) - @property def construction_name(self): """ Get thermal opening construction name + :return: str """ return self._construction_name - - @construction_name.setter - def construction_name(self, value): - """ - Set thermal opening construction name - """ - self._construction_name = value