finished system catalog factory

This commit is contained in:
Pilar Monsalvete 2023-04-28 14:07:07 -04:00
parent 0a96b83c22
commit 3bfb985c04
7 changed files with 246 additions and 76 deletions

View File

@ -5,28 +5,17 @@ Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca 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.equipment import Equipment
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 Archetype: class Archetype:
def __init__(self, def __init__(self, lod, name, equipments):
lod,
name,
demand_types,
generation_system,
distribution_system,
emission_system):
self._lod = lod self._lod = lod
self._name = name self._name = name
self._demand_types = demand_types self._equipments = equipments
self._generation_system = generation_system
self._distribution_system = distribution_system
self._emission_system = emission_system
@property @property
def lod(self): def lod(self):
@ -45,33 +34,9 @@ class Archetype:
return f'{self._name}_lod{self._lod}' return f'{self._name}_lod{self._lod}'
@property @property
def demand_types(self): def equipments(self) -> List[Equipment]:
""" """
Get demand able to cover from [heating, cooling, domestic_hot_water, electricity] Get list of equipments that compose the total energy system
:return: [string] :return: [Equipment]
""" """
return self._demand_types return self._equipments
@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

View File

@ -7,12 +7,20 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
class Content: class Content:
def __init__(self, archetypes): def __init__(self, archetypes, equipments):
self._archetypes = archetypes self._archetypes = archetypes
self._equipments = equipments
@property @property
def archetypes(self): def archetypes(self):
""" """
All archetypes in the catalog All archetype systems in the catalog
""" """
return self._archetypes return self._archetypes
@property
def equipments(self):
"""
All equipments in the catalog
"""
return self._equipments

View File

@ -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

View File

