lca_carbon_workflow/lca_carbon_workflow.py

207 lines
8.8 KiB
Python
Raw Normal View History

2024-07-15 15:06:44 -04:00
"""
2024-07-16 16:29:33 -04:00
lca_carbon_workflow module
2024-07-15 15:06:44 -04:00
Returns the summarize of envelope and energy systems
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2024 Concordia CERC group
2024-08-13 13:13:10 -04:00
Project developers: Alireza Adli alireza.adli@concordia.ca
2024-07-15 15:06:44 -04:00
Mohammad Reza Seyedabadi mohammad.seyedabadi@mail.concordia.ca
"""
from pathlib import Path
2024-10-09 15:59:38 -04:00
from input_geojson_content import InputGeoJsonContent
2024-07-15 15:06:44 -04:00
from hub.imports.geometry_factory import GeometryFactory
from hub.imports.construction_factory import ConstructionFactory
from hub.helpers.dictionaries import Dictionaries
2024-08-05 16:55:11 -04:00
from city_model_structure.life_cycle_assessment.access_nrcan_catalogue \
import AccessNrcanCatalog
from city_model_structure.life_cycle_assessment.opening_emission \
import OpeningEmission
2024-07-20 12:17:56 -04:00
from city_model_structure.life_cycle_assessment.envelope_emission \
import EnvelopeEmission
from city_model_structure.life_cycle_assessment.lca_end_of_life_carbon \
import EndOfLifeEmission
2024-07-15 15:06:44 -04:00
class LCACarbonWorkflow:
def __init__(
self,
city_path,
archetypes_catalog_file_name,
constructions_catalog_file,
catalog='nrcan',
building_parameters=('height', 'year_of_construction', 'function')):
2024-10-14 11:04:57 -04:00
"""
LCACarbonWorkflow takes a number of buildings and enrich the city object
using cerc-hub GeometryFactory and ConstructionFactory. Then it
calculates embodied and end of life carbon emission of each building.
It puts out the results of opening and envelop emission for each
mentioned cycle separately.
:param city_path: Either a path to the buildings (GeoJson)
file or the content of such a file.
:param archetypes_catalog_file_name: Path to the buildings'
archetypes (JSON).
:param constructions_catalog_file: Path to the construction materials
data.
:param catalog: Type of the catalog (in this case 'nrcan', the default
argument)
:param building_parameters: Parameters used for using the catalog (in
this case three default arguments)
"""
self.file_path = Path(__file__).parent / 'input_files' / InputGeoJsonContent(
city_path).content
2024-10-09 15:59:38 -04:00
self.catalogs_path = Path(__file__).parent / 'input_files'
self.archetypes_catalog_file_name = archetypes_catalog_file_name
self.constructions_catalog_file = constructions_catalog_file
self.nrcan_catalogs = AccessNrcanCatalog(
self.catalogs_path,
archetypes=self.archetypes_catalog_file_name,
constructions=self.constructions_catalog_file)
self.out_path = (Path(__file__).parent / 'out_files')
self.handler = catalog
self.height, self.year_of_construction, self.function = \
building_parameters
2024-07-15 15:06:44 -04:00
print('[simulation start]')
self.city = GeometryFactory(
'geojson',
path=self.file_path,
height_field=self.height,
year_of_construction_field=self.year_of_construction,
function_field=self.function,
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
print(f'city created from {self.file_path}')
ConstructionFactory(self.handler, self.city).enrich()
2024-07-15 15:06:44 -04:00
2024-07-21 10:35:42 -04:00
self.building_envelope_emission = []
self.building_opening_emission = []
self.building_component_emission = []
self.building_envelope_end_of_life_emission = []
self.building_opening_end_of_life_emission = []
self.building_component_end_of_life_emission = []
2024-07-21 10:35:42 -04:00
2024-07-20 10:39:33 -04:00
def calculate_building_component_emission(self, building):
surface_envelope_emission = []
surface_opening_emission = []
surface_envelope_end_of_life_emission = []
surface_opening_end_of_life_emission = []
opaque_surface_code = self.nrcan_catalogs.find_opaque_surface(
self.nrcan_catalogs.hub_to_nrcan_function(building.function),
self.nrcan_catalogs.year_to_period_of_construction(
building.year_of_construction),
'6')
2024-07-16 16:29:33 -04:00
for surface in building.surfaces:
boundary_envelope_emission = []
boundary_opening_emission = []
boundary_envelope_end_of_life_emission = []
boundary_opening_end_of_life_emission = []
2024-07-29 14:09:33 -04:00
2024-07-17 14:35:00 -04:00
for boundary in surface.associated_thermal_boundaries:
opening_emission = None
opening_end_of_life_emission = None
layer_emission, layer_end_of_life_emission = \
2024-07-31 15:26:12 -04:00
self._calculate_envelope_emission(boundary)
boundary_envelope_emission += layer_emission
boundary_envelope_end_of_life_emission += layer_end_of_life_emission
2024-07-20 12:17:56 -04:00
if boundary.window_ratio:
opening_emission, opening_end_of_life_emission = \
2024-07-31 15:26:12 -04:00
self._calculate_opening_emission(
building, surface, boundary, opaque_surface_code)
2024-07-19 14:08:32 -04:00
if opening_emission:
boundary_opening_emission += opening_emission
boundary_opening_end_of_life_emission += opening_end_of_life_emission
2024-07-19 14:08:32 -04:00
if boundary_opening_emission:
surface_opening_emission += boundary_opening_emission
surface_opening_end_of_life_emission += \
boundary_opening_end_of_life_emission
surface_envelope_emission += boundary_envelope_emission
surface_envelope_end_of_life_emission += \
boundary_envelope_end_of_life_emission
building_envelope_emission = sum(surface_envelope_emission)
building_envelope_workload = sum(surface_envelope_end_of_life_emission)
building_opening_emission = sum(surface_opening_emission)
building_opening_workload = sum(surface_opening_end_of_life_emission)
building_component_emission = \
2024-07-21 10:35:42 -04:00
building_envelope_emission + building_opening_emission
2024-07-31 15:54:02 -04:00
building_component_workload = \
building_envelope_workload + building_opening_workload
2024-07-21 10:35:42 -04:00
return building_envelope_emission, building_opening_emission, \
2024-07-31 15:54:02 -04:00
building_component_emission, building_envelope_workload, \
building_opening_workload, building_component_workload
def _calculate_envelope_emission(self, boundary):
layer_emission = []
layer_end_of_life_emission = []
for layer in boundary.layers:
if not layer.no_mass:
2024-07-31 15:08:02 -04:00
layer_material = \
2024-10-13 12:36:43 -04:00
self.nrcan_catalogs.search_material(layer.material_name)
layer_emission.append(EnvelopeEmission(
2024-07-31 15:08:02 -04:00
layer_material['embodied_carbon'],
boundary.opaque_area,
layer.thickness, layer.density).calculate_envelope_emission())
boundary_workload = \
boundary.opaque_area * \
layer.thickness * \
layer.density
layer_end_of_life_emission.append(EndOfLifeEmission(
layer_material['recycling_ratio'],
layer_material['onsite_recycling_ratio'],
layer_material['company_recycling_ratio'],
layer_material['landfilling_ratio'],
boundary_workload).calculate_end_of_life_emission())
return layer_emission, layer_end_of_life_emission
2024-07-20 10:39:33 -04:00
def _calculate_opening_emission(
2024-07-31 15:26:12 -04:00
self,
building, surface, boundary, opaque_surface_code,
density=2579):
"""Windows have the assumed density of 2579 kg/m3
Window's thickness assumed the same as wall's thickness
These two values are being used to calculate window's workload
for End of Life emission evaluation."""
2024-07-20 10:39:33 -04:00
opening_emission = []
opening_end_of_life_emission = []
2024-07-20 10:39:33 -04:00
for opening in boundary.thermal_openings:
transparent_surface_type = 'Window'
if building.year_of_construction >= 2020 and \
surface.type == 'Roof':
transparent_surface_type = 'Skylight'
opening_material = self.nrcan_catalogs.search_transparent_surfaces(
transparent_surface_type, opaque_surface_code)
opening_emission.append(
OpeningEmission(opening_material['embodied_carbon'],
opening.area).calculate_opening_emission())
window_workload = opening.area * boundary.thickness * density
opening_end_of_life_emission.append(EndOfLifeEmission(
opening_material['recycling_ratio'],
opening_material['onsite_recycling_ratio'],
opening_material['company_recycling_ratio'],
opening_material['landfilling_ratio'],
window_workload).calculate_end_of_life_emission())
return opening_emission, opening_end_of_life_emission
2024-07-16 16:29:33 -04:00
2024-07-16 16:45:43 -04:00
def calculate_emission(self):
2024-07-17 14:35:00 -04:00
for building in self.city.buildings:
2024-07-31 15:54:02 -04:00
envelope_emission, opening_emission, component_emission, \
envelope_end_of_life_emission, \
opening_end_of_life_emission, \
component_end_of_life_emission = \
2024-07-21 10:35:42 -04:00
self.calculate_building_component_emission(building)
2024-07-31 15:54:02 -04:00
self.building_envelope_emission.append(envelope_emission)
self.building_opening_emission.append(opening_emission)
self.building_component_emission.append(component_emission)
self.building_envelope_end_of_life_emission.append(
envelope_end_of_life_emission)
self.building_opening_end_of_life_emission.append(
opening_end_of_life_emission)
self.building_component_end_of_life_emission.append(
component_end_of_life_emission)