The energy plus result importer for multiple buildings is created and tested. Currently, buildings are enriched with hourly values but monthly and yearly values are not working.

This commit is contained in:
Saeed Ranjbar 2023-12-05 19:38:11 -05:00
parent c3f2cfb02a
commit 020190829f
5 changed files with 8837 additions and 8844 deletions

View File

@ -12,89 +12,54 @@ import csv
import hub.helpers.constants as cte import hub.helpers.constants as cte
class EnergyPlusSingleBuilding: class EnergyPlusMultipleBuildings:
def __init__(self, city, base_path): def __init__(self, city, base_path):
self._city = city self._city = city
self._base_path = base_path self._base_path = base_path
@staticmethod def _building_energy_demands(self, energy_plus_output_file_path):
def _building_energy_demands(energy_plus_output_file_path): buildings_energy_demands = {}
with open(Path(energy_plus_output_file_path).resolve(), 'r', encoding='utf8') as csv_file: with open(Path(energy_plus_output_file_path).resolve(), 'r', encoding='utf8') as csv_file:
csv_output = csv.reader(csv_file) csv_output = list(csv.DictReader(csv_file))
headers = next(csv_output)
building_energy_demands = {
'Heating (J)': [],
'Cooling (J)': [],
'DHW (J)': [],
'Appliances (J)': [],
'Lighting (J)': []
}
heating_column_index = []
cooling_column_index = []
dhw_column_index = []
appliance_column_index = []
lighting_column_index = []
for index, header in enumerate(headers):
if "Total Heating" in header:
heating_column_index.append(index)
elif "Total Cooling" in header:
cooling_column_index.append(index)
elif "DHW" in header:
dhw_column_index.append(index)
elif "InteriorEquipment" in header:
appliance_column_index.append(index)
elif "InteriorLights" in header:
lighting_column_index.append(index)
for line in csv_output: for building in self._city.buildings:
total_heating_demand = 0 building_name = building.name
total_cooling_demand = 0 buildings_energy_demands[f'Building {building_name} Heating Demand (J)'] = [
total_dhw_demand = 0 float(
total_appliance_demand = 0 row[f"{building_name} IDEAL LOADS AIR SYSTEM:Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)"])
total_lighting_demand = 0 for row in csv_output
for heating_index in heating_column_index: ]
total_heating_demand += float(line[heating_index]) buildings_energy_demands[f'Building {building_name} Cooling Demand (J)'] = [
building_energy_demands['Heating (J)'].append(total_heating_demand) float(
for cooling_index in cooling_column_index: row[f"{building_name} IDEAL LOADS AIR SYSTEM:Zone Ideal Loads Supply Air Total Cooling Energy [J](Hourly)"])
total_cooling_demand += float(line[cooling_index]) for row in csv_output
building_energy_demands['Cooling (J)'].append(total_cooling_demand) ]
for dhw_index in dhw_column_index: buildings_energy_demands[f'Building {building_name} DHW Demand (W)'] = [
total_dhw_demand += float(line[dhw_index]) * cte.WATTS_HOUR_TO_JULES float(row[f"DHW {building.name}:Water Use Equipment Heating Rate [W](Hourly)"])
building_energy_demands['DHW (J)'].append(total_dhw_demand) for row in csv_output
for appliance_index in appliance_column_index: ]
total_appliance_demand += float(line[appliance_index]) buildings_energy_demands[f'Building {building_name} Appliances (W)'] = [
building_energy_demands['Appliances (J)'].append(total_appliance_demand) float(row[f"{building_name}_APPLIANCE:Other Equipment Electricity Rate [W](Hourly)"])
for lighting_index in lighting_column_index: for row in csv_output
total_lighting_demand += float(line[lighting_index]) ]
building_energy_demands['Lighting (J)'].append(total_lighting_demand) buildings_energy_demands[f'Building {building_name} Lighting (W)'] = [
float(row[f"{building_name}:Zone Lights Electricity Rate [W](Hourly)"]) for row in csv_output
return building_energy_demands ]
return buildings_energy_demands
def enrich(self): def enrich(self):
""" """
Enrich the city by using the energy plus workflow output files (J) Enrich the city by using the energy plus workflow output files (J)
:return: None :return: None
""" """
for building in self._city.buildings: file_name = f'{self._city.name}_out.csv'
file_name = f'{building.name}_out.csv'
energy_plus_output_file_path = Path(self._base_path / file_name).resolve() energy_plus_output_file_path = Path(self._base_path / file_name).resolve()
if energy_plus_output_file_path.is_file(): if energy_plus_output_file_path.is_file():
building_energy_demands = self._building_energy_demands(energy_plus_output_file_path) building_energy_demands = self._building_energy_demands(energy_plus_output_file_path)
building.heating_demand[cte.HOUR] = building_energy_demands['Heating (J)'] for building in self._city.buildings:
building.cooling_demand[cte.HOUR] = building_energy_demands['Cooling (J)'] building.heating_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Heating Demand (J)']
building.domestic_hot_water_heat_demand[cte.HOUR] = building_energy_demands['DHW (J)'] building.cooling_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Cooling Demand (J)']
building.appliances_electrical_demand[cte.HOUR] = building_energy_demands['Appliances (J)'] building.domestic_hot_water_heat_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} DHW Demand (W)']
building.lighting_electrical_demand[cte.HOUR] = building_energy_demands['Lighting (J)'] building.appliances_electrical_demand[cte.HOUR] = building_energy_demands[f'Building {building.name} Appliances (W)']
building.heating_demand[cte.MONTH] = MonthlyValues.get_total_month(building.heating_demand[cte.HOUR])
building.cooling_demand[cte.MONTH] = MonthlyValues.get_total_month(building.cooling_demand[cte.HOUR])
building.domestic_hot_water_heat_demand[cte.MONTH] = (
MonthlyValues.get_total_month(building.domestic_hot_water_heat_demand[cte.HOUR]))
building.appliances_electrical_demand[cte.MONTH] = (
MonthlyValues.get_total_month(building.appliances_electrical_demand[cte.HOUR]))
building.lighting_electrical_demand[cte.MONTH] = (
MonthlyValues.get_total_month(building.lighting_electrical_demand[cte.HOUR]))
building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.MONTH])]
building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.MONTH])]
building.domestic_hot_water_heat_demand[cte.YEAR] = [sum(building.domestic_hot_water_heat_demand[cte.MONTH])]
building.appliances_electrical_demand[cte.YEAR] = [sum(building.appliances_electrical_demand[cte.MONTH])]
building.lighting_electrical_demand[cte.YEAR] = [sum(building.lighting_electrical_demand[cte.MONTH])]

