adding peak loads partial

This commit is contained in:
Guille Gutierrez 2023-04-18 12:21:00 -04:00
parent 090b2251f1
commit aa13d85c01
12 changed files with 289 additions and 48 deletions

View File

@ -44,6 +44,8 @@ class Building(CityObject):
self._lighting_electrical_demand = dict() self._lighting_electrical_demand = dict()
self._appliances_electrical_demand = dict() self._appliances_electrical_demand = dict()
self._domestic_hot_water_heat_demand = dict() self._domestic_hot_water_heat_demand = dict()
self._heating_peak_load = dict()
self._cooling_peak_load = dict()
self._eave_height = None self._eave_height = None
self._grounds = [] self._grounds = []
self._roofs = [] self._roofs = []
@ -362,6 +364,38 @@ class Building(CityObject):
""" """
self._domestic_hot_water_heat_demand = value self._domestic_hot_water_heat_demand = value
@property
def heating_peak_load(self) -> dict:
"""
Get heating peak load in W
:return: dict{DataFrame(float)}
"""
return self._heating_peak_load
@heating_peak_load.setter
def heating_peak_load(self, value):
"""
Set heating peak load in W
:param value: dict{DataFrame(float)}
"""
self._heating_peak_load = value
@property
def cooling_peak_load(self) -> dict:
"""
Get cooling peak load in W
:return: dict{DataFrame(float)}
"""
return self._cooling_peak_load
@cooling_peak_load.setter
def cooling_peak_load(self, value):
"""
Set peak load in W
:param value: dict{DataFrame(float)}
"""
self._cooling_peak_load = value
@property @property
def eave_height(self): def eave_height(self):
""" """

View File

@ -110,6 +110,14 @@ class CityObject:
""" """
return self._surfaces return self._surfaces
@surfaces.setter
def surfaces(self, value):
"""
Set city object surfaces
:return: [Surface]
"""
self._surfaces = value
def surface(self, name) -> Union[Surface, None]: def surface(self, name) -> Union[Surface, None]:
""" """
Get the city object surface with a given name Get the city object surface with a given name

View File

@ -184,6 +184,7 @@ MIN_FLOAT = float('-inf')
# Tools # Tools
SRA = 'sra' SRA = 'sra'
INSEL_MEB = 'insel meb' INSEL_MEB = 'insel meb'
PEAK_LOAD = 'peak load'
# Costs units # Costs units
CURRENCY_PER_SQM = 'currency/m2' CURRENCY_PER_SQM = 'currency/m2'

View File

@ -71,8 +71,11 @@ class Geojson:
polygon = Polygon(points) polygon = Polygon(points)
polygon.area = igh.ground_area(points) polygon.area = igh.ground_area(points)
surface = Surface(polygon, polygon) surface = Surface(polygon, polygon)
surfaces.append(surface) if len(buildings) == 1:
buildings.append(Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function)) buildings[0].surfaces.append(surface)
else:
surfaces.append(surface)
buildings.append(Building(f'{name}', surfaces, year_of_construction, function))
return buildings return buildings
@staticmethod @staticmethod
@ -82,9 +85,10 @@ class Geojson:
buildings = [] buildings = []
for zone, lod0_building in enumerate(lod0_buildings): for zone, lod0_building in enumerate(lod0_buildings):
# print(zone, lod0_building.name)
volume = 0
for surface in lod0_building.grounds: for surface in lod0_building.grounds:
volume = volume + surface.solid_polygon.area * height
volume = surface.solid_polygon.area * height
surfaces.append(surface) surfaces.append(surface)
roof_coordinates = [] roof_coordinates = []
# adding a roof means invert the polygon coordinates and change the Z value # adding a roof means invert the polygon coordinates and change the Z value
@ -112,10 +116,9 @@ class Geojson:
polygon = Polygon(wall_coordinates) polygon = Polygon(wall_coordinates)
wall = Surface(polygon, polygon) wall = Surface(polygon, polygon)
surfaces.append(wall) surfaces.append(wall)
building = Building(f'{name}', surfaces, year_of_construction, function)
building = Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function) building.volume = volume
building.volume = volume buildings.append(building)
buildings.append(building)
return buildings return buildings
@ -218,7 +221,7 @@ class Geojson:
polygons = self._get_polygons(polygons, coordinates) polygons = self._get_polygons(polygons, coordinates)
for polygon in polygons: for polygon in polygons:
if extrusion_height == 0: if extrusion_height == 0:
buildings = buildings + Geojson._create_buildings_lod0(f'{building_name}_part_{part}', buildings = buildings + Geojson._create_buildings_lod0(f'{building_name}',
year_of_construction, year_of_construction,
function, function,
[polygon]) [polygon])
@ -226,11 +229,22 @@ class Geojson:
else: else:
if self._max_z < extrusion_height: if self._max_z < extrusion_height:
self._max_z = extrusion_height self._max_z = extrusion_height
buildings = buildings + Geojson._create_buildings_lod1(f'{building_name}_part_{part}', if part == 0:
year_of_construction, buildings = buildings + Geojson._create_buildings_lod1(f'{building_name}',
function, year_of_construction,
extrusion_height, function,
[polygon]) extrusion_height,
[polygon])
else:
new_part = Geojson._create_buildings_lod1(f'{building_name}',
year_of_construction,
function,
extrusion_height,
[polygon])
surfaces = buildings[len(buildings) - 1].surfaces + new_part[0].surfaces
volume = buildings[len(buildings) - 1].volume + new_part[0].volume
buildings[len(buildings) - 1] = Building(f'{building_name}', surfaces, year_of_construction, function)
buildings[len(buildings) - 1].volume = volume
self._city = City([self._min_x, self._min_y, 0.0], [self._max_x, self._max_y, self._max_z], 'epsg:26911') self._city = City([self._min_x, self._min_y, 0.0], [self._max_x, self._max_y, self._max_z], 'epsg:26911')
for building in buildings: for building in buildings:

