From 483c24b19ee400aefdda929c9ecbf14b876885d0 Mon Sep 17 00:00:00 2001 From: p_monsalvete Date: Tue, 25 Apr 2023 09:22:44 -0400 Subject: [PATCH 1/2] Oriol changes. Not working, trying to understand the logic of the workflow --- life_cycle_costs.py | 78 ++++++++++++++++++++++++++++++++++----------- main.py | 58 ++++++++++++++++++++++++--------- 2 files changed, 102 insertions(+), 34 deletions(-) diff --git a/life_cycle_costs.py b/life_cycle_costs.py index fd3af0a..3d93e1e 100644 --- a/life_cycle_costs.py +++ b/life_cycle_costs.py @@ -2,36 +2,68 @@ 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 """ import math +import hub.catalog_factories.costs_catalog_factory as CostCatalogFactory +from hub.catalog_factories.cost.montreal_custom_catalog import MontrealCustomCatalog +from hub.helpers.dictionaries import Dictionaries class LifeCycleCosts: # todo: this should be (city, costs_catalog) or similar - def __init__(self, building, number_of_years, consumer_price_index, discount_rate, end_of_life_cost, - capital_costs_at_year_0, items, fuels, concepts): - self._building = building + def __init__(self, city, number_of_years, consumer_price_index, discount_rate, + retrofitting_scenario): + self._city = city self._number_of_years = number_of_years self._consumer_price_index = consumer_price_index self._discount_rate = discount_rate - - self._end_of_life_cost = end_of_life_cost - - self._capital_costs_at_year_0 = capital_costs_at_year_0 - self._items = items - - self._fuels = fuels - - self._concepts = concepts + self._cost_catalog=CostCatalogFactory('montreal_custom').catalog + self._end_of_life_cost = 0 + self._capital_costs_at_year_0 = 0 + self._items = 0 + self._fuels = 0 + self._concepts = 0 + self._retrofitting_scenario = retrofitting_scenario def calculate_capital_costs(self): - total_capital_costs = self._capital_costs_at_year_0 - 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) - for item in self._items: - total_capital_costs += item.reposition_costs[year] * costs_increase - return total_capital_costs + 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}') + +'''total_capital_costs = self._capital_costs_at_year_0 + #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) + # for item in self._items: + # total_capital_costs += item.reposition_costs[year] * costs_increase + #return total_capital_costs def calculate_end_of_life_costs(self): price_increase = 0 @@ -53,4 +85,12 @@ class LifeCycleCosts: costs_increase = math.pow(1 + self._consumer_price_index, year) / math.pow(1 + self._discount_rate, year) for concept in self._concepts: total_maintenance_costs += concept.mantainance_costs * costs_increase - return total_maintenance_costs + 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 070aa0e..c81d343 100644 --- a/main.py +++ b/main.py @@ -4,28 +4,56 @@ 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 +import sys from pathlib import Path -from imports.geometry_factory import GeometryFactory +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 -gml_file = 'city.gml' -file = Path(gml_file).resolve() -city = GeometryFactory('gml', file).city +file_path = (Path(__file__).parent.parent / 'costs_workflow' / 'input_files' / 'Citylayers_neighbours.geojson') +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) +print('[simulation start]') +city = GeometryFactory('geojson', + path=file_path, + height_field='heightmax', + year_of_construction_field='ANNEE_CONS', + name_field='OBJECTID_12', + 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() +print('enrich constructions... done') number_of_years = 40 consumer_price_index = 0.1 +discount_rate=0.06 +retrofitting_scenario = 1 -for building in city.buildings: - lcc = LifeCycleCosts(building, number_of_years, consumer_price_index, costs_catalog) - 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 +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 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}') +# 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}') From 4f019160851bc8cb739967f078710c3706bc4492 Mon Sep 17 00:00:00 2001 From: p_monsalvete Date: Tue, 25 Apr 2023 11:49:17 -0400 Subject: [PATCH 2/2] solved capital costs for opaque and transparent calculation --- life_cycle_costs.py | 85 ++++++++++++++++++++++----------------------- main.py | 31 ++++++----------- 2 files changed, 52 insertions(+), 64 deletions(-) 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}')