diff --git a/hub/catalog_factories/data_models/energy_systems/content.py b/hub/catalog_factories/data_models/energy_systems/content.py index 8042a73d..d3fd9068 100644 --- a/hub/catalog_factories/data_models/energy_systems/content.py +++ b/hub/catalog_factories/data_models/energy_systems/content.py @@ -10,12 +10,13 @@ class Content: """ Content class """ - def __init__(self, archetypes, systems, generations, distributions, emissions): + def __init__(self, archetypes, systems, generations, distributions, emissions, storages): self._archetypes = archetypes self._systems = systems self._generations = generations self._distributions = distributions self._emissions = emissions + self._storages = storages @property def archetypes(self): @@ -52,6 +53,13 @@ class Content: """ return self._emissions + @property + def storage_equipments(self): + """ + All storage equipments in the catalog + """ + return self._storages + def to_dictionary(self): """Class content to dictionary""" _archetypes = [] diff --git a/hub/catalog_factories/energy_systems/energy_system_catalog.py b/hub/catalog_factories/energy_systems/energy_system_catalog.py deleted file mode 100644 index 564b5d40..00000000 --- a/hub/catalog_factories/energy_systems/energy_system_catalog.py +++ /dev/null @@ -1,251 +0,0 @@ -""" -Energy system catalog -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca -Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca -""" - -from ast import literal_eval -import xmltodict -from hub.catalog_factories.catalog import Catalog -from hub.catalog_factories.data_models.energy_systems.system import System -from hub.catalog_factories.data_models.energy_systems.content import Content -from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem -from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem -from hub.catalog_factories.data_models.energy_systems.energy_emission_system import EnergyEmissionSystem -from hub.catalog_factories.data_models.energy_systems.performance_curves import PerformanceCurves -from hub.catalog_factories.data_models.energy_systems.archetype import Archetype - - -class EnergySystem(Catalog): - """ - Montreal custom energy systems catalog class - """ - def __init__(self, path): - path = str(path / 'montreal_custom_systems.xml') - with open(path, 'r', encoding='utf-8') as xml: - self._archetypes = xmltodict.parse(xml.read(), force_list=('system', 'system_cluster', 'equipment', - 'demand', 'system_id')) - - self._lod = float(self._archetypes['catalog']['@lod']) - - self._catalog_generation_equipments = self._load_generation_equipments() - self._catalog_distribution_equipments = self._load_distribution_equipments() - self._catalog_emission_equipments = self._load_emission_equipments() - self._catalog_systems = self._load_systems() - self._catalog_archetypes = self._load_archetypes() - - # store the full catalog data model in self._content - self._content = Content(self._catalog_archetypes, - self._catalog_systems, - self._catalog_generation_equipments, - self._catalog_distribution_equipments, - self._catalog_emission_equipments) - - def _load_generation_equipments(self): - _equipments = [] - equipments = self._archetypes['catalog']['generation_equipments']['equipment'] - for equipment in equipments: - equipment_id = float(equipment['@id']) - equipment_type = equipment['@type'] - fuel_type = equipment['@fuel_type'] - name = equipment['name'] - heating_efficiency = None - if 'heating_efficiency' in equipment: - heating_efficiency = float(equipment['heating_efficiency']) - cooling_efficiency = None - if 'cooling_efficiency' in equipment: - cooling_efficiency = float(equipment['cooling_efficiency']) - electricity_efficiency = None - if 'electrical_efficiency' in equipment: - electricity_efficiency = float(equipment['electrical_efficiency']) - storage = literal_eval(equipment['storage'].capitalize()) - generation_system = GenerationSystem(equipment_id, - name, - equipment_type, - fuel_type, - None, - heating_efficiency, - cooling_efficiency, - electricity_efficiency, - None, - None, - storage, - None) - - _equipments.append(generation_system) - return _equipments - - def _load_distribution_equipments(self): - _equipments = [] - equipments = self._archetypes['catalog']['distribution_equipments']['equipment'] - for equipment in equipments: - equipment_id = float(equipment['@id']) - equipment_type = equipment['@type'] - name = equipment['name'] - distribution_heat_losses = None - if 'distribution_heat_losses' in equipment: - distribution_heat_losses = float(equipment['distribution_heat_losses']['#text']) / 100 - distribution_consumption_fix_flow = None - if 'distribution_consumption_fix_flow' in equipment: - distribution_consumption_fix_flow = float(equipment['distribution_consumption_fix_flow']['#text']) / 100 - distribution_consumption_variable_flow = None - if 'distribution_consumption_variable_flow' in equipment: - distribution_consumption_variable_flow = float(equipment['distribution_consumption_variable_flow']['#text']) / 100 - - distribution_system = DistributionSystem(equipment_id, - name, - equipment_type, - None, - distribution_consumption_fix_flow, - distribution_consumption_variable_flow, - distribution_heat_losses) - - _equipments.append(distribution_system) - return _equipments - - def _load_emission_equipments(self): - _equipments = [] - equipments = self._archetypes['catalog']['dissipation_equipments']['equipment'] - for equipment in equipments: - equipment_id = float(equipment['@id']) - equipment_type = equipment['@type'] - name = equipment['name'] - parasitic_consumption = None - if 'parasitic_consumption' in equipment: - parasitic_consumption = float(equipment['parasitic_consumption']['#text']) / 100 - - emission_system = EnergyEmissionSystem(equipment_id, - name, - equipment_type, - parasitic_consumption) - - _equipments.append(emission_system) - return _equipments - - def _load_systems(self): - _catalog_systems = [] - systems = self._archetypes['catalog']['systems']['system'] - for system in systems: - system_id = float(system['@id']) - name = system['name'] - demands = system['demands']['demand'] - generation_equipment = system['equipments']['generation_id'] - _generation_equipment = None - for equipment_archetype in self._catalog_generation_equipments: - if int(equipment_archetype.id) == int(generation_equipment): - _generation_equipment = equipment_archetype - distribution_equipment = system['equipments']['distribution_id'] - _distribution_equipment = None - for equipment_archetype in self._catalog_distribution_equipments: - if int(equipment_archetype.id) == int(distribution_equipment): - _distribution_equipment = equipment_archetype - emission_equipment = system['equipments']['dissipation_id'] - _emission_equipment = None - for equipment_archetype in self._catalog_emission_equipments: - if int(equipment_archetype.id) == int(emission_equipment): - _emission_equipment = equipment_archetype - - _catalog_systems.append(System(self._lod, - system_id, - name, - demands, - _generation_equipment, - _distribution_equipment, - _emission_equipment)) - return _catalog_systems - - def _load_archetypes(self): - _catalog_archetypes = [] - system_clusters = self._archetypes['catalog']['system_clusters']['system_cluster'] - for system_cluster in system_clusters: - name = system_cluster['@name'] - systems = system_cluster['systems']['system_id'] - _systems = [] - for system in systems: - for system_archetype in self._catalog_systems: - if int(system_archetype.id) == int(system): - _systems.append(system_archetype) - _catalog_archetypes.append(Archetype(self._lod, name, _systems)) - return _catalog_archetypes - - def names(self, category=None): - """ - Get the catalog elements names - :parm: optional category filter - """ - if category is None: - _names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'distribution_equipments': [], - 'emission_equipments':[]} - for archetype in self._content.archetypes: - _names['archetypes'].append(archetype.manufacturer) - for system in self._content.systems: - _names['systems'].append(system.manufacturer) - for equipment in self._content.generation_equipments: - _names['generation_equipments'].append(equipment.manufacturer) - for equipment in self._content.distribution_equipments: - _names['distribution_equipments'].append(equipment.manufacturer) - for equipment in self._content.emission_equipments: - _names['emission_equipments'].append(equipment.manufacturer) - else: - _names = {category: []} - if category.lower() == 'archetypes': - for archetype in self._content.archetypes: - _names[category].append(archetype.manufacturer) - elif category.lower() == 'systems': - for system in self._content.systems: - _names[category].append(system.manufacturer) - elif category.lower() == 'generation_equipments': - for system in self._content.generation_equipments: - _names[category].append(system.manufacturer) - elif category.lower() == 'distribution_equipments': - for system in self._content.distribution_equipments: - _names[category].append(system.manufacturer) - elif category.lower() == 'emission_equipments': - for system in self._content.emission_equipments: - _names[category].append(system.manufacturer) - 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 - if category.lower() == 'archetypes': - return self._content.archetypes - if category.lower() == 'systems': - return self._content.systems - if category.lower() == 'generation_equipments': - return self._content.generation_equipments - if category.lower() == 'distribution_equipments': - return self._content.distribution_equipments - if category.lower() == 'emission_equipments': - return self._content.emission_equipments - 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.manufacturer.lower() == name.lower(): - return entry - for entry in self._content.systems: - if entry.manufacturer.lower() == name.lower(): - return entry - for entry in self._content.generation_equipments: - if entry.manufacturer.lower() == name.lower(): - return entry - for entry in self._content.distribution_equipments: - if entry.manufacturer.lower() == name.lower(): - return entry - for entry in self._content.emission_equipments: - if entry.manufacturer.lower() == name.lower(): - return entry - raise IndexError(f"{name} doesn't exists in the catalog") diff --git a/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py b/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py new file mode 100644 index 00000000..86d8f215 --- /dev/null +++ b/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py @@ -0,0 +1,109 @@ +""" +North america energy system catalog +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca +""" + +from ast import literal_eval +import xmltodict +from hub.catalog_factories.catalog import Catalog +from hub.catalog_factories.data_models.energy_systems.system import System +from hub.catalog_factories.data_models.energy_systems.content import Content +from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem +from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem +from hub.catalog_factories.data_models.energy_systems.energy_emission_system import EnergyEmissionSystem +from hub.catalog_factories.data_models.energy_systems.energy_storage_system import EnergyStorageSystem +from hub.catalog_factories.data_models.energy_systems.performance_curves import PerformanceCurves +from hub.catalog_factories.data_models.energy_systems.archetype import Archetype +from hub.catalog_factories.data_models.construction.material import Material +from hub.catalog_factories.data_models.construction.layer import Layer + + +class NorthAmericaEnergySystemCatalog(Catalog): + """ + North america energy system catalog class + """ + def __init__(self, path): + path = str(path / 'Tools4CitiesESMF.xml') + with open(path, 'r', encoding='utf-8') as xml: + self._archetypes = xmltodict.parse(xml.read()) +# self._systems = self._load_systems() +# self._generation_components = self._load_generation_components() + self._storage_components = self._load_storage_components() + print(self._storage_components) +# self._system_archetypes = self._load_system_archetypes() + + # store the full catalog data model in self._content +# self._content = Content(self._system_archetypes, +# self._systems, +# self._generation_components, +# None, +# None, +# self._storage_components) + + def _load_storage_components(self): + storage_components = [] + components = self._archetypes['encomp:EnergySystemCatalog']['energycomponent']['thermalStorages'] + for component in components: + model_name = component['@modelName'] + manufacturer = component['@manufacturer'] + volume = component['@volume'] + height = component['@height'] + maximum_operating_temperature = component['@maxTemp'] + materials = self._load_materials() + material_name = component['@insulationMaterial'] + insulation_material = self._search_material(materials, material_name) + material_name = component['@tankMaterial'] + tank_material = self._search_material(materials, material_name) + thickness = float(component['@insulationThickness']) / 100 # from cm to m + insulation_layer = Layer(None, 'insulation', insulation_material, thickness) + thickness = float(component['@tankThickness']) / 100 # from cm to m + tank_layer = Layer(None, 'insulation', tank_material, thickness) + # the convention is from outside to inside + layers = [insulation_layer, tank_layer] + storage_component = EnergyStorageSystem(model_name, + manufacturer, + 'thermal', + volume, + None, + None, + None, + None, + None, + height, + layers, + maximum_operating_temperature) + storage_components.append(storage_component) + return storage_components + + def _load_materials(self): + materials = [] + _materials = self._archetypes['encomp:EnergySystemCatalog']['energycomponent']['materials'] + for _material in _materials: + name = _material['@name'] + thermal_conductivity = _material['@thermalConductivity'] + material = Material(None, + name, + None, + None, + None, + False, + None, + thermal_conductivity, + None, + None) + materials.append(material) + return materials + + @staticmethod + def _search_material(materials, material_name): + _material = None + for material in materials: + if material.name == material_name: + _material = material + return _material + + if _material is None: + raise ValueError(f'Material not found in catalog [{material_name}]') diff --git a/hub/catalog_factories/energy_systems_catalog_factory.py b/hub/catalog_factories/energy_systems_catalog_factory.py index 4b59eeda..6e102bc3 100644 --- a/hub/catalog_factories/energy_systems_catalog_factory.py +++ b/hub/catalog_factories/energy_systems_catalog_factory.py @@ -9,6 +9,7 @@ from pathlib import Path from typing import TypeVar from hub.catalog_factories.energy_systems.montreal_custom_catalog import MontrealCustomCatalog +from hub.catalog_factories.energy_systems.north_america_energy_system_catalog import NorthAmericaEnergySystemCatalog from hub.helpers.utils import validate_import_export_type Catalog = TypeVar('Catalog') @@ -32,6 +33,13 @@ class EnergySystemsCatalogFactory: """ return MontrealCustomCatalog(self._path) + @property + def _north_america(self): + """ + Retrieve North American catalog + """ + return NorthAmericaEnergySystemCatalog(self._path) + @property def catalog(self) -> Catalog: """ diff --git a/hub/data/energy_systems/Tools4CitiesESMF.encomp b/hub/data/energy_systems/Tools4CitiesESMF.xml similarity index 88% rename from hub/data/energy_systems/Tools4CitiesESMF.encomp rename to hub/data/energy_systems/Tools4CitiesESMF.xml index 06c9e622..6ee58c84 100644 --- a/hub/data/energy_systems/Tools4CitiesESMF.encomp +++ b/hub/data/energy_systems/Tools4CitiesESMF.xml @@ -23,11 +23,11 @@ - - - - - + + + + + @@ -37,7 +37,7 @@ - + diff --git a/tests/test_systems_catalog.py b/tests/test_systems_catalog.py index f17038cb..48446d50 100644 --- a/tests/test_systems_catalog.py +++ b/tests/test_systems_catalog.py @@ -35,3 +35,5 @@ class TestSystemsCatalog(TestCase): with self.assertRaises(IndexError): catalog.get_entry('unknown') + def test_north_america_systems_catalog(self): + catalog = EnergySystemsCatalogFactory('north_america').catalog