View File

@ -107,6 +107,9 @@ class GeometryFactory:
Enrich the city given to the class using the class given handler Enrich the city given to the class using the class given handler
:return: City :return: City
""" """
if self._data_frame is None: return Geojson(self._path,
self._data_frame = geopandas.read_file(self._path) self._name_field,
return GPandas(self._data_frame).city self._height_field,
self._year_of_construction_field,
self._function_field,
self._function_to_hub).city

View File

@ -4,7 +4,6 @@ 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 pandas as pd import pandas as pd
import csv import csv
@ -40,60 +39,55 @@ class InselMonthlyEnergyBalance:
monthly_cooling = pd.DataFrame(cooling, columns=[cte.INSEL_MEB]).astype(float) monthly_cooling = pd.DataFrame(cooling, columns=[cte.INSEL_MEB]).astype(float)
return monthly_heating, monthly_cooling return monthly_heating, monthly_cooling
def _dhw_demand(self): def _dhw_and_electric_demand(self):
for building in self._city.buildings: for building in self._city.buildings:
domestic_hot_water_demand = [] domestic_hot_water_demand = []
if building.internal_zones[0].thermal_zones is None:
domestic_hot_water_demand = [0] * 12
else:
thermal_zone = building.internal_zones[0].thermal_zones[0]
area = thermal_zone.total_floor_area
cold_water = building.cold_water_temperature[cte.MONTH]['epw']
for month in range(0, 12):
total_dhw_demand = 0
for schedule in thermal_zone.domestic_hot_water.schedules:
total_day = 0
for value in schedule.values:
total_day += value
for day_type in schedule.day_types:
demand = thermal_zone.domestic_hot_water.peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY \
* (thermal_zone.domestic_hot_water.service_temperature - cold_water[month])
total_dhw_demand += total_day * cte.DAYS_A_MONTH[day_type][month] * demand
domestic_hot_water_demand.append(total_dhw_demand * area)
building.domestic_hot_water_heat_demand[cte.MONTH] = \
pd.DataFrame(domestic_hot_water_demand, columns=[cte.INSEL_MEB])
def _electrical_demand(self):
for building in self._city.buildings:
lighting_demand = [] lighting_demand = []
appliances_demand = [] appliances_demand = []
if building.internal_zones[0].thermal_zones is None: if building.internal_zones[0].thermal_zones is None:
domestic_hot_water_demand = [0] * 12
lighting_demand = [0] * 12 lighting_demand = [0] * 12
appliances_demand = [0] * 12 appliances_demand = [0] * 12
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']
peak_flow = thermal_zone.domestic_hot_water.peak_flow
service_temperature = thermal_zone.domestic_hot_water.service_temperature
lighting_density = thermal_zone.lighting.density
appliances_density = thermal_zone.appliances.density
for month in range(0, 12): for month in range(0, 12):
total_dhw_demand = 0
total_lighting = 0 total_lighting = 0
total_appliances = 0
for schedule in thermal_zone.lighting.schedules: for schedule in thermal_zone.lighting.schedules:
total_day = 0 total_day = 0
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] * thermal_zone.lighting.density total_lighting += total_day * cte.DAYS_A_MONTH[day_type][month] * lighting_density
lighting_demand.append(total_lighting * area) lighting_demand.append(total_lighting * area)
total_appliances = 0
for schedule in thermal_zone.appliances.schedules: for schedule in thermal_zone.appliances.schedules:
total_day = 0 total_day = 0
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] * thermal_zone.appliances.density total_appliances += total_day * cte.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:
total_day = 0
for value in schedule.values:
total_day += value
for day_type in schedule.day_types:
demand = 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
domestic_hot_water_demand.append(total_dhw_demand * area)
building.domestic_hot_water_heat_demand[cte.MONTH] = pd.DataFrame(domestic_hot_water_demand, columns=[cte.INSEL_MEB])
building.lighting_electrical_demand[cte.MONTH] = pd.DataFrame(lighting_demand, columns=[cte.INSEL_MEB]) building.lighting_electrical_demand[cte.MONTH] = pd.DataFrame(lighting_demand, columns=[cte.INSEL_MEB])
building.appliances_electrical_demand[cte.MONTH] = pd.DataFrame(appliances_demand, columns=[cte.INSEL_MEB]) building.appliances_electrical_demand[cte.MONTH] = pd.DataFrame(appliances_demand, columns=[cte.INSEL_MEB])
@ -109,5 +103,4 @@ class InselMonthlyEnergyBalance:
building.cooling[cte.YEAR] = pd.DataFrame( building.cooling[cte.YEAR] = pd.DataFrame(
[building.cooling[cte.MONTH][cte.INSEL_MEB].astype(float).sum()], columns=[cte.INSEL_MEB] [building.cooling[cte.MONTH][cte.INSEL_MEB].astype(float).sum()], columns=[cte.INSEL_MEB]
) )
self._dhw_demand() self._dhw_and_electric_demand()
self._electrical_demand()