View File

@ -10,8 +10,8 @@ from pathlib import Path
from hub.helpers.utils import validate_import_export_type from hub.helpers.utils import validate_import_export_type
from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance
from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
from hub.imports.results.energy_plus import EnergyPlus
# from hub.imports.results.ep_multiple_buildings import EnergyPlusMultiple from hub.imports.results.ep_multiple_buildings import EnergyPlusMultipleBuildings
from hub.imports.results.energy_plus_single_building import EnergyPlusSingleBuilding from hub.imports.results.energy_plus_single_building import EnergyPlusSingleBuilding
class ResultFactory: class ResultFactory:
@ -54,11 +54,11 @@ class ResultFactory:
""" """
EnergyPlusSingleBuilding(self._city, self._base_path).enrich() EnergyPlusSingleBuilding(self._city, self._base_path).enrich()
# def _energy_plus_multiple(self): def _energy_plus_multiple_buildings(self):
# """ """
# Enrich the city with energy plus results Enrich the city with energy plus results
# """ """
# EnergyPlusMultiple(self._city, self._base_path).enrich() EnergyPlusMultipleBuildings(self._city, self._base_path).enrich()
def enrich(self): def enrich(self):
""" """

View File

@ -30,11 +30,11 @@ class TestResultsImport(TestCase):
""" """
self._example_path = (Path(__file__).parent / 'tests_data').resolve() self._example_path = (Path(__file__).parent / 'tests_data').resolve()
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve() self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
file = 'test.geojson' file = 'Citylayers_neighbours_simp2.json'
file_path = (self._example_path / file).resolve() file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('geojson', self._city = GeometryFactory('geojson',
path=file_path, path=file_path,
height_field='citygml_me', height_field='heightmax',
year_of_construction_field='ANNEE_CONS', year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI', function_field='CODE_UTILI',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city function_to_hub=Dictionaries().montreal_function_to_hub_function).city
@ -115,3 +115,25 @@ class TestResultsImport(TestCase):
self.assertDictEqual(building.domestic_hot_water_heat_demand, {}) self.assertDictEqual(building.domestic_hot_water_heat_demand, {})
self.assertDictEqual(building.lighting_electrical_demand, {}) self.assertDictEqual(building.lighting_electrical_demand, {})
self.assertDictEqual(building.appliances_electrical_demand, {}) self.assertDictEqual(building.appliances_electrical_demand, {})
def test_energy_plus_multiple_buildings_results_import(self):
ResultFactory('energy_plus_multiple_buildings', self._city, self._example_path).enrich()
csv_output_name = f'{self._city.name}_out.csv'
csv_output_path = (self._example_path / csv_output_name).resolve()
if csv_output_path.is_file():
for building in self._city.buildings:
self.assertIsNotNone(building.heating_demand)
self.assertIsNotNone(building.cooling_demand)
self.assertIsNotNone(building.domestic_hot_water_heat_demand)
self.assertIsNotNone(building.lighting_electrical_demand)
self.assertIsNotNone(building.appliances_electrical_demand)
total_demand = sum(building.heating_demand[cte.HOUR])
self.assertAlmostEqual(total_demand, building.heating_demand[cte.YEAR][0], 3)
total_demand = sum(building.heating_demand[cte.MONTH])
self.assertEqual(total_demand, building.heating_demand[cte.YEAR][0], 3)
# if building.name != '12':
# self.assertDictEqual(building.heating_demand, {})
# self.assertDictEqual(building.cooling_demand, {})
# self.assertDictEqual(building.domestic_hot_water_heat_demand, {})
# self.assertDictEqual(building.lighting_electrical_demand, {})
# self.assertDictEqual(building.appliances_electrical_demand, {})

View File

@ -0,0 +1,6 @@
{"type":"FeatureCollection", "features": [
{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-73.57185265377689,45.52343504199365],[-73.57186901784087,45.52344250726594],[-73.5719186361361,45.523388576721516],[-73.57169557189309,45.52328954697509],[-73.57164717307853,45.523341318247276],[-73.57185265377689,45.52343504199365]]]},"id":86522, "properties":{"ID_UEV":"01027575","CIVIQUE_DE":" 951","CIVIQUE_FI":" 959","NOM_RUE":"rue Napoléon (MTL)","SUITE_DEBU":" ","MUNICIPALI":"50","ETAGE_HORS":3,"NOMBRE_LOG":5,"ANNEE_CONS":1927,"CODE_UTILI":"1000","LETTRE_DEB":" ","LETTRE_FIN":" ","LIBELLE_UT":"Logement","CATEGORIE_":"Régulier","MATRICULE8":"9942-16-9406-0-000-0000","SUPERFICIE":189,"SUPERFIC_1":342,"NO_ARROND_":"REM21","Shape_Leng":0.000632076842566,"OBJECTID":86522,"Join_Count":1,"TARGET_FID":86522,"feature_id":"bd64c84e-a70a-4112-915e-74b79f16c189","md_id":" ","acqtech":1360,"acqtech_en":"Lidar","acqtech_fr":"Lidar","provider":461,"provideren":"Municipal","providerfr":"Municipal","datemin":"20151124","datemax":"20151208","haccmin":2,"haccmax":2,"vaccmin":1,"vaccmax":1,"heightmin":2.03,"heightmax":16.11,"elevmin":43.98,"elevmax":46.16,"bldgarea":2049.47,"comment":"Detection of Lidar points classified as ground in the building. Détection de points Lidar classifiés sol dans le bâtiment.","OBJECTID_1":86522,"Shape_Le_1":0.000632076842566,"Shape_Ar_1":1.66656602227e-8,"OBJECTID_12":86522,"Join_Count_1":4,"TARGET_FID_1":86521,"g_objectid":"965958","g_co_mrc":"66023","g_code_mun":"66023","g_arrond":"REM21","g_anrole":"2019","g_usag_pre":"Résidentiel","g_no_lot":"1885186","g_nb_poly_":"1","g_utilisat":"1000","g_nb_logem":"5","g_nb_locau":" ","g_descript":"Unité d'évaluation","g_id_provi":"66023994216872540000000","g_sup_tota":"228.4","g_geometry":"0.000850333","g_geomet_1":"2.66017e-008","g_dat_acqu":"2020-02-12T00:00:00","g_dat_char":"2020-02-17T00:00:00","Shape_Leng_1":0.000632076842566,"Shape_Area_1":1.66656602227e-8,"Shape_Length":0.0006320773708141846,"Shape_Area":1.66656602227e-8}},
{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-73.57153144831767,45.523465428286954],[-73.57149617241038,45.523503246577604],[-73.5714876720184,45.52349934711725],[-73.57146469883673,45.52352357665177],[-73.571684848377,45.523623993152796],[-73.5717241721328,45.523584846563494],[-73.57163387210545,45.52354014666048],[-73.57165310140948,45.523520919155146],[-73.57153144831767,45.523465428286954]]]},"id":92980,"properties":{"ID_UEV":"01105693","CIVIQUE_DE":" 981","CIVIQUE_FI":" 981","NOM_RUE":"rue Napoléon (MTL)","SUITE_DEBU":" ","MUNICIPALI":"50","ETAGE_HORS":1,"NOMBRE_LOG":1,"ANNEE_CONS":1927,"CODE_UTILI":"1000","LETTRE_DEB":" ","LETTRE_FIN":" ","LIBELLE_UT":"Logement","CATEGORIE_":"Condominium","MATRICULE8":"9942-26-0726-9-001-0002","SUPERFICIE":64,"SUPERFIC_1":1097,"NO_ARROND_":"REM21","Shape_Leng":0.000653576866621,"OBJECTID":92980,"Join_Count":1,"TARGET_FID":92980,"feature_id":"bd64c84e-a70a-4112-915e-74b79f16c189","md_id":" ","acqtech":1360,"acqtech_en":"Lidar","acqtech_fr":"Lidar","provider":461,"provideren":"Municipal","providerfr":"Municipal","datemin":"20151124","datemax":"20151208","haccmin":2,"haccmax":2,"vaccmin":1,"vaccmax":1,"heightmin":2.03,"heightmax":16.11,"elevmin":43.98,"elevmax":46.16,"bldgarea":2049.47,"comment":"Detection of Lidar points classified as ground in the building. Détection de points Lidar classifiés sol dans le bâtiment.","OBJECTID_1":92980,"Shape_Le_1":0.000653576866621,"Shape_Ar_1":1.64021795264e-8,"OBJECTID_12":92980,"Join_Count_1":3,"TARGET_FID_1":92979,"g_objectid":"967849","g_co_mrc":"66023","g_code_mun":"66023","g_arrond":"REM21","g_anrole":"2019","g_usag_pre":"Résidentiel","g_no_lot":"2316950","g_nb_poly_":"1","g_utilisat":"1000","g_nb_logem":"6","g_nb_locau":" ","g_descript":"Unité d'évaluation","g_id_provi":"66023994226021950000000","g_sup_tota":"205.6","g_geometry":"0.000725388","g_geomet_1":"2.3681e-008","g_dat_acqu":"2020-02-12T00:00:00","g_dat_char":"2020-02-17T00:00:00","Shape_Leng_1":0.000653576866621,"Shape_Area_1":1.64021795264e-8,"Shape_Length":0.0006535770208011338,"Shape_Area":1.64021795264e-8}},
{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-73.57185265377689,45.52343504199365],[-73.57164717307853,45.523341318247276],[-73.57159495574257,45.523397333420235],[-73.57180091488027,45.52349127660119],[-73.57185265377689,45.52343504199365]]]},"id":146189, "properties":{"ID_UEV":"01027577","CIVIQUE_DE":" 961","CIVIQUE_FI":" 965","NOM_RUE":"rue Napoléon (MTL)","SUITE_DEBU":" ","MUNICIPALI":"50","ETAGE_HORS":3,"NOMBRE_LOG":3,"ANNEE_CONS":1927,"CODE_UTILI":"1000","LETTRE_DEB":" ","LETTRE_FIN":" ","LIBELLE_UT":"Logement","CATEGORIE_":"Régulier","MATRICULE8":"9942-16-9812-9-000-0000","SUPERFICIE":159,"SUPERFIC_1":313,"NO_ARROND_":"REM21","Shape_Leng":0.00060521313674,"OBJECTID":146189,"Join_Count":1,"TARGET_FID":146189,"feature_id":"bd64c84e-a70a-4112-915e-74b79f16c189","md_id":" ","acqtech":1360,"acqtech_en":"Lidar","acqtech_fr":"Lidar","provider":461,"provideren":"Municipal","providerfr":"Municipal","datemin":"20151124","datemax":"20151208","haccmin":2,"haccmax":2,"vaccmin":1,"vaccmax":1,"heightmin":2.03,"heightmax":16.11,"elevmin":43.98,"elevmax":46.16,"bldgarea":2049.47,"comment":"Detection of Lidar points classified as ground in the building. Détection de points Lidar classifiés sol dans le bâtiment.","OBJECTID_1":146189,"Shape_Le_1":0.00060521313674,"Shape_Ar_1":1.64233386484e-8,"OBJECTID_12":146189,"Join_Count_1":4,"TARGET_FID_1":146188,"g_objectid":"967849","g_co_mrc":"66023","g_code_mun":"66023","g_arrond":"REM21","g_anrole":"2019","g_usag_pre":"Résidentiel","g_no_lot":"2316950","g_nb_poly_":"1","g_utilisat":"1000","g_nb_logem":"6","g_nb_locau":" ","g_descript":"Unité d'évaluation","g_id_provi":"66023994226021950000000","g_sup_tota":"205.6","g_geometry":"0.000725388","g_geomet_1":"2.3681e-008","g_dat_acqu":"2020-02-12T00:00:00","g_dat_char":"2020-02-17T00:00:00","Shape_Leng_1":0.00060521313674,"Shape_Area_1":1.64233386484e-8,"Shape_Length":0.0006052125392461572,"Shape_Area":1.64233386484e-8}},
{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-73.57165310140948,45.523520919155146],[-73.57166317201774,45.52351084674825],[-73.57174737194362,45.523552647236954],[-73.5717762716576,45.523526846586776],[-73.57178620916619,45.52353250781903],[-73.57181157904108,45.523504934605114],[-73.57180091488027,45.52349127660119],[-73.57159495574257,45.523397333420235],[-73.57153144831767,45.523465428286954],[-73.57165310140948,45.523520919155146]]]},"id":156117,"properties":{"ID_UEV":"01027579","CIVIQUE_DE":" 967","CIVIQUE_FI":" 977","NOM_RUE":"rue Napoléon (MTL)","SUITE_DEBU":" ","MUNICIPALI":"50","ETAGE_HORS":3,"NOMBRE_LOG":6,"ANNEE_CONS":1927,"CODE_UTILI":"1000","LETTRE_DEB":" ","LETTRE_FIN":" ","LIBELLE_UT":"Logement","CATEGORIE_":"Régulier","MATRICULE8":"9942-26-0219-5-000-0000","SUPERFICIE":206,"SUPERFIC_1":360,"NO_ARROND_":"REM21","Shape_Leng":0.000675507023301,"OBJECTID":156117,"Join_Count":1,"TARGET_FID":156117,"feature_id":"bd64c84e-a70a-4112-915e-74b79f16c189","md_id":" ","acqtech":1360,"acqtech_en":"Lidar","acqtech_fr":"Lidar","provider":461,"provideren":"Municipal","providerfr":"Municipal","datemin":"20151124","datemax":"20151208","haccmin":2,"haccmax":2,"vaccmin":1,"vaccmax":1,"heightmin":2.03,"heightmax":16.11,"elevmin":43.98,"elevmax":46.16,"bldgarea":2049.47,"comment":"Detection of Lidar points classified as ground in the building. Détection de points Lidar classifiés sol dans le bâtiment.","OBJECTID_1":156117,"Shape_Le_1":0.000675507023301,"Shape_Ar_1":1.96911729663e-8,"OBJECTID_12":156117,"Join_Count_1":5,"TARGET_FID_1":156116,"g_objectid":"965958","g_co_mrc":"66023","g_code_mun":"66023","g_arrond":"REM21","g_anrole":"2019","g_usag_pre":"Résidentiel","g_no_lot":"1885186","g_nb_poly_":"1","g_utilisat":"1000","g_nb_logem":"5","g_nb_locau":" ","g_descript":"Unité d'évaluation","g_id_provi":"66023994216872540000000","g_sup_tota":"228.4","g_geometry":"0.000850333","g_geomet_1":"2.66017e-008","g_dat_acqu":"2020-02-12T00:00:00","g_dat_char":"2020-02-17T00:00:00","Shape_Leng_1":0.000675507023301,"Shape_Area_1":1.96911729663e-8,"Shape_Length":0.0006755075167615554,"Shape_Area":1.96911729663e-8}}
]}

File diff suppressed because it is too large Load Diff