cleaned some todos

This commit is contained in:
Pilar 2023-02-09 05:29:53 -05:00
parent 5ae78e7c00
commit b61722db2e
8 changed files with 19 additions and 435 deletions

View File

@ -6,8 +6,10 @@ 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 sys
from typing import List, Union from typing import List, Union
import numpy as np import numpy as np
from hub.hub_logger import logger
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.city_model_structure.building_demand.surface import Surface from hub.city_model_structure.building_demand.surface import Surface
from hub.city_model_structure.city_object import CityObject from hub.city_model_structure.city_object import CityObject
@ -46,20 +48,31 @@ class Building(CityObject):
self._roofs = [] self._roofs = []
self._walls = [] self._walls = []
self._internal_walls = [] self._internal_walls = []
self._ground_walls = []
self._attic_floors = []
self._interior_slabs = []
for surface_id, surface in enumerate(self.surfaces): for surface_id, surface in enumerate(self.surfaces):
self._min_x = min(self._min_x, surface.lower_corner[0]) self._min_x = min(self._min_x, surface.lower_corner[0])
self._min_y = min(self._min_y, surface.lower_corner[1]) self._min_y = min(self._min_y, surface.lower_corner[1])
self._min_z = min(self._min_z, surface.lower_corner[2]) self._min_z = min(self._min_z, surface.lower_corner[2])
surface.id = surface_id surface.id = surface_id
# todo: consider all type of surfaces, not only these four
if surface.type == cte.GROUND: if surface.type == cte.GROUND:
self._grounds.append(surface) self._grounds.append(surface)
elif surface.type == cte.WALL: elif surface.type == cte.WALL:
self._walls.append(surface) self._walls.append(surface)
elif surface.type == cte.ROOF: elif surface.type == cte.ROOF:
self._roofs.append(surface) self._roofs.append(surface)
else: elif surface.type == cte.INTERIOR_WALL:
self._internal_walls.append(surface) self._internal_walls.append(surface)
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:
logger.error(f'Building {self.name} [alias {self.alias}] has an unexpected surface type {surface.type}.\n')
sys.stderr.write(f'Building {self.name} [alias {self.alias}] has an unexpected surface type {surface.type}.\n')
@property @property
def shell(self) -> Polyhedron: def shell(self) -> Polyhedron:

View File

@ -6,7 +6,6 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from typing import Union, List from typing import Union, List
from hub.city_model_structure.attributes.schedule import Schedule from hub.city_model_structure.attributes.schedule import Schedule
from hub.city_model_structure.building_demand.occupant import Occupant
class Occupancy: class Occupancy:
@ -106,19 +105,3 @@ class Occupancy:
:param value: [Schedule] :param value: [Schedule]
""" """
self._occupancy_schedules = value self._occupancy_schedules = value
@property
def occupants(self) -> Union[None, List[Occupant]]:
"""
Get list of occupants
:return: None or List of Occupant
"""
return self._occupants
@occupants.setter
def occupants(self, value):
"""
Set list of occupants
:param value: [Occupant]
"""
self._occupants = value

View File

