2022-04-08 09:35:33 -04:00
|
|
|
"""
|
2022-04-11 14:32:44 -04:00
|
|
|
Nrel construction catalog
|
2022-04-08 09:35:33 -04:00
|
|
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
|
|
Copyright © 2022 Concordia CERC group
|
|
|
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|
|
|
"""
|
2022-04-08 14:14:04 -04:00
|
|
|
|
2022-04-08 09:35:33 -04:00
|
|
|
import xmltodict
|
|
|
|
from pathlib import Path
|
2022-04-08 18:03:35 -04:00
|
|
|
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
|
2022-12-15 07:42:59 -05:00
|
|
|
from catalog_factories.construction.construction_helper import ConstructionHelper
|
2022-04-08 09:35:33 -04:00
|
|
|
|
|
|
|
|
|
|
|
class NrelCatalog(Catalog):
|
|
|
|
def __init__(self, path):
|
2022-04-08 14:14:04 -04:00
|
|
|
archetypes_path = str(Path(path / 'us_archetypes.xml').resolve())
|
|
|
|
constructions_path = str(Path(path / 'us_constructions.xml').resolve())
|
|
|
|
with open(constructions_path) as xml:
|
2022-04-11 12:37:46 -04:00
|
|
|
self._constructions = xmltodict.parse(xml.read(), force_list=('material', 'window', 'construction', 'layer'))
|
2022-04-08 14:14:04 -04:00
|
|
|
with open(archetypes_path) as xml:
|
|
|
|
self._archetypes = xmltodict.parse(xml.read(), force_list=('archetype', 'construction'))
|
2022-04-11 12:37:46 -04:00
|
|
|
self._catalog_windows = self._load_windows()
|
|
|
|
self._catalog_materials = self._load_materials()
|
|
|
|
self._catalog_constructions = self._load_constructions()
|
|
|
|
self._catalog_archetypes = self._load_archetypes()
|
2022-04-08 14:14:04 -04:00
|
|
|
|
2022-04-11 12:37:46 -04:00
|
|
|
# store the full catalog data model in self._content
|
|
|
|
self._content = Content(self._catalog_archetypes,
|
|
|
|
self._catalog_constructions,
|
|
|
|
self._catalog_materials,
|
|
|
|
self._catalog_windows)
|
|
|
|
|
|
|
|
def _load_windows(self):
|
|
|
|
_catalog_windows = []
|
2022-04-08 14:14:04 -04:00
|
|
|
windows = self._constructions['library']['windows']['window']
|
|
|
|
for window in windows:
|
2022-04-11 12:37:46 -04:00
|
|
|
frame_ratio = window['frame_ratio']['#text']
|
2022-04-08 14:14:04 -04:00
|
|
|
g_value = window['shgc']
|
2022-04-11 12:37:46 -04:00
|
|
|
overall_u_value = float(window['conductivity']['#text']) / float(window['thickness']['#text'])
|
|
|
|
name = window['@name']
|
2022-04-13 18:31:54 -04:00
|
|
|
window_id = window['@id']
|
|
|
|
_catalog_windows.append(Window(window_id, frame_ratio, g_value, overall_u_value, name))
|
2022-04-11 12:37:46 -04:00
|
|
|
return _catalog_windows
|
2022-04-08 14:14:04 -04:00
|
|
|
|
2022-04-11 12:37:46 -04:00
|
|
|
def _load_materials(self):
|
|
|
|
_catalog_materials = []
|
2022-04-08 14:14:04 -04:00
|
|
|
materials = self._constructions['library']['materials']['material']
|
|
|
|
for material in materials:
|
|
|
|
material_id = material['@id']
|
|
|
|
name = material['@name']
|
2022-04-11 12:37:46 -04:00
|
|
|
solar_absorptance = material['solar_absorptance']['#text']
|
|
|
|
thermal_absorptance = material['thermal_absorptance']['#text']
|
|
|
|
visible_absorptance = material['visible_absorptance']['#text']
|
2022-04-13 18:31:54 -04:00
|
|
|
no_mass = False
|
2022-04-08 14:14:04 -04:00
|
|
|
thermal_resistance = None,
|
|
|
|
conductivity = None,
|
|
|
|
density = None,
|
|
|
|
specific_heat = None
|
2022-04-11 12:37:46 -04:00
|
|
|
if 'no_mass' in material and material['no_mass'] == 'true':
|
2022-04-08 14:14:04 -04:00
|
|
|
no_mass = True
|
2022-04-11 12:37:46 -04:00
|
|
|
thermal_resistance = material['thermal_resistance']['#text']
|
2022-04-08 14:14:04 -04:00
|
|
|
else:
|
2022-04-11 12:37:46 -04:00
|
|
|
conductivity = material['conductivity']['#text']
|
|
|
|
density = material['density']['#text']
|
|
|
|
specific_heat = material['specific_heat']['#text']
|
2022-04-08 14:14:04 -04:00
|
|
|
_material = Material(material_id,
|
|
|
|
name,
|
|
|
|
solar_absorptance,
|
|
|
|
thermal_absorptance,
|
|
|
|
visible_absorptance,
|
|
|
|
no_mass,
|
|
|
|
thermal_resistance,
|
|
|
|
conductivity,
|
|
|
|
density,
|
|
|
|
specific_heat)
|
2022-04-11 12:37:46 -04:00
|
|
|
_catalog_materials.append(_material)
|
|
|
|
return _catalog_materials
|
2022-04-08 14:14:04 -04:00
|
|
|
|
2022-04-11 12:37:46 -04:00
|
|
|
def _load_constructions(self):
|
|
|
|
_catalog_constructions = []
|
2022-04-08 14:14:04 -04:00
|
|
|
constructions = self._constructions['library']['constructions']['construction']
|
|
|
|
for construction in constructions:
|
|
|
|
construction_id = construction['@id']
|
2022-12-15 07:42:59 -05:00
|
|
|
construction_type = ConstructionHelper().nrel_surfaces_types_to_hub_types[construction['@type']]
|
2022-04-08 14:14:04 -04:00
|
|
|
name = construction['@name']
|
|
|
|
layers = []
|
|
|
|
for layer in construction['layers']['layer']:
|
|
|
|
layer_id = layer['@id']
|
2022-04-11 12:37:46 -04:00
|
|
|
layer_name = layer['@name']
|
2022-04-13 18:31:54 -04:00
|
|
|
material_id = layer['material'][0]
|
2022-04-11 12:37:46 -04:00
|
|
|
thickness = 0
|
|
|
|
if 'thickness' in layer:
|
|
|
|
thickness = layer['thickness']['#text']
|
|
|
|
for material in self._catalog_materials:
|
2022-04-13 18:31:54 -04:00
|
|
|
if str(material_id) == str(material.id):
|
2022-04-11 12:37:46 -04:00
|
|
|
layers.append(Layer(layer_id, layer_name, material, thickness))
|
2022-04-08 14:14:04 -04:00
|
|
|
break
|
2022-04-11 12:37:46 -04:00
|
|
|
_catalog_constructions.append(Construction(construction_id, construction_type, name, layers))
|
|
|
|
return _catalog_constructions
|
2022-04-08 14:14:04 -04:00
|
|
|
|
2022-04-11 12:37:46 -04:00
|
|
|
def _load_archetypes(self):
|
|
|
|
_catalog_archetypes = []
|
2022-04-08 14:14:04 -04:00
|
|
|
archetypes = self._archetypes['archetypes']['archetype']
|
|
|
|
for archetype in archetypes:
|
|
|
|
archetype_id = archetype['@id']
|
2022-12-15 07:42:59 -05:00
|
|
|
function = ConstructionHelper().nrel_to_function[archetype['@building_type']]
|
2022-04-19 15:49:41 -04:00
|
|
|
name = f"{function} {archetype['@climate_zone']} {archetype['@reference_standard']}"
|
|
|
|
climate_zone = archetype['@climate_zone']
|
2022-12-15 07:42:59 -05:00
|
|
|
construction_period = \
|
|
|
|
ConstructionHelper().reference_standard_to_construction_period[archetype['@reference_standard']]
|
2022-04-11 12:37:46 -04:00
|
|
|
average_storey_height = archetype['average_storey_height']['#text']
|
2022-11-28 14:10:13 -05:00
|
|
|
thermal_capacity = str(float(archetype['thermal_capacity']['#text']) * 1000)
|
2022-04-11 12:37:46 -04:00
|
|
|
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_to_thermal_bridges']['#text']
|
|
|
|
indirect_heated_ratio = archetype['indirect_heated_ratio']['#text']
|
|
|
|
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off']['#text']
|
|
|
|
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on']['#text']
|
2022-04-13 18:31:54 -04:00
|
|
|
|
2022-04-08 14:14:04 -04:00
|
|
|
archetype_constructions = []
|
|
|
|
for archetype_construction in archetype['constructions']['construction']:
|
2022-04-11 12:37:46 -04:00
|
|
|
for construction in self._catalog_constructions:
|
2022-04-08 14:14:04 -04:00
|
|
|
if construction.id == archetype_construction['@id']:
|
2022-04-11 12:37:46 -04:00
|
|
|
window_ratio = archetype_construction['window_ratio']['#text']
|
2022-04-13 18:31:54 -04:00
|
|
|
window_id = archetype_construction['window']
|
|
|
|
_construction = None
|
|
|
|
_window = None
|
|
|
|
for window in self._catalog_windows:
|
|
|
|
if window_id == window.id:
|
|
|
|
_window = window
|
|
|
|
break
|
2022-04-08 14:14:04 -04:00
|
|
|
_construction = Construction(construction.id,
|
|
|
|
construction.type,
|
|
|
|
construction.name,
|
|
|
|
construction.layers,
|
|
|
|
window_ratio,
|
2022-04-13 18:31:54 -04:00
|
|
|
_window)
|
2022-04-08 14:14:04 -04:00
|
|
|
archetype_constructions.append(_construction)
|
2022-04-13 18:31:54 -04:00
|
|
|
break
|
|
|
|
|
2022-04-11 12:37:46 -04:00
|
|
|
_catalog_archetypes.append(Archetype(archetype_id,
|
2022-04-13 18:31:54 -04:00
|
|
|
name,
|
2022-04-11 12:37:46 -04:00
|
|
|
function,
|
2022-04-19 15:49:41 -04:00
|
|
|
climate_zone,
|
2022-04-11 12:37:46 -04:00
|
|
|
construction_period,
|
2022-04-13 18:31:54 -04:00
|
|
|
archetype_constructions,
|
2022-04-11 12:37:46 -04:00
|
|
|
average_storey_height,
|
|
|
|
thermal_capacity,
|
|
|
|
extra_loses_due_to_thermal_bridges,
|
|
|
|
indirect_heated_ratio,
|
|
|
|
infiltration_rate_for_ventilation_system_off,
|
|
|
|
infiltration_rate_for_ventilation_system_on))
|
|
|
|
return _catalog_archetypes
|
2022-04-08 09:35:33 -04:00
|
|
|
|
|
|
|
def names(self, category=None):
|
2022-04-08 14:14:04 -04:00
|
|
|
"""
|
|
|
|
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
|
2022-04-08 09:35:33 -04:00
|
|
|
|
|
|
|
def entries(self, category=None):
|
2022-04-08 14:14:04 -04:00
|
|
|
"""
|
|
|
|
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}]')
|
2022-04-08 09:35:33 -04:00
|
|
|
|
|
|
|
def get_entry(self, name):
|
2022-04-08 14:14:04 -04:00
|
|
|
"""
|
|
|
|
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")
|