Compare commits
7 Commits
main
...
feature/cm
Author | SHA1 | Date | |
---|---|---|---|
b4f1a2471e | |||
79edd8f6a2 | |||
04214be864 | |||
f6955130be | |||
7cc7221ab8 | |||
0a2ea1061f | |||
a477a2b893 |
1265846
data/cmm_points_function_vintage_surface.csv
Normal file
1265846
data/cmm_points_function_vintage_surface.csv
Normal file
File diff suppressed because it is too large
Load Diff
210241
data/energy_demand_data.csv
Normal file
210241
data/energy_demand_data.csv
Normal file
File diff suppressed because it is too large
Load Diff
56
hub/city_model_structure/simplified_building.py
Normal file
56
hub/city_model_structure/simplified_building.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
from typing import Union
|
||||
|
||||
|
||||
class SimplifiedBuilding:
|
||||
"""
|
||||
SimplifiedBuilding class
|
||||
"""
|
||||
def __init__(self, name, centroid=None, postal_code=None, total_floor_area=None, year_of_construction=None, function=None, city=None):
|
||||
self._name = name
|
||||
self._centroid = centroid
|
||||
self._total_floor_area = total_floor_area
|
||||
self._year_of_construction = year_of_construction
|
||||
self._function = function
|
||||
self._postal_code = postal_code
|
||||
self._city = city
|
||||
self._type = 'building'
|
||||
self.heating_demand = []
|
||||
self.cooling_demand = []
|
||||
self.electricity_demand = []
|
||||
self.appliance_demand = []
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def centroid(self):
|
||||
return self._centroid
|
||||
|
||||
@property
|
||||
def postal_code(self):
|
||||
return self._postal_code
|
||||
|
||||
@property
|
||||
def total_floor_area(self):
|
||||
return self._total_floor_area
|
||||
|
||||
@property
|
||||
def year_of_construction(self):
|
||||
return self._year_of_construction
|
||||
|
||||
@property
|
||||
def function(self) -> Union[None, str]:
|
||||
return self._function
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def city(self):
|
||||
return self._city
|
||||
|
||||
@city.setter
|
||||
def city(self, value):
|
||||
self._city = value
|
31
hub/city_model_structure/simplified_city.py
Normal file
31
hub/city_model_structure/simplified_city.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
from typing import List
|
||||
from hub.city_model_structure.simplified_building import SimplifiedBuilding
|
||||
|
||||
class SimplifiedCity:
|
||||
"""
|
||||
SimplifiedCity class
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._name = "Montreal Metropolitan Area"
|
||||
self._buildings = []
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value):
|
||||
if value is not None:
|
||||
self._name = str(value)
|
||||
|
||||
@property
|
||||
def buildings(self) -> List[SimplifiedBuilding]:
|
||||
return self._buildings
|
||||
|
||||
def add_city_object(self, new_city_object):
|
||||
if new_city_object.type == 'building':
|
||||
self._buildings.append(new_city_object)
|
||||
new_city_object.city = self
|
||||
else:
|
||||
raise NotImplementedError(f"Type {new_city_object.type} is not supported")
|
|
@ -627,7 +627,333 @@ class MontrealFunctionToHubFunction:
|
|||
'4815': cte.NON_HEATED,
|
||||
'6651': cte.WORKSHOP,
|
||||
'2822': cte.INDUSTRY,
|
||||
'2821': cte.INDUSTRY
|
||||
'2821': cte.INDUSTRY,
|
||||
'1211': cte.RESIDENTIAL,
|
||||
'8133': cte.INDUSTRY,
|
||||
'6572': cte.HEALTH_CARE,
|
||||
'2734': cte.INDUSTRY,
|
||||
'8132': cte.INDUSTRY,
|
||||
'6659': cte.INDUSTRY,
|
||||
'6332': cte.COMMERCIAL,
|
||||
'6595': cte.COMMERCIAL,
|
||||
'5393': cte.COMMERCIAL,
|
||||
'5450': cte.COMMERCIAL,
|
||||
'8127': cte.INDUSTRY,
|
||||
'5595': cte.COMMERCIAL,
|
||||
'6571': cte.HEALTH_CARE,
|
||||
'5030': cte.COMMERCIAL,
|
||||
'9460': cte.WAREHOUSE,
|
||||
'7516': cte.SPORTS_LOCATION,
|
||||
'5523': cte.COMMERCIAL,
|
||||
'5722': cte.COMMERCIAL,
|
||||
'4732': cte.NON_HEATED,
|
||||
'7491': cte.SPORTS_LOCATION,
|
||||
'3262': cte.INDUSTRY,
|
||||
'8543': cte.INDUSTRY,
|
||||
'6129': cte.COMMERCIAL,
|
||||
'5362': cte.COMMERCIAL,
|
||||
'8122': cte.INDUSTRY,
|
||||
'5597': cte.COMMERCIAL,
|
||||
'3269': cte.INDUSTRY,
|
||||
'5331': cte.COMMERCIAL,
|
||||
'5522': cte.COMMERCIAL,
|
||||
'7421': cte.WAREHOUSE,
|
||||
'2723': cte.INDUSTRY,
|
||||
'4822': cte.NON_HEATED,
|
||||
'6319': cte.COMMERCIAL,
|
||||
'8131': cte.INDUSTRY,
|
||||
'7422': cte.SPORTS_LOCATION,
|
||||
'3140': cte.INDUSTRY,
|
||||
'9220': cte.NON_HEATED,
|
||||
'4852': cte.NON_HEATED,
|
||||
'3694': cte.INDUSTRY,
|
||||
'6632': cte.COMMERCIAL,
|
||||
'6656': cte.WAREHOUSE,
|
||||
'8322': cte.INDUSTRY,
|
||||
'8126': cte.INDUSTRY,
|
||||
'6638': cte.COMMERCIAL,
|
||||
'2292': cte.INDUSTRY,
|
||||
'6392': cte.COMMERCIAL,
|
||||
'4313': cte.WAREHOUSE,
|
||||
'4312': cte.NON_HEATED,
|
||||
'6417': cte.COMMERCIAL,
|
||||
'6234': cte.COMMERCIAL,
|
||||
'6254': cte.COMMERCIAL,
|
||||
'7396': cte.SPORTS_LOCATION,
|
||||
'3579': cte.INDUSTRY,
|
||||
'6596': cte.COMMERCIAL,
|
||||
'5397': cte.COMMERCIAL,
|
||||
'5946': cte.COMMERCIAL,
|
||||
'6657': cte.COMMERCIAL,
|
||||
'6995': cte.COMMERCIAL,
|
||||
'6711': cte.OFFICE_AND_ADMINISTRATION,
|
||||
'5713': cte.COMMERCIAL,
|
||||
'5954': cte.COMMERCIAL,
|
||||
'6342': cte.COMMERCIAL,
|
||||
'6333': cte.COMMERCIAL,
|
||||
'5932': cte.COMMERCIAL,
|
||||
'5332': cte.COMMERCIAL,
|
||||
'3510': cte.INDUSTRY,
|
||||
'5732': cte.COMMERCIAL,
|
||||
'4811': cte.INDUSTRY,
|
||||
'5422': cte.COMMERCIAL,
|
||||
'5596': cte.COMMERCIAL,
|
||||
'5740': cte.COMMERCIAL,
|
||||
'3232': cte.INDUSTRY,
|
||||
'5933': cte.COMMERCIAL,
|
||||
'5992': cte.COMMERCIAL,
|
||||
'3443': cte.INDUSTRY,
|
||||
'2472': cte.INDUSTRY,
|
||||
'6151': cte.COMMERCIAL,
|
||||
'3263': cte.INDUSTRY,
|
||||
'5396': cte.COMMERCIAL,
|
||||
'3249': cte.INDUSTRY,
|
||||
'4752': cte.COMMERCIAL,
|
||||
'6836': cte.EDUCATION,
|
||||
'3934': cte.INDUSTRY,
|
||||
'4849': cte.NON_HEATED,
|
||||
'4749': cte.NON_HEATED,
|
||||
'3441': cte.INDUSTRY,
|
||||
'7441': cte.SPORTS_LOCATION,
|
||||
'6320': cte.COMMERCIAL,
|
||||
'6191': cte.COMMERCIAL,
|
||||
'6561': cte.HEALTH_CARE,
|
||||
'5185': cte.COMMERCIAL,
|
||||
'4731': cte.COMMERCIAL,
|
||||
'5680': cte.COMMERCIAL,
|
||||
'9458': cte.COMMERCIAL,
|
||||
'2737': cte.INDUSTRY,
|
||||
'3264': cte.INDUSTRY,
|
||||
'6233': cte.COMMERCIAL,
|
||||
'4819': cte.INDUSTRY,
|
||||
'5183': cte.COMMERCIAL,
|
||||
'6724': cte.OFFICE_AND_ADMINISTRATION,
|
||||
'6131': cte.COMMERCIAL,
|
||||
'8121': cte.INDUSTRY,
|
||||
'6652': cte.WAREHOUSE,
|
||||
'5983': cte.COMMERCIAL,
|
||||
'7393': cte.SPORTS_LOCATION,
|
||||
'3350': cte.INDUSTRY,
|
||||
'6397': cte.COMMERCIAL,
|
||||
'3594': cte.INDUSTRY,
|
||||
'6637': cte.WAREHOUSE,
|
||||
'5191': cte.COMMERCIAL,
|
||||
'6636': cte.WAREHOUSE,
|
||||
'2061': cte.INDUSTRY,
|
||||
'2049': cte.INDUSTRY,
|
||||
'8299': cte.WAREHOUSE,
|
||||
'8180': cte.COMMERCIAL,
|
||||
'6516': cte.HEALTH_CARE,
|
||||
'6597': cte.OFFICE_AND_ADMINISTRATION,
|
||||
'2933': cte.INDUSTRY,
|
||||
'5154': cte.COMMERCIAL,
|
||||
'6371': cte.WAREHOUSE,
|
||||
'5995': cte.COMMERCIAL,
|
||||
'4772': cte.COMMERCIAL,
|
||||
'4760': cte.COMMERCIAL,
|
||||
'6493': cte.COMMERCIAL,
|
||||
'5947': cte.COMMERCIAL,
|
||||
'5242': cte.COMMERCIAL,
|
||||
'5892': cte.COMMERCIAL,
|
||||
'5719': cte.COMMERCIAL,
|
||||
'2895': cte.INDUSTRY,
|
||||
'7415': cte.SPORTS_LOCATION,
|
||||
'4563': cte.NON_HEATED,
|
||||
'3014': cte.INDUSTRY,
|
||||
'5691': cte.COMMERCIAL,
|
||||
'3111': cte.INDUSTRY,
|
||||
'8198': cte.INDUSTRY,
|
||||
'8141': cte.INDUSTRY,
|
||||
'7452': cte.WAREHOUSE,
|
||||
'3222': cte.INDUSTRY,
|
||||
'2713': cte.INDUSTRY,
|
||||
'2088': cte.INDUSTRY,
|
||||
'6564': cte.HEALTH_CARE,
|
||||
'6622': cte.WAREHOUSE,
|
||||
'5440': cte.COMMERCIAL,
|
||||
'2894': cte.INDUSTRY,
|
||||
'6625': cte.WAREHOUSE,
|
||||
'6239': cte.COMMERCIAL,
|
||||
'8129': cte.WAREHOUSE,
|
||||
'6647': cte.WAREHOUSE,
|
||||
'8137': cte.WAREHOUSE,
|
||||
'6553': cte.COMMERCIAL,
|
||||
'3442': cte.INDUSTRY,
|
||||
'4391': cte.NON_HEATED,
|
||||
'5591': cte.COMMERCIAL,
|
||||
'5151': cte.COMMERCIAL,
|
||||
'5196': cte.COMMERCIAL,
|
||||
'6616': cte.COMMERCIAL,
|
||||
'2216': cte.INDUSTRY,
|
||||
'8191': cte.WAREHOUSE,
|
||||
'6422': cte.COMMERCIAL,
|
||||
'1212': cte.RESIDENTIAL,
|
||||
'8134': cte.WAREHOUSE,
|
||||
'5194': cte.COMMERCIAL,
|
||||
'6658': cte.WAREHOUSE,
|
||||
'8123': cte.WAREHOUSE,
|
||||
'6346': cte.COMMERCIAL,
|
||||
'2731': cte.INDUSTRY,
|
||||
'7445': cte.COMMERCIAL,
|
||||
'8125': cte.WAREHOUSE,
|
||||
'4746': cte.NON_HEATED,
|
||||
'3922': cte.INDUSTRY,
|
||||
'5360': cte.WAREHOUSE,
|
||||
'3330': cte.WAREHOUSE,
|
||||
'7610': cte.WAREHOUSE,
|
||||
'6142': cte.WAREHOUSE,
|
||||
'4610': cte.WAREHOUSE,
|
||||
'6552': cte.WAREHOUSE,
|
||||
'8120': cte.WAREHOUSE,
|
||||
'6313': cte.WAREHOUSE,
|
||||
'6398': cte.WAREHOUSE,
|
||||
'6730': cte.WAREHOUSE,
|
||||
'6153': cte.WAREHOUSE,
|
||||
'3013': cte.WAREHOUSE,
|
||||
'5187': cte.WAREHOUSE,
|
||||
'5182': cte.WAREHOUSE,
|
||||
'6336': cte.WAREHOUSE,
|
||||
'5122': cte.WAREHOUSE,
|
||||
'3914': cte.WAREHOUSE,
|
||||
'3480': cte.WAREHOUSE,
|
||||
'8135': cte.WAREHOUSE,
|
||||
'3979': cte.WAREHOUSE,
|
||||
'8319': cte.WAREHOUSE,
|
||||
'6155': cte.WAREHOUSE,
|
||||
'5998': cte.WAREHOUSE,
|
||||
'3016': cte.WAREHOUSE,
|
||||
'5333': cte.WAREHOUSE,
|
||||
'6381': cte.WAREHOUSE,
|
||||
'5912': cte.WAREHOUSE,
|
||||
'4829': cte.WAREHOUSE,
|
||||
'2732': cte.WAREHOUSE,
|
||||
'5993': cte.WAREHOUSE,
|
||||
'2735': cte.WAREHOUSE,
|
||||
'6421': cte.WAREHOUSE,
|
||||
'5981': cte.WAREHOUSE,
|
||||
'7213': cte.WAREHOUSE,
|
||||
'5994': cte.WAREHOUSE,
|
||||
'3940': cte.WAREHOUSE,
|
||||
'3893': cte.WAREHOUSE,
|
||||
'6729': cte.WAREHOUSE,
|
||||
'3152': cte.WAREHOUSE,
|
||||
'6991': cte.WAREHOUSE,
|
||||
'6626': cte.WAREHOUSE,
|
||||
'6149': cte.WAREHOUSE,
|
||||
'4764': cte.WAREHOUSE,
|
||||
'7511': cte.WAREHOUSE,
|
||||
'6655': cte.WAREHOUSE,
|
||||
'8229': cte.WAREHOUSE,
|
||||
'6418': cte.WAREHOUSE,
|
||||
'6356': cte.WAREHOUSE,
|
||||
'6562': cte.WAREHOUSE,
|
||||
'6654': cte.WAREHOUSE,
|
||||
'5164': cte.WAREHOUSE,
|
||||
'5188': cte.WAREHOUSE,
|
||||
'6996': cte.WAREHOUSE,
|
||||
'3221': cte.WAREHOUSE,
|
||||
'8124': cte.WAREHOUSE,
|
||||
'2494': cte.WAREHOUSE,
|
||||
'6215': cte.WAREHOUSE,
|
||||
'6644': cte.WAREHOUSE,
|
||||
'6262': cte.WAREHOUSE,
|
||||
'4927': cte.WAREHOUSE,
|
||||
'3991': cte.WAREHOUSE,
|
||||
'2215': cte.WAREHOUSE,
|
||||
'5144': cte.WAREHOUSE,
|
||||
'2740': cte.WAREHOUSE,
|
||||
'5670': cte.WAREHOUSE,
|
||||
'6442': cte.WAREHOUSE,
|
||||
'3612': cte.WAREHOUSE,
|
||||
'5990': cte.WAREHOUSE,
|
||||
'5193': cte.WAREHOUSE,
|
||||
'5197': cte.WAREHOUSE,
|
||||
'3974': cte.WAREHOUSE,
|
||||
'2019': cte.WAREHOUSE,
|
||||
'7314': cte.WAREHOUSE,
|
||||
'3542': cte.WAREHOUSE,
|
||||
'5165': cte.WAREHOUSE,
|
||||
'4291': cte.WAREHOUSE,
|
||||
'1913': cte.WAREHOUSE,
|
||||
'5270': cte.WAREHOUSE,
|
||||
'7481': cte.WAREHOUSE,
|
||||
'4855': cte.WAREHOUSE,
|
||||
'6261': cte.WAREHOUSE,
|
||||
'2733': cte.WAREHOUSE,
|
||||
'5943': cte.WAREHOUSE,
|
||||
'7522': cte.WAREHOUSE,
|
||||
'5714': cte.WAREHOUSE,
|
||||
'5653': cte.WAREHOUSE,
|
||||
'2640': cte.WAREHOUSE,
|
||||
'4813': cte.WAREHOUSE,
|
||||
'6345': cte.WAREHOUSE,
|
||||
'5177': cte.WAREHOUSE,
|
||||
'4789': cte.WAREHOUSE,
|
||||
'5195': cte.WAREHOUSE,
|
||||
'3017': cte.WAREHOUSE,
|
||||
'4872': cte.WAREHOUSE,
|
||||
'7411': cte.WAREHOUSE,
|
||||
'3973': cte.WAREHOUSE,
|
||||
'3039': cte.WAREHOUSE,
|
||||
'6159': cte.WAREHOUSE,
|
||||
'5982': cte.WAREHOUSE,
|
||||
'5539': cte.WAREHOUSE,
|
||||
'8542': cte.WAREHOUSE,
|
||||
'2222': cte.WAREHOUSE,
|
||||
'8312': cte.WAREHOUSE,
|
||||
'3832': cte.WAREHOUSE,
|
||||
'3592': cte.WAREHOUSE,
|
||||
'8128': cte.WAREHOUSE,
|
||||
'6523': cte.WAREHOUSE,
|
||||
'3430': cte.WAREHOUSE,
|
||||
'5395': cte.WAREHOUSE,
|
||||
'3716': cte.WAREHOUSE,
|
||||
'7223': cte.WAREHOUSE,
|
||||
'7521': cte.WAREHOUSE,
|
||||
'2738': cte.WAREHOUSE,
|
||||
'2217': cte.WAREHOUSE,
|
||||
'8311': cte.WAREHOUSE,
|
||||
'3693': cte.WAREHOUSE,
|
||||
'6123': cte.WAREHOUSE,
|
||||
'7115': cte.WAREHOUSE,
|
||||
'4567': cte.WAREHOUSE,
|
||||
'4742': cte.WAREHOUSE,
|
||||
'5159': cte.WAREHOUSE,
|
||||
'5192': cte.WAREHOUSE,
|
||||
'5178': cte.WAREHOUSE,
|
||||
'5716': cte.WAREHOUSE,
|
||||
'7392': cte.WAREHOUSE,
|
||||
'2913': cte.WAREHOUSE,
|
||||
'4854': cte.WAREHOUSE,
|
||||
'2062': cte.WAREHOUSE,
|
||||
'5363': cte.WAREHOUSE,
|
||||
'6347': cte.WAREHOUSE,
|
||||
'1914': cte.WAREHOUSE,
|
||||
'7519': cte.WAREHOUSE,
|
||||
'2094': cte.WAREHOUSE,
|
||||
'6645': cte.WAREHOUSE,
|
||||
'7414': cte.WAREHOUSE,
|
||||
'6732': cte.WAREHOUSE,
|
||||
'6554': cte.WAREHOUSE,
|
||||
'7394': cte.WAREHOUSE,
|
||||
'6222': cte.WAREHOUSE,
|
||||
'3520': cte.WAREHOUSE,
|
||||
'6741': cte.WAREHOUSE,
|
||||
'7116': cte.WAREHOUSE,
|
||||
'8099': cte.WAREHOUSE,
|
||||
'3642': cte.WAREHOUSE,
|
||||
'6614': cte.WAREHOUSE,
|
||||
'6252': cte.WAREHOUSE,
|
||||
'2452': cte.WAREHOUSE,
|
||||
'3251': cte.WAREHOUSE,
|
||||
'5115': cte.WAREHOUSE,
|
||||
'6366': cte.WAREHOUSE,
|
||||
'5143': cte.WAREHOUSE,
|
||||
'5493': cte.WAREHOUSE,
|
||||
'7395': cte.WAREHOUSE,
|
||||
'6363': cte.WAREHOUSE,
|
||||
'6393': cte.WAREHOUSE,
|
||||
'6244': cte.WAREHOUSE
|
||||
}
|
||||
|
||||
@property
|
||||
|
|
115
hub/imports/geometry/csv.py
Normal file
115
hub/imports/geometry/csv.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
import csv
|
||||
import uuid
|
||||
from decimal import Decimal, InvalidOperation
|
||||
from pyproj import Transformer
|
||||
from hub.city_model_structure.simplified_building import SimplifiedBuilding
|
||||
from hub.city_model_structure.simplified_city import SimplifiedCity
|
||||
|
||||
|
||||
class Csv:
|
||||
"""
|
||||
CSV class
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
path,
|
||||
centroid_x_field=None,
|
||||
centroid_y_field=None,
|
||||
postal_code_field=None,
|
||||
year_of_construction_field=None,
|
||||
function_field=None,
|
||||
function_to_hub=None,
|
||||
total_floor_area_field=None):
|
||||
self._simplified_city = None
|
||||
self._centroid_x_field = centroid_x_field
|
||||
self._centroid_y_field = centroid_y_field
|
||||
self._postal_code_field = postal_code_field
|
||||
self._year_of_construction_field = year_of_construction_field
|
||||
self._function_field = function_field
|
||||
self._function_to_hub = function_to_hub
|
||||
self._total_floor_area_field = total_floor_area_field
|
||||
self.transformer = Transformer.from_crs("EPSG:3857", "EPSG:4326", always_xy=True)
|
||||
|
||||
with open(path, 'r', encoding='utf8') as csv_file:
|
||||
reader = csv.DictReader(csv_file)
|
||||
self._csv_data = [row for row in reader]
|
||||
|
||||
def safe_int(self, value):
|
||||
if value in ('NULL', '', None):
|
||||
return None
|
||||
try:
|
||||
return int(value)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def safe_str(self, value):
|
||||
if value in ('NULL', '', None):
|
||||
return None
|
||||
try:
|
||||
return str(value)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def safe_float(self, value):
|
||||
if value in ('NULL', '', None):
|
||||
return None
|
||||
try:
|
||||
return float(value)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def safe_decimal(self, value):
|
||||
if value in ('NULL', '', None):
|
||||
return None
|
||||
try:
|
||||
return Decimal(value)
|
||||
except InvalidOperation:
|
||||
return None
|
||||
|
||||
@property
|
||||
def city(self) -> SimplifiedCity:
|
||||
if self._simplified_city is None:
|
||||
self._simplified_city = SimplifiedCity()
|
||||
for index, row in enumerate(self._csv_data):
|
||||
centroid = None
|
||||
if self._centroid_x_field and self._centroid_y_field:
|
||||
centroid_x = self.safe_float(row[self._centroid_x_field])
|
||||
centroid_y = self.safe_float(row.get(self._centroid_y_field))
|
||||
if centroid_x is not None and centroid_y is not None:
|
||||
lon, lat = self.transformer.transform(centroid_x, centroid_y)
|
||||
centroid = (lon, lat)
|
||||
|
||||
postal_code = None
|
||||
if self._postal_code_field:
|
||||
postal_code = self.safe_float(row[self._postal_code_field])
|
||||
|
||||
year_of_construction = None
|
||||
if self._year_of_construction_field:
|
||||
year_of_construction = self.safe_int(row[self._year_of_construction_field])
|
||||
|
||||
function = None
|
||||
if self._function_field:
|
||||
function = row[self._function_field]
|
||||
if self._function_to_hub:
|
||||
function = self._function_to_hub.get(function, function)
|
||||
|
||||
total_floor_area = None
|
||||
if self._total_floor_area_field:
|
||||
total_floor_area = self.safe_float(row[self._total_floor_area_field])
|
||||
|
||||
# Use index as the name of the building
|
||||
building_name = f"Building_{index + 1}"
|
||||
|
||||
building = SimplifiedBuilding(
|
||||
name=building_name,
|
||||
centroid=centroid,
|
||||
postal_code=postal_code,
|
||||
total_floor_area=total_floor_area,
|
||||
year_of_construction=year_of_construction,
|
||||
function=function
|
||||
)
|
||||
|
||||
if building.total_floor_area is not None and building.total_floor_area >= 25:
|
||||
self._simplified_city.add_city_object(building)
|
||||
|
||||
return self._simplified_city
|
|
@ -6,10 +6,12 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|||
"""
|
||||
|
||||
from hub.city_model_structure.city import City
|
||||
from hub.city_model_structure.simplified_city import SimplifiedCity
|
||||
from hub.helpers.utils import validate_import_export_type
|
||||
from hub.imports.geometry.citygml import CityGml
|
||||
from hub.imports.geometry.geojson import Geojson
|
||||
from hub.imports.geometry.obj import Obj
|
||||
from hub.imports.geometry.csv import Csv
|
||||
|
||||
|
||||
class GeometryFactory:
|
||||
|
@ -20,19 +22,27 @@ class GeometryFactory:
|
|||
path=None,
|
||||
aliases_field=None,
|
||||
height_field=None,
|
||||
centroid_x_field=None,
|
||||
centroid_y_field=None,
|
||||
position_x_field=None,
|
||||
year_of_construction_field=None,
|
||||
function_field=None,
|
||||
function_to_hub=None,
|
||||
hub_crs=None):
|
||||
hub_crs=None,
|
||||
total_floor_area_field=None):
|
||||
self._file_type = '_' + file_type.lower()
|
||||
validate_import_export_type(GeometryFactory, file_type)
|
||||
self._path = path
|
||||
self._aliases_field = aliases_field
|
||||
self._height_field = height_field
|
||||
self._centroid_x_field = centroid_x_field
|
||||
self._centroid_y_field = centroid_y_field
|
||||
self._position_x_field = position_x_field
|
||||
self._year_of_construction_field = year_of_construction_field
|
||||
self._function_field = function_field
|
||||
self._function_to_hub = function_to_hub
|
||||
self._hub_crs = hub_crs
|
||||
self._total_floor_area_field = total_floor_area_field
|
||||
|
||||
@property
|
||||
def _citygml(self) -> City:
|
||||
|
@ -68,6 +78,17 @@ class GeometryFactory:
|
|||
self._function_to_hub,
|
||||
self._hub_crs).city
|
||||
|
||||
@property
|
||||
def _csv(self) -> SimplifiedCity:
|
||||
return Csv(self._path,
|
||||
self._centroid_x_field,
|
||||
self._centroid_y_field,
|
||||
self._position_x_field,
|
||||
self._year_of_construction_field,
|
||||
self._function_field,
|
||||
self._function_to_hub,
|
||||
self._total_floor_area_field).city
|
||||
|
||||
@property
|
||||
def city(self) -> City:
|
||||
"""
|
||||
|
@ -75,3 +96,11 @@ class GeometryFactory:
|
|||
:return: City
|
||||
"""
|
||||
return getattr(self, self._file_type, lambda: None)
|
||||
|
||||
@property
|
||||
def simplified_city(self) -> SimplifiedCity:
|
||||
"""
|
||||
Enrich the city given to the class using the class given handler
|
||||
:return: SimplifiedCity
|
||||
"""
|
||||
return getattr(self, self._file_type, lambda: None)
|
||||
|
|
152
hub/imports/results/archetype_based_demand.py
Normal file
152
hub/imports/results/archetype_based_demand.py
Normal file
|
@ -0,0 +1,152 @@
|
|||
import pandas as pd
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
|
||||
class DemandEnricher:
|
||||
"""
|
||||
DemandEnricher class to enrich buildings with demand data
|
||||
"""
|
||||
|
||||
def __init__(self, database_url):
|
||||
# Create a SQLAlchemy engine using the provided database URL
|
||||
self.engine = create_engine(database_url)
|
||||
# Initialize the function mapping and cache
|
||||
self.create_function_mapping()
|
||||
self.archetype_cache = {}
|
||||
|
||||
def create_function_mapping(self):
|
||||
# Define function mapping from city functions to archetype functions
|
||||
self.function_mapping = {
|
||||
'residential': 'Maison Unifamiliale',
|
||||
'single family house': 'Maison Unifamiliale',
|
||||
'multifamily house': 'Apartements partie 3 du code',
|
||||
'medium office': 'Bureaux',
|
||||
'office and administration': 'Bureaux',
|
||||
'commercial': 'Commercial attaché',
|
||||
'warehouse': 'Commercial détaché', # Approximate
|
||||
'restaurant': 'Commercial attaché', # Approximate
|
||||
'hotel': 'Commercial attaché', # Approximate
|
||||
# Add more mappings as needed
|
||||
}
|
||||
|
||||
def get_vintage_range(self, year):
|
||||
# Determine the vintage range based on the year of construction
|
||||
if year <= 1947:
|
||||
return 'avant 1947'
|
||||
elif 1947 < year <= 1983:
|
||||
return '1947-1983'
|
||||
elif 1983 < year <= 2010:
|
||||
return '1984-2010'
|
||||
elif year > 2010:
|
||||
return 'après 2010'
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_archetype_demands(self, type_of_building):
|
||||
# Check if the demands for this archetype are already cached
|
||||
if type_of_building in self.archetype_cache:
|
||||
return self.archetype_cache[type_of_building]
|
||||
|
||||
# Construct the SQL query
|
||||
query = text("""
|
||||
SELECT heating, cooling, equipment, lighting
|
||||
FROM energy_data
|
||||
WHERE type_of_building = :type_of_building
|
||||
ORDER BY timestamp
|
||||
""")
|
||||
|
||||
# Execute the query with parameter substitution
|
||||
with self.engine.connect() as conn:
|
||||
result = conn.execute(query, type_of_building=type_of_building)
|
||||
demands = result.fetchall()
|
||||
if not demands:
|
||||
return None
|
||||
|
||||
# Convert the result to a DataFrame
|
||||
demands_df = pd.DataFrame(demands, columns=['heating', 'cooling', 'equipment', 'lighting'])
|
||||
# Convert columns to numeric types
|
||||
for demand_column in ['heating', 'cooling', 'equipment', 'lighting']:
|
||||
demands_df[demand_column] = pd.to_numeric(demands_df[demand_column], errors='coerce')
|
||||
demands_df[demand_column].fillna(0, inplace=True)
|
||||
|
||||
# Cache the demands for future use
|
||||
self.archetype_cache[type_of_building] = demands_df
|
||||
return demands_df
|
||||
|
||||
def enrich_city(self, city):
|
||||
# Enrich each building in the city with demand data
|
||||
for building in city.buildings:
|
||||
# Ensure the building has the necessary attributes
|
||||
if (building.year_of_construction is not None and
|
||||
building.function is not None and
|
||||
building.total_floor_area is not None):
|
||||
# Map the building's function to an archetype function
|
||||
building_function_lower = building.function.lower()
|
||||
mapped_function = None
|
||||
for key in self.function_mapping:
|
||||
if key in building_function_lower:
|
||||
mapped_function = self.function_mapping[key]
|
||||
break
|
||||
if mapped_function:
|
||||
# Determine the vintage range
|
||||
vintage_range = self.get_vintage_range(building.year_of_construction)
|
||||
if vintage_range:
|
||||
# Construct the Type_of_building string
|
||||
type_of_building = f"{mapped_function} {vintage_range}"
|
||||
# Get the demands for this archetype
|
||||
demands_df = self.get_archetype_demands(type_of_building)
|
||||
if demands_df is not None:
|
||||
# Check total_floor_area
|
||||
total_floor_area = building.total_floor_area
|
||||
if not isinstance(total_floor_area, (int, float)) or pd.isnull(total_floor_area):
|
||||
print(f"Invalid total_floor_area for building {building.name}. Skipping.")
|
||||
building.heating_demand = []
|
||||
building.cooling_demand = []
|
||||
building.electricity_demand = []
|
||||
building.appliance_demand = []
|
||||
continue
|
||||
# Proceed with multiplication
|
||||
try:
|
||||
demands_df['Heating_total'] = demands_df['heating'] * total_floor_area
|
||||
demands_df['Cooling_total'] = demands_df['cooling'] * total_floor_area
|
||||
demands_df['Equipment_total'] = demands_df['equipment'] * total_floor_area
|
||||
demands_df['Lighting_total'] = demands_df['lighting'] * total_floor_area
|
||||
# Assign the total demand profiles to the building's attributes
|
||||
building.heating_demand = demands_df['Heating_total'].tolist()
|
||||
building.cooling_demand = demands_df['Cooling_total'].tolist()
|
||||
building.electricity_demand = demands_df['Lighting_total'].tolist()
|
||||
building.appliance_demand = demands_df['Equipment_total'].tolist()
|
||||
except Exception as e:
|
||||
print(f"Error calculating demands for building {building.name}: {e}")
|
||||
building.heating_demand = []
|
||||
building.cooling_demand = []
|
||||
building.electricity_demand = []
|
||||
building.appliance_demand = []
|
||||
else:
|
||||
# No data found for this Type_of_building
|
||||
building.heating_demand = []
|
||||
building.cooling_demand = []
|
||||
building.electricity_demand = []
|
||||
building.appliance_demand = []
|
||||
else:
|
||||
# Vintage range could not be determined
|
||||
building.heating_demand = []
|
||||
building.cooling_demand = []
|
||||
building.electricity_demand = []
|
||||
building.appliance_demand = []
|
||||
else:
|
||||
# Function mapping not found
|
||||
building.heating_demand = []
|
||||
building.cooling_demand = []
|
||||
building.electricity_demand = []
|
||||
building.appliance_demand = []
|
||||
else:
|
||||
# Missing necessary attributes
|
||||
building.heating_demand = []
|
||||
building.cooling_demand = []
|
||||
building.electricity_demand = []
|
||||
building.appliance_demand = []
|
||||
|
||||
def close_connection(self):
|
||||
# Dispose of the engine to close the database connection
|
||||
self.engine.dispose()
|
41
main.py
Normal file
41
main.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
from hub.imports.geometry_factory import GeometryFactory
|
||||
from hub.helpers.dictionaries import Dictionaries
|
||||
from hub.imports.results.archetype_based_demand import DemandEnricher
|
||||
import urllib.parse
|
||||
|
||||
input_file = "data/cmm_points_function_vintage_surface.csv"
|
||||
output_file = "output_buildings.csv"
|
||||
|
||||
# Database credentials
|
||||
db_username = 'postgres'
|
||||
db_password = 'your_password_with_special_characters' # Replace with your actual password
|
||||
db_host = 'localhost'
|
||||
db_port = '5432'
|
||||
db_name = 'energydemanddb'
|
||||
|
||||
# URL-encode username and password
|
||||
db_username_encoded = urllib.parse.quote_plus(db_username)
|
||||
db_password_encoded = urllib.parse.quote_plus(db_password)
|
||||
|
||||
# Construct the database connection URL
|
||||
database_url = f'postgresql://{db_username_encoded}:{db_password_encoded}@{db_host}:{db_port}/{db_name}'
|
||||
|
||||
# Initialize city object from GeometryFactory
|
||||
city = GeometryFactory(
|
||||
file_type="csv",
|
||||
path=input_file,
|
||||
centroid_x_field="centroid_x",
|
||||
centroid_y_field="centroid_y",
|
||||
year_of_construction_field="anne_cnstr",
|
||||
function_field="code_util",
|
||||
function_to_hub=Dictionaries().montreal_function_to_hub_function,
|
||||
total_floor_area_field="supfi_etag"
|
||||
).city
|
||||
|
||||
# Create an instance of DemandEnricher using the database URL
|
||||
demand_enricher = DemandEnricher(database_url)
|
||||
demand_enricher.enrich_city(city)
|
||||
# Close the database connection when done
|
||||
demand_enricher.close_connection()
|
||||
|
||||
print("done")
|
1125156
output_buildings.csv
Normal file
1125156
output_buildings.csv
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user