From e9559a848552a47aae686324eaa8de0610e97d2c Mon Sep 17 00:00:00 2001 From: Pilar Date: Wed, 9 Nov 2022 14:22:26 -0500 Subject: [PATCH] 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):