merge branch
This commit is contained in:
parent
301ea48953
commit
1b80543bb1
@ -1,25 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
Cost workflow initialization
|
Cost workflow initialization
|
||||||
"""
|
"""
|
||||||
import glob
|
from .capital_costs import CapitalCosts
|
||||||
import os
|
from .end_of_life_costs import EndOfLifeCosts
|
||||||
from pathlib import Path
|
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)
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Configuration module
|
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
|
from hub.catalog_factories.catalog import Catalog
|
||||||
|
|
||||||
|
|
||||||
@ -25,7 +21,10 @@ class Configuration:
|
|||||||
gas_price_index,
|
gas_price_index,
|
||||||
discount_rate,
|
discount_rate,
|
||||||
retrofitting_year_construction,
|
retrofitting_year_construction,
|
||||||
factories_handler
|
factories_handler,
|
||||||
|
retrofit_scenario,
|
||||||
|
fuel_type,
|
||||||
|
dictionary
|
||||||
):
|
):
|
||||||
self._number_of_years = number_of_years
|
self._number_of_years = number_of_years
|
||||||
self._percentage_credit = percentage_credit
|
self._percentage_credit = percentage_credit
|
||||||
@ -38,7 +37,10 @@ class Configuration:
|
|||||||
self._discount_rate = discount_rate
|
self._discount_rate = discount_rate
|
||||||
self._retrofitting_year_construction = retrofitting_year_construction
|
self._retrofitting_year_construction = retrofitting_year_construction
|
||||||
self._factories_handler = factories_handler
|
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
|
@property
|
||||||
def number_of_years(self):
|
def number_of_years(self):
|
||||||
@ -195,8 +197,29 @@ class Configuration:
|
|||||||
self._factories_handler = value
|
self._factories_handler = value
|
||||||
|
|
||||||
@property
|
@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
|
217
costs/cost.py
217
costs/cost.py
@ -1,20 +1,14 @@
|
|||||||
"""
|
"""
|
||||||
Cost module
|
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
|
|
||||||
"""
|
"""
|
||||||
|
import hub.helpers.dictionaries
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import numpy_financial as npf
|
|
||||||
import pandas as pd
|
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.configuration import Configuration
|
||||||
from costs.results import Results
|
from costs import CapitalCosts, EndOfLifeCosts, TotalMaintenanceCosts, TotalOperationalCosts, TotalOperationalIncomes
|
||||||
from life_cycle_costs import LifeCycleCosts
|
from costs.constants import CURRENT_STATUS
|
||||||
|
|
||||||
|
|
||||||
class Cost:
|
class Cost:
|
||||||
@ -23,8 +17,7 @@ class Cost:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
buildings: [CityObject],
|
building: Building,
|
||||||
buildings_results: dict,
|
|
||||||
number_of_years=31,
|
number_of_years=31,
|
||||||
percentage_credit=0,
|
percentage_credit=0,
|
||||||
interest_rate=0.04,
|
interest_rate=0.04,
|
||||||
@ -35,9 +28,13 @@ class Cost:
|
|||||||
gas_price_index=0.05,
|
gas_price_index=0.05,
|
||||||
discount_rate=0.03,
|
discount_rate=0.03,
|
||||||
retrofitting_year_construction=2020,
|
retrofitting_year_construction=2020,
|
||||||
factories_handler='montreal_custom'):
|
factories_handler='montreal_custom',
|
||||||
self._buildings = buildings
|
retrofit_scenario=CURRENT_STATUS,
|
||||||
self._results = Results(buildings_results)
|
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,
|
self._configuration = Configuration(number_of_years,
|
||||||
percentage_credit,
|
percentage_credit,
|
||||||
interest_rate, credit_years,
|
interest_rate, credit_years,
|
||||||
@ -47,21 +44,27 @@ class Cost:
|
|||||||
gas_price_index,
|
gas_price_index,
|
||||||
discount_rate,
|
discount_rate,
|
||||||
retrofitting_year_construction,
|
retrofitting_year_construction,
|
||||||
factories_handler)
|
factories_handler,
|
||||||
self._global_capital_costs = None
|
retrofit_scenario,
|
||||||
self._global_capital_incomes = None
|
fuel_type,
|
||||||
self._global_end_of_life_costs = None
|
dictionary)
|
||||||
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):
|
@property
|
||||||
lcc = LifeCycleCosts(building, building_results, self._configuration)
|
def building(self) -> Building:
|
||||||
self._global_capital_costs, self._global_capital_incomes = lcc.calculate_capital_costs
|
"""
|
||||||
self._global_end_of_life_costs = lcc.calculate_end_of_life_costs
|
Get current building.
|
||||||
self._global_operational_costs = lcc.calculate_total_operational_costs
|
"""
|
||||||
self._global_maintenance_costs = lcc.calculate_total_maintenance_costs
|
return self._building
|
||||||
self._global_operational_incomes = lcc.calculate_total_operational_incomes
|
|
||||||
|
@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
|
@property
|
||||||
def life_cycle(self) -> pd.DataFrame:
|
def life_cycle(self) -> pd.DataFrame:
|
||||||
@ -70,93 +73,71 @@ class Cost:
|
|||||||
:return: DataFrame
|
:return: DataFrame
|
||||||
"""
|
"""
|
||||||
results = pd.DataFrame()
|
results = pd.DataFrame()
|
||||||
for building_index, building in enumerate(self._buildings):
|
global_capital_costs, global_capital_incomes = CapitalCosts(self._building, self._configuration).calculate()
|
||||||
self._life_cycle_costs(building, self._buildings_results[building_index])
|
global_end_of_life_costs = EndOfLifeCosts(self._building, self._configuration).calculate()
|
||||||
df_capital_costs_skin = (
|
global_operational_costs = TotalOperationalCosts(self._building, self._configuration).calculate()
|
||||||
self._global_capital_costs['B2010_opaque_walls'] +
|
global_maintenance_costs = TotalMaintenanceCosts(self._building, self._configuration).calculate()
|
||||||
self._global_capital_costs['B2020_transparent'] +
|
global_operational_incomes = TotalOperationalIncomes(self._building, self._configuration).calculate()
|
||||||
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,
|
df_capital_costs_skin = (
|
||||||
life_cycle_costs_capital_systems,
|
global_capital_costs['B2010_opaque_walls'] +
|
||||||
life_cycle_costs_end_of_life_costs,
|
global_capital_costs['B2020_transparent'] +
|
||||||
life_cycle_operational_costs,
|
global_capital_costs['B3010_opaque_roof'] +
|
||||||
life_cycle_maintenance_costs,
|
global_capital_costs['B10_superstructure']
|
||||||
life_cycle_operational_incomes,
|
)
|
||||||
life_cycle_capital_incomes]
|
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
|
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')
|
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
numpy_financial
|
|
||||||
cerc_hub
|
|
Loading…
Reference in New Issue
Block a user