From 96afcee56eeda476c34fcfc4a8ec2383548dbf8b Mon Sep 17 00:00:00 2001 From: Pilar Date: Tue, 8 Nov 2022 15:57:50 -0500 Subject: [PATCH 1/4] changed vegetation from thermal boundary to surface --- .../building_demand/surface.py | 51 +++++++++++-------- .../building_demand/thermal_boundary.py | 23 ++------- exports/formats/idf.py | 18 +++---- unittests/test_greenery_in_idf.py | 8 ++- 4 files changed, 44 insertions(+), 56 deletions(-) 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() From f5fe1fd4d916d5cb0aa2fe8340b2200698c8b2e0 Mon Sep 17 00:00:00 2001 From: Pilar Date: Tue, 8 Nov 2022 16:28:07 -0500 Subject: [PATCH 2/4] added associated_thermal_boundaries to Surface --- .../building_demand/storey.py | 4 +++- .../building_demand/surface.py | 20 ++++++++++++++++++- .../helpers/storeys_generation.py | 2 +- unittests/test_geometry_factory.py | 3 +-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/city_model_structure/building_demand/storey.py b/city_model_structure/building_demand/storey.py index 42264eda..96c52937 100644 --- a/city_model_structure/building_demand/storey.py +++ b/city_model_structure/building_demand/storey.py @@ -66,7 +66,9 @@ class Storey: windows_areas = [] for hole in surface.holes_polygons: windows_areas.append(hole.area) - self._thermal_boundaries.append(ThermalBoundary(surface, surface.solid_polygon.area, windows_areas)) + new_thermal_boundary = ThermalBoundary(surface, surface.solid_polygon.area, windows_areas) + surface.associated_thermal_boundaries.append(new_thermal_boundary) + self._thermal_boundaries.append(new_thermal_boundary) return self._thermal_boundaries @property diff --git a/city_model_structure/building_demand/surface.py b/city_model_structure/building_demand/surface.py index 016b3563..ad1722d3 100644 --- a/city_model_structure/building_demand/surface.py +++ b/city_model_structure/building_demand/surface.py @@ -30,6 +30,7 @@ class Surface: self._id = None self._azimuth = None self._inclination = None + self._area = None self._lower_corner = None self._upper_corner = None self._shared_surfaces = [] @@ -38,7 +39,7 @@ class Surface: self._holes_polygons = holes_polygons self._solid_polygon = solid_polygon self._inverse = None - self._associated_thermal_boundaries = None + self._associated_thermal_boundaries = [] self._vegetation = None # todo: create self._associated_thermal_boundaries and bring the vegetation here instead of in thermal_boundary @@ -147,6 +148,15 @@ class Surface: self._upper_corner = [self._max_coord('x'), self._max_coord('y'), self._max_coord('z')] return self._upper_corner + @property + def perimeter_area(self): + """ + Get perimeter surface area in square meters (opaque + transparent) + :return: float + """ + self._area = self.perimeter_polygon.area + return self._area + @property def azimuth(self): """ @@ -309,3 +319,11 @@ class Surface: :return: None or [ThermalBoundary] """ return self._associated_thermal_boundaries + + @associated_thermal_boundaries.setter + def associated_thermal_boundaries(self, value): + """ + Set the list of thermal boundaries that has this surface as external face + :param value: None or [ThermalBoundary] + """ + self._associated_thermal_boundaries = value diff --git a/imports/construction/helpers/storeys_generation.py b/imports/construction/helpers/storeys_generation.py index 51d6e416..19bad00e 100644 --- a/imports/construction/helpers/storeys_generation.py +++ b/imports/construction/helpers/storeys_generation.py @@ -99,7 +99,7 @@ class StoreysGeneration: polygon = Polygon(coordinates) ceiling = Surface(polygon, polygon, surface_type=cte.INTERIOR_SLAB) surfaces_child.append(ceiling) - volume = ceiling.area_above_ground * height + volume = ceiling.perimeter_area * height total_volume += volume storeys.append(Storey(name, surfaces_child, neighbours, volume, self._internal_zone, self._floor_area)) name = 'storey_' + str(number_of_storeys - 1) diff --git a/unittests/test_geometry_factory.py b/unittests/test_geometry_factory.py index 0749bf57..76fd1619 100644 --- a/unittests/test_geometry_factory.py +++ b/unittests/test_geometry_factory.py @@ -92,8 +92,7 @@ class TestGeometryFactory(TestCase): self.assertIsNone(surface.swr, 'surface swr is not none') self.assertIsNotNone(surface.lower_corner, 'surface envelope_lower_corner is none') self.assertIsNotNone(surface.upper_corner, 'surface envelope_upper_corner is none') - self.assertIsNotNone(surface.area_below_ground, 'surface area_below_ground is none') - self.assertIsNotNone(surface.area_above_ground, 'surface area_above_ground is none') + self.assertIsNotNone(surface.perimeter_area, 'surface area_above_ground is none') self.assertIsNotNone(surface.azimuth, 'surface azimuth is none') self.assertIsNotNone(surface.type, 'surface type is none') self.assertIsNotNone(surface.inclination, 'surface inclination is none') From e9559a848552a47aae686324eaa8de0610e97d2c Mon Sep 17 00:00:00 2001 From: Pilar Date: Wed, 9 Nov 2022 14:22:26 -0500 Subject: [PATCH 3/4] finished the reorganization between thermal boundaries and surfaces --- city_model_structure/building.py | 30 ++- .../building_demand/storey.py | 2 +- .../building_demand/surface.py | 60 +++-- .../building_demand/thermal_boundary.py | 161 +----------- .../building_demand/thermal_opening.py | 109 +-------- .../building_demand/thermal_zone.py | 10 - imports/construction/us_physics_parameters.py | 14 +- unittests/test_construction_factory.py | 231 +++++++++--------- unittests/test_geometry_factory.py | 8 +- 9 files changed, 203 insertions(+), 422 deletions(-) diff --git a/city_model_structure/building.py b/city_model_structure/building.py index 092310ef..53743f4c 100644 --- a/city_model_structure/building.py +++ b/city_model_structure/building.py @@ -8,6 +8,7 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord from typing import List, Union import numpy as np +import helpers.constants as cte from city_model_structure.building_demand.surface import Surface from city_model_structure.city_object import CityObject from city_model_structure.building_demand.household import Household @@ -48,11 +49,11 @@ class Building(CityObject): self._min_z = min(self._min_z, surface.lower_corner[2]) surface.id = surface_id # todo: consider all type of surfaces, not only these four - if surface.type == 'Ground': + if surface.type == cte.GROUND: self._grounds.append(surface) - elif surface.type == 'Wall': + elif surface.type == cte.WALL: self._walls.append(surface) - elif surface.type == 'Roof': + elif surface.type == cte.ROOF: self._roofs.append(surface) else: self._internal_walls.append(surface) @@ -60,11 +61,18 @@ class Building(CityObject): @property def shell(self) -> Polyhedron: """ - Get building shell + Get building's external polyhedron :return: [Polyhedron] """ + polygons = [] + for surface in self.surfaces: + if surface.type is not cte.INTERIOR_WALL: + polygons.append(surface.solid_polygon) + if surface.holes_polygons is not None: + for hole in surface.holes_polygons: + polygons.append(hole) if self._shell is None: - self._shell = Polyhedron(self.surfaces) + self._shell = Polyhedron(polygons) return self._shell @property @@ -103,6 +111,14 @@ class Building(CityObject): """ return self._walls + @property + def internal_walls(self) -> List[Surface]: + """ + Get building internal wall surfaces + :return: [Surface] + """ + return self._internal_walls + @property def terrains(self) -> Union[None, List[Surface]]: """ @@ -327,7 +343,7 @@ class Building(CityObject): @property def human_readable_name(self): """ - Get the human readable name for the building + Get the human-readable name for the building :return: str """ return self._human_readable_name @@ -335,6 +351,6 @@ class Building(CityObject): @human_readable_name.setter def human_readable_name(self, value): """ - Set the human readable name for the building + Set the human-readable name for the building """ self._human_readable_name = value diff --git a/city_model_structure/building_demand/storey.py b/city_model_structure/building_demand/storey.py index 96c52937..4a491758 100644 --- a/city_model_structure/building_demand/storey.py +++ b/city_model_structure/building_demand/storey.py @@ -80,7 +80,7 @@ class Storey: if self._virtual_surfaces is None: self._virtual_surfaces = [] for thermal_boundary in self.thermal_boundaries: - self._virtual_surfaces.append(thermal_boundary.virtual_internal_surface) + self._virtual_surfaces.append(thermal_boundary.internal_surface) return self._virtual_surfaces @property diff --git a/city_model_structure/building_demand/surface.py b/city_model_structure/building_demand/surface.py index ad1722d3..6fbb53cc 100644 --- a/city_model_structure/building_demand/surface.py +++ b/city_model_structure/building_demand/surface.py @@ -23,9 +23,8 @@ class Surface: Surface class """ - def __init__(self, solid_polygon, perimeter_polygon, holes_polygons=None, name=None, surface_type=None, swr=None): + def __init__(self, solid_polygon, perimeter_polygon, holes_polygons=None, name=None, surface_type=None): self._type = surface_type - self._swr = swr self._name = name self._id = None self._azimuth = None @@ -38,12 +37,12 @@ class Surface: self._perimeter_polygon = perimeter_polygon self._holes_polygons = holes_polygons self._solid_polygon = solid_polygon + self._short_wave_reflectance = None + self._long_wave_emittance = None self._inverse = None self._associated_thermal_boundaries = [] self._vegetation = None - # todo: create self._associated_thermal_boundaries and bring the vegetation here instead of in thermal_boundary - @property def name(self): """ @@ -81,23 +80,6 @@ class Surface: """ raise NotImplementedError - @property - def swr(self) -> Union[None, float]: - """ - Get surface short wave reflectance - :return: None or float - """ - return self._swr - - @swr.setter - def swr(self, value): - """ - Set surface short wave reflectance - :param value: float - """ - if value is not None: - self._swr = float(value) - def _max_coord(self, axis): if axis == 'x': axis = 0 @@ -255,6 +237,42 @@ class Surface: """ self._holes_polygons = value + @property + def short_wave_reflectance(self): + """ + Get the short wave reflectance, this includes all solar spectrum, visible and not visible + The absorptance as an opaque surface, can be calculated as 1-short_wave_reflectance + :return: float + """ + return self._short_wave_reflectance + + @short_wave_reflectance.setter + def short_wave_reflectance(self, value): + """ + Set the short wave reflectance, this includes all solar spectrum, visible and not visible + The absorptance as an opaque surface, can be calculated as 1-short_wave_reflectance + :param value: float + """ + self._short_wave_reflectance = value + + @property + def long_wave_emittance(self): + """ + Get the long wave emittance af the surface + The thermal absorptance can be calculated as 1-long_wave_emittance + :return: float + """ + return self._long_wave_emittance + + @long_wave_emittance.setter + def long_wave_emittance(self, value): + """ + Set the long wave emittance af the surface + The thermal absorptance can be calculated as 1-long_wave_emittance + :param value: float + """ + self._long_wave_emittance = value + @property def inverse(self) -> Surface: """ diff --git a/city_model_structure/building_demand/thermal_boundary.py b/city_model_structure/building_demand/thermal_boundary.py index 83747a49..9bbd5943 100644 --- a/city_model_structure/building_demand/thermal_boundary.py +++ b/city_model_structure/building_demand/thermal_boundary.py @@ -28,19 +28,12 @@ class ThermalBoundary: self._thermal_zones = None self._thermal_openings = None self._layers = None - self._outside_solar_absorptance = None - self._outside_thermal_absorptance = None - self._outside_visible_absorptance = None - self._u_value = None - self._outside_shortwave_reflectance = None - self._construction_name = None - self._hi = ch().convective_heat_transfer_coefficient_interior self._he = ch().convective_heat_transfer_coefficient_exterior + self._hi = ch().convective_heat_transfer_coefficient_interior + self._u_value = None + self._construction_name = None self._thickness = None - self._virtual_internal_surface = None - self._inside_emissivity = None - self._alpha_coefficient = None - self._radiative_coefficient = None + self._internal_surface = None self._window_ratio = None self._window_ratio_is_calculated = False @@ -78,23 +71,6 @@ class ThermalBoundary: """ self._thermal_zones = value - # todo: do I need these two?? - @property - def azimuth(self): - """ - Get the thermal boundary azimuth in radians - :return: float - """ - return self.parent_surface.azimuth - - @property - def inclination(self): - """ - Get the thermal boundary inclination in radians - :return: float - """ - return self.parent_surface.inclination - @property def opaque_area(self): """ @@ -117,58 +93,6 @@ class ThermalBoundary: self._thickness += layer.thickness return self._thickness - @property - def outside_solar_absorptance(self) -> Union[None, float]: - """ - Get thermal boundary outside solar absorptance - :return: None or float - """ - return self._outside_solar_absorptance - - @outside_solar_absorptance.setter - def outside_solar_absorptance(self, value): - """ - Set thermal boundary outside solar absorptance - :param value: float - """ - if value is not None: - self._outside_solar_absorptance = float(value) - self._outside_shortwave_reflectance = 1.0 - float(value) - - @property - def outside_thermal_absorptance(self) -> Union[None, float]: - """ - Get thermal boundary outside thermal absorptance - :return: float - """ - return self._outside_thermal_absorptance - - @outside_thermal_absorptance.setter - def outside_thermal_absorptance(self, value): - """ - Set thermal boundary outside thermal absorptance - :param value: float - """ - if value is not None: - self._outside_thermal_absorptance = float(value) - - @property - def outside_visible_absorptance(self) -> Union[None, float]: - """ - Get thermal boundary outside visible absorptance - :return: None or float - """ - return self._outside_visible_absorptance - - @outside_visible_absorptance.setter - def outside_visible_absorptance(self, value): - """ - Set thermal boundary outside visible absorptance - :param value: float - """ - if value is not None: - self._outside_visible_absorptance = float(value) - @property def thermal_openings(self) -> Union[None, List[ThermalOpening]]: """ @@ -310,24 +234,6 @@ class ThermalBoundary: if value is not None: self._u_value = float(value) - @property - def outside_shortwave_reflectance(self) -> Union[None, float]: - """ - Get thermal boundary external shortwave reflectance - :return: None or float - """ - return self._outside_shortwave_reflectance - - @outside_shortwave_reflectance.setter - def outside_shortwave_reflectance(self, value): - """ - Set thermal boundary external shortwave reflectance - :param value: float - """ - if value is not None: - self._outside_shortwave_reflectance = float(value) - self._outside_solar_absorptance = 1.0 - float(value) - @property def hi(self) -> Union[None, float]: """ @@ -363,62 +269,11 @@ class ThermalBoundary: self._he = value @property - def virtual_internal_surface(self) -> Surface: + def internal_surface(self) -> Surface: """ Get the internal surface of the thermal boundary :return: Surface """ - if self._virtual_internal_surface is None: - self._virtual_internal_surface = self.parent_surface.inverse - return self._virtual_internal_surface - - @property - def inside_emissivity(self) -> Union[None, float]: - """ - Get the short wave emissivity factor of the thermal boundary's internal surface (-) - :return: None or float - """ - return self._inside_emissivity - - @inside_emissivity.setter - def inside_emissivity(self, value): - """ - Set short wave emissivity factor of the thermal boundary's internal surface (-) - :param value: float - """ - if value is not None: - self._inside_emissivity = float(value) - - @property - def alpha_coefficient(self) -> Union[None, float]: - """ - Get the long wave emissivity factor of the thermal boundary's internal surface (-) - :return: None or float - """ - return self._alpha_coefficient - - @alpha_coefficient.setter - def alpha_coefficient(self, value): - """ - Set long wave emissivity factor of the thermal boundary's internal surface (-) - :param value: float - """ - if value is not None: - self._alpha_coefficient = float(value) - - @property - def radiative_coefficient(self) -> Union[None, float]: - """ - Get the radiative coefficient of the thermal boundary's external surface (-) - :return: None or float - """ - return self._radiative_coefficient - - @radiative_coefficient.setter - def radiative_coefficient(self, value): - """ - Set radiative coefficient of the thermal boundary's external surface (-) - :param value: float - """ - if value is not None: - self._radiative_coefficient = float(value) + if self._internal_surface is None: + self._internal_surface = self.parent_surface.inverse + return self._internal_surface diff --git a/city_model_structure/building_demand/thermal_opening.py b/city_model_structure/building_demand/thermal_opening.py index 84002a08..89f90db4 100644 --- a/city_model_structure/building_demand/thermal_opening.py +++ b/city_model_structure/building_demand/thermal_opening.py @@ -19,19 +19,13 @@ class ThermalOpening: def __init__(self): self._id = None self._area = None - self._openable_ratio = None self._conductivity = None self._frame_ratio = None self._g_value = None self._thickness = None - self._front_side_solar_transmittance_at_normal_incidence = None - self._back_side_solar_transmittance_at_normal_incidence = None self._overall_u_value = None self._hi = ch().convective_heat_transfer_coefficient_interior self._he = ch().convective_heat_transfer_coefficient_exterior - self._inside_emissivity = None - self._alpha_coefficient = None - self._radiative_coefficient = None self._construction_name = None @property @@ -61,20 +55,6 @@ class ThermalOpening: if value is not None: self._area = float(value) - @property - def openable_ratio(self): - """ - Raises not implemented error - """ - raise NotImplementedError - - @openable_ratio.setter - def openable_ratio(self, value): - """ - Raises not implemented error - """ - raise NotImplementedError - @property def conductivity(self) -> Union[None, float]: """ @@ -119,7 +99,7 @@ class ThermalOpening: @property def g_value(self) -> Union[None, float]: """ - Get thermal opening g-value + Get thermal opening transmittance at normal incidence :return: None or float """ return self._g_value @@ -127,7 +107,7 @@ class ThermalOpening: @g_value.setter def g_value(self, value): """ - Set thermal opening g-value + Set thermal opening transmittance at normal incidence :param value: float """ if value is not None: @@ -157,40 +137,6 @@ class ThermalOpening: r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self._thickness) self._overall_u_value = 1 / r_value - @property - def front_side_solar_transmittance_at_normal_incidence(self) -> Union[None, float]: - """ - Get thermal opening front side solar transmittance at normal incidence - :return: None or float - """ - return self._front_side_solar_transmittance_at_normal_incidence - - @front_side_solar_transmittance_at_normal_incidence.setter - def front_side_solar_transmittance_at_normal_incidence(self, value): - """ - Set thermal opening front side solar transmittance at normal incidence - :param value: float - """ - if value is not None: - self._front_side_solar_transmittance_at_normal_incidence = float(value) - - @property - def back_side_solar_transmittance_at_normal_incidence(self) -> Union[None, float]: - """ - Get thermal opening back side solar transmittance at normal incidence - :return: None or float - """ - return self._back_side_solar_transmittance_at_normal_incidence - - @back_side_solar_transmittance_at_normal_incidence.setter - def back_side_solar_transmittance_at_normal_incidence(self, value): - """ - Set thermal opening back side solar transmittance at normal incidence - :param value: float - """ - if value is not None: - self._back_side_solar_transmittance_at_normal_incidence = float(value) - @property def overall_u_value(self) -> Union[None, float]: """ @@ -242,57 +188,6 @@ class ThermalOpening: if value is not None: self._he = float(value) - @property - def inside_emissivity(self) -> Union[None, float]: - """ - Get the short wave emissivity factor of the thermal opening's internal surface (-) - :return: None or float - """ - return self._inside_emissivity - - @inside_emissivity.setter - def inside_emissivity(self, value): - """ - Set short wave emissivity factor of the thermal opening's internal surface (-) - :param value: float - """ - if value is not None: - self._inside_emissivity = float(value) - - @property - def alpha_coefficient(self) -> Union[None, float]: - """ - Get the long wave emissivity factor of the thermal opening's internal surface (-) - :return: None or float - """ - return self._alpha_coefficient - - @alpha_coefficient.setter - def alpha_coefficient(self, value): - """ - Set long wave emissivity factor of the thermal opening's internal surface (-) - :param value: float - """ - if value is not None: - self._alpha_coefficient = float(value) - - @property - def radiative_coefficient(self) -> Union[None, float]: - """ - Get the radiative coefficient of the thermal opening's external surface (-) - :return: None or float - """ - return self._radiative_coefficient - - @radiative_coefficient.setter - def radiative_coefficient(self, value): - """ - Set radiative coefficient of the thermal opening's external surface (-) - :param value: float - """ - if value is not None: - self._radiative_coefficient = float(value) - @property def construction_name(self): """ diff --git a/city_model_structure/building_demand/thermal_zone.py b/city_model_structure/building_demand/thermal_zone.py index 9fc434f1..417a6b39 100644 --- a/city_model_structure/building_demand/thermal_zone.py +++ b/city_model_structure/building_demand/thermal_zone.py @@ -15,7 +15,6 @@ from city_model_structure.building_demand.appliances import Appliances from city_model_structure.building_demand.lighting import Lighting from city_model_structure.building_demand.internal_gain import InternalGain from city_model_structure.building_demand.thermal_control import ThermalControl -from city_model_structure.energy_systems.hvac_system import HvacSystem from city_model_structure.attributes.schedule import Schedule import helpers.constants as cte @@ -208,15 +207,6 @@ class ThermalZone: if value is not None: self._ordinate_number = int(value) - @property - def hvac_system(self) -> Union[None, HvacSystem]: - """ - Get HVAC system installed for this thermal zone - From internal_zone - :return: None or HvacSystem - """ - return self._parent_internal_zone.hvac_system - @property def view_factors_matrix(self): """ diff --git a/imports/construction/us_physics_parameters.py b/imports/construction/us_physics_parameters.py index 3ace0850..2baa6749 100644 --- a/imports/construction/us_physics_parameters.py +++ b/imports/construction/us_physics_parameters.py @@ -29,7 +29,6 @@ class UsPhysicsParameters(NrelPhysicsInterface): """ Returns the city with the construction parameters assigned to the buildings """ - # todo: erase city = self._city for building in city.buildings: try: @@ -40,7 +39,8 @@ class UsPhysicsParameters(NrelPhysicsInterface): f'and climate zone reference norm {self._climate_zone}\n') return - # if building has no thermal zones defined from geometry, one thermal zone per storey is assigned + # if building has no thermal zones defined from geometry, and the building will be divided in storeys, + # one thermal zone per storey is assigned if len(building.internal_zones) == 1: if building.internal_zones[0].thermal_zones is None: self._create_storeys(building, archetype, self._divide_in_storeys) @@ -121,9 +121,13 @@ class UsPhysicsParameters(NrelPhysicsInterface): thermal_boundary.layers.append(layer) # The agreement is that the layers are defined from outside to inside external_layer = construction_archetype.layers[0] - thermal_boundary.outside_solar_absorptance = external_layer.material.solar_absorptance - thermal_boundary.outside_thermal_absorptance = external_layer.material.thermal_absorptance - thermal_boundary.outside_visible_absorptance = external_layer.material.visible_absorptance + external_surface = thermal_boundary.parent_surface + external_surface.short_wave_reflectance = 1 - float(external_layer.material.solar_absorptance) + external_surface.long_wave_emittance = 1 - float(external_layer.material.solar_absorptance) + internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1] + internal_surface = thermal_boundary.internal_surface + internal_surface.short_wave_reflectance = 1 - float(internal_layer.material.solar_absorptance) + internal_surface.long_wave_emittance = 1 - float(internal_layer.material.solar_absorptance) for thermal_opening in thermal_boundary.thermal_openings: if construction_archetype.window is not None: diff --git a/unittests/test_construction_factory.py b/unittests/test_construction_factory.py index 485c1d0a..6ca15a2c 100644 --- a/unittests/test_construction_factory.py +++ b/unittests/test_construction_factory.py @@ -30,110 +30,15 @@ class TestConstructionFactory(TestCase): self.assertIsNotNone(self._city, 'city is none') return self._city - def _check_buildings(self, city): - for building in city.buildings: - self.assertIsNotNone(building.name, 'building name is none') - self.assertIsNotNone(building.lod, 'building lod is none') - self.assertIsNotNone(building.type, 'building type is none') - self.assertIsNotNone(building.volume, 'building volume is none') - self.assertIsNotNone(building.detailed_polyhedron, 'building detailed polyhedron is none') - self.assertIsNotNone(building.simplified_polyhedron, 'building simplified polyhedron is none') - self.assertIsNotNone(building.surfaces, 'building surfaces is none') - self.assertIsNotNone(building.centroid, 'building centroid is none') - self.assertIsNotNone(building.max_height, 'building max_height is none') - self.assertEqual(len(building.external_temperature), 0, 'building external temperature is calculated') - self.assertEqual(len(building.global_horizontal), 0, 'building global horizontal is calculated') - self.assertEqual(len(building.diffuse), 0, 'building diffuse is calculated') - self.assertEqual(len(building.beam), 0, 'building beam is calculated') - self.assertIsNotNone(building.lower_corner, 'building lower corner is none') - self.assertEqual(len(building.sensors), 0, 'building sensors are assigned') - self.assertIsNotNone(building.internal_zones, 'no internal zones created') - self.assertIsNotNone(building.grounds, 'building grounds is none') - self.assertIsNotNone(building.walls, 'building walls is none') - self.assertIsNotNone(building.roofs, 'building roofs is none') - for internal_zone in building.internal_zones: - self.assertIsNone(internal_zone.usage_zones, 'usage zones are defined') - self.assertTrue(len(internal_zone.thermal_zones) > 0, 'thermal zones are not defined') - self.assertIsNone(building.basement_heated, 'building basement_heated is not none') - self.assertIsNone(building.attic_heated, 'building attic_heated is not none') - self.assertIsNone(building.terrains, 'building terrains is not none') - self.assertIsNotNone(building.year_of_construction, 'building year_of_construction is none') - self.assertIsNotNone(building.function, 'building function is none') - self.assertIsNotNone(building.average_storey_height, 'building average_storey_height is none') - self.assertIsNotNone(building.storeys_above_ground, 'building storeys_above_ground is none') - self.assertEqual(len(building.heating), 0, 'building heating is not none') - self.assertEqual(len(building.cooling), 0, 'building cooling is not none') - self.assertIsNotNone(building.eave_height, 'building eave height is none') - self.assertIsNotNone(building.roof_type, 'building roof type is none') - self.assertIsNotNone(building.floor_area, 'building floor_area is none') - self.assertIsNone(building.households, 'building households is not none') - self.assertFalse(building.is_conditioned, 'building is conditioned') - - def _check_thermal_zones(self, internal_zone): - for thermal_zone in internal_zone.thermal_zones: - self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none') - self.assertIsNotNone(thermal_zone.footprint_area, 'thermal_zone floor area is none') - self.assertTrue(len(thermal_zone.thermal_boundaries) > 0, 'thermal_zone thermal_boundaries not defined') - self.assertIsNotNone(thermal_zone.additional_thermal_bridge_u_value, 'additional_thermal_bridge_u_value is none') - self.assertIsNotNone(thermal_zone.effective_thermal_capacity, 'thermal_zone effective_thermal_capacity is none') - self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, - 'thermal_zone indirectly_heated_area_ratio is none') - self.assertIsNotNone(thermal_zone.infiltration_rate_system_off, - 'thermal_zone infiltration_rate_system_off is none') - self.assertIsNotNone(thermal_zone.infiltration_rate_system_on, 'thermal_zone infiltration_rate_system_on is none') - self.assertIsNotNone(thermal_zone.volume, 'thermal_zone volume is none') - self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none') - self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none') - self.assertIsNone(thermal_zone.hvac_system, 'thermal_zone hvac_system is not none') - self.assertIsNone(thermal_zone.usage, 'thermal_zone usage is not none') - self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none') - self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none') - self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none') - self.assertIsNone(thermal_zone.occupancy, 'thermal_zone occupancy is not none') - self.assertIsNone(thermal_zone.lighting, 'thermal_zone lighting is not none') - self.assertIsNone(thermal_zone.appliances, 'thermal_zone appliances is not none') - self.assertIsNone(thermal_zone.thermal_control, 'thermal_zone thermal control is not none') - self.assertIsNone(thermal_zone.internal_gains, 'thermal_zone internal gains not returns none') - - def _check_thermal_boundaries(self, thermal_zone): - for thermal_boundary in thermal_zone.thermal_boundaries: - self.assertIsNotNone(thermal_boundary.id, 'thermal_boundary id is none') - self.assertIsNotNone(thermal_boundary.parent_surface, 'thermal_boundary surface is none') - self.assertIsNotNone(thermal_boundary.thermal_zones, 'thermal_boundary delimits no thermal zone') - self.assertIsNotNone(thermal_boundary.opaque_area, 'thermal_boundary area is none') - self.assertIsNotNone(thermal_boundary.azimuth, 'thermal_boundary azimuth is none') - self.assertIsNotNone(thermal_boundary.inclination, 'thermal_boundary inclination is none') - self.assertIsNotNone(thermal_boundary.thickness, 'thermal_boundary thickness is none') - self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type is none') - self.assertIsNotNone(thermal_boundary.outside_solar_absorptance, 'outside_solar_absorptance is none') - self.assertIsNotNone(thermal_boundary.outside_shortwave_reflectance, 'shortwave_reflectance is none') - self.assertIsNotNone(thermal_boundary.thermal_openings, 'thermal_openings is none') - self.assertIsNotNone(thermal_boundary.construction_name, 'construction_name is none') - self.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none') - self.assertIsNone(thermal_boundary.windows_areas, 'windows_areas is not none') - self.assertIsNotNone(thermal_boundary.u_value, 'u_value is none') - self.assertIsNotNone(thermal_boundary.hi, 'hi is none') - self.assertIsNotNone(thermal_boundary.he, 'he is none') - self.assertIsNotNone(thermal_boundary.virtual_internal_surface, 'virtual_internal_surface is none') - self.assertIsNone(thermal_boundary.inside_emissivity, 'inside_emissivity is not none') - self.assertIsNone(thermal_boundary.alpha_coefficient, 'alpha_coefficient is not none') - self.assertIsNone(thermal_boundary.radiative_coefficient, 'radiative_coefficient is not none') - - def _check_thermal_openings(self, thermal_boundary): - for thermal_opening in thermal_boundary.thermal_openings: - self.assertIsNotNone(thermal_opening.id, 'thermal opening id is not none') - self.assertIsNotNone(thermal_opening.construction_name, 'thermal opening construction is not none') - self.assertIsNotNone(thermal_opening.area, 'thermal opening area is not none') - self.assertRaises(Exception, lambda: thermal_opening.openable_ratio, - 'thermal_opening openable_ratio is not raising an exception') - self.assertIsNotNone(thermal_opening.frame_ratio, 'thermal opening frame_ratio is none') - self.assertIsNotNone(thermal_opening.g_value, 'thermal opening g_value is none') - self.assertIsNotNone(thermal_opening.overall_u_value, 'thermal opening overall_u_value is none') - self.assertIsNotNone(thermal_opening.hi, 'thermal opening hi is none') - self.assertIsNotNone(thermal_opening.he, 'thermal opening he is none') - self.assertIsNone(thermal_opening.inside_emissivity, 'thermal opening inside_emissivity is not none') - self.assertIsNone(thermal_opening.alpha_coefficient, 'thermal opening alpha_coefficient is not none') - self.assertIsNone(thermal_opening.radiative_coefficient, 'thermal opening radiative_coefficient is not none') + @staticmethod + def _internal_function(function_format, original_function): + if function_format == 'hft': + new_function = GeometryHelper.libs_function_from_hft(original_function) + elif function_format == 'pluto': + new_function = GeometryHelper.libs_function_from_pluto(original_function) + else: + raise Exception('Function key not recognized. Implemented only "hft" and "pluto"') + return new_function def test_citygml_function(self): """ @@ -162,6 +67,111 @@ class TestConstructionFactory(TestCase): for building in city.buildings: self.assertRaises(Exception, lambda: self._internal_function(function_format, building.function)) + def _check_buildings(self, city): + for building in city.buildings: + self.assertIsNotNone(building.name, 'building name is none') + self.assertIsNotNone(building.lod, 'building lod is none') + self.assertIsNotNone(building.type, 'building type is none') + self.assertIsNotNone(building.volume, 'building volume is none') + self.assertIsNotNone(building.detailed_polyhedron, 'building detailed polyhedron is none') + self.assertIsNotNone(building.simplified_polyhedron, 'building simplified polyhedron is none') + self.assertIsNotNone(building.surfaces, 'building surfaces is none') + self.assertIsNotNone(building.centroid, 'building centroid is none') + self.assertIsNotNone(building.max_height, 'building max_height is none') + self.assertEqual(len(building.external_temperature), 0, 'building external temperature is calculated') + self.assertEqual(len(building.global_horizontal), 0, 'building global horizontal is calculated') + self.assertEqual(len(building.diffuse), 0, 'building diffuse is calculated') + self.assertEqual(len(building.beam), 0, 'building beam is calculated') + self.assertIsNotNone(building.lower_corner, 'building lower corner is none') + self.assertEqual(len(building.sensors), 0, 'building sensors are assigned') + self.assertIsNotNone(building.internal_zones, 'no internal zones created') + self.assertIsNotNone(building.grounds, 'building grounds is none') + self.assertIsNotNone(building.walls, 'building walls is none') + self.assertIsNotNone(building.roofs, 'building roofs is none') + self.assertIsNotNone(building.internal_walls, 'building internal walls is none') + self.assertIsNone(building.basement_heated, 'building basement_heated is not none') + self.assertIsNone(building.attic_heated, 'building attic_heated is not none') + self.assertIsNone(building.terrains, 'building terrains is not none') + self.assertIsNotNone(building.year_of_construction, 'building year_of_construction is none') + self.assertIsNotNone(building.function, 'building function is none') + self.assertIsNotNone(building.average_storey_height, 'building average_storey_height is none') + self.assertIsNotNone(building.storeys_above_ground, 'building storeys_above_ground is none') + self.assertEqual(len(building.heating), 0, 'building heating is not none') + self.assertEqual(len(building.cooling), 0, 'building cooling is not none') + self.assertIsNotNone(building.eave_height, 'building eave height is none') + self.assertIsNotNone(building.roof_type, 'building roof type is none') + self.assertIsNotNone(building.floor_area, 'building floor_area is none') + self.assertIsNone(building.households, 'building households is not none') + self.assertFalse(building.is_conditioned, 'building is conditioned') + self.assertIsNotNone(building.shell, 'building shell is none') + self.assertIsNone(building.human_readable_name, 'building human_readable_name is not none') + + def _check_thermal_zones(self, internal_zone): + for thermal_zone in internal_zone.thermal_zones: + self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none') + self.assertIsNotNone(thermal_zone.footprint_area, 'thermal_zone floor area is none') + self.assertTrue(len(thermal_zone.thermal_boundaries) > 0, 'thermal_zone thermal_boundaries not defined') + self.assertIsNotNone(thermal_zone.additional_thermal_bridge_u_value, 'additional_thermal_bridge_u_value is none') + self.assertIsNotNone(thermal_zone.effective_thermal_capacity, 'thermal_zone effective_thermal_capacity is none') + self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, + 'thermal_zone indirectly_heated_area_ratio is none') + self.assertIsNotNone(thermal_zone.infiltration_rate_system_off, + 'thermal_zone infiltration_rate_system_off is none') + self.assertIsNotNone(thermal_zone.infiltration_rate_system_on, 'thermal_zone infiltration_rate_system_on is none') + self.assertIsNotNone(thermal_zone.volume, 'thermal_zone volume is none') + self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none') + self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none') + self.assertIsNotNone(thermal_zone.total_floor_area, 'thermal zone total_floor_area is none') + self.assertIsNone(thermal_zone.usage, 'thermal_zone usage is not none') + self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none') + self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none') + self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none') + self.assertIsNone(thermal_zone.occupancy, 'thermal_zone occupancy is not none') + self.assertIsNone(thermal_zone.lighting, 'thermal_zone lighting is not none') + self.assertIsNone(thermal_zone.appliances, 'thermal_zone appliances is not none') + self.assertIsNone(thermal_zone.thermal_control, 'thermal_zone thermal control is not none') + self.assertIsNone(thermal_zone.internal_gains, 'thermal_zone internal gains not returns none') + + def _check_thermal_boundaries(self, thermal_zone): + for thermal_boundary in thermal_zone.thermal_boundaries: + self.assertIsNotNone(thermal_boundary.id, 'thermal_boundary id is none') + self.assertIsNotNone(thermal_boundary.parent_surface, 'thermal_boundary surface is none') + self.assertIsNotNone(thermal_boundary.thermal_zones, 'thermal_boundary delimits no thermal zone') + self.assertIsNotNone(thermal_boundary.opaque_area, 'thermal_boundary area is none') + self.assertIsNotNone(thermal_boundary.thickness, 'thermal_boundary thickness is none') + self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type is none') + self.assertIsNotNone(thermal_boundary.thermal_openings, 'thermal_openings is none') + self.assertIsNotNone(thermal_boundary.construction_name, 'construction_name is none') + self.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none') + self.assertIsNone(thermal_boundary.windows_areas, 'windows_areas is not none') + self.assertIsNotNone(thermal_boundary.u_value, 'u_value is none') + self.assertIsNotNone(thermal_boundary.hi, 'hi is none') + self.assertIsNotNone(thermal_boundary.he, 'he is none') + self.assertIsNotNone(thermal_boundary.internal_surface, 'virtual_internal_surface is none') + self.assertIsNotNone(thermal_boundary.layers, 'layers is not none') + + def _check_thermal_openings(self, thermal_boundary): + for thermal_opening in thermal_boundary.thermal_openings: + self.assertIsNotNone(thermal_opening.id, 'thermal opening id is not none') + self.assertIsNotNone(thermal_opening.construction_name, 'thermal opening construction is not none') + self.assertIsNotNone(thermal_opening.area, 'thermal opening area is not none') + self.assertIsNotNone(thermal_opening.frame_ratio, 'thermal opening frame_ratio is none') + self.assertIsNotNone(thermal_opening.g_value, 'thermal opening g_value is none') + self.assertIsNotNone(thermal_opening.overall_u_value, 'thermal opening overall_u_value is none') + self.assertIsNotNone(thermal_opening.hi, 'thermal opening hi is none') + self.assertIsNotNone(thermal_opening.he, 'thermal opening he is none') + self.assertIsNotNone(thermal_opening.construction_name, 'thermal opening construction_name is none') + + def _check_surfaces(self, thermal_boundary): + external_surface = thermal_boundary.parent_surface + internal_surface = thermal_boundary.internal_surface + self.assertIsNotNone(external_surface.short_wave_reflectance, + 'external surface short_wave_reflectance id is not none') + self.assertIsNotNone(external_surface.long_wave_emittance, 'external surface long_wave_emittance id is not none') + self.assertIsNotNone(internal_surface.short_wave_reflectance, + 'external surface short_wave_reflectance id is not none') + self.assertIsNotNone(internal_surface.long_wave_emittance, 'external surface long_wave_emittance id is not none') + def test_city_with_construction_extended_library(self): """ Enrich the city with the construction information and verify it @@ -180,17 +190,6 @@ class TestConstructionFactory(TestCase): for thermal_zone in internal_zone.thermal_zones: self._check_thermal_boundaries(thermal_zone) for thermal_boundary in thermal_zone.thermal_boundaries: - self.assertIsNotNone(thermal_boundary.outside_thermal_absorptance, 'outside_thermal_absorptance is none') - self.assertIsNotNone(thermal_boundary.outside_visible_absorptance, 'outside_visible_absorptance is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self._check_thermal_openings(thermal_boundary) - - @staticmethod - def _internal_function(function_format, original_function): - if function_format == 'hft': - new_function = GeometryHelper.libs_function_from_hft(original_function) - elif function_format == 'pluto': - new_function = GeometryHelper.libs_function_from_pluto(original_function) - else: - raise Exception('Function key not recognized. Implemented only "hft" and "pluto"') - return new_function + self._check_surfaces(thermal_boundary) diff --git a/unittests/test_geometry_factory.py b/unittests/test_geometry_factory.py index 76fd1619..5551403c 100644 --- a/unittests/test_geometry_factory.py +++ b/unittests/test_geometry_factory.py @@ -89,17 +89,21 @@ class TestGeometryFactory(TestCase): for surface in building.surfaces: self.assertIsNotNone(surface.name, 'surface name is none') self.assertIsNotNone(surface.id, 'surface id is none') - self.assertIsNone(surface.swr, 'surface swr is not none') self.assertIsNotNone(surface.lower_corner, 'surface envelope_lower_corner is none') self.assertIsNotNone(surface.upper_corner, 'surface envelope_upper_corner is none') self.assertIsNotNone(surface.perimeter_area, 'surface area_above_ground is none') self.assertIsNotNone(surface.azimuth, 'surface azimuth is none') - self.assertIsNotNone(surface.type, 'surface type is none') self.assertIsNotNone(surface.inclination, 'surface inclination is none') + self.assertIsNotNone(surface.type, 'surface type is none') self.assertEqual(len(surface.global_irradiance), 0, 'global irradiance is calculated') self.assertIsNotNone(surface.perimeter_polygon, 'surface perimeter_polygon is none') self.assertIsNone(surface.holes_polygons, 'surface hole_polygons is not none') self.assertIsNotNone(surface.solid_polygon, 'surface solid_polygon is none') + self.assertIsNone(surface.short_wave_reflectance, 'surface short_wave_reflectance is not none') + self.assertIsNone(surface.long_wave_emittance, 'surface long_wave_emittance is not none') + self.assertIsNotNone(surface.inverse, 'surface inverse is none') + self.assertEqual(len(surface.associated_thermal_boundaries), 0, 'associated_thermal_boundaries are assigned') + self.assertIsNone(surface.vegetation, 'surface vegetation is not none') # citygml_classes def test_import_citygml(self): From 686b04cb6cfdd600d050883c57c4025980728133 Mon Sep 17 00:00:00 2001 From: Pilar Date: Wed, 9 Nov 2022 16:19:56 -0500 Subject: [PATCH 4/4] new system classes added --- .../energy_systems/hvac_system.py | 23 +++++++++++-- .../energy_systems/hvac_terminal_unit.py | 33 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 city_model_structure/energy_systems/hvac_terminal_unit.py diff --git a/city_model_structure/energy_systems/hvac_system.py b/city_model_structure/energy_systems/hvac_system.py index 3e390cfe..d526b445 100644 --- a/city_model_structure/energy_systems/hvac_system.py +++ b/city_model_structure/energy_systems/hvac_system.py @@ -4,7 +4,8 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -from typing import Union +from typing import Union, List +from city_model_structure.building_demand.thermal_zone import ThermalZone class HvacSystem: @@ -13,11 +14,12 @@ class HvacSystem: """ def __init__(self): self._type = None + self._thermal_zones = None @property def type(self) -> Union[None, str]: """ - Get hvac system type a thermal zone + Get hvac system type :return: None or str """ return self._type @@ -25,9 +27,24 @@ class HvacSystem: @type.setter def type(self, value): """ - Set heating set point defined for a thermal zone + Set hvac system type :param value: str """ if value is not None: self._type = str(value) + @property + def thermal_zones(self) -> Union[None, List[ThermalZone]]: + """ + Get list of zones that this unit serves + :return: None or [ThermalZone] + """ + return self._thermal_zones + + @thermal_zones.setter + def thermal_zones(self, value): + """ + Set list of zones that this unit serves + :param value: [ThermalZone] + """ + self._thermal_zones = value diff --git a/city_model_structure/energy_systems/hvac_terminal_unit.py b/city_model_structure/energy_systems/hvac_terminal_unit.py new file mode 100644 index 00000000..7583bdc4 --- /dev/null +++ b/city_model_structure/energy_systems/hvac_terminal_unit.py @@ -0,0 +1,33 @@ +""" +HvacTerminalUnit module +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" +from typing import Union + + +class HvacTerminalUnit: + """ + HvacTerminalUnit class + """ + def __init__(self): + self._type = None + + @property + def type(self) -> Union[None, str]: + """ + Get type of hvac terminal unit defined for a thermal zone + :return: None or str + """ + return self._type + + @type.setter + def type(self, value): + """ + Set type of hvac terminal unit defined for a thermal zone + :param value: str + """ + if value is not None: + self._type = str(value) +