@ -1,145 +0,0 @@
"""
Occupant module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Sanam Dabirian sanam.dabirian@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class Occupant:
"""
Occupant class
"""
def __init__(self):
"""
Constructor
"""
self._heat_dissipation = None
self._occupancy_rate = None
self._occupant_type = None
self._arrival_time = None
self._departure_time = None
self._break_time = None
self._day_of_week = None
self._pd_of_meetings_duration = None
@property
def heat_dissipation(self):
"""
Get heat dissipation of occupants in W/person
:return: float
"""
return self._heat_dissipation
@heat_dissipation.setter
def heat_dissipation(self, value):
"""
Set heat dissipation of occupants in W/person
:param value: float
"""
self._heat_dissipation = float(value)
@property
def occupancy_rate(self):
"""
Get rate of schedules
:return: float
"""
return self._occupancy_rate
@occupancy_rate.setter
def occupancy_rate(self, value):
"""
Set rate of schedules
:param value: float
"""
self._occupancy_rate = float(value)
@property
def occupant_type(self):
"""
Get type of schedules
:return: str
"""
return self._occupant_type
@occupant_type.setter
def occupant_type(self, value):
"""
Set type of schedules
:param value: float
"""
self._occupant_type = float(value)
@property
def arrival_time(self):
"""
Get the arrival time of the occupant (for office building) in UTC with format YYYYMMDD HH:mm:ss
:return: time
"""
return self._arrival_time
@arrival_time.setter
def arrival_time(self, value):
"""
Set the arrival time of the occupant (for office building) in UTC with format YYYYMMDD HH:mm:ss
:param value: time
"""
self._arrival_time = value
@property
def departure_time(self):
"""
Get the departure time of the occupant (for office building) in UTC with format YYYYMMDD HH:mm:ss
:return: time
"""
return self._departure_time
@departure_time.setter
def departure_time(self, value):
"""
Set the departure time of the occupant (for office building) in UTC with format YYYYMMDD HH:mm:ss
:param value: str
"""
self._departure_time = value
@property
def break_time(self):
"""
Get the lunch or break time of the occupant (for office building) in UTC with format ????
:return: break time
"""
# todo @Sanam: define this format, is it the starting time? is it a list with both, starting and ending time?
return self._break_time
@property
def day_of_week(self):
"""
Get the day of the week (MON, TUE, WED, THU, FRI, SAT, SUN)
:return: str
"""
# todo @Sanam: is this a property or should it be a function
# to get the day of the week of an specific day of the year?
return self._day_of_week
@property
def pd_of_meetings_duration(self):
"""
Get the probability distribution of the meeting duration
:return: ??
"""
# todo @Sanam: what format are you expecting here??
return self._pd_of_meetings_duration
@pd_of_meetings_duration.setter
def pd_of_meetings_duration(self, value):
"""
Get the probability distribution of the meeting duration
:param value: ??
:return:
"""
# todo @Sanam: what format are you expecting here??
self._pd_of_meetings_duration = value

View File

@ -72,14 +72,6 @@ class Surface:
if value is not None: if value is not None:
self._id = str(value) self._id = str(value)
# todo: implement share surfaces
@property
def share_surfaces(self):
"""
Raises not implemented error
"""
raise NotImplementedError
def _max_coord(self, axis): def _max_coord(self, axis):
if axis == 'x': if axis == 'x':
axis = 0 axis = 0
@ -163,11 +155,11 @@ class Surface:
@property @property
def type(self): def type(self):
""" """
Get surface type Ground, Wall or Roof Get surface type Ground, Ground wall, Wall, Attic floor, Interior slab, Interior wall, Roof or Virtual internal
If the geometrical LoD is lower than 4,
the surfaces' types are not defined in the importer and can only be Ground, Wall or Roof
:return: str :return: str
""" """
# todo: there are more types: internal wall, internal floor... this method must be redefined
if self._type is None: if self._type is None:
grad = np.rad2deg(self.inclination) grad = np.rad2deg(self.inclination)
if grad >= 170: if grad >= 170:
@ -304,7 +296,7 @@ class Surface:
:return: Surface, Surface, Any :return: Surface, Surface, Any
""" """
# todo: check return types # todo: check return types
# todo: recheck this method for LoD3 (windows) # recheck this method for LoD3 (windows)
origin = Point([0, 0, z]) origin = Point([0, 0, z])
normal = np.array([0, 0, 1]) normal = np.array([0, 0, 1])
plane = Plane(normal=normal, origin=origin) plane = Plane(normal=normal, origin=origin)

View File

@ -23,7 +23,6 @@ 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.machine import Machine from hub.city_model_structure.machine import Machine
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
from hub.city_model_structure.subway_entrance import SubwayEntrance
from hub.helpers.geometry_helper import GeometryHelper from hub.helpers.geometry_helper import GeometryHelper
from hub.helpers.location import Location from hub.helpers.location import Location
from hub.city_model_structure.energy_system import EnergySystem from hub.city_model_structure.energy_system import EnergySystem
@ -40,9 +39,7 @@ class City:
self._lower_corner = lower_corner self._lower_corner = lower_corner
self._upper_corner = upper_corner self._upper_corner = upper_corner
self._buildings = None self._buildings = None
self._subway_entrances = None
self._srs_name = srs_name self._srs_name = srs_name
# todo: right now extracted at city level, in the future should be extracted also at building level if exist
self._location = None self._location = None
self._country_code = None self._country_code = None
self._climate_reference_city = None self._climate_reference_city = None
@ -163,9 +160,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.subway_entrances is not None:
for subway_entrance in self.subway_entrances:
self._city_objects.append(subway_entrance)
if self.energy_systems is not None: if self.energy_systems is not None:
for energy_system in self.energy_systems: for energy_system in self.energy_systems:
self._city_objects.append(energy_system) self._city_objects.append(energy_system)
@ -179,14 +173,6 @@ class City:
""" """
return self._buildings return self._buildings
@property
def subway_entrances(self) -> Union[List[SubwayEntrance], None]:
"""
Get the subway entrances belonging to the city
:return: a list of subway entrances objects or none
"""
return self._subway_entrances
@property @property
def lower_corner(self) -> List[float]: def lower_corner(self) -> List[float]:
""" """
@ -224,10 +210,6 @@ class City:
if self._buildings is None: if self._buildings is None:
self._buildings = [] self._buildings = []
self._buildings.append(new_city_object) self._buildings.append(new_city_object)
elif new_city_object.type == 'subway_entrance':
if self._subway_entrances is None:
self._subway_entrances = []
self._subway_entrances.append(new_city_object)
elif new_city_object.type == 'energy_system': elif new_city_object.type == 'energy_system':
if self._energy_systems is None: if self._energy_systems is None:
self._energy_systems = [] self._energy_systems = []

View File

@ -1,45 +0,0 @@
"""
Subway entrance 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
"""
from hub.city_model_structure.city_object import CityObject
class SubwayEntrance(CityObject):
"""
SubwayEntrance(CityObject) class
"""
def __init__(self, name, latitude, longitude):
super().__init__(name, 0)
self._name = name
self._latitude = latitude
self._longitude = longitude
self._type = 'subway_entrance'
@property
def latitude(self):
# todo: to be defined the spacial point and the units
"""
Get latitude
:return: float
"""
return self._latitude
@property
def longitude(self):
# todo: to be defined the spacial point and the units
"""
Get longitude
:return: float
"""
return self._longitude
@property
def name(self):
"""
Get name
:return: str
"""
return self._name

View File

@ -1,138 +0,0 @@
"""
monthly_to_hourly_demand 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
"""
import calendar as cal
import pandas as pd
from hub.city_model_structure.building_demand.occupant import Occupant
import hub.helpers.constants as cte
class MonthlyToHourlyDemand:
"""
MonthlyToHourlyDemand class
"""
def __init__(self, building, conditioning_seasons):
self._hourly_heating = pd.DataFrame()
self._hourly_cooling = pd.DataFrame()
self._building = building
self._conditioning_seasons = conditioning_seasons
def hourly_heating(self, key):
"""
hourly distribution of the monthly heating of a building
:param key: string
:return: [hourly_heating]
"""
# todo: this method and the insel model have to be reviewed for more than one thermal zone
external_temp = self._building.external_temperature[cte.HOUR]
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
for usage in self._building.usages:
temp_set = float(usage.heating_setpoint)-3
temp_back = float(usage.heating_setback)-3
# todo: if these are data frames, then they should be called as (Occupancy should be in low case):
# usage.schedules.Occupancy
# self._conditioning_seasons.heating
occupancy = Occupant().get_complete_year_schedule(usage.schedules['Occupancy'])
heating_schedule = self._conditioning_seasons['heating']
hourly_heating = []
i = 0
j = 0
temp_grad_day = []
for month in range(1, 13):
temp_grad_month = 0
month_range = cal.monthrange(2015, month)[1]
for _ in range(1, month_range+1):
external_temp_med = 0
for hour in range(0, 24):
external_temp_med += external_temp[key][i]/24
for hour in range(0, 24):
if external_temp_med < temp_set and heating_schedule[month-1] == 1:
if occupancy[hour] > 0:
hdd = temp_set - external_temp[key][i]
if hdd < 0:
hdd = 0
temp_grad_day.append(hdd)
else:
hdd = temp_back - external_temp[key][i]
if hdd < 0:
hdd = 0
temp_grad_day.append(hdd)
else:
temp_grad_day.append(0)
temp_grad_month += temp_grad_day[i]
i += 1
for _ in range(1, month_range + 1):
for hour in range(0, 24):
monthly_demand = self._building.heating[cte.MONTH][month-1]
if monthly_demand == 'NaN':
monthly_demand = 0
if temp_grad_month == 0:
hourly_demand = 0
else:
hourly_demand = float(monthly_demand)*float(temp_grad_day[j])/float(temp_grad_month)
hourly_heating.append(hourly_demand)
j += 1
self._hourly_heating = pd.DataFrame(data=hourly_heating, columns=['monthly to hourly'])
return self._hourly_heating
def hourly_cooling(self, key):
"""
hourly distribution of the monthly cooling of a building
:param key: string
:return: [hourly_cooling]
"""
# todo: this method and the insel model have to be reviewed for more than one thermal zone
external_temp = self._building.external_temperature[cte.HOUR]
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
for usage in self._building.usages:
temp_set = float(usage.cooling_setpoint)
temp_back = 100
occupancy = Occupant().get_complete_year_schedule(usage.schedules['Occupancy'])
cooling_schedule = self._conditioning_seasons['cooling']
hourly_cooling = []
i = 0
j = 0
temp_grad_day = []
for month in range(1, 13):
temp_grad_month = 0
month_range = cal.monthrange(2015, month)[1]
for _ in range(1, month_range[1] + 1):
for hour in range(0, 24):
if external_temp[key][i] > temp_set and cooling_schedule[month - 1] == 1:
if occupancy[hour] > 0:
cdd = external_temp[key][i] - temp_set
if cdd < 0:
cdd = 0
temp_grad_day.append(cdd)
else:
cdd = external_temp[key][i] - temp_back
if cdd < 0:
cdd = 0
temp_grad_day.append(cdd)
else:
temp_grad_day.append(0)
temp_grad_month += temp_grad_day[i]
i += 1
for _ in range(1, month_range[1] + 1):
for hour in range(0, 24):
# monthly_demand = self._building.heating[cte.MONTH]['INSEL'][month-1]
monthly_demand = self._building.cooling[cte.MONTH][month - 1]
if monthly_demand == 'NaN':
monthly_demand = 0
if temp_grad_month == 0:
hourly_demand = 0
else:
hourly_demand = float(monthly_demand) * float(temp_grad_day[j]) / float(temp_grad_month)
hourly_cooling.append(hourly_demand)
j += 1
self._hourly_cooling = pd.DataFrame(data=hourly_cooling, columns=['monthly to hourly'])
return self._hourly_cooling

View File

@ -1,58 +0,0 @@
"""
OsmSubway module parses osm files and import the metro location into the city model structure
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import sys
import xmltodict
from pyproj import Transformer
from hub.city_model_structure.city import City
from hub.city_model_structure.subway_entrance import SubwayEntrance
class OsmSubway:
"""
Open street map subway
"""
def __init__(self, path):
self._city = None
self._subway_entrances = []
with open(path) as osm:
self._osm = xmltodict.parse(osm.read(), force_list='tag')
for node in self._osm['osm']['node']:
if 'tag' not in node:
continue
for tag in node['tag']:
if '@v' not in tag:
continue
if tag['@v'] == 'subway_entrance':
subway_entrance = SubwayEntrance(node['@id'], node['@lat'], node['@lon'])
self._subway_entrances.append(subway_entrance)
@property
def city(self) -> City:
"""
Get a city with subway entrances
"""
transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857")
lower_corner = [sys.float_info.max, sys.float_info.max, 0]
upper_corner = [sys.float_info.min, sys.float_info.min, 0]
x = 0
y = 1
for subway_entrance in self._subway_entrances:
coordinate = transformer.transform(subway_entrance.longitude, subway_entrance.latitude)
if coordinate[x] >= upper_corner[x]:
upper_corner[x] = coordinate[x]
if coordinate[y] >= upper_corner[y]:
upper_corner[y] = coordinate[y]
if coordinate[x] < lower_corner[x]:
lower_corner[x] = coordinate[x]
if coordinate[y] < lower_corner[y]:
lower_corner[y] = coordinate[y]
city = City(lower_corner, upper_corner, 'unknown')
for subway_entrance in self._subway_entrances:
city.add_city_object(subway_entrance)
return city