""" Costs Workflow SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Project Author Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca """ import glob import os from pathlib import Path import sys import pandas as pd import numpy as np from hub.imports.construction_factory import ConstructionFactory from hub.helpers.dictionaries import Dictionaries from hub.hub_logger import logger from hub.imports.geometry_factory import GeometryFactory from hub.imports.usage_factory import UsageFactory from hub.imports.weather_factory import WeatherFactory from hub.catalog_factories.costs_catalog_factory import CostCatalogFactory import hub.helpers.constants as cte from monthly_energy_balance_engine import MonthlyEnergyBalanceEngine from sra_engine import SraEngine from hub.imports.energy_systems_factory import EnergySystemsFactory from energy_systems_sizing import EnergySystemsSizing from life_cycle_costs import LifeCycleCosts def _npv_from_list(discount_rate, list_cashflow): lcc_value = np.npv(discount_rate,list_cashflow) raise KeyError('bad inputs') def _search_archetype(costs_catalog, building_function): costs_archetypes = costs_catalog.entries('archetypes').archetypes for building_archetype in costs_archetypes: if str(building_function) == str(building_archetype.function): return building_archetype raise KeyError('archetype not found') file_path = (Path(__file__).parent.parent/'costs_workflow'/'input_files'/'selected_building_2864.geojson') climate_reference_city = 'Montreal' weather_file = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw' weather_format = 'epw' construction_format = 'nrcan' usage_format = 'comnet' energy_systems_format = 'montreal_custom' attic_heated_case = 0 basement_heated_case = 1 tmp_folder = (Path(__file__).parent.parent/'monthly_energy_balance_workflow'/'tmp') out_path = (Path(__file__).parent.parent / 'costs_workflow' / 'out_files') files = glob.glob(f'{out_path}/*') for file in files: if file != '.gitignore': os.remove(file) number_of_years = 30 consumer_price_index = 0.04 electricity_peak_index = 0.05 electricity_price_index = 0.05 gas_price_index = 0.05 discount_rate = 0.03 retrofitting_year_of_construction =2020 retrofitting_scenarios = [0, 1, 2, 3] life_cycle_results = pd.DataFrame() print('[city creation start]') city = GeometryFactory('geojson', path=file_path, height_field='heightmax', name_field='OBJECTID_12', year_of_construction_field='ANNEE_CONS', function_field='CODE_UTILI', function_to_hub=Dictionaries().montreal_function_to_hub_function).city print(f'city created from {file_path}') city.climate_reference_city = climate_reference_city city.climate_file = (tmp_folder / f'{climate_reference_city}.cli').resolve() print(f'city created from {file_path}') WeatherFactory(weather_format, city, file_name=weather_file).enrich() print('enrich weather... done') ConstructionFactory(construction_format, city).enrich() print('enrich constructions... done') UsageFactory(usage_format, city).enrich() print('enrich usage... done') for building in city.buildings: building.energy_systems_archetype_name = 'system 1 gas' EnergySystemsFactory(energy_systems_format, city).enrich() print('enrich systems... done') print('exporting:') catalog = CostCatalogFactory('montreal_custom').catalog print('costs catalog access... done') sra_file = (tmp_folder / f'{city.name}_sra.xml').resolve() SraEngine(city, sra_file, tmp_folder, weather_file) print(' sra processed...') for building in city.buildings: building.attic_heated = attic_heated_case building.basement_heated = basement_heated_case for retrofitting_scenario in retrofitting_scenarios: if retrofitting_scenario == 1 or retrofitting_scenario==3: for building in city.buildings: building.year_of_construction=2020 ConstructionFactory(construction_format, city).enrich() print('enrich retrofitted constructions... done') if retrofitting_scenario==2 or retrofitting_scenario==3: for building in city.buildings: building.energy_systems_archetype_name = 'system 6 electricity pv' EnergySystemsFactory(energy_systems_format, city).enrich() print('enrich systems... done') MonthlyEnergyBalanceEngine(city, tmp_folder) EnergySystemsSizing(city).enrich() print(f'beginning costing scenario {retrofitting_scenario} systems... done') for building in city.buildings: #try: function = Dictionaries().hub_function_to_montreal_custom_costs_function[building.function] archetype = _search_archetype(catalog, function) #except KeyError: # logger.error(f'Building {building.name} has unknown costs archetype for building function: ' # f'{building.function}\n') # sys.stderr.write(f'Building {building.name} has unknown costs archetype for building function: ' # f'{building.function}\n') #continue print('lcc for first building started') lcc = LifeCycleCosts(building, archetype, number_of_years, consumer_price_index, electricity_peak_index, electricity_price_index, gas_price_index, discount_rate, retrofitting_scenario) df_capital_costs_skin = lcc.calculate_capital_costs()['B2010_opaque_walls']+\ lcc.calculate_capital_costs()['B2020_transparent']+\ lcc.calculate_capital_costs()['B3010_opaque_roof']+\ lcc.calculate_capital_costs()['B10_superstructure'] df_capital_costs_systems = lcc.calculate_capital_costs()['D3020_heat_generating_systems']+\ lcc.calculate_capital_costs()['D3030_cooling_generation_systems']+\ lcc.calculate_capital_costs()['D3080_other_hvac_ahu']+\ lcc.calculate_capital_costs()['D5020_lighting_and_branch_wiring']+\ lcc.calculate_capital_costs()['D301010_photovoltaic_system'] df_end_of_life_costs = lcc.calculate_end_of_life_costs()['End_of_life_costs'] df_operational_costs = lcc.calculate_total_operational_costs()['Fixed_costs_electricity_peak']+\ lcc.calculate_total_operational_costs()['Fixed_costs_electricity_monthly']+\ lcc.calculate_total_operational_costs()['Fixed_costs_electricity_peak']+\ lcc.calculate_total_operational_costs()['Fixed_costs_electricity_monthly']+\ lcc.calculate_total_operational_costs()['Variable_costs_electricity']+ \ lcc.calculate_total_operational_costs()['Fixed_costs_gas']+ \ lcc.calculate_total_operational_costs()['Variable_costs_gas'] df_maintenance_costs = lcc.calculate_total_operational_costs()['Heating_maintenance']+\ lcc.calculate_total_operational_costs()['Cooling_maintenance']+\ lcc.calculate_total_operational_costs()['PV_maintenance'] df_operational_incomes = lcc.calculate_total_operational_incomes()['Incomes electricity'] life_cycle_costs_capital_skin=_npv_from_list(discount_rate , df_capital_costs_skin.values.tolist()) life_cycle_costs_capital_systems=_npv_from_list(discount_rate , df_capital_costs_systems.values.tolist()) life_cycle_costs_end_of_life_costs = _npv_from_list(discount_rate, df_end_of_life_costs.values.tolist()) life_cycle_operational_costs = _npv_from_list(discount_rate, df_operational_costs.values.tolist()) life_cycle_maintenance_costs = _npv_from_list(discount_rate, df_maintenance_costs.values.tolist()) life_cycle_operational_incomes = _npv_from_list(discount_rate, df_operational_incomes.values.tolist()) life_cycle_costs = life_cycle_costs_capital_skin + life_cycle_costs_capital_systems + \ life_cycle_costs_end_of_life_costs + life_cycle_operational_costs + \ life_cycle_maintenance_costs - life_cycle_operational_incomes life_cycle_results[f'Scenario {retrofitting_scenario}'] = [life_cycle_costs_capital_skin, life_cycle_costs_capital_systems , life_cycle_costs_end_of_life_costs, life_cycle_operational_costs, life_cycle_maintenance_costs, life_cycle_operational_incomes] life_cycle_results.index = ['total_capital_costs_skin','total_capital_costs_systems','end_of_life_costs', 'total_operational_costs','total_maintenance_costs','life_cycle_costs', 'maintenance_costs'] life_cycle_results.to_excel(Path(__file__).parent/'out_files'/f'Results{building.name}.xlsx', index=True)