diff --git a/hub/catalog_factories/data_models/energy_systems/archetype.py b/hub/catalog_factories/data_models/energy_systems/archetype.py
index 58b671b6..b770eae1 100644
--- a/hub/catalog_factories/data_models/energy_systems/archetype.py
+++ b/hub/catalog_factories/data_models/energy_systems/archetype.py
@@ -5,28 +5,17 @@ Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
-from typing import Union
+from typing import List
-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.emission_system import EmissionSystem
+from hub.catalog_factories.data_models.energy_systems.equipment import Equipment
class Archetype:
- def __init__(self,
- lod,
- name,
- demand_types,
- generation_system,
- distribution_system,
- emission_system):
+ def __init__(self, lod, name, equipments):
self._lod = lod
self._name = name
- self._demand_types = demand_types
- self._generation_system = generation_system
- self._distribution_system = distribution_system
- self._emission_system = emission_system
+ self._equipments = equipments
@property
def lod(self):
@@ -45,33 +34,9 @@ class Archetype:
return f'{self._name}_lod{self._lod}'
@property
- def demand_types(self):
+ def equipments(self) -> List[Equipment]:
"""
- Get demand able to cover from [heating, cooling, domestic_hot_water, electricity]
- :return: [string]
+ Get list of equipments that compose the total energy system
+ :return: [Equipment]
"""
- return self._demand_types
-
- @property
- def generation_system(self) -> GenerationSystem:
- """
- Get generation system
- :return: GenerationSystem
- """
- return self._generation_system
-
- @property
- def distribution_system(self) -> Union[None, DistributionSystem]:
- """
- Get distribution system
- :return: DistributionSystem
- """
- return self._distribution_system
-
- @property
- def emission_system(self) -> Union[None, EmissionSystem]:
- """
- Get emission system
- :return: EmissionSystem
- """
- return self._emission_system
+ return self._equipments
diff --git a/hub/catalog_factories/data_models/energy_systems/content.py b/hub/catalog_factories/data_models/energy_systems/content.py
index 5a0b61f3..53c07efb 100644
--- a/hub/catalog_factories/data_models/energy_systems/content.py
+++ b/hub/catalog_factories/data_models/energy_systems/content.py
@@ -7,12 +7,20 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
class Content:
- def __init__(self, archetypes):
+ def __init__(self, archetypes, equipments):
self._archetypes = archetypes
+ self._equipments = equipments
@property
def archetypes(self):
"""
- All archetypes in the catalog
+ All archetype systems in the catalog
"""
return self._archetypes
+
+ @property
+ def equipments(self):
+ """
+ All equipments in the catalog
+ """
+ return self._equipments
diff --git a/hub/catalog_factories/data_models/energy_systems/equipment.py b/hub/catalog_factories/data_models/energy_systems/equipment.py
new file mode 100644
index 00000000..9b2ddcd4
--- /dev/null
+++ b/hub/catalog_factories/data_models/energy_systems/equipment.py
@@ -0,0 +1,87 @@
+"""
+Energy System catalog equipment
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2023 Concordia CERC group
+Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from typing import Union
+
+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.emission_system import EmissionSystem
+
+
+class Equipment:
+ def __init__(self,
+ lod,
+ equipment_id,
+ name,
+ demand_types,
+ generation_system,
+ distribution_system,
+ emission_system):
+
+ self._lod = lod
+ self._equipment_id = equipment_id
+ self._name = name
+ self._demand_types = demand_types
+ self._generation_system = generation_system
+ self._distribution_system = distribution_system
+ self._emission_system = emission_system
+
+ @property
+ def lod(self):
+ """
+ Get level of detail of the catalog
+ :return: string
+ """
+ return self._lod
+
+ @property
+ def id(self):
+ """
+ Get equipment id
+ :return: string
+ """
+ return self._equipment_id
+
+ @property
+ def name(self):
+ """
+ Get name
+ :return: string
+ """
+ return f'{self._name}_lod{self._lod}'
+
+ @property
+ def demand_types(self):
+ """
+ Get demand able to cover from [heating, cooling, domestic_hot_water, electricity]
+ :return: [string]
+ """
+ return self._demand_types
+
+ @property
+ def generation_system(self) -> GenerationSystem:
+ """
+ Get generation system
+ :return: GenerationSystem
+ """
+ return self._generation_system
+
+ @property
+ def distribution_system(self) -> Union[None, DistributionSystem]:
+ """
+ Get distribution system
+ :return: DistributionSystem
+ """
+ return self._distribution_system
+
+ @property
+ def emission_system(self) -> Union[None, EmissionSystem]:
+ """
+ Get emission system
+ :return: EmissionSystem
+ """
+ return self._emission_system
diff --git a/hub/catalog_factories/data_models/energy_systems/generation_system.py b/hub/catalog_factories/data_models/energy_systems/generation_system.py
index b6d0eb3a..51a5325c 100644
--- a/hub/catalog_factories/data_models/energy_systems/generation_system.py
+++ b/hub/catalog_factories/data_models/energy_systems/generation_system.py
@@ -11,7 +11,7 @@ from typing import Union
class GenerationSystem:
def __init__(self, system_type, fuel_type, source_types, heat_efficiency, cooling_efficiency, electricity_efficiency,
- source_temperature, source_mass_flow, storage_capacity, auxiliary_equipment):
+ source_temperature, source_mass_flow, storage, auxiliary_equipment):
self._type = system_type
self._fuel_type = fuel_type
@@ -21,7 +21,7 @@ class GenerationSystem:
self._electricity_efficiency = electricity_efficiency
self._source_temperature = source_temperature
self._source_mass_flow = source_mass_flow
- self._storage_capacity = storage_capacity
+ self._storage = storage
self._auxiliary_equipment = auxiliary_equipment
@property
@@ -89,12 +89,12 @@ class GenerationSystem:
return self._source_mass_flow
@property
- def storage_capacity(self):
+ def storage(self):
"""
- Get storage_capacity in J
- :return: float
+ Get boolean storage exists
+ :return: bool
"""
- return self._storage_capacity
+ return self._storage
@property
def auxiliary_equipment(self) -> Union[None, GenerationSystem]:
diff --git a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py
index 2ac6daab..d42601b2 100644
--- a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py
+++ b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py
@@ -8,50 +8,127 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import xmltodict
from hub.catalog_factories.catalog import Catalog
-from hub.catalog_factories.data_models.energy_systems.archetype import Archetype
+from hub.catalog_factories.data_models.energy_systems.equipment import Equipment
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.archetype import Archetype
class MontrealCustomCatalog(Catalog):
def __init__(self, path):
path = str(path / 'montreal_custom_systems.xml')
with open(path) as xml:
- self._archetypes = xmltodict.parse(xml.read(), force_list='archetype')
+ self._archetypes = xmltodict.parse(xml.read(), force_list=('equipment', 'system', 'demand', 'equipment_id'))
+
+ self._lod = float(self._archetypes['catalog']['@lod'])
+
+ self._catalog_equipments = self._load_equipments()
+ self._catalog_archetypes = self._load_archetypes()
# store the full catalog data model in self._content
- self._content = Content(self._load_archetypes())
+ self._content = Content(self._catalog_archetypes,
+ self._catalog_equipments)
+
+ def _load_equipments(self):
+ _catalog_equipments = []
+ equipments = self._archetypes['catalog']['equipments']['equipment']
+ for equipment in equipments:
+ equipment_id = float(equipment['@id'])
+ equipment_type = equipment['@type']
+ fuel_type = equipment['@fuel_type']
+ name = equipment['name']
+ demands = equipment['demands']['demand']
+ 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 'electricity_efficiency' in equipment:
+ electricity_efficiency = float(equipment['electricity_efficiency'])
+ distribution_heat_losses = None
+ if 'distribution_heat_losses' in equipment:
+ distribution_heat_losses = float(equipment['distribution_heat_losses']['#text']) / 100
+ distribution_consumption = None
+ if 'distribution_consumption' in equipment:
+ distribution_consumption = float(equipment['distribution_consumption']['#text']) / 100
+ storage = eval(equipment['storage'].capitalize())
+ generation_system = GenerationSystem(equipment_type,
+ fuel_type,
+ None,
+ heating_efficiency,
+ cooling_efficiency,
+ electricity_efficiency,
+ None,
+ None,
+ storage,
+ None)
+ distribution_system = DistributionSystem(None,
+ None,
+ distribution_consumption,
+ distribution_heat_losses)
+ _catalog_equipments.append(Equipment(self._lod,
+ equipment_id,
+ name,
+ demands,
+ generation_system,
+ distribution_system,
+ None))
+ return _catalog_equipments
def _load_archetypes(self):
_catalog_archetypes = []
- archetypes = self._archetypes['archetypes']['archetype']
- for archetype in archetypes:
- name = archetype['@name']
- lod = float(archetype['@lod'])
- demand_types = archetype['@demands']
- _catalog_archetypes.append(Archetype(lod,
- name,
- demand_types,
- generation_system,
- distribution_system,
- emission_system))
+ systems = self._archetypes['catalog']['systems']['system']
+ for system in systems:
+ name = system['@name']
+ system_equipments = system['equipments']['equipment_id']
+ _equipments = []
+ for system_equipment in system_equipments:
+ for equipment in self._catalog_equipments:
+ if int(equipment.id) == int(system_equipment):
+ _equipments.append(equipment)
+ _catalog_archetypes.append(Archetype(self._lod, name, _equipments))
return _catalog_archetypes
def names(self, category=None):
"""
Get the catalog elements names
- :parm: for energy systems catalog category filter does nothing as there is only one category (archetypes)
+ :parm: optional category filter
"""
- _names = {'archetypes': []}
- for archetype in self._content.archetypes:
- _names['archetypes'].append(archetype.name)
+ if category is None:
+ _names = {'archetypes': [], 'equipments': []}
+ for archetype in self._content.archetypes:
+ _names['archetypes'].append(archetype.name)
+ for equipment in self._content.equipments:
+ _names['equipments'].append(equipment.name)
+ else:
+ _names = {category: []}
+ if category.lower() == 'archetypes':
+ for archetype in self._content.archetypes:
+ _names[category].append(archetype.name)
+ elif category.lower() == 'equipments':
+ for equipment in self._content.equipments:
+ _names[category].append(equipment.name)
+ else:
+ raise ValueError(f'Unknown category [{category}]')
return _names
def entries(self, category=None):
"""
Get the catalog elements
- :parm: for energy systems catalog category filter does nothing as there is only one category (archetypes)
+ :parm: optional category filter
"""
- return self._content
+ if category is None:
+ return self._content
+ else:
+ if category.lower() == 'archetypes':
+ return self._content.archetypes
+ elif category.lower() == 'equipments':
+ return self._content.equipments
+ else:
+ raise ValueError(f'Unknown category [{category}]')
def get_entry(self, name):
"""
@@ -61,4 +138,7 @@ class MontrealCustomCatalog(Catalog):
for entry in self._content.archetypes:
if entry.name.lower() == name.lower():
return entry
+ for entry in self._content.equipments:
+ if entry.name.lower() == name.lower():
+ return entry
raise IndexError(f"{name} doesn't exists in the catalog")
diff --git a/hub/data/energy_systems/montreal_custom_systems.xml b/hub/data/energy_systems/montreal_custom_systems.xml
index a7f21025..65c03767 100644
--- a/hub/data/energy_systems/montreal_custom_systems.xml
+++ b/hub/data/energy_systems/montreal_custom_systems.xml
@@ -30,7 +30,7 @@
0.85
25
- NEEDED VALUE
+ 100000
false
@@ -41,7 +41,7 @@
1
25
- NEEDED VALUE
+ 100000
false
@@ -73,7 +73,7 @@
3.23
0
- NEEDED VALUE
+ 100000
false
@@ -93,7 +93,7 @@
3.23
0
- NEEDED VALUE
+ 100000
false
@@ -214,7 +214,7 @@
8
-
+
6
8
diff --git a/hub/unittests/test_systems_catalog.py b/hub/unittests/test_systems_catalog.py
new file mode 100644
index 00000000..da1f8d01
--- /dev/null
+++ b/hub/unittests/test_systems_catalog.py
@@ -0,0 +1,30 @@
+"""
+TestSystemsCatalog
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2022 Concordia CERC group
+Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
+"""
+
+from unittest import TestCase
+from hub.catalog_factories.energy_systems_catalog_factory import EnergySystemsCatalogFactory
+
+
+class TestSystemsCatalog(TestCase):
+
+ def test_montreal_custom_catalog(self):
+ catalog = EnergySystemsCatalogFactory('montreal_custom').catalog
+ catalog_categories = catalog.names()
+ archetypes = catalog.names('archetypes')
+ self.assertEqual(18, len(archetypes['archetypes']))
+ equipments = catalog.names('equipments')
+ self.assertEqual(10, len(equipments['equipments']))
+ with self.assertRaises(ValueError):
+ catalog.names('unknown')
+
+ # retrieving all the entries should not raise any exceptions
+ for category in catalog_categories:
+ for value in catalog_categories[category]:
+ catalog.get_entry(value)
+
+ with self.assertRaises(IndexError):
+ catalog.get_entry('unknown')