Add code comment to the classes and improve overall quality

This commit is contained in:
Guille Gutierrez 2020-06-11 16:55:52 -04:00
parent 145520c8a2
commit 4284b2cb3e
14 changed files with 77 additions and 312 deletions

View File

@ -7,7 +7,7 @@ from __future__ import annotations
from typing import Union from typing import Union
import numpy as np import numpy as np
import pyny3d.geoms as pn import pyny3d.geoms as pn
from helpers.geometry import Geometry from helpers.geometry_helper import GeometryHelper
class Surface: class Surface:
@ -21,7 +21,7 @@ class Surface:
self._swr = swr self._swr = swr
self._remove_last = remove_last self._remove_last = remove_last
self._is_projected = is_projected self._is_projected = is_projected
self._geometry = Geometry() self._geometry_helper = GeometryHelper()
self._polygon = None self._polygon = None
self._ground_polygon = None self._ground_polygon = None
self._area = None self._area = None
@ -89,7 +89,7 @@ class Surface:
""" """
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 = GeometryHelper.to_points_matrix(self._points, self._remove_last)
return self._points return self._points
def _min_coord(self, axis): def _min_coord(self, axis):
@ -153,7 +153,7 @@ class Surface:
coordinates = coordinates + ' ' coordinates = coordinates + ' '
coordinates = coordinates + str(x) + ' ' + str(y) + ' ' + str(z) coordinates = coordinates + str(x) + ' ' + str(y) + ' ' + str(z)
self._ground_points = np.fromstring(coordinates, dtype=float, sep=' ') 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 return self._ground_points
@property @property
@ -309,7 +309,7 @@ class Surface:
""" """
if self.type != 'Wall' or surface.type != 'Wall': if self.type != 'Wall' or surface.type != 'Wall':
return 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 intersection_area = self.intersect(surface).area
self.add_shared(surface, intersection_area) self.add_shared(surface, intersection_area)
surface.add_shared(self, intersection_area) surface.add_shared(self, intersection_area)

View File

@ -7,7 +7,7 @@ from typing import List
from city_model_structure.thermal_opening import ThermalOpening from city_model_structure.thermal_opening import ThermalOpening
from city_model_structure.thermal_zone import ThermalZone from city_model_structure.thermal_zone import ThermalZone
from city_model_structure.layer import Layer from city_model_structure.layer import Layer
from helpers.configuration import Configuration from helpers.configuration_helper import ConfigurationHelper
class ThermalBoundary: 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 # 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._thermal_openings = [ThermalOpening()]
self._layers = None 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_thermal_absorptance = None
self._outside_visible_absorptance = None self._outside_visible_absorptance = None
self._window_ratio = None self._window_ratio = None
@ -208,8 +208,8 @@ class ThermalBoundary:
:return: float :return: float
""" """
if self._u_value is None: if self._u_value is None:
h_i = Configuration().h_i h_i = ConfigurationHelper().h_i
h_e = Configuration().h_e h_e = ConfigurationHelper().h_e
r_value = 1.0/h_i + 1.0/h_e r_value = 1.0/h_i + 1.0/h_e
try: try:
for layer in self.layers: for layer in self.layers:

View File

@ -3,7 +3,7 @@ ThermalOpening module
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
from helpers.configuration import Configuration from helpers.configuration_helper import ConfigurationHelper
class ThermalOpening: class ThermalOpening:
@ -13,7 +13,7 @@ class ThermalOpening:
def __init__(self): def __init__(self):
self._openable_ratio = None self._openable_ratio = None
self._conductivity = None self._conductivity = None
self._frame_ratio = Configuration().frame_ratio self._frame_ratio = ConfigurationHelper().frame_ratio
self._g_value = None self._g_value = None
self._thickness = None self._thickness = None
self._front_side_solar_transmittance_at_normal_incidence = 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. # This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read.
self._conductivity = value self._conductivity = value
if self._overall_u_value is None and self.thickness is not None: if self._overall_u_value is None and self.thickness is not None:
h_i = Configuration().h_i h_i = ConfigurationHelper().h_i
h_e = Configuration().h_e h_e = ConfigurationHelper().h_e
r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness) r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness)
self._overall_u_value = 1 / r_value 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. # This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read.
self._thickness = value self._thickness = value
if self._overall_u_value is None and self.conductivity is not None: if self._overall_u_value is None and self.conductivity is not None:
h_i = Configuration().h_i h_i = ConfigurationHelper().h_i
h_e = Configuration().h_e h_e = ConfigurationHelper().h_e
r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness) r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness)
self._overall_u_value = 1 / r_value self._overall_u_value = 1 / r_value
@ -156,7 +156,7 @@ class ThermalOpening:
@property @property
def overall_u_value(self): def overall_u_value(self):
""" """
Get thermal opening overall u value Get thermal opening overall u value in W/m2K
:return: float :return: float
""" """
return self._overall_u_value return self._overall_u_value
@ -164,7 +164,7 @@ class ThermalOpening:
@overall_u_value.setter @overall_u_value.setter
def overall_u_value(self, value): def overall_u_value(self, value):
""" """
Get thermal opening overall u value Get thermal opening overall u value in W/m2K
:param value: float :param value: float
:return: None :return: None
""" """

