diff --git a/costs/__init__.py b/costs/__init__.py index 7ec7382..ef0404e 100644 --- a/costs/__init__.py +++ b/costs/__init__.py @@ -1,25 +1,9 @@ """ Cost workflow initialization """ -import glob -import os -from pathlib import Path +from .capital_costs import CapitalCosts +from .end_of_life_costs import EndOfLifeCosts +from .total_maintenance_costs import TotalMaintenanceCosts +from .total_operational_costs import TotalOperationalCosts +from .total_operational_incomes import TotalOperationalIncomes - -# constants -CURRENT_STATUS = 0 -SKIN_RETROFIT = 1 -SYSTEM_RETROFIT_AND_PV = 2 -SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV = 3 -RETROFITTING_SCENARIOS = [ - CURRENT_STATUS, - SKIN_RETROFIT, - SYSTEM_RETROFIT_AND_PV, - SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV -] -tmp_folder = Path('./tmp').resolve() -out_path = Path('./outputs').resolve() -files = glob.glob(f'{out_path}/*') -for file in files: - if file != '.gitignore': - os.remove(file) diff --git a/costs/configuration.py b/costs/configuration.py index 2d174b9..751d4a8 100644 --- a/costs/configuration.py +++ b/costs/configuration.py @@ -1,11 +1,7 @@ """ Configuration module -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Project Author 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 """ -from hub.catalog_factories.costs_catalog_factory import CostCatalogFactory +from hub.catalog_factories.costs_catalog_factory import CostsCatalogFactory from hub.catalog_factories.catalog import Catalog @@ -25,7 +21,10 @@ class Configuration: gas_price_index, discount_rate, retrofitting_year_construction, - factories_handler + factories_handler, + retrofit_scenario, + fuel_type, + dictionary ): self._number_of_years = number_of_years self._percentage_credit = percentage_credit @@ -38,7 +37,10 @@ class Configuration: self._discount_rate = discount_rate self._retrofitting_year_construction = retrofitting_year_construction self._factories_handler = factories_handler - self._cost_catalog = CostCatalogFactory(factories_handler).catalog + self._costs_catalog = CostsCatalogFactory(factories_handler).catalog + self._retrofit_scenario = retrofit_scenario + self._fuel_type = fuel_type + self._dictionary = dictionary @property def number_of_years(self): @@ -195,8 +197,29 @@ class Configuration: self._factories_handler = value @property - def cost_catalog(self) -> Catalog: + def costs_catalog(self) -> Catalog: """ - Get cost catalog + Get costs catalog """ - return self._cost_catalog + return self._costs_catalog + + @property + def retrofit_scenario(self): + """ + Get retrofit scenario + """ + return self._retrofit_scenario + + @property + def fuel_type(self): + """ + Get fuel type (0: Electricity, 1: Gas) + """ + return self._fuel_type + + @property + def dictionary(self): + """ + Get hub function to cost function dictionary + """ + return self._dictionary \ No newline at end of file diff --git a/costs/cost.py b/costs/cost.py index 5a4381b..537a23b 100644 --- a/costs/cost.py +++ b/costs/cost.py @@ -1,20 +1,14 @@ """ Cost module -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Project Author 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 """ - -from pathlib import Path - -import numpy_financial as npf +import hub.helpers.dictionaries import pandas as pd -from hub.persistence.models.city_object import CityObject +import numpy_financial as npf +from hub.city_model_structure.building import Building -from configuration import Configuration -from costs.results import Results -from life_cycle_costs import LifeCycleCosts +from costs.configuration import Configuration +from costs import CapitalCosts, EndOfLifeCosts, TotalMaintenanceCosts, TotalOperationalCosts, TotalOperationalIncomes +from costs.constants import CURRENT_STATUS class Cost: @@ -23,8 +17,7 @@ class Cost: """ def __init__(self, - buildings: [CityObject], - buildings_results: dict, + building: Building, number_of_years=31, percentage_credit=0, interest_rate=0.04, @@ -35,9 +28,13 @@ class Cost: gas_price_index=0.05, discount_rate=0.03, retrofitting_year_construction=2020, - factories_handler='montreal_custom'): - self._buildings = buildings - self._results = Results(buildings_results) + factories_handler='montreal_custom', + retrofit_scenario=CURRENT_STATUS, + dictionary=hub.helpers.dictionaries.Dictionaries().hub_function_to_montreal_custom_costs_function): + self._building = building + fuel_type = 0 + if "gas" in building.energy_systems_archetype_name: + fuel_type = 1 self._configuration = Configuration(number_of_years, percentage_credit, interest_rate, credit_years, @@ -47,21 +44,27 @@ class Cost: gas_price_index, discount_rate, retrofitting_year_construction, - factories_handler) - self._global_capital_costs = None - self._global_capital_incomes = None - self._global_end_of_life_costs = None - self._global_operational_costs = None - self._global_maintenance_costs = None - self._global_operational_incomes = None + factories_handler, + retrofit_scenario, + fuel_type, + dictionary) - def _life_cycle_costs(self, building: CityObject, building_results: dict): - lcc = LifeCycleCosts(building, building_results, self._configuration) - self._global_capital_costs, self._global_capital_incomes = lcc.calculate_capital_costs - self._global_end_of_life_costs = lcc.calculate_end_of_life_costs - self._global_operational_costs = lcc.calculate_total_operational_costs - self._global_maintenance_costs = lcc.calculate_total_maintenance_costs - self._global_operational_incomes = lcc.calculate_total_operational_incomes + @property + def building(self) -> Building: + """ + Get current building. + """ + return self._building + + @building.setter + def building(self, value: Building): + """ + Set current building. + """ + self._building = value + + def _npv_from_list(self, list_cashflow): + return npf.npv(self._configuration.discount_rate, list_cashflow) @property def life_cycle(self) -> pd.DataFrame: @@ -70,93 +73,71 @@ class Cost: :return: DataFrame """ results = pd.DataFrame() - for building_index, building in enumerate(self._buildings): - self._life_cycle_costs(building, self._buildings_results[building_index]) - df_capital_costs_skin = ( - self._global_capital_costs['B2010_opaque_walls'] + - self._global_capital_costs['B2020_transparent'] + - self._global_capital_costs['B3010_opaque_roof'] + - self._global_capital_costs['B10_superstructure'] - ) - df_capital_costs_systems = ( - self._global_capital_costs['D3020_heat_generating_systems'] + - self._global_capital_costs['D3030_cooling_generation_systems'] + - self._global_capital_costs['D3080_other_hvac_ahu'] + - self._global_capital_costs['D5020_lighting_and_branch_wiring'] + - self._global_capital_costs['D301010_photovoltaic_system'] - ) - df_end_of_life_costs = self._global_end_of_life_costs['End_of_life_costs'] - df_operational_costs = ( - self._global_operational_costs['Fixed_costs_electricity_peak'] + - self._global_operational_costs['Fixed_costs_electricity_monthly'] + - self._global_operational_costs['Fixed_costs_electricity_peak'] + - self._global_operational_costs['Fixed_costs_electricity_monthly'] + - self._global_operational_costs['Variable_costs_electricity'] + - self._global_operational_costs['Fixed_costs_gas'] + - self._global_operational_costs['Variable_costs_gas'] - ) - df_maintenance_costs = ( - self._global_maintenance_costs['Heating_maintenance'] + - self._global_maintenance_costs['Cooling_maintenance'] + - self._global_maintenance_costs['PV_maintenance'] - ) - df_operational_incomes = self._global_operational_incomes['Incomes electricity'] - df_capital_incomes = ( - self._global_capital_incomes['Subsidies construction'] + - self._global_capital_incomes['Subsidies HVAC'] + - self._global_capital_incomes['Subsidies PV'] - ) - life_cycle_costs_capital_skin = npf.npv( - self._configuration.discount_rate, df_capital_costs_skin.values.tolist() - ) - life_cycle_costs_capital_systems = npf.npv( - self._configuration.discount_rate, df_capital_costs_systems.values.tolist() - ) - life_cycle_costs_end_of_life_costs = npf.npv( - self._configuration.discount_rate, df_end_of_life_costs.values.tolist() - ) - life_cycle_operational_costs = npf.npv( - self._configuration.discount_rate, df_operational_costs.values.tolist() - ) - life_cycle_maintenance_costs = npf.npv( - self._configuration.discount_rate, df_maintenance_costs.values.tolist() - ) - life_cycle_operational_incomes = npf.npv( - self._configuration.discount_rate, df_operational_incomes.values.tolist() - ) - life_cycle_capital_incomes = npf.npv( - self._configuration.discount_rate, df_capital_incomes.values.tolist() - ) + 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() - results[f'{building.name}_{building.city_id}'] = [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] + 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 = 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.values.tolist()) + 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 + ] + + results.index = ['total_capital_costs_skin', + 'total_capital_costs_systems', + 'end_of_life_costs', + 'total_operational_costs', + 'total_maintenance_costs', + 'operational_incomes', + 'capital_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'] return results - - def to_xlsx(self, path: Path): - """ - Export life cycle costs to xls file - :return: none - """ - for building_index, building in enumerate(self._buildings): - _path = (path / f'{building.name}_{building.city_id}').resolve() - self._life_cycle_costs(building, self._buildings_results[building_index]) - with pd.ExcelWriter(path) as writer: - self._global_capital_costs.to_excel(writer, sheet_name='global_capital_costs') - self._global_end_of_life_costs.to_excel(writer, sheet_name='global_end_of_life_costs') - self._global_operational_costs.to_excel(writer, sheet_name='global_operational_costs') - self._global_maintenance_costs.to_excel(writer, sheet_name='global_maintenance_costs') - self._global_operational_incomes.to_excel(writer, sheet_name='global_operational_incomes') - self._global_capital_incomes.to_excel(writer, sheet_name='global_capital_incomes') diff --git a/resources.txt b/resources.txt deleted file mode 100644 index bc8992f..0000000 --- a/resources.txt +++ /dev/null @@ -1,2 +0,0 @@ -numpy_financial -cerc_hub \ No newline at end of file