Compare commits

...

7 Commits

10 changed files with 2601995 additions and 2 deletions

File diff suppressed because it is too large Load Diff

210241
data/energy_demand_data.csv Normal file

File diff suppressed because it is too large Load Diff

View 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

View 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")

View File

@ -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
View 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

View File

@ -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)

View 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
View 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

File diff suppressed because it is too large Load Diff