View File

@ -6,7 +6,7 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
from typing import List, TypeVar from typing import List, TypeVar
from city_model_structure.usage_zone import UsageZone from city_model_structure.usage_zone import UsageZone
from city_model_structure.surface import Surface from city_model_structure.surface import Surface
from helpers.configuration import Configuration from helpers.configuration_helper import ConfigurationHelper
ThermalBoundary = TypeVar('ThermalBoundary') ThermalBoundary = TypeVar('ThermalBoundary')
@ -19,12 +19,12 @@ class ThermalZone:
self._surfaces = surfaces self._surfaces = surfaces
self._floor_area = None self._floor_area = None
self._bounded = None self._bounded = None
self._heated = Configuration().heated self._heated = ConfigurationHelper().heated
self._cooled = Configuration().cooled self._cooled = ConfigurationHelper().cooled
self._additional_thermal_bridge_u_value = Configuration().additional_thermal_bridge_u_value self._additional_thermal_bridge_u_value = ConfigurationHelper().additional_thermal_bridge_u_value
self._effective_thermal_capacity = None self._effective_thermal_capacity = None
self._indirectly_heated_area_ratio = Configuration().indirectly_heated_area_ratio self._indirectly_heated_area_ratio = ConfigurationHelper().indirectly_heated_area_ratio
self._infiltration_rate_system_on = Configuration().infiltration_rate_system_on self._infiltration_rate_system_on = ConfigurationHelper().infiltration_rate_system_on
self._infiltration_rate_system_off = None self._infiltration_rate_system_off = None
self._usage_zones = None self._usage_zones = None
@ -85,7 +85,7 @@ class ThermalZone:
@property @property
def additional_thermal_bridge_u_value(self): 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: float
""" """
return self._additional_thermal_bridge_u_value return self._additional_thermal_bridge_u_value
@ -93,7 +93,7 @@ class ThermalZone:
@additional_thermal_bridge_u_value.setter @additional_thermal_bridge_u_value.setter
def additional_thermal_bridge_u_value(self, value): 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 :param value: float
:return: None :return: None
""" """

View File

@ -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')

View File

@ -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

View File

@ -35,7 +35,7 @@ class UsBasePhysicsParameters:
archetype = self._search_archetype(building_type, archetype = self._search_archetype(building_type,
UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction), UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction),
self._climate_zone) 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 # ToDo: Raise WrongArchetype if not all the surface types are defined for the given city_object
if archetype is None: if archetype is None:
print(building_type, UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction), print(building_type, UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction),

View File

