""" Cost module SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2023 Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Code contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributor Oriol Gavalda Torrellas oriol.gavalda@concordia.ca """ import datetime import pandas as pd import numpy_financial as npf from hub.city_model_structure.building import Building from hub.helpers.dictionaries import Dictionaries from scripts.costs.configuration import Configuration from scripts.costs.capital_costs import CapitalCosts from scripts.costs.end_of_life_costs import EndOfLifeCosts from scripts.costs.total_maintenance_costs import TotalMaintenanceCosts from scripts.costs.total_operational_costs import TotalOperationalCosts from scripts.costs.total_operational_incomes import TotalOperationalIncomes from scripts.costs.constants import CURRENT_STATUS, SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV import hub.helpers.constants as cte class Cost: """ Cost class """ def __init__(self, building: Building, number_of_years=31, percentage_credit=0, interest_rate=0.04, credit_years=15, consumer_price_index=0.04, electricity_peak_index=0.05, electricity_price_index=0.05, fuel_price_index=0.05, discount_rate=0.03, retrofitting_year_construction=2020, factories_handler='montreal_new', retrofit_scenario=CURRENT_STATUS, dictionary=None, fuel_tariffs=None): if fuel_tariffs is None: fuel_tariffs = ['Electricity-D', 'Gas-Energir'] if dictionary is None: dictionary = Dictionaries().hub_function_to_montreal_custom_costs_function self._building = building fuel_type = self._building.energy_consumption_breakdown.keys() self._configuration = Configuration(number_of_years, percentage_credit, interest_rate, credit_years, consumer_price_index, electricity_peak_index, electricity_price_index, fuel_price_index, discount_rate, retrofitting_year_construction, factories_handler, retrofit_scenario, fuel_type, dictionary, fuel_tariffs) @property def building(self) -> Building: """ Get current building. """ return self._building def _npv_from_list(self, list_cashflow): return npf.npv(self._configuration.discount_rate, list_cashflow) @property def life_cycle(self) -> pd.DataFrame: """ Get complete life cycle costs :return: DataFrame """ results = pd.DataFrame() global_capital_costs, global_capital_incomes = CapitalCosts(self._building, self._configuration).calculate() global_end_of_life_costs = EndOfLifeCosts(self._building, self._configuration).calculate() global_operational_costs = TotalOperationalCosts(self._building, self._configuration).calculate() global_maintenance_costs = TotalMaintenanceCosts(self._building, self._configuration).calculate() global_operational_incomes = TotalOperationalIncomes(self._building, self._configuration).calculate() df_capital_costs_skin = ( global_capital_costs['B2010_opaque_walls'] + global_capital_costs['B2020_transparent'] + global_capital_costs['B3010_opaque_roof'] + global_capital_costs['B1010_superstructure'] ) df_capital_costs_systems = ( global_capital_costs['D3020_simultaneous_heat_and_cooling_generating_systems'] + global_capital_costs['D3030_heating_systems'] + global_capital_costs['D3040_cooling_systems'] + global_capital_costs['D3050_distribution_systems'] + global_capital_costs['D3060_other_hvac_ahu'] + global_capital_costs['D3070_storage_systems'] + global_capital_costs['D40_dhw'] + global_capital_costs['D2010_photovoltaic_system'] ) df_end_of_life_costs = global_end_of_life_costs['End_of_life_costs'] operational_costs_list = [ global_operational_costs['Fixed Costs Electricity Peak'], global_operational_costs['Fixed Costs Electricity Monthly'], global_operational_costs['Variable Costs Electricity'] ] additional_costs = [ global_operational_costs[f'Fixed Costs {fuel}'] for fuel in self._building.energy_consumption_breakdown.keys() if fuel != cte.ELECTRICITY ] + [ global_operational_costs[f'Variable Costs {fuel}'] for fuel in self._building.energy_consumption_breakdown.keys() if fuel != cte.ELECTRICITY ] df_operational_costs = sum(operational_costs_list + additional_costs) 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 = self._npv_from_list(df_capital_costs_skin.values.tolist()) life_cycle_costs_capital_systems = self._npv_from_list(df_capital_costs_systems.values.tolist()) life_cycle_costs_end_of_life_costs = self._npv_from_list(df_end_of_life_costs.values.tolist()) life_cycle_operational_costs = self._npv_from_list(df_operational_costs) life_cycle_maintenance_costs = self._npv_from_list(df_maintenance_costs.values.tolist()) life_cycle_operational_incomes = self._npv_from_list(df_operational_incomes.values.tolist()) life_cycle_capital_incomes = self._npv_from_list(df_capital_incomes.values.tolist()) results[f'Scenario {self._configuration.retrofit_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, global_capital_costs, global_capital_incomes, global_end_of_life_costs, global_operational_costs, global_maintenance_costs, global_operational_incomes ] results.index = [ 'total_capital_costs_skin', 'total_capital_costs_systems', 'end_of_life_costs', 'total_operational_costs', 'total_maintenance_costs', 'operational_incomes', 'capital_incomes', 'global_capital_costs', 'global_capital_incomes', 'global_end_of_life_costs', 'global_operational_costs', 'global_maintenance_costs', 'global_operational_incomes' ] return results