View File

@ -0,0 +1,118 @@
"""
Calculation of loads for peak heating and cooling
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import hub.helpers.constants as cte
class LoadsCalculation:
"""
LoadsCalculation class
"""
def __init__(self, building):
self._building = building
@staticmethod
def _get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature, ground_temperature):
load_transmitted_opaque = 0
load_transmitted_transparent = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
if thermal_boundary.type == cte.GROUND:
external_temperature = ground_temperature
elif thermal_boundary.type == cte.INTERIOR_WALL:
external_temperature = internal_temperature
else:
external_temperature = ambient_temperature
load_transmitted_opaque += thermal_boundary.u_value * thermal_boundary.opaque_area \
* (internal_temperature - external_temperature)
for thermal_opening in thermal_boundary.thermal_openings:
load_transmitted_transparent += thermal_opening.overall_u_value \
* (internal_temperature - external_temperature)
load_transmitted_opaque += thermal_zone.additional_thermal_bridge_u_value * thermal_zone.footprint_area \
* (internal_temperature - ambient_temperature)
load_transmitted = load_transmitted_opaque + load_transmitted_transparent
return load_transmitted
@staticmethod
def _get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature):
load_renovation_sensible = 0
for usage in thermal_zone.usages:
load_renovation_sensible += cte.AIR_DENSITY * cte.AIR_HEAT_CAPACITY * usage.mechanical_air_change \
* thermal_zone.volume / cte.HOUR_TO_MINUTES / cte.MINUTES_TO_SECONDS \
* (internal_temperature - ambient_temperature)
load_infiltration_sensible = cte.AIR_DENSITY * cte.AIR_HEAT_CAPACITY * thermal_zone.infiltration_rate_system_off \
* thermal_zone.volume / cte.HOUR_TO_MINUTES / cte.MINUTES_TO_SECONDS \
* (internal_temperature - ambient_temperature)
load_ventilation = load_renovation_sensible + load_infiltration_sensible
return load_ventilation
def get_heating_transmitted_load(self, ambient_temperature, ground_temperature):
heating_load_transmitted = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_heating_set_point
heating_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature,
ground_temperature)
return heating_load_transmitted
def get_cooling_transmitted_load(self, ambient_temperature, ground_temperature):
cooling_load_transmitted = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_cooling_set_point
cooling_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature,
ground_temperature)
return cooling_load_transmitted
def get_heating_ventilation_load_sensible(self, ambient_temperature):
heating_ventilation_load = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_heating_set_point
heating_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature)
return heating_ventilation_load
def get_cooling_ventilation_load_sensible(self, ambient_temperature):
cooling_ventilation_load = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_cooling_set_point
cooling_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature)
return cooling_ventilation_load
def get_internal_load_sensible(self):
cooling_load_occupancy_sensible = 0
cooling_load_lighting = 0
cooling_load_equipment_sensible = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
cooling_load_occupancy_sensible += (thermal_zone.occupancy.sensible_convective_internal_gain
+ thermal_zone.occupancy.sensible_radiative_internal_gain) \
* thermal_zone.footprint_area
cooling_load_lighting += (thermal_zone.lighting.density * thermal_zone.lighting.convective_fraction
+ thermal_zone.lighting.density * thermal_zone.lighting.radiative_fraction) \
* thermal_zone.footprint_area
cooling_load_equipment_sensible += (thermal_zone.appliances.density * thermal_zone.appliances.convective_fraction
+ thermal_zone.appliances.density * thermal_zone.appliances.radiative_fraction) \
* thermal_zone.footprint_area
internal_load = cooling_load_occupancy_sensible + cooling_load_lighting + cooling_load_equipment_sensible
return internal_load
def get_radiation_load(self, irradiance_format, hour):
cooling_load_radiation = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
radiation = thermal_boundary.parent_surface.global_irradiance[cte.HOUR][irradiance_format][hour]
cooling_load_radiation += thermal_opening.area * (1 - thermal_opening.frame_ratio) * thermal_opening.g_value \
* radiation
return cooling_load_radiation

View File

@ -0,0 +1,61 @@
import hub.helpers.constants as cte
from hub.imports.results.peak_calculation.loads_calculation import LoadsCalculation
class PeakLoad:
_MONTH_STARTING_HOUR = [0, 744, 1416, 2160, 2880, 3624, 4344, 5088, 5832, 6552, 7296, 8016]
def __init__(self, city):
self._city = city
self._weather_format = 'epw'
def enrich(self):
for building in self._city.buildings:
monthly_heating_loads = []
monthly_cooling_loads = []
ambient_temperature = building.external_temperature[cte.HOUR][self._weather_format]
for month in range(0, 12):
ground_temperature = building.ground_temperature[cte.MONTH]['2'][month]
heating_ambient_temperature = 100
cooling_ambient_temperature = -100
heating_calculation_hour = -1
cooling_calculation_hour = -1
start_hour = self._MONTH_STARTING_HOUR[month]
end_hour = 8760
if month < 11:
end_hour = self._MONTH_STARTING_HOUR[month + 1]
for hour in range(start_hour, end_hour):
temperature = ambient_temperature[hour]
if temperature < heating_ambient_temperature:
heating_ambient_temperature = temperature
heating_calculation_hour = hour
if temperature > cooling_ambient_temperature:
cooling_ambient_temperature = temperature
cooling_calculation_hour = hour
loads = LoadsCalculation(building)
heating_load_transmitted = loads.get_heating_transmitted_load(heating_ambient_temperature, ground_temperature)
heating_load_ventilation_sensible = loads.get_heating_ventilation_load_sensible(heating_ambient_temperature)
heating_load_ventilation_latent = 0
heating_load = heating_load_transmitted + heating_load_ventilation_sensible + heating_load_ventilation_latent
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_internal_gains_sensible = loads.get_internal_load_sensible()
cooling_load_radiation = loads.get_radiation_load(self._irradiance_format, cooling_calculation_hour)
cooling_load_sensible = cooling_load_transmitted + cooling_load_renovation_sensible - cooling_load_radiation \
- cooling_load_internal_gains_sensible
cooling_load_latent = 0
cooling_load = cooling_load_sensible + cooling_load_latent
if heating_load < 0:
heating_load = 0
if cooling_load > 0:
cooling_load = 0
monthly_heating_loads.append(heating_load)
monthly_cooling_loads.append(cooling_load)
self._results[building.name] = {'monthly heating peak load': monthly_heating_loads,
'monthly cooling peak load': monthly_cooling_loads}
self._print_results()

View File

@ -9,6 +9,7 @@ from pathlib import Path
from hub.helpers.utils import validate_import_export_type from hub.helpers.utils import validate_import_export_type
from hub.hub_logger import logger from hub.hub_logger import logger
from hub.imports.results.peak_load import PeakLoad
from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance
from hub.imports.results.insel_heatpump_energy_demand import InselHeatPumpEnergyDemand from hub.imports.results.insel_heatpump_energy_demand import InselHeatPumpEnergyDemand
@ -59,6 +60,12 @@ class ResultFactory:
""" """
InselMonthlyEnergyBalance(self._city, self._base_path).enrich() InselMonthlyEnergyBalance(self._city, self._base_path).enrich()
def _peak_load(self):
"""
Enrich the city with peak load results
"""
PeakLoad(self._city).enrich()
def enrich(self): def enrich(self):
""" """
Enrich the city given to the class using the usage factory given handler Enrich the city given to the class using the usage factory given handler

View File

@ -25,3 +25,4 @@ triangle
psycopg2-binary psycopg2-binary
Pillow Pillow
pathlib pathlib
pickle5

View File

@ -87,6 +87,7 @@ setup(
('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')), ('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')),
('hub/data/construction.', glob.glob('hub/data/construction/*')), ('hub/data/construction.', glob.glob('hub/data/construction/*')),
('hub/data/customized_imports', glob.glob('hub/data/customized_imports/*.xml')), ('hub/data/customized_imports', glob.glob('hub/data/customized_imports/*.xml')),
('data/geolocation', glob.glob('hub/data/geolocation/*.txt')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xml')), ('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xml')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.insel')), ('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.insel')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xlsx')), ('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xlsx')),