@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
from unittest import TestCase from unittest import TestCase
import os
from pathlib import Path from pathlib import Path
from geometry.geometry_factory import GeometryFactory from geometry.geometry_factory import GeometryFactory
import os
class TestGeometryFactory(TestCase): class TestGeometryFactory(TestCase):
@ -21,11 +21,7 @@ class TestGeometryFactory(TestCase):
self._city_gml = None self._city_gml = None
self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve() self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
def get_citygml(self): def _get_citygml(self):
"""
Retrieve the test city gml
:return: City
"""
if self._city_gml is None: if self._city_gml is None:
file_path = (self._example_path / 'buildings.gml').resolve() file_path = (self._example_path / 'buildings.gml').resolve()
self._city_gml = GeometryFactory('citygml', file_path).city self._city_gml = GeometryFactory('citygml', file_path).city
@ -37,7 +33,7 @@ class TestGeometryFactory(TestCase):
Test the City parsing Test the City parsing
:return: None :return: None
""" """
city = self.get_citygml() city = self._get_citygml()
self.assertIsNotNone(city.city_objects, 'city_objects is none') self.assertIsNotNone(city.city_objects, 'city_objects is none')
for city_object in city.city_objects: for city_object in city.city_objects:
self.assertIsNotNone(city.city_object(city_object.name), 'city_object return none') 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 Test city objects in the city
:return: None :return: None
""" """
city = self.get_citygml() city = self._get_citygml()
for city_object in city.city_objects: for city_object in city.city_objects:
self.assertIsNotNone(city_object.name, 'city_object name is none') self.assertIsNotNone(city_object.name, 'city_object name is none')
self.assertIsNotNone(city_object.lod, 'city_object lod is none') self.assertIsNotNone(city_object.lod, 'city_object lod is none')
@ -80,7 +76,7 @@ class TestGeometryFactory(TestCase):
Test surfaces in city objects Test surfaces in city objects
:return: None :return: None
""" """
city = self.get_citygml() city = self._get_citygml()
for city_object in city.city_objects: for city_object in city.city_objects:
for surface in city_object.surfaces: for surface in city_object.surfaces:
self.assertIsNotNone(surface.name, 'surface name is none') self.assertIsNotNone(surface.name, 'surface name is none')
@ -111,7 +107,7 @@ class TestGeometryFactory(TestCase):
Test thermal zones in city objects Test thermal zones in city objects
:return: None :return: None
""" """
city = self.get_citygml() city = self._get_citygml()
for city_object in city.city_objects: for city_object in city.city_objects:
for thermal_zone in city_object.thermal_zones: for thermal_zone in city_object.thermal_zones:
self.assertIsNotNone(thermal_zone.surfaces, 'thermal_zone surfaces is none') self.assertIsNotNone(thermal_zone.surfaces, 'thermal_zone surfaces is none')
@ -137,7 +133,7 @@ class TestGeometryFactory(TestCase):
Test thermal boundaries in thermal zones Test thermal boundaries in thermal zones
:return: None :return: None
""" """
city = self.get_citygml() city = self._get_citygml()
for city_object in city.city_objects: for city_object in city.city_objects:
for thermal_zone in city_object.thermal_zones: for thermal_zone in city_object.thermal_zones:
for thermal_boundary in thermal_zone.bounded: for thermal_boundary in thermal_zone.bounded:
@ -167,7 +163,7 @@ class TestGeometryFactory(TestCase):
Test thermal openings in thermal zones Test thermal openings in thermal zones
:return: None :return: None
""" """
city = self.get_citygml() city = self._get_citygml()
for city_object in city.city_objects: for city_object in city.city_objects:
for thermal_zone in city_object.thermal_zones: for thermal_zone in city_object.thermal_zones:
for thermal_boundary in thermal_zone.bounded: for thermal_boundary in thermal_zone.bounded:

View File

@ -13,26 +13,34 @@ class TestPhysicsFactory(TestCase):
""" """
TestPhysicsFactory TestCase TestPhysicsFactory TestCase
""" """
def setup(self) -> None: def setUp(self) -> None:
"""
Configure test environment
:return:
"""
self._city_gml = None self._city_gml = None
self._nyc_with_physics = None self._nyc_with_physics = None
self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve() self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
def get_citygml(self): def _get_citygml(self):
if self._city_gml is None: if self._city_gml is None:
file_path = (self._example_path / 'buildings.gml').resolve() file_path = (self._example_path / 'buildings.gml').resolve()
self._city_gml = GeometryFactory('citygml', file_path).city self._city_gml = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(self._city_gml, 'city is none') self.assertIsNotNone(self._city_gml, 'city is none')
return self._city_gml return self._city_gml
def get_city_with_physics(self): def _get_city_with_physics(self):
if self._nyc_with_physics is None: 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) PhysicsFactory('us_new_york_city', self._nyc_with_physics, base_path=self._example_path)
return self._nyc_with_physics return self._nyc_with_physics
def test_city_with_physics(self): 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: for city_object in city.city_objects:
self.assertIsNotNone(city_object.average_storey_height, 'average_storey_height is none') self.assertIsNotNone(city_object.average_storey_height, 'average_storey_height is none')
self.assertIsNotNone(city_object.storeys_above_ground, 'storeys_above_ground is none') self.assertIsNotNone(city_object.storeys_above_ground, 'storeys_above_ground is none')

View File

@ -8,22 +8,29 @@ from usage.usage_feeders.us_new_york_city_usage_parameters import UsNewYorkCityU
class UsageFactory: class UsageFactory:
"""
UsageFactory class
"""
def __init__(self, handler, city): def __init__(self, handler, city):
self._handler = handler.lower().replace(' ', '_') self._handler = '_' + handler.lower().replace(' ', '_')
self._city = city self._city = city
self.factory() self.factory()
def us_new_york_city(self): def _us_new_york_city(self):
UsNewYorkCityUsageParameters(self._city) UsNewYorkCityUsageParameters(self._city)
def ca(self): def _ca(self):
raise Exception('Not implemented') raise Exception('Not implemented')
def de(self): def _de(self):
DeUsageParameters(self._city) DeUsageParameters(self._city)
def es(self): def _es(self):
raise Exception('Not implemented') raise Exception('Not implemented')
def factory(self): def factory(self):
"""
Enrich the city with the usage information
:return: None
"""
getattr(self, self._handler, lambda: None)() getattr(self, self._handler, lambda: None)()

