all tests passed
This commit is contained in:
parent
e138a24555
commit
67cd435fd5
|
@ -296,7 +296,7 @@ class Building(CityObject):
|
||||||
def cold_water_temperature(self) -> {float}:
|
def cold_water_temperature(self) -> {float}:
|
||||||
"""
|
"""
|
||||||
Get cold water temperature in degrees Celsius
|
Get cold water temperature in degrees Celsius
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._cold_water_temperature
|
return self._cold_water_temperature
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ class Building(CityObject):
|
||||||
def cold_water_temperature(self, value):
|
def cold_water_temperature(self, value):
|
||||||
"""
|
"""
|
||||||
Set cold water temperature in degrees Celsius
|
Set cold water temperature in degrees Celsius
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._cold_water_temperature = value
|
self._cold_water_temperature = value
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ class Building(CityObject):
|
||||||
def heating_demand(self) -> dict:
|
def heating_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get heating demand in Wh
|
Get heating demand in Wh
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._heating_demand
|
return self._heating_demand
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ class Building(CityObject):
|
||||||
def heating_demand(self, value):
|
def heating_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set heating demand in Wh
|
Set heating demand in Wh
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._heating_demand = value
|
self._heating_demand = value
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ class Building(CityObject):
|
||||||
def cooling_demand(self) -> dict:
|
def cooling_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get cooling demand in Wh
|
Get cooling demand in Wh
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._cooling_demand
|
return self._cooling_demand
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ class Building(CityObject):
|
||||||
def cooling_demand(self, value):
|
def cooling_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set cooling demand in Wh
|
Set cooling demand in Wh
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._cooling_demand = value
|
self._cooling_demand = value
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@ class Building(CityObject):
|
||||||
def lighting_electrical_demand(self) -> dict:
|
def lighting_electrical_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get lighting electrical demand in Wh
|
Get lighting electrical demand in Wh
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._lighting_electrical_demand
|
return self._lighting_electrical_demand
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ class Building(CityObject):
|
||||||
def lighting_electrical_demand(self, value):
|
def lighting_electrical_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set lighting electrical demand in Wh
|
Set lighting electrical demand in Wh
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._lighting_electrical_demand = value
|
self._lighting_electrical_demand = value
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ class Building(CityObject):
|
||||||
def appliances_electrical_demand(self) -> dict:
|
def appliances_electrical_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get appliances electrical demand in Wh
|
Get appliances electrical demand in Wh
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._appliances_electrical_demand
|
return self._appliances_electrical_demand
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ class Building(CityObject):
|
||||||
def appliances_electrical_demand(self, value):
|
def appliances_electrical_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set appliances electrical demand in Wh
|
Set appliances electrical demand in Wh
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._appliances_electrical_demand = value
|
self._appliances_electrical_demand = value
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ class Building(CityObject):
|
||||||
def domestic_hot_water_heat_demand(self) -> dict:
|
def domestic_hot_water_heat_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get domestic hot water heat demand in Wh
|
Get domestic hot water heat demand in Wh
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._domestic_hot_water_heat_demand
|
return self._domestic_hot_water_heat_demand
|
||||||
|
|
||||||
|
@ -384,7 +384,7 @@ class Building(CityObject):
|
||||||
def domestic_hot_water_heat_demand(self, value):
|
def domestic_hot_water_heat_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set domestic hot water heat demand in Wh
|
Set domestic hot water heat demand in Wh
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._domestic_hot_water_heat_demand = value
|
self._domestic_hot_water_heat_demand = value
|
||||||
|
|
||||||
|
@ -428,12 +428,12 @@ class Building(CityObject):
|
||||||
def heating_peak_load(self) -> Union[None, dict]:
|
def heating_peak_load(self) -> Union[None, dict]:
|
||||||
"""
|
"""
|
||||||
Get heating peak load in W
|
Get heating peak load in W
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
results = {}
|
results = {}
|
||||||
if cte.HOUR in self.heating_demand:
|
if cte.HOUR in self.heating_demand:
|
||||||
monthly_values = PeakLoads().\
|
monthly_values = PeakLoads().\
|
||||||
peak_loads_from_hourly(self.heating_demand[cte.HOUR][next(iter(self.heating_demand[cte.HOUR]))])
|
peak_loads_from_hourly(self.heating_demand[cte.HOUR])
|
||||||
else:
|
else:
|
||||||
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
|
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
|
||||||
if monthly_values is None:
|
if monthly_values is None:
|
||||||
|
@ -446,11 +446,11 @@ class Building(CityObject):
|
||||||
def cooling_peak_load(self) -> Union[None, dict]:
|
def cooling_peak_load(self) -> Union[None, dict]:
|
||||||
"""
|
"""
|
||||||
Get cooling peak load in W
|
Get cooling peak load in W
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
results = {}
|
results = {}
|
||||||
if cte.HOUR in self.cooling_demand:
|
if cte.HOUR in self.cooling_demand:
|
||||||
monthly_values = PeakLoads().peak_loads_from_hourly(self.cooling_demand[cte.HOUR][next(iter(self.cooling_demand[cte.HOUR]))])
|
monthly_values = PeakLoads().peak_loads_from_hourly(self.cooling_demand[cte.HOUR])
|
||||||
else:
|
else:
|
||||||
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
|
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
|
||||||
if monthly_values is None:
|
if monthly_values is None:
|
||||||
|
@ -614,7 +614,8 @@ class Building(CityObject):
|
||||||
"""
|
"""
|
||||||
if len(self._heating_consumption) == 0:
|
if len(self._heating_consumption) == 0:
|
||||||
for heating_demand_key in self.heating_demand:
|
for heating_demand_key in self.heating_demand:
|
||||||
demand = self.heating_demand[heating_demand_key][cte.INSEL_MEB]
|
demand = self.heating_demand[heating_demand_key]
|
||||||
|
print('AAAAAAAAAA', heating_demand_key, demand)
|
||||||
consumption_type = cte.HEATING
|
consumption_type = cte.HEATING
|
||||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||||
if final_energy_consumed is None:
|
if final_energy_consumed is None:
|
||||||
|
@ -630,7 +631,7 @@ class Building(CityObject):
|
||||||
"""
|
"""
|
||||||
if len(self._cooling_consumption) == 0:
|
if len(self._cooling_consumption) == 0:
|
||||||
for cooling_demand_key in self.cooling_demand:
|
for cooling_demand_key in self.cooling_demand:
|
||||||
demand = self.cooling_demand[cooling_demand_key][cte.INSEL_MEB]
|
demand = self.cooling_demand[cooling_demand_key]
|
||||||
consumption_type = cte.COOLING
|
consumption_type = cte.COOLING
|
||||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||||
if final_energy_consumed is None:
|
if final_energy_consumed is None:
|
||||||
|
@ -646,7 +647,7 @@ class Building(CityObject):
|
||||||
"""
|
"""
|
||||||
if len(self._domestic_hot_water_consumption) == 0:
|
if len(self._domestic_hot_water_consumption) == 0:
|
||||||
for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand:
|
for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand:
|
||||||
demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key][cte.INSEL_MEB]
|
demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key]
|
||||||
consumption_type = cte.DOMESTIC_HOT_WATER
|
consumption_type = cte.DOMESTIC_HOT_WATER
|
||||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||||
if final_energy_consumed is None:
|
if final_energy_consumed is None:
|
||||||
|
@ -677,7 +678,7 @@ class Building(CityObject):
|
||||||
_total_hours = 0
|
_total_hours = 0
|
||||||
for key in _working_hours:
|
for key in _working_hours:
|
||||||
hours = sum(_working_hours[key])
|
hours = sum(_working_hours[key])
|
||||||
_total_hours += hours * cte.DAYS_A_YEAR[key]
|
_total_hours += hours * cte.WEEK_DAYS_A_YEAR[key]
|
||||||
return _total_hours
|
return _total_hours
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -710,8 +711,8 @@ class Building(CityObject):
|
||||||
if _peak_load_type == cte.HEATING.lower():
|
if _peak_load_type == cte.HEATING.lower():
|
||||||
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
|
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
|
||||||
for heating_demand_key in self.heating_demand:
|
for heating_demand_key in self.heating_demand:
|
||||||
_consumption = [0]*len(self.heating_demand[heating_demand_key][cte.INSEL_MEB])
|
_consumption = [0]*len(self.heating_demand[heating_demand_key])
|
||||||
_demand = self.heating_demand[heating_demand_key][cte.INSEL_MEB]
|
_demand = self.heating_demand[heating_demand_key]
|
||||||
for i, _ in enumerate(_consumption):
|
for i, _ in enumerate(_consumption):
|
||||||
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
||||||
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
|
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
|
||||||
|
@ -720,7 +721,7 @@ class Building(CityObject):
|
||||||
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
|
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
|
||||||
for demand_key in self.cooling_demand:
|
for demand_key in self.cooling_demand:
|
||||||
_consumption = self._distribution_systems_electrical_consumption[demand_key]
|
_consumption = self._distribution_systems_electrical_consumption[demand_key]
|
||||||
_demand = self.cooling_demand[demand_key][cte.INSEL_MEB]
|
_demand = self.cooling_demand[demand_key]
|
||||||
for i, _ in enumerate(_consumption):
|
for i, _ in enumerate(_consumption):
|
||||||
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
||||||
self._distribution_systems_electrical_consumption[demand_key] = _consumption
|
self._distribution_systems_electrical_consumption[demand_key] = _consumption
|
||||||
|
@ -780,12 +781,12 @@ class Building(CityObject):
|
||||||
_efficiency = energy_system.generation_system.generic_generation_system.electricity_efficiency
|
_efficiency = energy_system.generation_system.generic_generation_system.electricity_efficiency
|
||||||
self._onsite_electrical_production = {}
|
self._onsite_electrical_production = {}
|
||||||
for _key in self.roofs[0].global_irradiance.keys():
|
for _key in self.roofs[0].global_irradiance.keys():
|
||||||
_results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key][cte.SRA]))]
|
_results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key]))]
|
||||||
for surface in self.roofs:
|
for surface in self.roofs:
|
||||||
if _key in orientation_losses_factor:
|
if _key in orientation_losses_factor:
|
||||||
_results = [x + y * _efficiency * surface.perimeter_area
|
_results = [x + y * _efficiency * surface.perimeter_area
|
||||||
* surface.solar_collectors_area_reduction_factor * z
|
* surface.solar_collectors_area_reduction_factor * z
|
||||||
for x, y, z in zip(_results, surface.global_irradiance[_key][cte.SRA],
|
for x, y, z in zip(_results, surface.global_irradiance[_key],
|
||||||
orientation_losses_factor[_key]['south'])]
|
orientation_losses_factor[_key]['south'])]
|
||||||
self._onsite_electrical_production[_key] = _results
|
self._onsite_electrical_production[_key] = _results
|
||||||
return self._onsite_electrical_production
|
return self._onsite_electrical_production
|
||||||
|
|
|
@ -179,7 +179,7 @@ class Surface:
|
||||||
def global_irradiance(self) -> dict:
|
def global_irradiance(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get global irradiance on surface in Wh/m2
|
Get global irradiance on surface in Wh/m2
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict
|
||||||
"""
|
"""
|
||||||
return self._global_irradiance
|
return self._global_irradiance
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ class Surface:
|
||||||
def global_irradiance(self, value):
|
def global_irradiance(self, value):
|
||||||
"""
|
"""
|
||||||
Set global irradiance on surface in Wh/m2
|
Set global irradiance on surface in Wh/m2
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict
|
||||||
"""
|
"""
|
||||||
self._global_irradiance = value
|
self._global_irradiance = value
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ from hub.city_model_structure.building import Building
|
||||||
from hub.city_model_structure.buildings_cluster import BuildingsCluster
|
from hub.city_model_structure.buildings_cluster import BuildingsCluster
|
||||||
from hub.city_model_structure.city_object import CityObject
|
from hub.city_model_structure.city_object import CityObject
|
||||||
from hub.city_model_structure.city_objects_cluster import CityObjectsCluster
|
from hub.city_model_structure.city_objects_cluster import CityObjectsCluster
|
||||||
from hub.city_model_structure.energy_system import EnergySystem
|
|
||||||
from hub.city_model_structure.iot.station import Station
|
from hub.city_model_structure.iot.station import Station
|
||||||
from hub.city_model_structure.level_of_detail import LevelOfDetail
|
from hub.city_model_structure.level_of_detail import LevelOfDetail
|
||||||
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
||||||
|
@ -163,9 +162,6 @@ class City:
|
||||||
if self.buildings is not None:
|
if self.buildings is not None:
|
||||||
for building in self.buildings:
|
for building in self.buildings:
|
||||||
self._city_objects.append(building)
|
self._city_objects.append(building)
|
||||||
if self.energy_systems is not None:
|
|
||||||
for energy_system in self.energy_systems:
|
|
||||||
self._city_objects.append(energy_system)
|
|
||||||
return self._city_objects
|
return self._city_objects
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -409,14 +405,6 @@ class City:
|
||||||
"""
|
"""
|
||||||
return self._parts_consisting_buildings
|
return self._parts_consisting_buildings
|
||||||
|
|
||||||
@property
|
|
||||||
def energy_systems(self) -> Union[List[EnergySystem], None]:
|
|
||||||
"""
|
|
||||||
Get energy systems belonging to the city
|
|
||||||
:return: None or [EnergySystem]
|
|
||||||
"""
|
|
||||||
return self._energy_systems
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stations(self) -> [Station]:
|
def stations(self) -> [Station]:
|
||||||
"""
|
"""
|
||||||
|
@ -478,12 +466,12 @@ class City:
|
||||||
parameter_city_building_total_radiation = 0
|
parameter_city_building_total_radiation = 0
|
||||||
for surface in building.surfaces:
|
for surface in building.surfaces:
|
||||||
if surface.global_irradiance:
|
if surface.global_irradiance:
|
||||||
parameter_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
parameter_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
|
|
||||||
merged_city_building_total_radiation = 0
|
merged_city_building_total_radiation = 0
|
||||||
for surface in merged_city.city_object(building.name).surfaces:
|
for surface in merged_city.city_object(building.name).surfaces:
|
||||||
if surface.global_irradiance:
|
if surface.global_irradiance:
|
||||||
merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
|
|
||||||
if merged_city_building_total_radiation == 0:
|
if merged_city_building_total_radiation == 0:
|
||||||
merged_city.remove_city_object(merged_city.city_object(building.name))
|
merged_city.remove_city_object(merged_city.city_object(building.name))
|
||||||
|
|
|
@ -172,7 +172,7 @@ class CityObject:
|
||||||
def external_temperature(self) -> {float}:
|
def external_temperature(self) -> {float}:
|
||||||
"""
|
"""
|
||||||
Get external temperature surrounding the city object in Celsius
|
Get external temperature surrounding the city object in Celsius
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
return self._external_temperature
|
return self._external_temperature
|
||||||
|
|
||||||
|
@ -180,11 +180,10 @@ class CityObject:
|
||||||
def external_temperature(self, value):
|
def external_temperature(self, value):
|
||||||
"""
|
"""
|
||||||
Set external temperature surrounding the city object in Celsius
|
Set external temperature surrounding the city object in Celsius
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
self._external_temperature = value
|
self._external_temperature = value
|
||||||
|
|
||||||
# todo: this is the new format we will use to get rid of the data frames
|
|
||||||
@property
|
@property
|
||||||
def ground_temperature(self) -> dict:
|
def ground_temperature(self) -> dict:
|
||||||
"""
|
"""
|
||||||
|
@ -206,7 +205,7 @@ class CityObject:
|
||||||
def global_horizontal(self) -> dict:
|
def global_horizontal(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get global horizontal radiation surrounding the city object in W/m2
|
Get global horizontal radiation surrounding the city object in W/m2
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
return self._global_horizontal
|
return self._global_horizontal
|
||||||
|
|
||||||
|
@ -214,7 +213,7 @@ class CityObject:
|
||||||
def global_horizontal(self, value):
|
def global_horizontal(self, value):
|
||||||
"""
|
"""
|
||||||
Set global horizontal radiation surrounding the city object in W/m2
|
Set global horizontal radiation surrounding the city object in W/m2
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
self._global_horizontal = value
|
self._global_horizontal = value
|
||||||
|
|
||||||
|
@ -222,7 +221,7 @@ class CityObject:
|
||||||
def diffuse(self) -> dict:
|
def diffuse(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get diffuse radiation surrounding the city object in W/m2
|
Get diffuse radiation surrounding the city object in W/m2
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
return self._diffuse
|
return self._diffuse
|
||||||
|
|
||||||
|
@ -230,7 +229,7 @@ class CityObject:
|
||||||
def diffuse(self, value):
|
def diffuse(self, value):
|
||||||
"""
|
"""
|
||||||
Set diffuse radiation surrounding the city object in W/m2
|
Set diffuse radiation surrounding the city object in W/m2
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
self._diffuse = value
|
self._diffuse = value
|
||||||
|
|
||||||
|
@ -238,7 +237,7 @@ class CityObject:
|
||||||
def beam(self) -> dict:
|
def beam(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get beam radiation surrounding the city object in W/m2
|
Get beam radiation surrounding the city object in W/m2
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
return self._beam
|
return self._beam
|
||||||
|
|
||||||
|
@ -246,7 +245,7 @@ class CityObject:
|
||||||
def beam(self, value):
|
def beam(self, value):
|
||||||
"""
|
"""
|
||||||
Set beam radiation surrounding the city object in W/m2
|
Set beam radiation surrounding the city object in W/m2
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
self._beam = value
|
self._beam = value
|
||||||
|
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
"""
|
|
||||||
EnergySystem module
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
||||||
Code contributors: Peter Yefi peteryefi@gmail.com
|
|
||||||
"""
|
|
||||||
|
|
||||||
from hub.city_model_structure.city_object import CityObject
|
|
||||||
from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP
|
|
||||||
from hub.city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP
|
|
||||||
|
|
||||||
|
|
||||||
class EnergySystem(CityObject):
|
|
||||||
"""
|
|
||||||
EnergySystem(CityObject) class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, name, surfaces):
|
|
||||||
super().__init__(name, surfaces)
|
|
||||||
self._air_source_hp = None
|
|
||||||
self._water_to_water_hp = None
|
|
||||||
self._type = 'energy_system'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def air_source_hp(self) -> AirSourceHP:
|
|
||||||
"""
|
|
||||||
Heat pump energy system
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return self._air_source_hp
|
|
||||||
|
|
||||||
@air_source_hp.setter
|
|
||||||
def air_source_hp(self, value):
|
|
||||||
"""
|
|
||||||
Set heat pump for energy system
|
|
||||||
:param value: AirSourceHP
|
|
||||||
"""
|
|
||||||
if self._air_source_hp is None:
|
|
||||||
self._air_source_hp = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def water_to_water_hp(self) -> WaterToWaterHP:
|
|
||||||
"""
|
|
||||||
Water to water heat pump energy system
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return self._water_to_water_hp
|
|
||||||
|
|
||||||
@water_to_water_hp.setter
|
|
||||||
def water_to_water_hp(self, value):
|
|
||||||
"""
|
|
||||||
Set water to water heat pump for energy system
|
|
||||||
:param value: WaterToWaterHP
|
|
||||||
"""
|
|
||||||
if self._water_to_water_hp is None:
|
|
||||||
self._water_to_water_hp = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def type(self) -> str:
|
|
||||||
"""
|
|
||||||
Type of city object
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
return self._type
|
|
|
@ -1,132 +0,0 @@
|
||||||
"""
|
|
||||||
air_source_hp module defines an air source heat pump
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
||||||
Code contributors: Peter Yefi peteryefi@gmail.com
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import List
|
|
||||||
from hub.city_model_structure.energy_systems.heat_pump import HeatPump
|
|
||||||
|
|
||||||
|
|
||||||
class AirSourceHP(HeatPump):
|
|
||||||
"""
|
|
||||||
AirSourceHP class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self._cooling_capacity = None
|
|
||||||
self._cooling_comp_power = None
|
|
||||||
self._cooling_capacity_coff = None # a coefficients for insel
|
|
||||||
self._heating_capacity = None
|
|
||||||
self._heating_comp_power = None
|
|
||||||
self._heating_capacity_coff = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cooling_capacity(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get cooling capacity in kW
|
|
||||||
:return: [[float]]
|
|
||||||
"""
|
|
||||||
return self._cooling_capacity
|
|
||||||
|
|
||||||
@cooling_capacity.setter
|
|
||||||
def cooling_capacity(self, value):
|
|
||||||
"""
|
|
||||||
Set cooling capacity in kW
|
|
||||||
:param value: [[float]]
|
|
||||||
"""
|
|
||||||
if self._cooling_capacity is None:
|
|
||||||
self._cooling_capacity = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cooling_comp_power(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get cooling compressor power input in kW
|
|
||||||
:return: [[float]]
|
|
||||||
"""
|
|
||||||
return self._cooling_comp_power
|
|
||||||
|
|
||||||
@cooling_comp_power.setter
|
|
||||||
def cooling_comp_power(self, value):
|
|
||||||
"""
|
|
||||||
Set the cooling compressor in kW
|
|
||||||
:param value: [[float]]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._cooling_comp_power is None:
|
|
||||||
self._cooling_comp_power = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cooling_capacity_coff(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get cooling capacity coefficients
|
|
||||||
:return: [float]
|
|
||||||
"""
|
|
||||||
return self._cooling_capacity_coff
|
|
||||||
|
|
||||||
@cooling_capacity_coff.setter
|
|
||||||
def cooling_capacity_coff(self, value):
|
|
||||||
"""
|
|
||||||
Set the value for cooling capacity coefficients
|
|
||||||
:param value: [float]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._cooling_capacity_coff is None:
|
|
||||||
self._cooling_capacity_coff = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def heating_capacity(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get heating capacity kW
|
|
||||||
:return: [[float]]
|
|
||||||
"""
|
|
||||||
return self._heating_capacity
|
|
||||||
|
|
||||||
@heating_capacity.setter
|
|
||||||
def heating_capacity(self, value):
|
|
||||||
"""
|
|
||||||
Set the heating capacity in kW
|
|
||||||
:param value: [[float]]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._heating_capacity is None:
|
|
||||||
self._heating_capacity = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def heating_comp_power(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get heating compressor power kW
|
|
||||||
:return: [[float]]
|
|
||||||
"""
|
|
||||||
return self._heating_comp_power
|
|
||||||
|
|
||||||
@heating_comp_power.setter
|
|
||||||
def heating_comp_power(self, value):
|
|
||||||
"""
|
|
||||||
Set the heating compressor power in kW
|
|
||||||
:param value: [[float]]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._heating_comp_power is None:
|
|
||||||
self._heating_comp_power = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def heating_capacity_coff(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get heating capacity coefficients
|
|
||||||
:return: [float]
|
|
||||||
"""
|
|
||||||
return self._heating_capacity_coff
|
|
||||||
|
|
||||||
@heating_capacity_coff.setter
|
|
||||||
def heating_capacity_coff(self, value):
|
|
||||||
"""
|
|
||||||
Set the value for heating capacity coefficients
|
|
||||||
:param value: [float]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._heating_capacity_coff is None:
|
|
||||||
self._heating_capacity_coff = value
|
|
|
@ -1,131 +0,0 @@
|
||||||
"""
|
|
||||||
water_to_water_hp module defines a water to water heat pump heat pump
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Peter Yefi peteryefi@gmail.com
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import List
|
|
||||||
from hub.city_model_structure.energy_systems.heat_pump import HeatPump
|
|
||||||
|
|
||||||
|
|
||||||
class WaterToWaterHP(HeatPump):
|
|
||||||
"""
|
|
||||||
WaterToWaterHP class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self._entering_water_temp = None
|
|
||||||
self._leaving_water_temp = None
|
|
||||||
self._total_cooling_capacity = None
|
|
||||||
self._power_demand = None
|
|
||||||
self._flow_rate = None
|
|
||||||
self._power_demand_coff = None # a coefficients
|
|
||||||
|
|
||||||
@property
|
|
||||||
def entering_water_temp(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get entering water temperature in degree celsius
|
|
||||||
:return: [[float]]
|
|
||||||
"""
|
|
||||||
return self._entering_water_temp
|
|
||||||
|
|
||||||
@entering_water_temp.setter
|
|
||||||
def entering_water_temp(self, value):
|
|
||||||
"""
|
|
||||||
Set entering water temperature in degree celsius
|
|
||||||
:param value: [[float]]
|
|
||||||
"""
|
|
||||||
if self._entering_water_temp is None:
|
|
||||||
self._entering_water_temp = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def leaving_water_temp(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get leaving water temperature in degree celsius
|
|
||||||
:return: [[float]]
|
|
||||||
"""
|
|
||||||
return self._leaving_water_temp
|
|
||||||
|
|
||||||
@leaving_water_temp.setter
|
|
||||||
def leaving_water_temp(self, value):
|
|
||||||
"""
|
|
||||||
Set the leaving water temperature in degree celsius
|
|
||||||
:param value: [[float]]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._leaving_water_temp is None:
|
|
||||||
self._leaving_water_temp = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def total_cooling_capacity(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get total cooling capacity
|
|
||||||
:return: [float]
|
|
||||||
"""
|
|
||||||
return self._total_cooling_capacity
|
|
||||||
|
|
||||||
@total_cooling_capacity.setter
|
|
||||||
def total_cooling_capacity(self, value):
|
|
||||||
"""
|
|
||||||
Set the value for total cooling capacity
|
|
||||||
:param value: [float]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._total_cooling_capacity is None:
|
|
||||||
self._total_cooling_capacity = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def power_demand(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get power demand in kW
|
|
||||||
:return: [float]
|
|
||||||
"""
|
|
||||||
return self._power_demand
|
|
||||||
|
|
||||||
@power_demand.setter
|
|
||||||
def power_demand(self, value):
|
|
||||||
"""
|
|
||||||
Set the value for power demand in kW
|
|
||||||
:param value: [float]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._power_demand is None:
|
|
||||||
self._power_demand = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def flow_rate(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get flow rate in kg/s
|
|
||||||
:return: [[float]]
|
|
||||||
"""
|
|
||||||
return self._flow_rate
|
|
||||||
|
|
||||||
@flow_rate.setter
|
|
||||||
def flow_rate(self, value):
|
|
||||||
"""
|
|
||||||
Set flow rate in kW
|
|
||||||
:param value: [[float]]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._flow_rate is None:
|
|
||||||
self._flow_rate = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def power_demand_coff(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Get power demand coefficients
|
|
||||||
:return: [float]
|
|
||||||
"""
|
|
||||||
return self._power_demand_coff
|
|
||||||
|
|
||||||
@power_demand_coff.setter
|
|
||||||
def power_demand_coff(self, value):
|
|
||||||
"""
|
|
||||||
Set the value for power demand coefficients
|
|
||||||
:param value: [float]
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._power_demand_coff is None:
|
|
||||||
self._power_demand_coff = value
|
|
|
@ -533,7 +533,7 @@ class Idf:
|
||||||
self._add_schedules(usage, 'Appliance', thermal_zone.appliances.schedules)
|
self._add_schedules(usage, 'Appliance', thermal_zone.appliances.schedules)
|
||||||
self._add_schedules(usage, 'DHW_prof', thermal_zone.domestic_hot_water.schedules)
|
self._add_schedules(usage, 'DHW_prof', thermal_zone.domestic_hot_water.schedules)
|
||||||
_new_schedules = self._create_yearly_values_schedules('cold_temp',
|
_new_schedules = self._create_yearly_values_schedules('cold_temp',
|
||||||
building.cold_water_temperature[cte.HOUR]['epw'])
|
building.cold_water_temperature[cte.HOUR])
|
||||||
self._add_schedules(building.name, 'cold_temp', _new_schedules)
|
self._add_schedules(building.name, 'cold_temp', _new_schedules)
|
||||||
value = thermal_zone.domestic_hot_water.service_temperature
|
value = thermal_zone.domestic_hot_water.service_temperature
|
||||||
_new_schedules = self._create_constant_value_schedules('DHW_temp', value)
|
_new_schedules = self._create_constant_value_schedules('DHW_temp', value)
|
||||||
|
|
|
@ -30,13 +30,11 @@ class InselMonthlyEnergyBalance:
|
||||||
"""
|
"""
|
||||||
Insel monthly energy balance class
|
Insel monthly energy balance class
|
||||||
"""
|
"""
|
||||||
def __init__(self, city, path, custom_insel_block, radiation_calculation_method='sra', weather_format='epw'):
|
def __init__(self, city, path, custom_insel_block):
|
||||||
self._city = city
|
self._city = city
|
||||||
self._path = path
|
self._path = path
|
||||||
self._custom_insel_block = custom_insel_block
|
self._custom_insel_block = custom_insel_block
|
||||||
self._results = None
|
self._results = None
|
||||||
self._radiation_calculation_method = radiation_calculation_method
|
|
||||||
self._weather_format = weather_format
|
|
||||||
self._contents = []
|
self._contents = []
|
||||||
self._insel_files_paths = []
|
self._insel_files_paths = []
|
||||||
self._sanity_check()
|
self._sanity_check()
|
||||||
|
@ -48,7 +46,7 @@ class InselMonthlyEnergyBalance:
|
||||||
logging.warning('Building %s has missing values. Monthly Energy Balance cannot be processed', building.name)
|
logging.warning('Building %s has missing values. Monthly Energy Balance cannot be processed', building.name)
|
||||||
|
|
||||||
self._contents.append(
|
self._contents.append(
|
||||||
self._generate_meb_template(building, output_path, self._radiation_calculation_method, self._weather_format, self._custom_insel_block)
|
self._generate_meb_template(building, output_path, self._custom_insel_block)
|
||||||
)
|
)
|
||||||
self._export()
|
self._export()
|
||||||
|
|
||||||
|
@ -96,7 +94,7 @@ class InselMonthlyEnergyBalance:
|
||||||
f'Required minimum level 1')
|
f'Required minimum level 1')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format, custom_insel_block):
|
def _generate_meb_template(building, insel_outputs_path, custom_insel_block):
|
||||||
file = ""
|
file = ""
|
||||||
i_block = 1
|
i_block = 1
|
||||||
parameters = ["1", "12", "1"]
|
parameters = ["1", "12", "1"]
|
||||||
|
@ -148,7 +146,7 @@ class InselMonthlyEnergyBalance:
|
||||||
total_values = sum(schedule.values)
|
total_values = sum(schedule.values)
|
||||||
total_hours = 0
|
total_hours = 0
|
||||||
for day_type in schedule.day_types:
|
for day_type in schedule.day_types:
|
||||||
total_hours += cte.DAYS_A_YEAR[day_type] / 365 / 24
|
total_hours += cte.WEEK_DAYS_A_YEAR[day_type] / 365 / 24
|
||||||
total_values *= total_hours
|
total_values *= total_hours
|
||||||
total_internal_gain += internal_gain * total_values
|
total_internal_gain += internal_gain * total_values
|
||||||
|
|
||||||
|
@ -181,8 +179,8 @@ class InselMonthlyEnergyBalance:
|
||||||
ventilation_day += 0
|
ventilation_day += 0
|
||||||
infiltration_day += infiltration_value / 24
|
infiltration_day += infiltration_value / 24
|
||||||
for day_type in schedule.day_types:
|
for day_type in schedule.day_types:
|
||||||
infiltration += infiltration_day * cte.DAYS_A_YEAR[day_type] / 365
|
infiltration += infiltration_day * cte.WEEK_DAYS_A_YEAR[day_type] / 365
|
||||||
ventilation += ventilation_day * cte.DAYS_A_YEAR[day_type] / 365
|
ventilation += ventilation_day * cte.WEEK_DAYS_A_YEAR[day_type] / 365
|
||||||
|
|
||||||
ventilation_infiltration = ventilation + infiltration
|
ventilation_infiltration = ventilation + infiltration
|
||||||
parameters.append(f'{ventilation_infiltration} % BP(18) #8 Minimum air change rate zone {i + 1} (ACH)')
|
parameters.append(f'{ventilation_infiltration} % BP(18) #8 Minimum air change rate zone {i + 1} (ACH)')
|
||||||
|
@ -230,7 +228,6 @@ class InselMonthlyEnergyBalance:
|
||||||
parameters.append(thermal_boundary.parent_surface.short_wave_reflectance)
|
parameters.append(thermal_boundary.parent_surface.short_wave_reflectance)
|
||||||
else:
|
else:
|
||||||
parameters.append(0.0)
|
parameters.append(0.0)
|
||||||
|
|
||||||
file = InselMonthlyEnergyBalance._add_block(file, i_block, custom_insel_block, inputs=inputs, parameters=parameters)
|
file = InselMonthlyEnergyBalance._add_block(file, i_block, custom_insel_block, inputs=inputs, parameters=parameters)
|
||||||
|
|
||||||
i_block = 20
|
i_block = 20
|
||||||
|
@ -238,9 +235,8 @@ class InselMonthlyEnergyBalance:
|
||||||
parameters = ['12 % Monthly ambient temperature (degree Celsius)']
|
parameters = ['12 % Monthly ambient temperature (degree Celsius)']
|
||||||
|
|
||||||
external_temperature = building.external_temperature[cte.MONTH]
|
external_temperature = building.external_temperature[cte.MONTH]
|
||||||
|
|
||||||
for i in range(0, len(external_temperature)):
|
for i in range(0, len(external_temperature)):
|
||||||
parameters.append(f'{i + 1} {external_temperature.at[i, weather_format]}')
|
parameters.append(f'{i + 1} {external_temperature[i]}')
|
||||||
|
|
||||||
file = InselMonthlyEnergyBalance._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters)
|
file = InselMonthlyEnergyBalance._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters)
|
||||||
|
|
||||||
|
@ -248,12 +244,11 @@ class InselMonthlyEnergyBalance:
|
||||||
inputs = ['1']
|
inputs = ['1']
|
||||||
parameters = ['12 % Monthly sky temperature']
|
parameters = ['12 % Monthly sky temperature']
|
||||||
|
|
||||||
sky_temperature = Weather.sky_temperature(external_temperature[[weather_format]].to_numpy().T[0])
|
sky_temperature = Weather.sky_temperature(external_temperature)
|
||||||
for i, temperature in enumerate(sky_temperature):
|
for i, temperature in enumerate(sky_temperature):
|
||||||
parameters.append(f'{i + 1} {temperature}')
|
parameters.append(f'{i + 1} {temperature}')
|
||||||
|
|
||||||
file = InselMonthlyEnergyBalance._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters)
|
file = InselMonthlyEnergyBalance._add_block(file, i_block, 'polyg', inputs=inputs, parameters=parameters)
|
||||||
|
|
||||||
for i, surface in enumerate(surfaces):
|
for i, surface in enumerate(surfaces):
|
||||||
i_block = 101 + i
|
i_block = 101 + i
|
||||||
inputs = ['1 % Monthly surface radiation (W/m2)']
|
inputs = ['1 % Monthly surface radiation (W/m2)']
|
||||||
|
@ -266,7 +261,7 @@ class InselMonthlyEnergyBalance:
|
||||||
global_irradiance = surface.global_irradiance[cte.MONTH]
|
global_irradiance = surface.global_irradiance[cte.MONTH]
|
||||||
for j in range(0, len(global_irradiance)):
|
for j in range(0, len(global_irradiance)):
|
||||||
parameters.append(f'{j + 1} '
|
parameters.append(f'{j + 1} '
|
||||||
f'{global_irradiance.at[j, radiation_calculation_method] / 24 / _NUMBER_DAYS_PER_MONTH[j]}')
|
f'{global_irradiance[j] / 24 / _NUMBER_DAYS_PER_MONTH[j]}')
|
||||||
else:
|
else:
|
||||||
for j in range(0, 12):
|
for j in range(0, 12):
|
||||||
parameters.append(f'{j + 1} 0.0')
|
parameters.append(f'{j + 1} 0.0')
|
||||||
|
@ -290,5 +285,4 @@ class InselMonthlyEnergyBalance:
|
||||||
f"'{str(insel_outputs_path)}' % File name",
|
f"'{str(insel_outputs_path)}' % File name",
|
||||||
"'*' % Fortran format"]
|
"'*' % Fortran format"]
|
||||||
file = InselMonthlyEnergyBalance._add_block(file, i_block, 'WRITE', inputs=inputs, parameters=parameters)
|
file = InselMonthlyEnergyBalance._add_block(file, i_block, 'WRITE', inputs=inputs, parameters=parameters)
|
||||||
|
|
||||||
return file
|
return file
|
||||||
|
|
|
@ -66,8 +66,8 @@ class SimplifiedRadiosityAlgorithm:
|
||||||
else:
|
else:
|
||||||
i = (total_days + day - 1) * 24 + hour - 1
|
i = (total_days + day - 1) * 24 + hour - 1
|
||||||
representative_building = self._city.buildings[0]
|
representative_building = self._city.buildings[0]
|
||||||
content += f'{day} {month} {hour} {representative_building.global_horizontal[cte.HOUR].epw[i]} ' \
|
content += f'{day} {month} {hour} {representative_building.global_horizontal[cte.HOUR][i]} ' \
|
||||||
f'{representative_building.beam[cte.HOUR].epw[i]}\n'
|
f'{representative_building.beam[cte.HOUR][i]}\n'
|
||||||
with open(file, 'w', encoding='utf-8') as file:
|
with open(file, 'w', encoding='utf-8') as file:
|
||||||
file.write(content)
|
file.write(content)
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ WEEK_DAYS = 'Weekdays'
|
||||||
WEEK_ENDS = 'Weekends'
|
WEEK_ENDS = 'Weekends'
|
||||||
ALL_DAYS = 'Alldays'
|
ALL_DAYS = 'Alldays'
|
||||||
|
|
||||||
DAYS_A_MONTH = {'monday': [5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 5],
|
WEEK_DAYS_A_MONTH = {'monday': [5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 5],
|
||||||
'tuesday': [5, 4, 4, 4, 5, 4, 5, 4, 4, 5, 4, 4],
|
'tuesday': [5, 4, 4, 4, 5, 4, 5, 4, 4, 5, 4, 4],
|
||||||
'wednesday': [5, 4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4],
|
'wednesday': [5, 4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4],
|
||||||
'thursday': [4, 4, 5, 4, 5, 4, 4, 5, 4, 4, 5, 4],
|
'thursday': [4, 4, 5, 4, 5, 4, 4, 5, 4, 4, 5, 4],
|
||||||
|
@ -57,7 +57,7 @@ DAYS_A_MONTH = {'monday': [5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4, 5],
|
||||||
'sunday': [4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4, 5],
|
'sunday': [4, 4, 4, 5, 4, 4, 5, 4, 5, 4, 4, 5],
|
||||||
'holiday': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
|
'holiday': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
|
||||||
|
|
||||||
DAYS_A_YEAR = {'monday': 51,
|
WEEK_DAYS_A_YEAR = {'monday': 51,
|
||||||
'tuesday': 50,
|
'tuesday': 50,
|
||||||
'wednesday': 50,
|
'wednesday': 50,
|
||||||
'thursday': 50,
|
'thursday': 50,
|
||||||
|
@ -66,6 +66,19 @@ DAYS_A_YEAR = {'monday': 51,
|
||||||
'sunday': 52,
|
'sunday': 52,
|
||||||
'holiday': 10}
|
'holiday': 10}
|
||||||
|
|
||||||
|
DAYS_A_MONTH = {'January': 31,
|
||||||
|
'February': 28,
|
||||||
|
'March': 31,
|
||||||
|
'April': 30,
|
||||||
|
'May': 31,
|
||||||
|
'June': 30,
|
||||||
|
'July': 31,
|
||||||
|
'August': 31,
|
||||||
|
'September': 30,
|
||||||
|
'October': 31,
|
||||||
|
'November': 30,
|
||||||
|
'December': 31}
|
||||||
|
|
||||||
# data types
|
# data types
|
||||||
ANY_NUMBER = 'any_number'
|
ANY_NUMBER = 'any_number'
|
||||||
FRACTION = 'fraction'
|
FRACTION = 'fraction'
|
||||||
|
|
|
@ -3,55 +3,46 @@ Monthly values module
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
|
Copyright © 2020 Project Author Pilar Monsalvete pilar_monsalvete@yahoo.es
|
||||||
"""
|
"""
|
||||||
import calendar as cal
|
|
||||||
import pandas as pd
|
import hub.helpers.constants as cte
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
|
|
||||||
class MonthlyValues:
|
class MonthlyValues:
|
||||||
"""
|
"""
|
||||||
Monthly values class
|
Monthly values class
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
@staticmethod
|
||||||
self._month_hour = None
|
def get_mean_values(values):
|
||||||
|
|
||||||
def get_mean_values(self, values):
|
|
||||||
"""
|
"""
|
||||||
Calculates the mean values for each month
|
Calculates the mean values for each month from a list with hourly values
|
||||||
:return: DataFrame(float)
|
:return: [float] x 12
|
||||||
|
:param values: [float] x 8760
|
||||||
"""
|
"""
|
||||||
out = None
|
out = []
|
||||||
if values is not None:
|
if values is not None:
|
||||||
if 'month' not in values.columns:
|
for month in cte.DAYS_A_MONTH:
|
||||||
values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1)
|
total = 0
|
||||||
out = values.groupby('month', as_index=False).mean()
|
for j in range(0, cte.DAYS_A_MONTH[month]):
|
||||||
del out['month']
|
for k in range(0, 24):
|
||||||
|
hour = k + 24 * j + cte.DAYS_A_MONTH[month] - 31
|
||||||
|
total += values[hour] / 24 / cte.DAYS_A_MONTH[month]
|
||||||
|
out.append(total)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def get_total_month(self, values):
|
@staticmethod
|
||||||
|
def get_total_month(values):
|
||||||
"""
|
"""
|
||||||
Calculates the total value for each month
|
Calculates the total value for each month
|
||||||
:return: DataFrame(int)
|
:return: [float] x 12
|
||||||
|
:param values: [float] x 8760
|
||||||
"""
|
"""
|
||||||
out = None
|
out = []
|
||||||
if values is not None:
|
if values is not None:
|
||||||
if 'month' not in values.columns:
|
for month in cte.DAYS_A_MONTH:
|
||||||
values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1)
|
total = 0
|
||||||
out = pd.DataFrame(values).groupby('month', as_index=False).sum()
|
for j in range(0, cte.DAYS_A_MONTH[month]):
|
||||||
del out['month']
|
for k in range(0, 24):
|
||||||
|
hour = k + 24 * j + cte.DAYS_A_MONTH[month] - 31
|
||||||
|
total += values[hour]
|
||||||
|
out.append(total)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@property
|
|
||||||
def month_hour(self):
|
|
||||||
"""
|
|
||||||
returns a DataFrame that has x values of the month number (January = 1, February = 2...),
|
|
||||||
being x the number of hours of the corresponding month
|
|
||||||
:return: DataFrame(int)
|
|
||||||
"""
|
|
||||||
array = []
|
|
||||||
for i in range(0, 12):
|
|
||||||
days_of_month = cal.monthrange(2015, i+1)[1]
|
|
||||||
total_hours = days_of_month * 24
|
|
||||||
array = np.concatenate((array, np.full(total_hours, i + 1)))
|
|
||||||
self._month_hour = pd.DataFrame(array, columns=['month'])
|
|
||||||
return self._month_hour
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ class LoadsCalculation:
|
||||||
internal_load = cooling_load_occupancy_sensible + cooling_load_lighting + cooling_load_equipment_sensible
|
internal_load = cooling_load_occupancy_sensible + cooling_load_lighting + cooling_load_equipment_sensible
|
||||||
return internal_load
|
return internal_load
|
||||||
|
|
||||||
def get_radiation_load(self, irradiance_format, hour):
|
def get_radiation_load(self, hour):
|
||||||
"""
|
"""
|
||||||
Calculates the radiation load
|
Calculates the radiation load
|
||||||
:return: int
|
:return: int
|
||||||
|
@ -142,7 +142,7 @@ class LoadsCalculation:
|
||||||
for thermal_zone in internal_zone.thermal_zones:
|
for thermal_zone in internal_zone.thermal_zones:
|
||||||
for thermal_boundary in thermal_zone.thermal_boundaries:
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||||
for thermal_opening in thermal_boundary.thermal_openings:
|
for thermal_opening in thermal_boundary.thermal_openings:
|
||||||
radiation = thermal_boundary.parent_surface.global_irradiance[cte.HOUR][irradiance_format][hour]
|
radiation = thermal_boundary.parent_surface.global_irradiance[cte.HOUR][hour]
|
||||||
cooling_load_radiation += (
|
cooling_load_radiation += (
|
||||||
thermal_opening.area * (1 - thermal_opening.frame_ratio) * thermal_opening.g_value * radiation
|
thermal_opening.area * (1 - thermal_opening.frame_ratio) * thermal_opening.g_value * radiation
|
||||||
)
|
)
|
||||||
|
|
|
@ -54,11 +54,13 @@ class PeakLoads:
|
||||||
"""
|
"""
|
||||||
month = 1
|
month = 1
|
||||||
peaks = [0 for _ in range(12)]
|
peaks = [0 for _ in range(12)]
|
||||||
for i, value in enumerate(hourly_values):
|
print('hv', hourly_values)
|
||||||
|
for i in range(0, len(hourly_values)):
|
||||||
if _MONTH_STARTING_HOUR[month] <= i:
|
if _MONTH_STARTING_HOUR[month] <= i:
|
||||||
month += 1
|
month += 1
|
||||||
if value > peaks[month-1]:
|
if hourly_values[i] > peaks[month-1]:
|
||||||
peaks[month-1] = value
|
peaks[month-1] = hourly_values[i]
|
||||||
|
print('peak', peaks)
|
||||||
return peaks
|
return peaks
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -70,7 +72,7 @@ class PeakLoads:
|
||||||
if not self._can_be_calculated():
|
if not self._can_be_calculated():
|
||||||
return None
|
return None
|
||||||
monthly_heating_loads = []
|
monthly_heating_loads = []
|
||||||
ambient_temperature = self._building.external_temperature[cte.HOUR]['epw']
|
ambient_temperature = self._building.external_temperature[cte.HOUR]
|
||||||
for month in range(0, 12):
|
for month in range(0, 12):
|
||||||
ground_temperature = self._building.ground_temperature[cte.MONTH]['2'][month]
|
ground_temperature = self._building.ground_temperature[cte.MONTH]['2'][month]
|
||||||
heating_ambient_temperature = 100
|
heating_ambient_temperature = 100
|
||||||
|
@ -100,7 +102,7 @@ class PeakLoads:
|
||||||
if not self._can_be_calculated():
|
if not self._can_be_calculated():
|
||||||
return None
|
return None
|
||||||
monthly_cooling_loads = []
|
monthly_cooling_loads = []
|
||||||
ambient_temperature = self._building.external_temperature[cte.HOUR]['epw']
|
ambient_temperature = self._building.external_temperature[cte.HOUR]
|
||||||
for month in range(0, 12):
|
for month in range(0, 12):
|
||||||
ground_temperature = self._building.ground_temperature[cte.MONTH]['2'][month]
|
ground_temperature = self._building.ground_temperature[cte.MONTH]['2'][month]
|
||||||
cooling_ambient_temperature = -100
|
cooling_ambient_temperature = -100
|
||||||
|
@ -118,7 +120,7 @@ class PeakLoads:
|
||||||
cooling_load_transmitted = loads.get_cooling_transmitted_load(cooling_ambient_temperature, ground_temperature)
|
cooling_load_transmitted = loads.get_cooling_transmitted_load(cooling_ambient_temperature, ground_temperature)
|
||||||
cooling_load_renovation_sensible = loads.get_cooling_ventilation_load_sensible(cooling_ambient_temperature)
|
cooling_load_renovation_sensible = loads.get_cooling_ventilation_load_sensible(cooling_ambient_temperature)
|
||||||
cooling_load_internal_gains_sensible = loads.get_internal_load_sensible()
|
cooling_load_internal_gains_sensible = loads.get_internal_load_sensible()
|
||||||
cooling_load_radiation = loads.get_radiation_load('sra', cooling_calculation_hour)
|
cooling_load_radiation = loads.get_radiation_load(cooling_calculation_hour)
|
||||||
cooling_load_sensible = cooling_load_transmitted + cooling_load_renovation_sensible - cooling_load_radiation \
|
cooling_load_sensible = cooling_load_transmitted + cooling_load_renovation_sensible - cooling_load_radiation \
|
||||||
- cooling_load_internal_gains_sensible
|
- cooling_load_internal_gains_sensible
|
||||||
|
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
"""
|
|
||||||
AirSourceHeatPumpParameters import the heat pump information
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Peter Yefi peteryefi@gmail.comCode
|
|
||||||
contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
||||||
"""
|
|
||||||
import io
|
|
||||||
|
|
||||||
import itertools
|
|
||||||
from typing import List
|
|
||||||
from typing import Dict
|
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
|
||||||
from scipy.optimize import curve_fit
|
|
||||||
from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP
|
|
||||||
from hub.city_model_structure.energy_system import EnergySystem
|
|
||||||
|
|
||||||
|
|
||||||
class AirSourceHeatPumpParameters:
|
|
||||||
"""
|
|
||||||
AirSourceHeatPumpParameters class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, city, base_path):
|
|
||||||
self._city = city
|
|
||||||
self._base_path = (base_path / 'heat_pumps/air_source.xlsx').resolve()
|
|
||||||
|
|
||||||
def _read_file(self) -> Dict:
|
|
||||||
"""
|
|
||||||
reads xlsx file containing the heat pump information
|
|
||||||
into a dictionary
|
|
||||||
:return : Dict
|
|
||||||
"""
|
|
||||||
with open(self._base_path, 'rb') as xls:
|
|
||||||
xl_file = pd.read_excel(io.BytesIO(xls.read()), sheet_name=None)
|
|
||||||
|
|
||||||
cooling_data = {}
|
|
||||||
heating_data = {}
|
|
||||||
|
|
||||||
for sheet, _ in xl_file.items():
|
|
||||||
if 'Summary' in sheet:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Remove nan rows and columns and extract cooling and heating data
|
|
||||||
# for each sheet
|
|
||||||
df = xl_file[sheet].dropna(axis=1, how='all')
|
|
||||||
cooling_df = df.iloc[4:34, 0:8]
|
|
||||||
heating_df = df.iloc[4:29, 8:20]
|
|
||||||
|
|
||||||
# extract the data into dictionaries each sheet is a key entry in the
|
|
||||||
# dictionary
|
|
||||||
cooling_data[sheet] = {}
|
|
||||||
heating_data[sheet] = {}
|
|
||||||
i = 0
|
|
||||||
# for each sheet extract data for twout/Ta.RU temperatures. Thus, the twout
|
|
||||||
# temp is the key for the values of pf,pa,qw data
|
|
||||||
while i < 25:
|
|
||||||
cooling_data[sheet][cooling_df.iloc[i][0]] = cooling_df.iloc[i + 1:i + 4, 2:8].values.tolist()
|
|
||||||
heating_data[sheet][heating_df.iloc[i][0]] = heating_df.iloc[i + 1:i + 4, 2:8].values.tolist()
|
|
||||||
i = i + 5
|
|
||||||
# extract the last cooling data
|
|
||||||
cooling_data[sheet][cooling_df.iloc[i][0]] = cooling_df.iloc[i + 1:i + 4, 2:8].values.tolist()
|
|
||||||
return {"cooling": cooling_data, "heating": heating_data}
|
|
||||||
|
|
||||||
def enrich_city(self):
|
|
||||||
"""
|
|
||||||
Enriches the city with information from file
|
|
||||||
"""
|
|
||||||
heat_pump_data = self._read_file()
|
|
||||||
for (k_cool, v_cool), (_, v_heat) in zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()):
|
|
||||||
heat_pump = AirSourceHP()
|
|
||||||
heat_pump.model = k_cool
|
|
||||||
h_data = self._extract_heat_pump_data(v_heat)
|
|
||||||
c_data = self._extract_heat_pump_data(v_cool)
|
|
||||||
heat_pump.cooling_capacity = c_data[0]
|
|
||||||
heat_pump.cooling_comp_power = c_data[1]
|
|
||||||
heat_pump.cooling_capacity_coff = self._compute_coefficients(c_data, "cool")
|
|
||||||
heat_pump.heating_capacity = h_data[0]
|
|
||||||
heat_pump.heating_comp_power = h_data[1]
|
|
||||||
heat_pump.heating_capacity_coff = self._compute_coefficients(h_data)
|
|
||||||
|
|
||||||
energy_system = EnergySystem(f'{heat_pump.model} capacity heat pump', [])
|
|
||||||
energy_system.air_source_hp = heat_pump
|
|
||||||
self._city.add_city_object(energy_system)
|
|
||||||
return self._city
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _extract_heat_pump_data(heat_pump_capacity_data: Dict) -> [List, List]:
|
|
||||||
"""
|
|
||||||
Fetches a list of metric based data for heat pump for various temperature,
|
|
||||||
e.g. cooling capacity data for 12 capacity heat pump
|
|
||||||
for 6,7,8,9,10 and 11 degree Celsius
|
|
||||||
:param heat_pump_capacity_data: the heat pump capacity data from the
|
|
||||||
which the metric specific data is fetched: {List}
|
|
||||||
:return: List
|
|
||||||
"""
|
|
||||||
cooling_heating_capacity_data = []
|
|
||||||
compressor_power_data = []
|
|
||||||
for _, metric_data in heat_pump_capacity_data.items():
|
|
||||||
cooling_heating_capacity_data.append(metric_data[0])
|
|
||||||
compressor_power_data.append(metric_data[1])
|
|
||||||
return [cooling_heating_capacity_data, compressor_power_data]
|
|
||||||
|
|
||||||
def _compute_coefficients(self, heat_pump_data: List, data_type="heat") -> List[float]:
|
|
||||||
"""
|
|
||||||
Compute heat output and electrical demand coefficients
|
|
||||||
from heating and cooling performance data
|
|
||||||
:param heat_pump_data: a list of heat pump data. e.g. cooling capacity
|
|
||||||
:param data_type: string to indicate if data is cooling performance data
|
|
||||||
or heating performance data
|
|
||||||
:return: Tuple[Dict, Dict]
|
|
||||||
"""
|
|
||||||
# Determine the recurrence of temperature values. 6 repetitions for
|
|
||||||
# cooling performance and 5 repetition for heating performance
|
|
||||||
temp_multiplier = 5 if data_type == "heat" else 6
|
|
||||||
out_temp = [25, 30, 32, 35, 40, 45] * temp_multiplier
|
|
||||||
|
|
||||||
heat_x_values = np.repeat([-5, 0, 7, 10, 15], 6)
|
|
||||||
cool_x_values = np.repeat([6, 7, 8, 9, 10, 11], 6)
|
|
||||||
x_values = heat_x_values if data_type == "heat" else cool_x_values
|
|
||||||
x_values = x_values.tolist()
|
|
||||||
# convert list of lists to one list
|
|
||||||
|
|
||||||
hp_data = [i / j for i, j in
|
|
||||||
zip(list(itertools.chain.from_iterable(heat_pump_data[0])),
|
|
||||||
list(itertools.chain.from_iterable(heat_pump_data[1])))]
|
|
||||||
|
|
||||||
# Compute heat output coefficients
|
|
||||||
popt, _ = curve_fit(self._objective_function, [x_values, out_temp], hp_data)
|
|
||||||
return popt.tolist()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _objective_function(xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float) -> float:
|
|
||||||
"""
|
|
||||||
Objective function for computing coefficients
|
|
||||||
:param xdata:
|
|
||||||
:param a1: float
|
|
||||||
:param a2: float
|
|
||||||
:param a3: float
|
|
||||||
:param a4: float
|
|
||||||
:param a5: float
|
|
||||||
:param a6: float
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
x, y = xdata
|
|
||||||
return (a1 * x ** 2) + (a2 * x) + (a3 * x * y) + (a4 * y) + (a5 * y ** 2) + a6
|
|
|
@ -1,29 +0,0 @@
|
||||||
"""
|
|
||||||
Energy systems helper
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
||||||
"""
|
|
||||||
|
|
||||||
from hub.helpers import constants as cte
|
|
||||||
|
|
||||||
|
|
||||||
class EnergySystemsHelper:
|
|
||||||
"""
|
|
||||||
EnergySystems helper
|
|
||||||
"""
|
|
||||||
_montreal_custom_fuel_to_hub_fuel = {
|
|
||||||
'gas': cte.GAS,
|
|
||||||
'electricity': cte.ELECTRICITY,
|
|
||||||
'renewable': cte.RENEWABLE
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def montreal_custom_fuel_to_hub_fuel(fuel):
|
|
||||||
"""
|
|
||||||
Get hub fuel from montreal_custom catalog fuel
|
|
||||||
:param fuel: str
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
return EnergySystemsHelper._montreal_custom_fuel_to_hub_fuel[fuel]
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ from hub.city_model_structure.energy_systems.generation_system import Generation
|
||||||
from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem
|
from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem
|
||||||
from hub.city_model_structure.energy_systems.emission_system import EmissionSystem
|
from hub.city_model_structure.energy_systems.emission_system import EmissionSystem
|
||||||
from hub.helpers.dictionaries import Dictionaries
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
from hub.imports.energy_systems.helpers.energy_systems_helper import EnergySystemsHelper
|
|
||||||
|
|
||||||
|
|
||||||
class MontrealCustomEnergySystemParameters:
|
class MontrealCustomEnergySystemParameters:
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
"""
|
|
||||||
WaterToWaterHPParameters import the heat pump information
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Peter Yefi peteryefi@gmail.com
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import Dict
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import pandas as pd
|
|
||||||
from scipy.optimize import curve_fit
|
|
||||||
|
|
||||||
from hub.city_model_structure.energy_system import EnergySystem
|
|
||||||
from hub.city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP
|
|
||||||
|
|
||||||
|
|
||||||
class WaterToWaterHPParameters:
|
|
||||||
"""
|
|
||||||
WaterToWaterHPParameters class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, city, base_path):
|
|
||||||
self._city = city
|
|
||||||
self._base_path = (base_path / 'heat_pumps/water_to_water.xlsx').resolve()
|
|
||||||
|
|
||||||
def _read_file(self) -> Dict:
|
|
||||||
# todo: this method is keeping the excel file open and should be either corrected or removed
|
|
||||||
xl_file = pd.ExcelFile(self._base_path)
|
|
||||||
heat_pump_dfs = {sheet_name: xl_file.parse(sheet_name)
|
|
||||||
for sheet_name in xl_file.sheet_names}
|
|
||||||
|
|
||||||
hp_data = {}
|
|
||||||
flow_rates = {
|
|
||||||
'156': [2.84, 4.23, 5.68],
|
|
||||||
'256': [4.73, 7.13, 9.446],
|
|
||||||
'335': [6.62, 9.97, 12.93],
|
|
||||||
}
|
|
||||||
|
|
||||||
for sheet, _ in heat_pump_dfs.items():
|
|
||||||
|
|
||||||
df = heat_pump_dfs[sheet].dropna(axis=1, how='all')
|
|
||||||
df = df.iloc[3:, 6:35]
|
|
||||||
|
|
||||||
if '156' in sheet:
|
|
||||||
hp_data[sheet] = self._extract_required_hp_data(df, [0, 10, 25, 40, 55, 67], flow_rates['156'])
|
|
||||||
elif '256' in sheet:
|
|
||||||
hp_data[sheet] = self._extract_required_hp_data(df, [0, 9, 24, 39, 54, 66], flow_rates['256'])
|
|
||||||
elif '335' in sheet:
|
|
||||||
hp_data[sheet] = self._extract_required_hp_data(df, [0, 11, 26, 41, 56, 69], flow_rates['335'])
|
|
||||||
|
|
||||||
return hp_data
|
|
||||||
|
|
||||||
def _extract_required_hp_data(self, dataframe, ranges, flow_rates):
|
|
||||||
"""
|
|
||||||
Extracts 156 Kw water to water heat pump data
|
|
||||||
:param dataframe: dataframe containing all data
|
|
||||||
:param ranges: the range of values to extract
|
|
||||||
:param flow_rates: the flow rates of water through pump
|
|
||||||
:return: Dict
|
|
||||||
"""
|
|
||||||
# extract data rows and columns
|
|
||||||
data = {'tc': self._extract_hp_data(dataframe, [1, 11, 21], ranges),
|
|
||||||
'pd': self._extract_hp_data(dataframe, [2, 12, 22], ranges),
|
|
||||||
'lwt': self._extract_hp_data(dataframe, [5, 15, 25], ranges),
|
|
||||||
'fr': (self._extract_flow_and_ewt(dataframe, ranges, [1, 11, 21], flow_rates))[0],
|
|
||||||
'ewt': (self._extract_flow_and_ewt(dataframe, ranges, [1, 11, 21], flow_rates))[1]}
|
|
||||||
# range values for extracting data
|
|
||||||
return data
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _extract_hp_data(df, columns, ranges):
|
|
||||||
"""
|
|
||||||
Extract variable specific (LWT, PD or TC) data from water to water hp
|
|
||||||
:param df: the dataframe
|
|
||||||
:param columns: the columns to extract data from
|
|
||||||
:param ranges: the range of values to extract
|
|
||||||
:return: List
|
|
||||||
"""
|
|
||||||
data = pd.concat([df.iloc[ranges[0]:ranges[1], columns[0]], df.iloc[ranges[0]:ranges[1], columns[1]]])
|
|
||||||
data = pd.concat([df.iloc[ranges[0]:ranges[1], columns[2]], data])
|
|
||||||
for i in range(1, 5):
|
|
||||||
data = pd.concat([df.iloc[ranges[i]:ranges[i + 1], columns[0]], data])
|
|
||||||
data = pd.concat([df.iloc[ranges[i]:ranges[i + 1], columns[1]], data])
|
|
||||||
data = pd.concat([df.iloc[ranges[i]:ranges[i + 1], columns[2]], data])
|
|
||||||
|
|
||||||
return data.dropna().values.tolist()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _extract_flow_and_ewt(df, ranges, columns, flow_rates):
|
|
||||||
"""
|
|
||||||
Create the flow and ewt data based on the length of the various
|
|
||||||
columns for the variables being extracted
|
|
||||||
:param df: the dataframe
|
|
||||||
:param ranges: the range of values to extract
|
|
||||||
:param columns: the columns to extract data from
|
|
||||||
:param flow_rates: flow rate values
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
ewt_values = [-1.111111111, 4.444444444, 10, 15.55555556, 21.11111111]
|
|
||||||
length = [len(df.iloc[ranges[0]:ranges[1], columns[0]].dropna()),
|
|
||||||
len(df.iloc[ranges[0]:ranges[1], columns[1]].dropna()),
|
|
||||||
len(df.iloc[ranges[0]:ranges[1], columns[2]].dropna())]
|
|
||||||
|
|
||||||
ewt_data = np.repeat(ewt_values[0], sum(length))
|
|
||||||
flow_rates_data = np.repeat(flow_rates, length)
|
|
||||||
|
|
||||||
for i in range(1, 5):
|
|
||||||
length = [len(df.iloc[ranges[i]:ranges[i + 1], columns[0]].dropna()),
|
|
||||||
len(df.iloc[ranges[i]:ranges[i + 1], columns[1]].dropna()),
|
|
||||||
len(df.iloc[ranges[i]:ranges[i + 1], columns[2]].dropna())]
|
|
||||||
flow_rates_data = np.append(flow_rates_data, np.repeat(flow_rates, length))
|
|
||||||
ewt_data = np.append(ewt_data, np.repeat(ewt_values[i], sum(length)))
|
|
||||||
|
|
||||||
return flow_rates_data.tolist(), ewt_data.tolist()
|
|
||||||
|
|
||||||
def enrich_city(self):
|
|
||||||
"""
|
|
||||||
Enriches the city with information from file
|
|
||||||
"""
|
|
||||||
heap_pump_data = self._read_file()
|
|
||||||
for model, data in heap_pump_data.items():
|
|
||||||
heat_pump = WaterToWaterHP()
|
|
||||||
heat_pump.model = model.strip()
|
|
||||||
heat_pump.total_cooling_capacity = data['tc']
|
|
||||||
heat_pump.power_demand = data['pd']
|
|
||||||
heat_pump.flow_rate = data['fr']
|
|
||||||
heat_pump.entering_water_temp = data['ewt']
|
|
||||||
heat_pump.leaving_water_temp = data['lwt']
|
|
||||||
heat_pump.power_demand_coff = self._compute_coefficients(data)
|
|
||||||
energy_system = EnergySystem(heat_pump.model, [])
|
|
||||||
energy_system.water_to_water_hp = heat_pump
|
|
||||||
self._city.add_city_object(energy_system)
|
|
||||||
return self._city
|
|
||||||
|
|
||||||
def _compute_coefficients(self, heat_pump_data: Dict) -> List[float]:
|
|
||||||
"""
|
|
||||||
Compute heat output and electrical demand coefficients
|
|
||||||
from heating performance data
|
|
||||||
:param heat_pump_data: a dictionary of heat pump data.
|
|
||||||
:return: Tuple[Dict, Dict]
|
|
||||||
"""
|
|
||||||
demand = [i / j for i, j in zip(heat_pump_data['tc'], heat_pump_data['pd'])]
|
|
||||||
|
|
||||||
# Compute heat output coefficients
|
|
||||||
popt, _ = curve_fit(
|
|
||||||
self._objective_function, [heat_pump_data['ewt'], heat_pump_data['lwt'], heat_pump_data['fr']], demand
|
|
||||||
)
|
|
||||||
return popt.tolist()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _objective_function(xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float,
|
|
||||||
a7: float, a8: float, a9: float, a10: float, a11: float) -> float:
|
|
||||||
"""
|
|
||||||
Objective function for computing coefficients
|
|
||||||
:param xdata:
|
|
||||||
:param a1: float
|
|
||||||
:param a2: float
|
|
||||||
:param a3: float
|
|
||||||
:param a4: float
|
|
||||||
:param a5: float
|
|
||||||
:param a6: float
|
|
||||||
:param a7: float
|
|
||||||
:param a8: float
|
|
||||||
:param a9: float
|
|
||||||
:param a10: float
|
|
||||||
:param a11: float
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
x, y, t = xdata
|
|
||||||
return (a1 * x ** 2) + (a2 * x) + (a3 * y ** 2) + (a4 * y) + (a5 * t ** 2) + (a6 * t) + (a7 * x * y) + (
|
|
||||||
a8 * x * t) + (a9 * y * t) + (a10 * x * y * t) + a11
|
|
|
@ -8,9 +8,7 @@ Code contributors: Peter Yefi peteryefi@gmail.com
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from hub.helpers.utils import validate_import_export_type
|
from hub.helpers.utils import validate_import_export_type
|
||||||
from hub.imports.energy_systems.air_source_hp_parameters import AirSourceHeatPumpParameters
|
|
||||||
from hub.imports.energy_systems.montreal_custom_energy_system_parameters import MontrealCustomEnergySystemParameters
|
from hub.imports.energy_systems.montreal_custom_energy_system_parameters import MontrealCustomEnergySystemParameters
|
||||||
from hub.imports.energy_systems.water_to_water_hp_parameters import WaterToWaterHPParameters
|
|
||||||
|
|
||||||
|
|
||||||
class EnergySystemsFactory:
|
class EnergySystemsFactory:
|
||||||
|
@ -26,24 +24,6 @@ class EnergySystemsFactory:
|
||||||
self._city = city
|
self._city = city
|
||||||
self._base_path = base_path
|
self._base_path = base_path
|
||||||
|
|
||||||
def _air_source_hp(self):
|
|
||||||
"""
|
|
||||||
Enrich the city by using xlsx heat pump information
|
|
||||||
"""
|
|
||||||
AirSourceHeatPumpParameters(self._city, self._base_path).enrich_city()
|
|
||||||
self._city.level_of_detail.energy_systems = 0
|
|
||||||
for building in self._city.buildings:
|
|
||||||
building.level_of_detail.energy_systems = 0
|
|
||||||
|
|
||||||
def _water_to_water_hp(self):
|
|
||||||
"""
|
|
||||||
Enrich the city by using water to water heat pump information
|
|
||||||
"""
|
|
||||||
WaterToWaterHPParameters(self._city, self._base_path).enrich_city()
|
|
||||||
self._city.level_of_detail.energy_systems = 0
|
|
||||||
for building in self._city.buildings:
|
|
||||||
building.level_of_detail.energy_systems = 0
|
|
||||||
|
|
||||||
def _montreal_custom(self):
|
def _montreal_custom(self):
|
||||||
"""
|
"""
|
||||||
Enrich the city by using montreal custom energy systems catalog information
|
Enrich the city by using montreal custom energy systems catalog information
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
"""
|
|
||||||
gpandas module parses geopandas input table and import the geometry into the city model structure
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder: Milad Aghamohamadnia --- milad.aghamohamadnia@concordia.ca
|
|
||||||
"""
|
|
||||||
|
|
||||||
import trimesh
|
|
||||||
import trimesh.exchange.load
|
|
||||||
import trimesh.geometry
|
|
||||||
import trimesh.creation
|
|
||||||
import trimesh.repair
|
|
||||||
from shapely.geometry import Point
|
|
||||||
from shapely.geometry import Polygon as ShapelyPoly
|
|
||||||
from trimesh import Scene
|
|
||||||
|
|
||||||
from hub.city_model_structure.attributes.polygon import Polygon
|
|
||||||
from hub.city_model_structure.building import Building
|
|
||||||
from hub.city_model_structure.building_demand.surface import Surface
|
|
||||||
from hub.city_model_structure.city import City
|
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
|
|
||||||
|
|
||||||
class GPandas:
|
|
||||||
"""
|
|
||||||
GeoPandas class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, dataframe, srs_name='EPSG:26911'):
|
|
||||||
"""_summary_
|
|
||||||
Arguments:
|
|
||||||
dataframe {Geopandas.Dataframe} -- input geometry data in geopandas table
|
|
||||||
Keyword Arguments:
|
|
||||||
srs_name {str} -- coordinate system of coordinate system (default: {'EPSG:26911'})
|
|
||||||
"""
|
|
||||||
|
|
||||||
self._srs_name = srs_name
|
|
||||||
self._city = None
|
|
||||||
self._scene = dataframe
|
|
||||||
self._scene = self._scene.to_crs(self._srs_name)
|
|
||||||
min_x, min_y, max_x, max_y = self._scene.total_bounds
|
|
||||||
self._lower_corner = [min_x, min_y, 0]
|
|
||||||
self._upper_corner = [max_x, max_y, 0]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def scene(self) -> Scene:
|
|
||||||
"""
|
|
||||||
Get GeoPandas scene
|
|
||||||
"""
|
|
||||||
return self._scene
|
|
||||||
|
|
||||||
@property
|
|
||||||
def city(self) -> City:
|
|
||||||
"""
|
|
||||||
Get city out of a GeoPandas Table
|
|
||||||
"""
|
|
||||||
if self._city is None:
|
|
||||||
self._city = City(self._lower_corner, self._upper_corner, self._srs_name)
|
|
||||||
lod = 0
|
|
||||||
for _, bldg in self._scene.iterrows():
|
|
||||||
polygon = bldg.geometry
|
|
||||||
height = float(bldg['height'])
|
|
||||||
building_mesh = trimesh.creation.extrude_polygon(polygon, height)
|
|
||||||
trimesh.repair.fill_holes(building_mesh)
|
|
||||||
trimesh.repair.fix_winding(building_mesh)
|
|
||||||
year_of_construction = int(bldg['year_built'])
|
|
||||||
name = bldg['name']
|
|
||||||
lod = 1
|
|
||||||
if year_of_construction > 2000:
|
|
||||||
function = cte.RESIDENTIAL
|
|
||||||
else:
|
|
||||||
function = cte.INDUSTRY
|
|
||||||
surfaces = []
|
|
||||||
for _, face in enumerate(building_mesh.faces):
|
|
||||||
points = []
|
|
||||||
for vertex_index in face:
|
|
||||||
points.append(building_mesh.vertices[vertex_index])
|
|
||||||
solid_polygon = Polygon(points)
|
|
||||||
perimeter_polygon = solid_polygon
|
|
||||||
surface = Surface(solid_polygon, perimeter_polygon)
|
|
||||||
surfaces.append(surface)
|
|
||||||
building = Building(name, surfaces, year_of_construction, function, terrains=None)
|
|
||||||
self._city.add_city_object(building)
|
|
||||||
self._city.level_of_detail.geometry = lod
|
|
||||||
for building in self._city.buildings:
|
|
||||||
building.level_of_detail.geometry = lod
|
|
||||||
return self._city
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def resize_polygon(poly, factor=0.10, expand=False) -> ShapelyPoly:
|
|
||||||
"""
|
|
||||||
returns the shapely polygon which is smaller or bigger by passed factor.
|
|
||||||
Arguments:
|
|
||||||
poly {shapely.geometry.Polygon} -- an input geometry in shapely polygon format
|
|
||||||
|
|
||||||
Keyword Arguments:
|
|
||||||
factor {float} -- factor of expansion (default: {0.10})
|
|
||||||
expand {bool} -- If expand = True , then it returns bigger polygon, else smaller (default: {False})
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
{shapely.geometry.Polygon} -- output geometry in shapely polygon format
|
|
||||||
"""
|
|
||||||
xs = list(poly.exterior.coords.xy[0])
|
|
||||||
ys = list(poly.exterior.coords.xy[1])
|
|
||||||
x_center = 0.5 * min(xs) + 0.5 * max(xs)
|
|
||||||
y_center = 0.5 * min(ys) + 0.5 * max(ys)
|
|
||||||
min_corner = Point(min(xs), min(ys))
|
|
||||||
center = Point(x_center, y_center)
|
|
||||||
shrink_distance = center.distance(min_corner) * factor
|
|
||||||
|
|
||||||
if expand:
|
|
||||||
poly_resized = poly.buffer(shrink_distance) # expand
|
|
||||||
else:
|
|
||||||
poly_resized = poly.buffer(-shrink_distance) # shrink
|
|
||||||
return poly_resized
|
|
|
@ -4,13 +4,11 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
import geopandas
|
|
||||||
|
|
||||||
from hub.city_model_structure.city import City
|
from hub.city_model_structure.city import City
|
||||||
from hub.helpers.utils import validate_import_export_type
|
from hub.helpers.utils import validate_import_export_type
|
||||||
from hub.imports.geometry.citygml import CityGml
|
from hub.imports.geometry.citygml import CityGml
|
||||||
from hub.imports.geometry.geojson import Geojson
|
from hub.imports.geometry.geojson import Geojson
|
||||||
from hub.imports.geometry.gpandas import GPandas
|
|
||||||
from hub.imports.geometry.obj import Obj
|
from hub.imports.geometry.obj import Obj
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,16 +54,6 @@ class GeometryFactory:
|
||||||
"""
|
"""
|
||||||
return Obj(self._path).city
|
return Obj(self._path).city
|
||||||
|
|
||||||
@property
|
|
||||||
def _gpandas(self) -> City:
|
|
||||||
"""
|
|
||||||
Enrich the city by using GeoPandas information as data source
|
|
||||||
:return: City
|
|
||||||
"""
|
|
||||||
if self._data_frame is None:
|
|
||||||
self._data_frame = geopandas.read_file(self._path)
|
|
||||||
return GPandas(self._data_frame).city
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _geojson(self) -> City:
|
def _geojson(self) -> City:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
"""
|
|
||||||
Insel Heap pump energy demand and fossil fuel consumption
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2023 Concordia CERC group
|
|
||||||
Project Coder peter.yefi@gmail.cm
|
|
||||||
"""
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
|
|
||||||
class InselHeatPumpEnergyDemand:
|
|
||||||
"""
|
|
||||||
Import Energy demand and fossil fuel consumption results
|
|
||||||
"""
|
|
||||||
def __init__(self, city, base_path, hp_model):
|
|
||||||
"""
|
|
||||||
:param city: the city
|
|
||||||
:param base_path: the insel simulation output file
|
|
||||||
:param hp_model: the heatpump model for both air source and water to water
|
|
||||||
"""
|
|
||||||
self._city = city
|
|
||||||
self._hp_model = hp_model
|
|
||||||
with open(Path(base_path).resolve(), 'r', encoding='utf8') as csv_file:
|
|
||||||
df = pd.read_csv(csv_file)
|
|
||||||
self._monthly_electricity_demand = df.iloc[:, 1]
|
|
||||||
self._monthly_fossil_fuel_consumption = df.iloc[:, 2]
|
|
||||||
|
|
||||||
def enrich(self):
|
|
||||||
"""
|
|
||||||
Enrich the city with the heat pump information
|
|
||||||
"""
|
|
||||||
for energy_system in self._city.energy_systems:
|
|
||||||
if energy_system.air_source_hp is not None:
|
|
||||||
if energy_system.air_source_hp.model == self._hp_model:
|
|
||||||
energy_system.air_source_hp.hp_monthly_fossil_consumption = self._monthly_fossil_fuel_consumption
|
|
||||||
|
|
||||||
if energy_system.water_to_water_hp is not None:
|
|
||||||
if energy_system.water_to_water_hp.model == self._hp_model:
|
|
||||||
energy_system.water_to_water_hp.hp_monthly_electricity_demand = self._monthly_electricity_demand
|
|
|
@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guillermo.GutierrezMorote@concordia.ca
|
Project Coder Guillermo.GutierrezMorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import csv
|
import csv
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
@ -34,11 +34,9 @@ class InselMonthlyEnergyBalance:
|
||||||
demand[i] = str(aux)
|
demand[i] = str(aux)
|
||||||
else:
|
else:
|
||||||
demand[i] = '0'
|
demand[i] = '0'
|
||||||
heating.append(demand[0])
|
heating.append(float(demand[0]))
|
||||||
cooling.append(demand[1])
|
cooling.append(float(demand[1]))
|
||||||
monthly_heating = pd.DataFrame(heating, columns=[cte.INSEL_MEB]).astype(float)
|
return heating, cooling
|
||||||
monthly_cooling = pd.DataFrame(cooling, columns=[cte.INSEL_MEB]).astype(float)
|
|
||||||
return monthly_heating, monthly_cooling
|
|
||||||
|
|
||||||
def _dhw_and_electric_demand(self):
|
def _dhw_and_electric_demand(self):
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
|
@ -52,7 +50,7 @@ class InselMonthlyEnergyBalance:
|
||||||
else:
|
else:
|
||||||
thermal_zone = building.internal_zones[0].thermal_zones[0]
|
thermal_zone = building.internal_zones[0].thermal_zones[0]
|
||||||
area = thermal_zone.total_floor_area
|
area = thermal_zone.total_floor_area
|
||||||
cold_water = building.cold_water_temperature[cte.MONTH]['epw']
|
cold_water = building.cold_water_temperature[cte.MONTH]
|
||||||
peak_flow = thermal_zone.domestic_hot_water.peak_flow
|
peak_flow = thermal_zone.domestic_hot_water.peak_flow
|
||||||
service_temperature = thermal_zone.domestic_hot_water.service_temperature
|
service_temperature = thermal_zone.domestic_hot_water.service_temperature
|
||||||
lighting_density = thermal_zone.lighting.density
|
lighting_density = thermal_zone.lighting.density
|
||||||
|
@ -68,7 +66,7 @@ class InselMonthlyEnergyBalance:
|
||||||
for value in schedule.values:
|
for value in schedule.values:
|
||||||
total_day += value
|
total_day += value
|
||||||
for day_type in schedule.day_types:
|
for day_type in schedule.day_types:
|
||||||
total_lighting += total_day * cte.DAYS_A_MONTH[day_type][month] * lighting_density
|
total_lighting += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * lighting_density
|
||||||
lighting_demand.append(total_lighting * area)
|
lighting_demand.append(total_lighting * area)
|
||||||
|
|
||||||
for schedule in thermal_zone.appliances.schedules:
|
for schedule in thermal_zone.appliances.schedules:
|
||||||
|
@ -76,7 +74,7 @@ class InselMonthlyEnergyBalance:
|
||||||
for value in schedule.values:
|
for value in schedule.values:
|
||||||
total_day += value
|
total_day += value
|
||||||
for day_type in schedule.day_types:
|
for day_type in schedule.day_types:
|
||||||
total_appliances += total_day * cte.DAYS_A_MONTH[day_type][month] * appliances_density
|
total_appliances += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * appliances_density
|
||||||
appliances_demand.append(total_appliances * area)
|
appliances_demand.append(total_appliances * area)
|
||||||
|
|
||||||
for schedule in thermal_zone.domestic_hot_water.schedules:
|
for schedule in thermal_zone.domestic_hot_water.schedules:
|
||||||
|
@ -87,26 +85,15 @@ class InselMonthlyEnergyBalance:
|
||||||
demand = (
|
demand = (
|
||||||
peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * (service_temperature - cold_water[month])
|
peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * (service_temperature - cold_water[month])
|
||||||
)
|
)
|
||||||
total_dhw_demand += total_day * cte.DAYS_A_MONTH[day_type][month] * demand
|
total_dhw_demand += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * demand
|
||||||
domestic_hot_water_demand.append(total_dhw_demand * area)
|
domestic_hot_water_demand.append(total_dhw_demand * area)
|
||||||
|
|
||||||
building.domestic_hot_water_heat_demand[cte.MONTH] = pd.DataFrame(domestic_hot_water_demand,
|
building.domestic_hot_water_heat_demand[cte.MONTH] = domestic_hot_water_demand
|
||||||
columns=[cte.INSEL_MEB])
|
building.domestic_hot_water_heat_demand[cte.YEAR] = [sum(domestic_hot_water_demand)]
|
||||||
yearly_domestic_hot_water_demand = [sum(domestic_hot_water_demand)]
|
building.lighting_electrical_demand[cte.MONTH] = lighting_demand
|
||||||
building.domestic_hot_water_heat_demand[cte.YEAR] = pd.DataFrame(yearly_domestic_hot_water_demand,
|
building.lighting_electrical_demand[cte.YEAR] = [sum(lighting_demand)]
|
||||||
columns=[cte.INSEL_MEB])
|
building.appliances_electrical_demand[cte.MONTH] = appliances_demand
|
||||||
building.lighting_electrical_demand[cte.MONTH] = pd.DataFrame(lighting_demand, columns=[cte.INSEL_MEB])
|
building.appliances_electrical_demand[cte.YEAR] = [sum(appliances_demand)]
|
||||||
yearly_lighting_electrical_demand = [sum(lighting_demand)]
|
|
||||||
building.lighting_electrical_demand[cte.YEAR] = pd.DataFrame(
|
|
||||||
yearly_lighting_electrical_demand,
|
|
||||||
columns=[cte.INSEL_MEB]
|
|
||||||
)
|
|
||||||
building.appliances_electrical_demand[cte.MONTH] = pd.DataFrame(appliances_demand, columns=[cte.INSEL_MEB])
|
|
||||||
yearly_appliances_electrical_demand = [sum(appliances_demand)]
|
|
||||||
building.appliances_electrical_demand[cte.YEAR] = pd.DataFrame(
|
|
||||||
yearly_appliances_electrical_demand,
|
|
||||||
columns=[cte.INSEL_MEB]
|
|
||||||
)
|
|
||||||
|
|
||||||
def enrich(self):
|
def enrich(self):
|
||||||
"""
|
"""
|
||||||
|
@ -118,10 +105,6 @@ class InselMonthlyEnergyBalance:
|
||||||
insel_output_file_path = Path(self._base_path / file_name).resolve()
|
insel_output_file_path = Path(self._base_path / file_name).resolve()
|
||||||
if insel_output_file_path.is_file():
|
if insel_output_file_path.is_file():
|
||||||
building.heating_demand[cte.MONTH], building.cooling_demand[cte.MONTH] = self._conditioning_demand(insel_output_file_path)
|
building.heating_demand[cte.MONTH], building.cooling_demand[cte.MONTH] = self._conditioning_demand(insel_output_file_path)
|
||||||
building.heating_demand[cte.YEAR] = pd.DataFrame(
|
building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.MONTH])]
|
||||||
[building.heating_demand[cte.MONTH][cte.INSEL_MEB].astype(float).sum()], columns=[cte.INSEL_MEB]
|
building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.MONTH])]
|
||||||
)
|
|
||||||
building.cooling_demand[cte.YEAR] = pd.DataFrame(
|
|
||||||
[building.cooling_demand[cte.MONTH][cte.INSEL_MEB].astype(float).sum()], columns=[cte.INSEL_MEB]
|
|
||||||
)
|
|
||||||
self._dhw_and_electric_demand()
|
self._dhw_and_electric_demand()
|
||||||
|
|
|
@ -4,10 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guillermo.GutierrezMorote@concordia.ca
|
Project Coder Guillermo.GutierrezMorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
import calendar as cal
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
|
from hub.helpers.monthly_values import MonthlyValues
|
||||||
|
|
||||||
|
|
||||||
class SimplifiedRadiosityAlgorithm:
|
class SimplifiedRadiosityAlgorithm:
|
||||||
|
@ -19,54 +19,11 @@ class SimplifiedRadiosityAlgorithm:
|
||||||
self._city = city
|
self._city = city
|
||||||
self._base_path = base_path
|
self._base_path = base_path
|
||||||
self._input_file_path = (self._base_path / f'{self._city.name}_sra_SW.out').resolve()
|
self._input_file_path = (self._base_path / f'{self._city.name}_sra_SW.out').resolve()
|
||||||
self._month_hour = self._month_hour_data_frame
|
|
||||||
self._results = self._read_results()
|
|
||||||
self._radiation_list = []
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _month_hour_data_frame(self):
|
|
||||||
array = []
|
|
||||||
for i in range(0, 12):
|
|
||||||
days_of_month = cal.monthrange(2015, i+1)[1]
|
|
||||||
total_hours = days_of_month * 24
|
|
||||||
array = np.concatenate((array, np.full(total_hours, i + 1)))
|
|
||||||
return pd.DataFrame(array, columns=[cte.MONTH])
|
|
||||||
|
|
||||||
def _get_monthly_values(self, values):
|
|
||||||
out = None
|
|
||||||
if values is not None:
|
|
||||||
if cte.MONTH not in values.columns:
|
|
||||||
values = pd.concat([self._month_hour, pd.DataFrame(values)], axis=1)
|
|
||||||
out = values.groupby(cte.MONTH, as_index=False).sum()
|
|
||||||
del out[cte.MONTH]
|
|
||||||
return out
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_yearly_values(values):
|
|
||||||
return [values.sum()]
|
|
||||||
|
|
||||||
def _read_results(self):
|
|
||||||
try:
|
try:
|
||||||
return pd.read_csv(self._input_file_path, sep='\s+', header=0)
|
self._results = pd.read_csv(self._input_file_path, sep='\s+', header=0).to_dict(orient='list')
|
||||||
except FileNotFoundError as err:
|
except FileNotFoundError as err:
|
||||||
raise FileNotFoundError('No SRA output file found') from err
|
raise FileNotFoundError('No SRA output file found') from err
|
||||||
|
|
||||||
@property
|
|
||||||
def _radiation(self) -> []:
|
|
||||||
if len(self._radiation_list) == 0:
|
|
||||||
id_building = ''
|
|
||||||
header_building = []
|
|
||||||
for column in self._results.columns.values:
|
|
||||||
if id_building != column.split(':')[1]:
|
|
||||||
id_building = column.split(':')[1]
|
|
||||||
if len(header_building) > 0:
|
|
||||||
self._radiation_list.append(pd.concat([self._month_hour, self._results[header_building]], axis=1))
|
|
||||||
header_building = [column]
|
|
||||||
else:
|
|
||||||
header_building.append(column)
|
|
||||||
self._radiation_list.append(pd.concat([self._month_hour, self._results[header_building]], axis=1))
|
|
||||||
return self._radiation_list
|
|
||||||
|
|
||||||
def enrich(self):
|
def enrich(self):
|
||||||
"""
|
"""
|
||||||
saves in building surfaces the correspondent irradiance at different time-scales depending on the mode
|
saves in building surfaces the correspondent irradiance at different time-scales depending on the mode
|
||||||
|
@ -74,28 +31,21 @@ class SimplifiedRadiosityAlgorithm:
|
||||||
specific building values
|
specific building values
|
||||||
:return: none
|
:return: none
|
||||||
"""
|
"""
|
||||||
for radiation in self._radiation:
|
_irradiance = {}
|
||||||
city_object_name = radiation.columns.values.tolist()[1].split(':')[1]
|
for key in self._results:
|
||||||
|
header_name = key.split(':')
|
||||||
|
result = self._results[key]
|
||||||
|
city_object_name = header_name[1]
|
||||||
building = self._city.city_object(city_object_name)
|
building = self._city.city_object(city_object_name)
|
||||||
for column in radiation.columns.values:
|
surface_id = header_name[2]
|
||||||
if column == cte.MONTH:
|
|
||||||
continue
|
|
||||||
header_id = column
|
|
||||||
surface_id = header_id.split(':')[2]
|
|
||||||
surface = building.surface_by_id(surface_id)
|
surface = building.surface_by_id(surface_id)
|
||||||
new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=[cte.SRA])
|
monthly_result = MonthlyValues.get_total_month(result)
|
||||||
month_new_value = self._get_monthly_values(new_value)
|
yearly_result = [sum(result)]
|
||||||
if cte.MONTH not in surface.global_irradiance:
|
_irradiance[cte.YEAR] = yearly_result
|
||||||
surface.global_irradiance[cte.MONTH] = month_new_value
|
_irradiance[cte.MONTH] = monthly_result
|
||||||
else:
|
_irradiance[cte.HOUR] = result
|
||||||
pd.concat([surface.global_irradiance[cte.MONTH], month_new_value], axis=1)
|
surface.global_irradiance = _irradiance
|
||||||
if cte.HOUR not in surface.global_irradiance:
|
|
||||||
surface.global_irradiance[cte.HOUR] = new_value
|
|
||||||
else:
|
|
||||||
pd.concat([surface.global_irradiance[cte.HOUR], new_value], axis=1)
|
|
||||||
if cte.YEAR not in surface.global_irradiance:
|
|
||||||
surface.global_irradiance[cte.YEAR] = pd.DataFrame(SimplifiedRadiosityAlgorithm._get_yearly_values(new_value),
|
|
||||||
columns=[cte.SRA])
|
|
||||||
self._city.level_of_detail.surface_radiation = 2
|
self._city.level_of_detail.surface_radiation = 2
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
building.level_of_detail.surface_radiation = 2
|
building.level_of_detail.surface_radiation = 2
|
||||||
|
|
|
@ -8,7 +8,6 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from hub.helpers.utils import validate_import_export_type
|
from hub.helpers.utils import validate_import_export_type
|
||||||
from hub.imports.results.insel_heatpump_energy_demand import InselHeatPumpEnergyDemand
|
|
||||||
from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance
|
from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance
|
||||||
from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
|
from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
|
||||||
|
|
||||||
|
@ -41,13 +40,6 @@ class ResultFactory:
|
||||||
"""
|
"""
|
||||||
SimplifiedRadiosityAlgorithm(self._city, self._base_path).enrich()
|
SimplifiedRadiosityAlgorithm(self._city, self._base_path).enrich()
|
||||||
|
|
||||||
def _heat_pump(self):
|
|
||||||
"""
|
|
||||||
Enrich the city (energy system specifically) with heat pump insel simulation
|
|
||||||
results
|
|
||||||
"""
|
|
||||||
InselHeatPumpEnergyDemand(self._city, self._base_path, self._hp_model).enrich()
|
|
||||||
|
|
||||||
def _insel_monthly_energy_balance(self):
|
def _insel_monthly_energy_balance(self):
|
||||||
"""
|
"""
|
||||||
Enrich the city with insel monthly energy balance results
|
Enrich the city with insel monthly energy balance results
|
||||||
|
|
|
@ -104,7 +104,7 @@ class ComnetUsageParameters:
|
||||||
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
|
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
|
||||||
peak_flow = None
|
peak_flow = None
|
||||||
if len(cold_water_temperature) > 0:
|
if len(cold_water_temperature) > 0:
|
||||||
cold_temperature = cold_water_temperature[cte.YEAR]['epw']
|
cold_temperature = cold_water_temperature[cte.YEAR][0]
|
||||||
peak_flow = 0
|
peak_flow = 0
|
||||||
if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0:
|
if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0:
|
||||||
peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \
|
peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \
|
||||||
|
|
|
@ -104,7 +104,7 @@ class EilatUsageParameters:
|
||||||
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
|
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
|
||||||
peak_flow = None
|
peak_flow = None
|
||||||
if len(cold_water_temperature) > 0:
|
if len(cold_water_temperature) > 0:
|
||||||
cold_temperature = cold_water_temperature[cte.YEAR]['epw']
|
cold_temperature = cold_water_temperature[cte.YEAR][0]
|
||||||
peak_flow = 0
|
peak_flow = 0
|
||||||
if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0:
|
if (archetype.domestic_hot_water.service_temperature - cold_temperature) > 0:
|
||||||
peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \
|
peak_flow = archetype.domestic_hot_water.density / cte.WATER_DENSITY / cte.WATER_HEAT_CAPACITY \
|
||||||
|
|
|
@ -130,7 +130,7 @@ class NrcanUsageParameters:
|
||||||
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
|
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
|
||||||
density = None
|
density = None
|
||||||
if len(cold_water_temperature) > 0:
|
if len(cold_water_temperature) > 0:
|
||||||
cold_temperature = cold_water_temperature[cte.YEAR]['epw']
|
cold_temperature = cold_water_temperature[cte.YEAR][0]
|
||||||
density = (
|
density = (
|
||||||
archetype.domestic_hot_water.peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY *
|
archetype.domestic_hot_water.peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY *
|
||||||
(archetype.domestic_hot_water.service_temperature - cold_temperature)
|
(archetype.domestic_hot_water.service_temperature - cold_temperature)
|
||||||
|
|
|
@ -4,14 +4,15 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
import requests
|
import requests
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
|
from hub.helpers.monthly_values import MonthlyValues
|
||||||
from hub.city_model_structure.city import City
|
from hub.city_model_structure.city import City
|
||||||
from hub.imports.weather.helpers.weather import Weather as wh
|
from hub.imports.weather.helpers.weather import Weather as wh
|
||||||
|
|
||||||
|
@ -75,6 +76,25 @@ class EpwWeatherParameters:
|
||||||
'snow_depth_cm',
|
'snow_depth_cm',
|
||||||
'days_since_last_snowfall', 'albedo', 'liquid_precipitation_depth_mm',
|
'days_since_last_snowfall', 'albedo', 'liquid_precipitation_depth_mm',
|
||||||
'liquid_precipitation_quality_hr'])
|
'liquid_precipitation_quality_hr'])
|
||||||
|
number_invalid_records = self._weather_values[
|
||||||
|
self._weather_values.dry_bulb_temperature_c == 99.9].count().dry_bulb_temperature_c
|
||||||
|
if number_invalid_records > 0:
|
||||||
|
sys.stderr.write(f'Warning: {self._path} invalid records (value of 99.9) in dry bulb temperature\n')
|
||||||
|
number_invalid_records = self._weather_values[
|
||||||
|
self._weather_values.global_horizontal_radiation_wh_m2 == 9999].count().global_horizontal_radiation_wh_m2
|
||||||
|
if number_invalid_records > 0:
|
||||||
|
sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in global horizontal radiation\n')
|
||||||
|
number_invalid_records = self._weather_values[
|
||||||
|
self._weather_values.diffuse_horizontal_radiation_wh_m2 == 9999].count().diffuse_horizontal_radiation_wh_m2
|
||||||
|
if number_invalid_records > 0:
|
||||||
|
sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in diffuse horizontal radiation\n')
|
||||||
|
number_invalid_records = self._weather_values[
|
||||||
|
self._weather_values.direct_normal_radiation_wh_m2 == 9999].count().direct_normal_radiation_wh_m2
|
||||||
|
if number_invalid_records > 0:
|
||||||
|
sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in direct horizontal radiation\n')
|
||||||
|
|
||||||
|
self._weather_values = self._weather_values.to_dict(orient='list')
|
||||||
|
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
sys.stderr.write(f'Error: wrong formatting of weather file {self._path}\n')
|
sys.stderr.write(f'Error: wrong formatting of weather file {self._path}\n')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
@ -82,72 +102,29 @@ class EpwWeatherParameters:
|
||||||
building.ground_temperature[cte.MONTH] = ground_temperature_from_file
|
building.ground_temperature[cte.MONTH] = ground_temperature_from_file
|
||||||
ground_temperature = {}
|
ground_temperature = {}
|
||||||
for ground_temperature_set in building.ground_temperature[cte.MONTH]:
|
for ground_temperature_set in building.ground_temperature[cte.MONTH]:
|
||||||
temperature = 0
|
temperature = sum(building.ground_temperature[cte.MONTH][ground_temperature_set]) / 12
|
||||||
for value in building.ground_temperature[cte.MONTH][ground_temperature_set]:
|
|
||||||
temperature += value / 12
|
|
||||||
ground_temperature[ground_temperature_set] = [temperature]
|
ground_temperature[ground_temperature_set] = [temperature]
|
||||||
building.ground_temperature[cte.YEAR] = ground_temperature
|
building.ground_temperature[cte.YEAR] = ground_temperature
|
||||||
if cte.HOUR in building.external_temperature:
|
if cte.HOUR in building.external_temperature:
|
||||||
del building.external_temperature[cte.HOUR]
|
del building.external_temperature[cte.HOUR]
|
||||||
new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw'])
|
# 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
|
# number_invalid_records = new_value[new_value.epw == 99.9].count().epw
|
||||||
if number_invalid_records > 0:
|
building.external_temperature[cte.HOUR] = self._weather_values['dry_bulb_temperature_c']
|
||||||
sys.stderr.write(f'Warning: {self._path} invalid records (value of 99.9) in dry bulb temperature\n')
|
building.global_horizontal[cte.HOUR] = self._weather_values['global_horizontal_radiation_wh_m2']
|
||||||
if cte.HOUR not in building.external_temperature:
|
building.diffuse[cte.HOUR] = self._weather_values['diffuse_horizontal_radiation_wh_m2']
|
||||||
building.external_temperature[cte.HOUR] = new_value
|
building.beam[cte.HOUR] = self._weather_values['direct_normal_radiation_wh_m2']
|
||||||
else:
|
building.cold_water_temperature[cte.HOUR] = wh().cold_water_temperature(building.external_temperature[cte.HOUR])
|
||||||
pd.concat([building.external_temperature[cte.HOUR], new_value], axis=1)
|
|
||||||
|
|
||||||
new_value = pd.DataFrame(self._weather_values[['global_horizontal_radiation_wh_m2']].to_numpy(), columns=['epw'])
|
|
||||||
number_invalid_records = new_value[new_value.epw == 9999].count().epw
|
|
||||||
if number_invalid_records > 0:
|
|
||||||
sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in global horizontal radiation\n')
|
|
||||||
if cte.HOUR not in building.global_horizontal:
|
|
||||||
building.global_horizontal[cte.HOUR] = new_value
|
|
||||||
else:
|
|
||||||
pd.concat([building.global_horizontal[cte.HOUR], new_value], axis=1)
|
|
||||||
|
|
||||||
new_value = pd.DataFrame(self._weather_values[['diffuse_horizontal_radiation_wh_m2']].to_numpy(), columns=['epw'])
|
|
||||||
number_invalid_records = new_value[new_value.epw == 9999].count().epw
|
|
||||||
if number_invalid_records > 0:
|
|
||||||
sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in diffuse horizontal radiation\n')
|
|
||||||
if cte.HOUR not in building.diffuse:
|
|
||||||
building.diffuse[cte.HOUR] = new_value
|
|
||||||
else:
|
|
||||||
pd.concat([building.diffuse[cte.HOUR], new_value], axis=1)
|
|
||||||
|
|
||||||
new_value = pd.DataFrame(self._weather_values[['direct_normal_radiation_wh_m2']].to_numpy(), columns=['epw'])
|
|
||||||
number_invalid_records = new_value[new_value.epw == 9999].count().epw
|
|
||||||
if number_invalid_records > 0:
|
|
||||||
sys.stderr.write(f'Warning: {self._path} invalid records (value of 9999) in direct horizontal radiation\n')
|
|
||||||
if cte.HOUR not in building.beam:
|
|
||||||
building.beam[cte.HOUR] = new_value
|
|
||||||
else:
|
|
||||||
pd.concat([building.beam[cte.HOUR], new_value], axis=1)
|
|
||||||
|
|
||||||
new_value = wh().cold_water_temperature(building.external_temperature[cte.HOUR]['epw'])
|
|
||||||
if cte.HOUR not in building.cold_water_temperature:
|
|
||||||
building.cold_water_temperature[cte.HOUR] = new_value
|
|
||||||
else:
|
|
||||||
pd.concat([building.cold_water_temperature[cte.HOUR], new_value], axis=1)
|
|
||||||
# create the monthly and yearly values out of the hourly
|
# create the monthly and yearly values out of the hourly
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
if cte.MONTH not in building.external_temperature:
|
building.external_temperature[cte.MONTH] = MonthlyValues().get_mean_values(building.external_temperature[cte.HOUR])
|
||||||
building.external_temperature[cte.MONTH] = \
|
building.external_temperature[cte.YEAR] = [sum(building.external_temperature[cte.HOUR]) / 9870]
|
||||||
wh().get_monthly_mean_values(building.external_temperature[cte.HOUR][['epw']])
|
building.cold_water_temperature[cte.MONTH] = MonthlyValues().get_mean_values(building.cold_water_temperature[cte.HOUR])
|
||||||
if cte.YEAR not in building.external_temperature:
|
building.cold_water_temperature[cte.YEAR] = [sum(building.cold_water_temperature[cte.HOUR]) / 9870]
|
||||||
building.external_temperature[cte.YEAR] = \
|
|
||||||
wh(). get_yearly_mean_values(building.external_temperature[cte.HOUR][['epw']])
|
|
||||||
if cte.MONTH not in building.cold_water_temperature:
|
|
||||||
building.cold_water_temperature[cte.MONTH] = wh().get_monthly_mean_values(
|
|
||||||
building.cold_water_temperature[cte.HOUR][['epw']])
|
|
||||||
if cte.YEAR not in building.cold_water_temperature:
|
|
||||||
building.cold_water_temperature[cte.YEAR] = wh().get_yearly_mean_values(
|
|
||||||
building.cold_water_temperature[cte.HOUR][['epw']])
|
|
||||||
|
|
||||||
# If the usage has already being imported, the domestic hot water missing values must be calculated here that
|
# 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
|
# the cold water temperature is finally known
|
||||||
cold_temperature = building.cold_water_temperature[cte.YEAR]['epw']
|
cold_temperature = building.cold_water_temperature[cte.YEAR][0]
|
||||||
for internal_zone in building.internal_zones:
|
for internal_zone in building.internal_zones:
|
||||||
if internal_zone.usages is not None:
|
if internal_zone.usages is not None:
|
||||||
for usage in internal_zone.usages:
|
for usage in internal_zone.usages:
|
||||||
|
|
|
@ -4,11 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import calendar as cal
|
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,55 +73,7 @@ class Weather:
|
||||||
for temperature in ambient_temperature_fahrenheit:
|
for temperature in ambient_temperature_fahrenheit:
|
||||||
radians = (0.986 * (temperature-15-lag) - 90) * math.pi / 180
|
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)
|
cold_temperature.append((average_temperature + 6 + ratio * (delta_temperature/2) * math.sin(radians) - 32) * 5/9)
|
||||||
return pd.DataFrame(cold_temperature, columns=['epw'])
|
return cold_temperature
|
||||||
|
|
||||||
def get_monthly_mean_values(self, values):
|
|
||||||
"""
|
|
||||||
Get the monthly mean for the given values
|
|
||||||
:return: float
|
|
||||||
"""
|
|
||||||
out = None
|
|
||||||
if values is not None:
|
|
||||||
if 'month' not in values.columns:
|
|
||||||
values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1)
|
|
||||||
out = values.groupby('month', as_index=False).mean()
|
|
||||||
del out['month']
|
|
||||||
return out
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_yearly_mean_values(values):
|
|
||||||
"""
|
|
||||||
Get the yearly mean for the given values
|
|
||||||
:return: float
|
|
||||||
"""
|
|
||||||
return values.mean()
|
|
||||||
|
|
||||||
def get_total_month(self, values):
|
|
||||||
"""
|
|
||||||
Get the total value the given values
|
|
||||||
:return: float
|
|
||||||
"""
|
|
||||||
out = None
|
|
||||||
if values is not None:
|
|
||||||
if 'month' not in values.columns:
|
|
||||||
values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1)
|
|
||||||
out = pd.DataFrame(values).groupby('month', as_index=False).sum()
|
|
||||||
del out['month']
|
|
||||||
return out
|
|
||||||
|
|
||||||
@property
|
|
||||||
def month_hour(self):
|
|
||||||
"""
|
|
||||||
returns a DataFrame that has x values of the month number (January = 1, February = 2...),
|
|
||||||
being x the number of hours of the corresponding month
|
|
||||||
:return: DataFrame(int)
|
|
||||||
"""
|
|
||||||
array = []
|
|
||||||
for i in range(0, 12):
|
|
||||||
days_of_month = cal.monthrange(2015, i+1)[1]
|
|
||||||
total_hours = days_of_month * 24
|
|
||||||
array = np.concatenate((array, np.full(total_hours, i + 1)))
|
|
||||||
return pd.DataFrame(array, columns=['month'])
|
|
||||||
|
|
||||||
def epw_file(self, region_code):
|
def epw_file(self, region_code):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -4,7 +4,6 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from hub.city_model_structure.city import City
|
from hub.city_model_structure.city import City
|
||||||
from hub.helpers.utils import validate_import_export_type
|
from hub.helpers.utils import validate_import_export_type
|
||||||
|
|
|
@ -4,14 +4,13 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import distutils.spawn
|
import distutils.spawn
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
from hub.city_model_structure.city import City
|
from hub.city_model_structure.city import City
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
from hub.imports.results_factory import ResultFactory
|
from hub.imports.results_factory import ResultFactory
|
||||||
|
@ -72,13 +71,13 @@ class TestCityMerge(TestCase):
|
||||||
for building in merged_city.buildings:
|
for building in merged_city.buildings:
|
||||||
for surface in building.surfaces:
|
for surface in building.surfaces:
|
||||||
if surface.global_irradiance:
|
if surface.global_irradiance:
|
||||||
full_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
full_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
|
|
||||||
merged_city_building_total_radiation = 0
|
merged_city_building_total_radiation = 0
|
||||||
for building in merged_city.buildings:
|
for building in merged_city.buildings:
|
||||||
for surface in building.surfaces:
|
for surface in building.surfaces:
|
||||||
if surface.global_irradiance:
|
if surface.global_irradiance:
|
||||||
merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
self.assertEqual(full_city_building_total_radiation, merged_city_building_total_radiation)
|
self.assertEqual(full_city_building_total_radiation, merged_city_building_total_radiation)
|
||||||
|
|
||||||
merged_city = even_city.merge(full_city)
|
merged_city = even_city.merge(full_city)
|
||||||
|
@ -86,24 +85,24 @@ class TestCityMerge(TestCase):
|
||||||
for building in merged_city.buildings:
|
for building in merged_city.buildings:
|
||||||
for surface in building.surfaces:
|
for surface in building.surfaces:
|
||||||
if surface.global_irradiance:
|
if surface.global_irradiance:
|
||||||
merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
self.assertEqual(full_city_building_total_radiation, merged_city_building_total_radiation)
|
self.assertEqual(full_city_building_total_radiation, merged_city_building_total_radiation)
|
||||||
|
|
||||||
for building in even_city.buildings:
|
for building in even_city.buildings:
|
||||||
for surface in building.surfaces:
|
for surface in building.surfaces:
|
||||||
surface.global_irradiance[cte.YEAR] = pd.DataFrame([3], columns=['sra_mockup_value'])
|
surface.global_irradiance[cte.YEAR] = [3]
|
||||||
|
|
||||||
merged_city = full_city.merge(even_city)
|
merged_city = full_city.merge(even_city)
|
||||||
first_merged_city_building_total_radiation = 0
|
first_merged_city_building_total_radiation = 0
|
||||||
for building in merged_city.buildings:
|
for building in merged_city.buildings:
|
||||||
for surface in building.surfaces:
|
for surface in building.surfaces:
|
||||||
if surface.global_irradiance:
|
if surface.global_irradiance:
|
||||||
first_merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
first_merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
merged_city = even_city.merge(full_city)
|
merged_city = even_city.merge(full_city)
|
||||||
second_merged_city_building_total_radiation = 0
|
second_merged_city_building_total_radiation = 0
|
||||||
for building in merged_city.buildings:
|
for building in merged_city.buildings:
|
||||||
for surface in building.surfaces:
|
for surface in building.surfaces:
|
||||||
if surface.global_irradiance:
|
if surface.global_irradiance:
|
||||||
second_merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR].iloc[0, 0]
|
second_merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
self.assertEqual(first_merged_city_building_total_radiation, second_merged_city_building_total_radiation)
|
self.assertEqual(first_merged_city_building_total_radiation, second_merged_city_building_total_radiation)
|
||||||
|
|
||||||
|
|
|
@ -37,24 +37,6 @@ class TestExports(TestCase):
|
||||||
self.assertIsNotNone(self._city, 'city is none')
|
self.assertIsNotNone(self._city, 'city is none')
|
||||||
return self._city
|
return self._city
|
||||||
|
|
||||||
@property
|
|
||||||
def _read_sra_file(self) -> []:
|
|
||||||
path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve()
|
|
||||||
_results = pd.read_csv(path, sep='\s+', header=0)
|
|
||||||
id_building = ''
|
|
||||||
header_building = []
|
|
||||||
_radiation = []
|
|
||||||
for column in _results.columns.values:
|
|
||||||
if id_building != column.split(':')[1]:
|
|
||||||
id_building = column.split(':')[1]
|
|
||||||
if len(header_building) > 0:
|
|
||||||
_radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1))
|
|
||||||
header_building = [column]
|
|
||||||
else:
|
|
||||||
header_building.append(column)
|
|
||||||
_radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1))
|
|
||||||
return _radiation
|
|
||||||
|
|
||||||
def _set_irradiance_surfaces(self, city):
|
def _set_irradiance_surfaces(self, city):
|
||||||
"""
|
"""
|
||||||
saves in building surfaces the correspondent irradiance at different time-scales depending on the mode
|
saves in building surfaces the correspondent irradiance at different time-scales depending on the mode
|
||||||
|
@ -64,19 +46,22 @@ class TestExports(TestCase):
|
||||||
:return: none
|
:return: none
|
||||||
"""
|
"""
|
||||||
city.level_of_detail.surface_radiation = 2
|
city.level_of_detail.surface_radiation = 2
|
||||||
for radiation in self._read_sra_file:
|
path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve()
|
||||||
city_object_name = radiation.columns.values.tolist()[1].split(':')[1]
|
self._results = pd.read_csv(path, sep='\s+', header=0).to_dict(orient='list')
|
||||||
building = city.city_object(city_object_name)
|
_irradiance = {}
|
||||||
for column in radiation.columns.values:
|
for key in self._results:
|
||||||
if column == cte.MONTH:
|
header_name = key.split(':')
|
||||||
continue
|
result = self._results[key]
|
||||||
header_id = column
|
city_object_name = header_name[1]
|
||||||
surface_id = header_id.split(':')[2]
|
building = self._city.city_object(city_object_name)
|
||||||
|
surface_id = header_name[2]
|
||||||
surface = building.surface_by_id(surface_id)
|
surface = building.surface_by_id(surface_id)
|
||||||
new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=['sra'])
|
monthly_result = MonthlyValues.get_total_month(result)
|
||||||
surface.global_irradiance[cte.HOUR] = new_value
|
yearly_result = [sum(result)]
|
||||||
month_new_value = MonthlyValues().get_mean_values(new_value)
|
_irradiance[cte.YEAR] = yearly_result
|
||||||
surface.global_irradiance[cte.MONTH] = month_new_value
|
_irradiance[cte.MONTH] = monthly_result
|
||||||
|
_irradiance[cte.HOUR] = result
|
||||||
|
surface.global_irradiance = _irradiance
|
||||||
|
|
||||||
def test_insel_monthly_energy_balance_export(self):
|
def test_insel_monthly_energy_balance_export(self):
|
||||||
"""
|
"""
|
||||||
|
@ -86,7 +71,7 @@ class TestExports(TestCase):
|
||||||
WeatherFactory('epw', city).enrich()
|
WeatherFactory('epw', city).enrich()
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.external_temperature[cte.MONTH] = MonthlyValues().\
|
building.external_temperature[cte.MONTH] = MonthlyValues().\
|
||||||
get_mean_values(building.external_temperature[cte.HOUR][['epw']])
|
get_mean_values(building.external_temperature[cte.HOUR])
|
||||||
self._set_irradiance_surfaces(city)
|
self._set_irradiance_surfaces(city)
|
||||||
|
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
|
|
|
@ -225,16 +225,16 @@ TestDBFactory
|
||||||
yearly_lighting_peak_load = building.lighting_peak_load[cte.YEAR]
|
yearly_lighting_peak_load = building.lighting_peak_load[cte.YEAR]
|
||||||
monthly_appliances_peak_load = building.appliances_peak_load[cte.MONTH]
|
monthly_appliances_peak_load = building.appliances_peak_load[cte.MONTH]
|
||||||
yearly_appliances_peak_load = building.appliances_peak_load[cte.YEAR]
|
yearly_appliances_peak_load = building.appliances_peak_load[cte.YEAR]
|
||||||
monthly_cooling_demand = building.cooling_demand[cte.MONTH][cte.INSEL_MEB]
|
monthly_cooling_demand = building.cooling_demand[cte.MONTH]
|
||||||
yearly_cooling_demand = building.cooling_demand[cte.YEAR][cte.INSEL_MEB]
|
yearly_cooling_demand = building.cooling_demand[cte.YEAR]
|
||||||
monthly_heating_demand = building.heating_demand[cte.MONTH][cte.INSEL_MEB]
|
monthly_heating_demand = building.heating_demand[cte.MONTH]
|
||||||
yearly_heating_demand = building.heating_demand[cte.YEAR][cte.INSEL_MEB]
|
yearly_heating_demand = building.heating_demand[cte.YEAR]
|
||||||
monthly_lighting_electrical_demand = building.lighting_electrical_demand[cte.MONTH][cte.INSEL_MEB]
|
monthly_lighting_electrical_demand = building.lighting_electrical_demand[cte.MONTH]
|
||||||
yearly_lighting_electrical_demand = building.lighting_electrical_demand[cte.YEAR][cte.INSEL_MEB]
|
yearly_lighting_electrical_demand = building.lighting_electrical_demand[cte.YEAR]
|
||||||
monthly_appliances_electrical_demand = building.appliances_electrical_demand[cte.MONTH][cte.INSEL_MEB]
|
monthly_appliances_electrical_demand = building.appliances_electrical_demand[cte.MONTH]
|
||||||
yearly_appliances_electrical_demand = building.appliances_electrical_demand[cte.YEAR][cte.INSEL_MEB]
|
yearly_appliances_electrical_demand = building.appliances_electrical_demand[cte.YEAR]
|
||||||
monthly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.MONTH][cte.INSEL_MEB]
|
monthly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.MONTH]
|
||||||
yearly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.YEAR][cte.INSEL_MEB]
|
yearly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.YEAR]
|
||||||
monthly_heating_consumption = building.heating_consumption[cte.MONTH]
|
monthly_heating_consumption = building.heating_consumption[cte.MONTH]
|
||||||
yearly_heating_consumption = building.heating_consumption[cte.YEAR]
|
yearly_heating_consumption = building.heating_consumption[cte.YEAR]
|
||||||
monthly_cooling_consumption = building.cooling_consumption[cte.MONTH]
|
monthly_cooling_consumption = building.cooling_consumption[cte.MONTH]
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
"""
|
|
||||||
Test EnergySystemsFactory and various heatpump models
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Peter Yefi peteryefi@gmail.com
|
|
||||||
"""
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from unittest import TestCase
|
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
|
||||||
from hub.imports.energy_systems_factory import EnergySystemsFactory
|
|
||||||
from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP
|
|
||||||
from hub.exports.energy_systems_factory import EnergySystemsExportFactory
|
|
||||||
import os
|
|
||||||
|
|
||||||
# User defined parameters
|
|
||||||
user_input = {
|
|
||||||
'StartYear': 2020,
|
|
||||||
'EndYear': 2021,
|
|
||||||
'MaximumHPEnergyInput': 8000,
|
|
||||||
'HoursOfStorageAtMaxDemand': 1,
|
|
||||||
'BuildingSuppTemp': 40,
|
|
||||||
'TemperatureDifference': 15,
|
|
||||||
'FuelLHV': 47100,
|
|
||||||
'FuelPrice': 0.12,
|
|
||||||
'FuelEF': 1887,
|
|
||||||
'FuelDensity': 0.717,
|
|
||||||
'HPSupTemp': 60
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TestEnergySystemsFactory(TestCase):
|
|
||||||
"""
|
|
||||||
TestBuilding TestCase 1
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
"""
|
|
||||||
Test setup
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
|
||||||
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
|
|
||||||
city_file = (self._example_path/"C40_Final.gml").resolve()
|
|
||||||
self._output_path = (self._output_path/"as_user_output.csv").resolve()
|
|
||||||
self._city = GeometryFactory('citygml', path=city_file).city
|
|
||||||
EnergySystemsFactory('air_source_hp', self._city).enrich()
|
|
||||||
|
|
||||||
def test_air_source_heat_pump_import(self):
|
|
||||||
self.assertIsNotNone(self._city.energy_systems, 'City has energy systems')
|
|
||||||
self.assertIsInstance(self._city.energy_systems[0].air_source_hp, AirSourceHP)
|
|
||||||
self.assertEqual(self._city.energy_systems[0].air_source_hp.model, '012')
|
|
||||||
self.assertEqual(self._city.energy_systems[16].air_source_hp.model, '140')
|
|
||||||
|
|
||||||
def test_air_source_series_heat_pump_export(self):
|
|
||||||
EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='012',
|
|
||||||
output_path=self._output_path).export()
|
|
||||||
df = pd.read_csv(self._output_path)
|
|
||||||
self.assertEqual(df.shape, (13, 3))
|
|
||||||
self.assertEqual(df.iloc[0, 1], 1867715.88)
|
|
||||||
|
|
||||||
def test_air_source_parallel_heat_pump_export(self):
|
|
||||||
output = EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='018',
|
|
||||||
output_path=None, sim_type=1).export()
|
|
||||||
self.assertEqual(output["hourly_electricity_demand"][0], 38748.5625)
|
|
||||||
self.assertIsNotNone(output["daily_fossil_consumption"])
|
|
||||||
self.assertEqual(len(output["hourly_electricity_demand"]), 8760)
|
|
||||||
|
|
||||||
def tearDown(self) -> None:
|
|
||||||
try:
|
|
||||||
os.remove(self._output_path)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
|
@ -1,72 +0,0 @@
|
||||||
"""
|
|
||||||
Test EnergySystemsFactory and various heatpump models
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Peter Yefi peteryefi@gmail.com
|
|
||||||
"""
|
|
||||||
from pathlib import Path
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
from hub.city_model_structure.energy_systems.water_to_water_hp import WaterToWaterHP
|
|
||||||
from hub.exports.energy_systems_factory import EnergySystemsExportFactory
|
|
||||||
from hub.imports.energy_systems_factory import EnergySystemsFactory
|
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
|
||||||
|
|
||||||
|
|
||||||
class TestEnergySystemsFactory(TestCase):
|
|
||||||
"""
|
|
||||||
TestEnergySystemsFactory for Water to Water HP
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
"""
|
|
||||||
Test setup
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
|
||||||
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
|
|
||||||
city_file = (self._example_path / "C40_Final.gml").resolve()
|
|
||||||
self._output_path = (self._example_path / "w2w_user_output.csv").resolve()
|
|
||||||
self._city = GeometryFactory('citygml', path=city_file).city
|
|
||||||
EnergySystemsFactory('water_to_water_hp', self._city).enrich()
|
|
||||||
|
|
||||||
def test_water_to_water_heat_pump_import(self):
|
|
||||||
self.assertIsNotNone(self._city.energy_systems, 'City has energy systems')
|
|
||||||
self.assertIsInstance(self._city.energy_systems[0].water_to_water_hp, WaterToWaterHP)
|
|
||||||
self.assertEqual(self._city.energy_systems[0].water_to_water_hp.model, 'ClimateMaster 156 kW')
|
|
||||||
self.assertEqual(self._city.energy_systems[2].water_to_water_hp.model, 'ClimateMaster 335 kW')
|
|
||||||
|
|
||||||
def test_water_to_water_heat_pump_export(self):
|
|
||||||
# User defined parameters
|
|
||||||
user_input = {
|
|
||||||
'StartYear': 2020,
|
|
||||||
'EndYear': 2021,
|
|
||||||
'MaximumHPEnergyInput': 8000,
|
|
||||||
'HoursOfStorageAtMaxDemand': 1,
|
|
||||||
'BuildingSuppTemp': 40,
|
|
||||||
'TemperatureDifference': 15,
|
|
||||||
'FuelLHV': 47100,
|
|
||||||
'FuelPrice': 0.12,
|
|
||||||
'FuelEF': 1887,
|
|
||||||
'FuelDensity': 0.717,
|
|
||||||
'HPSupTemp': 60,
|
|
||||||
'b1': 10,
|
|
||||||
'b2': 10,
|
|
||||||
'b3': 10,
|
|
||||||
'b4': 10,
|
|
||||||
'b5': 10,
|
|
||||||
'b6': 10,
|
|
||||||
'b7': 10,
|
|
||||||
'b8': 10,
|
|
||||||
'b9': 10,
|
|
||||||
'b10': 10,
|
|
||||||
'b11': 10
|
|
||||||
}
|
|
||||||
|
|
||||||
EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='ClimateMaster 256 kW',
|
|
||||||
output_path=self._output_path, sim_type=1).export('water')
|
|
||||||
df = pd.read_csv(self._output_path)
|
|
||||||
self.assertEqual(df.shape, (13, 3))
|
|
||||||
self.assertEqual(df.iloc[0, 1], 1031544.62)
|
|
|
@ -5,10 +5,10 @@ Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
import pandas as pd
|
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
from hub.helpers.dictionaries import Dictionaries
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
from hub.imports.construction_factory import ConstructionFactory
|
from hub.imports.construction_factory import ConstructionFactory
|
||||||
|
@ -58,10 +58,10 @@ class TestExports(TestCase):
|
||||||
self._complete_city.climate_reference_city = 'Summerland'
|
self._complete_city.climate_reference_city = 'Summerland'
|
||||||
dummy_measures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
dummy_measures = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
||||||
for building in self._complete_city.buildings:
|
for building in self._complete_city.buildings:
|
||||||
building.heating_demand[cte.MONTH] = pd.DataFrame({'INSEL': dummy_measures})
|
building.heating_demand[cte.MONTH] = dummy_measures
|
||||||
building.cooling_demand[cte.MONTH] = pd.DataFrame({'INSEL': dummy_measures})
|
building.cooling_demand[cte.MONTH] = dummy_measures
|
||||||
building.heating_demand[cte.YEAR] = pd.DataFrame({'INSEL': [0.0]})
|
building.heating_demand[cte.YEAR] = [0.0]
|
||||||
building.cooling_demand[cte.YEAR] = pd.DataFrame({'INSEL': [0.0]})
|
building.cooling_demand[cte.YEAR] = [0.0]
|
||||||
return self._complete_city
|
return self._complete_city
|
||||||
|
|
||||||
def _export(self, export_type, from_pickle=False):
|
def _export(self, export_type, from_pickle=False):
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
"""
|
|
||||||
Test EnergySystemsFactory and various heatpump models
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2023 Concordia CERC group
|
|
||||||
Project Coder Peter Yefi peteryefi@gmail.com
|
|
||||||
"""
|
|
||||||
from pathlib import Path
|
|
||||||
from unittest import TestCase
|
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
|
||||||
from hub.imports.energy_systems_factory import EnergySystemsFactory
|
|
||||||
from hub.exports.energy_systems_factory import EnergySystemsExportFactory
|
|
||||||
from hub.imports.results_factory import ResultFactory
|
|
||||||
import os
|
|
||||||
from pandas.core.series import Series
|
|
||||||
|
|
||||||
# User defined parameters
|
|
||||||
user_input = {
|
|
||||||
'StartYear': 2020,
|
|
||||||
'EndYear': 2021,
|
|
||||||
'MaximumHPEnergyInput': 8000,
|
|
||||||
'HoursOfStorageAtMaxDemand': 1,
|
|
||||||
'BuildingSuppTemp': 40,
|
|
||||||
'TemperatureDifference': 15,
|
|
||||||
'FuelLHV': 47100,
|
|
||||||
'FuelPrice': 0.12,
|
|
||||||
'FuelEF': 1887,
|
|
||||||
'FuelDensity': 0.717,
|
|
||||||
'HPSupTemp': 60
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TestHeatPumpResults(TestCase):
|
|
||||||
"""
|
|
||||||
TestHeatPumpResults
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
"""
|
|
||||||
Test setup
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
|
||||||
self._output_path = (Path(__file__).parent / 'tests_outputs/as_user_output.csv').resolve()
|
|
||||||
city_file = (self._example_path / "C40_Final.gml").resolve()
|
|
||||||
self._city = GeometryFactory('citygml', path=city_file).city
|
|
||||||
EnergySystemsFactory('air_source_hp', self._city).enrich()
|
|
||||||
|
|
||||||
def test_air_source_series_heat_pump_012_results(self):
|
|
||||||
EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='012',
|
|
||||||
output_path=self._output_path).export()
|
|
||||||
ResultFactory('heat_pump', self._city, self._output_path, '012').enrich()
|
|
||||||
|
|
||||||
for energy_system in self._city.energy_systems:
|
|
||||||
self.assertIsNone(energy_system.water_to_water_hp)
|
|
||||||
if energy_system.air_source_hp.model == '012':
|
|
||||||
self.assertIsInstance(energy_system.air_source_hp.hp_monthly_fossil_consumption, Series)
|
|
||||||
self.assertEqual(energy_system.air_source_hp.hp_monthly_fossil_consumption.iloc[5], 1.51325583)
|
|
||||||
self.assertEqual(energy_system.air_source_hp.hp_monthly_fossil_consumption.iloc[12], 35.853598782915)
|
|
||||||
|
|
||||||
def test_air_source_series_heat_pump_015_results(self):
|
|
||||||
EnergySystemsExportFactory(city=self._city, handler=user_input, hp_model='140',
|
|
||||||
output_path=self._output_path).export()
|
|
||||||
ResultFactory('heat_pump', self._city, self._output_path, '140').enrich()
|
|
||||||
|
|
||||||
for energy_system in self._city.energy_systems:
|
|
||||||
self.assertIsNone(energy_system.water_to_water_hp)
|
|
||||||
if energy_system.air_source_hp.model == '140':
|
|
||||||
self.assertIsInstance(energy_system.air_source_hp.hp_monthly_fossil_consumption, Series)
|
|
||||||
self.assertEqual(energy_system.air_source_hp.hp_monthly_fossil_consumption.iloc[0], 7.91282225)
|
|
||||||
self.assertEqual(energy_system.air_source_hp.hp_monthly_fossil_consumption.iloc[2], 0.068873927)
|
|
||||||
|
|
||||||
def tearDown(self) -> None:
|
|
||||||
try:
|
|
||||||
os.remove(self._output_path)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
|
@ -37,24 +37,6 @@ class TestExports(TestCase):
|
||||||
self.assertIsNotNone(self._city, 'city is none')
|
self.assertIsNotNone(self._city, 'city is none')
|
||||||
return self._city
|
return self._city
|
||||||
|
|
||||||
@property
|
|
||||||
def _read_sra_file(self) -> []:
|
|
||||||
path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve()
|
|
||||||
_results = pd.read_csv(path, sep='\s+', header=0)
|
|
||||||
id_building = ''
|
|
||||||
header_building = []
|
|
||||||
_radiation = []
|
|
||||||
for column in _results.columns.values:
|
|
||||||
if id_building != column.split(':')[1]:
|
|
||||||
id_building = column.split(':')[1]
|
|
||||||
if len(header_building) > 0:
|
|
||||||
_radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1))
|
|
||||||
header_building = [column]
|
|
||||||
else:
|
|
||||||
header_building.append(column)
|
|
||||||
_radiation.append(pd.concat([MonthlyValues().month_hour, _results[header_building]], axis=1))
|
|
||||||
return _radiation
|
|
||||||
|
|
||||||
def _set_irradiance_surfaces(self, city):
|
def _set_irradiance_surfaces(self, city):
|
||||||
"""
|
"""
|
||||||
saves in building surfaces the correspondent irradiance at different time-scales depending on the mode
|
saves in building surfaces the correspondent irradiance at different time-scales depending on the mode
|
||||||
|
@ -64,19 +46,22 @@ class TestExports(TestCase):
|
||||||
:return: none
|
:return: none
|
||||||
"""
|
"""
|
||||||
city.level_of_detail.surface_radiation = 2
|
city.level_of_detail.surface_radiation = 2
|
||||||
for radiation in self._read_sra_file:
|
path = (self._example_path / "one_building_in_kelowna_sra_SW.out").resolve()
|
||||||
city_object_name = radiation.columns.values.tolist()[1].split(':')[1]
|
self._results = pd.read_csv(path, sep='\s+', header=0).to_dict(orient='list')
|
||||||
building = city.city_object(city_object_name)
|
_irradiance = {}
|
||||||
for column in radiation.columns.values:
|
for key in self._results:
|
||||||
if column == cte.MONTH:
|
header_name = key.split(':')
|
||||||
continue
|
result = self._results[key]
|
||||||
header_id = column
|
city_object_name = header_name[1]
|
||||||
surface_id = header_id.split(':')[2]
|
building = self._city.city_object(city_object_name)
|
||||||
|
surface_id = header_name[2]
|
||||||
surface = building.surface_by_id(surface_id)
|
surface = building.surface_by_id(surface_id)
|
||||||
new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=['sra'])
|
monthly_result = MonthlyValues.get_total_month(result)
|
||||||
surface.global_irradiance[cte.HOUR] = new_value
|
yearly_result = [sum(result)]
|
||||||
month_new_value = MonthlyValues().get_mean_values(new_value)
|
_irradiance[cte.YEAR] = yearly_result
|
||||||
surface.global_irradiance[cte.MONTH] = month_new_value
|
_irradiance[cte.MONTH] = monthly_result
|
||||||
|
_irradiance[cte.HOUR] = result
|
||||||
|
surface.global_irradiance = _irradiance
|
||||||
|
|
||||||
def test_insel_monthly_energy_balance_export(self):
|
def test_insel_monthly_energy_balance_export(self):
|
||||||
"""
|
"""
|
||||||
|
@ -86,7 +71,7 @@ class TestExports(TestCase):
|
||||||
WeatherFactory('epw', city).enrich()
|
WeatherFactory('epw', city).enrich()
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.external_temperature[cte.MONTH] = MonthlyValues().\
|
building.external_temperature[cte.MONTH] = MonthlyValues().\
|
||||||
get_mean_values(building.external_temperature[cte.HOUR][['epw']])
|
get_mean_values(building.external_temperature[cte.HOUR])
|
||||||
self._set_irradiance_surfaces(city)
|
self._set_irradiance_surfaces(city)
|
||||||
|
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
|
|
|
@ -4,12 +4,11 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
|
||||||
from hub.exports.exports_factory import ExportsFactory
|
from hub.exports.exports_factory import ExportsFactory
|
||||||
|
@ -65,10 +64,10 @@ class TestResultsImport(TestCase):
|
||||||
ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich()
|
ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich()
|
||||||
# Check that all the buildings have heating and cooling values
|
# Check that all the buildings have heating and cooling values
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
self.assertIsNotNone(building.heating_demand[cte.MONTH][cte.INSEL_MEB])
|
self.assertIsNotNone(building.heating_demand[cte.MONTH])
|
||||||
self.assertIsNotNone(building.cooling_demand[cte.MONTH][cte.INSEL_MEB])
|
self.assertIsNotNone(building.cooling_demand[cte.MONTH])
|
||||||
self.assertIsNotNone(building.heating_demand[cte.YEAR][cte.INSEL_MEB])
|
self.assertIsNotNone(building.heating_demand[cte.YEAR])
|
||||||
self.assertIsNotNone(building.cooling_demand[cte.YEAR][cte.INSEL_MEB])
|
self.assertIsNotNone(building.cooling_demand[cte.YEAR])
|
||||||
self.assertIsNotNone(building.lighting_peak_load[cte.MONTH])
|
self.assertIsNotNone(building.lighting_peak_load[cte.MONTH])
|
||||||
self.assertIsNotNone(building.lighting_peak_load[cte.YEAR])
|
self.assertIsNotNone(building.lighting_peak_load[cte.YEAR])
|
||||||
self.assertIsNotNone(building.appliances_peak_load[cte.MONTH])
|
self.assertIsNotNone(building.appliances_peak_load[cte.MONTH])
|
||||||
|
@ -89,7 +88,7 @@ class TestResultsImport(TestCase):
|
||||||
expected_monthly_list = [0 for _ in range(12)]
|
expected_monthly_list = [0 for _ in range(12)]
|
||||||
expected_monthly_list[0] = 1000
|
expected_monthly_list[0] = 1000
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
building.heating_demand[cte.HOUR] = pd.DataFrame(values, columns=['dummy'])
|
building.heating_demand[cte.HOUR] = values
|
||||||
building.cooling_demand[cte.HOUR] = pd.DataFrame(values, columns=['dummy'])
|
building.cooling_demand[cte.HOUR] = values
|
||||||
self.assertIsNotNone(building.heating_peak_load)
|
self.assertIsNotNone(building.heating_peak_load)
|
||||||
self.assertIsNotNone(building.cooling_peak_load)
|
self.assertIsNotNone(building.cooling_peak_load)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user