""" Building module SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca contributors: Pilar Monsalvete pilar_monsalvete@yahoo.es """ from typing import List from city_model_structure.attributes.surface import Surface from city_model_structure.attributes.thermal_boundary import ThermalBoundary from city_model_structure.attributes.thermal_zone import ThermalZone from city_model_structure.attributes.usage_zone import UsageZone from city_model_structure.city_object import CityObject from helpers.geometry_helper import GeometryHelper as gh class Building(CityObject): """ Building(CityObject) class """ def __init__(self, name, lod, surfaces, terrains, year_of_construction, function, city_lower_corner): # todo: take the default values out of the classes!! super().__init__(lod, surfaces, name) self._basement_heated = None self._attic_heated = None self._terrains = terrains self._year_of_construction = year_of_construction self._function = function #todo: change lower_corner to building lower_corner instead city lower corner self._lower_corner = city_lower_corner self._heated = None self._cooled = None self._average_storey_height = None self._storeys_above_ground = None self._floor_area = None self._usage_zones = [] self._type = 'building' self._heating = dict() self._cooling = dict() self._external_temperature = dict() self._global_horizontal = dict() self._diffuse = dict() self._beam = dict() # ToDo: Check this for LOD4 self._thermal_zones = [] if self.lod < 4: # for lod under 4 is just one thermal zone self._thermal_zones.append(ThermalZone(self.surfaces, self._heated, self._cooled)) for t_zones in self._thermal_zones: t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces] surface_id = 0 for surface in self.surfaces: surface.lower_corner = self._lower_corner surface.parent(self, surface_id) surface_id += 1 @property def usage_zones(self) -> List[UsageZone]: """ Get city object usage zones :return: [UsageZone] """ return self._usage_zones @usage_zones.setter def usage_zones(self, values): """ Set city objects usage zones :param values: [UsageZones] :return: None """ # ToDo: this is only valid for one usage zone need to be revised for multiple usage zones. self._usage_zones = values for thermal_zone in self.thermal_zones: thermal_zone.usage_zones = [(100, usage_zone) for usage_zone in values] @property def terrains(self) -> List[Surface]: """ Get city object terrain surfaces :return: [Surface] """ return self._terrains @property def attic_heated(self): """ Get if the city object attic is heated :return: Boolean """ return self._attic_heated @attic_heated.setter def attic_heated(self, value): """ Set if the city object attic is heated :param value: Boolean :return: None """ self._attic_heated = value @property def basement_heated(self): """ Get if the city object basement is heated :return: Boolean """ return self._basement_heated @basement_heated.setter def basement_heated(self, value): """ Set if the city object basement is heated :param value: Boolean :return: None """ self._basement_heated = value @property def name(self): """ City object name :return: str """ return self._name @property def thermal_zones(self) -> List[ThermalZone]: """ City object thermal zones :return: [ThermalZone] """ return self._thermal_zones @property def heated_volume(self): """ City object heated volume in cubic meters :return: float """ # ToDo: this need to be calculated based on the basement and attic heated values raise NotImplementedError @property def year_of_construction(self): """ City object year of construction :return: int """ return self._year_of_construction @property def function(self): """ City object function :return: str """ return self._function @property def average_storey_height(self): """ Get city object average storey height in meters :return: float """ return self._average_storey_height @average_storey_height.setter def average_storey_height(self, value): """ Set city object average storey height in meters :param value: float :return: None """ self._average_storey_height = value @property def storeys_above_ground(self): """ Get city object storeys number above ground :return: int """ return self._storeys_above_ground @storeys_above_ground.setter def storeys_above_ground(self, value): """ Set city object storeys number above ground :param value: int :return: """ self._storeys_above_ground = value @staticmethod def _tuple_to_point(xy_tuple): return [xy_tuple[0], xy_tuple[1], 0.0] @property def type(self): """ building type :return: str """ return self._type @property def heating(self) -> dict: """ heating demand in Wh :return: dict{DataFrame(float)} """ return self._heating @heating.setter def heating(self, value): """ heating demand in Wh :param value: dict{DataFrame(float)} """ self._heating = value @property def cooling(self) -> dict: """ cooling demand in Wh :return: dict{DataFrame(float)} """ return self._cooling @cooling.setter def cooling(self, value): """ cooling demand in Wh :param value: dict{DataFrame(float)} """ self._cooling = value @property def external_temperature(self) -> dict: """ external temperature surrounding the building in grads Celsius :return: dict{DataFrame(float)} """ return self._external_temperature @external_temperature.setter def external_temperature(self, value): """ external temperature surrounding the building in grads Celsius :param value: dict{DataFrame(float)} """ self._external_temperature = value @property def global_horizontal(self) -> dict: """ global horizontal radiation surrounding the building in W/m2 :return: dict{DataFrame(float)} """ return self._global_horizontal @global_horizontal.setter def global_horizontal(self, value): """ global horizontal radiation surrounding the building in W/m2 :param value: dict{DataFrame(float)} """ self._global_horizontal = value @property def diffuse(self) -> dict: """ diffuse radiation surrounding the building in W/m2 :return: dict{DataFrame(float)} """ return self._diffuse @diffuse.setter def diffuse(self, value): """ diffuse radiation surrounding the building in W/m2 :param value: dict{DataFrame(float)} """ self._diffuse = value @property def beam(self) -> dict: """ beam radiation surrounding the building in W/m2 :return: dict{DataFrame(float)} """ return self._beam @beam.setter def beam(self, value): """ beam radiation surrounding the building in W/m2 :param value: dict{DataFrame(float)} """ self._beam = value @property def storeys(self): storeys = [] # todo: these values are not read yet from the files # number_of_storeys = self.storeys_above_ground # height = self.average_storey_height number_of_storeys = 4 height = 1.5 trimesh = self.simplified_polyhedron.trimesh normal_plane = [0, 0, -1] rest_trimesh = trimesh for n in range(0, number_of_storeys - 1): # todo: I need the lower corner of the building!! # point_plane = [self._lower_corner[0], self._lower_corner[1], self._lower_corner[2] + height] point_plane = [self._lower_corner[0] + 0.5, self._lower_corner[1] + 0.5, self._lower_corner[2] + height * (n + 1)] trimeshes = gh.divide_mesh_by_plane(rest_trimesh, normal_plane, point_plane) storey = trimeshes[0] rest_trimesh = trimeshes[1] storeys.append(storey) storeys.append(rest_trimesh) return storeys @property def floor_area(self): """ Floor area of the building m2 :return: float """ if self._floor_area is None: self._floor_area = 0 for surface in self.surfaces: if surface.type == 'Ground': self._floor_area += surface.perimeter_polygon.area return self._floor_area # todo: erase this function, only for rabeehs case @floor_area.setter def floor_area(self, value): self._floor_area = value