diff --git a/life_cycle_costs.py b/life_cycle_costs.py index 3d93e1e..cd259f4 100644 --- a/life_cycle_costs.py +++ b/life_cycle_costs.py @@ -4,22 +4,21 @@ 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 """ -import math -import hub.catalog_factories.costs_catalog_factory as CostCatalogFactory -from hub.catalog_factories.cost.montreal_custom_catalog import MontrealCustomCatalog +import sys +from hub.hub_logger import logger from hub.helpers.dictionaries import Dictionaries class LifeCycleCosts: # todo: this should be (city, costs_catalog) or similar - def __init__(self, city, number_of_years, consumer_price_index, discount_rate, + def __init__(self, building, catalog, number_of_years, consumer_price_index, discount_rate, retrofitting_scenario): - self._city = city + self._building = building self._number_of_years = number_of_years self._consumer_price_index = consumer_price_index self._discount_rate = discount_rate - self._cost_catalog=CostCatalogFactory('montreal_custom').catalog + self._cost_catalog = catalog self._end_of_life_cost = 0 self._capital_costs_at_year_0 = 0 self._items = 0 @@ -28,35 +27,43 @@ class LifeCycleCosts: self._retrofitting_scenario = retrofitting_scenario def calculate_capital_costs(self): - surface_opaque=0 - surface_transparent=0 - city = self._city - for building in city.buildings: - try: - function = 'residential' #Dictionaries().hub_function_to_nrel_construction_function[building.function] - archetype = self._search_archetype(self._cost_catalog, function) - except KeyError: - logger.error(f'Building {building.name} has unknown construction archetype for building function: ' - f'{building.function} and building year of construction: {building.year_of_construction} ' - f'and climate zone reference norm {self._climate_zone}\n') - sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: ' - f'{building.function} and building year of construction: {building.year_of_construction} ' - f'and climate zone reference norm {self._climate_zone}\n') - # if building has no thermal zones defined from geometry, and the building will be divided in storeys, - # one thermal zone per storey is assigned - for internal_zone in building.internal_zones: - if internal_zone.thermal_zones is None: - continue - for thermal_zone in internal_zone.thermal_zones: - for thermal_boundary in thermal_zone.thermal_boundaries: - surface_opaque += thermal_boundary.opaque_area*(1-thermal_boundary.window_ratio) - surface_transparent += thermal_boundary.opaque_area*(thermal_boundary.window_ratio) - print(f'surface_opaque {surface_opaque}') - print(f'surface_transparent {surface_transparent}') - capital_cost_op = surface_opaque*self._cost_catalog.archetypes.archetype[0].capital_cost.general_chapters[0].items[1].refurbishment[0] - capital_cost_transp= surface_transparent*self._cost_catalog.archetypes.archetype[0].capital_cost.general_chapters[0].items[2].refurbishment[0] - print(f'cost_opaque {capital_cost_op}') - print(f'cost_transparent {capital_cost_transp}') + building = self._building + surface_opaque = 0 + surface_transparent = 0 + try: + function = Dictionaries().hub_function_to_montreal_custom_costs_function[building.function] + archetype = self._search_archetype(self._cost_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') + return + + for internal_zone in building.internal_zones: + for thermal_zone in internal_zone.thermal_zones: + for thermal_boundary in thermal_zone.thermal_boundaries: + surface_opaque += thermal_boundary.opaque_area * (1-thermal_boundary.window_ratio) + surface_transparent += thermal_boundary.opaque_area * thermal_boundary.window_ratio + + chapters = archetype.capital_cost.general_chapters + + if self._retrofitting_scenario == 1 or self._retrofitting_scenario == 3: + chapter = chapters.chapter('B_shell') + capital_cost_opaque = surface_opaque * chapter.item('B2010_opaque_walls').refurbishment[0] + capital_cost_transparent = surface_transparent * chapter.item('B2020_transparent').refurbishment[0] + + print(f'cost_opaque {capital_cost_opaque}') + print(f'cost_transparent {capital_cost_transparent}') + + @staticmethod + def _search_archetype(costs_catalog, function): + costs_archetypes = costs_catalog.entries('archetypes').archetypes + for building_archetype in costs_archetypes: + if str(function) == str(building_archetype.function): + return building_archetype + raise KeyError('archetype not found') + '''total_capital_costs = self._capital_costs_at_year_0 #for year in range(1, self._number_of_years + 1): @@ -86,11 +93,3 @@ class LifeCycleCosts: for concept in self._concepts: total_maintenance_costs += concept.mantainance_costs * costs_increase return total_maintenance_costs''' - - @staticmethod - def _search_archetype(costs_catalog, function): - costs_archetypes = costs_catalog.entries('archetypes') - for building_archetype in costs_archetypes: - if (str(function) == str(building_archetype.function)): - return building_archetype - raise KeyError('archetype not found') diff --git a/main.py b/main.py index c81d343..b0a94d9 100644 --- a/main.py +++ b/main.py @@ -6,20 +6,13 @@ Copyright © 2022 Project Author Pilar Monsalvete Álvarez de Uribarri pilar.mon import glob import os -import sys -from pathlib import Path -import csv from hub.imports.construction_factory import ConstructionFactory -from hub.imports.usage_factory import UsageFactory -from hub.exports.exports_factory import ExportsFactory -from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory from hub.helpers.dictionaries import Dictionaries from pathlib import Path from hub.imports.geometry_factory import GeometryFactory from life_cycle_costs import LifeCycleCosts -import hub.catalog_factories.costs_catalog_factory as CostCatalogFactory -from hub.catalog_factories.cost.montreal_custom_catalog import MontrealCustomCatalog +from hub.catalog_factories.costs_catalog_factory import CostCatalogFactory file_path = (Path(__file__).parent.parent / 'costs_workflow' / 'input_files' / 'Citylayers_neighbours.geojson') out_path = (Path(__file__).parent.parent / 'costs_workflow' / 'out_files') @@ -41,19 +34,15 @@ ConstructionFactory('nrcan', city).enrich() print('enrich constructions... done') number_of_years = 40 consumer_price_index = 0.1 -discount_rate=0.06 +discount_rate = 0.06 retrofitting_scenario = 1 +catalog = CostCatalogFactory('montreal_custom').catalog -lcc = LifeCycleCosts(city, number_of_years, consumer_price_index, discount_rate, retrofitting_scenario) -total_capital_costs = lcc.calculate_capital_costs() -# end_of_life_costs = lcc.calculate_end_of_life_costs() -# total_operational_costs = lcc.calculate_total_operational_costs() -# total_maintenance_costs = lcc.calculate_total_maintenance_costs() -# life_cycle_costs = total_capital_costs + end_of_life_costs + total_operational_costs + total_maintenance_costs +for building in city.buildings: + lcc = LifeCycleCosts(building, catalog, number_of_years, consumer_price_index, discount_rate, retrofitting_scenario) + total_capital_costs = lcc.calculate_capital_costs() + # end_of_life_costs = lcc.calculate_end_of_life_costs() + # total_operational_costs = lcc.calculate_total_operational_costs() + # total_maintenance_costs = lcc.calculate_total_maintenance_costs() + # life_cycle_costs = total_capital_costs + end_of_life_costs + total_operational_costs + total_maintenance_costs - print(f'Building name: {building.name}') - print(f'Capital costs: {total_capital_costs}') -# print(f'End of life costs: {end_of_life_costs}') -# print(f'Operational costs: {total_operational_costs}') -# print(f'Maintenance costs: {total_maintenance_costs}') -# print(f'Life cycle costs: {life_cycle_costs}')