city_retrofit/hub/city_model_structure/building.py

756 lines
25 KiB
Python
Raw Normal View History

"""
Building module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
2023-05-17 17:10:30 -04:00
import logging
from typing import List, Union, TypeVar
2023-05-17 17:10:30 -04:00
import numpy as np
2023-01-24 10:51:50 -05:00
import hub.helpers.constants as cte
2023-05-17 17:10:30 -04:00
from hub.city_model_structure.attributes.polyhedron import Polyhedron
2023-01-24 10:51:50 -05:00
from hub.city_model_structure.building_demand.household import Household
from hub.city_model_structure.building_demand.internal_zone import InternalZone
2023-06-08 14:18:29 -04:00
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
2023-05-17 17:10:30 -04:00
from hub.city_model_structure.building_demand.surface import Surface
from hub.city_model_structure.city_object import CityObject
from hub.city_model_structure.energy_systems.energy_system import EnergySystem
2023-05-17 17:10:30 -04:00
from hub.helpers.peak_loads import PeakLoads
2021-03-31 14:17:53 -04:00
City = TypeVar('City')
class Building(CityObject):
"""
Building(CityObject) class
"""
def __init__(self, name, surfaces, year_of_construction, function, terrains=None, city=None):
2022-11-28 13:44:02 -05:00
super().__init__(name, surfaces)
self._city = city
2021-10-18 16:07:18 -04:00
self._households = None
self._basement_heated = None
self._attic_heated = None
self._terrains = terrains
self._year_of_construction = year_of_construction
self._function = function
self._average_storey_height = None
self._storeys_above_ground = None
self._floor_area = None
self._roof_type = None
2022-03-08 20:08:03 -05:00
self._internal_zones = None
2023-06-08 14:18:29 -04:00
self._thermal_zones = None
self._shell = None
2023-06-06 17:44:07 -04:00
self._aliases = []
self._type = 'building'
2023-05-30 17:13:49 -04:00
self._cold_water_temperature = {}
self._heating_demand = {}
self._cooling_demand = {}
2023-05-30 17:13:49 -04:00
self._lighting_electrical_demand = {}
self._appliances_electrical_demand = {}
self._domestic_hot_water_heat_demand = {}
self._heating_consumption = {}
self._cooling_consumption = {}
self._domestic_hot_water_consumption = {}
self._distribution_systems_electrical_consumption = {}
self._onsite_electrical_production = {}
2021-03-31 14:17:53 -04:00
self._eave_height = None
self._energy_systems = None
self._systems_archetype_name = None
self._grounds = []
self._roofs = []
self._walls = []
self._internal_walls = []
2023-02-09 05:29:53 -05:00
self._ground_walls = []
self._attic_floors = []
self._interior_slabs = []
for surface_id, surface in enumerate(self.surfaces):
self._min_x = min(self._min_x, surface.lower_corner[0])
self._min_y = min(self._min_y, surface.lower_corner[1])
self._min_z = min(self._min_z, surface.lower_corner[2])
surface.id = surface_id
if surface.type == cte.GROUND:
self._grounds.append(surface)
elif surface.type == cte.WALL:
self._walls.append(surface)
elif surface.type == cte.ROOF:
self._roofs.append(surface)
2023-02-09 05:29:53 -05:00
elif surface.type == cte.INTERIOR_WALL:
self._internal_walls.append(surface)
2023-02-09 05:29:53 -05:00
elif surface.type == cte.GROUND_WALL:
self._ground_walls.append(surface)
elif surface.type == cte.ATTIC_FLOOR:
self._attic_floors.append(surface)
elif surface.type == cte.INTERIOR_SLAB:
self._interior_slabs.append(surface)
else:
2023-06-06 14:31:25 -04:00
logging.error(f'Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type)
@property
2022-03-08 20:08:03 -05:00
def shell(self) -> Polyhedron:
"""
Get building's external polyhedron
2022-03-08 20:08:03 -05:00
:return: [Polyhedron]
"""
polygons = []
for surface in self.surfaces:
if surface.type is not cte.INTERIOR_WALL:
polygons.append(surface.solid_polygon)
if surface.holes_polygons is not None:
for hole in surface.holes_polygons:
polygons.append(hole)
2022-03-08 20:08:03 -05:00
if self._shell is None:
self._shell = Polyhedron(polygons)
2022-03-08 20:08:03 -05:00
return self._shell
@property
def internal_zones(self) -> List[InternalZone]:
"""
Get building internal zones
For Lod up to 3, there is only one internal zone which corresponds to the building shell.
In LoD 4 there can be more than one. In this case the definition of surfaces and floor area must be redefined.
:return: [InternalZone]
"""
if self._internal_zones is None:
self._internal_zones = [InternalZone(self.surfaces, self.floor_area)]
return self._internal_zones
2023-06-08 14:18:29 -04:00
@property
def thermal_zones(self) -> Union[None, List[ThermalZone]]:
"""
Get building thermal zones
For Lod up to 3, there can be more than one thermal zone per internal zone.
In LoD 4, there can be more than one internal zone, and therefore, only one thermal zone per internal zone
:return: [ThermalZone]
"""
if self._thermal_zones is None:
self._thermal_zones = []
for internal_zone in self.internal_zones:
if internal_zone.thermal_zones is None:
self._thermal_zones = None
return self._thermal_zones
for thermal_zone in internal_zone.thermal_zones:
self._thermal_zones.append(thermal_zone)
return self._thermal_zones
@property
2021-09-01 09:39:27 -04:00
def grounds(self) -> List[Surface]:
"""
Get building ground surfaces
2021-09-01 09:39:27 -04:00
:return: [Surface]
"""
return self._grounds
@property
2021-09-01 09:39:27 -04:00
def roofs(self) -> List[Surface]:
"""
Get building roof surfaces
:return: [Surface]
"""
return self._roofs
@property
2021-09-01 09:39:27 -04:00
def walls(self) -> List[Surface]:
"""
Get building wall surfaces
:return: [Surface]
"""
return self._walls
@property
def internal_walls(self) -> List[Surface]:
"""
Get building internal wall surfaces
:return: [Surface]
"""
return self._internal_walls
@property
2022-03-08 19:19:52 -05:00
def terrains(self) -> Union[None, List[Surface]]:
"""
Get city object terrain surfaces
:return: [Surface]
"""
return self._terrains
@property
2021-09-14 13:46:48 -04:00
def attic_heated(self) -> Union[None, int]:
"""
Get if the city object attic is heated
2022-11-25 14:45:03 -05:00
0: no attic in the building
1: attic exists but is not heated
2: attic exists and is heated
2021-09-14 13:46:48 -04:00
:return: None or int
"""
return self._attic_heated
@attic_heated.setter
def attic_heated(self, value):
"""
Set if the city object attic is heated
2022-11-25 14:45:03 -05:00
0: no attic in the building
1: attic exists but is not heated
2: attic exists and is heated
2021-09-14 13:46:48 -04:00
:param value: int
"""
2021-09-14 13:46:48 -04:00
if value is not None:
self._attic_heated = int(value)
@property
2021-09-14 13:46:48 -04:00
def basement_heated(self) -> Union[None, int]:
"""
Get if the city object basement is heated
2022-11-25 14:45:03 -05:00
0: no basement in the building
1: basement exists but is not heated
2: basement exists and is heated
2021-09-14 13:46:48 -04:00
:return: None or int
"""
return self._basement_heated
@basement_heated.setter
def basement_heated(self, value):
"""
Set if the city object basement is heated
2022-11-25 14:45:03 -05:00
0: no basement in the building
1: basement exists but is not heated
2: basement exists and is heated
2021-09-14 13:46:48 -04:00
:param value: int
"""
2021-09-14 13:46:48 -04:00
if value is not None:
self._basement_heated = int(value)
@property
def year_of_construction(self):
"""
Get building year of construction
:return: int
"""
return self._year_of_construction
@year_of_construction.setter
def year_of_construction(self, value):
"""
Set building year of construction
:param value: int
"""
if value is not None:
2022-03-08 19:19:52 -05:00
self._year_of_construction = int(value)
@property
2021-09-14 13:46:48 -04:00
def function(self) -> Union[None, str]:
"""
Get building function
2021-09-14 13:46:48 -04:00
:return: None or str
"""
return self._function
@function.setter
def function(self, value):
"""
Set building function
:param value: str
"""
2021-09-14 13:46:48 -04:00
if value is not None:
self._function = str(value)
@property
2021-09-14 13:46:48 -04:00
def average_storey_height(self) -> Union[None, float]:
"""
Get building average storey height in meters
2021-09-14 13:46:48 -04:00
:return: None or float
"""
return self._average_storey_height
@average_storey_height.setter
def average_storey_height(self, value):
"""
Set building average storey height in meters
:param value: float
"""
2021-09-14 13:46:48 -04:00
if value is not None:
self._average_storey_height = float(value)
@property
2021-09-14 13:46:48 -04:00
def storeys_above_ground(self) -> Union[None, int]:
"""
Get building storeys number above ground
2021-09-14 13:46:48 -04:00
:return: None or int
"""
if self._storeys_above_ground is None:
if self.eave_height is not None and self.average_storey_height is not None:
self._storeys_above_ground = int(self.eave_height / self.average_storey_height)
return self._storeys_above_ground
@storeys_above_ground.setter
def storeys_above_ground(self, value):
"""
Set building storeys number above ground
:param value: int
"""
2021-09-14 13:46:48 -04:00
if value is not None:
self._storeys_above_ground = int(value)
2023-03-20 14:15:57 -04:00
@property
def cold_water_temperature(self) -> {float}:
"""
Get cold water temperature in degrees Celsius
:return: dict{DataFrame(float)}
"""
return self._cold_water_temperature
@cold_water_temperature.setter
def cold_water_temperature(self, value):
"""
Set cold water temperature in degrees Celsius
:param value: dict{DataFrame(float)}
"""
self._cold_water_temperature = value
@property
def heating_demand(self) -> dict:
"""
Get heating demand in Wh
:return: dict{DataFrame(float)}
"""
return self._heating_demand
@heating_demand.setter
def heating_demand(self, value):
"""
Set heating demand in Wh
:param value: dict{DataFrame(float)}
"""
2023-06-07 12:55:03 -04:00
self._heating_demand = value
@property
def cooling_demand(self) -> dict:
"""
Get cooling demand in Wh
:return: dict{DataFrame(float)}
"""
return self._cooling_demand
@cooling_demand.setter
def cooling_demand(self, value):
"""
Set cooling demand in Wh
:param value: dict{DataFrame(float)}
"""
2023-06-07 12:55:03 -04:00
self._cooling_demand = value
@property
def lighting_electrical_demand(self) -> dict:
"""
Get lighting electrical demand in Wh
:return: dict{DataFrame(float)}
"""
return self._lighting_electrical_demand
@lighting_electrical_demand.setter
def lighting_electrical_demand(self, value):
"""
Set lighting electrical demand in Wh
:param value: dict{DataFrame(float)}
"""
self._lighting_electrical_demand = value
@property
def appliances_electrical_demand(self) -> dict:
"""
Get appliances electrical demand in Wh
:return: dict{DataFrame(float)}
"""
return self._appliances_electrical_demand
@appliances_electrical_demand.setter
def appliances_electrical_demand(self, value):
"""
Set appliances electrical demand in Wh
:param value: dict{DataFrame(float)}
"""
self._appliances_electrical_demand = value
@property
def domestic_hot_water_heat_demand(self) -> dict:
"""
Get domestic hot water heat demand in Wh
:return: dict{DataFrame(float)}
"""
return self._domestic_hot_water_heat_demand
@domestic_hot_water_heat_demand.setter
def domestic_hot_water_heat_demand(self, value):
"""
Set domestic hot water heat demand in Wh
:param value: dict{DataFrame(float)}
"""
self._domestic_hot_water_heat_demand = value
2023-04-18 12:21:00 -04:00
@property
2023-05-12 09:27:29 -04:00
def heating_peak_load(self) -> Union[None, dict]:
2023-04-18 12:21:00 -04:00
"""
Get heating peak load in W
:return: dict{DataFrame(float)}
"""
2023-04-27 13:31:00 -04:00
results = {}
if cte.HOUR in self.heating_demand:
2023-05-12 09:27:29 -04:00
monthly_values = PeakLoads().\
peak_loads_from_hourly(self.heating_demand[cte.HOUR][next(iter(self.heating_demand[cte.HOUR]))])
2023-05-01 10:37:51 -04:00
else:
2023-05-12 09:27:29 -04:00
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
if monthly_values is None:
return None
2023-06-02 15:05:29 -04:00
results[cte.MONTH] = monthly_values
results[cte.YEAR] = [max(monthly_values)]
2023-04-27 13:31:00 -04:00
return results
2023-04-18 12:21:00 -04:00
@property
2023-05-12 09:27:29 -04:00
def cooling_peak_load(self) -> Union[None, dict]:
2023-04-18 12:21:00 -04:00
"""
Get cooling peak load in W
:return: dict{DataFrame(float)}
"""
2023-04-27 13:31:00 -04:00
results = {}
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]))])
2023-05-01 10:37:51 -04:00
else:
2023-05-12 09:27:29 -04:00
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
if monthly_values is None:
return None
2023-06-02 15:05:29 -04:00
results[cte.MONTH] = monthly_values
results[cte.YEAR] = [max(monthly_values)]
2023-05-01 10:37:51 -04:00
return results
2023-04-18 12:21:00 -04:00
@property
2021-03-31 14:17:53 -04:00
def eave_height(self):
"""
Get building eave height in meters
2021-03-31 14:17:53 -04:00
:return: float
"""
if self._eave_height is None:
self._eave_height = 0
for wall in self.walls:
2023-06-02 15:05:29 -04:00
self._eave_height = max(self._eave_height, wall.upper_corner[2]) - self.simplified_polyhedron.min_z
2021-03-31 14:17:53 -04:00
return self._eave_height
@property
def roof_type(self):
"""
Get roof type for the building flat or pitch
:return: str
"""
if self._roof_type is None:
self._roof_type = 'flat'
for roof in self.roofs:
grads = np.rad2deg(roof.inclination)
if 355 > grads > 5:
self._roof_type = 'pitch'
break
return self._roof_type
2022-03-08 19:19:52 -05:00
@roof_type.setter
def roof_type(self, value):
"""
Set roof type for the building flat or pitch
:return: str
"""
self._roof_type = value
@property
def floor_area(self):
"""
Get building floor area in square meters
:return: float
"""
if self._floor_area is None:
self._floor_area = 0
for surface in self.surfaces:
if surface.type == 'Ground':
self._floor_area += surface.perimeter_polygon.area
return self._floor_area
2021-10-18 16:07:18 -04:00
@property
def households(self) -> List[Household]:
"""
Get the list of households inside the building
:return: List[Household]
"""
return self._households
2022-03-08 19:19:52 -05:00
@property
def is_conditioned(self):
"""
Get building heated flag
:return: Boolean
"""
if self.internal_zones is None:
2022-03-08 19:19:52 -05:00
return False
for internal_zone in self.internal_zones:
2022-12-06 15:28:59 -05:00
if internal_zone.usages is not None:
2023-01-26 08:53:00 -05:00
for usage in internal_zone.usages:
if usage.thermal_control is not None:
return True
2022-03-08 19:19:52 -05:00
return False
@property
def aliases(self):
"""
2023-01-31 13:11:39 -05:00
Get the alias name for the building
:return: str
"""
return self._aliases
def add_alias(self, value):
"""
Add a new alias for the building
"""
2023-06-06 17:44:07 -04:00
self._aliases.append(value)
if self.city is not None:
self.city.add_building_alias(self, value)
@property
def city(self) -> City:
"""
Get the city containing the building
:return: City
"""
return self._city
@city.setter
def city(self, value):
"""
Set the city containing the building
"""
self._city = value
2023-02-07 06:16:08 -05:00
@property
def usages_percentage(self):
"""
Get the usages and percentages for the building
"""
_usage = ''
for internal_zone in self.internal_zones:
if internal_zone.usages is None:
continue
2023-02-07 06:16:08 -05:00
for usage in internal_zone.usages:
_usage = f'{_usage}{usage.name}_{usage.percentage} '
return _usage.rstrip()
@property
def energy_systems(self) -> Union[None, List[EnergySystem]]:
"""
Get list of energy systems installed to cover the building demands
:return: [EnergySystem]
"""
return self._energy_systems
@energy_systems.setter
def energy_systems(self, value):
"""
Set list of energy systems installed to cover the building demands
:param value: [EnergySystem]
"""
self._energy_systems = value
@property
2023-05-02 12:35:42 -04:00
def energy_systems_archetype_name(self):
"""
2023-05-02 12:35:42 -04:00
Get energy systems archetype name
:return: str
"""
return self._systems_archetype_name
2023-05-02 12:35:42 -04:00
@energy_systems_archetype_name.setter
def energy_systems_archetype_name(self, value):
"""
2023-05-02 12:35:42 -04:00
Set energy systems archetype name
:param value: str
"""
self._systems_archetype_name = value
@property
def heating_consumption(self):
"""
Get energy consumption for heating according to the heating system installed in Wh
return: dict
"""
if len(self._heating_consumption) == 0:
for heating_demand_key in self.heating_demand:
demand = self.heating_demand[heating_demand_key][cte.INSEL_MEB]
consumption_type = cte.HEATING
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
2023-05-29 15:26:21 -04:00
if final_energy_consumed is None:
continue
self._heating_consumption[heating_demand_key] = final_energy_consumed
return self._heating_consumption
@property
def cooling_consumption(self):
"""
Get energy consumption for cooling according to the cooling system installed in Wh
return: dict
"""
if len(self._cooling_consumption) == 0:
for cooling_demand_key in self.cooling_demand:
demand = self.cooling_demand[cooling_demand_key][cte.INSEL_MEB]
consumption_type = cte.COOLING
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
2023-05-29 15:26:21 -04:00
if final_energy_consumed is None:
continue
self._cooling_consumption[cooling_demand_key] = final_energy_consumed
return self._cooling_consumption
@property
def domestic_hot_water_consumption(self):
"""
Get energy consumption for domestic according to the domestic hot water system installed in Wh
return: dict
"""
if len(self._domestic_hot_water_consumption) == 0:
for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand:
demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key][cte.INSEL_MEB]
consumption_type = cte.DOMESTIC_HOT_WATER
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
2023-05-29 15:26:21 -04:00
if final_energy_consumed is None:
continue
self._domestic_hot_water_consumption[domestic_hot_water_demand_key] = final_energy_consumed
return self._domestic_hot_water_consumption
def _calculate_working_hours(self):
_working_hours = {}
for internal_zone in self.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
_working_hours_per_thermal_zone = {}
for schedule in thermal_zone.thermal_control.hvac_availability_schedules:
_working_hours_per_schedule = [0] * len(schedule.values)
for i, value in enumerate(schedule.values):
if value > 0:
_working_hours_per_schedule[i] = 1
2023-06-07 14:40:44 -04:00
for day_type in schedule.day_types:
_working_hours_per_thermal_zone[day_type] = _working_hours_per_schedule
if len(_working_hours) == 0:
_working_hours = _working_hours_per_thermal_zone
else:
2023-05-30 17:13:49 -04:00
for key, item in _working_hours.items():
saved_values = _working_hours_per_thermal_zone[key]
2023-05-30 17:13:49 -04:00
for i, value in enumerate(item):
2023-06-07 14:40:44 -04:00
_working_hours[key][i] = max(_working_hours[key][i], saved_values[i])
_total_hours = 0
for key in _working_hours:
hours = sum(_working_hours[key])
_total_hours += hours * cte.DAYS_A_YEAR[key]
return _total_hours
@property
def distribution_systems_electrical_consumption(self):
"""
Get total electricity consumption for distribution and emission systems in Wh
return: dict
"""
2023-05-30 17:13:49 -04:00
if len(self._distribution_systems_electrical_consumption) != 0:
return self._distribution_systems_electrical_consumption
2023-06-02 15:05:29 -04:00
_peak_load = self.heating_peak_load[cte.YEAR][0]
2023-05-30 17:13:49 -04:00
_peak_load_type = cte.HEATING
2023-06-02 15:05:29 -04:00
if _peak_load < self.cooling_peak_load[cte.YEAR][0]:
_peak_load = self.cooling_peak_load[cte.YEAR][0]
2023-05-30 17:13:49 -04:00
_peak_load_type = cte.COOLING
_working_hours = self._calculate_working_hours()
2023-05-30 17:13:49 -04:00
_consumption_fix_flow = 0
if self.energy_systems is None:
return self._distribution_systems_electrical_consumption
2023-05-30 17:13:49 -04:00
for energy_system in self.energy_systems:
emission_system = energy_system.emission_system.generic_emission_system
parasitic_energy_consumption = 0
if emission_system is not None:
parasitic_energy_consumption = emission_system.parasitic_energy_consumption
2023-05-30 17:13:49 -04:00
distribution_system = energy_system.distribution_system.generic_distribution_system
consumption_variable_flow = distribution_system.distribution_consumption_variable_flow
for demand_type in energy_system.demand_types:
if demand_type.lower() == cte.HEATING.lower():
if _peak_load_type == cte.HEATING.lower():
2023-05-30 17:13:49 -04:00
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
for heating_demand_key in self.heating_demand:
_consumption = [0]*len(self.heating_demand[heating_demand_key][cte.INSEL_MEB])
_demand = self.heating_demand[heating_demand_key][cte.INSEL_MEB]
2023-06-01 14:10:03 -04:00
for i, _ in enumerate(_consumption):
2023-05-30 17:13:49 -04:00
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
if demand_type.lower() == cte.COOLING.lower():
if _peak_load_type == cte.COOLING.lower():
2023-05-30 17:13:49 -04:00
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
for demand_key in self.cooling_demand:
2023-05-30 17:13:49 -04:00
_consumption = self._distribution_systems_electrical_consumption[demand_key]
_demand = self.cooling_demand[demand_key][cte.INSEL_MEB]
2023-06-01 14:10:03 -04:00
for i, _ in enumerate(_consumption):
2023-05-30 17:13:49 -04:00
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
self._distribution_systems_electrical_consumption[demand_key] = _consumption
for key, item in self._distribution_systems_electrical_consumption.items():
for i in range(0, len(item)):
self._distribution_systems_electrical_consumption[key][i] += _peak_load * _consumption_fix_flow \
* _working_hours
return self._distribution_systems_electrical_consumption
def _calculate_consumption(self, consumption_type, demand):
# todo: modify when COP depends on the hour
coefficient_of_performance = 0
2023-05-29 15:26:21 -04:00
if self.energy_systems is None:
return None
for energy_system in self.energy_systems:
for demand_type in energy_system.demand_types:
2023-05-12 09:27:29 -04:00
if demand_type.lower() == consumption_type.lower():
2023-05-30 17:13:49 -04:00
if consumption_type in (cte.HEATING, cte.DOMESTIC_HOT_WATER):
coefficient_of_performance = energy_system.generation_system.generic_generation_system.heat_efficiency
elif consumption_type == cte.COOLING:
coefficient_of_performance = energy_system.generation_system.generic_generation_system.cooling_efficiency
elif consumption_type == cte.ELECTRICITY:
coefficient_of_performance = \
energy_system.generation_system.generic_generation_system.electricity_efficiency
if coefficient_of_performance == 0:
values = [0]*len(demand)
final_energy_consumed = values
else:
final_energy_consumed = []
for demand_value in demand:
final_energy_consumed.append(demand_value / coefficient_of_performance)
return final_energy_consumed
@property
def onsite_electrical_production(self):
"""
Get total electricity produced onsite in Wh
return: dict
"""
# Add other systems whenever new ones appear
orientation_losses_factor = {cte.MONTH: {'north': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'east': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'south': [2.137931, 1.645503, 1.320946, 1.107817, 0.993213, 0.945175,
0.967949, 1.065534, 1.24183, 1.486486, 1.918033, 2.210526],
'west': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]},
cte.YEAR: {'north': [0],
'east': [0],
'south': [1.212544],
'west': [0]}
}
2023-05-29 15:26:21 -04:00
if self.energy_systems is None:
return self._onsite_electrical_production
for energy_system in self.energy_systems:
if energy_system.generation_system.generic_generation_system.type == cte.PHOTOVOLTAIC:
_efficiency = energy_system.generation_system.generic_generation_system.electricity_efficiency
self._onsite_electrical_production = {}
2023-05-12 09:27:29 -04:00
for _key in self.roofs[0].global_irradiance.keys():
_results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key][cte.SRA]))]
for surface in self.roofs:
if _key in orientation_losses_factor:
_results = [x + y * _efficiency * surface.perimeter_area
* surface.solar_collectors_area_reduction_factor * z
for x, y, z in zip(_results, surface.global_irradiance[_key][cte.SRA],
orientation_losses_factor[_key]['south'])]
2023-05-12 09:27:29 -04:00
self._onsite_electrical_production[_key] = _results
return self._onsite_electrical_production