costs_workflow/costs/__main__.py

197 lines
9.4 KiB
Python
Raw Normal View History

"""
Costs Workflow
SPDX - License - Identifier: LGPL - 3.0 - or -later
2023-05-30 15:08:11 -04:00
Copyright © 2022 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributor Oriol Gavalda Torrellas oriol.gavalda@concordia.ca
"""
from pathlib import Path
2023-05-30 14:42:49 -04:00
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
2023-05-30 14:42:49 -04:00
from hub.imports.construction_factory import ConstructionFactory
from hub.imports.energy_systems_factory import EnergySystemsFactory
from hub.imports.geometry_factory import GeometryFactory
from hub.imports.usage_factory import UsageFactory
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
# import constants
from costs import CLIMATE_REFERENCE_CITY, WEATHER_FILE, WEATHER_FORMAT, CONSTRUCTION_FORMAT, USAGE_FORMAT
from costs import ENERGY_SYSTEM_FORMAT, ATTIC_HEATED_CASE, BASEMENT_HEATED_CASE, RETROFITTING_SCENARIOS, NUMBER_OF_YEARS
from costs import CONSUMER_PRICE_INDEX, ELECTRICITY_PEAK_INDEX, ELECTRICITY_PRICE_INDEX, GAS_PRICE_INDEX, DISCOUNT_RATE
from costs import SKIN_RETROFIT, SYSTEM_RETROFIT_AND_PV, SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV
from costs import RETROFITTING_YEAR_CONSTRUCTION
# import paths
from costs import file_path, tmp_folder, out_path
2023-05-30 14:42:49 -04:00
def _npv_from_list(npv_discount_rate, list_cashflow):
lcc_value = npf.npv(npv_discount_rate, list_cashflow)
return lcc_value
2023-05-30 15:08:11 -04:00
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')
2023-05-30 15:08:11 -04:00
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):
2023-05-30 15:08:11 -04:00
for building in city.buildings:
2023-05-31 12:39:22 -04:00
building.year_of_construction = RETROFITTING_YEAR_CONSTRUCTION
ConstructionFactory(CONSTRUCTION_FORMAT, city).enrich()
2023-05-30 15:08:11 -04:00
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:
2023-05-30 15:08:11 -04:00
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)
2023-05-31 12:26:01 -04:00
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')
2023-05-31 12:26:01 -04:00
global_capital_incomes.to_excel(writer, sheet_name='global_capital_incomes')
2023-05-30 15:08:11 -04:00
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']
2023-05-30 15:08:11 -04:00
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']
)
2023-05-31 12:26:01 -04:00
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())
2023-05-30 15:08:11 -04:00
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 -
2023-05-31 12:26:01 -04:00
life_cycle_operational_incomes -
life_cycle_capital_incomes
2023-05-30 15:08:11 -04:00
)
life_cycle_results[f'Scenario {retrofitting_scenario}'] = [life_cycle_costs_capital_skin,
2023-05-30 15:08:11 -04:00
life_cycle_costs_capital_systems,
life_cycle_costs_end_of_life_costs,
life_cycle_operational_costs,
life_cycle_maintenance_costs,
2023-05-31 12:26:01 -04:00
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}')