diff --git a/hub/city_model_structure/building.py b/hub/city_model_structure/building.py index 48bf7e6f..04c4703a 100644 --- a/hub/city_model_structure/building.py +++ b/hub/city_model_structure/building.py @@ -19,7 +19,7 @@ from hub.city_model_structure.city_object import CityObject from hub.city_model_structure.building_demand.household import Household from hub.city_model_structure.building_demand.internal_zone import InternalZone from hub.city_model_structure.attributes.polyhedron import Polyhedron -from hub.city_model_structure.energy_systems.generic_energy_system import GenericEnergySystem +from hub.city_model_structure.energy_systems.energy_system import EnergySystem class Building(CityObject): @@ -371,8 +371,6 @@ class Building(CityObject): :return: dict{DataFrame(float)} """ results = {} - # todo: needed?? - monthly_values = None if cte.HOUR in self.heating: monthly_values = PeakLoads().\ peak_loads_from_hourly(self.heating[cte.HOUR][next(iter(self.heating[cte.HOUR]))].values) @@ -501,10 +499,10 @@ class Building(CityObject): return _usage.rstrip() @property - def energy_systems(self) -> Union[None, List[GenericEnergySystem]]: + def energy_systems(self) -> Union[None, List[EnergySystem]]: """ Get list of energy systems installed to cover the building demands - :return: [GenericEnergySystem] + :return: [EnergySystem] """ return self._energy_systems @@ -512,7 +510,7 @@ class Building(CityObject): def energy_systems(self, value): """ Set list of energy systems installed to cover the building demands - :param value: [GenericEnergySystem] + :param value: [EnergySystem] """ self._energy_systems = value @@ -538,11 +536,12 @@ class Building(CityObject): Get energy consumption for heating according to the heating system installed return: dict """ - for heating_demand_key in self.heating: - demand = self.heating[heating_demand_key][cte.INSEL_MEB] - consumption_type = cte.HEATING - final_energy_consumed = self._calculate_consumption(consumption_type, demand) - self._heating_consumption[heating_demand_key] = final_energy_consumed + if len(self._heating_consumption) == 0: + for heating_demand_key in self.heating: + demand = self.heating[heating_demand_key][cte.INSEL_MEB] + consumption_type = cte.HEATING + final_energy_consumed = self._calculate_consumption(consumption_type, demand) + self._heating_consumption[heating_demand_key] = final_energy_consumed return self._heating_consumption @property @@ -551,11 +550,12 @@ class Building(CityObject): Get energy consumption for cooling according to the cooling system installed return: dict """ - for cooling_demand_key in self.cooling: - demand = self.cooling[cooling_demand_key][cte.INSEL_MEB] - consumption_type = cte.COOLING - final_energy_consumed = self._calculate_consumption(consumption_type, demand) - self._cooling_consumption[cooling_demand_key] = final_energy_consumed + if len(self._cooling_consumption) == 0: + for cooling_demand_key in self.cooling: + demand = self.cooling[cooling_demand_key][cte.INSEL_MEB] + consumption_type = cte.COOLING + final_energy_consumed = self._calculate_consumption(consumption_type, demand) + self._cooling_consumption[cooling_demand_key] = final_energy_consumed return self._cooling_consumption @property @@ -564,11 +564,12 @@ class Building(CityObject): Get energy consumption for domestic according to the domestic hot water system installed return: dict """ - for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand: - demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key][cte.INSEL_MEB] - consumption_type = cte.DOMESTIC_HOT_WATER - final_energy_consumed = self._calculate_consumption(consumption_type, demand) - self._domestic_hot_water_consumption[domestic_hot_water_demand_key] = final_energy_consumed + if len(self._domestic_hot_water_consumption) == 0: + for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand: + demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key][cte.INSEL_MEB] + consumption_type = cte.DOMESTIC_HOT_WATER + final_energy_consumed = self._calculate_consumption(consumption_type, demand) + self._domestic_hot_water_consumption[domestic_hot_water_demand_key] = final_energy_consumed return self._domestic_hot_water_consumption def _calculate_consumption(self, consumption_type, demand): @@ -578,15 +579,17 @@ class Building(CityObject): for demand_type in energy_system.demand_types: if demand_type.lower() == consumption_type.lower(): if consumption_type == cte.HEATING or consumption_type == cte.DOMESTIC_HOT_WATER: - coefficient_of_performance = energy_system.generation_system.heat_efficiency + coefficient_of_performance = energy_system.generation_system.generic_generation_system.heat_efficiency elif consumption_type == cte.COOLING: - coefficient_of_performance = energy_system.generation_system.cooling_efficiency + coefficient_of_performance = energy_system.generation_system.generic_generation_system.cooling_efficiency elif consumption_type == cte.ELECTRICITY: - coefficient_of_performance = energy_system.generation_system.electricity_efficiency - final_energy_consumed = [] + coefficient_of_performance = \ + energy_system.generation_system.generic_generation_system.electricity_efficiency if coefficient_of_performance == 0: - final_energy_consumed.append(0) + values = [0]*len(demand) + final_energy_consumed = values else: + final_energy_consumed = [] for demand_value in demand: final_energy_consumed.append(demand_value / coefficient_of_performance) return final_energy_consumed @@ -599,8 +602,8 @@ class Building(CityObject): """ # Add other systems whenever new ones appear for energy_system in self.energy_systems: - if energy_system.generation_system.type == cte.PHOTOVOLTAIC: - _efficiency = energy_system.generation_system.electricity_efficiency + if energy_system.generation_system.generic_generation_system.type == cte.PHOTOVOLTAIC: + _efficiency = energy_system.generation_system.generic_generation_system.electricity_efficiency self._onsite_electrical_production = {} for _key in self.roofs[0].global_irradiance.keys(): _results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key]))] diff --git a/hub/city_model_structure/city.py b/hub/city_model_structure/city.py index e8a34595..78d753a8 100644 --- a/hub/city_model_structure/city.py +++ b/hub/city_model_structure/city.py @@ -16,6 +16,7 @@ import pyproj from typing import List, Union from pyproj import Transformer from pathlib import Path +from pandas import DataFrame from hub.city_model_structure.building import Building from hub.city_model_structure.city_object import CityObject from hub.city_model_structure.city_objects_cluster import CityObjectsCluster @@ -61,6 +62,8 @@ class City: self._lca_materials = None self._level_of_detail = LevelOfDetail() self._city_objects_dictionary = {} + self._energy_systems_connection_table = None + self._generic_energy_systems = None @property def fuels(self) -> [Fuel]: @@ -490,4 +493,36 @@ class City: """ return self._level_of_detail + @property + def energy_systems_connection_table(self) -> Union[None, DataFrame]: + """ + Get energy systems connection table which includes at least two columns: energy_system_type and associated_building + and may also include dimensioned_energy_system and connection_building_to_dimensioned_energy_system + :return: DataFrame + """ + return self._energy_systems_connection_table + @energy_systems_connection_table.setter + def energy_systems_connection_table(self, value): + """ + Set energy systems connection table which includes at least two columns: energy_system_type and associated_building + and may also include dimensioned_energy_system and connection_building_to_dimensioned_energy_system + :param value: DataFrame + """ + self._energy_systems_connection_table = value + + @property + def generic_energy_systems(self) -> dict: + """ + Get dictionary with generic energy systems installed in the city + :return: dict + """ + return self._generic_energy_systems + + @generic_energy_systems.setter + def generic_energy_systems(self, value): + """ + Set dictionary with generic energy systems installed in the city + :return: dict + """ + self._generic_energy_systems = value diff --git a/hub/city_model_structure/energy_systems/control_system.py b/hub/city_model_structure/energy_systems/control_system.py new file mode 100644 index 00000000..0154a164 --- /dev/null +++ b/hub/city_model_structure/energy_systems/control_system.py @@ -0,0 +1,30 @@ +""" +Energy control system definition +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2023 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" + + +class ControlSystem: + """ + ControlSystem class + """ + def __init__(self): + self._control_type = None + + @property + def type(self): + """ + Get control type + :return: string + """ + return self._control_type + + @type.setter + def type(self, value): + """ + Set control type + :param value: string + """ + self._control_type = value diff --git a/hub/city_model_structure/energy_systems/distribution_system.py b/hub/city_model_structure/energy_systems/distribution_system.py new file mode 100644 index 00000000..a5a1d770 --- /dev/null +++ b/hub/city_model_structure/energy_systems/distribution_system.py @@ -0,0 +1,32 @@ +""" +Energy distribution system definition +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 hub.city_model_structure.energy_systems.generic_distribution_system import GenericDistributionSystem + + +class DistributionSystem: + """ + DistributionSystem class + """ + def __init__(self): + self._generic_distribution_system = None + + @property + def generic_distribution_system(self) -> GenericDistributionSystem: + """ + Get generic_distribution_system + :return: GenericDistributionSystem + """ + return self._generic_distribution_system + + @generic_distribution_system.setter + def generic_distribution_system(self, value): + """ + Set associated generic_distribution_system + :param value: GenericDistributionSystem + """ + self._generic_distribution_system = value diff --git a/hub/city_model_structure/energy_systems/emission_system.py b/hub/city_model_structure/energy_systems/emission_system.py new file mode 100644 index 00000000..a1fd9a30 --- /dev/null +++ b/hub/city_model_structure/energy_systems/emission_system.py @@ -0,0 +1,32 @@ +""" +Energy emission system definition +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 hub.city_model_structure.energy_systems.generic_emission_system import GenericEmissionSystem + + +class EmissionSystem: + """ + EmissionSystem class + """ + def __init__(self): + self._generic_emission_system = None + + @property + def generic_emission_system(self) -> GenericEmissionSystem: + """ + Get associated generic_emission_system + :return: GenericEmissionSystem + """ + return self._generic_emission_system + + @generic_emission_system.setter + def generic_emission_system(self, value): + """ + Set associated + :param value: GenericEmissionSystem + """ + self._generic_emission_system = value diff --git a/hub/city_model_structure/energy_systems/energy_system.py b/hub/city_model_structure/energy_systems/energy_system.py new file mode 100644 index 00000000..399566d7 --- /dev/null +++ b/hub/city_model_structure/energy_systems/energy_system.py @@ -0,0 +1,124 @@ +""" +Energy system definition +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, List + +from hub.city_model_structure.energy_systems.generic_energy_system import GenericEnergySystem +from hub.city_model_structure.energy_systems.generation_system import GenerationSystem +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.control_system import ControlSystem +from hub.city_model_structure.city_object import CityObject + + +class EnergySystem: + """ + EnergySystem class + """ + def __init__(self): + self._generic_energy_system = None + self._generation_system = None + self._distribution_system = None + self._emission_system = None + self._connected_city_objects = None + self._control_system = None + + @property + def generic_energy_system(self) -> GenericEnergySystem: + """ + Get associated generic_energy_system + :return: GenericEnergySystem + """ + return self._generic_energy_system + + @generic_energy_system.setter + def generic_energy_system(self, value): + """ + Set associated generic_energy_system + :param value: GenericEnergySystem + """ + self._generic_energy_system = value + + @property + def generation_system(self) -> GenerationSystem: + """ + Get generation system + :return: GenerationSystem + """ + return self._generation_system + + @generation_system.setter + def generation_system(self, value): + """ + Set generation system + :param value: GenerationSystem + """ + self._generation_system = value + + @property + def distribution_system(self) -> Union[None, DistributionSystem]: + """ + Get distribution system + :return: DistributionSystem + """ + return self._distribution_system + + @distribution_system.setter + def distribution_system(self, value): + """ + Set distribution system + :param value: DistributionSystem + """ + self._distribution_system = value + + @property + def emission_system(self) -> Union[None, EmissionSystem]: + """ + Get emission system + :return: EmissionSystem + """ + return self._emission_system + + @emission_system.setter + def emission_system(self, value): + """ + Set emission system + :param value: EmissionSystem + """ + self._emission_system = value + + @property + def connected_city_objects(self) -> Union[None, List[CityObject]]: + """ + Get list of city objects that are connected to this energy system + :return: List[CityObject] + """ + return self._connected_city_objects + + @connected_city_objects.setter + def connected_city_objects(self, value): + """ + Set list of city objects that are connected to this energy system + :param value: List[CityObject] + """ + self._connected_city_objects = value + + @property + def control_system(self) -> Union[None, ControlSystem]: + """ + Get control system of the energy system + :return: ControlSystem + """ + return self._control_system + + @control_system.setter + def control_system(self, value): + """ + Set control system of the energy system + :param value: ControlSystem + """ + self._control_system = value diff --git a/hub/city_model_structure/energy_systems/generation_system.py b/hub/city_model_structure/energy_systems/generation_system.py new file mode 100644 index 00000000..1561e370 --- /dev/null +++ b/hub/city_model_structure/energy_systems/generation_system.py @@ -0,0 +1,120 @@ +""" +Energy generation system definition +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 __future__ import annotations +from typing import Union + +from hub.city_model_structure.energy_systems.generic_generation_system import GenericGenerationSystem + + +class GenerationSystem: + """ + GenerationSystem class + """ + def __init__(self): + self._heat_power = None + self._cooling_power = None + self._electricity_power = None + self._storage_capacity = None + self._generic_generation_system = None + self._auxiliary_equipment = None + + @property + def generic_generation_system(self) -> GenericGenerationSystem: + """ + Get associated generic_generation_system + :return: GenericGenerationSystem + """ + return self._generic_generation_system + + @generic_generation_system.setter + def generic_generation_system(self, value): + """ + Set associated generic_generation_system + :param value: GenericGenerationSystem + """ + self._generic_generation_system = 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 + + @property + def storage_capacity(self): + """ + Get storage_capacity in J + :return: float + """ + return self._storage_capacity + + @storage_capacity.setter + def storage_capacity(self, value): + """ + Set storage_capacity in J + :param value: float + """ + self._storage_capacity = value + + @property + def auxiliary_equipment(self) -> Union[None, GenerationSystem]: + """ + Get auxiliary_equipment + :return: GenerationSystem + """ + return self._auxiliary_equipment + + @auxiliary_equipment.setter + def auxiliary_equipment(self, value): + """ + Set auxiliary_equipment + :param value: GenerationSystem + """ + self._auxiliary_equipment = value diff --git a/hub/city_model_structure/energy_systems/generic_energy_system.py b/hub/city_model_structure/energy_systems/generic_energy_system.py index 350e3f0d..da108a09 100644 --- a/hub/city_model_structure/energy_systems/generic_energy_system.py +++ b/hub/city_model_structure/energy_systems/generic_energy_system.py @@ -18,12 +18,29 @@ class GenericEnergySystem: GenericEnergySystem class """ def __init__(self): + self._name = None self._demand_types = None self._generation_system = None self._distribution_system = None self._emission_system = None self._connected_city_objects = None + @property + def name(self): + """ + Get energy system name + :return: str + """ + return self._name + + @name.setter + def name(self, value): + """ + Set energy system name + :param value: + """ + self._name = value + @property def demand_types(self): """ @@ -46,9 +63,16 @@ class GenericEnergySystem: Get generation system :return: GenerationSystem """ - self._generation_system = GenericGenerationSystem(self.connected_city_objects) return self._generation_system + @generation_system.setter + def generation_system(self, value): + """ + Set generation system + :return: GenerationSystem + """ + self._generation_system = value + @property def distribution_system(self) -> Union[None, GenericDistributionSystem]: """ @@ -80,19 +104,3 @@ class GenericEnergySystem: :param value: EmissionSystem """ self._emission_system = value - - @property - def connected_city_objects(self) -> Union[None, List[CityObject]]: - """ - Get list of city objects that are connected to this energy system - :return: List[CityObject] - """ - return self._connected_city_objects - - @connected_city_objects.setter - def connected_city_objects(self, value): - """ - Set list of city objects that are connected to this energy system - :param value: List[CityObject] - """ - self._connected_city_objects = value diff --git a/hub/city_model_structure/energy_systems/generic_generation_system.py b/hub/city_model_structure/energy_systems/generic_generation_system.py index 1d19ea5c..28094571 100644 --- a/hub/city_model_structure/energy_systems/generic_generation_system.py +++ b/hub/city_model_structure/energy_systems/generic_generation_system.py @@ -8,30 +8,22 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca from __future__ import annotations from typing import Union -import hub.helpers.constants as cte - class GenericGenerationSystem: """ GenericGenerationSystem class """ - def __init__(self, city_objects=None, heat_power=None, cooling_power=None, electricity_power=None): - self._city_objects = city_objects + def __init__(self): self._type = None self._fuel_type = None - self._heat_power = heat_power - self._cooling_power = cooling_power - self._electricity_power = electricity_power self._source_types = None self._heat_efficiency = None self._cooling_efficiency = None self._electricity_efficiency = None self._source_temperature = None self._source_mass_flow = None - self._storage_capacity = None self._storage = None self._auxiliary_equipment = None - self._peak_coverages = None @property def type(self): @@ -81,52 +73,6 @@ class GenericGenerationSystem: """ self._source_types = value - @property - def heat_power(self): - """ - Get heat_power in W - :return: float - """ - if self._heat_power is None: - self._heat_power = 0 - for city_object in self._city_objects: - if city_object.heating_peak_load is not None: - if self.peak_coverages[cte.HEATING] is None: - return None - self._heat_power += city_object.heating_peak_load[cte.YEAR][0] * self.peak_coverages[cte.HEATING] - return self._heat_power - - @property - def cooling_power(self): - """ - Get cooling_power in W - :return: float - """ - if self._cooling_power is None: - self._cooling_power = 0 - for city_object in self._city_objects: - if city_object.cooling_peak_load is not None: - if self.peak_coverages[cte.COOLING] is None: - return None - self._cooling_power += city_object.cooling_peak_load[cte.YEAR][0] * self.peak_coverages[cte.COOLING] - return self._cooling_power - - @property - def electricity_power(self): - """ - Get electricity_power in W - :return: float - """ - if self._electricity_power is None: - self._electricity_power = 0 - for city_object in self._city_objects: - if city_object.electricity_peak_load is not None: - if self.peak_coverages[cte.ELECTRICITY] is None: - return None - self._electricity_power += city_object.electricity_peak_load[cte.YEAR][0]\ - * self.peak_coverages[cte.ELECTRICITY] - return self._electricity_power - @property def heat_efficiency(self): """ @@ -207,14 +153,6 @@ class GenericGenerationSystem: """ self._source_mass_flow = value - @property - def storage_capacity(self): - """ - Get storage_capacity in J - :return: float - """ - return self._storage_capacity - @property def storage(self): """ @@ -239,18 +177,10 @@ class GenericGenerationSystem: """ return self._auxiliary_equipment - @property - def peak_coverages(self) -> dict: + @auxiliary_equipment.setter + def auxiliary_equipment(self, value): """ - Get ratio of each energy type power peak covered by the system - :return: dict {Heating: value, Cooling: value, Domestic Hot Water: value, Electricity: value} + Set auxiliary_equipment + :return: GenerationSystem """ - return self._peak_coverages - - @peak_coverages.setter - def peak_coverages(self, value): - """ - Set ratio of each energy type power peak covered by the system - :param value: dict - """ - self._peak_coverages = value + self._auxiliary_equipment = value diff --git a/hub/helpers/peak_loads.py b/hub/helpers/peak_loads.py index a9bcf58f..9bfb00d6 100644 --- a/hub/helpers/peak_loads.py +++ b/hub/helpers/peak_loads.py @@ -6,10 +6,8 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributors: Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ -import sys import math -from hub.hub_logger import logger import hub.helpers.constants as cte from hub.helpers.peak_calculation.loads_calculation import LoadsCalculation @@ -61,7 +59,7 @@ class PeakLoads: @property def heating_peak_loads_from_methodology(self): - if self._can_be_calculated(): + if not self._can_be_calculated(): return None monthly_heating_loads = [] ambient_temperature = self._building.external_temperature[cte.HOUR]['epw'] @@ -88,7 +86,7 @@ class PeakLoads: @property def cooling_peak_loads_from_methodology(self): - if self._can_be_calculated(): + if not self._can_be_calculated(): return None monthly_cooling_loads = [] ambient_temperature = self._building.external_temperature[cte.HOUR]['epw'] diff --git a/hub/hub_logger/__init__.py b/hub/hub_logger/__init__.py index 1c7c5f04..d1d11d35 100644 --- a/hub/hub_logger/__init__.py +++ b/hub/hub_logger/__init__.py @@ -1,7 +1,6 @@ import logging as logger from pathlib import Path import os -import logging import sys @@ -27,7 +26,6 @@ def get_logger(file_logger=False): except IOError as err: print(f'I/O exception: {err}') else: - logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout)) - logging.getLogger().setLevel(logging.DEBUG) + logger.getLogger().addHandler(logger.StreamHandler(stream=sys.stdout)) + logger.getLogger().setLevel(logger.DEBUG) return logger.getLogger() - diff --git a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py index 11bfe59f..79772efc 100644 --- a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py +++ b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py @@ -6,6 +6,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ import sys +from pandas import DataFrame from hub.hub_logger import logger from hub.catalog_factories.energy_systems_catalog_factory import EnergySystemsCatalogFactory @@ -13,7 +14,6 @@ from hub.city_model_structure.energy_systems.generic_energy_system import Generi from hub.city_model_structure.energy_systems.generic_generation_system import GenericGenerationSystem from hub.city_model_structure.energy_systems.generic_distribution_system import GenericDistributionSystem from hub.helpers.dictionaries import Dictionaries -import hub.helpers.constants as cte class MontrealCustomEnergySystemParameters: @@ -31,25 +31,34 @@ class MontrealCustomEnergySystemParameters: """ city = self._city montreal_custom_catalog = EnergySystemsCatalogFactory('montreal_custom').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 + if city.generic_energy_systems is None: + _generic_energy_systems = {} + else: + _generic_energy_systems = city.generic_energy_systems for building in city.buildings: archetype_name = f'{building.energy_systems_archetype_name}_lod1.0' # archetype_name = building.energy_systems_archetype_name try: - print(archetype_name) archetype = self._search_archetypes(montreal_custom_catalog, archetype_name) except KeyError: - print('ERROR') logger.error(f'Building {building.name} has unknown energy system archetype for system name: {archetype_name}') sys.stderr.write(f'Building {building.name} has unknown energy system archetype ' f'for system name: {archetype_name}') - print('END ERROR') continue + building_systems = [] + data = [archetype_name, building.name] + _energy_systems_connection_table.loc[len(_energy_systems_connection_table)] = data for equipment in archetype.equipments: energy_system = GenericEnergySystem() _hub_demand_types = [] for demand_type in equipment.demand_types: _hub_demand_types.append(Dictionaries().montreal_demand_type_to_hub_energy_demand_type[demand_type]) + energy_system.name = archetype_name energy_system.demand_types = _hub_demand_types _generation_system = GenericGenerationSystem() archetype_generation_equipment = equipment.generation_system @@ -63,11 +72,6 @@ class MontrealCustomEnergySystemParameters: _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 - # dhw peak does not add anything to the total heat peak - _generation_system.peak_coverages = {cte.HEATING: 1, - cte.COOLING: 1, - cte.DOMESTIC_HOT_WATER: 0, - cte.ELECTRICITY: 0} _generation_system.storage = archetype_generation_equipment.storage _generation_system.auxiliary_equipment = None @@ -83,7 +87,11 @@ class MontrealCustomEnergySystemParameters: energy_system.distribution_system = _distribution_system building_systems.append(energy_system) - building.energy_systems = building_systems + if archetype_name not in _generic_energy_systems: + _generic_energy_systems[archetype_name] = building_systems + + city.energy_systems_connection_table = _energy_systems_connection_table + city.generic_energy_systems = _generic_energy_systems @staticmethod def _search_archetypes(catalog, name): diff --git a/hub/unittests/test_systems_factory.py b/hub/unittests/test_systems_factory.py index 318bba7f..4d53fa89 100644 --- a/hub/unittests/test_systems_factory.py +++ b/hub/unittests/test_systems_factory.py @@ -8,6 +8,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca import subprocess from pathlib import Path from unittest import TestCase +import copy import hub.helpers.constants as cte from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory @@ -18,6 +19,10 @@ from hub.imports.geometry_factory import GeometryFactory from hub.imports.results_factory import ResultFactory from hub.imports.usage_factory import UsageFactory from hub.imports.energy_systems_factory import EnergySystemsFactory +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.distribution_system import DistributionSystem +from hub.city_model_structure.energy_systems.emission_system import EmissionSystem class TestSystemsFactory(TestCase): @@ -44,9 +49,7 @@ class TestSystemsFactory(TestCase): building.energy_systems_archetype_name = 'system 1 gas' EnergySystemsFactory('montreal_custom', self._city).enrich() - for building in self._city.buildings: - self.assertEqual(2, len(building.energy_systems[0].demand_types)) - self.assertEqual(1, len(building.energy_systems[1].demand_types)) + self.assertEqual(1, len(self._city.energy_systems_connection_table)) def test_montreal_custom_system_results(self): """ @@ -64,10 +67,42 @@ class TestSystemsFactory(TestCase): insel_path = (self._output_path / f'{building.name}.insel') subprocess.run(['insel', str(insel_path)]) ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich() + self._city.save(self._output_path / 'city.pickle') for building in self._city.buildings: building.energy_systems_archetype_name = 'system 1 gas' EnergySystemsFactory('montreal_custom', 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']\ + .where(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_system) + _building_emission_system = EmissionSystem() + _building_emission_system.generic_emission_system = \ + copy.deepcopy(_generic_building_energy_system.emission_system) + _building_generation_system = GenerationSystem() + _building_generation_system.generic_generation_system = \ + copy.deepcopy(_generic_building_energy_system.generation_system) + if cte.HEATING in _building_energy_equipment.demand_types: + _building_generation_system.heat_power = building.heating_peak_load[cte.YEAR]['heating peak loads'][0] + if cte.COOLING in _building_energy_equipment.demand_types: + _building_generation_system.cooling_power = building.cooling_peak_load[cte.YEAR]['cooling peak loads'][0] + _building_energy_equipment.generation_system = _building_generation_system + _building_energy_equipment.distribution_system = _building_distribution_system + _building_energy_equipment.emission_system = _building_emission_system + + _building_energy_systems.append(_building_energy_equipment) + building.energy_systems = _building_energy_systems for building in self._city.buildings: self.assertLess(0, building.heating_consumption[cte.YEAR][0])