Add code comment to the classes and improve overall quality

This commit is contained in:
Guille Gutierrez 2020-06-11 15:45:11 -04:00
parent 22dc10c532
commit 145520c8a2
17 changed files with 458 additions and 61 deletions

View File

@ -4,10 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from __future__ import annotations
from typing import Union
import numpy as np
import pyny3d.geoms as pn
from helpers.geometry import Geometry
from typing import Union
class Surface:
@ -207,9 +207,9 @@ class Surface:
def _is_almost_same_terrain(self, terrain_points, ground_points):
equal = 0
for t in terrain_points:
for g in ground_points:
if self._geometry.almost_equal(t, g):
for terrain_point in terrain_points:
for ground_point in ground_points:
if self._geometry.almost_equal(terrain_point, ground_point):
equal += 1
return equal == len(terrain_points)
@ -250,8 +250,8 @@ class Surface:
"""
if self._normal is None:
points = self.points
n = np.cross(points[1] - points[0], points[2] - points[0])
self._normal = n / np.linalg.norm(n)
cross_product = np.cross(points[1] - points[0], points[2] - points[0])
self._normal = cross_product / np.linalg.norm(cross_product)
return self._normal
@property
@ -283,7 +283,7 @@ class Surface:
"""
if self._type is None:
grad = np.rad2deg(self.inclination)
if 170 <= grad:
if grad >= 170:
self._type = 'Ground'
elif 80 <= grad <= 100:
self._type = 'Wall'
@ -307,7 +307,7 @@ class Surface:
:param surface: Surface
:return: None
"""
if self.type is not 'Wall' or surface.type is not 'Wall':
if self.type != 'Wall' or surface.type != 'Wall':
return
if self._geometry.is_almost_same_surface(self, surface):
intersection_area = self.intersect(surface).area

View File

@ -3,14 +3,17 @@ ThermalBoundary module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
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 typing import List
class ThermalBoundary:
"""
ThermalBoundary class
"""
def __init__(self, surface, delimits):
self._surface = surface
self._delimits = delimits
@ -27,83 +30,169 @@ class ThermalBoundary:
@property
def delimits(self) -> List[ThermalZone]:
"""
Get the thermal zones delimited by the thermal boundary
:return: [ThermalZone]
"""
return self._delimits
@property
def azimuth(self):
"""
Thermal boundary azimuth in radians
:return: float
"""
return self._surface.azimuth
@property
def inclination(self):
"""
Thermal boundary inclination in radians
:return: float
"""
return self._surface.inclination
@property
def area(self):
"""
Thermal boundary area in square meters
:return: float
"""
return self._surface.area
@property
def area_above_ground(self):
"""
Thermal boundary area above ground in square meters
:return: float
"""
return self._surface.area_above_ground
@property
def area_below_ground(self):
"""
Thermal boundary area below ground in square meters
:return: float
"""
return self._surface.area_below_ground
@property
def outside_solar_absorptance(self):
"""
Get thermal boundary outside solar absorptance
:return: 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
:return: None
"""
self._outside_solar_absorptance = value
self._shortwave_reflectance = 1.0 - float(value)
@property
def outside_thermal_absorptance(self):
"""
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
:return: None
"""
self._outside_thermal_absorptance = value
@property
def outside_visible_absorptance(self):
"""
Get thermal boundary outside visible absorptance
:return: 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
:return: None
"""
self._outside_visible_absorptance = value
@property
def thermal_openings(self) -> List[ThermalOpening]:
"""
Get thermal boundary thermal openings
:return: [ThermalOpening]
"""
return self._thermal_openings
@thermal_openings.setter
def thermal_openings(self, value):
"""
Set thermal boundary thermal openings
:param value: [ThermalOpening]
:return: None
"""
self._thermal_openings = value
@property
def layers(self) -> List[Layer]:
"""
Get thermal boundary layers
:return: [Layers]
"""
return self._layers
@layers.setter
def layers(self, value):
"""
Set thermal boundary layers
:param value: [Layer]
:return: None
"""
self._layers = value
@property
def type(self):
"""
Thermal boundary surface type
:return: str
"""
return self._surface.type
@property
def window_ratio(self):
"""
Get thermal boundary window ratio
:return: float
"""
return self._window_ratio
@window_ratio.setter
def window_ratio(self, value):
"""
Set thermal boundary window ratio
:param value: float
:return: None
"""
self._window_ratio = value
@property
def window_area(self):
"""
Thermal boundary window area in square meters
:return: float
"""
if self._window_area is None:
try:
self._window_area = float(self._surface.area) * float(self.window_ratio)
@ -113,6 +202,11 @@ class ThermalBoundary:
@property
def u_value(self):
"""
Thermal boundary u value in W/m2K
internal and external convective coefficient in W/m2K values, can be configured at configuration.ini
:return: float
"""
if self._u_value is None:
h_i = Configuration().h_i
h_e = Configuration().h_e
@ -130,9 +224,18 @@ class ThermalBoundary:
@property
def shortwave_reflectance(self):
"""
Get thermal boundary shortwave reflectance
:return: float
"""
return self._shortwave_reflectance
@shortwave_reflectance.setter
def shortwave_reflectance(self, value):
"""
Set thermal boundary shortwave reflectance
:param value: float
:return:
"""
self._shortwave_reflectance = value
self._outside_solar_absorptance = 1.0 - float(value)

View File

@ -7,90 +7,165 @@ from helpers.configuration import Configuration
class ThermalOpening:
"""
ThermalOpening class
"""
def __init__(self):
self._openable_ratio = None
self._conductivity_w_mk = None
self._conductivity = None
self._frame_ratio = Configuration().frame_ratio
self._g_value = None
self._thickness_m = 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
@property
def openable_ratio(self):
"""
Get thermal opening openable ratio, NOT IMPLEMENTED
:return: Exception
"""
raise Exception('Not implemented')
@openable_ratio.setter
def openable_ratio(self, value):
"""
Set thermal opening openable ratio, NOT IMPLEMENTED
:param value: Any
:return: Exception
"""
raise Exception('Not implemented')
@property
def conductivity_w_mk(self):
return self._conductivity_w_mk
def conductivity(self):
"""
Get thermal opening conductivity in W/mK
:return: float
"""
return self._conductivity
@conductivity_w_mk.setter
def conductivity_w_mk(self, value):
@conductivity.setter
def conductivity(self, value):
"""
Get thermal opening conductivity in W/mK
:param value: float
:return: None
"""
# The code to calculate overall_u_value is duplicated here and in thickness_m.
# This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read.
self._conductivity_w_mk = value
if self._overall_u_value is None and self.thickness_m is not None:
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
r_value = 1 / h_i + 1 / h_e + float(self.conductivity_w_mk) / float(self.thickness_m)
r_value = 1 / h_i + 1 / h_e + float(self.conductivity) / float(self.thickness)
self._overall_u_value = 1 / r_value
@property
def frame_ratio(self):
"""
Get thermal opening frame ratio
:return: float
"""
return self._frame_ratio
@frame_ratio.setter
def frame_ratio(self, value):
"""
Set thermal opening frame ratio
:param value: float
:return: None
"""
self._frame_ratio = value
@property
def g_value(self):
"""
Get thermal opening g value
:return: float
"""
return self._g_value
@g_value.setter
def g_value(self, value):
"""
Set thermal opening g value
:param value:
:return:
"""
self._g_value = value
@property
def thickness_m(self):
return self._thickness_m
def thickness(self):
"""
Get thermal opening thickness in meters
:return:
"""
return self._thickness
@thickness_m.setter
def thickness_m(self, value):
# The code to calculate overall_u_value is duplicated here and in conductivity_w_mk.
@thickness.setter
def thickness(self, value):
"""
Set thermal opening thickness in meters
:param value: float
:return: None
"""
# The code to calculate overall_u_value is duplicated here and in conductivity.
# This ensures a more robust code that returns the overall_u_value regardless the order the parameters are read.
self._thickness_m = value
if self._overall_u_value is None and self.conductivity_w_mk is not None:
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
r_value = 1 / h_i + 1 / h_e + float(self.conductivity_w_mk) / float(self.thickness_m)
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):
"""
Get thermal opening front side solar transmittance at normal incidence
:return: 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
:return: None
"""
self._front_side_solar_transmittance_at_normal_incidence = value
@property
def back_side_solar_transmittance_at_normal_incidence(self):
"""
Get thermal opening back side solar transmittance at normal incidence
:return: 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
:return: None
"""
self._back_side_solar_transmittance_at_normal_incidence = value
@property
def overall_u_value(self):
"""
Get thermal opening overall u value
:return: float
"""
return self._overall_u_value
@overall_u_value.setter
def overall_u_value(self, value):
"""
Get thermal opening overall u value
:param value: float
:return: None
"""
self._overall_u_value = value

View File

@ -3,8 +3,8 @@ UsageZone module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from city_model_structure.internal_gains import InternalGains
from typing import List
from city_model_structure.internal_gains import InternalGains
class UsageZone:
@ -41,59 +41,118 @@ class UsageZone:
@property
def heating_setpoint(self):
"""
:return:
Get usage zone heating set point in celsius grads
:return: float
"""
return self._heating_setpoint
@heating_setpoint.setter
def heating_setpoint(self, value):
"""
Set usage zone heating set point in celsius grads
:param value: float
:return: None
"""
self._heating_setpoint = value
@property
def heating_setback(self):
"""
Get usage zone heating setback in celsius grads
:return: float
"""
return self._heating_setback
@heating_setback.setter
def heating_setback(self, value):
"""
Set usage zone heating setback in celsius grads
:param value: float
:return: None
"""
self._heating_setback = value
@property
def cooling_setpoint(self):
"""
Get usage zone cooling setpoint in celsius grads
:return: float
"""
return self._cooling_setpoint
@cooling_setpoint.setter
def cooling_setpoint(self, value):
"""
Set usage zone cooling setpoint in celsius grads
:param value: float
:return: None
"""
self._cooling_setpoint = value
@property
def hours_day(self):
"""
Get usage zone usage hours per day
:return: float
"""
return self._hours_day
@hours_day.setter
def hours_day(self, value):
"""
Set usage zone usage hours per day
:param value: float
:return: float
"""
self._hours_day = value
@property
def days_year(self):
"""
Get usage zone usage days per year
:return: float
"""
return self._days_year
@days_year.setter
def days_year(self, value):
"""
Set usage zone usage days per year
:param value: float
:return: None
"""
self._days_year = value
@property
def mechanical_air_change(self):
"""
Set usage zone mechanical air change in air change per hour
:return: float
"""
return self._mechanical_air_change
@mechanical_air_change.setter
def mechanical_air_change(self, value):
"""
Get usage zone mechanical air change in air change per hour
:param value: float
:return: None
"""
self._mechanical_air_change = value
@property
def usage(self):
"""
Get usage zone usage
:return: str
"""
return self._usage
@usage.setter
def usage(self, value):
"""
Get usage zone usage
:param value: str
:return: None
"""
self._usage = value

View File

@ -9,21 +9,25 @@ from city_model_structure.city import City
class GeometryFactory:
def __init__(self, file_type, path):
self._file_type = file_type.lower()
self._file_type = '_' + file_type.lower()
self._path = path
@property
def citygml(self):
def _citygml(self):
return CityGml(self._path).city
@property
def geojson(self):
def _geojson(self):
raise Exception('Not implemented')
@property
def bim(self):
def _bim(self):
raise Exception('Not implemented')
@property
def city(self) -> City:
"""
Geometry factory city model structure with geometry
:return: City
"""
return getattr(self, self._file_type, lambda: None)

View File

@ -12,6 +12,9 @@ from helpers.geometry import Geometry
class CityGml:
"""
CityGml class
"""
def __init__(self, path):
self._city = None
with open(path) as gml:
@ -42,10 +45,18 @@ class CityGml:
@property
def content(self):
"""
CityGml raw content
:return: str
"""
return self._gml
@property
def city(self):
def city(self) -> City:
"""
City model structure enriched with the geometry information
:return: City
"""
if self._city is None:
self._city = City(self._lower_corner, self._upper_corner, self._srs_name)
for o in self._gml['CityModel']['cityObjectMember']:

View File

@ -8,6 +8,9 @@ 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()
@ -16,36 +19,73 @@ class Configuration:
@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

@ -11,14 +11,29 @@ 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
@ -49,6 +64,12 @@ class Geometry:
@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:
@ -107,6 +128,13 @@ class Geometry:
@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.

View File

@ -8,26 +8,33 @@ from physics.physics_feeders.us_physics_parameters import UsPhysicsParameters
class PhysicsFactory:
"""
PhysicsFactor class
"""
def __init__(self, handler, city, base_path='data/physics'):
self._handler = handler.lower().replace(' ', '_')
self._handler = '_' + handler.lower().replace(' ', '_')
self._city = city
self._base_path = base_path
self.factory()
def us_new_york_city(self):
def _us_new_york_city(self):
UsNewYorkCityPhysicsParameters(self._city, self._base_path)
def us(self):
def _us(self):
UsPhysicsParameters(self._city, self._base_path)
def ca(self):
def _ca(self):
raise Exception('Not implemented')
def de(self):
def _de(self):
raise Exception('Not implemented')
def es(self):
def _es(self):
raise Exception('Not implemented')
def factory(self):
"""
Enrich the city with the physics information
:return: None
"""
getattr(self, self._handler, lambda: None)()

View File

@ -6,6 +6,9 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
class UsPlutoToFunction:
"""
UsPlutoToFunction
"""
building_function = {
'A0': 'single family house',
'A1': 'single family house',

View File

@ -5,7 +5,10 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
"""
class UsToLibraryTypes(object):
class UsToLibraryTypes:
"""
UsToLibraryTypes
"""
standards = {
'ASHRAE Std189': 1,
'ASHRAE 90.1-2004': 2
@ -44,6 +47,11 @@ class UsToLibraryTypes(object):
@staticmethod
def yoc_to_standard(year_of_construction):
"""
Year of construction to standard
:param year_of_construction: int
:return: str
"""
if int(year_of_construction) < 2009:
standard = 'ASHRAE 90.1_2004'
else:
@ -52,6 +60,11 @@ class UsToLibraryTypes(object):
@staticmethod
def city_to_reference_city(city):
"""
City name to reference city
:param city: str
:return: str
"""
# ToDo: Dummy function that need to be implemented
reference_city = 'Baltimore'
if city is not None:
@ -60,5 +73,10 @@ class UsToLibraryTypes(object):
@staticmethod
def city_to_climate_zone(city):
"""
City name to climate zone
:param city: str
:return: str
"""
reference_city = UsToLibraryTypes.city_to_reference_city(city)
return UsToLibraryTypes.reference_city_climate_zone[reference_city]

View File

@ -4,14 +4,17 @@ UsPhysicsParameters as base class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pathlib import Path
import xmltodict
from city_model_structure.layer import Layer
from city_model_structure.material import Material
from pathlib import Path
from physics.physics_feeders.helpers.us_to_library_types import UsToLibraryTypes
class UsBasePhysicsParameters:
"""
UsBasePhysicsParameters class
"""
def __init__(self, climate_zone, city_objects, function_to_type, base_path):
self._climate_zone = climate_zone
self._city_objects = city_objects
@ -29,9 +32,9 @@ class UsBasePhysicsParameters:
building_type = function_to_type(city_object.function)
if building_type is None:
return
archetype = self.search_archetype(building_type,
UsToLibraryTypes.yoc_to_standard(city_object.year_of_construction),
self._climate_zone)
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: Raise WrongArchetype if not all the surface types are defined for the given city_object
if archetype is None:
@ -50,9 +53,9 @@ class UsBasePhysicsParameters:
thermal_zone.infiltration_rate_system_on = archetype['infiltration_rate_for_ventilation_system_on']['#text']
for thermal_boundary in thermal_zone.bounded:
construction_type = UsToLibraryTypes.construction_types[thermal_boundary.type]
construction = UsBasePhysicsParameters.search_construction_in_archetype(archetype, construction_type)
construction = UsBasePhysicsParameters._search_construction_in_archetype(archetype, construction_type)
construction_id = construction['@id']
c_lib = self.search_construction_type('construction', construction_id)
c_lib = self._search_construction_type('construction', construction_id)
if 'outside_solar_absorptance' in c_lib:
thermal_boundary.outside_solar_absorptance = c_lib['outside_solar_absorptance']['#text']
thermal_boundary.outside_thermal_absorptance = c_lib['outside_thermal_absorptance']['#text']
@ -63,7 +66,7 @@ class UsBasePhysicsParameters:
layer = Layer()
if 'thickness' in current_layer:
layer.thickness = current_layer['thickness']['#text']
material_lib = self.search_construction_type('material', current_layer['material'])
material_lib = self._search_construction_type('material', current_layer['material'])
material = Material()
if 'conductivity' in material_lib:
material.conductivity = material_lib['conductivity']['#text']
@ -80,8 +83,8 @@ class UsBasePhysicsParameters:
for opening in thermal_boundary.thermal_openings:
if construction['window'] is None:
continue
w_lib = self.search_construction_type('window', construction['window'])
opening.conductivity_w_mk = w_lib['conductivity']['#text']
w_lib = self._search_construction_type('window', construction['window'])
opening.conductivity = w_lib['conductivity']['#text']
opening.frame_ratio = w_lib['frame_ratio']['#text']
opening.g_value = w_lib['solar_transmittance_at_normal_incidence']['#text']
opening.thickness = w_lib['thickness']['#text']
@ -90,7 +93,7 @@ class UsBasePhysicsParameters:
opening.front_side_solar_transmittance_at_normal_incidence = \
w_lib['front_side_solar_transmittance_at_normal_incidence']['#text']
def search_archetype(self, building_type, standard, climate_zone):
def _search_archetype(self, building_type, standard, climate_zone):
for archetype in self._archetypes['archetypes']['archetype']:
a_yc = str(archetype['@reference_standard'])
a_bt = str(archetype['@building_type'])
@ -99,14 +102,14 @@ class UsBasePhysicsParameters:
return archetype
return None
def search_construction_type(self, construction_type, construction_id):
def _search_construction_type(self, construction_type, construction_id):
for c_lib in self._library['library'][construction_type + 's'][construction_type]:
if construction_id == c_lib['@id']:
return c_lib
raise Exception('Archetype definition contains elements that does not exist in the library')
@staticmethod
def search_construction_in_archetype(archetype, construction_type):
def _search_construction_in_archetype(archetype, construction_type):
for construction in archetype['constructions']['construction']:
if construction['@type'] == construction_type:
return construction

View File

@ -8,6 +8,9 @@ from physics.physics_feeders.helpers.us_pluto_to_function import UsPlutoToFuncti
class UsNewYorkCityPhysicsParameters(UsBasePhysicsParameters):
"""
UsNewYorkCityPhysicsParameters class
"""
def __init__(self, city, base_path):
self._city = city
climate_zone = 'ASHRAE_2004:4A'

View File

@ -8,6 +8,9 @@ from physics.physics_feeders.helpers.us_to_library_types import UsToLibraryTypes
class UsPhysicsParameters(UsBasePhysicsParameters):
"""
UsPhysicsParameters class
"""
def __init__(self, city, base_path):
self._city = city
self._climate_zone = UsToLibraryTypes.city_to_climate_zone(city.name)

View File

@ -140,6 +140,9 @@ disable=print-statement,
exception-escape,
comprehension-escape,
import-error,
parse-error,
syntax-error,
bad-continuation,
no-name-in-module
# Enable the message, report, category or checker with the given id(s). You can

View File

@ -7,15 +7,25 @@ from unittest import TestCase
from pathlib import Path
from geometry.geometry_factory import GeometryFactory
import os
from city_model_structure.surface import Surface
class TestGeometryFactory(TestCase):
"""
TestGeometryFactory TestCase
"""
def setUp(self) -> None:
"""
Test setup
:return: None
"""
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
"""
if self._city_gml is None:
file_path = (self._example_path / 'buildings.gml').resolve()
self._city_gml = GeometryFactory('citygml', file_path).city
@ -23,6 +33,10 @@ class TestGeometryFactory(TestCase):
return self._city_gml
def test_citygml_city(self):
"""
Test the City parsing
:return: None
"""
city = self.get_citygml()
self.assertIsNotNone(city.city_objects, 'city_objects is none')
for city_object in city.city_objects:
@ -34,6 +48,10 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(city.country_code, 'country code is none')
def test_citygml_city_objects(self):
"""
Test city objects in the city
:return: None
"""
city = self.get_citygml()
for city_object in city.city_objects:
self.assertIsNotNone(city_object.name, 'city_object name is none')
@ -58,6 +76,10 @@ class TestGeometryFactory(TestCase):
os.remove(Path(self._example_path, city_object.name + '.stl').resolve())
def test_citygml_surfaces(self):
"""
Test surfaces in city objects
:return: None
"""
city = self.get_citygml()
for city_object in city.city_objects:
for surface in city_object.surfaces:
@ -85,6 +107,10 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(surface.intersect(surface), 'self intersection is none')
def test_citygml_thermal_zone(self):
"""
Test thermal zones in city objects
:return: None
"""
city = self.get_citygml()
for city_object in city.city_objects:
for thermal_zone in city_object.thermal_zones:
@ -97,8 +123,8 @@ class TestGeometryFactory(TestCase):
'thermal_zone additional_thermal_bridge_u_value is not none')
self.assertIsNone(thermal_zone.effective_thermal_capacity,
'thermal_zone effective_thermal_capacity is not none')
self.assertIsNone(thermal_zone.indirectly_heated_area_ratio
, 'thermal_zone indirectly_heated_area_ratio is not none')
self.assertIsNone(thermal_zone.indirectly_heated_area_ratio,
'thermal_zone indirectly_heated_area_ratio is not none')
self.assertIsNone(thermal_zone.infiltration_rate_system_off,
'thermal_zone infiltration_rate_system_off is not none')
self.assertIsNone(thermal_zone.infiltration_rate_system_on,
@ -107,6 +133,10 @@ class TestGeometryFactory(TestCase):
'thermal_zone usage_zones are not none')
def test_citygml_thermal_boundary(self):
"""
Test thermal boundaries in thermal zones
:return: None
"""
city = self.get_citygml()
for city_object in city.city_objects:
for thermal_zone in city_object.thermal_zones:
@ -133,6 +163,10 @@ class TestGeometryFactory(TestCase):
self.assertIsNone(thermal_boundary.window_ratio, 'thermal_boundary window_ratio was initialized')
def test_citygml_thermal_opening(self):
"""
Test thermal openings in thermal zones
:return: None
"""
city = self.get_citygml()
for city_object in city.city_objects:
for thermal_zone in city_object.thermal_zones:
@ -141,11 +175,11 @@ class TestGeometryFactory(TestCase):
self.assertIsNone(thermal_opening.area, 'thermal_opening area was initialized')
self.assertTrue(thermal_opening.frame_ratio == 0, 'thermal_opening frame_ratio was not 0')
self.assertIsNone(thermal_opening.g_value, 'thermal_opening g_value was initialized')
self.assertIsNone(thermal_opening.conductivity_w_mk, 'thermal_opening conductivity_w_mk was initialized')
self.assertIsNone(thermal_opening.conductivity, 'thermal_opening conductivity_w_mk was initialized')
self.assertIsNone(thermal_opening.inside_reflectance, 'thermal_opening inside_reflectance was initialized')
self.assertRaises(Exception, lambda: thermal_opening.openable_ratio,
'thermal_opening openable_ratio is not raising an exception')
self.assertIsNone(thermal_opening.outside_reflectance,
'thermal_opening outside_reflectance was initialized')
self.assertIsNone(thermal_opening.thickness_m, 'thermal_opening thickness_m was initialized')
self.assertIsNone(thermal_opening.thickness, 'thermal_opening thickness_m was initialized')
self.assertRaises(Exception, lambda: thermal_opening.u_value, 'thermal_opening u_value was initialized')

View File

@ -10,7 +10,10 @@ from physics.physics_factory import PhysicsFactory
class TestPhysicsFactory(TestCase):
def setUp(self) -> None:
"""
TestPhysicsFactory TestCase
"""
def setup(self) -> None:
self._city_gml = None
self._nyc_with_physics = None
self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()