@ -11,7 +11,7 @@ from typing import Union
class GenerationSystem: class GenerationSystem:
def __init__(self, system_type, fuel_type, source_types, heat_efficiency, cooling_efficiency, electricity_efficiency, 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._type = system_type
self._fuel_type = fuel_type self._fuel_type = fuel_type
@ -21,7 +21,7 @@ class GenerationSystem:
self._electricity_efficiency = electricity_efficiency self._electricity_efficiency = electricity_efficiency
self._source_temperature = source_temperature self._source_temperature = source_temperature
self._source_mass_flow = source_mass_flow self._source_mass_flow = source_mass_flow
self._storage_capacity = storage_capacity self._storage = storage
self._auxiliary_equipment = auxiliary_equipment self._auxiliary_equipment = auxiliary_equipment
@property @property
@ -89,12 +89,12 @@ class GenerationSystem:
return self._source_mass_flow return self._source_mass_flow
@property @property
def storage_capacity(self): def storage(self):
""" """
Get storage_capacity in J Get boolean storage exists
:return: float :return: bool
""" """
return self._storage_capacity return self._storage
@property @property
def auxiliary_equipment(self) -> Union[None, GenerationSystem]: def auxiliary_equipment(self) -> Union[None, GenerationSystem]:

View File

@ -8,50 +8,127 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import xmltodict import xmltodict
from hub.catalog_factories.catalog import Catalog 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.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): class MontrealCustomCatalog(Catalog):
def __init__(self, path): def __init__(self, path):
path = str(path / 'montreal_custom_systems.xml') path = str(path / 'montreal_custom_systems.xml')
with open(path) as 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 # 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): def _load_archetypes(self):
_catalog_archetypes = [] _catalog_archetypes = []
archetypes = self._archetypes['archetypes']['archetype'] systems = self._archetypes['catalog']['systems']['system']
for archetype in archetypes: for system in systems:
name = archetype['@name'] name = system['@name']
lod = float(archetype['@lod']) system_equipments = system['equipments']['equipment_id']
demand_types = archetype['@demands'] _equipments = []
_catalog_archetypes.append(Archetype(lod, for system_equipment in system_equipments:
name, for equipment in self._catalog_equipments:
demand_types, if int(equipment.id) == int(system_equipment):
generation_system, _equipments.append(equipment)
distribution_system, _catalog_archetypes.append(Archetype(self._lod, name, _equipments))
emission_system))
return _catalog_archetypes return _catalog_archetypes
def names(self, category=None): def names(self, category=None):
""" """
Get the catalog elements names 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': []} if category is None:
_names = {'archetypes': [], 'equipments': []}
for archetype in self._content.archetypes: for archetype in self._content.archetypes:
_names['archetypes'].append(archetype.name) _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 return _names
def entries(self, category=None): def entries(self, category=None):
""" """
Get the catalog elements Get the catalog elements
:parm: for energy systems catalog category filter does nothing as there is only one category (archetypes) :parm: optional category filter
""" """
if category is None:
return self._content 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): def get_entry(self, name):
""" """
@ -61,4 +138,7 @@ class MontrealCustomCatalog(Catalog):
for entry in self._content.archetypes: for entry in self._content.archetypes:
if entry.name.lower() == name.lower(): if entry.name.lower() == name.lower():
return entry 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") raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -30,7 +30,7 @@
</demands> </demands>
<heating_efficiency>0.85</heating_efficiency> <heating_efficiency>0.85</heating_efficiency>
<distribution_heat_losses units="%">25</distribution_heat_losses> <distribution_heat_losses units="%">25</distribution_heat_losses>
<distribution_consumption units="%">NEEDED VALUE</distribution_consumption> <distribution_consumption units="%">100000</distribution_consumption>
<storage>false</storage> <storage>false</storage>
</equipment> </equipment>
<equipment id="4" type="furnace" fuel_type="electricity"> <equipment id="4" type="furnace" fuel_type="electricity">
@ -41,7 +41,7 @@
</demands> </demands>
<heating_efficiency>1</heating_efficiency> <heating_efficiency>1</heating_efficiency>
<distribution_heat_losses units="%">25</distribution_heat_losses> <distribution_heat_losses units="%">25</distribution_heat_losses>
<distribution_consumption units="%">NEEDED VALUE</distribution_consumption> <distribution_consumption units="%">100000</distribution_consumption>
<storage>false</storage> <storage>false</storage>
</equipment> </equipment>
<equipment id="5" type="baseboard" fuel_type="gas"> <equipment id="5" type="baseboard" fuel_type="gas">
@ -73,7 +73,7 @@
</demands> </demands>
<cooling_efficiency>3.23</cooling_efficiency> <cooling_efficiency>3.23</cooling_efficiency>
<distribution_heat_losses units="%">0</distribution_heat_losses> <distribution_heat_losses units="%">0</distribution_heat_losses>
<distribution_consumption units="%">NEEDED VALUE</distribution_consumption> <distribution_consumption units="%">100000</distribution_consumption>
<storage>false</storage> <storage>false</storage>
</equipment> </equipment>
<equipment id="8" type="cooler" fuel_type="electricity"> <equipment id="8" type="cooler" fuel_type="electricity">
@ -93,7 +93,7 @@
</demands> </demands>
<cooling_efficiency>3.23</cooling_efficiency> <cooling_efficiency>3.23</cooling_efficiency>
<distribution_heat_losses units="%">0</distribution_heat_losses> <distribution_heat_losses units="%">0</distribution_heat_losses>
<distribution_consumption units="%">NEEDED VALUE</distribution_consumption> <distribution_consumption units="%">100000</distribution_consumption>
<storage>false</storage> <storage>false</storage>
</equipment> </equipment>
<equipment id="10" type="electricity generator" fuel_type="renewable"> <equipment id="10" type="electricity generator" fuel_type="renewable">
@ -214,7 +214,7 @@
<equipment_id>8</equipment_id> <equipment_id>8</equipment_id>
</equipments> </equipments>
</system> </system>
<system name="system 6] electricity pv"> <system name="system 6 electricity pv">
<equipments> <equipments>
<equipment_id>6</equipment_id> <equipment_id>6</equipment_id>
<equipment_id>8</equipment_id> <equipment_id>8</equipment_id>

View File

@ -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')