View File

@ -3,12 +3,15 @@ DeUsageParameters model the usage properties for a German building
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
import xmltodict
from pathlib import Path from pathlib import Path
import xmltodict
from usage.usage_feeders.helpers.us_function_to_usage import UsFunctionToUsage from usage.usage_feeders.helpers.us_function_to_usage import UsFunctionToUsage
class DeUsageParameters: class DeUsageParameters:
"""
DeUsageParameters
"""
def __init__(self, city_objects): def __init__(self, city_objects):
self._city_objects = city_objects self._city_objects = city_objects
@ -17,4 +20,4 @@ class DeUsageParameters:
with open(path) as xml: with open(path) as xml:
self._library = xmltodict.parse(xml.read()) self._library = xmltodict.parse(xml.read())
for city_object in city_objects: for city_object in city_objects:
UsFunctionToUsage.function_to_usage(city_object.function) UsFunctionToUsage.usage(city_object.function)

View File

@ -3,13 +3,16 @@ UsBaseUsageParameters base class to model the usage properties for a building in
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
import xmltodict
from pathlib import Path from pathlib import Path
import xmltodict
from city_model_structure.usage_zone import UsageZone from city_model_structure.usage_zone import UsageZone
from city_model_structure.internal_gains import InternalGains from city_model_structure.internal_gains import InternalGains
class UsBaseUsageParameters: class UsBaseUsageParameters:
"""
UsBaseUsageParameters class
"""
def __init__(self, city, function_to_usage): def __init__(self, city, function_to_usage):
self._city = city self._city = city
# ToDo: this is using the german library as a temporary approach, need to use/define a library for US # 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: with open(path) as xml:
self._library = xmltodict.parse(xml.read(), force_list='zoneUsageVariant') self._library = xmltodict.parse(xml.read(), force_list='zoneUsageVariant')
for city_object in self._city.city_objects: 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 = UsageZone()
usage_zone.usage = function_to_usage(city_object.function) usage_zone.usage = function_to_usage(city_object.function)
for zone_usage_type in self._library['buildingUsageLibrary']['zoneUsageType']: for zone_usage_type in self._library['buildingUsageLibrary']['zoneUsageType']:
@ -31,14 +34,12 @@ class UsBaseUsageParameters:
city_object.usage_zone = [usage_zone] city_object.usage_zone = [usage_zone]
break break
continue continue
else: city_object.usage_zones = [UsBaseUsageParameters._parse_zone_usage_type(zone_usage_type, usage_zone)]
city_object.usage_zones = [UsBaseUsageParameters._parse_zone_usage_type(zone_usage_type, usage_zone)] break
break
if city_object.usage_zones is None: if city_object.usage_zones is None:
print(city_object.function) print(city_object.function)
raise Exception('Usage not found for building function') raise Exception('Usage not found for building function')
@staticmethod @staticmethod
def _parse_zone_usage_type(zone_usage_type, usage_zone): def _parse_zone_usage_type(zone_usage_type, usage_zone):
usage_zone.hours_day = zone_usage_type['occupancy']['usageHoursPerDay'] usage_zone.hours_day = zone_usage_type['occupancy']['usageHoursPerDay']

View File

@ -8,6 +8,9 @@ from usage.usage_feeders.helpers.us_pluto_to_usage import UsPlutoToUsage as Pu
class UsNewYorkCityUsageParameters(UsBaseUsageParameters): class UsNewYorkCityUsageParameters(UsBaseUsageParameters):
"""
UsNewYorkCityUsageParameters class
"""
def __init__(self, city): def __init__(self, city):
self._city = city self._city = city
super().__init__(self._city, Pu.usage) super().__init__(self._city, Pu.usage)

View File

@ -8,5 +8,8 @@ from usage.usage_feeders.helpers.us_function_to_usage import UsFunctionToUsage
class UsUsageParameters(UsBaseUsageParameters): class UsUsageParameters(UsBaseUsageParameters):
"""
UsUsageParameters class
"""
def __init__(self, city): def __init__(self, city):
super().__init__(city, UsFunctionToUsage.usage) super().__init__(city, UsFunctionToUsage.usage)