costs_workflow/main.py

186 lines
8.9 KiB
Python
Raw Normal View History

"""
Costs Workflow
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import glob
import os
from pathlib import Path
import sys
import pandas as pd
import numpy_financial as npf
from hub.imports.construction_factory import ConstructionFactory
from hub.helpers.dictionaries import Dictionaries
from hub.imports.geometry_factory import GeometryFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory
from hub.catalog_factories.costs_catalog_factory import CostCatalogFactory
import hub.helpers.constants as cte
from monthly_energy_balance_engine import MonthlyEnergyBalanceEngine
from sra_engine import SraEngine
from hub.imports.energy_systems_factory import EnergySystemsFactory
from energy_systems_sizing import EnergySystemsSizing
from life_cycle_costs import LifeCycleCosts
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')
file_path = (Path(__file__).parent.parent/'costs_workflow'/'input_files'/'selected_building_2864.geojson')
climate_reference_city = 'Montreal'
weather_file = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw'
weather_format = 'epw'
construction_format = 'nrcan'
usage_format = 'comnet'
energy_systems_format = 'montreal_custom'
attic_heated_case = 0
basement_heated_case = 1
tmp_folder = (Path(__file__).parent.parent/'monthly_energy_balance_workflow'/'tmp')
out_path = (Path(__file__).parent.parent / 'costs_workflow' / 'out_files')
files = glob.glob(f'{out_path}/*')
for file in files:
if file != '.gitignore':
os.remove(file)
number_of_years = 31
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_of_construction =2020
retrofitting_scenarios = [0, 1, 2, 3]
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_systems_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 == 1 or retrofitting_scenario == 3:
for building in city.buildings:
building.year_of_construction=2020
ConstructionFactory(construction_format, city).enrich()
print('enrich retrofitted constructions... done')
if retrofitting_scenario == 2 or retrofitting_scenario == 3:
for building in city.buildings:
building.energy_systems_archetype_name = 'system 6 electricity pv'
EnergySystemsFactory(energy_systems_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:
#try:
function = Dictionaries().hub_function_to_montreal_custom_costs_function[building.function]
archetype = _search_archetype(catalog, function)
#except KeyError:
# logger.error(f'Building {building.name} has unknown costs archetype for building function: '
# f'{building.function}\n')
# sys.stderr.write(f'Building {building.name} has unknown costs archetype for building function: '
# f'{building.function}\n')
#continue
print('lcc for first building started')
lcc = LifeCycleCosts(building, archetype, number_of_years, consumer_price_index, electricity_peak_index,
electricity_price_index, gas_price_index, discount_rate, retrofitting_scenario)
global_capital_costs = 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()
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']
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_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_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_results.index = [f'total_capital_costs_skin',
f'total_capital_costs_systems', f'end_of_life_costs',
f'total_operational_costs', f'total_maintenance_costs',
f'operational_incomes']
print(life_cycle_results)
#todo: change if there is more than 1 building
life_cycle_results.to_excel(Path(__file__).parent/'out_files'/f'Results.xlsx', index=True)