diff --git a/.gitignore b/.gitignore index e23b0042..723ef36f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1 @@ -!.gitignore -**/venv/ -.idea/ -/development_tests/ -/data/energy_systems/heat_pumps/*.csv -/data/energy_systems/heat_pumps/*.insel -.DS_Store -**/.env -**/hub/logs/ -**/__pycache__/ -**/.idea/ - +.idea \ No newline at end of file diff --git a/hub/catalog_factories/data_models/energy_systems/archetype.py b/hub/catalog_factories/data_models/energy_systems/archetype.py index 86bfb68d..7f43c5dc 100644 --- a/hub/catalog_factories/data_models/energy_systems/archetype.py +++ b/hub/catalog_factories/data_models/energy_systems/archetype.py @@ -3,6 +3,7 @@ Energy System catalog archetype SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2023 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca """ from typing import List @@ -55,3 +56,5 @@ class Archetype: } } return content + + 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/data_models/energy_systems/distribution_system.py b/hub/catalog_factories/data_models/energy_systems/distribution_system.py index e24ba64c..cac9b2b3 100644 --- a/hub/catalog_factories/data_models/energy_systems/distribution_system.py +++ b/hub/catalog_factories/data_models/energy_systems/distribution_system.py @@ -3,6 +3,7 @@ Energy System catalog distribution system SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2023 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca """ diff --git a/hub/catalog_factories/data_models/energy_systems/electrical_storage_system.py b/hub/catalog_factories/data_models/energy_systems/electrical_storage_system.py new file mode 100644 index 00000000..6f5d6d14 --- /dev/null +++ b/hub/catalog_factories/data_models/energy_systems/electrical_storage_system.py @@ -0,0 +1,93 @@ +""" +Energy System catalog electrical storage system +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2023 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca +""" + +from hub.catalog_factories.data_models.energy_systems.energy_storage_system import EnergyStorageSystem + + +class ElectricalStorageSystem(EnergyStorageSystem): + """" + Energy Storage System Class + """ + + def __init__(self, storage_id, name, model_name, manufacturer, storage_type, nominal_capacity, losses_ratio, + rated_output_power, nominal_efficiency, battery_voltage, depth_of_discharge, self_discharge_rate): + + super().__init__(storage_id, name, model_name, manufacturer, nominal_capacity, losses_ratio) + self._storage_type = storage_type + self._rated_output_power = rated_output_power + self._nominal_efficiency = nominal_efficiency + self._battery_voltage = battery_voltage + self._depth_of_discharge = depth_of_discharge + self._self_discharge_rate = self_discharge_rate + + @property + def storage_type(self): + """ + Get storage type from ['electrical', 'lithium_ion', 'lead_acid', 'NiCd'] + :return: string + """ + return self._storage_type + + @property + def rated_output_power(self): + """ + Get the rated output power of storage system in Watts + :return: float + """ + return self._rated_output_power + + @property + def nominal_efficiency(self): + """ + Get the nominal efficiency of the storage system + :return: float + """ + return self._nominal_efficiency + + @property + def battery_voltage(self): + """ + Get the battery voltage in Volts + :return: float + """ + return self._battery_voltage + + @property + def depth_of_discharge(self): + """ + Get the depth of discharge as a percentage + :return: float + """ + return self._depth_of_discharge + + @property + def self_discharge_rate(self): + """ + Get the self discharge rate of battery as a percentage + :return: float + """ + return self._self_discharge_rate + + def to_dictionary(self): + """Class content to dictionary""" + content = {'Storage component': { + 'storage id': self.id, + 'name': self.name, + 'model name': self.model_name, + 'manufacturer': self.manufacturer, + 'storage type': self.storage_type, + 'nominal capacity [J]': self.nominal_capacity, + 'losses-ratio [J/J]': self.losses_ratio, + 'rated power [W]': self.rated_output_power, + 'nominal efficiency': self.nominal_efficiency, + 'battery voltage [V]': self.battery_voltage, + 'depth of discharge [%]': self.depth_of_discharge, + 'self discharge rate': self.self_discharge_rate + } + } + return content diff --git a/hub/catalog_factories/data_models/energy_systems/energy_storage_system.py b/hub/catalog_factories/data_models/energy_systems/energy_storage_system.py new file mode 100644 index 00000000..a5302cb4 --- /dev/null +++ b/hub/catalog_factories/data_models/energy_systems/energy_storage_system.py @@ -0,0 +1,75 @@ +""" +Energy System catalog heat generation system +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2023 Concordia CERC group +Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca +Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" + +from abc import ABC + + +class EnergyStorageSystem(ABC): + """" + Energy Storage System Abstract Class + """ + + def __init__(self, storage_id, name, model_name, manufacturer, nominal_capacity, losses_ratio): + self._storage_id = storage_id + self._name = name + self._model_name = model_name + self._manufacturer = manufacturer + self._nominal_capacity = nominal_capacity + self._losses_ratio = losses_ratio + + @property + def id(self): + """ + Get storage id + :return: string + """ + return self._storage_id + + @property + def name(self): + """ + Get storage name + :return: string + """ + return self._name + + @property + def model_name(self): + """ + Get system model + :return: float + """ + return self._model_name + + @property + def manufacturer(self): + """ + Get name of manufacturer + :return: string + """ + return self._manufacturer + + @property + def nominal_capacity(self): + """ + Get the nominal capacity of the storage system in Jules + :return: float + """ + return self._nominal_capacity + + @property + def losses_ratio(self): + """ + Get the losses-ratio of storage system in Jules lost / Jules stored + :return: float + """ + return self._losses_ratio + + def to_dictionary(self): + """Class content to dictionary""" + raise NotImplementedError 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 1728540f..c2fd9a75 100644 --- a/hub/catalog_factories/data_models/energy_systems/generation_system.py +++ b/hub/catalog_factories/data_models/energy_systems/generation_system.py @@ -1,33 +1,58 @@ """ -Energy System catalog generation system +Energy System catalog heat generation system SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2023 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca """ -from __future__ import annotations from typing import Union +from hub.catalog_factories.data_models.energy_systems.performance_curves import PerformanceCurves class GenerationSystem: """ - Generation system class + Heat Generation system class """ - def __init__(self, system_id, name, system_type, fuel_type, source_types, heat_efficiency, cooling_efficiency, - electricity_efficiency, source_temperature, source_mass_flow, storage, auxiliary_equipment): + def __init__(self, system_id, name, model_name, manufacturer, system_type, fuel_type, nominal_thermal_output, + maximum_heat_output, minimum_heat_output, source_medium, supply_medium, heat_efficiency, + nominal_cooling_output, maximum_cooling_output, minimum_cooling_output, cooling_efficiency, + electricity_efficiency, source_temperature, source_mass_flow, nominal_electricity_output, + maximum_heat_supply_temperature, minimum_heat_supply_temperature, + maximum_cooling_supply_temperature, minimum_cooling_supply_temperature, heat_output_curve, + heat_fuel_consumption_curve, heat_efficiency_curve, cooling_output_curve, cooling_fuel_consumption_curve, + cooling_efficiency_curve): self._system_id = system_id self._name = name - self._type = system_type + self._model_name = model_name + self._manufacturer = manufacturer + self._system_type = system_type self._fuel_type = fuel_type - self._source_types = source_types + self._nominal_thermal_output = nominal_thermal_output + self._maximum_heat_output = maximum_heat_output + self._minimum_heat_output = minimum_heat_output self._heat_efficiency = heat_efficiency + self._nominal_cooling_output = nominal_cooling_output + self._maximum_cooling_output = maximum_cooling_output + self._minimum_cooling_output = minimum_cooling_output self._cooling_efficiency = cooling_efficiency self._electricity_efficiency = electricity_efficiency + self._nominal_electricity_output = nominal_electricity_output + self._source_medium = source_medium self._source_temperature = source_temperature self._source_mass_flow = source_mass_flow - self._storage = storage - self._auxiliary_equipment = auxiliary_equipment + self._supply_medium = supply_medium + self._maximum_heat_supply_temperature = maximum_heat_supply_temperature + self._minimum_heat_supply_temperature = minimum_heat_supply_temperature + self._maximum_cooling_supply_temperature = maximum_cooling_supply_temperature + self._minimum_cooling_supply_temperature = minimum_cooling_supply_temperature + self._heat_output_curve = heat_output_curve + self._heat_fuel_consumption_curve = heat_fuel_consumption_curve + self._heat_efficiency_curve = heat_efficiency_curve + self._cooling_output_curve = cooling_output_curve + self._cooling_fuel_consumption_curve = cooling_fuel_consumption_curve + self._cooling_efficiency_curve = cooling_efficiency_curve @property def id(self): @@ -46,28 +71,76 @@ class GenerationSystem: return self._name @property - def type(self): + def model_name(self): + """ + Get system id + :return: float + """ + return self._model_name + + @property + def manufacturer(self): + """ + Get name + :return: string + """ + return self._manufacturer + + @property + def system_type(self): """ Get type :return: string """ - return self._type + return self._system_type @property def fuel_type(self): """ - Get fuel_type from [renewable, gas, diesel, electricity, wood, coal] + Get fuel_type from [renewable, gas, diesel, electricity, wood, coal, biogas] :return: string """ return self._fuel_type @property - def source_types(self): + def nominal_thermal_output(self): """ - Get source_type from [air, water, geothermal, district_heating, grid, on_site_electricity] + Get nominal_thermal_output of heat generation devices in kW + :return: float + """ + return self._nominal_thermal_output + + @property + def maximum_heat_output(self): + """ + Get maximum heat output of heat generation devices in W + :return: float + """ + return self._maximum_heat_output + + @property + def minimum_heat_output(self): + """ + Get minimum heat output of heat generation devices in W + :return: float + """ + return self._minimum_heat_output + + @property + def source_medium(self): + """ + Get source_type from [air, water, ground, district_heating, grid, on_site_electricity] :return: [string] """ - return self._source_types + return self._source_medium + + @property + def supply_medium(self): + """ + Get the supply medium from ['air', 'water'] + :return: string + """ + return self._supply_medium @property def heat_efficiency(self): @@ -77,6 +150,30 @@ class GenerationSystem: """ return self._heat_efficiency + @property + def nominal_cooling_output(self): + """ + Get nominal_thermal_output of heat generation devices in kW + :return: float + """ + return self._nominal_cooling_output + + @property + def maximum_cooling_output(self): + """ + Get maximum heat output of heat generation devices in W + :return: float + """ + return self._maximum_cooling_output + + @property + def minimum_cooling_output(self): + """ + Get minimum heat output of heat generation devices in W + :return: float + """ + return self._minimum_cooling_output + @property def cooling_efficiency(self): """ @@ -110,38 +207,126 @@ class GenerationSystem: return self._source_mass_flow @property - def storage(self): + def nominal_electricity_output(self): """ - Get boolean storage exists - :return: bool + Get nominal_power_output of electricity generation devices or inverters in kW + :return: float """ - return self._storage + return self._nominal_electricity_output @property - def auxiliary_equipment(self) -> Union[None, GenerationSystem]: + def maximum_heat_supply_temperature(self): """ - Get auxiliary_equipment - :return: GenerationSystem + Get the maximum heat supply temperature in degree Celsius + :return: float """ - return self._auxiliary_equipment + return self._minimum_heat_supply_temperature + + @property + def minimum_heat_supply_temperature(self): + """ + Get the minimum heat supply temperature in degree Celsius + :return: float + """ + return self._minimum_heat_supply_temperature + + @property + def maximum_cooling_supply_temperature(self): + """ + Get the maximum cooling supply temperature in degree Celsius + :return: float + """ + return self._maximum_cooling_supply_temperature + + @property + def minimum_cooling_supply_temperature(self): + """ + Get the minimum cooling supply temperature in degree Celsius + :return: float + """ + return self._minimum_cooling_supply_temperature + + @property + def heat_output_curve(self) -> Union[None, PerformanceCurves]: + """ + Get the heat output curve of the heat generation device + :return: PerformanceCurve + """ + return self._heat_output_curve + + @property + def heat_fuel_consumption_curve(self) -> Union[None, PerformanceCurves]: + """ + Get the heating fuel consumption curve of the heat generation device + :return: PerformanceCurve + """ + return self._heat_fuel_consumption_curve + + @property + def heat_efficiency_curve(self) -> Union[None, PerformanceCurves]: + """ + Get the heating efficiency curve of the heat generation device + :return: PerformanceCurve + """ + return self._heat_efficiency_curve + + @property + def cooling_output_curve(self) -> Union[None, PerformanceCurves]: + """ + Get the heat output curve of the heat generation device + :return: PerformanceCurve + """ + return self._cooling_output_curve + + @property + def cooling_fuel_consumption_curve(self) -> Union[None, PerformanceCurves]: + """ + Get the heating fuel consumption curve of the heat generation device + :return: PerformanceCurve + """ + return self._cooling_fuel_consumption_curve + + @property + def cooling_efficiency_curve(self) -> Union[None, PerformanceCurves]: + """ + Get the heating efficiency curve of the heat generation device + :return: PerformanceCurve + """ + return self._cooling_efficiency_curve def to_dictionary(self): """Class content to dictionary""" - _auxiliary_equipment = [] - if self.auxiliary_equipment is not None: - _auxiliary_equipment = self.auxiliary_equipment.to_dictionary() - content = {'Layer': {'id': self.id, - 'name': self.name, - 'type': self.type, - 'fuel type': self.fuel_type, - 'source types': self.source_types, - 'source temperature [Celsius]': self.source_temperature, - 'source mass flow [kg/s]': self.source_mass_flow, - 'heat efficiency': self.heat_efficiency, - 'cooling efficiency': self.cooling_efficiency, - 'electricity efficiency': self.electricity_efficiency, - 'it has storage': self.storage, - 'auxiliary equipment': _auxiliary_equipment - } - } + content = {'Energy Generation component': { + 'id': self.id, + 'name': self.name, + 'model name': self.model_name, + 'manufacturer': self.manufacturer, + 'type': self.system_type, + 'fuel type': self.fuel_type, + 'nominal thermal output [W]': self.nominal_thermal_output, + 'maximum heat output [W]': self.maximum_heat_output, + 'minimum heat output [W]': self.minimum_heat_output, + 'source medium': self.source_medium, + 'supply medium': self.supply_medium, + 'source temperature [Celsius]': self.source_temperature, + 'source mass flow [kg/s]': self.source_mass_flow, + 'heat efficiency': self.heat_efficiency, + 'nominal cooling output [W]': self.nominal_cooling_output, + 'maximum cooling output [W]': self.maximum_cooling_output, + 'minimum cooling output [W]': self.minimum_cooling_output, + 'cooling efficiency': self.cooling_efficiency, + 'electricity efficiency': self.electricity_efficiency, + 'nominal power output [W]': self.nominal_electricity_output, + 'maximum heating supply temperature [Celsius]': self.maximum_heat_supply_temperature, + 'minimum heating supply temperature [Celsius]': self.minimum_heat_supply_temperature, + 'maximum cooling supply temperature [Celsius]': self.maximum_cooling_supply_temperature, + 'minimum cooling supply temperature [Celsius]': self.minimum_cooling_supply_temperature, + 'heat output curve': self.heat_output_curve, + 'heat fuel consumption curve': self.heat_fuel_consumption_curve, + 'heat efficiency curve': self.heat_efficiency_curve, + 'cooling output curve': self.cooling_output_curve, + 'cooling fuel consumption curve': self.cooling_fuel_consumption_curve, + 'cooling efficiency curve': self.cooling_efficiency_curve + } + } return content diff --git a/hub/catalog_factories/data_models/energy_systems/performance_curves.py b/hub/catalog_factories/data_models/energy_systems/performance_curves.py new file mode 100644 index 00000000..65cc0878 --- /dev/null +++ b/hub/catalog_factories/data_models/energy_systems/performance_curves.py @@ -0,0 +1,72 @@ +""" +Energy System catalog heat generation system +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2023 Concordia CERC group +Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca +Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" + +from __future__ import annotations + + +class PerformanceCurves: + """ + Parameter function class + """ + + def __init__(self, curve_type, dependant_variable, parameters, coefficients): + self._curve_type = curve_type + self._dependant_variable = dependant_variable + self._parameters = parameters + self._coefficients = coefficients + + @property + def curve_type(self): + """ + The type of the fit function from the following + Linear =>>> y = a*x + b + Exponential =>>> y = a*(b**x) + Polynomial =>>> y = a*(x**2) + b*x + c + Power =>>> y = a*(x**b) + Second degree multivariable =>>> y = a*(x**2) + b*x + c*x*z + d*z + e*(z**2) + f + + Get the type of function from ['linear', 'exponential', 'polynomial', 'power', 'second degree multivariable'] + :return: string + """ + return self._curve_type + + @property + def dependant_variable(self): + """ + y (e.g. COP in COP = a*source temperature**2 + b*source temperature + c*source temperature*supply temperature + + d*supply temperature + e*supply temperature**2 + f) + """ + return self._dependant_variable + + @property + def parameters(self): + """ + Get the list of parameters involved in fitting process as ['x', 'z'] (e.g. [source temperature, supply temperature] + in COP=) + :return: string + """ + return self._parameters + + @property + def coefficients(self): + """ + Get the coefficients of the functions as list of ['a', 'b', 'c', 'd', 'e', 'f'] + :return: [coefficients] + """ + return self._coefficients + + def to_dictionary(self): + """Class content to dictionary""" + content = {'Parameter Function': { + 'curve type': self.curve_type, + 'dependant variable': self.dependant_variable, + 'parameter(s)': self.parameters, + 'coefficients': self.coefficients, + } + } + return content diff --git a/hub/catalog_factories/data_models/energy_systems/pv_generation_system.py b/hub/catalog_factories/data_models/energy_systems/pv_generation_system.py new file mode 100644 index 00000000..ce0e71f1 --- /dev/null +++ b/hub/catalog_factories/data_models/energy_systems/pv_generation_system.py @@ -0,0 +1,131 @@ +""" +Energy System catalog heat generation system +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2023 Concordia CERC group +Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca +Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" + +from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem + + +class PvGenerationSystem(GenerationSystem): + """ + Electricity Generation system class + """ + + def __init__(self, system_id, name, model_name, manufacturer, electricity_efficiency, + nominal_electricity_output, nominal_ambient_temperature, nominal_cell_temperature, + nominal_radiation, standard_test_condition_cell_temperature, standard_test_condition_maximum_power, + cell_temperature_coefficient, width, height): + super().__init__(system_id=system_id, name=name, model_name=model_name, + manufacturer=manufacturer, system_type='pv', fuel_type='renewable', + nominal_thermal_output=None, maximum_heat_output=None, + minimum_heat_output=None, source_medium=None, + supply_medium=None, heat_efficiency=None, nominal_cooling_output=None, + maximum_cooling_output=None, minimum_cooling_output=None, + cooling_efficiency=None, electricity_efficiency=electricity_efficiency, + source_temperature=None, source_mass_flow=None, + nominal_electricity_output=nominal_electricity_output, + maximum_heat_supply_temperature=None, + minimum_heat_supply_temperature=None, + maximum_cooling_supply_temperature=None, + minimum_cooling_supply_temperature=None, heat_output_curve=None, + heat_fuel_consumption_curve=None, heat_efficiency_curve=None, + cooling_output_curve=None, cooling_fuel_consumption_curve=None, + cooling_efficiency_curve=None) + self._nominal_ambient_temperature = nominal_ambient_temperature + self._nominal_cell_temperature = nominal_cell_temperature + self._nominal_radiation = nominal_radiation + self._standard_test_condition_cell_temperature = standard_test_condition_cell_temperature + self._standard_test_condition_maximum_power = standard_test_condition_maximum_power + self._cell_temperature_coefficient = cell_temperature_coefficient + self._width = width + self._height = height + + @property + def nominal_ambient_temperature(self): + """ + Get nominal ambient temperature of PV panels in degree Celsius + :return: float + """ + return self._nominal_ambient_temperature + + @property + def nominal_cell_temperature(self): + """ + Get nominal cell temperature of PV panels in degree Celsius + :return: float + """ + return self._nominal_cell_temperature + + @property + def nominal_radiation(self): + """ + Get nominal radiation of PV panels + :return: float + """ + return self._nominal_radiation + + @property + def standard_test_condition_cell_temperature(self): + """ + Get standard test condition cell temperature of PV panels in degree Celsius + :return: float + """ + return self._standard_test_condition_cell_temperature + + @property + def standard_test_condition_maximum_power(self): + """ + Get standard test condition maximum power of PV panels in kW + :return: float + """ + return self._standard_test_condition_maximum_power + + @property + def cell_temperature_coefficient(self): + """ + Get cell temperature coefficient of PV module + :return: float + """ + return self._cell_temperature_coefficient + + @property + def width(self): + """ + Get PV module width in m + :return: float + """ + return self._width + + @property + def height(self): + """ + Get PV module height in m + :return: float + """ + return self._height + + def to_dictionary(self): + """Class content to dictionary""" + content = {'Energy Generation component': { + 'id': self.id, + 'name': self.name, + 'model name': self.model_name, + 'manufacturer': self.manufacturer, + 'type': self.system_type, + 'fuel type': self.fuel_type, + 'electricity efficiency': self.electricity_efficiency, + 'nominal power output [kW]': self.nominal_electricity_output, + 'nominal ambient temperature [Celsius]': self.nominal_ambient_temperature, + 'nominal cell temperature [Celsius]': self.nominal_cell_temperature, + 'nominal radiation [W/m2]': self.nominal_radiation, + 'standard test condition cell temperature [Celsius]': self.standard_test_condition_cell_temperature, + 'standard test condition maximum power [kW]': self.standard_test_condition_maximum_power, + 'cell temperature coefficient': self.cell_temperature_coefficient, + 'width': self.width, + 'height': self.height, + } + } + return content diff --git a/hub/catalog_factories/data_models/energy_systems/system.py b/hub/catalog_factories/data_models/energy_systems/system.py index 6059bec7..30ee9292 100644 --- a/hub/catalog_factories/data_models/energy_systems/system.py +++ b/hub/catalog_factories/data_models/energy_systems/system.py @@ -1,13 +1,16 @@ """ -Energy System catalog equipment +Energy System catalog heat generation system SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2023 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca """ -from typing import Union +from typing import Union, List from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem +from hub.catalog_factories.data_models.energy_systems.thermal_storage_system import ThermalStorageSystem +from hub.catalog_factories.data_models.energy_systems.electrical_storage_system import ElectricalStorageSystem from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem @@ -16,22 +19,25 @@ class System: """ System class """ + def __init__(self, lod, system_id, name, demand_types, - generation_system, - distribution_system, - emission_system): - + generation_systems, + distribution_systems, + emission_systems, + energy_storage_systems): self._lod = lod self._system_id = system_id self._name = name self._demand_types = demand_types - self._generation_system = generation_system - self._distribution_system = distribution_system - self._emission_system = emission_system + self._distribution_systems = distribution_systems + self._emission_systems = emission_systems + self._generation_systems = generation_systems + self._energy_storage_systems = energy_storage_systems + # self._configuration = configuration @property def lod(self): @@ -52,7 +58,7 @@ class System: @property def name(self): """ - Get name + Get the system name :return: string """ return self._name @@ -60,50 +66,63 @@ class System: @property def demand_types(self): """ - Get demand able to cover from [heating, cooling, domestic_hot_water, electricity] + Get demand able to cover from ['heating', 'cooling', 'domestic_hot_water', 'electricity'] :return: [string] """ return self._demand_types @property - def generation_system(self) -> GenerationSystem: + def generation_systems(self) -> List[GenerationSystem]: """ - Get generation system - :return: GenerationSystem + Get generation systems + :return: [GenerationSystem] """ - return self._generation_system + return self._generation_systems @property - def distribution_system(self) -> Union[None, DistributionSystem]: + def distribution_systems(self) -> Union[None, List[DistributionSystem]]: """ - Get distribution system - :return: DistributionSystem + Get distribution systems + :return: [DistributionSystem] """ - return self._distribution_system + return self._distribution_systems @property - def emission_system(self) -> Union[None, EmissionSystem]: + def emission_systems(self) -> Union[None, List[EmissionSystem]]: """ - Get emission system - :return: EmissionSystem + Get emission systems + :return: [EmissionSystem] """ - return self._emission_system + return self._emission_systems + + @property + def energy_storage_systems(self) -> Union[None, List[ThermalStorageSystem], List[ElectricalStorageSystem]]: + """ + Get energy storage systems + :return: [EnergyStorageSystem] + """ + return self._energy_storage_systems def to_dictionary(self): """Class content to dictionary""" - _distribution_system = None - if self.distribution_system is not None: - _distribution_system = self.distribution_system.to_dictionary() - _emission_system = None - if self.emission_system is not None: - _emission_system = self.emission_system.to_dictionary() - content = {'Layer': {'id': self.id, - 'name': self.name, - 'level of detail': self.lod, - 'demand types': self.demand_types, - 'generation system': self.generation_system.to_dictionary(), - 'distribution system': _distribution_system, - 'emission system': _emission_system - } + _generation_systems = [] + for _generation in self.generation_systems: + _generation_systems.append(_generation.to_dictionary()) + _distribution_systems = [_distribution.to_dictionary() for _distribution in + self.distribution_systems] if self.distribution_systems is not None else None + _emission_systems = [_emission.to_dictionary() for _emission in + self.emission_systems] if self.emission_systems is not None else None + _storage_systems = [_storage.to_dictionary() for _storage in + self.energy_storage_systems] if self.energy_storage_systems is not None else None + + content = {'system': {'id': self.id, + 'name': self.name, + 'level of detail': self.lod, + 'demand types': self.demand_types, + 'generation system(s)': _generation_systems, + 'distribution system(s)': _distribution_systems, + 'emission system(s)': _emission_systems, + 'energy storage system(s)': _storage_systems, + } } return content diff --git a/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py b/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py new file mode 100644 index 00000000..71b4f931 --- /dev/null +++ b/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py @@ -0,0 +1,89 @@ +""" +Energy System catalog thermal storage system +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2023 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca +""" + +from hub.catalog_factories.data_models.energy_systems.energy_storage_system import EnergyStorageSystem +from hub.catalog_factories.data_models.construction.layer import Layer + + +class ThermalStorageSystem(EnergyStorageSystem): + """" + Energy Storage System Class + """ + + def __init__(self, storage_id, name, model_name, manufacturer, storage_type, nominal_capacity, losses_ratio, + volume, height, layers, maximum_operating_temperature): + + super().__init__(storage_id, name, model_name, manufacturer, nominal_capacity, losses_ratio) + self._storage_type = storage_type + self._volume = volume + self._height = height + self._layers = layers + self._maximum_operating_temperature = maximum_operating_temperature + + @property + def storage_type(self): + """ + Get storage type from ['thermal', 'sensible', 'latent'] + :return: string + """ + return self._storage_type + + @property + def volume(self): + """ + Get the physical volume of the storage system in cubic meters + :return: float + """ + return self._volume + + @property + def height(self): + """ + Get the diameter of the storage system in meters + :return: float + """ + return self._height + + @property + def layers(self) -> [Layer]: + """ + Get construction layers + :return: [layer] + """ + return self._layers + + @property + def maximum_operating_temperature(self): + """ + Get maximum operating temperature of the storage system in degree Celsius + :return: float + """ + return self._maximum_operating_temperature + + def to_dictionary(self): + """Class content to dictionary""" + _layers = None + if self.layers is not None: + _layers = [] + for _layer in self.layers: + _layers.append(_layer.to_dictionary()) + content = {'Storage component': { + 'storage id': self.id, + 'name': self.name, + 'model name': self.model_name, + 'manufacturer': self.manufacturer, + 'storage type': self.storage_type, + 'nominal capacity [J]': self.nominal_capacity, + 'losses-ratio [J/J]': self.losses_ratio, + 'volume [m3]': self.volume, + 'height [m]': self.height, + 'layers': _layers, + 'maximum operating temperature [Celsius]': self.maximum_operating_temperature + } + } + return content diff --git a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py index 91c8d4e4..b2df20c2 100644 --- a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py +++ b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py @@ -14,12 +14,15 @@ from hub.catalog_factories.data_models.energy_systems.generation_system import G 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.archetype import Archetype +from hub.catalog_factories.data_models.energy_systems.thermal_storage_system import ThermalStorageSystem +from hub.catalog_factories.data_models.energy_systems.electrical_storage_system import ElectricalStorageSystem class MontrealCustomCatalog(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: @@ -28,21 +31,23 @@ class MontrealCustomCatalog(Catalog): self._lod = float(self._archetypes['catalog']['@lod']) - self._catalog_generation_equipments = self._load_generation_equipments() + self._catalog_generation_equipments, self._catalog_storage_equipments = \ + self._load_generation_and_storage_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) + self._catalog_emission_equipments, + None) - def _load_generation_equipments(self): + def _load_generation_and_storage_equipments(self): _equipments = [] + _storages = [] equipments = self._archetypes['catalog']['generation_equipments']['equipment'] for equipment in equipments: equipment_id = float(equipment['@id']) @@ -58,22 +63,48 @@ class MontrealCustomCatalog(Catalog): 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, + None, + None, equipment_type, fuel_type, None, + None, + None, + None, + None, heating_efficiency, + None, + None, + None, cooling_efficiency, electricity_efficiency, None, None, - storage, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, None) - _equipments.append(generation_system) - return _equipments + storage = literal_eval(equipment['storage'].capitalize()) + if storage: + if equipment_type == 'electricity generator': + storage_system = ElectricalStorageSystem(equipment_id, None, None, None, 'electrical', None, None, None, None, + None, None, None) + else: + storage_system = ThermalStorageSystem(equipment_id, None, None, None, 'thermal', None, None, None, None, None, + None) + _storages.append(storage_system) + + return _equipments, _storages def _load_distribution_equipments(self): _equipments = [] @@ -90,7 +121,8 @@ class MontrealCustomCatalog(Catalog): 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_consumption_variable_flow = float( + equipment['distribution_consumption_variable_flow']['#text']) / 100 distribution_system = DistributionSystem(equipment_id, name, @@ -130,28 +162,33 @@ class MontrealCustomCatalog(Catalog): name = system['name'] demands = system['demands']['demand'] generation_equipment = system['equipments']['generation_id'] - _generation_equipment = None + _generation_equipments = None for equipment_archetype in self._catalog_generation_equipments: if int(equipment_archetype.id) == int(generation_equipment): - _generation_equipment = equipment_archetype + _generation_equipments = [equipment_archetype] + _storage_equipments = None + for equipment_archetype in self._catalog_storage_equipments: + if int(equipment_archetype.id) == int(generation_equipment): + _storage_equipments = [equipment_archetype] distribution_equipment = system['equipments']['distribution_id'] - _distribution_equipment = None + _distribution_equipments = None for equipment_archetype in self._catalog_distribution_equipments: if int(equipment_archetype.id) == int(distribution_equipment): - _distribution_equipment = equipment_archetype + _distribution_equipments = [equipment_archetype] emission_equipment = system['equipments']['dissipation_id'] - _emission_equipment = None + _emission_equipments = None for equipment_archetype in self._catalog_emission_equipments: if int(equipment_archetype.id) == int(emission_equipment): - _emission_equipment = equipment_archetype + _emission_equipments = [equipment_archetype] _catalog_systems.append(System(self._lod, system_id, name, demands, - _generation_equipment, - _distribution_equipment, - _emission_equipment)) + _generation_equipments, + _distribution_equipments, + _emission_equipments, + _storage_equipments)) return _catalog_systems def _load_archetypes(self): @@ -175,7 +212,7 @@ class MontrealCustomCatalog(Catalog): """ if category is None: _names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'distribution_equipments': [], - 'emission_equipments':[]} + 'emission_equipments': []} for archetype in self._content.archetypes: _names['archetypes'].append(archetype.name) for system in self._content.systems: @@ -246,4 +283,4 @@ class MontrealCustomCatalog(Catalog): for entry in self._content.emission_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") \ No newline at end of file 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..b5702215 --- /dev/null +++ b/hub/catalog_factories/energy_systems/north_america_energy_system_catalog.py @@ -0,0 +1,510 @@ +""" +North america energy system catalog +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca +Code contributors: 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.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.pv_generation_system import PvGenerationSystem +from hub.catalog_factories.data_models.energy_systems.thermal_storage_system import ThermalStorageSystem +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 / 'north_america_systems.xml') + with open(path, 'r', encoding='utf-8') as xml: + self._archetypes = xmltodict.parse(xml.read(), force_list=['photovoltaicModules', 'templateStorages']) + self._generation_components = self._load_generation_components() + self._storage_components = self._load_storage_components() + self._systems = self._load_systems() + self._system_archetypes = self._load_archetypes() + self._content = Content(self._system_archetypes, + self._systems, + self._generation_components, + None, + None, + self._storage_components) + + def _load_generation_components(self): + generation_components = [] + boilers = self._archetypes['EnergySystemCatalog']['energy_generation_components']['boilers'] + heat_pumps = self._archetypes['EnergySystemCatalog']['energy_generation_components']['heatPumps'] + photovoltaics = self._archetypes['EnergySystemCatalog']['energy_generation_components']['photovoltaicModules'] + templates = self._archetypes['EnergySystemCatalog']['energy_generation_components']['templateGenerationEquipments'] + for boiler in boilers: + boiler_id = boiler['@generation_id'] + boiler_name = boiler['@name'] + boiler_model_name = boiler['@modelName'] + boiler_manufacturer = boiler['@manufacturer'] + system_type = 'boiler' + boiler_fuel_type = boiler['@fuel'] + boiler_nominal_thermal_output = float(boiler['@installedThermalPower']) + boiler_maximum_heat_output = float(boiler['@maximumHeatOutput']) + boiler_minimum_heat_output = float(boiler['@minimumHeatOutput']) + boiler_heat_efficiency = float(boiler['@nominalEfficiency']) + + boiler_component = GenerationSystem(boiler_id, + boiler_name, + boiler_model_name, + boiler_manufacturer, + system_type, + boiler_fuel_type, + boiler_nominal_thermal_output, + boiler_maximum_heat_output, + boiler_minimum_heat_output, + None, + None, + boiler_heat_efficiency, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None) + generation_components.append(boiler_component) + for heat_pump in heat_pumps: + heat_pump_id = heat_pump['@generation_id'] + heat_pump_name = heat_pump['@name'] + heat_pump_model_name = heat_pump['@modelName'] + heat_pump_manufacturer = heat_pump['@manufacturer'] + system_type = 'heat pump' + heat_pump_fuel_type = heat_pump['@fuel'] + heat_pump_nominal_thermal_output = float(heat_pump['@installedThermalPower']) + heat_pump_maximum_heat_output = float(heat_pump['@maximumHeatOutput']) + heat_pump_minimum_heat_output = float(heat_pump['@minimumHeatOutput']) + heat_pump_source_medium = heat_pump['@heatSource'] + heat_pump_supply_medium = heat_pump['@supply_medium'] + heat_pump_nominal_cop = float(heat_pump['@nominalCOP']) + heat_pump_maximum_heat_supply_temperature = float(heat_pump['@maxHeatingSupTemperature']) + heat_pump_minimum_heat_supply_temperature = float(heat_pump['@minHeatingSupTemperature']) + heat_pump_maximum_cooling_supply_temperature = float(heat_pump['@maxCoolingSupTemperature']) + heat_pump_minimum_cooling_supply_temperature = float(heat_pump['@minCoolingSupTemperature']) + cop_curve_type = heat_pump['performance_curve']['@curve_type'] + dependant_variable = heat_pump['performance_curve']['dependant_variable'] + parameters = heat_pump['performance_curve']['parameters'] + coefficients = list(heat_pump['performance_curve']['coefficients'].values()) + cop_curve = PerformanceCurves(cop_curve_type, dependant_variable, parameters, coefficients) + + heat_pump_component = GenerationSystem(heat_pump_id, + heat_pump_name, + heat_pump_model_name, + heat_pump_manufacturer, + system_type, + heat_pump_fuel_type, + heat_pump_nominal_thermal_output, + heat_pump_maximum_heat_output, + heat_pump_minimum_heat_output, + heat_pump_source_medium, + heat_pump_supply_medium, + heat_pump_nominal_cop, + None, + None, + None, + None, + None, + None, + None, + None, + heat_pump_maximum_heat_supply_temperature, + heat_pump_minimum_heat_supply_temperature, + heat_pump_maximum_cooling_supply_temperature, + heat_pump_minimum_cooling_supply_temperature, + None, + None, + cop_curve, + None, + None, + None) + generation_components.append(heat_pump_component) + for pv in photovoltaics: + pv_id = pv['@generation_id'] + pv_name = pv['@name'] + pv_model_name = pv['@modelName'] + pv_manufacturer = pv['@manufacturer'] + pv_electricity_efficiency = pv['@nominalEfficiency'] + pv_nominal_electricity_output = pv['@nominalPower'] + nominal_ambient_temperature = float(pv['@nominalAmbientTemperature']) + nominal_cell_temperature = float(pv['@nominalCellTemperature']) + nominal_radiation = float(pv['@nominalRadiation']) + standard_test_condition_cell_temperature = float(pv['@STCCellTemperature']) + standard_test_condition_maximum_power = float(pv['@STCMaxPower']) + cell_temperature_coefficient = float(pv['@CellTemperatureCoefficient']) + width = float(pv['@width']) + height = float(pv['@height']) + + pv_component = PvGenerationSystem(pv_id, + pv_name, + pv_model_name, + pv_manufacturer, + pv_electricity_efficiency, + pv_nominal_electricity_output, + nominal_ambient_temperature, + nominal_cell_temperature, + nominal_radiation, + standard_test_condition_cell_temperature, + standard_test_condition_maximum_power, + cell_temperature_coefficient, + width, + height) + generation_components.append(pv_component) + for template in templates: + system_id = template['@generation_id'] + system_name = template['@name'] + if "Boiler" in system_name: + system_type = 'boiler' + fuel_type = template['@fuel'] + heat_efficiency = float(template['@nominalEfficiency']) + source_medium = None + supply_medium = None + boiler_template = GenerationSystem(system_id, + system_name, + None, + None, + system_type, + fuel_type, + None, + None, + None, + source_medium, + supply_medium, + heat_efficiency, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None) + generation_components.append(boiler_template) + elif "Heat Pump" in system_name: + system_type = 'heat pump' + fuel_type = template['@fuel'] + heat_efficiency = template['@nominalCOP'] + source_medium = template['@heatSource'] + supply_medium = template['@supply_medium'] + heat_pump_template = GenerationSystem(system_id, + system_name, + None, + None, + system_type, + fuel_type, + None, + None, + None, + source_medium, + supply_medium, + heat_efficiency, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None) + generation_components.append(heat_pump_template) + else: + electricity_efficiency = float(template['@nominalEfficiency']) + height = float(template['@height']) + width = float(template['@width']) + pv_template = PvGenerationSystem(system_id, + system_name, + None, + None, + electricity_efficiency, + None, + None, + None, + None, + None, + None, + None, + width, + height) + generation_components.append(pv_template) + + return generation_components + + def _load_storage_components(self): + storage_components = [] + thermal_storages = self._archetypes['EnergySystemCatalog']['energy_storage_components']['thermalStorages'] + template_storages = self._archetypes['EnergySystemCatalog']['energy_storage_components']['templateStorages'] + for tes in thermal_storages: + storage_id = tes['@storage_id'] + name = tes['@name'] + model_name = tes['@modelName'] + manufacturer = tes['@manufacturer'] + storage_type = 'sensible' + volume = tes['physical_characteristics']['@volume'] + height = tes['physical_characteristics']['@height'] + maximum_operating_temperature = tes['@maxTemp'] + materials = self._load_materials() + insulation_material_id = tes['insulation']['@material_id'] + insulation_material = self._search_material(materials, insulation_material_id) + material_id = tes['physical_characteristics']['@material_id'] + tank_material = self._search_material(materials, material_id) + thickness = float(tes['insulation']['@insulationThickness']) / 100 # from cm to m + insulation_layer = Layer(None, 'insulation', insulation_material, thickness) + thickness = float(tes['physical_characteristics']['@tankThickness']) / 100 # from cm to m + tank_layer = Layer(None, 'tank', tank_material, thickness) +# the convention is from outside to inside + layers = [insulation_layer, tank_layer] + storage_component = ThermalStorageSystem(storage_id, + name, + model_name, + manufacturer, + storage_type, + None, + None, + volume, + height, + layers, + maximum_operating_temperature) + storage_components.append(storage_component) + + for template in template_storages: + storage_id = template['@storage_id'] + name = template['@name'] + storage_type = 'sensible' + maximum_temperature = template['@maxTemp'] + height = template['physical_characteristics']['@height'] + materials = self._load_materials() + insulation_material_id = template['insulation']['@material_id'] + insulation_material = self._search_material(materials, insulation_material_id) + material_id = template['physical_characteristics']['@material_id'] + tank_material = self._search_material(materials, material_id) + thickness = float(template['insulation']['@insulationThickness']) / 100 # from cm to m + insulation_layer = Layer(None, 'insulation', insulation_material, thickness) + thickness = float(template['physical_characteristics']['@tankThickness']) / 100 # from cm to m + tank_layer = Layer(None, 'tank', tank_material, thickness) +# the convention is from outside to inside + layers = [insulation_layer, tank_layer] + storage_component = ThermalStorageSystem(storage_id, + name, + None, + None, + storage_type, + None, + None, + None, + height, + layers, + maximum_temperature) + storage_components.append(storage_component) + return storage_components + + def _load_systems(self): + _catalog_systems = [] + systems = self._archetypes['EnergySystemCatalog']['systems']['system'] + for system in systems: + system_id = system['@id'] + name = system['name'] + demands = system['demands']['demand'] + generation_components = system['components']['generation_id'] + generation_systems = self._search_generation_equipment(self._load_generation_components(), generation_components) + if 'storage_id' in system['components'].keys(): + storage_components = system['components']['storage_id'] + storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_components) + else: + storage_systems = None + energy_system = System(None, + system_id, + name, + demands, + generation_systems, + None, + None, + storage_systems) + _catalog_systems.append(energy_system) + return _catalog_systems + + def _load_archetypes(self): + _system_archetypes = [] + system_clusters = self._archetypes['EnergySystemCatalog']['system_archetypes']['system_archetype'] + for system_cluster in system_clusters: + name = system_cluster['name'] + systems = system_cluster['systems']['system_id'] + integer_system_ids = [int(item) for item in systems] + _systems = [] + for system_archetype in self._systems: + if int(system_archetype.id) in integer_system_ids: + _systems.append(system_archetype) + _system_archetypes.append(Archetype(None, name, _systems)) + return _system_archetypes + + def _load_materials(self): + materials = [] + _materials = self._archetypes['EnergySystemCatalog']['materials']['material'] + for _material in _materials: + material_id = _material['@material_id'] + name = _material['@name'] + thermal_conductivity = _material['@thermalConductivity'] + material = Material(material_id, + name, + None, + None, + None, + False, + None, + thermal_conductivity, + None, + None) + materials.append(material) + return materials + + @staticmethod + def _search_material(materials, material_id): + _material = None + for material in materials: + if int(material.id) == int(material_id): + _material = material + return _material + + if _material is None: + raise ValueError(f'Material with the id = [{material_id}] not found in catalog ') + + @staticmethod + def _search_generation_equipment(generation_systems, generation_id): + _generation_systems = [] + if type(generation_id) == list: + integer_ids = [int(item) for item in generation_id] + for generation in generation_systems: + if int(generation.id) in integer_ids: + _generation_systems.append(generation) + else: + integer_id = int(generation_id) + for generation in generation_systems: + if int(generation.id) == integer_id: + _generation_systems.append(generation) + + if len(_generation_systems) == 0: + _generation_systems = None + raise ValueError(f'The system with the following id is not found in catalog [{generation_id}]') + return _generation_systems + + @staticmethod + def _search_storage_equipment(storage_systems, storage_id): + _storage_systems = [] + for storage in storage_systems: + if storage.id in storage_id: + _storage_systems.append(storage) + if len(_storage_systems) == 0: + _storage_systems_systems = None + raise ValueError(f'The system with the following id is not found in catalog [{storage_id}]') + return _storage_systems + + def names(self, category=None): + """ + Get the catalog elements names + :parm: optional category filter + """ + if category is None: + _names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'storage_equipments': []} + for archetype in self._content.archetypes: + _names['archetypes'].append(archetype.name) + for system in self._content.systems: + _names['systems'].append(system.name) + for equipment in self._content.generation_equipments: + _names['generation_equipments'].append(equipment.name) + for equipment in self._content.storage_equipments: + _names['storage_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() == 'systems': + for system in self._content.systems: + _names[category].append(system.name) + elif category.lower() == 'generation_equipments': + for system in self._content.generation_equipments: + _names[category].append(system.name) + elif category.lower() == 'storage_equipments': + for system in self._content.storage_equipments: + _names[category].append(system.name) + 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() == 'storage_equipments': + return self._content.storage_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.name.lower() == name.lower(): + return entry + for entry in self._content.systems: + if entry.name.lower() == name.lower(): + return entry + for entry in self._content.generation_equipments: + if entry.name.lower() == name.lower(): + return entry + for entry in self._content.storage_equipments: + if entry.name.lower() == name.lower(): + return entry + raise IndexError(f"{name} doesn't exists in the catalog") 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/north_america_systems.xml b/hub/data/energy_systems/north_america_systems.xml new file mode 100644 index 00000000..285f9de7 --- /dev/null +++ b/hub/data/energy_systems/north_america_systems.xml @@ -0,0 +1,227 @@ + + + ./schemas/ + + + + + + + + + + + + + + + + + + + COP + source_temperature + supply_temperature + + + + + + COP + source_temperature + supply_temperature + + + + + + COP + source_temperature + supply_temperature + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Air Source Heat Pump with Natural Gas Boiler and thermal storage + + heating + domestic_hot_water + + + 16 + 18 + 6 + + + + Air Source Heat Pump with Electrical Boiler and thermal storage + + heating + domestic_hot_water + + + 17 + 18 + 6 + + + + Ground Source Heat Pump with Natural Gas Boiler and thermal storage + + heating + domestic_hot_water + + + 16 + 19 + 6 + + + + Ground Source Heat Pump with Electrical Boiler and thermal storage + + heating + domestic_hot_water + + + 17 + 19 + 6 + + + + Water Source Heat Pump with Natural Gas Boiler and thermal storage + + heating + domestic_hot_water + + + 16 + 20 + 6 + + + + Water Source Heat Pump with Electrical Boiler and thermal storage\ + + heating + domestic_hot_water + + + 17 + 20 + 6 + + + + Photovoltaic System + + electricity + + + 21 + + + + + + PV+ASHP+GasBoiler+TES + + 7 + 1 + + + + PV+ASHP+ElectricBoiler+TES + + 7 + 2 + + + + PV+GSHP+GasBoiler+TES + + 7 + 3 + + + + PV+GSHP+ElectricBoiler+TES + + 7 + 4 + + + + PV+WSHP+GasBoiler+TES + + 7 + 5 + + + + PV+WSHP+ElectricBoiler+TES + + 7 + 6 + + + + + + + + + + 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 9b3f7a61..49f7086f 100644 --- a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py +++ b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py @@ -92,7 +92,7 @@ class MontrealCustomEnergySystemParameters: _type] _fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_equipment.fuel_type] _generation_system.fuel_type = _fuel_type - _generation_system.source_types = archetype_generation_equipment.source_types + _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 @@ -104,7 +104,7 @@ class MontrealCustomEnergySystemParameters: energy_system.generation_system = _generation_system _distribution_system = GenericDistributionSystem() - archetype_distribution_equipment = system.distribution_system + archetype_distribution_equipment = system.distribution_systems _distribution_system.type = archetype_distribution_equipment.type _distribution_system.supply_temperature = archetype_distribution_equipment.supply_temperature _distribution_system.distribution_consumption_fix_flow = \ @@ -139,10 +139,10 @@ class MontrealCustomEnergySystemParameters: _building_distribution_system = DistributionSystem() _building_distribution_system.generic_distribution_system = \ - copy.deepcopy(_generic_building_energy_system.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_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_system) diff --git a/hub/imports/geometry_factory.py b/hub/imports/geometry_factory.py index 3e6ca0b3..7adf8197 100644 --- a/hub/imports/geometry_factory.py +++ b/hub/imports/geometry_factory.py @@ -17,8 +17,7 @@ class GeometryFactory: GeometryFactory class """ def __init__(self, file_type, - path=None, - data_frame=None, + path, aliases_field=None, height_field=None, year_of_construction_field=None, @@ -27,7 +26,6 @@ class GeometryFactory: self._file_type = '_' + file_type.lower() validate_import_export_type(GeometryFactory, file_type) self._path = path - self._data_frame = data_frame self._aliases_field = aliases_field self._height_field = height_field self._year_of_construction_field = year_of_construction_field diff --git a/tests/test_systems_catalog.py b/tests/test_systems_catalog.py index 48af728c..862ea874 100644 --- a/tests/test_systems_catalog.py +++ b/tests/test_systems_catalog.py @@ -13,6 +13,7 @@ class TestSystemsCatalog(TestCase): def test_montreal_custom_catalog(self): catalog = EnergySystemsCatalogFactory('montreal_custom').catalog + catalog_categories = catalog.names() archetypes = catalog.names('archetypes') self.assertEqual(23, len(archetypes['archetypes'])) @@ -32,5 +33,13 @@ class TestSystemsCatalog(TestCase): for value in catalog_categories[category]: catalog.get_entry(value) + print(catalog.entries()) + with self.assertRaises(IndexError): catalog.get_entry('unknown') + + def test_north_america_systems_catalog(self): + catalog = EnergySystemsCatalogFactory('north_america').catalog + print(catalog.entries()) + + diff --git a/tests/test_systems_factory.py b/tests/test_systems_factory.py index 8d191043..9044ad18 100644 --- a/tests/test_systems_factory.py +++ b/tests/test_systems_factory.py @@ -90,11 +90,11 @@ class TestSystemsFactory(TestCase): _building_distribution_system = DistributionSystem() _building_distribution_system.generic_distribution_system = ( - copy.deepcopy(_generic_building_energy_system.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_system) + copy.deepcopy(_generic_building_energy_system.emission_systems) ) _building_generation_system = GenerationSystem() _building_generation_system.generic_generation_system = (