From 43eb91c8899b2b5b03be8563671b853c24011ec3 Mon Sep 17 00:00:00 2001 From: Guille Date: Thu, 1 Jun 2023 14:07:41 -0400 Subject: [PATCH] partial refactor --- costs/__init__.py | 20 +- costs/__main__.py | 167 +-------------- costs/building.py | 6 + costs/configuration.py | 198 ++++++++++++++++++ costs/cost.py | 162 +++++++++++++++ costs/life_cycle_costs.py | 207 ++----------------- costs/life_cycle_costs_old.py | 369 ++++++++++++++++++++++++++++++++++ 7 files changed, 760 insertions(+), 369 deletions(-) create mode 100644 costs/building.py create mode 100644 costs/configuration.py create mode 100644 costs/cost.py create mode 100644 costs/life_cycle_costs_old.py diff --git a/costs/__init__.py b/costs/__init__.py index f92f26b..5daa3ed 100644 --- a/costs/__init__.py +++ b/costs/__init__.py @@ -5,28 +5,24 @@ import glob import os from pathlib import Path -# configurable parameters +# constant + + +# to remove + file_path = Path('./data/selected_building_2864.geojson').resolve() CONSTRUCTION_FORMAT = 'nrcan' USAGE_FORMAT = 'comnet' ENERGY_SYSTEM_FORMAT = 'montreal_custom' ATTIC_HEATED_CASE = 0 BASEMENT_HEATED_CASE = 1 -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 -GAS_PRICE_INDEX = 0.05 -DISCOUNT_RATE = 0.03 -RETROFITTING_YEAR_CONSTRUCTION = 2020 - CLIMATE_REFERENCE_CITY = 'Montreal' WEATHER_FILE = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw' WEATHER_FORMAT = 'epw' CURRENT_STATUS = 0 + +# constants + SKIN_RETROFIT = 1 SYSTEM_RETROFIT_AND_PV = 2 SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV = 3 diff --git a/costs/__main__.py b/costs/__main__.py index e76efab..3c45080 100644 --- a/costs/__main__.py +++ b/costs/__main__.py @@ -7,10 +7,10 @@ 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 @@ -20,7 +20,7 @@ from hub.imports.weather_factory import WeatherFactory from monthly_energy_balance_engine import MonthlyEnergyBalanceEngine from sra_engine import SraEngine -from life_cycle_costs import LifeCycleCosts +from life_cycle_costs_old import LifeCycleCosts # import constants from costs import CLIMATE_REFERENCE_CITY, WEATHER_FILE, WEATHER_FORMAT, CONSTRUCTION_FORMAT, USAGE_FORMAT @@ -33,164 +33,3 @@ from costs import RETROFITTING_YEAR_CONSTRUCTION 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_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', - '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}') diff --git a/costs/building.py b/costs/building.py new file mode 100644 index 0000000..5b6441b --- /dev/null +++ b/costs/building.py @@ -0,0 +1,6 @@ +from hub.persistence.models.city_object import CityObject + +class Building(CityObject): + + def __init__(self, ): + super() \ No newline at end of file diff --git a/costs/configuration.py b/costs/configuration.py new file mode 100644 index 0000000..afbdd5b --- /dev/null +++ b/costs/configuration.py @@ -0,0 +1,198 @@ +""" +Configuration module +""" +from hub.catalog_factories.costs_catalog_factory import CostCatalogFactory +from hub.catalog_factories.catalog import Catalog + + +class Configuration: + """ + Configuration class + """ + + def __init__(self, + number_of_years, + percentage_credit, + interest_rate, + credit_years, + consumer_price_index, + electricity_peak_index, + electricity_price_index, + gas_price_index, + discount_rate, + retrofitting_year_construction, + factories_handler + ): + self._number_of_years = number_of_years + self._percentage_credit = percentage_credit + self._interest_rate = interest_rate + self._credit_years = credit_years + self._consumer_price_index = consumer_price_index + self._electricity_peak_index = electricity_peak_index + self._electricity_price_index = electricity_price_index + self._gas_price_index = gas_price_index + self._discount_rate = discount_rate + self._retrofitting_year_construction = retrofitting_year_construction + self._factories_handler = factories_handler + self._cost_catalog = CostCatalogFactory(factories_handler).catalog + + @property + def number_of_years(self): + """ + Get number of years + """ + return self._number_of_years + + @number_of_years.setter + def number_of_years(self, value): + """ + Set number of years + """ + self._number_of_years = value + + @property + def percentage_credit(self): + """ + Get percentage credit + """ + return self._percentage_credit + + @percentage_credit.setter + def percentage_credit(self, value): + """ + Set percentage credit + """ + self._percentage_credit = value + + @property + def interest_rate(self): + """ + Get interest rate + """ + return self._interest_rate + + @interest_rate.setter + def interest_rate(self, value): + """ + Set interest rate + """ + self._interest_rate = value + + @property + def credit_years(self): + """ + Get credit years + """ + return self._credit_years + + @credit_years.setter + def credit_years(self, value): + """ + Set credit years + """ + self._credit_years = value + + @property + def consumer_price_index(self): + """ + Get consumer price index + """ + return self._consumer_price_index + + @consumer_price_index.setter + def consumer_price_index(self, value): + """ + Set consumer price index + """ + self._consumer_price_index = value + + @property + def electricity_peak_index(self): + """ + Get electricity peak index + """ + return self._electricity_peak_index + + @electricity_peak_index.setter + def electricity_peak_index(self, value): + """ + Set electricity peak index + """ + self._electricity_peak_index = value + + @property + def electricity_price_index(self): + """ + Get electricity price index + """ + return self._electricity_price_index + + @electricity_price_index.setter + def electricity_price_index(self, value): + """ + Set electricity price index + """ + self._electricity_price_index = value + + @property + def gas_price_index(self): + """ + Get gas price index + """ + return self._gas_price_index + + @gas_price_index.setter + def gas_price_index(self, value): + """ + Set gas price index + """ + self._gas_price_index = value + + @property + def discount_rate(self): + """ + Get discount rate + """ + return self._discount_rate + + @discount_rate.setter + def discount_rate(self, value): + """ + Set discount rate + """ + self._discount_rate = value + + @property + def retrofitting_year_construction(self): + """ + Get retrofitting year construction + """ + return self._retrofitting_year_construction + + @retrofitting_year_construction.setter + def retrofitting_year_construction(self, value): + """ + Set retrofitting year construction + """ + self._retrofitting_year_construction = value + + @property + def factories_handler(self): + """ + Get factories handler + """ + return self._factories_handler + + @factories_handler.setter + def factories_handler(self, value): + """ + Set factories handler + """ + self._factories_handler = value + + @property + def cost_catalog(self) -> Catalog: + """ + Get cost catalog + """ + return self._cost_catalog diff --git a/costs/cost.py b/costs/cost.py new file mode 100644 index 0000000..7adebb9 --- /dev/null +++ b/costs/cost.py @@ -0,0 +1,162 @@ +""" +Cost module +""" +import pandas as pd +from hub.city_model_structure.city import City + +from configuration import Configuration +from life_cycle_costs import LifeCycleCosts + + +class Cost: + """ + Cost class + """ + + def __init__(self, + city: City, + 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, + gas_price_index=0.05, + discount_rate=0.03, + retrofitting_year_construction=2020, + factories_handler='montreal_custom'): + self._city = city + self._configuration = Configuration(number_of_years, + percentage_credit, + interest_rate, credit_years, + consumer_price_index, + electricity_peak_index, + electricity_price_index, + gas_price_index, + discount_rate, + retrofitting_year_construction, + factories_handler) + + @property + def life_cycle(self) -> pd.DataFrame: + """ + Get complete life cycle costs + :return: DataFrame + """ + results = pd.DataFrame() + for building in self._city.buildings: + lcc = LifeCycleCosts(building, self._configuration) + 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() + 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', + 'total_capital_costs_systems', + 'end_of_life_costs', + 'total_operational_costs', + 'total_maintenance_costs', + 'operational_incomes', + 'capital_incomes'] + return results + """ + + if "gas" in building.energy_systems_archetype_name: + FUEL_TYPE = 1 + else: + FUEL_TYPE = 0 + + + 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 = npf.npv(self._discount_rate, list_cashflow)_npv_from_list(, 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', + '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}') + return results + + +""" + diff --git a/costs/life_cycle_costs.py b/costs/life_cycle_costs.py index 7fc3974..0e88ed7 100644 --- a/costs/life_cycle_costs.py +++ b/costs/life_cycle_costs.py @@ -1,78 +1,36 @@ """ -LifeCycleCosts module calculates the life cycle costs of one building -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 +Life cycle costs module """ -import math - -import pandas as pd -import numpy_financial as npf -import hub.helpers.constants as cte -from costs import SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, PERCENTAGE_CREDIT,INTEREST_RATE,CREDIT_YEARS +from hub.city_model_structure.building import Building +from configuration import Configuration class LifeCycleCosts: """ - Life cycle cost class + Life cycle costs class """ - - def __init__(self, building, archetype, number_of_years, consumer_price_index, electricity_peak_index, - electricity_price_index, gas_price_index, discount_rate, - retrofitting_scenario, fuel_type): + def __init__(self, building: Building, configuration: Configuration): self._building = building - self._number_of_years = number_of_years - self._consumer_price_index = consumer_price_index - self._electricity_peak_index = electricity_peak_index - self._electricity_price_index = electricity_price_index - self._gas_price_index = gas_price_index - self._discount_rate = discount_rate - self._archetype = archetype - self._end_of_life_cost = 0 - self._capital_costs_at_year_0 = 0 - self._items = 0 - self._fuels = 0 - self._concepts = 0 - self._retrofitting_scenario = retrofitting_scenario + self._configuration = configuration self._total_floor_area = 0 - self._fuel_type = fuel_type for internal_zone in building.internal_zones: for thermal_zone in internal_zone.thermal_zones: self._total_floor_area += thermal_zone.total_floor_area - # todo: revise if it works - rng = range(number_of_years) - self._yearly_capital_costs = pd.DataFrame(index=rng, columns=['B2010_opaque_walls', 'B2020_transparent', - 'B3010_opaque_roof', 'B10_superstructure', - 'D301010_photovoltaic_system', - 'D3020_heat_generating_systems', - 'D3030_cooling_generation_systems', - 'D3040_distribution_systems', - 'D3080_other_hvac_ahu', - 'D5020_lighting_and_branch_wiring'], - dtype='float') - self._yearly_end_of_life_costs = pd.DataFrame(index=rng, columns=['End_of_life_costs'], dtype='float') - self._yearly_operational_costs = pd.DataFrame(index=rng, columns=['Fixed_costs_electricity_peak', - 'Fixed_costs_electricity_monthly', - 'Variable_costs_electricity', 'Fixed_costs_gas', - 'Variable_costs_gas'], - dtype='float') - self._yearly_maintenance_costs = pd.DataFrame(index=rng, columns=['Heating_maintenance', 'Cooling_maintenance', - 'PV_maintenance'], dtype='float') - self._yearly_operational_incomes = pd.DataFrame(index=rng, columns=['Incomes electricity'], dtype='float') - - self._yearly_capital_incomes = pd.DataFrame(index=rng, columns=['Subsidies construction', - 'Subsidies HVAC', 'Subsidies PV'], dtype='float') + self._archetype = None + for archetype in self._configuration.cost_catalog.entries('archetypes').archetype: + if str(building.function) == str(archetype.function): + self._archetype = archetype + break + if not self._archetype: + raise KeyError('archetype not found') def calculate_capital_costs(self): """ Calculate capital cost :return: pd.DataFrame """ - building = self._building - archetype = self._archetype - surface_opaque = 0 surface_transparent = 0 surface_roof = 0 @@ -88,7 +46,7 @@ class LifeCycleCosts: capital_cost_other_hvac_ahu = 0 capital_cost_lighting = 0 - total_floor_area = self._total_floor_area + total_floor_area = self._building.floor_area for internal_zone in building.internal_zones: for thermal_zone in internal_zone.thermal_zones: @@ -230,140 +188,3 @@ class LifeCycleCosts: self._yearly_capital_incomes.loc[0, 'Subsidies PV'] = capital_cost_pv * archetype.income.photovoltaic_subsidy/100 self._yearly_capital_incomes.fillna(0, inplace=True) return self._yearly_capital_costs, self._yearly_capital_incomes - - def calculate_end_of_life_costs(self): - """ - Calculate end of life costs - :return: pd.DataFrame - """ - archetype = self._archetype - total_floor_area = self._total_floor_area - - for year in range(1, self._number_of_years + 1): - price_increase = math.pow(1 + self._consumer_price_index, year) - if year == self._number_of_years: - self._yearly_end_of_life_costs.at[ - year, 'End_of_life_costs'] = total_floor_area * archetype.end_of_life_cost * price_increase - self._yearly_end_of_life_costs.fillna(0, inplace=True) - return self._yearly_end_of_life_costs - - @property - def calculate_total_operational_costs(self): - """ - Calculate total operational costs - :return: pd.DataFrame - """ - building = self._building - archetype = self._archetype - total_floor_area = self._total_floor_area - factor_residential = total_floor_area / 80 - # todo: split the heating between fuels - fixed_gas_cost_year_0 = 0 - variable_gas_cost_year_0 = 0 - electricity_heating = 0 - domestic_hot_water_electricity = 0 - if self._fuel_type == 1: - fixed_gas_cost_year_0 = archetype.operational_cost.fuels[1].fixed_monthly * 12 * factor_residential - variable_gas_cost_year_0 = ( - (building.heating_consumption[cte.YEAR][0] + building.domestic_hot_water_consumption[cte.YEAR][0]) / 1000 * - archetype.operational_cost.fuels[1].variable[0] - ) - if self._fuel_type == 0: - electricity_heating = building.heating_consumption[cte.YEAR][0] / 1000 - domestic_hot_water_electricity = building.domestic_hot_water_consumption[cte.YEAR][0] / 1000 - - electricity_cooling = building.cooling_consumption[cte.YEAR][0] / 1000 - electricity_lighting = building.lighting_electrical_demand[cte.YEAR]['insel meb'] / 1000 - electricity_plug_loads = building.appliances_electrical_demand[cte.YEAR]['insel meb'] / 1000 - electricity_distribution = 0 - total_electricity_consumption = ( - electricity_heating + electricity_cooling + electricity_lighting + domestic_hot_water_electricity + - electricity_plug_loads + electricity_distribution - ) - - # todo: change when peak electricity demand is coded. Careful with factor residential - peak_electricity_demand = 100 # self._peak_electricity_demand - variable_electricity_cost_year_0 = total_electricity_consumption * archetype.operational_cost.fuels[0].variable[0] - peak_electricity_cost_year_0 = peak_electricity_demand * archetype.operational_cost.fuels[0].fixed_power * 12 - monthly_electricity_cost_year_0 = archetype.operational_cost.fuels[0].fixed_monthly * 12 * factor_residential - - for year in range(1, self._number_of_years + 1): - price_increase_electricity = math.pow(1 + self._electricity_price_index, year) - price_increase_peak_electricity = math.pow(1 + self._electricity_peak_index, year) - price_increase_gas = math.pow(1 + self._gas_price_index, year) - self._yearly_operational_costs.at[year, 'Fixed_costs_electricity_peak'] = ( - peak_electricity_cost_year_0 * price_increase_peak_electricity - ) - - self._yearly_operational_costs.at[year, 'Fixed_costs_electricity_monthly'] = ( - monthly_electricity_cost_year_0 * price_increase_peak_electricity - ) - self._yearly_operational_costs.at[year, 'Variable_costs_electricity'] = float( - variable_electricity_cost_year_0 * price_increase_electricity - ) - self._yearly_operational_costs.at[year, 'Fixed_costs_gas'] = fixed_gas_cost_year_0 * price_increase_gas - self._yearly_operational_costs.at[year, 'Variable_costs_gas'] = ( - variable_gas_cost_year_0 * price_increase_peak_electricity - ) - self._yearly_operational_costs.at[year, 'Variable_costs_gas'] = ( - variable_gas_cost_year_0 * price_increase_peak_electricity - ) - self._yearly_operational_costs.fillna(0, inplace=True) - - return self._yearly_operational_costs - - def calculate_total_operational_incomes(self): - """ - Calculate total operational incomes - :return: pd.DataFrame - """ - building = self._building - if cte.YEAR not in building.onsite_electrical_production: - onsite_electricity_production = 0 - else: - onsite_electricity_production = building.onsite_electrical_production[cte.YEAR][0]/1000 - - for year in range(1, self._number_of_years + 1): - price_increase_electricity = math.pow(1 + self._electricity_price_index, year) - # todo: check the adequate assignation of price. Pilar - price_export = 0.075 # archetype.income.electricity_export - self._yearly_operational_incomes.loc[year, 'Incomes electricity'] = ( - onsite_electricity_production * price_export * price_increase_electricity - ) - - self._yearly_operational_incomes.fillna(0, inplace=True) - return self._yearly_operational_incomes - - def calculate_total_maintenance_costs(self): - """ - Calculate total maintenance costs - :return: pd.DataFrame - """ - building = self._building - archetype = self._archetype - # todo: change area pv when the variable exists - roof_area = 0 - for roof in building.roofs: - roof_area += roof.solid_polygon.area - surface_pv = roof_area * 0.5 - - peak_heating = building.heating_peak_load[cte.YEAR][cte.HEATING_PEAK_LOAD][0] - peak_cooling = building.cooling_peak_load[cte.YEAR][cte.COOLING_PEAK_LOAD][0] - - maintenance_heating_0 = peak_heating * archetype.operational_cost.maintenance_heating - maintenance_cooling_0 = peak_cooling * archetype.operational_cost.maintenance_cooling - maintenance_pv_0 = surface_pv * archetype.operational_cost.maintenance_pv - - for year in range(1, self._number_of_years + 1): - costs_increase = math.pow(1 + self._consumer_price_index, year) - self._yearly_maintenance_costs.loc[year, 'Heating_maintenance'] = ( - maintenance_heating_0 * costs_increase - ) - self._yearly_maintenance_costs.loc[year, 'Cooling_maintenance'] = ( - maintenance_cooling_0 * costs_increase - ) - self._yearly_maintenance_costs.loc[year, 'PV_maintenance'] = ( - maintenance_pv_0 * costs_increase - ) - self._yearly_maintenance_costs.fillna(0, inplace=True) - return self._yearly_maintenance_costs diff --git a/costs/life_cycle_costs_old.py b/costs/life_cycle_costs_old.py new file mode 100644 index 0000000..7fc3974 --- /dev/null +++ b/costs/life_cycle_costs_old.py @@ -0,0 +1,369 @@ +""" +LifeCycleCosts module calculates the life cycle costs of one building +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 +""" + +import math + +import pandas as pd +import numpy_financial as npf +import hub.helpers.constants as cte +from costs import SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, PERCENTAGE_CREDIT,INTEREST_RATE,CREDIT_YEARS + + +class LifeCycleCosts: + """ + Life cycle cost class + """ + + def __init__(self, building, archetype, number_of_years, consumer_price_index, electricity_peak_index, + electricity_price_index, gas_price_index, discount_rate, + retrofitting_scenario, fuel_type): + self._building = building + self._number_of_years = number_of_years + self._consumer_price_index = consumer_price_index + self._electricity_peak_index = electricity_peak_index + self._electricity_price_index = electricity_price_index + self._gas_price_index = gas_price_index + self._discount_rate = discount_rate + self._archetype = archetype + self._end_of_life_cost = 0 + self._capital_costs_at_year_0 = 0 + self._items = 0 + self._fuels = 0 + self._concepts = 0 + self._retrofitting_scenario = retrofitting_scenario + self._total_floor_area = 0 + self._fuel_type = fuel_type + for internal_zone in building.internal_zones: + for thermal_zone in internal_zone.thermal_zones: + self._total_floor_area += thermal_zone.total_floor_area + + # todo: revise if it works + rng = range(number_of_years) + self._yearly_capital_costs = pd.DataFrame(index=rng, columns=['B2010_opaque_walls', 'B2020_transparent', + 'B3010_opaque_roof', 'B10_superstructure', + 'D301010_photovoltaic_system', + 'D3020_heat_generating_systems', + 'D3030_cooling_generation_systems', + 'D3040_distribution_systems', + 'D3080_other_hvac_ahu', + 'D5020_lighting_and_branch_wiring'], + dtype='float') + self._yearly_end_of_life_costs = pd.DataFrame(index=rng, columns=['End_of_life_costs'], dtype='float') + self._yearly_operational_costs = pd.DataFrame(index=rng, columns=['Fixed_costs_electricity_peak', + 'Fixed_costs_electricity_monthly', + 'Variable_costs_electricity', 'Fixed_costs_gas', + 'Variable_costs_gas'], + dtype='float') + self._yearly_maintenance_costs = pd.DataFrame(index=rng, columns=['Heating_maintenance', 'Cooling_maintenance', + 'PV_maintenance'], dtype='float') + self._yearly_operational_incomes = pd.DataFrame(index=rng, columns=['Incomes electricity'], dtype='float') + + self._yearly_capital_incomes = pd.DataFrame(index=rng, columns=['Subsidies construction', + 'Subsidies HVAC', 'Subsidies PV'], dtype='float') + + def calculate_capital_costs(self): + """ + Calculate capital cost + :return: pd.DataFrame + """ + building = self._building + archetype = self._archetype + + surface_opaque = 0 + surface_transparent = 0 + surface_roof = 0 + surface_ground = 0 + capital_cost_pv = 0 + capital_cost_opaque = 0 + capital_cost_ground = 0 + capital_cost_transparent = 0 + capital_cost_roof = 0 + capital_cost_heating_equipment = 0 + capital_cost_cooling_equipment = 0 + capital_cost_distribution_equipment = 0 + capital_cost_other_hvac_ahu = 0 + capital_cost_lighting = 0 + + total_floor_area = self._total_floor_area + + for internal_zone in building.internal_zones: + for thermal_zone in internal_zone.thermal_zones: + for thermal_boundary in thermal_zone.thermal_boundaries: + if thermal_boundary.type == 'Ground': + surface_ground += thermal_boundary.opaque_area + elif thermal_boundary.type == 'Roof': + surface_roof += thermal_boundary.opaque_area + elif thermal_boundary.type == 'Wall': + surface_opaque += thermal_boundary.opaque_area * (1 - thermal_boundary.window_ratio) + surface_transparent += thermal_boundary.opaque_area * thermal_boundary.window_ratio + + chapters = archetype.capital_cost + + peak_heating = building.heating_peak_load[cte.YEAR].values[0]/1000 + peak_cooling = building.cooling_peak_load[cte.YEAR].values[0]/1000 + # todo: change area pv when the variable exists + roof_area = 0 + for roof in building.roofs: + roof_area += roof.solid_polygon.area + surface_pv = roof_area * 0.5 + + self._yearly_capital_costs.loc[0, 'B2010_opaque_walls'] = 0 + self._yearly_capital_costs.loc[0]['B2020_transparent'] = 0 + self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = 0 + self._yearly_capital_costs.loc[0]['B10_superstructure'] = 0 + + self._yearly_capital_costs.loc[0, 'D3020_heat_generating_systems'] = 0 + self._yearly_capital_costs.loc[0, 'D3030_cooling_generation_systems'] = 0 + self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = 0 + self._yearly_capital_costs.loc[0, 'D3080_other_hvac_ahu'] = 0 + self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = 0 + + self._yearly_capital_incomes.loc[0, 'Subsidies construction'] = 0 + self._yearly_capital_incomes.loc[0, 'Subsidies HVAC'] = 0 + self._yearly_capital_incomes.loc[0, 'Subsidies PV'] = 0 + + self._yearly_capital_costs.fillna(0, inplace=True) + if self._retrofitting_scenario in (SKIN_RETROFIT, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV): + chapter = chapters.chapter('B_shell') + capital_cost_opaque = surface_opaque * chapter.item('B2010_opaque_walls').refurbishment[0] + capital_cost_transparent = surface_transparent * chapter.item('B2020_transparent').refurbishment[0] + capital_cost_roof = surface_roof * chapter.item('B3010_opaque_roof').refurbishment[0] + capital_cost_ground = surface_ground * chapter.item('B10_superstructure').refurbishment[0] + + + self._yearly_capital_costs.loc[0, 'B2010_opaque_walls'] = capital_cost_opaque * (1-PERCENTAGE_CREDIT) + self._yearly_capital_costs.loc[0]['B2020_transparent'] = capital_cost_transparent * (1-PERCENTAGE_CREDIT) + self._yearly_capital_costs.loc[0, 'B3010_opaque_roof'] = capital_cost_roof * (1-PERCENTAGE_CREDIT) + self._yearly_capital_costs.loc[0]['B10_superstructure'] = capital_cost_ground * (1-PERCENTAGE_CREDIT) + + + if self._retrofitting_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV): + chapter = chapters.chapter('D_services') + capital_cost_pv = surface_pv * chapter.item('D301010_photovoltaic_system').initial_investment[0] + self._yearly_capital_costs.loc[0]['D301010_photovoltaic_system'] = capital_cost_pv + capital_cost_heating_equipment = ( + peak_heating * chapter.item('D3020_heat_generating_systems').initial_investment[0] + ) + capital_cost_cooling_equipment = ( + peak_cooling * chapter.item('D3030_cooling_generation_systems').initial_investment[0] + ) + capital_cost_distribution_equipment = ( + peak_cooling * chapter.item('D3040_distribution_systems').initial_investment[0] + ) + capital_cost_other_hvac_ahu = peak_cooling * chapter.item('D3080_other_hvac_ahu').initial_investment[0] + capital_cost_lighting = total_floor_area * chapter.item('D5020_lighting_and_branch_wiring').initial_investment[0] + + self._yearly_capital_costs.loc[0, 'D3020_heat_generating_systems'] = capital_cost_heating_equipment * (1-PERCENTAGE_CREDIT) + self._yearly_capital_costs.loc[0, 'D3030_cooling_generation_systems'] = capital_cost_cooling_equipment * (1-PERCENTAGE_CREDIT) + self._yearly_capital_costs.loc[0, 'D3040_distribution_systems'] = capital_cost_distribution_equipment * (1-PERCENTAGE_CREDIT) + self._yearly_capital_costs.loc[0, 'D3080_other_hvac_ahu'] = capital_cost_other_hvac_ahu * (1-PERCENTAGE_CREDIT) + self._yearly_capital_costs.loc[0, 'D5020_lighting_and_branch_wiring'] = capital_cost_lighting * (1-PERCENTAGE_CREDIT) + + for year in range(1, self._number_of_years): + chapter = chapters.chapter('D_services') + costs_increase = math.pow(1 + self._consumer_price_index, year) + self._yearly_capital_costs.loc[year, 'B2010_opaque_walls'] = -npf.pmt(INTEREST_RATE, CREDIT_YEARS, + capital_cost_opaque * (PERCENTAGE_CREDIT)) + self._yearly_capital_costs.loc[year, 'B2020_transparent'] = -npf.pmt(INTEREST_RATE, CREDIT_YEARS, + capital_cost_transparent * (PERCENTAGE_CREDIT) + ) + self._yearly_capital_costs.loc[year, 'B3010_opaque_roof'] = -npf.pmt(INTEREST_RATE, CREDIT_YEARS,capital_cost_roof + * (PERCENTAGE_CREDIT)) + self._yearly_capital_costs.loc[year, 'B10_superstructure'] = -npf.pmt(INTEREST_RATE, CREDIT_YEARS, + capital_cost_ground * (PERCENTAGE_CREDIT)) + self._yearly_capital_costs.loc[year, 'D3020_heat_generating_systems'] = -npf.pmt(INTEREST_RATE,CREDIT_YEARS, + capital_cost_heating_equipment + * (PERCENTAGE_CREDIT)) + self._yearly_capital_costs.loc[year, 'D3030_cooling_generation_systems'] = -npf.pmt(INTEREST_RATE, CREDIT_YEARS, + capital_cost_cooling_equipment + * (PERCENTAGE_CREDIT)) + self._yearly_capital_costs.loc[year, 'D3040_distribution_systems'] = -npf.pmt(INTEREST_RATE, CREDIT_YEARS, + capital_cost_distribution_equipment + * (PERCENTAGE_CREDIT)) + self._yearly_capital_costs.loc[year, 'D3080_other_hvac_ahu'] = -npf.pmt(INTEREST_RATE, CREDIT_YEARS, + capital_cost_other_hvac_ahu + * (PERCENTAGE_CREDIT)) + self._yearly_capital_costs.loc[year, 'D5020_lighting_and_branch_wiring'] = -npf.pmt(INTEREST_RATE, CREDIT_YEARS, + capital_cost_lighting + * (PERCENTAGE_CREDIT)) + if (year % chapter.item('D3020_heat_generating_systems').lifetime) == 0: + reposition_cost_heating_equipment = peak_heating * chapter.item('D3020_heat_generating_systems').reposition[0] \ + * costs_increase + self._yearly_capital_costs.loc[year, 'D3020_heat_generating_systems'] += reposition_cost_heating_equipment + + if (year % chapter.item('D3030_cooling_generation_systems').lifetime) == 0: + reposition_cost_cooling_equipment = peak_cooling \ + * chapter.item('D3030_cooling_generation_systems').reposition[0] \ + * costs_increase + self._yearly_capital_costs.loc[year, 'D3030_cooling_generation_systems'] += reposition_cost_cooling_equipment + + if (year % chapter.item('D3080_other_hvac_ahu').lifetime) == 0: + reposition_cost_hvac_ahu = peak_cooling * chapter.item('D3080_other_hvac_ahu').reposition[0] * costs_increase + self._yearly_capital_costs.loc[year, 'D3080_other_hvac_ahu'] = reposition_cost_hvac_ahu + + if (year % chapter.item('D5020_lighting_and_branch_wiring').lifetime) == 0: + reposition_cost_lighting = total_floor_area * chapter.item('D5020_lighting_and_branch_wiring').reposition[0] \ + * costs_increase + self._yearly_capital_costs.loc[year, 'D5020_lighting_and_branch_wiring'] += reposition_cost_lighting + + if self._retrofitting_scenario in (SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV): + if (year % chapter.item('D301010_photovoltaic_system').lifetime) == 0: + self._yearly_capital_costs.loc[year]['D301010_photovoltaic_system'] += surface_pv \ + * chapter.item( + 'D301010_photovoltaic_system').reposition[0] * costs_increase + capital_cost_skin = capital_cost_opaque + capital_cost_ground + capital_cost_transparent + capital_cost_roof + capital_cost_hvac = ( + capital_cost_heating_equipment + + capital_cost_cooling_equipment + + capital_cost_distribution_equipment + + capital_cost_other_hvac_ahu + capital_cost_lighting + ) + + self._yearly_capital_incomes.loc[0, 'Subsidies construction'] = ( + capital_cost_skin * archetype.income.construction_subsidy/100 + ) + self._yearly_capital_incomes.loc[0, 'Subsidies HVAC'] = capital_cost_hvac * archetype.income.hvac_subsidy/100 + self._yearly_capital_incomes.loc[0, 'Subsidies PV'] = capital_cost_pv * archetype.income.photovoltaic_subsidy/100 + self._yearly_capital_incomes.fillna(0, inplace=True) + return self._yearly_capital_costs, self._yearly_capital_incomes + + def calculate_end_of_life_costs(self): + """ + Calculate end of life costs + :return: pd.DataFrame + """ + archetype = self._archetype + total_floor_area = self._total_floor_area + + for year in range(1, self._number_of_years + 1): + price_increase = math.pow(1 + self._consumer_price_index, year) + if year == self._number_of_years: + self._yearly_end_of_life_costs.at[ + year, 'End_of_life_costs'] = total_floor_area * archetype.end_of_life_cost * price_increase + self._yearly_end_of_life_costs.fillna(0, inplace=True) + return self._yearly_end_of_life_costs + + @property + def calculate_total_operational_costs(self): + """ + Calculate total operational costs + :return: pd.DataFrame + """ + building = self._building + archetype = self._archetype + total_floor_area = self._total_floor_area + factor_residential = total_floor_area / 80 + # todo: split the heating between fuels + fixed_gas_cost_year_0 = 0 + variable_gas_cost_year_0 = 0 + electricity_heating = 0 + domestic_hot_water_electricity = 0 + if self._fuel_type == 1: + fixed_gas_cost_year_0 = archetype.operational_cost.fuels[1].fixed_monthly * 12 * factor_residential + variable_gas_cost_year_0 = ( + (building.heating_consumption[cte.YEAR][0] + building.domestic_hot_water_consumption[cte.YEAR][0]) / 1000 * + archetype.operational_cost.fuels[1].variable[0] + ) + if self._fuel_type == 0: + electricity_heating = building.heating_consumption[cte.YEAR][0] / 1000 + domestic_hot_water_electricity = building.domestic_hot_water_consumption[cte.YEAR][0] / 1000 + + electricity_cooling = building.cooling_consumption[cte.YEAR][0] / 1000 + electricity_lighting = building.lighting_electrical_demand[cte.YEAR]['insel meb'] / 1000 + electricity_plug_loads = building.appliances_electrical_demand[cte.YEAR]['insel meb'] / 1000 + electricity_distribution = 0 + total_electricity_consumption = ( + electricity_heating + electricity_cooling + electricity_lighting + domestic_hot_water_electricity + + electricity_plug_loads + electricity_distribution + ) + + # todo: change when peak electricity demand is coded. Careful with factor residential + peak_electricity_demand = 100 # self._peak_electricity_demand + variable_electricity_cost_year_0 = total_electricity_consumption * archetype.operational_cost.fuels[0].variable[0] + peak_electricity_cost_year_0 = peak_electricity_demand * archetype.operational_cost.fuels[0].fixed_power * 12 + monthly_electricity_cost_year_0 = archetype.operational_cost.fuels[0].fixed_monthly * 12 * factor_residential + + for year in range(1, self._number_of_years + 1): + price_increase_electricity = math.pow(1 + self._electricity_price_index, year) + price_increase_peak_electricity = math.pow(1 + self._electricity_peak_index, year) + price_increase_gas = math.pow(1 + self._gas_price_index, year) + self._yearly_operational_costs.at[year, 'Fixed_costs_electricity_peak'] = ( + peak_electricity_cost_year_0 * price_increase_peak_electricity + ) + + self._yearly_operational_costs.at[year, 'Fixed_costs_electricity_monthly'] = ( + monthly_electricity_cost_year_0 * price_increase_peak_electricity + ) + self._yearly_operational_costs.at[year, 'Variable_costs_electricity'] = float( + variable_electricity_cost_year_0 * price_increase_electricity + ) + self._yearly_operational_costs.at[year, 'Fixed_costs_gas'] = fixed_gas_cost_year_0 * price_increase_gas + self._yearly_operational_costs.at[year, 'Variable_costs_gas'] = ( + variable_gas_cost_year_0 * price_increase_peak_electricity + ) + self._yearly_operational_costs.at[year, 'Variable_costs_gas'] = ( + variable_gas_cost_year_0 * price_increase_peak_electricity + ) + self._yearly_operational_costs.fillna(0, inplace=True) + + return self._yearly_operational_costs + + def calculate_total_operational_incomes(self): + """ + Calculate total operational incomes + :return: pd.DataFrame + """ + building = self._building + if cte.YEAR not in building.onsite_electrical_production: + onsite_electricity_production = 0 + else: + onsite_electricity_production = building.onsite_electrical_production[cte.YEAR][0]/1000 + + for year in range(1, self._number_of_years + 1): + price_increase_electricity = math.pow(1 + self._electricity_price_index, year) + # todo: check the adequate assignation of price. Pilar + price_export = 0.075 # archetype.income.electricity_export + self._yearly_operational_incomes.loc[year, 'Incomes electricity'] = ( + onsite_electricity_production * price_export * price_increase_electricity + ) + + self._yearly_operational_incomes.fillna(0, inplace=True) + return self._yearly_operational_incomes + + def calculate_total_maintenance_costs(self): + """ + Calculate total maintenance costs + :return: pd.DataFrame + """ + building = self._building + archetype = self._archetype + # todo: change area pv when the variable exists + roof_area = 0 + for roof in building.roofs: + roof_area += roof.solid_polygon.area + surface_pv = roof_area * 0.5 + + peak_heating = building.heating_peak_load[cte.YEAR][cte.HEATING_PEAK_LOAD][0] + peak_cooling = building.cooling_peak_load[cte.YEAR][cte.COOLING_PEAK_LOAD][0] + + maintenance_heating_0 = peak_heating * archetype.operational_cost.maintenance_heating + maintenance_cooling_0 = peak_cooling * archetype.operational_cost.maintenance_cooling + maintenance_pv_0 = surface_pv * archetype.operational_cost.maintenance_pv + + for year in range(1, self._number_of_years + 1): + costs_increase = math.pow(1 + self._consumer_price_index, year) + self._yearly_maintenance_costs.loc[year, 'Heating_maintenance'] = ( + maintenance_heating_0 * costs_increase + ) + self._yearly_maintenance_costs.loc[year, 'Cooling_maintenance'] = ( + maintenance_cooling_0 * costs_increase + ) + self._yearly_maintenance_costs.loc[year, 'PV_maintenance'] = ( + maintenance_pv_0 * costs_increase + ) + self._yearly_maintenance_costs.fillna(0, inplace=True) + return self._yearly_maintenance_costs