From 2d11bf66400c0dc2178081b939246ce361c62b27 Mon Sep 17 00:00:00 2001 From: s_ranjbar Date: Thu, 27 Jun 2024 16:32:44 -0400 Subject: [PATCH] Reapply "fix: energy system catalogue and importers are modified" This reverts commit 9adacadc2aa2296af11e051bc10381d73d6e99f9. --- .../energy_systems/emission_system.py | 2 +- .../non_pv_generation_system.py | 52 +- .../energy_systems/performance_curves.py | 8 +- .../energy_systems/thermal_storage_system.py | 14 +- .../energy_systems/montreal_custom_catalog.py | 9 +- .../montreal_future_system_catalogue.py | 40 +- hub/city_model_structure/building.py | 102 +++- .../building_demand/surface.py | 36 +- hub/city_model_structure/city_object.py | 29 +- .../energy_systems/emission_system.py | 2 +- .../energy_systems/generation_system.py | 22 +- .../non_pv_generation_system.py | 106 +++- .../energy_systems/performance_curve.py | 17 +- .../energy_systems/pv_generation_system.py | 36 ++ .../energy_systems/thermal_storage_system.py | 51 ++ .../montreal_future_systems.xml | 474 ++++++++++++++---- .../insel/insel_monthly_energy_balance.py | 2 +- .../formats/simplified_radiosity_algorithm.py | 6 +- hub/helpers/constants.py | 5 +- ...ontreal_custom_energy_system_parameters.py | 6 +- ...ntreal_future_energy_systems_parameters.py | 23 +- hub/imports/results/ep_multiple_buildings.py | 9 +- .../results/simplified_radiosity_algorithm.py | 2 +- hub/imports/weather/epw_weather_parameters.py | 16 +- hub/imports/weather/helpers/weather.py | 32 +- tests/test_systems_catalog.py | 8 +- tests/test_systems_factory.py | 7 +- 27 files changed, 877 insertions(+), 239 deletions(-) diff --git a/hub/catalog_factories/data_models/energy_systems/emission_system.py b/hub/catalog_factories/data_models/energy_systems/emission_system.py index 538954d3..a8ac91b6 100644 --- a/hub/catalog_factories/data_models/energy_systems/emission_system.py +++ b/hub/catalog_factories/data_models/energy_systems/emission_system.py @@ -10,7 +10,7 @@ class EmissionSystem: """ Emission system class """ - def __init__(self, system_id, model_name=None, system_type=None, parasitic_energy_consumption=0): + def __init__(self, system_id, model_name=None, system_type=None, parasitic_energy_consumption=None): self._system_id = system_id self._model_name = model_name diff --git a/hub/catalog_factories/data_models/energy_systems/non_pv_generation_system.py b/hub/catalog_factories/data_models/energy_systems/non_pv_generation_system.py index 5b203d01..0844c785 100644 --- a/hub/catalog_factories/data_models/energy_systems/non_pv_generation_system.py +++ b/hub/catalog_factories/data_models/energy_systems/non_pv_generation_system.py @@ -25,9 +25,11 @@ class NonPvGenerationSystem(GenerationSystem): 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, - distribution_systems=None, energy_storage_systems=None, dual_supply_capability=False): - super().__init__(system_id=system_id, name=name, model_name=model_name, manufacturer=manufacturer, fuel_type=fuel_type, - distribution_systems=distribution_systems, energy_storage_systems=energy_storage_systems) + distribution_systems=None, energy_storage_systems=None, domestic_hot_water=False, + reversible=None, simultaneous_heat_cold=None): + super().__init__(system_id=system_id, name=name, model_name=model_name, manufacturer=manufacturer, + fuel_type=fuel_type, distribution_systems=distribution_systems, + energy_storage_systems=energy_storage_systems) self._system_type = system_type self._nominal_heat_output = nominal_heat_output self._maximum_heat_output = maximum_heat_output @@ -53,7 +55,9 @@ class NonPvGenerationSystem(GenerationSystem): self._cooling_output_curve = cooling_output_curve self._cooling_fuel_consumption_curve = cooling_fuel_consumption_curve self._cooling_efficiency_curve = cooling_efficiency_curve - self._dual_supply_capability = dual_supply_capability + self._domestic_hot_water = domestic_hot_water + self._reversible = reversible + self._simultaneous_heat_cold = simultaneous_heat_cold @property def system_type(self): @@ -256,12 +260,28 @@ class NonPvGenerationSystem(GenerationSystem): return self._cooling_efficiency_curve @property - def dual_supply_capability(self): + def domestic_hot_water(self): """ - Get dual supply capability + Get the ability to produce domestic hot water :return: bool """ - return self._dual_supply_capability + return self._domestic_hot_water + + @property + def reversibility(self): + """ + Get the ability to produce heating and cooling + :return: bool + """ + return self._reversible + + @property + def simultaneous_heat_cold(self): + """ + Get the ability to produce heating and cooling at the same time + :return: bool + """ + return self._simultaneous_heat_cold def to_dictionary(self): """Class content to dictionary""" @@ -269,6 +289,18 @@ class NonPvGenerationSystem(GenerationSystem): self.distribution_systems] if self.distribution_systems is not None else None _energy_storage_systems = [_energy_storage_system.to_dictionary() for _energy_storage_system in self.energy_storage_systems] if self.energy_storage_systems is not None else None + _heat_output_curve = self.heat_output_curve.to_dictionary() if ( + self.heat_output_curve is not None) else None + _heat_fuel_consumption_curve = self.heat_fuel_consumption_curve.to_dictionary() if ( + self.heat_fuel_consumption_curve is not None) else None + _heat_efficiency_curve = self.heat_efficiency_curve.to_dictionary() if ( + self.heat_efficiency_curve is not None) else None + _cooling_output_curve = self.cooling_output_curve.to_dictionary() if ( + self.cooling_output_curve is not None) else None + _cooling_fuel_consumption_curve = self.cooling_fuel_consumption_curve.to_dictionary() if ( + self.cooling_fuel_consumption_curve is not None) else None + _cooling_efficiency_curve = self.cooling_efficiency_curve.to_dictionary() if ( + self.cooling_efficiency_curve is not None) else None content = { 'Energy Generation component': @@ -298,13 +330,15 @@ class NonPvGenerationSystem(GenerationSystem): '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, + 'heat efficiency curve': _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, 'distribution systems connected': _distribution_systems, 'storage systems connected': _energy_storage_systems, - 'dual supply capability': self.dual_supply_capability + 'domestic hot water production capability': self.domestic_hot_water, + 'reversible cycle': self.reversibility, + 'simultaneous heat and cooling production': self.simultaneous_heat_cold } } 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 index 65cc0878..ff6c22d2 100644 --- a/hub/catalog_factories/data_models/energy_systems/performance_curves.py +++ b/hub/catalog_factories/data_models/energy_systems/performance_curves.py @@ -24,13 +24,13 @@ class PerformanceCurves: def curve_type(self): """ The type of the fit function from the following - Linear =>>> y = a*x + b + Linear =>>> y = a + b*x Exponential =>>> y = a*(b**x) - Polynomial =>>> y = a*(x**2) + b*x + c + Second degree polynomial =>>> y = a + b*x + c*(x**2) Power =>>> y = a*(x**b) - Second degree multivariable =>>> y = a*(x**2) + b*x + c*x*z + d*z + e*(z**2) + f + Bi-Quadratic =>>> y = a + b*x + c*(x**2) + d*z + e*(z**2) + f*x*z - Get the type of function from ['linear', 'exponential', 'polynomial', 'power', 'second degree multivariable'] + Get the type of function from ['linear', 'exponential', 'second degree polynomial', 'power', 'bi-quadratic'] :return: string """ return self._curve_type 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 index d3cdf255..ca773e09 100644 --- a/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py +++ b/hub/catalog_factories/data_models/energy_systems/thermal_storage_system.py @@ -17,7 +17,7 @@ class ThermalStorageSystem(EnergyStorageSystem): def __init__(self, storage_id, type_energy_stored=None, model_name=None, manufacturer=None, storage_type=None, nominal_capacity=None, losses_ratio=None, volume=None, height=None, layers=None, - maximum_operating_temperature=None, storage_medium=None): + maximum_operating_temperature=None, storage_medium=None, heating_coil_capacity=None): super().__init__(storage_id, model_name, manufacturer, nominal_capacity, losses_ratio) self._type_energy_stored = type_energy_stored @@ -27,6 +27,7 @@ class ThermalStorageSystem(EnergyStorageSystem): self._layers = layers self._maximum_operating_temperature = maximum_operating_temperature self._storage_medium = storage_medium + self._heating_coil_capacity = heating_coil_capacity @property def type_energy_stored(self): @@ -84,6 +85,14 @@ class ThermalStorageSystem(EnergyStorageSystem): """ return self._storage_medium + @property + def heating_coil_capacity(self): + """ + Get heating coil capacity in Watts + :return: [material + """ + return self._heating_coil_capacity + def to_dictionary(self): """Class content to dictionary""" _layers = None @@ -110,7 +119,8 @@ class ThermalStorageSystem(EnergyStorageSystem): 'height [m]': self.height, 'layers': _layers, 'maximum operating temperature [Celsius]': self.maximum_operating_temperature, - 'storage_medium': self.storage_medium.to_dictionary() + 'storage_medium': self.storage_medium.to_dictionary(), + 'heating coil capacity [W]': self.heating_coil_capacity } } 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 bf47d19b..d3e37e36 100644 --- a/hub/catalog_factories/energy_systems/montreal_custom_catalog.py +++ b/hub/catalog_factories/energy_systems/montreal_custom_catalog.py @@ -87,7 +87,7 @@ class MontrealCustomCatalog(Catalog): cooling_efficiency=cooling_efficiency, electricity_efficiency=electricity_efficiency, energy_storage_systems=storage_systems, - dual_supply_capability=False + domestic_hot_water=False ) _equipments.append(generation_system) @@ -111,10 +111,7 @@ class MontrealCustomCatalog(Catalog): distribution_consumption_variable_flow = float( equipment['distribution_consumption_variable_flow']['#text']) / 100 - emission_equipment = -1 - if 'dissipation_id' in equipment: - emission_equipment = equipment['dissipation_id'] - + emission_equipment = equipment['dissipation_id'] _emission_equipments = None for equipment_archetype in self._catalog_emission_equipments: if int(equipment_archetype.id) == int(emission_equipment): @@ -138,7 +135,7 @@ class MontrealCustomCatalog(Catalog): equipment_id = float(equipment['@id']) equipment_type = equipment['@type'] model_name = equipment['name'] - parasitic_consumption = 0 + parasitic_consumption = None if 'parasitic_consumption' in equipment: parasitic_consumption = float(equipment['parasitic_consumption']['#text']) / 100 diff --git a/hub/catalog_factories/energy_systems/montreal_future_system_catalogue.py b/hub/catalog_factories/energy_systems/montreal_future_system_catalogue.py index b6d7f9f5..625e362c 100644 --- a/hub/catalog_factories/energy_systems/montreal_future_system_catalogue.py +++ b/hub/catalog_factories/energy_systems/montreal_future_system_catalogue.py @@ -121,13 +121,26 @@ class MontrealFutureSystemCatalogue(Catalog): parameters = non_pv['cooling_efficiency_curve']['parameters'] coefficients = list(non_pv['cooling_efficiency_curve']['coefficients'].values()) cooling_efficiency_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients) - dual_supply_capability = None - if non_pv['dual_supply_capability'] is not None: - if non_pv['dual_supply_capability'] == 'True': - dual_supply_capability = True + dhw = None + if non_pv['domestic_hot_water'] is not None: + if non_pv['domestic_hot_water'] == 'True': + dhw = True else: - dual_supply_capability = False + dhw = False + reversible = None + if non_pv['reversible'] is not None: + if non_pv['reversible'] == 'True': + reversible = True + else: + reversible = False + + dual_supply = None + if non_pv['simultaneous_heat_cold'] is not None: + if non_pv['simultaneous_heat_cold'] == 'True': + dual_supply = True + else: + dual_supply = False non_pv_component = NonPvGenerationSystem(system_id=system_id, name=name, system_type=system_type, @@ -160,7 +173,9 @@ class MontrealFutureSystemCatalogue(Catalog): cooling_efficiency_curve=cooling_efficiency_curve, distribution_systems=distribution_systems, energy_storage_systems=energy_storage_systems, - dual_supply_capability=dual_supply_capability) + domestic_hot_water=dhw, + reversible=reversible, + simultaneous_heat_cold=dual_supply) generation_components.append(non_pv_component) pv_generation_components = self._archetypes['EnergySystemCatalog']['energy_generation_components'][ 'pv_generation_component'] @@ -187,7 +202,6 @@ class MontrealFutureSystemCatalogue(Catalog): storage_component = pv['energy_storage_systems']['storage_id'] storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_component) energy_storage_systems = storage_systems - pv_component = PvGenerationSystem(system_id=system_id, name=name, system_type=system_type, @@ -248,7 +262,7 @@ class MontrealFutureSystemCatalogue(Catalog): system_id = None model_name = None system_type = None - parasitic_energy_consumption = 0 + parasitic_energy_consumption = None emission_system = EmissionSystem(system_id=system_id, model_name=model_name, system_type=system_type, @@ -284,6 +298,7 @@ class MontrealFutureSystemCatalogue(Catalog): layers = [insulation_layer, tank_layer] nominal_capacity = tes['nominal_capacity'] losses_ratio = tes['losses_ratio'] + heating_coil_capacity = tes['heating_coil_capacity'] storage_component = ThermalStorageSystem(storage_id=storage_id, model_name=model_name, type_energy_stored=type_energy_stored, @@ -295,7 +310,8 @@ class MontrealFutureSystemCatalogue(Catalog): height=height, layers=layers, maximum_operating_temperature=maximum_operating_temperature, - storage_medium=medium) + storage_medium=medium, + heating_coil_capacity=heating_coil_capacity) storage_components.append(storage_component) for template in template_storages: @@ -303,7 +319,7 @@ class MontrealFutureSystemCatalogue(Catalog): storage_type = template['storage_type'] type_energy_stored = template['type_energy_stored'] maximum_operating_temperature = template['maximum_operating_temperature'] - height = template['physical_characteristics']['height'] + height = float(template['physical_characteristics']['height']) materials = self._load_materials() insulation_material_id = template['insulation']['material_id'] insulation_material = self._search_material(materials, insulation_material_id) @@ -322,6 +338,7 @@ class MontrealFutureSystemCatalogue(Catalog): nominal_capacity = template['nominal_capacity'] losses_ratio = template['losses_ratio'] volume = template['physical_characteristics']['volume'] + heating_coil_capacity = template['heating_coil_capacity'] storage_component = ThermalStorageSystem(storage_id=storage_id, model_name=model_name, type_energy_stored=type_energy_stored, @@ -333,7 +350,8 @@ class MontrealFutureSystemCatalogue(Catalog): height=height, layers=layers, maximum_operating_temperature=maximum_operating_temperature, - storage_medium=medium) + storage_medium=medium, + heating_coil_capacity=heating_coil_capacity) storage_components.append(storage_component) return storage_components diff --git a/hub/city_model_structure/building.py b/hub/city_model_structure/building.py index 315f65d9..387a4bf9 100644 --- a/hub/city_model_structure/building.py +++ b/hub/city_model_structure/building.py @@ -90,7 +90,9 @@ class Building(CityObject): self._interior_slabs.append(surface) else: logging.error('Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type) - self._heating_consumption_disaggregated = {} + self._domestic_hot_water_peak_load = None + self._fuel_consumption_breakdown = {} + self._pv_generation = {} @property def shell(self) -> Polyhedron: @@ -449,8 +451,8 @@ class Building(CityObject): monthly_values = PeakLoads(self).heating_peak_loads_from_methodology if monthly_values is None: return None - results[cte.MONTH] = monthly_values - results[cte.YEAR] = [max(monthly_values)] + results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values] + results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES] return results @property @@ -466,8 +468,24 @@ class Building(CityObject): monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology if monthly_values is None: return None - results[cte.MONTH] = [x * cte.WATTS_HOUR_TO_JULES for x in monthly_values] - results[cte.YEAR] = [max(monthly_values)] + results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values] + results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES] + return results + + @property + def domestic_hot_water_peak_load(self) -> Union[None, dict]: + """ + Get cooling peak load in W + :return: dict{[float]} + """ + results = {} + monthly_values = None + if cte.HOUR in self.domestic_hot_water_heat_demand: + monthly_values = PeakLoads().peak_loads_from_hourly(self.domestic_hot_water_heat_demand[cte.HOUR]) + if monthly_values is None: + return None + results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values] + results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES] return results @property @@ -825,23 +843,6 @@ class Building(CityObject): self._onsite_electrical_production[_key] = _results return self._onsite_electrical_production - @property - def heating_consumption_disaggregated(self) -> dict: - """ - Get energy consumed for heating from different fuels in J - return: dict - """ - return self._heating_consumption_disaggregated - - @heating_consumption_disaggregated.setter - def heating_consumption_disaggregated(self, value): - """ - Get energy consumed for heating from different fuels in J - return: dict - """ - self._heating_consumption_disaggregated = value - - @property def lower_corner(self): """ @@ -855,3 +856,60 @@ class Building(CityObject): Get building upper corner. """ return [self._max_x, self._max_y, self._max_z] + + @property + def energy_consumption_breakdown(self) -> dict: + """ + Get energy consumption of different sectors + return: dict + """ + fuel_breakdown = {cte.ELECTRICITY: {cte.LIGHTING: self.lighting_electrical_demand[cte.YEAR][0], + cte.APPLIANCES: self.appliances_electrical_demand[cte.YEAR][0]}} + energy_systems = self.energy_systems + for energy_system in energy_systems: + demand_types = energy_system.demand_types + generation_systems = energy_system.generation_systems + for demand_type in demand_types: + for generation_system in generation_systems: + if generation_system.system_type != cte.PHOTOVOLTAIC: + if generation_system.fuel_type not in fuel_breakdown: + fuel_breakdown[generation_system.fuel_type] = {} + if demand_type in generation_system.energy_consumption: + fuel_breakdown[f'{generation_system.fuel_type}'][f'{demand_type}'] = ( + generation_system.energy_consumption)[f'{demand_type}'][cte.YEAR][0] + storage_systems = generation_system.energy_storage_systems + if storage_systems: + for storage_system in storage_systems: + if storage_system.type_energy_stored == 'thermal' and storage_system.heating_coil_energy_consumption: + fuel_breakdown[cte.ELECTRICITY][f'{demand_type}'] += storage_system.heating_coil_energy_consumption[cte.YEAR][0] + #TODO: When simulation models of all energy system archetypes are created, this part can be removed + heating_fuels = [] + dhw_fuels = [] + for energy_system in self.energy_systems: + if cte.HEATING in energy_system.demand_types: + for generation_system in energy_system.generation_systems: + heating_fuels.append(generation_system.fuel_type) + if cte.DOMESTIC_HOT_WATER in energy_system.demand_types: + for generation_system in energy_system.generation_systems: + dhw_fuels.append(generation_system.fuel_type) + for key in fuel_breakdown: + if key == cte.ELECTRICITY and cte.COOLING not in fuel_breakdown[key]: + for energy_system in energy_systems: + if cte.COOLING in energy_system.demand_types and cte.COOLING not in fuel_breakdown[key]: + for generation_system in energy_system.generation_systems: + fuel_breakdown[generation_system.fuel_type][cte.COOLING] = self.cooling_consumption[cte.YEAR][0] + for fuel in heating_fuels: + if cte.HEATING not in fuel_breakdown[fuel]: + for energy_system in energy_systems: + if cte.HEATING in energy_system.demand_types: + for generation_system in energy_system.generation_systems: + fuel_breakdown[generation_system.fuel_type][cte.HEATING] = self.heating_consumption[cte.YEAR][0] + for fuel in dhw_fuels: + if cte.DOMESTIC_HOT_WATER not in fuel_breakdown[fuel]: + for energy_system in energy_systems: + if cte.DOMESTIC_HOT_WATER in energy_system.demand_types: + for generation_system in energy_system.generation_systems: + fuel_breakdown[generation_system.fuel_type][cte.DOMESTIC_HOT_WATER] = self.domestic_hot_water_consumption[cte.YEAR][0] + self._fuel_consumption_breakdown = fuel_breakdown + return self._fuel_consumption_breakdown + diff --git a/hub/city_model_structure/building_demand/surface.py b/hub/city_model_structure/building_demand/surface.py index ab27ffe8..65f90ae3 100644 --- a/hub/city_model_structure/building_demand/surface.py +++ b/hub/city_model_structure/building_demand/surface.py @@ -42,10 +42,12 @@ class Surface: self._short_wave_reflectance = None self._long_wave_emittance = None self._inverse = None - self._associated_thermal_boundaries = None + self._associated_thermal_boundaries = [] self._vegetation = None self._percentage_shared = None self._solar_collectors_area_reduction_factor = None + self._global_irradiance_tilted = {} + self._installed_solar_collector_area = None @property def name(self): @@ -384,3 +386,35 @@ class Surface: :param value: float """ self._solar_collectors_area_reduction_factor = value + + @property + def global_irradiance_tilted(self) -> dict: + """ + Get global irradiance on a tilted surface in J/m2 + :return: dict + """ + return self._global_irradiance_tilted + + @global_irradiance_tilted.setter + def global_irradiance_tilted(self, value): + """ + Set global irradiance on a tilted surface in J/m2 + :param value: dict + """ + self._global_irradiance_tilted = value + + @property + def installed_solar_collector_area(self): + """ + Get installed solar collector area in m2 + :return: dict + """ + return self._installed_solar_collector_area + + @installed_solar_collector_area.setter + def installed_solar_collector_area(self, value): + """ + Set installed solar collector area in m2 + :return: dict + """ + self._installed_solar_collector_area = value \ No newline at end of file diff --git a/hub/city_model_structure/city_object.py b/hub/city_model_structure/city_object.py index c18a4aa0..0d281b65 100644 --- a/hub/city_model_structure/city_object.py +++ b/hub/city_model_structure/city_object.py @@ -41,9 +41,10 @@ class CityObject: self._ground_temperature = {} self._global_horizontal = {} self._diffuse = {} - self._beam = {} + self._direct_normal = {} self._sensors = [] self._neighbours = None + self._beam = {} @property def level_of_detail(self) -> LevelOfDetail: @@ -238,20 +239,20 @@ class CityObject: self._diffuse = value @property - def beam(self) -> dict: + def direct_normal(self) -> dict: """ Get beam radiation surrounding the city object in J/m2 :return: dict{dict{[float]}} """ - return self._beam + return self._direct_normal - @beam.setter - def beam(self, value): + @direct_normal.setter + def direct_normal(self, value): """ Set beam radiation surrounding the city object in J/m2 :param value: dict{dict{[float]}} """ - self._beam = value + self._direct_normal = value @property def lower_corner(self): @@ -302,3 +303,19 @@ class CityObject: Set the list of neighbour_objects and their properties associated to the current city_object """ self._neighbours = value + + @property + def beam(self) -> dict: + """ + Get beam radiation surrounding the city object in J/m2 + :return: dict{dict{[float]}} + """ + return self._beam + + @beam.setter + def beam(self, value): + """ + Set beam radiation surrounding the city object in J/m2 + :param value: dict{dict{[float]}} + """ + self._beam = value diff --git a/hub/city_model_structure/energy_systems/emission_system.py b/hub/city_model_structure/energy_systems/emission_system.py index e8773013..32bf7c17 100644 --- a/hub/city_model_structure/energy_systems/emission_system.py +++ b/hub/city_model_structure/energy_systems/emission_system.py @@ -13,7 +13,7 @@ class EmissionSystem: def __init__(self): self._model_name = None self._type = None - self._parasitic_energy_consumption = 0 + self._parasitic_energy_consumption = None @property def model_name(self): diff --git a/hub/city_model_structure/energy_systems/generation_system.py b/hub/city_model_structure/energy_systems/generation_system.py index 394c2f09..1765c08e 100644 --- a/hub/city_model_structure/energy_systems/generation_system.py +++ b/hub/city_model_structure/energy_systems/generation_system.py @@ -11,7 +11,8 @@ from abc import ABC from typing import Union, List from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem -from hub.city_model_structure.energy_systems.energy_storage_system import EnergyStorageSystem +from hub.city_model_structure.energy_systems.thermal_storage_system import ThermalStorageSystem +from hub.city_model_structure.energy_systems.electrical_storage_system import ElectricalStorageSystem class GenerationSystem(ABC): @@ -26,6 +27,7 @@ class GenerationSystem(ABC): self._fuel_type = None self._distribution_systems = None self._energy_storage_systems = None + self._number_of_units = None @property def system_type(self): @@ -124,7 +126,7 @@ class GenerationSystem(ABC): self._distribution_systems = value @property - def energy_storage_systems(self) -> Union[None, List[EnergyStorageSystem]]: + def energy_storage_systems(self) -> Union[None, List[ThermalStorageSystem], List[ElectricalStorageSystem]]: """ Get energy storage systems connected to this generation system :return: [EnergyStorageSystem] @@ -138,3 +140,19 @@ class GenerationSystem(ABC): :param value: [EnergyStorageSystem] """ self._energy_storage_systems = value + + @property + def number_of_units(self): + """ + Get number of a specific generation unit + :return: int + """ + return self._number_of_units + + @number_of_units.setter + def number_of_units(self, value): + """ + Set number of a specific generation unit + :return: int + """ + self._number_of_units = value diff --git a/hub/city_model_structure/energy_systems/non_pv_generation_system.py b/hub/city_model_structure/energy_systems/non_pv_generation_system.py index fea1d7b2..0eb9ed0e 100644 --- a/hub/city_model_structure/energy_systems/non_pv_generation_system.py +++ b/hub/city_model_structure/energy_systems/non_pv_generation_system.py @@ -42,7 +42,12 @@ class NonPvGenerationSystem(GenerationSystem): self._cooling_output_curve = None self._cooling_fuel_consumption_curve = None self._cooling_efficiency_curve = None - self._dual_supply_capability = None + self._domestic_hot_water = None + self._heat_supply_temperature = None + self._cooling_supply_temperature = None + self._reversible = None + self._simultaneous_heat_cold = None + self._energy_consumption = {} @property def nominal_heat_output(self): @@ -429,21 +434,106 @@ class NonPvGenerationSystem(GenerationSystem): self._cooling_efficiency_curve = value @property - def dual_supply_capability(self): + def domestic_hot_water(self): """ - Get the capability of the generation component for simultaneous heat and cold production + Get the capability of generating domestic hot water :return: bool """ - return self._dual_supply_capability + return self._domestic_hot_water - @dual_supply_capability.setter - def dual_supply_capability(self, value): + @domestic_hot_water.setter + def domestic_hot_water(self, value): """ - Set the capability of the generation component for simultaneous heat and cold production + Set the capability of generating domestic hot water :return: bool """ - self._dual_supply_capability = value + self._domestic_hot_water = value + @property + def heat_supply_temperature(self): + """ + Get the hourly heat supply temperature + :return: list + """ + return self._heat_supply_temperature + + @heat_supply_temperature.setter + def heat_supply_temperature(self, value): + """ + set the hourly heat supply temperature + :param value: + :return: list + """ + self._heat_supply_temperature = value + + @property + def cooling_supply_temperature(self): + """ + Get the hourly cooling supply temperature + :return: list + """ + return self._heat_supply_temperature + + @cooling_supply_temperature.setter + def cooling_supply_temperature(self, value): + """ + set the hourly cooling supply temperature + :param value: + :return: list + """ + self._cooling_supply_temperature = value + + @property + def reversibility(self): + """ + Get the capability of generating both heating and cooling + + :return: bool + """ + return self._reversible + + @reversibility.setter + def reversibility(self, value): + """ + Set the capability of generating domestic hot water + + :return: bool + """ + self._reversible = value + + @property + def simultaneous_heat_cold(self): + """ + Get the capability of generating both heating and cooling at the same time + + :return: bool + """ + return self._simultaneous_heat_cold + + @simultaneous_heat_cold.setter + def simultaneous_heat_cold(self, value): + """ + Set the capability of generating domestic hot water at the same time + + :return: bool + """ + self._simultaneous_heat_cold = value + + @property + def energy_consumption(self) -> dict: + """ + Get energy consumption in W + :return: dict{[float]} + """ + return self._energy_consumption + + @energy_consumption.setter + def energy_consumption(self, value): + """ + Set energy consumption in W + :param value: dict{[float]} + """ + self._energy_consumption = value diff --git a/hub/city_model_structure/energy_systems/performance_curve.py b/hub/city_model_structure/energy_systems/performance_curve.py index e7c72287..df667993 100644 --- a/hub/city_model_structure/energy_systems/performance_curve.py +++ b/hub/city_model_structure/energy_systems/performance_curve.py @@ -24,28 +24,29 @@ class PerformanceCurves: def curve_type(self): """ Get the type of the fit function from the following - Linear =>>> y = a*x + b + Linear =>>> y = a + b*x Exponential =>>> y = a*(b**x) - Polynomial =>>> y = a*(x**2) + b*x + c + Second degree polynomial =>>> y = a + b*x + c*(x**2) Power =>>> y = a*(x**b) - Second degree multivariable =>>> y = a*(x**2) + b*x + c*x*z + d*z + e*(z**2) + f + Bi-Quadratic =>>> y = a + b*x + c*(x**2) + d*z + e*(z**2) + f*x*z - Get the type of function from ['linear', 'exponential', 'polynomial', 'power', 'second degree multivariable'] + Get the type of function from ['linear', 'exponential', 'second degree polynomial', 'power', 'bi-quadratic'] :return: string """ + return self._curve_type @curve_type.setter def curve_type(self, value): """ Set the type of the fit function from the following - Linear =>>> y = a*x + b + Linear =>>> y = a + b*x Exponential =>>> y = a*(b**x) - Polynomial =>>> y = a*(x**2) + b*x + c + Second degree polynomial =>>> y = a + b*x + c*(x**2) Power =>>> y = a*(x**b) - Second degree multivariable =>>> y = a*(x**2) + b*x + c*x*z + d*z + e*(z**2) + f + Bi-Quadratic =>>> y = a + b*x + c*(x**2) + d*z + e*(z**2) + f*x*z - Get the type of function from ['linear', 'exponential', 'polynomial', 'power', 'second degree multivariable'] + Get the type of function from ['linear', 'exponential', 'second degree polynomial', 'power', 'bi-quadratic'] :return: string """ self._curve_type = value diff --git a/hub/city_model_structure/energy_systems/pv_generation_system.py b/hub/city_model_structure/energy_systems/pv_generation_system.py index 13409c7e..ddbc847a 100644 --- a/hub/city_model_structure/energy_systems/pv_generation_system.py +++ b/hub/city_model_structure/energy_systems/pv_generation_system.py @@ -26,6 +26,10 @@ class PvGenerationSystem(GenerationSystem): self._width = None self._height = None self._electricity_power = None + self._tilt_angle = None + self._surface_azimuth = None + self._solar_altitude_angle = None + self._solar_azimuth_angle = None @property def nominal_electricity_output(self): @@ -202,3 +206,35 @@ class PvGenerationSystem(GenerationSystem): :param value: float """ self._electricity_power = value + + @property + def tilt_angle(self): + """ + Get tilt angle of PV system in degrees + :return: float + """ + return self._tilt_angle + + @tilt_angle.setter + def tilt_angle(self, value): + """ + Set PV system tilt angle in degrees + :param value: float + """ + self._tilt_angle = value + + @property + def surface_azimuth(self): + """ + Get surface azimuth angle of PV system in degrees. 0 is North + :return: float + """ + return self._surface_azimuth + + @surface_azimuth.setter + def surface_azimuth(self, value): + """ + Set PV system tilt angle in degrees + :param value: float + """ + self._surface_azimuth = value diff --git a/hub/city_model_structure/energy_systems/thermal_storage_system.py b/hub/city_model_structure/energy_systems/thermal_storage_system.py index 0f7f6a12..fd9b8f81 100644 --- a/hub/city_model_structure/energy_systems/thermal_storage_system.py +++ b/hub/city_model_structure/energy_systems/thermal_storage_system.py @@ -22,6 +22,9 @@ class ThermalStorageSystem(EnergyStorageSystem): self._height = None self._layers = None self._maximum_operating_temperature = None + self._heating_coil_capacity = None + self._temperature = None + self._heating_coil_energy_consumption = None @property def volume(self): @@ -86,3 +89,51 @@ class ThermalStorageSystem(EnergyStorageSystem): :param value: float """ self._maximum_operating_temperature = value + + @property + def heating_coil_capacity(self): + """ + Get heating coil capacity in Watts + :return: float + """ + return self._heating_coil_capacity + + @heating_coil_capacity.setter + def heating_coil_capacity(self, value): + """ + Set heating coil capacity in Watts + :param value: float + """ + self._heating_coil_capacity = value + + @property + def temperature(self) -> dict: + """ + Get fuel consumption in W, m3, or kg + :return: dict{[float]} + """ + return self._temperature + + @temperature.setter + def temperature(self, value): + """ + Set fuel consumption in W, m3, or kg + :param value: dict{[float]} + """ + self._temperature = value + + @property + def heating_coil_energy_consumption(self) -> dict: + """ + Get fuel consumption in W, m3, or kg + :return: dict{[float]} + """ + return self._heating_coil_energy_consumption + + @heating_coil_energy_consumption.setter + def heating_coil_energy_consumption(self, value): + """ + Set fuel consumption in W, m3, or kg + :param value: dict{[float]} + """ + self._heating_coil_energy_consumption = value diff --git a/hub/data/energy_systems/montreal_future_systems.xml b/hub/data/energy_systems/montreal_future_systems.xml index 769f87bd..b51c9488 100644 --- a/hub/data/energy_systems/montreal_future_systems.xml +++ b/hub/data/energy_systems/montreal_future_systems.xml @@ -5,11 +5,11 @@ 1 Water - - - - - + + + + + 981.0 4180.0 0.6 @@ -26,7 +26,7 @@ 4.7 23.5 0.95 - True + False natural gas @@ -50,7 +50,10 @@ - + True + + + False 2 @@ -62,7 +65,7 @@ 6.15 30.8 0.95 - True + False natural gas @@ -86,7 +89,10 @@ - + True + + + False 3 @@ -98,7 +104,7 @@ 8.8 44 0.95 - True + False natural gas @@ -122,7 +128,10 @@ - + True + + + False 4 @@ -134,7 +143,7 @@ 12.3 61.5 0.95 - True + False natural gas @@ -158,7 +167,10 @@ - + True + + + False 5 @@ -170,7 +182,7 @@ 4.0 35.2 0.95 - True + False natural gas @@ -194,7 +206,10 @@ - + True + + + False 6 @@ -206,7 +221,7 @@ 4.0 35.2 0.95 - False + False natural gas @@ -230,7 +245,10 @@ - + True + + + False 7 @@ -242,7 +260,7 @@ 2.5 25.0 0.96 - + False natural gas @@ -266,7 +284,10 @@ - + True + + + False 8 @@ -278,7 +299,7 @@ 3.2 32.0 0.96 - + False natural gas @@ -302,7 +323,10 @@ - + True + + + False 9 @@ -314,7 +338,7 @@ 4.5 45.0 0.95 - True + False natural gas @@ -338,7 +362,10 @@ - + True + + + False 10 @@ -350,7 +377,7 @@ 3.5 35.0 0.95 - True + False natural gas @@ -374,7 +401,10 @@ - + True + + + False 11 @@ -386,7 +416,7 @@ 5.3 53.0 0.95 - True + False natural gas @@ -410,7 +440,10 @@ - + True + + + False 12 @@ -441,10 +474,10 @@ 0 51.7 3.32 - + True Electricity Air - water + Water @@ -460,7 +493,7 @@ - second degree multivariable function + bi-quadratic COP source_temperature supply_temperature @@ -471,7 +504,10 @@ - False + False + + + False 14 @@ -483,10 +519,10 @@ 0 279.3 3.07 - + True Electricity Air - water + Water @@ -502,7 +538,7 @@ - second degree multivariable function + bi-quadratic COP source_temperature supply_temperature @@ -513,7 +549,10 @@ - False + False + + + False 15 @@ -525,10 +564,10 @@ 0 557 3.46 - + True Electricity Air - water + Water @@ -544,7 +583,7 @@ - second degree multivariable function + bi-quadratic COP source_temperature supply_temperature @@ -555,7 +594,10 @@ - False + False + + + False 16 @@ -567,7 +609,7 @@ 0.90 - + False natural gas @@ -593,7 +635,10 @@ 6 - + True + + + False 17 @@ -605,7 +650,7 @@ 0.95 - + False electricity @@ -631,22 +676,25 @@ 6 - + False + + + False 18 - template Air-to-Water heat pump + template Air-to-Water heat pump with storage heat pump - 3 - + 2 + True electricity Air - water + Water @@ -661,19 +709,34 @@ - + + bi-quadratic + COP + source_temperature + supply_temperature + + - + + bi-quadratic + COP + source_temperature + supply_temperature + + 6 - True + True + + + True 19 - template Groundwater-to-Water heat pump + template Groundwater-to-Water heat pump with storage heat pump @@ -681,10 +744,10 @@ 3.5 - + True electricity Ground - water + Water @@ -707,11 +770,14 @@ 6 - True + True + + + True 20 - template Water-to-Water heat pump + template Water-to-Water heat pump with storage heat pump @@ -719,10 +785,10 @@ 3.5 - + True electricity Water - water + Water @@ -745,7 +811,10 @@ 6 - True + True + + + False 21 @@ -757,7 +826,7 @@ 0.90 - + False natural gas @@ -781,7 +850,10 @@ - + True + + + False 22 @@ -793,7 +865,7 @@ 0.95 - + False electricity @@ -817,7 +889,10 @@ - + True + + + False 23 @@ -829,14 +904,14 @@ 3 - + True electricity Air - water + Water - + 4.5 @@ -847,13 +922,28 @@ - + + bi-quadratic + COP + source_temperature + supply_temperature + + - + + bi-quadratic + COP + source_temperature + supply_temperature + + - True + True + + + True 24 @@ -865,10 +955,10 @@ 3.5 - + True electricity Ground - water + Water @@ -889,7 +979,10 @@ - True + True + + + True 25 @@ -901,10 +994,10 @@ 3.5 - + True electricity Water - water + Water @@ -925,7 +1018,10 @@ - True + True + + + True 26 @@ -945,7 +1041,55 @@ 1.0 + False + + 27 + template domestic hot water heat pump + heat pump + + + + + + 3.5 + + electricity + Air + Water + + + + + + + + + + + + + + + + bi-quadratic + COP + source_temperature + supply_temperature + + + + + + + + 7 + + True + + + False + @@ -970,8 +1114,9 @@ 1 sensible - - + + + 2 @@ -995,8 +1140,9 @@ 1 sensible - - + + + 3 @@ -1020,8 +1166,9 @@ 1 sensible - - + + + 4 @@ -1044,8 +1191,9 @@ 1 sensible - - + + + 5 @@ -1069,15 +1217,16 @@ 1 sensible - - + + + 6 template Hot Water Storage Tank thermal - HF 200 - + + 95.0 1 @@ -1088,47 +1237,74 @@ 0 1.5 Steel - + 1 sensible - - + + + + + + 7 + template Hot Water Storage Tank with Heating Coil + thermal + + + 95.0 + + 1 + 90.0 + + + 2 + 0 + 1.5 + Steel + + + + 1 + + sensible + + + 5000 1 Polyurethane - - - - - - - + + + + + + + 0.028 2 Steel - - - - - - - + + + + + + + 18 - + - + @@ -1138,7 +1314,6 @@ heating cooling - domestic_hot_water 21 @@ -1226,13 +1401,75 @@ 26 + + 8 + 4 pipe system with air source heat pump storage and gas boiler + schemas/ASHP+TES+GasBoiler.jpg + + heating + cooling + + + 23 + 16 + + + + 9 + 4 pipe system with air source heat pump storage and electric boiler + schemas/ASHP+TES+GasBoiler.jpg + + heating + cooling + + + 22 + 18 + + + + 10 + Domestic Hot Water Heat Pump with Coiled Storage + schemas/ASHP+TES+GasBoiler.jpg + + domestic_hot_water + + + 27 + + + + 11 + Central Heating System َASHP Gas-Boiler TES + schemas/ASHP+TES+GasBoiler.jpg + + heating + + + 23 + 16 + + + + 12 + Unitary ASHP Cooling System + schemas/ASHP+TES+GasBoiler.jpg + + cooling + + + 23 + + + PV+ASHP+GasBoiler+TES 7 1 + 10 @@ -1306,6 +1543,31 @@ 6 + + PV+4Pipe+DHW + + 7 + 8 + 10 + + + + Central Heating+Unitary Cooling+Unitary DHW + + 10 + 11 + 12 + + + + Central Heating+Unitary Cooling+Unitary DHW+PV + + 7 + 10 + 11 + 12 + + diff --git a/hub/exports/building_energy/insel/insel_monthly_energy_balance.py b/hub/exports/building_energy/insel/insel_monthly_energy_balance.py index f14ec946..329e9a13 100644 --- a/hub/exports/building_energy/insel/insel_monthly_energy_balance.py +++ b/hub/exports/building_energy/insel/insel_monthly_energy_balance.py @@ -270,7 +270,7 @@ class InselMonthlyEnergyBalance: global_irradiance = surface.global_irradiance[cte.MONTH] for j in range(0, len(global_irradiance)): parameters.append(f'{j + 1} ' - f'{global_irradiance[j] * cte.WATTS_HOUR_TO_JULES / 24 / _NUMBER_DAYS_PER_MONTH[j]}') + f'{global_irradiance[j] / 24 / _NUMBER_DAYS_PER_MONTH[j]}') else: for j in range(0, 12): parameters.append(f'{j + 1} 0.0') diff --git a/hub/exports/formats/simplified_radiosity_algorithm.py b/hub/exports/formats/simplified_radiosity_algorithm.py index d008a958..25189419 100644 --- a/hub/exports/formats/simplified_radiosity_algorithm.py +++ b/hub/exports/formats/simplified_radiosity_algorithm.py @@ -66,9 +66,9 @@ class SimplifiedRadiosityAlgorithm: else: i = (total_days + day - 1) * 24 + hour - 1 representative_building = self._city.buildings[0] - _diffuse = representative_building.diffuse[cte.HOUR][i] * cte.WATTS_HOUR_TO_JULES - _beam = representative_building.beam[cte.HOUR][i] * cte.WATTS_HOUR_TO_JULES - content += f'{day} {month} {hour} {_diffuse} {_beam}\n' + _global = representative_building.diffuse[cte.HOUR][i] / cte.WATTS_HOUR_TO_JULES + _beam = representative_building.direct_normal[cte.HOUR][i] / cte.WATTS_HOUR_TO_JULES + content += f'{day} {month} {hour} {_global} {_beam}\n' with open(file, 'w', encoding='utf-8') as file: file.write(content) diff --git a/hub/helpers/constants.py b/hub/helpers/constants.py index 23fab290..ad32c835 100644 --- a/hub/helpers/constants.py +++ b/hub/helpers/constants.py @@ -10,11 +10,11 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca KELVIN = 273.15 WATER_DENSITY = 1000 # kg/m3 WATER_HEAT_CAPACITY = 4182 # J/kgK - +WATER_THERMAL_CONDUCTIVITY = 0.65 # W/mK +NATURAL_GAS_LHV = 36.6e6 # J/m3 AIR_DENSITY = 1.293 # kg/m3 AIR_HEAT_CAPACITY = 1005.2 # J/kgK - # converters HOUR_TO_MINUTES = 60 MINUTES_TO_SECONDS = 60 @@ -292,6 +292,7 @@ WOOD = 'Wood' GAS = 'Gas' DIESEL = 'Diesel' COAL = 'Coal' +BIOMASS = 'Biomass' AIR = 'Air' WATER = 'Water' GEOTHERMAL = 'Geothermal' 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 4cdb848a..15833c9b 100644 --- a/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py +++ b/hub/imports/energy_systems/montreal_custom_energy_system_parameters.py @@ -86,7 +86,8 @@ class MontrealCustomEnergySystemParameters: if archetype_generation_system.system_type == 'Photovoltaic': _generation_system = PvGenerationSystem() _type = 'PV system' - _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type] + _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[ + _type] _fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type] _generation_system.fuel_type = _fuel_type _generation_system.electricity_efficiency = archetype_generation_system.electricity_efficiency @@ -98,7 +99,8 @@ class MontrealCustomEnergySystemParameters: else: _generation_system = NonPvGenerationSystem() _type = archetype_generation_system.system_type - _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type] + _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[ + _type] _fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type] _generation_system.fuel_type = _fuel_type _generation_system.source_types = archetype_generation_system.source_medium diff --git a/hub/imports/energy_systems/montreal_future_energy_systems_parameters.py b/hub/imports/energy_systems/montreal_future_energy_systems_parameters.py index 542608a0..1bcde834 100644 --- a/hub/imports/energy_systems/montreal_future_energy_systems_parameters.py +++ b/hub/imports/energy_systems/montreal_future_energy_systems_parameters.py @@ -82,8 +82,7 @@ class MontrealFutureEnergySystemParameters: return _generic_energy_systems - @staticmethod - def _create_generation_systems(archetype_system): + def _create_generation_systems(self, archetype_system): _generation_systems = [] archetype_generation_systems = archetype_system.generation_systems if archetype_generation_systems is not None: @@ -107,6 +106,7 @@ class MontrealFutureEnergySystemParameters: _generation_system.cell_temperature_coefficient = archetype_generation_system.cell_temperature_coefficient _generation_system.width = archetype_generation_system.width _generation_system.height = archetype_generation_system.height + _generation_system.tilt_angle = self._city.latitude _generic_storage_system = None if archetype_generation_system.energy_storage_systems is not None: _generic_storage_system = ElectricalStorageSystem() @@ -140,12 +140,13 @@ class MontrealFutureEnergySystemParameters: _generation_system.cooling_output_curve = archetype_generation_system.cooling_output_curve _generation_system.cooling_fuel_consumption_curve = archetype_generation_system.cooling_fuel_consumption_curve _generation_system.cooling_efficiency_curve = archetype_generation_system.cooling_efficiency_curve - _generation_system.dual_supply_capability = archetype_generation_system.dual_supply_capability + _generation_system.domestic_hot_water = archetype_generation_system.domestic_hot_water _generation_system.nominal_electricity_output = archetype_generation_system.nominal_electricity_output _generation_system.source_medium = archetype_generation_system.source_medium _generation_system.heat_efficiency = archetype_generation_system.heat_efficiency _generation_system.cooling_efficiency = archetype_generation_system.cooling_efficiency _generation_system.electricity_efficiency = archetype_generation_system.electricity_efficiency + _generation_system.reversibility = archetype_generation_system.reversibility _generic_storage_system = None if archetype_generation_system.energy_storage_systems is not None: _storage_systems = [] @@ -155,11 +156,19 @@ class MontrealFutureEnergySystemParameters: _generic_storage_system.type_energy_stored = 'electrical' else: _generic_storage_system = ThermalStorageSystem() - _generic_storage_system.type_energy_stored = 'thermal' + _generic_storage_system.type_energy_stored = storage_system.type_energy_stored + _generic_storage_system.height = storage_system.height + _generic_storage_system.layers = storage_system.layers + _generic_storage_system.storage_medium = storage_system.storage_medium + _generic_storage_system.heating_coil_capacity = storage_system.heating_coil_capacity _storage_systems.append(_generic_storage_system) - _generation_system.energy_storage_systems = [_storage_systems] - if archetype_generation_system.dual_supply_capability: - _generation_system.dual_supply_capability = True + _generation_system.energy_storage_systems = _storage_systems + if archetype_generation_system.domestic_hot_water: + _generation_system.domestic_hot_water = True + if archetype_generation_system.reversibility: + _generation_system.reversibility = True + if archetype_generation_system.simultaneous_heat_cold: + _generation_system.simultaneous_heat_cold = True _generation_systems.append(_generation_system) return _generation_systems diff --git a/hub/imports/results/ep_multiple_buildings.py b/hub/imports/results/ep_multiple_buildings.py index 9da12c7a..bd9a2dd3 100644 --- a/hub/imports/results/ep_multiple_buildings.py +++ b/hub/imports/results/ep_multiple_buildings.py @@ -60,9 +60,12 @@ class EnergyPlusMultipleBuildings: for building in self._city.buildings: building.heating_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Heating Demand (J)'] building.cooling_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Cooling Demand (J)'] - building.domestic_hot_water_heat_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} DHW Demand (W)'] - building.appliances_electrical_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Appliances (W)'] - building.lighting_electrical_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Lighting (W)'] + building.domestic_hot_water_heat_demand[cte.HOUR] = \ + [x * cte.WATTS_HOUR_TO_JULES for x in building_energy_demands[f'Building {building.name} DHW Demand (W)']] + building.appliances_electrical_demand[cte.HOUR] = \ + [x * cte.WATTS_HOUR_TO_JULES for x in building_energy_demands[f'Building {building.name} Appliances (W)']] + building.lighting_electrical_demand[cte.HOUR] = \ + [x * cte.WATTS_HOUR_TO_JULES for x in building_energy_demands[f'Building {building.name} Lighting (W)']] building.heating_demand[cte.MONTH] = MonthlyValues.get_total_month(building.heating_demand[cte.HOUR]) building.cooling_demand[cte.MONTH] = MonthlyValues.get_total_month(building.cooling_demand[cte.HOUR]) building.domestic_hot_water_heat_demand[cte.MONTH] = ( diff --git a/hub/imports/results/simplified_radiosity_algorithm.py b/hub/imports/results/simplified_radiosity_algorithm.py index 57fae8e9..3824e7ce 100644 --- a/hub/imports/results/simplified_radiosity_algorithm.py +++ b/hub/imports/results/simplified_radiosity_algorithm.py @@ -34,7 +34,7 @@ class SimplifiedRadiosityAlgorithm: for key in self._results: _irradiance = {} header_name = key.split(':') - result = [x / cte.WATTS_HOUR_TO_JULES for x in self._results[key]] + result = [x * cte.WATTS_HOUR_TO_JULES for x in self._results[key]] city_object_name = header_name[1] building = self._city.city_object(city_object_name) surface_id = header_name[2] diff --git a/hub/imports/weather/epw_weather_parameters.py b/hub/imports/weather/epw_weather_parameters.py index b4f28291..0c362261 100644 --- a/hub/imports/weather/epw_weather_parameters.py +++ b/hub/imports/weather/epw_weather_parameters.py @@ -110,22 +110,26 @@ class EpwWeatherParameters: # new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw']) # number_invalid_records = new_value[new_value.epw == 99.9].count().epw building.external_temperature[cte.HOUR] = self._weather_values['dry_bulb_temperature_c'] - building.global_horizontal[cte.HOUR] = [x / cte.WATTS_HOUR_TO_JULES + building.global_horizontal[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES for x in self._weather_values['global_horizontal_radiation_wh_m2']] - building.diffuse[cte.HOUR] = [x / cte.WATTS_HOUR_TO_JULES + building.diffuse[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES for x in self._weather_values['diffuse_horizontal_radiation_wh_m2']] - building.beam[cte.HOUR] = [x / cte.WATTS_HOUR_TO_JULES - for x in self._weather_values['direct_normal_radiation_wh_m2']] + building.direct_normal[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES + for x in self._weather_values['direct_normal_radiation_wh_m2']] + building.beam[cte.HOUR] = [building.global_horizontal[cte.HOUR][i] - + building.diffuse[cte.HOUR][i] + for i in range(len(building.global_horizontal[cte.HOUR]))] building.cold_water_temperature[cte.HOUR] = wh().cold_water_temperature(building.external_temperature[cte.HOUR]) + # create the monthly and yearly values out of the hourly for building in self._city.buildings: building.external_temperature[cte.MONTH] = \ MonthlyValues().get_mean_values(building.external_temperature[cte.HOUR]) - building.external_temperature[cte.YEAR] = [sum(building.external_temperature[cte.HOUR]) / 9870] + building.external_temperature[cte.YEAR] = [sum(building.external_temperature[cte.HOUR]) / 8760] building.cold_water_temperature[cte.MONTH] = \ MonthlyValues().get_mean_values(building.cold_water_temperature[cte.HOUR]) - building.cold_water_temperature[cte.YEAR] = [sum(building.cold_water_temperature[cte.HOUR]) / 9870] + building.cold_water_temperature[cte.YEAR] = [sum(building.cold_water_temperature[cte.HOUR]) / 8760] # If the usage has already being imported, the domestic hot water missing values must be calculated here that # the cold water temperature is finally known diff --git a/hub/imports/weather/helpers/weather.py b/hub/imports/weather/helpers/weather.py index 7603cb5b..755f9ad3 100644 --- a/hub/imports/weather/helpers/weather.py +++ b/hub/imports/weather/helpers/weather.py @@ -8,7 +8,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca import logging import math import hub.helpers.constants as cte - +from datetime import datetime, timedelta class Weather: """ @@ -55,25 +55,19 @@ class Weather: # and Craig Christensen, National Renewable Energy Laboratory # ambient temperatures( in °C) # cold water temperatures( in °C) - ambient_temperature_fahrenheit = [] - average_temperature = 0 - maximum_temperature = -1000 - minimum_temperature = 1000 - for temperature in ambient_temperature: - value = temperature * 9 / 5 + 32 - ambient_temperature_fahrenheit.append(value) - average_temperature += value / 8760 - if value > maximum_temperature: - maximum_temperature = value - if value < minimum_temperature: - minimum_temperature = value - delta_temperature = maximum_temperature - minimum_temperature - ratio = 0.4 + 0.01 * (average_temperature - 44) - lag = 35 - 1 * (average_temperature - 44) + t_out_fahrenheit = [1.8 * t_out + 32 for t_out in ambient_temperature] + t_out_average = sum(t_out_fahrenheit) / len(t_out_fahrenheit) + max_difference = max(t_out_fahrenheit) - min(t_out_fahrenheit) + ratio = 0.4 + 0.01 * (t_out_average - 44) + lag = 35 - (t_out_average - 35) + number_of_day = [a for a in range(1, 366)] + day_of_year = [day for day in number_of_day for _ in range(24)] + cold_temperature_fahrenheit = [] cold_temperature = [] - for temperature in ambient_temperature_fahrenheit: - radians = (0.986 * (temperature-15-lag) - 90) * math.pi / 180 - cold_temperature.append((average_temperature + 6 + ratio * (delta_temperature/2) * math.sin(radians) - 32) * 5/9) + for i in range(len(ambient_temperature)): + cold_temperature_fahrenheit.append(t_out_average + 6 + ratio * (max_difference / 2) * + math.sin(math.radians(0.986 * (day_of_year[i] - 15 - lag) - 90))) + cold_temperature.append((cold_temperature_fahrenheit[i] - 32) / 1.8) return cold_temperature def epw_file(self, region_code): diff --git a/tests/test_systems_catalog.py b/tests/test_systems_catalog.py index d41e5c07..612a8fe6 100644 --- a/tests/test_systems_catalog.py +++ b/tests/test_systems_catalog.py @@ -38,12 +38,12 @@ class TestSystemsCatalog(TestCase): catalog = EnergySystemsCatalogFactory('montreal_future').catalog catalog_categories = catalog.names() - archetypes = catalog.names('archetypes') - self.assertEqual(12, len(archetypes['archetypes'])) + archetypes = catalog.names() + self.assertEqual(15, len(archetypes['archetypes'])) systems = catalog.names('systems') - self.assertEqual(7, len(systems['systems'])) + self.assertEqual(12, len(systems['systems'])) generation_equipments = catalog.names('generation_equipments') - self.assertEqual(26, len(generation_equipments['generation_equipments'])) + self.assertEqual(27, len(generation_equipments['generation_equipments'])) with self.assertRaises(ValueError): catalog.names('unknown') diff --git a/tests/test_systems_factory.py b/tests/test_systems_factory.py index c4c086e3..a8207a7a 100644 --- a/tests/test_systems_factory.py +++ b/tests/test_systems_factory.py @@ -122,14 +122,13 @@ class TestSystemsFactory(TestCase): for energy_system in building.energy_systems: if cte.HEATING in energy_system.demand_types: _generation_system = cast(NonPvGenerationSystem, energy_system.generation_systems[0]) - _generation_system.heat_power = building.heating_peak_load[cte.YEAR][0] + _generation_system.nominal_heat_output = building.heating_peak_load[cte.YEAR][0] if cte.COOLING in energy_system.demand_types: _generation_system = cast(NonPvGenerationSystem, energy_system.generation_systems[0]) - _generation_system.cooling_power = building.cooling_peak_load[cte.YEAR][0] + _generation_system.nominal_cooling_output = building.cooling_peak_load[cte.YEAR][0] for building in self._city.buildings: self.assertLess(0, building.heating_consumption[cte.YEAR][0]) self.assertLess(0, building.cooling_consumption[cte.YEAR][0]) self.assertLess(0, building.domestic_hot_water_consumption[cte.YEAR][0]) - self.assertLess(0, building.onsite_electrical_production[cte.YEAR][0]) - print('test') \ No newline at end of file + self.assertLess(0, building.onsite_electrical_production[cte.YEAR][0]) \ No newline at end of file