First commit
This commit is contained in:
commit
d0d596e208
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# costs
|
||||||
|
|
||||||
|
Object-oriented generalization for the cost workflow
|
25
costs/__init__.py
Normal file
25
costs/__init__.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
"""
|
||||||
|
Cost workflow initialization
|
||||||
|
"""
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
202
costs/configuration.py
Normal file
202
costs/configuration.py
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
"""
|
||||||
|
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.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
|
161
costs/cost.py
Normal file
161
costs/cost.py
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
"""
|
||||||
|
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 pandas as pd
|
||||||
|
from hub.persistence.models.city_object import CityObject
|
||||||
|
|
||||||
|
from configuration import Configuration
|
||||||
|
from life_cycle_costs import LifeCycleCosts
|
||||||
|
|
||||||
|
|
||||||
|
class Cost:
|
||||||
|
"""
|
||||||
|
Cost class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
buildings: [CityObject],
|
||||||
|
buildings_results: dict,
|
||||||
|
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._buildings = buildings
|
||||||
|
self._buildings_results = buildings_results
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
|
||||||
|
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 life_cycle(self) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Get complete life cycle costs
|
||||||
|
: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()
|
||||||
|
)
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
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')
|
315
costs/life_cycle_costs.py
Normal file
315
costs/life_cycle_costs.py
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
"""
|
||||||
|
Life cycle 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 hub.persistence.models.city_object import CityObject
|
||||||
|
from configuration import Configuration
|
||||||
|
|
||||||
|
|
||||||
|
class LifeCycleCosts:
|
||||||
|
"""
|
||||||
|
Life cycle costs class
|
||||||
|
"""
|
||||||
|
def __init__(self, building: CityObject, building_results: dict, configuration: Configuration):
|
||||||
|
self._building = building
|
||||||
|
self._building_results = building_results
|
||||||
|
self._configuration = configuration
|
||||||
|
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')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def calculate_capital_costs(self):
|
||||||
|
"""
|
||||||
|
Calculate capital cost
|
||||||
|
:return: pd.DataFrame
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 = self._building.wall_area * chapter.item('B2010_opaque_walls').refurbishment[0]
|
||||||
|
capital_cost_transparent = self._building.windows_area * chapter.item('B2020_transparent').refurbishment[0]
|
||||||
|
capital_cost_roof = self._building.roof_area * chapter.item('B3010_opaque_roof').refurbishment[0]
|
||||||
|
capital_cost_ground = self._building.area * 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 = self._building.total_heating_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 = self._building.total_heating_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
|
||||||
|
|
||||||
|
@property
|
||||||
|
def calculate_end_of_life_costs(self):
|
||||||
|
"""
|
||||||
|
Calculate end of life costs
|
||||||
|
:return: pd.DataFrame
|
||||||
|
"""
|
||||||
|
archetype = self._archetype
|
||||||
|
|
||||||
|
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'] = self._building.total_heating_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
|
||||||
|
|
||||||
|
factor_residential = self._building.total_heating_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
|
||||||
|
|
||||||
|
@property
|
||||||
|
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
|
||||||
|
|
||||||
|
@property
|
||||||
|
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
|
2
resources.txt
Normal file
2
resources.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
numpy_financial
|
||||||
|
cerc_hub
|
9
tests/test_costs.py
Normal file
9
tests/test_costs.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import unittest
|
||||||
|
from costs.cost import Cost
|
||||||
|
|
||||||
|
|
||||||
|
class TestCosts(unittest.TestCase):
|
||||||
|
def test_costs(self):
|
||||||
|
cost = Cost()
|
||||||
|
self.assertEqual(True, False) # add assertion here
|
||||||
|
|
Loading…
Reference in New Issue
Block a user