2023-12-28 13:48:22 -05:00
|
|
|
"""
|
|
|
|
This project aims to assign energy systems archetype names to Montreal buildings.
|
|
|
|
The random assignation is based on statistical information extracted from different sources, being:
|
|
|
|
- For residential buildings:
|
|
|
|
- SHEU 2015: https://oee.nrcan.gc.ca/corporate/statistics/neud/dpa/menus/sheu/2015/tables.cfm
|
|
|
|
- For non-residential buildings:
|
|
|
|
- Montreal dataportal: https://dataportalforcities.org/north-america/canada/quebec/montreal
|
|
|
|
- https://www.eia.gov/consumption/commercial/data/2018/
|
|
|
|
"""
|
|
|
|
import glob
|
|
|
|
import json
|
|
|
|
import random
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
from hub.city_model_structure.building import Building
|
|
|
|
from hub.city_model_structure.city import City
|
|
|
|
import hub.helpers.constants as cte
|
|
|
|
|
|
|
|
energy_systems_format = 'montreal_custom'
|
|
|
|
|
|
|
|
# parameters:
|
|
|
|
residential_systems_percentage = {'system 1 gas': 44,
|
|
|
|
'system 1 electricity': 6,
|
|
|
|
'system 2 gas': 0,
|
|
|
|
'system 2 electricity': 0,
|
|
|
|
'system 3 and 4 gas': 0,
|
|
|
|
'system 3 and 4 electricity': 0,
|
|
|
|
'system 5 gas': 0,
|
|
|
|
'system 5 electricity': 0,
|
|
|
|
'system 6 gas': 0,
|
|
|
|
'system 6 electricity': 0,
|
|
|
|
'system 8 gas': 44,
|
|
|
|
'system 8 electricity': 6}
|
2024-01-02 18:30:39 -05:00
|
|
|
|
|
|
|
residential_new_systems_percentage = {'PV+ASHP+GasBoiler+TES': 100,
|
|
|
|
'PV+ASHP+ElectricBoiler+TES': 0,
|
|
|
|
'PV+GSHP+GasBoiler+TES': 0,
|
|
|
|
'PV+GSHP+ElectricBoiler+TES': 0,
|
|
|
|
'PV+WSHP+GasBoiler+TES': 0,
|
|
|
|
'PV+WSHP+ElectricBoiler+TES': 0}
|
|
|
|
|
2023-12-28 13:48:22 -05:00
|
|
|
non_residential_systems_percentage = {'system 1 gas': 0,
|
|
|
|
'system 1 electricity': 0,
|
|
|
|
'system 2 gas': 0,
|
|
|
|
'system 2 electricity': 0,
|
|
|
|
'system 3 and 4 gas': 39,
|
|
|
|
'system 3 and 4 electricity': 36,
|
|
|
|
'system 5 gas': 0,
|
|
|
|
'system 5 electricity': 0,
|
|
|
|
'system 6 gas': 13,
|
|
|
|
'system 6 electricity': 12,
|
|
|
|
'system 8 gas': 0,
|
|
|
|
'system 8 electricity': 0}
|
|
|
|
|
|
|
|
|
|
|
|
def _retrieve_buildings(path, year_of_construction_field=None,
|
|
|
|
function_field=None, function_to_hub=None, aliases_field=None):
|
|
|
|
_buildings = []
|
|
|
|
with open(path, 'r', encoding='utf8') as json_file:
|
|
|
|
_geojson = json.loads(json_file.read())
|
|
|
|
for feature in _geojson['features']:
|
|
|
|
_building = {}
|
|
|
|
year_of_construction = None
|
|
|
|
if year_of_construction_field is not None:
|
|
|
|
year_of_construction = int(feature['properties'][year_of_construction_field])
|
|
|
|
function = None
|
|
|
|
if function_field is not None:
|
|
|
|
function = feature['properties'][function_field]
|
|
|
|
if function_to_hub is not None:
|
|
|
|
# use the transformation dictionary to retrieve the proper function
|
|
|
|
if function in function_to_hub:
|
|
|
|
function = function_to_hub[function]
|
|
|
|
building_name = ''
|
|
|
|
building_aliases = []
|
|
|
|
if 'id' in feature:
|
|
|
|
building_name = feature['id']
|
|
|
|
if aliases_field is not None:
|
|
|
|
for alias_field in aliases_field:
|
|
|
|
building_aliases.append(feature['properties'][alias_field])
|
|
|
|
_building['year_of_construction'] = year_of_construction
|
|
|
|
_building['function'] = function
|
|
|
|
_building['building_name'] = building_name
|
|
|
|
_building['building_aliases'] = building_aliases
|
|
|
|
_buildings.append(_building)
|
|
|
|
return _buildings
|
|
|
|
|
|
|
|
|
2023-12-28 18:41:08 -05:00
|
|
|
def call_random(_buildings: [Building], _systems_percentage):
|
2023-12-28 13:48:22 -05:00
|
|
|
_buildings_with_systems = []
|
|
|
|
_systems_distribution = []
|
|
|
|
_selected_buildings = list(range(0, len(_buildings)))
|
|
|
|
random.shuffle(_selected_buildings)
|
|
|
|
total = 0
|
|
|
|
maximum = 0
|
|
|
|
add_to = 0
|
|
|
|
for _system in _systems_percentage:
|
|
|
|
if _systems_percentage[_system] > 0:
|
|
|
|
number_of_buildings = round(_systems_percentage[_system] / 100 * len(_selected_buildings))
|
|
|
|
_systems_distribution.append({'system': _system, 'number': _systems_percentage[_system],
|
|
|
|
'number_of_buildings': number_of_buildings})
|
|
|
|
if number_of_buildings > maximum:
|
|
|
|
maximum = number_of_buildings
|
|
|
|
add_to = len(_systems_distribution) - 1
|
|
|
|
total += number_of_buildings
|
|
|
|
missing = 0
|
|
|
|
if total != len(_selected_buildings):
|
2024-01-02 18:30:39 -05:00
|
|
|
missing = len(_selected_buildings) - total
|
2023-12-28 13:48:22 -05:00
|
|
|
if missing != 0:
|
|
|
|
_systems_distribution[add_to]['number_of_buildings'] += missing
|
|
|
|
_position = 0
|
|
|
|
for case in _systems_distribution:
|
|
|
|
for i in range(0, case['number_of_buildings']):
|
|
|
|
_buildings[_selected_buildings[_position]].energy_systems_archetype_name = case['system']
|
|
|
|
_position += 1
|
|
|
|
return _buildings
|
|
|
|
|
|
|
|
# try:
|
|
|
|
# print('[simulation start]')
|
|
|
|
# input_path = Path('').resolve()
|
|
|
|
# output_path = Path('').resolve()
|
|
|
|
# files = glob.glob(str(input_path / '*'))
|
|
|
|
# processed_files = glob.glob(str(output_path / '*'))
|
|
|
|
#
|
|
|
|
# files_to_skip = []
|
|
|
|
#
|
|
|
|
# # keep track of processed pickles, so we don't process them again
|
|
|
|
# for processed_file in processed_files:
|
|
|
|
# files_to_skip.append(Path(processed_file).resolve().stem)
|
|
|
|
#
|
|
|
|
# for file in files:
|
|
|
|
# if Path(file).stem not in files_to_skip:
|
|
|
|
# city = City.load(file)
|
|
|
|
# available_systems = residential_systems_percentage.keys()
|
|
|
|
# residential_buildings = []
|
|
|
|
# non_residential_buildings = []
|
|
|
|
# for building in city.buildings:
|
|
|
|
# if building.function == cte.RESIDENTIAL:
|
|
|
|
# residential_buildings.append(building)
|
|
|
|
# else:
|
|
|
|
# non_residential_buildings.append(building)
|
|
|
|
# buildings_with_systems = _call_random(residential_buildings, available_systems, residential_systems_percentage)
|
|
|
|
# buildings_with_systems.extend(_call_random(non_residential_buildings, available_systems,
|
|
|
|
# non_residential_systems_percentage))
|
|
|
|
# file_path = (output_path / f'{Path(file).stem}.pickle').resolve()
|
|
|
|
# city.save(file_path)
|
|
|
|
# print(f'[{file_path} completed]')
|
|
|
|
#
|
|
|
|
# else:
|
|
|
|
# print(f"{Path(file)} already processed - skipping")
|
|
|
|
#
|
|
|
|
# except Exception as ex:
|
|
|
|
# print(ex)
|
|
|
|
# print('error: ', ex)
|
|
|
|
# print('[simulation abort]')
|
|
|
|
|
|
|
|
####My Randomization
|
|
|
|
# num_buildings = len(city.buildings)
|
|
|
|
# energy_systems = []
|
|
|
|
# for _ in range(num_buildings):
|
|
|
|
# system_archetype = random.choices(
|
|
|
|
# list(random_assignation.residential_systems_percentage.keys()),
|
|
|
|
# weights=list(random_assignation.residential_systems_percentage.values())
|
|
|
|
# )[0]
|
|
|
|
# energy_systems.append(system_archetype)
|
|
|
|
# for building, energy_system in zip(city.buildings, energy_systems):
|
2024-01-02 18:30:39 -05:00
|
|
|
# building.energy_systems_archetype_name = energy_system
|