diff --git a/city_model_structure/building_demand/surface.py b/city_model_structure/building_demand/surface.py index 71e75ee7..016b3563 100644 --- a/city_model_structure/building_demand/surface.py +++ b/city_model_structure/building_demand/surface.py @@ -13,6 +13,8 @@ from typing import List, Union from city_model_structure.attributes.polygon import Polygon from city_model_structure.attributes.plane import Plane from city_model_structure.attributes.point import Point +from city_model_structure.greenery.vegetation import Vegetation +from city_model_structure.building_demand.thermal_boundary import ThermalBoundary import helpers.constants as cte @@ -28,8 +30,6 @@ class Surface: self._id = None self._azimuth = None self._inclination = None - self._area_above_ground = None - self._area_below_ground = None self._lower_corner = None self._upper_corner = None self._shared_surfaces = [] @@ -37,8 +37,10 @@ class Surface: self._perimeter_polygon = perimeter_polygon self._holes_polygons = holes_polygons self._solid_polygon = solid_polygon - self._pv_system_installed = None self._inverse = None + self._associated_thermal_boundaries = None + self._vegetation = None + # todo: create self._associated_thermal_boundaries and bring the vegetation here instead of in thermal_boundary @property @@ -145,25 +147,6 @@ class Surface: self._upper_corner = [self._max_coord('x'), self._max_coord('y'), self._max_coord('z')] return self._upper_corner - @property - def area_above_ground(self): - """ - Get surface area above ground in square meters - :return: float - """ - if self._area_above_ground is None: - self._area_above_ground = self.perimeter_polygon.area - self.area_below_ground - return self._area_above_ground - - # todo: to be implemented when adding terrains - @property - def area_below_ground(self): - """ - Get surface area below ground in square meters - :return: float - """ - return 0.0 - @property def azimuth(self): """ @@ -302,3 +285,27 @@ class Surface: surface_child = Surface(part_1, part_1, name=self.name, surface_type=self.type) rest_surface = Surface(part_2, part_2, name=self.name, surface_type=self.type) return surface_child, rest_surface, intersection + + @property + def vegetation(self) -> Union[None, Vegetation]: + """ + Get the vegetation construction at the external surface of the thermal boundary + :return: None or Vegetation + """ + return self._vegetation + + @vegetation.setter + def vegetation(self, value): + """ + Set the vegetation construction at the external surface of the thermal boundary + :param value: Vegetation + """ + self._vegetation = value + + @property + def associated_thermal_boundaries(self) -> Union[None, List[ThermalBoundary]]: + """ + Get the list of thermal boundaries that has this surface as external face + :return: None or [ThermalBoundary] + """ + return self._associated_thermal_boundaries diff --git a/city_model_structure/building_demand/thermal_boundary.py b/city_model_structure/building_demand/thermal_boundary.py index e8df767e..83747a49 100644 --- a/city_model_structure/building_demand/thermal_boundary.py +++ b/city_model_structure/building_demand/thermal_boundary.py @@ -7,13 +7,13 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord """ import uuid -from typing import List, Union +from typing import List, Union, TypeVar from helpers.configuration_helper import ConfigurationHelper as ch from city_model_structure.building_demand.layer import Layer from city_model_structure.building_demand.thermal_opening import ThermalOpening from city_model_structure.building_demand.thermal_zone import ThermalZone -from city_model_structure.building_demand.surface import Surface -from city_model_structure.greenery.vegetation import Vegetation + +Surface = TypeVar('Surface') class ThermalBoundary: @@ -43,7 +43,6 @@ class ThermalBoundary: self._radiative_coefficient = None self._window_ratio = None self._window_ratio_is_calculated = False - self._vegetation = None @property def id(self): @@ -423,19 +422,3 @@ class ThermalBoundary: """ if value is not None: self._radiative_coefficient = float(value) - - @property - def vegetation(self) -> Union[None, Vegetation]: - """ - Get the vegetation construction at the external surface of the thermal boundary - :return: None or Vegetation - """ - return self._vegetation - - @vegetation.setter - def vegetation(self, value): - """ - Set the vegetation construction at the external surface of the thermal boundary - :param value: Vegetation - """ - self._vegetation = value diff --git a/exports/formats/idf.py b/exports/formats/idf.py index a4089b15..9c1ca65a 100644 --- a/exports/formats/idf.py +++ b/exports/formats/idf.py @@ -267,8 +267,8 @@ class Idf: def _add_construction(self, thermal_boundary): for construction in self._idf.idfobjects[self._CONSTRUCTION]: - if thermal_boundary.vegetation is not None: - if construction.Name == f'{thermal_boundary.construction_name}_{thermal_boundary.vegetation.name}': + if thermal_boundary.parent_surface.vegetation is not None: + if construction.Name == f'{thermal_boundary.construction_name}_{thermal_boundary.parent_surface.vegetation.name}': return else: if construction.Name == thermal_boundary.construction_name: @@ -283,9 +283,9 @@ class Idf: self._add_material(layer) layers = thermal_boundary.layers # The constructions should have at least one layer - if thermal_boundary.vegetation is not None: - _kwargs = {'Name': f'{thermal_boundary.construction_name}_{thermal_boundary.vegetation.name}', - 'Outside_Layer': thermal_boundary.vegetation.name} + if thermal_boundary.parent_surface.vegetation is not None: + _kwargs = {'Name': f'{thermal_boundary.construction_name}_{thermal_boundary.parent_surface.vegetation.name}', + 'Outside_Layer': thermal_boundary.parent_surface.vegetation.name} for i in range(0, len(layers) - 1): _kwargs[f'Layer_{i + 2}'] = layers[i].material.name else: @@ -401,8 +401,8 @@ class Idf: for thermal_zone in internal_zone.thermal_zones: for thermal_boundary in thermal_zone.thermal_boundaries: self._add_construction(thermal_boundary) - if thermal_boundary.vegetation is not None: - self._add_vegetation_material(thermal_boundary.vegetation) + if thermal_boundary.parent_surface.vegetation is not None: + self._add_vegetation_material(thermal_boundary.parent_surface.vegetation) for thermal_opening in thermal_boundary.thermal_openings: self._add_window_construction_and_material(thermal_opening) usage = thermal_zone.usage @@ -503,8 +503,8 @@ class Idf: outside_boundary_condition = 'Ground' sun_exposure = 'NoSun' wind_exposure = 'NoWind' - if boundary.vegetation is not None: - construction_name = f'{boundary.construction_name}_{boundary.vegetation.name}' + if boundary.parent_surface.vegetation is not None: + construction_name = f'{boundary.construction_name}_{boundary.parent_surface.vegetation.name}' else: construction_name = boundary.construction_name surface = self._idf.newidfobject(self._SURFACE, Name=f'{boundary.parent_surface.name}', diff --git a/unittests/test_greenery_in_idf.py b/unittests/test_greenery_in_idf.py index d230356b..216ea390 100644 --- a/unittests/test_greenery_in_idf.py +++ b/unittests/test_greenery_in_idf.py @@ -62,11 +62,9 @@ class GreeneryInIdf(TestCase): plants = [plant] vegetation = Vegetation(vegetation_name, soil, soil_thickness, plants) for building in city.buildings: - for internal_zone in building.internal_zones: - for thermal_zone in internal_zone.thermal_zones: - for thermal_boundary in thermal_zone.thermal_boundaries: - if thermal_boundary.type == cte.ROOF: - thermal_boundary.vegetation = vegetation + for surface in building.surfaces: + if surface.type == cte.ROOF: + surface.vegetation = vegetation _idf_2 = ExportsFactory('idf', city, output_path).export_debug() _idf_2.run()