forked from s_ranjbar/city_retrofit
Add code comment to the classes and improve overall quality
This commit is contained in:
parent
de16e01677
commit
22dc10c532
|
@ -49,8 +49,8 @@ class CityObject:
|
||||||
# for lod under 4 is just one thermal zone
|
# for lod under 4 is just one thermal zone
|
||||||
self._thermal_zones.append(ThermalZone(self.surfaces))
|
self._thermal_zones.append(ThermalZone(self.surfaces))
|
||||||
|
|
||||||
for t in self._thermal_zones:
|
for t_zones in self._thermal_zones:
|
||||||
t.bounded = [ThermalBoundary(s, [t]) for s in t.surfaces]
|
t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces]
|
||||||
surface_id = 0
|
surface_id = 0
|
||||||
for surface in self._surfaces:
|
for surface in self._surfaces:
|
||||||
surface.lower_corner = self._lower_corner
|
surface.lower_corner = self._lower_corner
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Polyhedron:
|
||||||
|
|
||||||
def _position_of(self, point):
|
def _position_of(self, point):
|
||||||
vertices = self.vertices
|
vertices = self.vertices
|
||||||
for i in range(len(vertices)):
|
for i in enumerate(vertices):
|
||||||
if self._geometry.almost_equal(vertices[i], point):
|
if self._geometry.almost_equal(vertices[i], point):
|
||||||
return i
|
return i
|
||||||
return -1
|
return -1
|
||||||
|
@ -37,16 +37,16 @@ class Polyhedron:
|
||||||
"""
|
"""
|
||||||
if self._vertices is None:
|
if self._vertices is None:
|
||||||
vertices, self._vertices = [], []
|
vertices, self._vertices = [], []
|
||||||
[vertices.extend(s.points) for s in self._surfaces]
|
_ = [vertices.extend(s.points) for s in self._surfaces]
|
||||||
for v1 in vertices:
|
for vertex_1 in vertices:
|
||||||
found = False
|
found = False
|
||||||
for v2 in self._vertices:
|
for vertex_2 in self._vertices:
|
||||||
found = False
|
found = False
|
||||||
if self._geometry.almost_equal(v1, v2):
|
if self._geometry.almost_equal(vertex_1, vertex_2):
|
||||||
found = True
|
found = True
|
||||||
break
|
break
|
||||||
if not found:
|
if not found:
|
||||||
self._vertices.append(v1)
|
self._vertices.append(vertex_1)
|
||||||
self._vertices = np.asarray(self._vertices)
|
self._vertices = np.asarray(self._vertices)
|
||||||
return self._vertices
|
return self._vertices
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ class Polyhedron:
|
||||||
"""
|
"""
|
||||||
if self._faces is None:
|
if self._faces is None:
|
||||||
self._faces = []
|
self._faces = []
|
||||||
for s in self._surfaces:
|
for surface in self._surfaces:
|
||||||
face = []
|
face = []
|
||||||
points = s.points
|
points = surface.points
|
||||||
for p in points:
|
for point in points:
|
||||||
face.append(self._position_of(p))
|
face.append(self._position_of(point))
|
||||||
self._faces.append(face)
|
self._faces.append(face)
|
||||||
self._faces = np.asarray(self._faces)
|
self._faces = np.asarray(self._faces)
|
||||||
return self._faces
|
return self._faces
|
||||||
|
@ -71,9 +71,9 @@ class Polyhedron:
|
||||||
def _polyhedron_mesh(self):
|
def _polyhedron_mesh(self):
|
||||||
if self._mesh is None:
|
if self._mesh is None:
|
||||||
self._mesh = stl.mesh.Mesh(np.zeros(self.faces.shape[0], dtype=stl.mesh.Mesh.dtype))
|
self._mesh = stl.mesh.Mesh(np.zeros(self.faces.shape[0], dtype=stl.mesh.Mesh.dtype))
|
||||||
for i, f in enumerate(self.faces):
|
for i, faces in enumerate(self.faces):
|
||||||
for j in range(3):
|
for j in range(3):
|
||||||
self._mesh.vectors[i][j] = self.vertices[f[j], :]
|
self._mesh.vectors[i][j] = self.vertices[faces[j], :]
|
||||||
return self._mesh
|
return self._mesh
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -83,7 +83,7 @@ class Polyhedron:
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._volume is None:
|
if self._volume is None:
|
||||||
self._volume, cog, inertia = self._polyhedron_mesh.get_mass_properties()
|
self._volume, _, _ = self._polyhedron_mesh.get_mass_properties()
|
||||||
return self._volume
|
return self._volume
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -11,6 +11,9 @@ from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class Surface:
|
class Surface:
|
||||||
|
"""
|
||||||
|
Surface class
|
||||||
|
"""
|
||||||
def __init__(self, coordinates, surface_type=None, name=None, swr='0.2', remove_last=True, is_projected=False):
|
def __init__(self, coordinates, surface_type=None, name=None, swr='0.2', remove_last=True, is_projected=False):
|
||||||
self._coordinates = coordinates
|
self._coordinates = coordinates
|
||||||
self._type = surface_type
|
self._type = surface_type
|
||||||
|
@ -42,25 +45,48 @@ class Surface:
|
||||||
self._ground_coordinates = (self.min_x, self.min_y, self.min_z)
|
self._ground_coordinates = (self.min_x, self.min_y, self.min_z)
|
||||||
|
|
||||||
def parent(self, parent, surface_id):
|
def parent(self, parent, surface_id):
|
||||||
|
"""
|
||||||
|
Assign a city object as surface parent and a surface id
|
||||||
|
:param parent: CityObject
|
||||||
|
:param surface_id: str
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
self._name = str(surface_id)
|
self._name = str(surface_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
"""
|
||||||
|
Surface name
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
if self._name is None:
|
if self._name is None:
|
||||||
raise Exception('surface has no name')
|
raise Exception('surface has no name')
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def swr(self):
|
def swr(self):
|
||||||
|
"""
|
||||||
|
Get surface short wave reflectance
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
return self._swr
|
return self._swr
|
||||||
|
|
||||||
@swr.setter
|
@swr.setter
|
||||||
def swr(self, value):
|
def swr(self, value):
|
||||||
|
"""
|
||||||
|
Set surface short wave reflectance
|
||||||
|
:param value: float
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
self._swr = value
|
self._swr = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def points(self) -> np.ndarray:
|
def points(self) -> np.ndarray:
|
||||||
|
"""
|
||||||
|
Surface point matrix
|
||||||
|
:return: np.ndarray
|
||||||
|
"""
|
||||||
if self._points is None:
|
if self._points is None:
|
||||||
self._points = np.fromstring(self._coordinates, dtype=float, sep=' ')
|
self._points = np.fromstring(self._coordinates, dtype=float, sep=' ')
|
||||||
self._points = Geometry.to_points_matrix(self._points, self._remove_last)
|
self._points = Geometry.to_points_matrix(self._points, self._remove_last)
|
||||||
|
@ -83,24 +109,40 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_x(self):
|
def min_x(self):
|
||||||
|
"""
|
||||||
|
Surface minimal x value
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
if self._min_x is None:
|
if self._min_x is None:
|
||||||
self._min_x = self._min_coord('x')
|
self._min_x = self._min_coord('x')
|
||||||
return self._min_x
|
return self._min_x
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_y(self):
|
def min_y(self):
|
||||||
|
"""
|
||||||
|
Surface minimal y value
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
if self._min_y is None:
|
if self._min_y is None:
|
||||||
self._min_y = self._min_coord('y')
|
self._min_y = self._min_coord('y')
|
||||||
return self._min_y
|
return self._min_y
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_z(self):
|
def min_z(self):
|
||||||
|
"""
|
||||||
|
Surface minimal z value
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
if self._min_z is None:
|
if self._min_z is None:
|
||||||
self._min_z = self._min_coord('z')
|
self._min_z = self._min_coord('z')
|
||||||
return self._min_z
|
return self._min_z
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ground_points(self) -> np.ndarray:
|
def ground_points(self) -> np.ndarray:
|
||||||
|
"""
|
||||||
|
Surface grounded points matrix
|
||||||
|
:return: np.ndarray
|
||||||
|
"""
|
||||||
if self._ground_points is None:
|
if self._ground_points is None:
|
||||||
coordinates = ''
|
coordinates = ''
|
||||||
for point in self.points:
|
for point in self.points:
|
||||||
|
@ -116,13 +158,21 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def points_list(self) -> np.ndarray:
|
def points_list(self) -> np.ndarray:
|
||||||
|
"""
|
||||||
|
Surface point list
|
||||||
|
:return: np.ndarray
|
||||||
|
"""
|
||||||
if self._points_list is None:
|
if self._points_list is None:
|
||||||
s = self.points
|
s = self.points
|
||||||
self._points_list = np.reshape(s, len(s) * 3)
|
self._points_list = np.reshape(s, len(s) * 3)
|
||||||
return self._points_list
|
return self._points_list
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def polygon(self) -> pn.Polygon:
|
def polygon(self) -> Union[pn.Polygon, None]:
|
||||||
|
"""
|
||||||
|
Surface polygon
|
||||||
|
:return: None or pyny3d.Polygon
|
||||||
|
"""
|
||||||
if self._polygon is None:
|
if self._polygon is None:
|
||||||
try:
|
try:
|
||||||
self._polygon = pn.Polygon(self.points)
|
self._polygon = pn.Polygon(self.points)
|
||||||
|
@ -133,6 +183,10 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ground_polygon(self) -> Union[pn.Polygon, None]:
|
def ground_polygon(self) -> Union[pn.Polygon, None]:
|
||||||
|
"""
|
||||||
|
Surface grounded polygon
|
||||||
|
:return: None or pyny3d.Polygon
|
||||||
|
"""
|
||||||
if self._ground_polygon is None:
|
if self._ground_polygon is None:
|
||||||
try:
|
try:
|
||||||
self._ground_polygon = pn.Polygon(self.ground_points)
|
self._ground_polygon = pn.Polygon(self.ground_points)
|
||||||
|
@ -143,6 +197,10 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def area(self):
|
def area(self):
|
||||||
|
"""
|
||||||
|
Surface area in square meters
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
if self._area is None:
|
if self._area is None:
|
||||||
self._area = self.polygon.get_area()
|
self._area = self.polygon.get_area()
|
||||||
return self._area
|
return self._area
|
||||||
|
@ -164,12 +222,20 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def area_above_ground(self):
|
def area_above_ground(self):
|
||||||
|
"""
|
||||||
|
Surface area above ground in square meters
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
if self._area_above_ground is None:
|
if self._area_above_ground is None:
|
||||||
self._area_above_ground = self.area - self.area_below_ground
|
self._area_above_ground = self.area - self.area_below_ground
|
||||||
return self._area_above_ground
|
return self._area_above_ground
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def area_below_ground(self):
|
def area_below_ground(self):
|
||||||
|
"""
|
||||||
|
Surface area below ground in square meters
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
if self._area_below_ground is None:
|
if self._area_below_ground is None:
|
||||||
self._area_below_ground = 0.0
|
self._area_below_ground = 0.0
|
||||||
if self._is_terrain:
|
if self._is_terrain:
|
||||||
|
@ -178,6 +244,10 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def normal(self) -> np.ndarray:
|
def normal(self) -> np.ndarray:
|
||||||
|
"""
|
||||||
|
Surface normal vector
|
||||||
|
:return: np.ndarray
|
||||||
|
"""
|
||||||
if self._normal is None:
|
if self._normal is None:
|
||||||
points = self.points
|
points = self.points
|
||||||
n = np.cross(points[1] - points[0], points[2] - points[0])
|
n = np.cross(points[1] - points[0], points[2] - points[0])
|
||||||
|
@ -186,6 +256,10 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def azimuth(self):
|
def azimuth(self):
|
||||||
|
"""
|
||||||
|
Surface azimuth in radians
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
if self._azimuth is None:
|
if self._azimuth is None:
|
||||||
normal = self.normal
|
normal = self.normal
|
||||||
self._azimuth = np.arctan2(normal[1], normal[0])
|
self._azimuth = np.arctan2(normal[1], normal[0])
|
||||||
|
@ -193,12 +267,20 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def inclination(self):
|
def inclination(self):
|
||||||
|
"""
|
||||||
|
Surface inclination in radians
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
if self._inclination is None:
|
if self._inclination is None:
|
||||||
self._inclination = np.arccos(self.normal[2])
|
self._inclination = np.arccos(self.normal[2])
|
||||||
return self._inclination
|
return self._inclination
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
|
"""
|
||||||
|
Surface type Ground, Wall or Roof
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
if self._type is None:
|
if self._type is None:
|
||||||
grad = np.rad2deg(self.inclination)
|
grad = np.rad2deg(self.inclination)
|
||||||
if 170 <= grad:
|
if 170 <= grad:
|
||||||
|
@ -210,36 +292,68 @@ class Surface:
|
||||||
return self._type
|
return self._type
|
||||||
|
|
||||||
def add_shared(self, surface, intersection_area):
|
def add_shared(self, surface, intersection_area):
|
||||||
|
"""
|
||||||
|
Add a given surface and shared area in percent to this surface.
|
||||||
|
:param surface:
|
||||||
|
:param intersection_area:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
percent = intersection_area / self.area
|
percent = intersection_area / self.area
|
||||||
self._shared_surfaces.append((percent, surface))
|
self._shared_surfaces.append((percent, surface))
|
||||||
|
|
||||||
def shared(self, surface):
|
def shared(self, surface):
|
||||||
|
"""
|
||||||
|
Check if given surface share some area with this surface
|
||||||
|
:param surface: Surface
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
if self.type is not 'Wall' or surface.type is not 'Wall':
|
if self.type is not 'Wall' or surface.type is not 'Wall':
|
||||||
return
|
return
|
||||||
if self._geometry.is_almost_same_surface(self, surface):
|
if self._geometry.is_almost_same_surface(self, surface):
|
||||||
intersection_area = self.intersect(surface).area
|
intersection_area = self.intersect(surface).area
|
||||||
percent = intersection_area / self.area
|
self.add_shared(surface, intersection_area)
|
||||||
self._shared_surfaces.append((percent, surface))
|
|
||||||
surface.add_shared(self, intersection_area)
|
surface.add_shared(self, intersection_area)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def global_irradiance_hour(self):
|
def global_irradiance_hour(self):
|
||||||
|
"""
|
||||||
|
Get surface global irradiance hour in Wh/m2
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
return self._global_irradiance_hour
|
return self._global_irradiance_hour
|
||||||
|
|
||||||
@global_irradiance_hour.setter
|
@global_irradiance_hour.setter
|
||||||
def global_irradiance_hour(self, value):
|
def global_irradiance_hour(self, value):
|
||||||
|
"""
|
||||||
|
Set surface global irradiance per hour in Wh/m2
|
||||||
|
:param value: float
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
self._global_irradiance_hour = value
|
self._global_irradiance_hour = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def global_irradiance_month(self):
|
def global_irradiance_month(self):
|
||||||
|
"""
|
||||||
|
Get surface global irradiance per month in Wh/m2
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
return self._global_irradiance_month
|
return self._global_irradiance_month
|
||||||
|
|
||||||
@global_irradiance_month.setter
|
@global_irradiance_month.setter
|
||||||
def global_irradiance_month(self, value):
|
def global_irradiance_month(self, value):
|
||||||
|
"""
|
||||||
|
Set surface global irradiance per month in Wh/m2
|
||||||
|
:param value: float
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
self._global_irradiance_month = value
|
self._global_irradiance_month = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def shapely(self):
|
def shapely(self) -> Union[None, pn.Polygon]:
|
||||||
|
"""
|
||||||
|
Surface shapely (Z projection)
|
||||||
|
:return: None or pyny3d.Polygon
|
||||||
|
"""
|
||||||
if self.polygon is None:
|
if self.polygon is None:
|
||||||
return None
|
return None
|
||||||
if self._shapely is None:
|
if self._shapely is None:
|
||||||
|
@ -247,7 +361,7 @@ class Surface:
|
||||||
return self._shapely
|
return self._shapely
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _polygon_to_surface(polygon):
|
def _polygon_to_surface(polygon) -> Surface:
|
||||||
coordinates = ''
|
coordinates = ''
|
||||||
for coordinate in polygon.exterior.coords:
|
for coordinate in polygon.exterior.coords:
|
||||||
if coordinates != '':
|
if coordinates != '':
|
||||||
|
@ -257,6 +371,10 @@ class Surface:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projection(self) -> Surface:
|
def projection(self) -> Surface:
|
||||||
|
"""
|
||||||
|
Projected surface (Z projection)
|
||||||
|
:return: Surface
|
||||||
|
"""
|
||||||
if self._is_projected:
|
if self._is_projected:
|
||||||
return self
|
return self
|
||||||
if self._projected_surface is None:
|
if self._projected_surface is None:
|
||||||
|
@ -264,6 +382,11 @@ class Surface:
|
||||||
return self._projected_surface
|
return self._projected_surface
|
||||||
|
|
||||||
def intersect(self, surface) -> Union[Surface, None]:
|
def intersect(self, surface) -> Union[Surface, None]:
|
||||||
|
"""
|
||||||
|
Get the intersection surface, if any, between the given surface and this surface
|
||||||
|
:param surface: Surface
|
||||||
|
:return: None or Surface
|
||||||
|
"""
|
||||||
min_x = min(self.min_x, surface.min_x)
|
min_x = min(self.min_x, surface.min_x)
|
||||||
min_y = min(self.min_y, surface.min_y)
|
min_y = min(self.min_y, surface.min_y)
|
||||||
min_z = min(self.min_z, surface.min_z)
|
min_z = min(self.min_z, surface.min_z)
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ThermalZone:
|
||||||
:return: Boolean
|
:return: Boolean
|
||||||
"""
|
"""
|
||||||
return self._heated
|
return self._heated
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cooled(self):
|
def cooled(self):
|
||||||
"""
|
"""
|
||||||
|
@ -44,10 +44,10 @@ class ThermalZone:
|
||||||
"""
|
"""
|
||||||
return self._cooled
|
return self._cooled
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def floor_area(self):
|
def floor_area(self):
|
||||||
"""
|
"""
|
||||||
Get thermal zone floor area in m2
|
Get thermal zone floor area in square meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._floor_area is None:
|
if self._floor_area is None:
|
||||||
|
|
|
@ -8,6 +8,9 @@ from typing import List
|
||||||
|
|
||||||
|
|
||||||
class UsageZone:
|
class UsageZone:
|
||||||
|
"""
|
||||||
|
UsageZone class
|
||||||
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._usage = None
|
self._usage = None
|
||||||
self._internal_gains = None
|
self._internal_gains = None
|
||||||
|
@ -20,14 +23,27 @@ class UsageZone:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def internal_gains(self) -> List[InternalGains]:
|
def internal_gains(self) -> List[InternalGains]:
|
||||||
|
"""
|
||||||
|
Get usage zone internal gains
|
||||||
|
:return: [InternalGains]
|
||||||
|
"""
|
||||||
return self._internal_gains
|
return self._internal_gains
|
||||||
|
|
||||||
@internal_gains.setter
|
@internal_gains.setter
|
||||||
def internal_gains(self, value):
|
def internal_gains(self, value):
|
||||||
|
"""
|
||||||
|
Set usage zone internal gains
|
||||||
|
:param value: [InternalGains]
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
self._internal_gains = value
|
self._internal_gains = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def heating_setpoint(self):
|
def heating_setpoint(self):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
return self._heating_setpoint
|
return self._heating_setpoint
|
||||||
|
|
||||||
@heating_setpoint.setter
|
@heating_setpoint.setter
|
||||||
|
|
Loading…
Reference in New Issue
Block a user