Incorporation of outputs of all the variables in excel, and pandas dataframe data for yearly values in the cashflow (only capital and reposition, pending operational, end of life and maintenance)

This commit is contained in:
Oriol Gavalda 2023-05-01 16:38:45 -04:00
parent f9bb954be8
commit 512cd6b81e
2 changed files with 186 additions and 77 deletions

View File

@ -2,17 +2,19 @@
LifeCycleCosts 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
Project contributor 2023 Author Oriol Gavaldà Torrellas oriol.gavalda@concordia.ca
Project contributor © 2023 Author Oriol Gavaldà Torrellas oriol.gavalda@concordia.ca
"""
import math
import pandas as pd
import numpy as np
from datetime import date
import hub.helpers.constants as cte
class LifeCycleCosts:
def __init__(self, building, archetype, number_of_years, consumer_price_index, discount_rate,
retrofitting_scenario, heating_scop, cooling_seer, peak_electricity_demand, factor_pv):
retrofitting_scenario, heating_scop, cooling_seer, peak_electricity_demand, factor_pv,factor_peak_lights):
self._building = building
self._number_of_years = number_of_years
self._consumer_price_index = consumer_price_index
@ -33,6 +35,16 @@ class LifeCycleCosts:
self._cooling_seer = cooling_seer
self._peak_electricity_demand = peak_electricity_demand
self._factor_pv = factor_pv
self._peak_lights = factor_peak_lights
#todo: revise if it works
rng = range(40)
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',
'D_services'], dtype='float')
self._yearly_capital_costs.replace(np.nan,0)
def calculate_capital_costs(self):
building = self._building
@ -45,6 +57,7 @@ class LifeCycleCosts:
surface_ground = 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:
@ -55,15 +68,14 @@ class LifeCycleCosts:
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
print(f'total floor area {total_floor_area}')
chapters = archetype.capital_cost
capital_cost_skin = 0
capital_cost_services = 0
reposition_cost_pv = 0
peak_heating = building.heating_peak_load[cte.YEAR]['insel'][0]
peak_cooling = building.cooling_peak_load[cte.YEAR]['insel'][0]
peak_heating = 0.1*self._total_floor_area
peak_cooling = 0.1*self._total_floor_area
if self._retrofitting_scenario == 1 or self._retrofitting_scenario == 3:
chapter = chapters.chapter('B_shell')
@ -72,33 +84,39 @@ class LifeCycleCosts:
capital_cost_roof = surface_roof * chapter.item('B3010_opaque_roof').refurbishment[0]
capital_cost_ground = surface_ground * chapter.item('B10_superstructure').refurbishment[0]
capital_cost_skin = capital_cost_opaque+capital_cost_transparent+capital_cost_roof+capital_cost_ground
print(f'capital cost skin {capital_cost_skin}')
self._yearly_capital_costs.loc[0]['B2010_opaque_walls'],self._yearly_capital_costs.loc[0]['B2020_transparent'], \
self._yearly_capital_costs.loc[0]['B3010_opaque_roof'],self._yearly_capital_costs.loc[0]['B10_superstructure'],\
self._yearly_capital_costs.loc[0]['B_Shell']\
=[capital_cost_opaque , capital_cost_transparent , capital_cost_roof , capital_cost_ground , capital_cost_skin]
if self._retrofitting_scenario == 2 or self._retrofitting_scenario == 3:
chapter = chapters.chapter('D_services')
capital_cost_pv = surface_roof * factor_pv * chapter.item('D301010_photovoltaic_system').initial_investment[0]
self._yearly_capital_costs.loc[0]['D301010_photovoltaic_system']=capital_cost_pv
for year in range(1, self._number_of_years + 1):
costs_increase = math.pow(1 + self._consumer_price_index, year) / math.pow(1 + self._discount_rate, year)
if (year % chapter.item('D301010_photovoltaic_system').lifetime) == 0:
reposition_cost_pv += surface_roof * factor_pv * chapter.item('D301010_photovoltaic_system').reposition[
0] * costs_increase
self._yearly_capital_costs.loc[year]['D301010_photovoltaic_system'] = surface_roof * \
factor_pv * chapter.item('D301010_photovoltaic_system').reposition[0] * costs_increase
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 * factor_pv \
capital_cost_lighting = total_floor_area * self._peak_lights \
* chapter.item('D5020_lighting_and_branch_wiring').initial_investment[0]
capital_cost_services = capital_cost_pv + capital_cost_heating_equipment + capital_cost_cooling_equipment\
+ capital_cost_distribution_equipment + capital_cost_other_hvac_ahu \
+ capital_cost_lighting
self._yearly_capital_costs.loc[0]['D3020_heat_generating_systems'], self._yearly_capital_costs.loc[0]['D3030_cooling_generation_systems'], \
self._yearly_capital_costs.loc[0]['D3040_distribution_systems'], self._yearly_capital_costs.loc[0]['D3080_other_hvac_ahu'], \
self._yearly_capital_costs.loc[0]['D5020_lighting_and_branch_wiring'], self._yearly_capital_costs.loc[0]['D_services'] \
= [capital_cost_heating_equipment, capital_cost_cooling_equipment, capital_cost_distribution_equipment,
capital_cost_other_hvac_ahu, capital_cost_lighting, capital_cost_services]
reposition_cost_heating_equipment = 0
reposition_cost_cooling_equipment = 0
@ -111,16 +129,19 @@ class LifeCycleCosts:
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
capital_cost_subtotal = capital_cost_skin + capital_cost_services
capital_cost_total = capital_cost_subtotal * (1+chapters.design_allowance) * (1+chapters.overhead_and_profit)
@ -132,6 +153,7 @@ class LifeCycleCosts:
reposition_cost_total = reposition_cost_subtotal * (1+chapters.design_allowance) * (1+chapters.overhead_and_profit)
life_cycle_cost_capital_total = capital_cost_total + reposition_cost_total
self._yearly_capital_costs.fillna(0,inplace=True)
return life_cycle_cost_capital_total
@ -157,14 +179,16 @@ class LifeCycleCosts:
variable_cost = 0
total_floor_area = self._total_floor_area
electricity_heating = building.heating[cte.YEAR]['insel'][0] / self._heating_scop
electricity_cooling = building.cooling[cte.YEAR]['insel'][0] / self._cooling_seer
electricity_lighting = building.lighting_electrical_demand[cte.YEAR]['insel'][0]
domestic_hot_water_demand = building.domestic_hot_water_heat_demand[cte.YEAR]['insel'][0]
electricity_plug_loads = building.appliances_electrical_demand[cte.YEAR]['insel'][0]
total_electricity_consumption = electricity_cooling + electricity_heating + electricity_lighting \
electricity_heating = building.heating[cte.YEAR]['insel meb'] / (self._heating_scop*1000)
electricity_cooling = building.cooling[cte.YEAR]['insel meb'] / (self._cooling_seer*1000)
electricity_lighting = building.lighting_electrical_demand['month']['insel meb'].sum()/1000
domestic_hot_water_demand = building.domestic_hot_water_heat_demand['month']['insel meb'].sum()/1000
electricity_plug_loads = building.appliances_electrical_demand['month']['insel meb'].sum()/1000
total_electricity_consumption = electricity_cooling[0] + electricity_heating[0] + electricity_lighting \
+ domestic_hot_water_demand + electricity_plug_loads
print(f'total electricity consumption: {total_electricity_consumption}')
peak_electricity_demand = self._peak_electricity_demand
operational_cost_year_0 = total_electricity_consumption * archetype.operational_cost.fuels[0].variable[0]
@ -189,14 +213,12 @@ class LifeCycleCosts:
building = self._building
archetype = self._archetype
factor_pv = self._factor_pv
surface_roof = 0
maintenance_pv = 0
maintenance_heating = 0
maintenance_cooling = 0
peak_heating = building.heating_peak_load[cte.YEAR]['insel'][0]
peak_cooling = building.cooling_peak_load[cte.YEAR]['insel'][0]
peak_heating = 0.1 * self._total_floor_area
peak_cooling = 0.1 * self._total_floor_area
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:

147
main.py
View File

@ -8,13 +8,19 @@ import glob
import os
from pathlib import Path
import sys
import pandas as pd
from hub.imports.construction_factory import ConstructionFactory
from hub.helpers.dictionaries import Dictionaries
from hub.hub_logger import logger
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 life_cycle_costs import LifeCycleCosts
@ -26,42 +32,78 @@ def _search_archetype(costs_catalog, building_function):
return building_archetype
raise KeyError('archetype not found')
file_path = (Path(__file__).parent.parent/'costs_workflow'/'input_files'/'selected_building_2864.geojson')
file_path2 = (Path(__file__).parent.parent/'costs_workflow'/'input_files'/'selected_building_2864_2.geojson')
climate_reference_city = 'Montreal'
weather_file = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw'
weather_format = 'epw'
construction_format = 'nrcan'
usage_format = 'nrcan'
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 = 30
consumer_price_index = 0.04
discount_rate = 0.03
peak_electricity_demand = 33
factor_pv = 0.5
factor_peak_lights = 0.07
retrofitting_scenarios = [0, 1, 2, 3]
life_cycle_results = pd.DataFrame()
for retrofitting_scenario in retrofitting_scenarios:
if retrofitting_scenario == 2 or retrofitting_scenario==3:
heating_scop = 3
cooling_seer = 4.5
else:
heating_scop = 1
cooling_seer = 2.8
if retrofitting_scenario == 0 or retrofitting_scenario == 2:
print('[simulation start]')
city = GeometryFactory('geojson',
path=file_path,
height_field='heightmax',
year_of_construction_field='ANNEE_CONS',
name_field='OBJECTID_12',
year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
print(f'city created from {file_path}')
ConstructionFactory('nrcan', city).enrich()
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')
catalog = CostCatalogFactory('montreal_custom').catalog
print('costs catalog access... done')
number_of_years = 30
consumer_price_index = 0.04
discount_rate = 0.03
# sra + monthly running
print('exporting:')
sra_file = (tmp_folder / f'{city.name}_sra.xml').resolve()
SraEngine(city, sra_file, tmp_folder, weather_file)
# Assign radiation to the city
print(' sra processed...')
for building in city.buildings:
building.heating[cte.YEAR]['insel'] = [23]
building.cooling[cte.YEAR]['insel'] = [13]
building.lighting_electrical_demand[cte.YEAR]['insel'] = [58]
building.appliances_electrical_demand[cte.YEAR]['insel'] = [32]
building.domestic_hot_water_heat_demand[cte.YEAR]['insel'] = [22]
building.attic_heated = attic_heated_case
building.basement_heated = basement_heated_case
peak_electricity_demand = 33
factor_pv = 0.5
retrofitting_scenarios = [0, 1, 2, 3]
MonthlyEnergyBalanceEngine(city, tmp_folder)
for building in city.buildings:
try:
@ -73,25 +115,70 @@ for building in city.buildings:
sys.stderr.write(f'Building {building.name} has unknown costs archetype for building function: '
f'{building.function}\n')
continue
for retrofitting_scenario in retrofitting_scenarios:
if retrofitting_scenario == 2 or retrofitting_scenario == 3:
heating_scop = 3
cooling_seer = 4.5
else:
heating_scop = 1
cooling_seer = 2
lcc = LifeCycleCosts(building, archetype, number_of_years, consumer_price_index,
discount_rate, retrofitting_scenario, heating_scop, cooling_seer,
peak_electricity_demand, factor_pv)
peak_electricity_demand, factor_pv,factor_peak_lights)
else:
print('[simulation start]')
city = GeometryFactory('geojson',
path=file_path2,
height_field='heightmax',
name_field='OBJECTID_12',
year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
print(f'city created from {file_path}')
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')
catalog = CostCatalogFactory('montreal_custom').catalog
print('costs catalog access... done')
# sra + monthly running
print('exporting:')
sra_file = (tmp_folder / f'{city.name}_sra.xml').resolve()
SraEngine(city, sra_file, tmp_folder, weather_file)
# Assign radiation to the city
print(' sra processed...')
for building in city.buildings:
building.attic_heated = attic_heated_case
building.basement_heated = basement_heated_case
MonthlyEnergyBalanceEngine(city, tmp_folder)
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
lcc = LifeCycleCosts(building, archetype, number_of_years, consumer_price_index,
discount_rate, retrofitting_scenario, heating_scop, cooling_seer,
peak_electricity_demand, factor_pv,factor_peak_lights)
total_capital_costs = lcc.calculate_capital_costs()
print(f'total capital costs scenario {retrofitting_scenario} are {total_capital_costs}')
end_of_life_costs = lcc.calculate_end_of_life_costs()
print(f'end_of_life_costs scenario {retrofitting_scenario} are {end_of_life_costs}')
total_operational_costs = lcc.calculate_total_operational_costs()
print(f'total_operational_costs scenario {retrofitting_scenario} are {total_operational_costs}')
total_maintenance_costs = lcc.calculate_total_maintenance_costs()
print(f'total_maintenance_costs scenario {retrofitting_scenario} are {total_maintenance_costs}')
life_cycle_costs = total_capital_costs + end_of_life_costs + total_operational_costs + total_maintenance_costs
print(f'life_cycle_costs scenario {retrofitting_scenario} are {life_cycle_costs}')
life_cycle_results[f'Scenario {retrofitting_scenario}'] = [total_capital_costs, end_of_life_costs,
total_operational_costs, total_maintenance_costs,
life_cycle_costs]
life_cycle_results.index = ['total_capital_costs','end_of_life_costs', 'total_operational_costs',
'total_maintenance_costs','life_cycle_costs']
life_cycle_results.to_excel(Path(__file__).parent/'out_files'/'Results.xlsx', index=True)