Add code comment to the classes and improve overall quality
This commit is contained in:
parent
145520c8a2
commit
4284b2cb3e
|
@ -7,7 +7,7 @@ from __future__ import annotations
|
|||
from typing import Union
|
||||
import numpy as np
|
||||
import pyny3d.geoms as pn
|
||||
from helpers.geometry import Geometry
|
||||
from helpers.geometry_helper import GeometryHelper
|
||||
|
||||
|
||||
class Surface:
|
||||
|
@ -21,7 +21,7 @@ class Surface:
|
|||
self._swr = swr
|
||||
self._remove_last = remove_last
|
||||
self._is_projected = is_projected
|
||||
self._geometry = Geometry()
|
||||
self._geometry_helper = GeometryHelper()
|
||||
self._polygon = None
|
||||
self._ground_polygon = None
|
||||
self._area = None
|
||||
|
@ -89,7 +89,7 @@ class Surface:
|
|||
"""
|
||||
if self._points is None:
|
||||
self._points = np.fromstring(self._coordinates, dtype=float, sep=' ')
|
||||
self._points = Geometry.to_points_matrix(self._points, self._remove_last)
|
||||
self._points = GeometryHelper.to_points_matrix(self._points, self._remove_last)
|
||||
return self._points
|
||||
|
||||
def _min_coord(self, axis):
|
||||
|
@ -153,7 +153,7 @@ class Surface:
|
|||
coordinates = coordinates + ' '
|
||||
coordinates = coordinates + str(x) + ' ' + str(y) + ' ' + str(z)
|
||||
self._ground_points = np.fromstring(coordinates, dtype=float, sep=' ')
|
||||
self._ground_points = Geometry.to_points_matrix(self._ground_points, False)
|
||||
self._ground_points = GeometryHelper.to_points_matrix(self._ground_points, False)
|
||||
return self._ground_points
|
||||
|
||||
@property
|
||||
|
@ -309,7 +309,7 @@ class Surface:
|
|||
"""
|
||||
if self.type != 'Wall' or surface.type != 'Wall':
|
||||
return
|
||||
if self._geometry.is_almost_same_surface(self, surface):
|
||||
if self._geometry_helper.is_almost_same_surface(self, surface):
|
||||
intersection_area = self.intersect(surface).area
|
||||
self.add_shared(surface, intersection_area)
|
||||
surface.add_shared(self, intersection_area)
|
||||
|
|
|
@ -7,7 +7,7 @@ from typing import List
|
|||
from city_model_structure.thermal_opening import ThermalOpening
|
||||
from city_model_structure.thermal_zone import ThermalZone
|
||||
from city_model_structure.layer import Layer
|
||||
from helpers.configuration import Configuration
|
||||
from helpers.configuration_helper import ConfigurationHelper
|
||||
|
||||
|
||||
class ThermalBoundary:
|
||||
|
@ -20,7 +20,7 @@ class ThermalBoundary:
|
|||
# ToDo: up to at least LOD2 will be just one thermal opening per Thermal boundary, review for LOD3 and LOD4
|
||||
self._thermal_openings = [ThermalOpening()]
|
||||
self._layers = None
|
||||
self._outside_solar_absorptance = Configuration().outside_solar_absorptance
|
||||
self._outside_solar_absorptance = ConfigurationHelper().outside_solar_absorptance
|
||||
self._outside_thermal_absorptance = None
|
||||
self._outside_visible_absorptance = None
|
||||
self._window_ratio = None
|
||||
|
@ -208,8 +208,8 @@ class ThermalBoundary:
|
|||
:return: float
|
||||
"""
|
||||
if self._u_value is None:
|
||||
h_i = Configuration().h_i
|
||||
h_e = Configuration().h_e
|
||||
h_i = ConfigurationHelper().h_i
|
||||
h_e = ConfigurationHelper().h_e
|
||||
r_value = 1.0/h_i + 1.0/h_e
|
||||
try:
|
||||
for layer in self.layers:
|
||||
|
|
|
@ -3,7 +3,7 @@ ThermalOpening module
|
|||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
from helpers.configuration import Configuration
|
||||
from helpers.configuration_helper import ConfigurationHelper
|
||||
|
||||
|
||||
class ThermalOpening:
|
||||
|
@ -13,7 +13,7 @@ class ThermalOpening:
|
|||
def __init__(self):
|
||||
self._openable_ratio = None
|
||||
self._conductivity = None
|
||||
self._frame_ratio = Configuration().frame_ratio
|
||||
self._frame_ratio = ConfigurationHelper().frame_ratio
|
||||
self._g_value = None
|
||||
self._thickness = None
|
||||
self._front_side_solar_transmittance_at_normal_incidence = None
|
||||
|
@ -56,8 +56,8 @@ class ThermalOpening:
|
|||
# This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read.
|
||||
self._conductivity = value
|
||||
if self._overall_u_value is None and self.thickness is not None:
|
||||
h_i = Configuration().h_i
|
||||
h_e = Configuration().h_e
|
||||
h_i = ConfigurationHelper().h_i
|
||||
h_e = ConfigurationHelper().h_e
|
||||
r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness)
|
||||
self._overall_u_value = 1 / r_value
|
||||
|
||||
|
@ -114,8 +114,8 @@ class ThermalOpening:
|
|||
# This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read.
|
||||
self._thickness = value
|
||||
if self._overall_u_value is None and self.conductivity is not None:
|
||||
h_i = Configuration().h_i
|
||||
h_e = Configuration().h_e
|
||||
h_i = ConfigurationHelper().h_i
|
||||
h_e = ConfigurationHelper().h_e
|
||||
r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness)
|
||||
self._overall_u_value = 1 / r_value
|
||||
|
||||
|
@ -156,7 +156,7 @@ class ThermalOpening:
|
|||
@property
|
||||
def overall_u_value(self):
|
||||
"""
|
||||
Get thermal opening overall u value
|
||||
Get thermal opening overall u value in W/m2K
|
||||
:return: float
|
||||
"""
|
||||
return self._overall_u_value
|
||||
|
@ -164,7 +164,7 @@ class ThermalOpening:
|
|||
@overall_u_value.setter
|
||||
def overall_u_value(self, value):
|
||||
"""
|
||||
Get thermal opening overall u value
|
||||
Get thermal opening overall u value in W/m2K
|
||||
:param value: float
|
||||
:return: None
|
||||
"""
|
||||
|
|
|
@ -6,7 +6,7 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
|
|||
from typing import List, TypeVar
|
||||
from city_model_structure.usage_zone import UsageZone
|
||||
from city_model_structure.surface import Surface
|
||||
from helpers.configuration import Configuration
|
||||
from helpers.configuration_helper import ConfigurationHelper
|
||||
|
||||
ThermalBoundary = TypeVar('ThermalBoundary')
|
||||
|
||||
|
@ -19,12 +19,12 @@ class ThermalZone:
|
|||
self._surfaces = surfaces
|
||||
self._floor_area = None
|
||||
self._bounded = None
|
||||
self._heated = Configuration().heated
|
||||
self._cooled = Configuration().cooled
|
||||
self._additional_thermal_bridge_u_value = Configuration().additional_thermal_bridge_u_value
|
||||
self._heated = ConfigurationHelper().heated
|
||||
self._cooled = ConfigurationHelper().cooled
|
||||
self._additional_thermal_bridge_u_value = ConfigurationHelper().additional_thermal_bridge_u_value
|
||||
self._effective_thermal_capacity = None
|
||||
self._indirectly_heated_area_ratio = Configuration().indirectly_heated_area_ratio
|
||||
self._infiltration_rate_system_on = Configuration().infiltration_rate_system_on
|
||||
self._indirectly_heated_area_ratio = ConfigurationHelper().indirectly_heated_area_ratio
|
||||
self._infiltration_rate_system_on = ConfigurationHelper().infiltration_rate_system_on
|
||||
self._infiltration_rate_system_off = None
|
||||
self._usage_zones = None
|
||||
|
||||
|
@ -85,7 +85,7 @@ class ThermalZone:
|
|||
@property
|
||||
def additional_thermal_bridge_u_value(self):
|
||||
"""
|
||||
Get thermal zone additional thermal bridge u value
|
||||
Get thermal zone additional thermal bridge u value W/m2K
|
||||
:return: float
|
||||
"""
|
||||
return self._additional_thermal_bridge_u_value
|
||||
|
@ -93,7 +93,7 @@ class ThermalZone:
|
|||
@additional_thermal_bridge_u_value.setter
|
||||
def additional_thermal_bridge_u_value(self, value):
|
||||
"""
|
||||
Set thermal zone additional thermal bridge u value
|
||||
Set thermal zone additional thermal bridge u value W/m2K
|
||||
:param value: float
|
||||
:return: None
|
||||
"""
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
"""
|
||||
Configuration helper
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
import configparser
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class Configuration:
|
||||
"""
|
||||
Configuration class
|
||||
"""
|
||||
def __init__(self):
|
||||
base_path = Path().resolve().parent
|
||||
config_file = Path(base_path / 'libs/config/configuration.ini').resolve()
|
||||
self._config = configparser.ConfigParser()
|
||||
self._config.read(config_file)
|
||||
|
||||
@property
|
||||
def h_i(self):
|
||||
"""
|
||||
Configured internal convective coefficient in W/m2K
|
||||
:return: float
|
||||
"""
|
||||
return self._config.getfloat('convective_fluxes', 'h_i')
|
||||
|
||||
@property
|
||||
def h_e(self):
|
||||
"""
|
||||
Configured external convective coefficient in W/m2K
|
||||
:return: float
|
||||
"""
|
||||
return self._config.getfloat('convective_fluxes', 'h_e')
|
||||
|
||||
@property
|
||||
def frame_ratio(self):
|
||||
"""
|
||||
Configured frame ratio
|
||||
:return: float
|
||||
"""
|
||||
return self._config.getfloat('windows', 'frame_ratio')
|
||||
|
||||
@property
|
||||
def heated(self):
|
||||
"""
|
||||
Configured heated flag
|
||||
:return: Boolean
|
||||
"""
|
||||
return self._config.getboolean('thermal_zones', 'heated')
|
||||
|
||||
@property
|
||||
def cooled(self):
|
||||
"""
|
||||
Configured cooled flag
|
||||
:return: Boolean
|
||||
"""
|
||||
return self._config.getboolean('thermal_zones', 'cooled')
|
||||
|
||||
@property
|
||||
def additional_thermal_bridge_u_value(self):
|
||||
"""
|
||||
Configured additional thermal bridge u value W/m2K
|
||||
:return:
|
||||
"""
|
||||
return self._config.getfloat('thermal_zones', 'additional_thermal_bridge_u_value')
|
||||
|
||||
@property
|
||||
def indirectly_heated_area_ratio(self):
|
||||
"""
|
||||
Configured indirectly heated area ratio
|
||||
:return: float
|
||||
"""
|
||||
|
||||
return self._config.getfloat('thermal_zones', 'indirectly_heated_area_ratio')
|
||||
|
||||
@property
|
||||
def infiltration_rate_system_on(self):
|
||||
"""
|
||||
Configured infiltration rate system on in air change per hour
|
||||
:return: float
|
||||
"""
|
||||
return self._config.getfloat('thermal_zones', 'infiltration_rate_system_on')
|
||||
|
||||
@property
|
||||
def outside_solar_absorptance(self):
|
||||
"""
|
||||
Configured infiltration rate system off in air change per hour
|
||||
:return: float
|
||||
"""
|
||||
return self._config.getfloat('thermal_zones', 'outside_solar_absorptance')
|
|
@ -1,165 +0,0 @@
|
|||
"""
|
||||
Geometry helper
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
import math
|
||||
import numpy as np
|
||||
from trimesh import Trimesh
|
||||
from trimesh import intersections
|
||||
import open3d as o3d
|
||||
|
||||
|
||||
class Geometry:
|
||||
"""
|
||||
Geometry helper class
|
||||
"""
|
||||
def __init__(self, delta=0.5):
|
||||
self._delta = delta
|
||||
|
||||
def almost_equal(self, v1, v2):
|
||||
"""
|
||||
Compare two points and decides if they are almost equal (quadratic error under delta)
|
||||
:param v1: [x,y,z]
|
||||
:param v2: [x,y,z]
|
||||
:return: Boolean
|
||||
"""
|
||||
delta = math.sqrt(pow((v1[0] - v2[0]), 2) + pow((v1[1] - v2[1]), 2) + pow((v1[2] - v2[2]), 2))
|
||||
return delta <= self._delta
|
||||
|
||||
def is_almost_same_surface(self, s1, s2):
|
||||
"""
|
||||
Compare two surfaces and decides if they are almost equal (quadratic error under delta)
|
||||
:param s1: Surface
|
||||
:param s2: Surface
|
||||
:return: Boolean
|
||||
"""
|
||||
# delta is grads an need to be converted into radians
|
||||
delta = np.rad2deg(self._delta)
|
||||
difference = (s1.inclination - s2.inclination) % math.pi
|
||||
if abs(difference) > delta:
|
||||
return False
|
||||
# s1 and s2 are at least almost parallel surfaces
|
||||
# calculate distance point to plane using all the vertex
|
||||
# select surface1 value for the point (X,Y,Z) where two of the values are 0
|
||||
minimum_distance = self._delta + 1
|
||||
parametric = s2.polygon.get_parametric()
|
||||
n2 = s2.normal
|
||||
for point in s1.points:
|
||||
distance = abs(
|
||||
(point[0] * parametric[0]) + (point[1] * parametric[1]) + (point[2] * parametric[2]) + parametric[3])
|
||||
normal_module = math.sqrt(pow(n2[0], 2) + pow(n2[1], 2) + pow(n2[2], 2))
|
||||
|
||||
if normal_module == 0:
|
||||
continue
|
||||
distance = distance / normal_module
|
||||
if distance < minimum_distance:
|
||||
minimum_distance = distance
|
||||
if minimum_distance <= self._delta:
|
||||
break
|
||||
if minimum_distance > self._delta or s1.intersect(s2) is None:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def to_points_matrix(points, remove_last=False):
|
||||
"""
|
||||
Transform a point vector into a point matrix
|
||||
:param points: [x, y, z, x, y, z ...]
|
||||
:param remove_last: Boolean
|
||||
:return: [[x,y,z],[x,y,z]...]
|
||||
"""
|
||||
rows = points.size // 3
|
||||
points = points.reshape(rows, 3)
|
||||
if remove_last:
|
||||
points = np.delete(points, rows - 1, 0)
|
||||
return points
|
||||
|
||||
@staticmethod
|
||||
def _segment_list_to_point_cloud(segment_list):
|
||||
point_list = np.asarray(segment_list[0])
|
||||
for segment in segment_list:
|
||||
for new_point in segment:
|
||||
found = False
|
||||
for point in point_list:
|
||||
same_point = np.allclose(new_point, point)
|
||||
if same_point:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
point_list = np.concatenate((point_list, [new_point]))
|
||||
return point_list
|
||||
|
||||
@staticmethod
|
||||
def _point_cloud_to_mesh(point_list, normal_list):
|
||||
# Return a mesh composed only by triangles
|
||||
pcd = o3d.geometry.PointCloud()
|
||||
pcd.points = o3d.utility.Vector3dVector(point_list)
|
||||
pcd.normals = o3d.utility.Vector3dVector(normal_list)
|
||||
distances = pcd.compute_nearest_neighbor_distance()
|
||||
avg_dist = np.mean(distances)
|
||||
radius = 3 * avg_dist
|
||||
bpa_mesh = o3d.geometry.TriangleMesh().create_from_point_cloud_ball_pivoting(
|
||||
pcd, o3d.utility.DoubleVector([radius, radius * 2]))
|
||||
mesh_result = Trimesh(vertices=np.asarray(bpa_mesh.vertices), faces=np.asarray(bpa_mesh.triangles))
|
||||
return mesh_result
|
||||
|
||||
@staticmethod
|
||||
def _merge_meshes(mesh1, mesh2):
|
||||
v_1 = mesh1.vertices
|
||||
f_1 = mesh1.faces
|
||||
v_2 = mesh2.vertices
|
||||
f_2 = mesh2.faces
|
||||
length = len(v_1)
|
||||
v_merge = np.concatenate((v_1, v_2))
|
||||
f_merge = np.asarray(f_1)
|
||||
|
||||
for item in f_2:
|
||||
point1 = item.item(0) + length
|
||||
point2 = item.item(1) + length
|
||||
point3 = item.item(2) + length
|
||||
surface = np.asarray([point1, point2, point3])
|
||||
f_merge = np.concatenate((f_merge, [surface]))
|
||||
|
||||
mesh_merge = Trimesh(vertices=v_merge, faces=f_merge)
|
||||
|
||||
return mesh_merge
|
||||
|
||||
@staticmethod
|
||||
def divide_mesh_by_plane(mesh, normal_plane, point_plane):
|
||||
"""
|
||||
Divide a mesh by a plane
|
||||
:param mesh: Trimesh
|
||||
:param normal_plane: [x, y, z]
|
||||
:param point_plane: [x, y, z]
|
||||
:return: [Trimesh]
|
||||
"""
|
||||
# The first mesh returns the positive side of the plane and the second the negative side.
|
||||
# If the plane does not divide the mesh (i.e. it does not touch it or it is coplanar with one or more faces),
|
||||
# then it returns only the original mesh.
|
||||
normal_plane_opp = [None] * len(normal_plane)
|
||||
for i in range(0, len(normal_plane)):
|
||||
normal_plane_opp[i] = - normal_plane[i]
|
||||
|
||||
normal = [normal_plane, normal_plane_opp]
|
||||
normal_opp = [normal_plane_opp, normal_plane]
|
||||
mesh_final = []
|
||||
for i in range(0, 2):
|
||||
mesh_1 = intersections.slice_mesh_plane(mesh, normal[i], point_plane)
|
||||
mesh_1_segments = intersections.mesh_plane(mesh, normal[i], point_plane)
|
||||
boo = mesh.difference(mesh_1, engine='blender')
|
||||
print(boo)
|
||||
quit()
|
||||
if len(mesh_1_segments) <= 0 or len(mesh_1.faces) == len(mesh.faces):
|
||||
mesh_final.append(mesh)
|
||||
break
|
||||
else:
|
||||
points = Geometry._segment_list_to_point_cloud(mesh_1_segments)
|
||||
points_normals = [[None] * 3] * len(points)
|
||||
for j in range(0, len(points_normals)):
|
||||
points_normals[j] = normal_opp[i]
|
||||
mesh_2 = Geometry._point_cloud_to_mesh(points, points_normals)
|
||||
mesh_final.append(Geometry._merge_meshes(mesh_1, mesh_2))
|
||||
|
||||
return mesh_final
|
|
@ -35,7 +35,7 @@ class UsBasePhysicsParameters:
|
|||
archetype = self._search_archetype(building_type,
|
||||
UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction),
|
||||
self._climate_zone)
|
||||
# ToDo:remove this in the future
|
||||
# ToDo: remove this in the future
|
||||
# ToDo: Raise WrongArchetype if not all the surface types are defined for the given city_object
|
||||
if archetype is None:
|
||||
print(building_type, UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction),
|
||||
|
|
|
@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
from unittest import TestCase
|
||||
import os
|
||||
from pathlib import Path
|
||||
from geometry.geometry_factory import GeometryFactory
|
||||
import os
|
||||
|
||||
|
||||
class TestGeometryFactory(TestCase):
|
||||
|
@ -21,11 +21,7 @@ class TestGeometryFactory(TestCase):
|
|||
self._city_gml = None
|
||||
self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
|
||||
|
||||
def get_citygml(self):
|
||||
"""
|
||||
Retrieve the test city gml
|
||||
:return: City
|
||||
"""
|
||||
def _get_citygml(self):
|
||||
if self._city_gml is None:
|
||||
file_path = (self._example_path / 'buildings.gml').resolve()
|
||||
self._city_gml = GeometryFactory('citygml', file_path).city
|
||||
|
@ -37,7 +33,7 @@ class TestGeometryFactory(TestCase):
|
|||
Test the City parsing
|
||||
:return: None
|
||||
"""
|
||||
city = self.get_citygml()
|
||||
city = self._get_citygml()
|
||||
self.assertIsNotNone(city.city_objects, 'city_objects is none')
|
||||
for city_object in city.city_objects:
|
||||
self.assertIsNotNone(city.city_object(city_object.name), 'city_object return none')
|
||||
|
@ -52,7 +48,7 @@ class TestGeometryFactory(TestCase):
|
|||
Test city objects in the city
|
||||
:return: None
|
||||
"""
|
||||
city = self.get_citygml()
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
self.assertIsNotNone(city_object.name, 'city_object name is none')
|
||||
self.assertIsNotNone(city_object.lod, 'city_object lod is none')
|
||||
|
@ -80,7 +76,7 @@ class TestGeometryFactory(TestCase):
|
|||
Test surfaces in city objects
|
||||
:return: None
|
||||
"""
|
||||
city = self.get_citygml()
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for surface in city_object.surfaces:
|
||||
self.assertIsNotNone(surface.name, 'surface name is none')
|
||||
|
@ -111,7 +107,7 @@ class TestGeometryFactory(TestCase):
|
|||
Test thermal zones in city objects
|
||||
:return: None
|
||||
"""
|
||||
city = self.get_citygml()
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for thermal_zone in city_object.thermal_zones:
|
||||
self.assertIsNotNone(thermal_zone.surfaces, 'thermal_zone surfaces is none')
|
||||
|
@ -137,7 +133,7 @@ class TestGeometryFactory(TestCase):
|
|||
Test thermal boundaries in thermal zones
|
||||
:return: None
|
||||
"""
|
||||
city = self.get_citygml()
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for thermal_zone in city_object.thermal_zones:
|
||||
for thermal_boundary in thermal_zone.bounded:
|
||||
|
@ -167,7 +163,7 @@ class TestGeometryFactory(TestCase):
|
|||
Test thermal openings in thermal zones
|
||||
:return: None
|
||||
"""
|
||||
city = self.get_citygml()
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for thermal_zone in city_object.thermal_zones:
|
||||
for thermal_boundary in thermal_zone.bounded:
|
||||
|
|
|
@ -13,26 +13,34 @@ class TestPhysicsFactory(TestCase):
|
|||
"""
|
||||
TestPhysicsFactory TestCase
|
||||
"""
|
||||
def setup(self) -> None:
|
||||
def setUp(self) -> None:
|
||||
"""
|
||||
Configure test environment
|
||||
:return:
|
||||
"""
|
||||
self._city_gml = None
|
||||
self._nyc_with_physics = None
|
||||
self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
|
||||
|
||||
def get_citygml(self):
|
||||
def _get_citygml(self):
|
||||
if self._city_gml is None:
|
||||
file_path = (self._example_path / 'buildings.gml').resolve()
|
||||
self._city_gml = GeometryFactory('citygml', file_path).city
|
||||
self.assertIsNotNone(self._city_gml, 'city is none')
|
||||
return self._city_gml
|
||||
|
||||
def get_city_with_physics(self):
|
||||
def _get_city_with_physics(self):
|
||||
if self._nyc_with_physics is None:
|
||||
self._nyc_with_physics = self.get_citygml()
|
||||
self._nyc_with_physics = self._get_citygml()
|
||||
PhysicsFactory('us_new_york_city', self._nyc_with_physics, base_path=self._example_path)
|
||||
return self._nyc_with_physics
|
||||
|
||||
def test_city_with_physics(self):
|
||||
city = self.get_city_with_physics()
|
||||
"""
|
||||
Enrich the city with the physic information and verify ot
|
||||
:return: None
|
||||
"""
|
||||
city = self._get_city_with_physics()
|
||||
for city_object in city.city_objects:
|
||||
self.assertIsNotNone(city_object.average_storey_height, 'average_storey_height is none')
|
||||
self.assertIsNotNone(city_object.storeys_above_ground, 'storeys_above_ground is none')
|
||||
|
|
|
@ -8,22 +8,29 @@ from usage.usage_feeders.us_new_york_city_usage_parameters import UsNewYorkCityU
|
|||
|
||||
|
||||
class UsageFactory:
|
||||
"""
|
||||
UsageFactory class
|
||||
"""
|
||||
def __init__(self, handler, city):
|
||||
self._handler = handler.lower().replace(' ', '_')
|
||||
self._handler = '_' + handler.lower().replace(' ', '_')
|
||||
self._city = city
|
||||
self.factory()
|
||||
|
||||
def us_new_york_city(self):
|
||||
def _us_new_york_city(self):
|
||||
UsNewYorkCityUsageParameters(self._city)
|
||||
|
||||
def ca(self):
|
||||
def _ca(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
def de(self):
|
||||
def _de(self):
|
||||
DeUsageParameters(self._city)
|
||||
|
||||
def es(self):
|
||||
def _es(self):
|
||||
raise Exception('Not implemented')
|
||||
|
||||
def factory(self):
|
||||
"""
|
||||
Enrich the city with the usage information
|
||||
:return: None
|
||||
"""
|
||||
getattr(self, self._handler, lambda: None)()
|
||||
|
|
|
@ -3,12 +3,15 @@ DeUsageParameters model the usage properties for a German building
|
|||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
import xmltodict
|
||||
from pathlib import Path
|
||||
import xmltodict
|
||||
from usage.usage_feeders.helpers.us_function_to_usage import UsFunctionToUsage
|
||||
|
||||
|
||||
class DeUsageParameters:
|
||||
"""
|
||||
DeUsageParameters
|
||||
"""
|
||||
def __init__(self, city_objects):
|
||||
self._city_objects = city_objects
|
||||
|
||||
|
@ -17,4 +20,4 @@ class DeUsageParameters:
|
|||
with open(path) as xml:
|
||||
self._library = xmltodict.parse(xml.read())
|
||||
for city_object in city_objects:
|
||||
UsFunctionToUsage.function_to_usage(city_object.function)
|
||||
UsFunctionToUsage.usage(city_object.function)
|
||||
|
|
|
@ -3,13 +3,16 @@ UsBaseUsageParameters base class to model the usage properties for a building in
|
|||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
import xmltodict
|
||||
from pathlib import Path
|
||||
import xmltodict
|
||||
from city_model_structure.usage_zone import UsageZone
|
||||
from city_model_structure.internal_gains import InternalGains
|
||||
|
||||
|
||||
class UsBaseUsageParameters:
|
||||
"""
|
||||
UsBaseUsageParameters class
|
||||
"""
|
||||
def __init__(self, city, function_to_usage):
|
||||
self._city = city
|
||||
# ToDo: this is using the german library as a temporary approach, need to use/define a library for US
|
||||
|
@ -17,7 +20,7 @@ class UsBaseUsageParameters:
|
|||
with open(path) as xml:
|
||||
self._library = xmltodict.parse(xml.read(), force_list='zoneUsageVariant')
|
||||
for city_object in self._city.city_objects:
|
||||
#ToDo: Right now is just one usage zone but will be multiple in the future
|
||||
# ToDo: Right now is just one usage zone but will be multiple in the future
|
||||
usage_zone = UsageZone()
|
||||
usage_zone.usage = function_to_usage(city_object.function)
|
||||
for zone_usage_type in self._library['buildingUsageLibrary']['zoneUsageType']:
|
||||
|
@ -31,14 +34,12 @@ class UsBaseUsageParameters:
|
|||
city_object.usage_zone = [usage_zone]
|
||||
break
|
||||
continue
|
||||
else:
|
||||
city_object.usage_zones = [UsBaseUsageParameters._parse_zone_usage_type(zone_usage_type, usage_zone)]
|
||||
break
|
||||
city_object.usage_zones = [UsBaseUsageParameters._parse_zone_usage_type(zone_usage_type, usage_zone)]
|
||||
break
|
||||
if city_object.usage_zones is None:
|
||||
print(city_object.function)
|
||||
raise Exception('Usage not found for building function')
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _parse_zone_usage_type(zone_usage_type, usage_zone):
|
||||
usage_zone.hours_day = zone_usage_type['occupancy']['usageHoursPerDay']
|
||||
|
|
|
@ -8,6 +8,9 @@ from usage.usage_feeders.helpers.us_pluto_to_usage import UsPlutoToUsage as Pu
|
|||
|
||||
|
||||
class UsNewYorkCityUsageParameters(UsBaseUsageParameters):
|
||||
"""
|
||||
UsNewYorkCityUsageParameters class
|
||||
"""
|
||||
def __init__(self, city):
|
||||
self._city = city
|
||||
super().__init__(self._city, Pu.usage)
|
||||
|
|
|
@ -8,5 +8,8 @@ from usage.usage_feeders.helpers.us_function_to_usage import UsFunctionToUsage
|
|||
|
||||
|
||||
class UsUsageParameters(UsBaseUsageParameters):
|
||||
"""
|
||||
UsUsageParameters class
|
||||
"""
|
||||
def __init__(self, city):
|
||||
super().__init__(city, UsFunctionToUsage.usage)
|
||||
|
|
Loading…
Reference in New Issue
Block a user