""" Costs Workflow SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributor Oriol Gavalda Torrellas oriol.gavalda@concordia.ca """ from pathlib import Path import numpy_financial as npf import pandas as pd from energy_systems_sizing import EnergySystemsSizing from hub.catalog_factories.costs_catalog_factory import CostCatalogFactory from hub.helpers.dictionaries import Dictionaries from hub.imports.construction_factory import ConstructionFactory from hub.imports.energy_systems_factory import EnergySystemsFactory from hub.imports.geometry_factory import GeometryFactory from hub.imports.usage_factory import UsageFactory from hub.imports.weather_factory import WeatherFactory from hub.helpers import constants as cte from monthly_energy_balance_engine import MonthlyEnergyBalanceEngine from sra_engine import SraEngine from life_cycle_costs import LifeCycleCosts # import constants from costs import CLIMATE_REFERENCE_CITY, WEATHER_FILE, WEATHER_FORMAT, CONSTRUCTION_FORMAT, USAGE_FORMAT from costs import ENERGY_SYSTEM_FORMAT, ATTIC_HEATED_CASE, BASEMENT_HEATED_CASE, RETROFITTING_SCENARIOS, NUMBER_OF_YEARS from costs import CONSUMER_PRICE_INDEX, ELECTRICITY_PEAK_INDEX, ELECTRICITY_PRICE_INDEX, GAS_PRICE_INDEX, DISCOUNT_RATE from costs import SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV # import paths from costs import file_path, tmp_folder, out_path def _npv_from_list(npv_discount_rate, list_cashflow): lcc_value = npf.npv(npv_discount_rate, list_cashflow) return lcc_value 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') life_cycle_results = pd.DataFrame() print('[city creation start]') city = GeometryFactory('geojson', path=file_path, height_field='heightmax', year_of_construction_field='ANNEE_CONS', function_field='CODE_UTILI', function_to_hub=Dictionaries().montreal_function_to_hub_function).city 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_SYSTEM_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 in (SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV): for building in city.buildings: building.year_of_construction = retrofitting_year_of_construction ConstructionFactory(CONSTRUCTION_FORMAT, city).enrich() print('enrich retrofitted constructions... done') if retrofitting_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV): for building in city.buildings: building.energy_systems_archetype_name = 'system 6 electricity pv' EnergySystemsFactory(ENERGY_SYSTEM_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: function = Dictionaries().hub_function_to_montreal_custom_costs_function[building.function] archetype = _search_archetype(catalog, function) print('lcc for first building started') if "gas" in building.energy_systems_archetype_name: FUEL_TYPE = 1 else: FUEL_TYPE = 0 lcc = LifeCycleCosts(building, archetype, NUMBER_OF_YEARS, CONSUMER_PRICE_INDEX, ELECTRICITY_PEAK_INDEX, ELECTRICITY_PRICE_INDEX, GAS_PRICE_INDEX, DISCOUNT_RATE, retrofitting_scenario, FUEL_TYPE) global_capital_costs, global_capital_incomes = lcc.calculate_capital_costs() global_end_of_life_costs = lcc.calculate_end_of_life_costs() global_operational_costs = lcc.calculate_total_operational_costs() global_maintenance_costs = lcc.calculate_total_maintenance_costs() global_operational_incomes = lcc.calculate_total_operational_incomes() full_path_output = Path(out_path / f'output {retrofitting_scenario} {building.name}.xlsx').resolve() with pd.ExcelWriter(full_path_output) as writer: global_capital_costs.to_excel(writer, sheet_name='global_capital_costs') global_end_of_life_costs.to_excel(writer, sheet_name='global_end_of_life_costs') global_operational_costs.to_excel(writer, sheet_name='global_operational_costs') global_maintenance_costs.to_excel(writer, sheet_name='global_maintenance_costs') global_operational_incomes.to_excel(writer, sheet_name='global_operational_incomes') global_capital_incomes.to_excel(writer, sheet_name='global_capital_incomes') df_capital_costs_skin = ( global_capital_costs['B2010_opaque_walls'] + global_capital_costs['B2020_transparent'] + global_capital_costs['B3010_opaque_roof'] + global_capital_costs['B10_superstructure'] ) df_capital_costs_systems = ( global_capital_costs['D3020_heat_generating_systems'] + global_capital_costs['D3030_cooling_generation_systems'] + global_capital_costs['D3080_other_hvac_ahu'] + global_capital_costs['D5020_lighting_and_branch_wiring'] + global_capital_costs['D301010_photovoltaic_system'] ) df_end_of_life_costs = global_end_of_life_costs['End_of_life_costs'] df_operational_costs = ( global_operational_costs['Fixed_costs_electricity_peak'] + global_operational_costs['Fixed_costs_electricity_monthly'] + global_operational_costs['Fixed_costs_electricity_peak'] + global_operational_costs['Fixed_costs_electricity_monthly'] + global_operational_costs['Variable_costs_electricity'] + global_operational_costs['Fixed_costs_gas'] + global_operational_costs['Variable_costs_gas'] ) df_maintenance_costs = ( global_maintenance_costs['Heating_maintenance'] + global_maintenance_costs['Cooling_maintenance'] + global_maintenance_costs['PV_maintenance'] ) df_operational_incomes = global_operational_incomes['Incomes electricity'] df_capital_incomes = global_capital_incomes['Subsidies construction'] + global_capital_incomes['Subsidies HVAC'] + \ global_capital_incomes['Subsidies PV'] 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_capital_incomes = _npv_from_list(DISCOUNT_RATE, df_capital_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_capital_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_capital_incomes] life_cycle_results.index = ['total_capital_costs_skin', f'total_capital_costs_systems','end_of_life_costs', 'total_operational_costs', 'total_maintenance_costs', 'operational_incomes', 'capital_incomes'] print(life_cycle_results) print(f'Scenario {retrofitting_scenario} {life_cycle_costs}')