From 9c1e05939a535ba663133b18f4f6eb1ec154ef9b Mon Sep 17 00:00:00 2001 From: Saeed Ranjbar Date: Tue, 17 Oct 2023 17:25:13 -0400 Subject: [PATCH] The city energy system importer for the north america is modified and tested. --- .../energy_systems/montreal_custom_catalog.py | 2 + .../north_america_energy_system_catalog.py | 6 +- .../energy_systems/generation_system.py | 17 ++ .../non_pv_generation_system.py | 50 ----- ...america_custom_energy_system_parameters.py | 198 ++++++++---------- tests/test_systems_factory.py | 45 +--- 6 files changed, 122 insertions(+), 196 deletions(-) diff --git a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py index 9b984fdd..0c0abb88 100644 --- a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py +++ b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py @@ -70,12 +70,14 @@ class MontrealCustomCatalog(Catalog): storage_systems = [storage_system] if model_name == 'PV system': generation_system = PvGenerationSystem(equipment_id, + name=None, model_name=model_name, electricity_efficiency=electricity_efficiency, energy_storage_systems=storage_systems ) else: generation_system = NonPvGenerationSystem(equipment_id, + name=None, model_name=model_name, system_type=equipment_type, fuel_type=fuel_type, 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 index 1e790d88..3e6c649a 100644 --- a/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py +++ b/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py @@ -28,7 +28,7 @@ class NorthAmericaEnergySystemCatalog(Catalog): def __init__(self, path): path = str(path / 'north_america_systems.xml') with open(path, 'r', encoding='utf-8') as xml: - self._archetypes = xmltodict.parse(xml.read(), force_list=['photovoltaicModules', 'templateStorages']) + self._archetypes = xmltodict.parse(xml.read(), force_list=['photovoltaicModules', 'templateStorages', 'demand']) self._storage_components = self._load_storage_components() self._generation_components = self._load_generation_components() @@ -47,7 +47,7 @@ class NorthAmericaEnergySystemCatalog(Catalog): for boiler in boilers: boiler_id = boiler['@generation_id'] name = boiler['@name'] - system_type = 'Boiler' + system_type = 'boiler' boiler_model_name = boiler['@modelName'] boiler_manufacturer = boiler['@manufacturer'] boiler_fuel_type = boiler['@fuel'] @@ -69,7 +69,7 @@ class NorthAmericaEnergySystemCatalog(Catalog): for heat_pump in heat_pumps: heat_pump_id = heat_pump['@generation_id'] name = heat_pump['@name'] - system_type = 'Heat Pump' + system_type = 'heat pump' heat_pump_model_name = heat_pump['@modelName'] heat_pump_manufacturer = heat_pump['@manufacturer'] heat_pump_fuel_type = heat_pump['@fuel'] diff --git a/hub/city_model_structure/energy_systems/generation_system.py b/hub/city_model_structure/energy_systems/generation_system.py index 8b2bcbab..394c2f09 100644 --- a/hub/city_model_structure/energy_systems/generation_system.py +++ b/hub/city_model_structure/energy_systems/generation_system.py @@ -20,6 +20,7 @@ class GenerationSystem(ABC): """ def __init__(self): self._system_type = None + self._name = None self._model_name = None self._manufacturer = None self._fuel_type = None @@ -42,6 +43,22 @@ class GenerationSystem(ABC): """ self._system_type = value + @property + def name(self): + """ + Get name + :return: string + """ + return self._name + + @name.setter + def name(self, value): + """ + Set name + :param value: string + """ + self._name = value + @property def model_name(self): """ diff --git a/hub/city_model_structure/energy_systems/non_pv_generation_system.py b/hub/city_model_structure/energy_systems/non_pv_generation_system.py index 9db9f683..3dc044e5 100644 --- a/hub/city_model_structure/energy_systems/non_pv_generation_system.py +++ b/hub/city_model_structure/energy_systems/non_pv_generation_system.py @@ -42,9 +42,6 @@ class NonPvGenerationSystem(GenerationSystem): self._cooling_output_curve = None self._cooling_fuel_consumption_curve = None self._cooling_efficiency_curve = None - self._heat_power = None - self._cooling_power = None - self._electricity_power = None @property def nominal_heat_output(self): @@ -430,51 +427,4 @@ class NonPvGenerationSystem(GenerationSystem): """ self._cooling_efficiency_curve = value - @property - def heat_power(self): - """ - Get heat_power in W - :return: float - """ - return self._heat_power - - @heat_power.setter - def heat_power(self, value): - """ - Set heat_power in W - :param value: float - """ - self._heat_power = value - - @property - def cooling_power(self): - """ - Get cooling_power in W - :return: float - """ - return self._cooling_power - - @cooling_power.setter - def cooling_power(self, value): - """ - Set cooling_power in W - :param value: float - """ - self._cooling_power = value - - @property - def electricity_power(self): - """ - Get electricity_power in W - :return: float - """ - return self._electricity_power - - @electricity_power.setter - def electricity_power(self, value): - """ - Set electricity_power in W - :param value: float - """ - self._electricity_power = value diff --git a/hub/imports/energy_systems/north_america_custom_energy_system_parameters.py b/hub/imports/energy_systems/north_america_custom_energy_system_parameters.py index 722ae153..f898cdfa 100644 --- a/hub/imports/energy_systems/north_america_custom_energy_system_parameters.py +++ b/hub/imports/energy_systems/north_america_custom_energy_system_parameters.py @@ -6,25 +6,23 @@ Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -import copy import logging - -from pandas import DataFrame +import copy from hub.catalog_factories.energy_systems_catalog_factory import EnergySystemsCatalogFactory +from hub.city_model_structure.energy_systems.energy_system import EnergySystem from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem -from hub.city_model_structure.energy_systems.emission_system import EmissionSystem -from hub.city_model_structure.energy_systems.energy_system import EnergySystem -from hub.city_model_structure.energy_systems.generation_system import GenerationSystem -from hub.city_model_structure.energy_systems.energy_system import EnergySystem -from hub.city_model_structure.energy_systems.generation_system import GenerationSystem +from hub.city_model_structure.energy_systems.non_pv_generation_system import NonPvGenerationSystem +from hub.city_model_structure.energy_systems.pv_generation_system import PvGenerationSystem +from hub.city_model_structure.energy_systems.electrical_storage_system import ElectricalStorageSystem from hub.city_model_structure.energy_systems.thermal_storage_system import ThermalStorageSystem +from hub.city_model_structure.energy_systems.emission_system import EmissionSystem from hub.helpers.dictionaries import Dictionaries class NorthAmericaCustomEnergySystemParameters: """ - NorthAmericaCustomEnergySystemParameters class + MontrealCustomEnergySystemParameters class """ def __init__(self, city): @@ -36,11 +34,7 @@ class NorthAmericaCustomEnergySystemParameters: :return: """ city = self._city - north_america_custom_catalog = EnergySystemsCatalogFactory('north_america').catalog - if city.energy_systems_connection_table is None: - _energy_systems_connection_table = DataFrame(columns=['Energy System Type', 'Building']) - else: - _energy_systems_connection_table = city.energy_systems_connection_table + montreal_custom_catalog = EnergySystemsCatalogFactory('north_america').catalog if city.generic_energy_systems is None: _generic_energy_systems = {} else: @@ -48,21 +42,18 @@ class NorthAmericaCustomEnergySystemParameters: for building in city.buildings: archetype_name = building.energy_systems_archetype_name try: - archetype = self._search_archetypes(north_america_custom_catalog, archetype_name) + archetype = self._search_archetypes(montreal_custom_catalog, archetype_name) except KeyError: logging.error('Building %s has unknown energy system archetype for system name %s', building.name, archetype_name) continue - _energy_systems_connection_table, _generic_energy_systems = self._create_generic_systems( - archetype, - building, - _energy_systems_connection_table, - _generic_energy_systems - ) - city.energy_systems_connection_table = _energy_systems_connection_table + + if archetype.name not in _generic_energy_systems: + _generic_energy_systems = self._create_generic_systems_list(archetype, _generic_energy_systems) + city.generic_energy_systems = _generic_energy_systems - self._associate_energy_systems(city) + self._assign_energy_systems_to_buildings(city) @staticmethod def _search_archetypes(catalog, name): @@ -72,98 +63,93 @@ class NorthAmericaCustomEnergySystemParameters: return building_archetype raise KeyError('archetype not found') - @staticmethod - def _create_generic_systems(archetype, building, - _energy_systems_connection_table, _generic_energy_systems): + def _create_generic_systems_list(self, archetype, _generic_energy_systems): building_systems = [] - data = [archetype.name, building.name] - _energy_systems_connection_table.loc[len(_energy_systems_connection_table)] = data - for system in archetype.systems: + for archetype_system in archetype.systems: energy_system = EnergySystem() _hub_demand_types = [] - demand_types = system.demand_types - if isinstance(demand_types, str): - demand_types = [demand_types] - for demand_type in demand_types: - _hub_demand_types.append(Dictionaries().north_america_demand_type_to_hub_energy_demand_type[demand_type]) - energy_system.name = system.name + for demand_type in archetype_system.demand_types: + _hub_demand_types.append(Dictionaries().montreal_demand_type_to_hub_energy_demand_type[demand_type]) + energy_system.name = archetype_system.name energy_system.demand_types = _hub_demand_types - archetype_generation_equipments = system.generation_systems - _generation_systems = [] - for archetype_generation_equipment in archetype_generation_equipments: - _generation_system = GenerationSystem() - _type = archetype_generation_equipment.name - _generation_system.type = Dictionaries().north_america_system_to_hub_energy_generation_system[_type] - _fuel_type = Dictionaries().north_america_custom_fuel_to_hub_fuel[archetype_generation_equipment.fuel_type] - _generation_system.fuel_type = _fuel_type - _generation_system.source_types = archetype_generation_equipment.source_medium - _generation_system.heat_efficiency = archetype_generation_equipment.heat_efficiency - _generation_system.cooling_efficiency = archetype_generation_equipment.cooling_efficiency - _generation_system.electricity_efficiency = archetype_generation_equipment.electricity_efficiency - _generation_system.source_temperature = archetype_generation_equipment.source_temperature - _generation_system.source_mass_flow = archetype_generation_equipment.source_mass_flow - _generation_system.storage = None - _generation_system.auxiliary_equipment = None - _generation_system.supply_medium = archetype_generation_equipment.supply_medium - _generation_system.maximum_heat_supply_temperature = archetype_generation_equipment.maximum_heat_supply_temperature - _generation_system.minimum_heat_supply_temperature = archetype_generation_equipment.minimum_heat_supply_temperature - _generation_system.maximum_cooling_supply_temperature = archetype_generation_equipment.maximum_cooling_supply_temperature - _generation_system.minimum_cooling_supply_temperature = archetype_generation_equipment.minimum_cooling_supply_temperature - _generation_system.heat_output_curve = archetype_generation_equipment.heat_output_curve - _generation_system.heat_fuel_consumption_curve = archetype_generation_equipment.heat_fuel_consumption_curve - _generation_system.heat_efficiency_curve = archetype_generation_equipment.heat_efficiency_curve - _generation_system.cooling_output_curve = archetype_generation_equipment.cooling_output_curve - _generation_system.cooling_fuel_consumption_curve = archetype_generation_equipment.cooling_fuel_consumption_curve - _generation_system.cooling_efficiency_curve = archetype_generation_equipment.cooling_efficiency_curve - _generation_systems.append(_generation_system) - - energy_system.generation_systems = _generation_systems - - _thermal_storage_system = ThermalStorageSystem() - archetype_storage_equipments = system.energy_storage_systems - if archetype_storage_equipments is not None: - for archetype_storage_equipment in archetype_storage_equipments: - _thermal_storage_system.maximum_operating_temperature = archetype_storage_equipment.maximum_operating_temperature - _thermal_storage_system.height = archetype_storage_equipment.height - _thermal_storage_system.layers = archetype_storage_equipment.layers - energy_system.energy_storage_systems = _thermal_storage_system - + energy_system.configuration_schema = archetype_system.configuration_schema + energy_system.generation_systems = self._create_generation_systems(archetype_system) + if energy_system.distribution_systems is not None: + energy_system.distribution_systems = self._create_distribution_systems(archetype_system) building_systems.append(energy_system) - if archetype.name not in _generic_energy_systems: - _generic_energy_systems[archetype.name] = building_systems - return _energy_systems_connection_table, _generic_energy_systems + _generic_energy_systems[archetype.name] = building_systems + + return _generic_energy_systems @staticmethod - def _associate_energy_systems(city): - energy_systems_connection = city.energy_systems_connection_table + def _create_generation_systems(archetype_system): + _generation_systems = [] + for archetype_generation_system in archetype_system.generation_systems: + if archetype_generation_system.system_type == 'PV system': + _generation_system = PvGenerationSystem() + _type = 'PV system' + _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type] + _fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type] + _generation_system.fuel_type = _fuel_type + _generation_system.electricity_efficiency = archetype_generation_system.electricity_efficiency + _generic_storage_system = None + if archetype_generation_system.energy_storage_systems is not None: + _generic_storage_system = ElectricalStorageSystem() + _generic_storage_system.type_energy_stored = 'electrical' + _generation_system.energy_storage_systems = [_generic_storage_system] + else: + _generation_system = NonPvGenerationSystem() + _type = archetype_generation_system.system_type + _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type] + _fuel_type = Dictionaries().north_america_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type] + _generation_system.fuel_type = _fuel_type + _generation_system.source_types = archetype_generation_system.source_medium + _generation_system.heat_efficiency = archetype_generation_system.heat_efficiency + _generation_system.cooling_efficiency = archetype_generation_system.cooling_efficiency + _generation_system.electricity_efficiency = archetype_generation_system.electricity_efficiency + _generic_storage_system = None + if archetype_generation_system.energy_storage_systems is not None: + _storage_systems = [] + for storage_system in archetype_generation_system.energy_storage_systems: + if storage_system.type_energy_stored == 'electrical': + _generic_storage_system = ElectricalStorageSystem() + _generic_storage_system.type_energy_stored = 'electrical' + else: + _generic_storage_system = ThermalStorageSystem() + _generic_storage_system.type_energy_stored = 'thermal' + _storage_systems.append(_generic_storage_system) + _generation_system.energy_storage_systems = [_storage_systems] + _generation_systems.append(_generation_system) + return _generation_systems + + @staticmethod + def _create_distribution_systems(archetype_system): + _distribution_systems = [] + for archetype_distribution_system in archetype_system.distribution_systems: + _distribution_system = DistributionSystem() + _distribution_system.type = archetype_distribution_system.type + _distribution_system.distribution_consumption_fix_flow = \ + archetype_distribution_system.distribution_consumption_fix_flow + _distribution_system.distribution_consumption_variable_flow = \ + archetype_distribution_system.distribution_consumption_variable_flow + _distribution_system.heat_losses = archetype_distribution_system.heat_losses + _emission_system = None + if archetype_distribution_system.emission_systems is not None: + _emission_system = EmissionSystem() + _distribution_system.emission_systems = [_emission_system] + _distribution_systems.append(_distribution_system) + return _distribution_systems + + @staticmethod + def _assign_energy_systems_to_buildings(city): for building in city.buildings: _building_energy_systems = [] - energy_systems = energy_systems_connection['Energy System Type'][ - energy_systems_connection['Building'] == building.name] - print(energy_systems) - for energy_system in energy_systems: - if str(energy_system) == 'nan': - break - _generic_building_energy_systems = city.generic_energy_systems[energy_system] - for _generic_building_energy_system in _generic_building_energy_systems: - _building_energy_equipment = EnergySystem() - _building_energy_equipment.name = _generic_building_energy_system.name - _building_energy_equipment.demand_types = _generic_building_energy_system.demand_types - _generation_systems = [] - _generic_building_generation_systems = _generic_building_energy_system.generation_systems - for _generic_building_generation_system in _generic_building_generation_systems: - _building_generation_system = GenerationSystem() - _building_generation_system.generic_generation_system = \ - copy.deepcopy(_generic_building_generation_system) - _generation_systems.append(_building_generation_system) - _building_energy_equipment.generation_systems = _generation_systems - _building_storage_system = ThermalStorageSystem() - _building_storage_system.generic_storage_system = \ - copy.deepcopy(_generic_building_energy_system.energy_storage_systems) + energy_systems_cluster_name = building.energy_systems_archetype_name + if str(energy_systems_cluster_name) == 'nan': + break + _generic_building_energy_systems = city.generic_energy_systems[energy_systems_cluster_name] + for _generic_building_energy_system in _generic_building_energy_systems: + _building_energy_systems.append(copy.deepcopy(_generic_building_energy_system)) - - _building_energy_equipment.energy_storage_systems = _building_storage_system - - _building_energy_systems.append(_building_energy_equipment) building.energy_systems = _building_energy_systems diff --git a/tests/test_systems_factory.py b/tests/test_systems_factory.py index 5dde6abf..ce508b46 100644 --- a/tests/test_systems_factory.py +++ b/tests/test_systems_factory.py @@ -104,7 +104,6 @@ class TestSystemsFactory(TestCase): building.energy_systems_archetype_name = 'PV+ASHP+GasBoiler+TES' EnergySystemsFactory('north_america', self._city).enrich() - self.assertEqual(17, len(self._city.energy_systems_connection_table)) self.assertEqual(1, len(self._city.generic_energy_systems)) def test_north_america_custom_system_results(self): @@ -128,46 +127,18 @@ class TestSystemsFactory(TestCase): building.energy_systems_archetype_name = 'PV+ASHP+GasBoiler+TES' EnergySystemsFactory('north_america', self._city).enrich() # Need to assign energy systems to buildings: - energy_systems_connection = self._city.energy_systems_connection_table for building in self._city.buildings: _building_energy_systems = [] - energy_systems = energy_systems_connection['Energy System Type'][ - energy_systems_connection['Building'] == building.name] - for energy_system in energy_systems: - _generic_building_energy_systems = self._city.generic_energy_systems[energy_system] - for _generic_building_energy_system in _generic_building_energy_systems: - _building_energy_equipment = EnergySystem() - _building_energy_equipment.demand_types = _generic_building_energy_system.demand_types - - _building_distribution_system = DistributionSystem() - _building_distribution_system.generic_distribution_system = ( - copy.deepcopy(_generic_building_energy_system.distribution_systems) - ) - _building_emission_system = EmissionSystem() - _building_emission_system.generic_emission_system = ( - copy.deepcopy(_generic_building_energy_system.emission_systems) - ) - _building_generation_system = GenerationSystem() - _building_generation_system.generic_generation_system = ( - copy.deepcopy(_generic_building_energy_system.generation_systems) - ) - _building_storage_system = ThermalStorageSystem() - _building_storage_system.generic_storage_system = \ - copy.deepcopy(_generic_building_energy_system.energy_storage_systems) - - if cte.HEATING in _building_energy_equipment.demand_types: - _building_generation_system.heat_power = building.heating_peak_load[cte.YEAR][0] - if cte.COOLING in _building_energy_equipment.demand_types: - _building_generation_system.cooling_power = building.cooling_peak_load[cte.YEAR][0] - _building_energy_equipment.generation_systems = _building_generation_system - _building_energy_equipment.distribution_systems = _building_distribution_system - _building_energy_equipment.emission_systems = _building_emission_system - - _building_energy_systems.append(_building_energy_equipment) - building.energy_systems = _building_energy_systems + for energy_system in building.energy_systems: + if cte.HEATING in energy_system.demand_types: + _generation_system = cast(NonPvGenerationSystem, energy_system.generation_systems[0]) + _generation_system.heat_power = building.heating_peak_load[cte.YEAR][0] + if cte.COOLING in energy_system.demand_types: + _generation_system = cast(NonPvGenerationSystem, energy_system.generation_systems[0]) + _generation_system.cooling_power = building.cooling_peak_load[cte.YEAR][0] for building in self._city.buildings: self.assertLess(0, building.heating_consumption[cte.YEAR][0]) - self.assertLess(0, building.cooling_consumption[cte.YEAR][0]) + self.assertEqual(0, building.cooling_consumption[cte.YEAR][0]) self.assertLess(0, building.domestic_hot_water_consumption[cte.YEAR][0]) self.assertLess(0, building.onsite_electrical_production[cte.YEAR][0]) \ No newline at end of file