Quality improvements
This commit is contained in:
parent
312a9c34be
commit
62bca29a82
|
@ -16,9 +16,9 @@ class ThermalBoundary:
|
||||||
"""
|
"""
|
||||||
ThermalBoundary class
|
ThermalBoundary class
|
||||||
"""
|
"""
|
||||||
def __init__(self, surface, delimits):
|
def __init__(self, surface, thermal_zones):
|
||||||
self._surface = surface
|
self._surface = surface
|
||||||
self._delimits = delimits
|
self._thermal_zones = thermal_zones
|
||||||
# ToDo: up to at least LOD2 will be just one thermal opening per Thermal boundary only if window_ratio > 0,
|
# ToDo: up to at least LOD2 will be just one thermal opening per Thermal boundary only if window_ratio > 0,
|
||||||
# review for LOD3 and LOD4
|
# review for LOD3 and LOD4
|
||||||
self._thermal_openings = None
|
self._thermal_openings = None
|
||||||
|
@ -50,12 +50,12 @@ class ThermalBoundary:
|
||||||
return self._surface
|
return self._surface
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def delimits(self) -> List[ThermalZone]:
|
def thermal_zones(self) -> List[ThermalZone]:
|
||||||
"""
|
"""
|
||||||
Get the thermal zones delimited by the thermal boundary
|
Get the thermal zones delimited by the thermal boundary
|
||||||
:return: [ThermalZone]
|
:return: [ThermalZone]
|
||||||
"""
|
"""
|
||||||
return self._delimits
|
return self._thermal_zones
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def azimuth(self):
|
def azimuth(self):
|
||||||
|
|
|
@ -7,10 +7,10 @@ import numpy as np
|
||||||
import xmltodict
|
import xmltodict
|
||||||
from city_model_structure.city import City
|
from city_model_structure.city import City
|
||||||
from city_model_structure.building import Building
|
from city_model_structure.building import Building
|
||||||
|
from city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
||||||
from helpers.geometry_helper import GeometryHelper
|
from helpers.geometry_helper import GeometryHelper
|
||||||
from imports.geometry.citygml_classes.citygml_lod2 import CityGmlLod2
|
from imports.geometry.citygml_classes.citygml_lod2 import CityGmlLod2
|
||||||
from imports.geometry.citygml_classes.citygml_lod1 import CityGmlLod1
|
from imports.geometry.citygml_classes.citygml_lod1 import CityGmlLod1
|
||||||
from city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
|
||||||
|
|
||||||
|
|
||||||
class CityGml:
|
class CityGml:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""
|
"""
|
||||||
CityGmlLod1 module parses citygml_classes files with level of detail 1 and import the geometry into the city model structure
|
CityGmlLod1 module parses citygml_classes files with level of detail 1 and import the geometry into the city model
|
||||||
|
structure
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
@ -18,14 +19,6 @@ class CityGmlLod1(CityGmlBase):
|
||||||
def _multi_curve(cls, o):
|
def _multi_curve(cls, o):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _multi_surface(cls, o):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _solid(cls, o):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __init__(self, o):
|
def __init__(self, o):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._o = o
|
self._o = o
|
||||||
|
@ -35,14 +28,16 @@ class CityGmlLod1(CityGmlBase):
|
||||||
def _identify(cls, o):
|
def _identify(cls, o):
|
||||||
if 'lod1Solid' in o:
|
if 'lod1Solid' in o:
|
||||||
return cls._solid(o)
|
return cls._solid(o)
|
||||||
elif 'lod1MultiSurface' in o:
|
if 'lod1MultiSurface' in o:
|
||||||
return cls._multi_surface(o)
|
return cls._multi_surface(o)
|
||||||
|
raise NotImplementedError(o)
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def _solid(o):
|
def _solid(cls, o):
|
||||||
try:
|
try:
|
||||||
solid_points = [
|
solid_points = [
|
||||||
CityGmlBase._solid_points(CityGmlBase._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList']['#text']))
|
CityGmlBase._solid_points(CityGmlBase._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList']
|
||||||
|
['#text']))
|
||||||
for s in o['lod1Solid']['Solid']['exterior']['CompositeSurface']['surfaceMember']]
|
for s in o['lod1Solid']['Solid']['exterior']['CompositeSurface']['surfaceMember']]
|
||||||
except TypeError:
|
except TypeError:
|
||||||
solid_points = [
|
solid_points = [
|
||||||
|
@ -51,9 +46,10 @@ class CityGmlLod1(CityGmlBase):
|
||||||
|
|
||||||
return [Surface(Polygon(sp), Polygon(sp)) for sp in solid_points]
|
return [Surface(Polygon(sp), Polygon(sp)) for sp in solid_points]
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def _multi_surface(o):
|
def _multi_surface(cls, o):
|
||||||
print("lod1_multi")
|
print("lod1_multi")
|
||||||
solid_points = [CityGmlBase._solid_points(CityGmlBase._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList']))
|
solid_points = [CityGmlBase._solid_points(CityGmlBase._remove_last_point(s['Polygon']['exterior']['LinearRing']
|
||||||
|
['posList']))
|
||||||
for s in o['Building']['lod1MultiSurface']['MultiSurface']['surfaceMember']]
|
for s in o['Building']['lod1MultiSurface']['MultiSurface']['surfaceMember']]
|
||||||
return [Surface(Polygon(sp), Polygon(sp)) for sp in solid_points]
|
return [Surface(Polygon(sp), Polygon(sp)) for sp in solid_points]
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
"""
|
"""
|
||||||
CityGmlLod1 module parses citygml_classes files with level of detail 1 and import the geometry into the city model structure
|
CityGmlLod1 module parses citygml_classes files with level of detail 1 and import the geometry into the city model
|
||||||
|
structure
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from imports.geometry.citygml_classes.citygml_base import CityGmlBase
|
from imports.geometry.citygml_classes.citygml_base import CityGmlBase
|
||||||
|
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
||||||
from city_model_structure.building_demand.surface import Surface
|
from city_model_structure.building_demand.surface import Surface
|
||||||
from city_model_structure.attributes.polygon import Polygon
|
from city_model_structure.attributes.polygon import Polygon
|
||||||
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
|
||||||
|
|
||||||
|
|
||||||
class CityGmlLod2(CityGmlBase):
|
class CityGmlLod2(CityGmlBase):
|
||||||
|
@ -23,10 +24,11 @@ class CityGmlLod2(CityGmlBase):
|
||||||
def _identify(cls, o):
|
def _identify(cls, o):
|
||||||
if 'lod2Solid' in o:
|
if 'lod2Solid' in o:
|
||||||
return cls._solid(o)
|
return cls._solid(o)
|
||||||
elif 'lod2MultiSurface' in o:
|
if 'lod2MultiSurface' in o:
|
||||||
return cls._multi_surface(o)
|
return cls._multi_surface(o)
|
||||||
elif 'lod2MultiCurve' in o:
|
if 'lod2MultiCurve' in o:
|
||||||
return cls._multi_curve(o)
|
return cls._multi_curve(o)
|
||||||
|
raise NotImplementedError(o)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _surface_encoding(surfaces):
|
def _surface_encoding(surfaces):
|
||||||
|
|
|
@ -8,6 +8,9 @@ import helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class GeometryHelper:
|
class GeometryHelper:
|
||||||
|
"""
|
||||||
|
Geometry helper
|
||||||
|
"""
|
||||||
# function
|
# function
|
||||||
pluto_to_function = {
|
pluto_to_function = {
|
||||||
'A0': 'single family house',
|
'A0': 'single family house',
|
||||||
|
@ -307,22 +310,13 @@ class GeometryHelper:
|
||||||
points = points.reshape(rows, 3)
|
points = points.reshape(rows, 3)
|
||||||
return points
|
return points
|
||||||
|
|
||||||
def almost_equal(self, delta_max, v1, v2):
|
|
||||||
"""
|
|
||||||
Compare two points and decides if they are almost equal (distance under delta_max)
|
|
||||||
:param delta_max: maximum distance to be considered same point
|
|
||||||
:param v1: [x,y,z]
|
|
||||||
:param v2: [x,y,z]
|
|
||||||
:return: Boolean
|
|
||||||
"""
|
|
||||||
delta = self.distance_between_points(v1, v2)
|
|
||||||
return delta <= delta_max
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def gml_surface_to_libs(surface):
|
def gml_surface_to_libs(surface):
|
||||||
|
"""
|
||||||
|
Transform citygml surface names into libs names
|
||||||
|
"""
|
||||||
if surface == 'WallSurface':
|
if surface == 'WallSurface':
|
||||||
return 'Wall'
|
return 'Wall'
|
||||||
elif surface == 'GroundSurface':
|
if surface == 'GroundSurface':
|
||||||
return 'Ground'
|
return 'Ground'
|
||||||
else:
|
return 'Roof'
|
||||||
return 'Roof'
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ class Obj:
|
||||||
with open(path, 'r') as file:
|
with open(path, 'r') as file:
|
||||||
self._scene = trimesh.exchange.load.load(file, file_type='obj', force='scene')
|
self._scene = trimesh.exchange.load.load(file, file_type='obj', force='scene')
|
||||||
self._corners = self._scene.bounds_corners
|
self._corners = self._scene.bounds_corners
|
||||||
_bound_corner_min = None
|
_bound_corner_min = []
|
||||||
_bound_corner_max = None
|
_bound_corner_max = []
|
||||||
for corner in self._corners:
|
for corner in self._corners:
|
||||||
if _bound_corner_min is None:
|
if _bound_corner_min is None:
|
||||||
_bound_corner_min = corner
|
_bound_corner_min = corner
|
||||||
|
@ -40,10 +40,16 @@ class Obj:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def scene(self) -> Scene:
|
def scene(self) -> Scene:
|
||||||
|
"""
|
||||||
|
Obj scene
|
||||||
|
"""
|
||||||
return self._scene
|
return self._scene
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def city(self) -> City:
|
def city(self) -> City:
|
||||||
|
"""
|
||||||
|
Create a city out of an obj file
|
||||||
|
"""
|
||||||
if self._city is None:
|
if self._city is None:
|
||||||
# todo: refactor this method to clearly choose the obj type
|
# todo: refactor this method to clearly choose the obj type
|
||||||
# todo: where do we get this information from?
|
# todo: where do we get this information from?
|
||||||
|
|
|
@ -4,12 +4,19 @@ 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 sys
|
||||||
import xmltodict
|
import xmltodict
|
||||||
|
from pyproj import Transformer
|
||||||
|
from city_model_structure.city import City
|
||||||
from city_model_structure.subway_entrance import SubwayEntrance
|
from city_model_structure.subway_entrance import SubwayEntrance
|
||||||
|
|
||||||
|
|
||||||
class OsmSubway:
|
class OsmSubway:
|
||||||
|
"""
|
||||||
|
Open street map subway
|
||||||
|
"""
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
|
self._city = None
|
||||||
self._subway_entrances = []
|
self._subway_entrances = []
|
||||||
with open(path) as osm:
|
with open(path) as osm:
|
||||||
self._osm = xmltodict.parse(osm.read(), force_list='tag')
|
self._osm = xmltodict.parse(osm.read(), force_list='tag')
|
||||||
|
@ -24,5 +31,24 @@ class OsmSubway:
|
||||||
self._subway_entrances.append(subway_entrance)
|
self._subway_entrances.append(subway_entrance)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def subway_entrances(self):
|
def city(self) -> City:
|
||||||
return self._subway_entrances
|
"""
|
||||||
|
City subway entrances
|
||||||
|
"""
|
||||||
|
transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857")
|
||||||
|
lower_corner = [sys.float_info.max, sys.float_info.max, 0]
|
||||||
|
upper_corner = [sys.float_info.min, sys.float_info.min, 0]
|
||||||
|
x = 0
|
||||||
|
y = 1
|
||||||
|
for subway_entrance in self._subway_entrances:
|
||||||
|
coordinate = transformer.transform(subway_entrance.longitude, subway_entrance.latitude)
|
||||||
|
if coordinate[x] >= upper_corner[x]:
|
||||||
|
upper_corner[x] = coordinate[x]
|
||||||
|
if coordinate[y] >= upper_corner[y]:
|
||||||
|
upper_corner[y] = coordinate[y]
|
||||||
|
if coordinate[x] < lower_corner[x]:
|
||||||
|
lower_corner[x] = coordinate[x]
|
||||||
|
if coordinate[y] < lower_corner[y]:
|
||||||
|
lower_corner[y] = coordinate[y]
|
||||||
|
|
||||||
|
return City(lower_corner, upper_corner, 'unknown')
|
||||||
|
|
|
@ -3,13 +3,11 @@ GeometryFactory retrieve the specific geometric module to load the given format
|
||||||
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 trimesh.scene import Scene
|
|
||||||
|
|
||||||
from city_model_structure.city import City
|
from city_model_structure.city import City
|
||||||
from city_model_structure.city_object import CityObject
|
|
||||||
from imports.geometry.citygml import CityGml
|
from imports.geometry.citygml import CityGml
|
||||||
from imports.geometry.osm_subway import OsmSubway
|
|
||||||
from imports.geometry.obj import Obj
|
from imports.geometry.obj import Obj
|
||||||
|
from imports.geometry.osm_subway import OsmSubway
|
||||||
|
|
||||||
|
|
||||||
class GeometryFactory:
|
class GeometryFactory:
|
||||||
|
@ -24,21 +22,13 @@ class GeometryFactory:
|
||||||
def _citygml(self):
|
def _citygml(self):
|
||||||
return CityGml(self._path).city
|
return CityGml(self._path).city
|
||||||
|
|
||||||
@property
|
|
||||||
def _stl(self):
|
|
||||||
raise Exception('Not implemented')
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _obj(self):
|
def _obj(self):
|
||||||
return Obj(self._path).scene
|
return Obj(self._path).city
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _geojson(self):
|
def _osm_subway(self):
|
||||||
raise Exception('Not implemented')
|
return OsmSubway(self._path).city
|
||||||
|
|
||||||
@property
|
|
||||||
def _bim(self):
|
|
||||||
raise Exception('Not implemented')
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def city(self) -> City:
|
def city(self) -> City:
|
||||||
|
@ -47,37 +37,3 @@ class GeometryFactory:
|
||||||
:return: City
|
:return: City
|
||||||
"""
|
"""
|
||||||
return getattr(self, self._file_type, lambda: None)
|
return getattr(self, self._file_type, lambda: None)
|
||||||
|
|
||||||
@property
|
|
||||||
def scene(self) -> Scene:
|
|
||||||
"""
|
|
||||||
Load the city model structure from a geometry source
|
|
||||||
:return: Trimesh scene
|
|
||||||
"""
|
|
||||||
return getattr(self, self._file_type, lambda: None)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _scene_debug(self):
|
|
||||||
"""
|
|
||||||
just for debug. More information is provided without the lambda parameter
|
|
||||||
"""
|
|
||||||
return getattr(self, self._file_type)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _city_debug(self):
|
|
||||||
"""
|
|
||||||
just for debug. More information is provided without the lambda parameter
|
|
||||||
"""
|
|
||||||
return CityGml(self._path).city
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _osm_subway(self):
|
|
||||||
return OsmSubway(self._path).subway_entrances
|
|
||||||
|
|
||||||
@property
|
|
||||||
def features(self) -> [CityObject]:
|
|
||||||
"""
|
|
||||||
Load the city model structure from a geometry source
|
|
||||||
:return: [CityObject]
|
|
||||||
"""
|
|
||||||
return getattr(self, self._file_type, lambda: None)
|
|
||||||
|
|
|
@ -9,7 +9,9 @@ from imports.schedules.helpers.schedules_helper import SchedulesHelper
|
||||||
|
|
||||||
|
|
||||||
class ComnetSchedules:
|
class ComnetSchedules:
|
||||||
|
"""
|
||||||
|
Commet based schedules
|
||||||
|
"""
|
||||||
def __init__(self, city, base_path):
|
def __init__(self, city, base_path):
|
||||||
self._city = city
|
self._city = city
|
||||||
self._comnet_schedules_path = base_path / 'comnet_archetypes.xlsx'
|
self._comnet_schedules_path = base_path / 'comnet_archetypes.xlsx'
|
||||||
|
|
|
@ -23,12 +23,12 @@ class DoeIdf:
|
||||||
def __init__(self, city, base_path):
|
def __init__(self, city, base_path):
|
||||||
self._hours = []
|
self._hours = []
|
||||||
panda_hours = pd.timedelta_range(0, periods=24, freq='H')
|
panda_hours = pd.timedelta_range(0, periods=24, freq='H')
|
||||||
for i, hour in enumerate(panda_hours):
|
for _, hour in enumerate(panda_hours):
|
||||||
self._hours.append(str(hour).replace('0 days ', '').replace(':00:00', ':00'))
|
self._hours.append(str(hour).replace('0 days ', '').replace(':00:00', ':00'))
|
||||||
self._city = city
|
self._city = city
|
||||||
self._idf_schedules_path = base_path / 'ASHRAE901_OfficeSmall_STD2019_Buffalo.idf'
|
self._idf_schedules_path = base_path / 'ASHRAE901_OfficeSmall_STD2019_Buffalo.idf'
|
||||||
with open(self._idf_schedules_path, 'r') as f:
|
with open(self._idf_schedules_path, 'r') as file:
|
||||||
idf = parseidf.parse(f.read())
|
idf = parseidf.parse(file.read())
|
||||||
self._load_schedule(idf, 'small_office')
|
self._load_schedule(idf, 'small_office')
|
||||||
self._load_schedule(idf, 'residential')
|
self._load_schedule(idf, 'residential')
|
||||||
|
|
||||||
|
@ -69,9 +69,8 @@ class DoeIdf:
|
||||||
if hour == hour_formatted:
|
if hour == hour_formatted:
|
||||||
hour_index += index
|
hour_index += index
|
||||||
break
|
break
|
||||||
else:
|
entry = days_schedules[hours_values + 1]
|
||||||
entry = days_schedules[hours_values + 1]
|
schedules_day[f'{days_schedules[day_index]}'].append(entry)
|
||||||
schedules_day[f'{days_schedules[day_index]}'].append(entry)
|
|
||||||
|
|
||||||
if 'Weekdays' in days_schedules[day_index]:
|
if 'Weekdays' in days_schedules[day_index]:
|
||||||
data['WD'] = []
|
data['WD'] = []
|
||||||
|
@ -101,9 +100,9 @@ class DoeIdf:
|
||||||
data['Sat'].append(entry)
|
data['Sat'].append(entry)
|
||||||
|
|
||||||
elif 'Sunday' in days_schedules[day_index]:
|
elif 'Sunday' in days_schedules[day_index]:
|
||||||
data['Sun'] = []
|
data['Sun'] = []
|
||||||
for entry in schedules_day[f'{days_schedules[day_index]}']:
|
for entry in schedules_day[f'{days_schedules[day_index]}']:
|
||||||
data['Sun'].append(entry)
|
data['Sun'].append(entry)
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
df = pd.DataFrame(data, index=rows)
|
df = pd.DataFrame(data, index=rows)
|
||||||
|
@ -113,4 +112,3 @@ class DoeIdf:
|
||||||
if usage_zone.schedules is None:
|
if usage_zone.schedules is None:
|
||||||
usage_zone.schedules = {}
|
usage_zone.schedules = {}
|
||||||
usage_zone.schedules[schedule_type] = df
|
usage_zone.schedules[schedule_type] = df
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,9 @@ import helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class SchedulesHelper:
|
class SchedulesHelper:
|
||||||
|
"""
|
||||||
|
Schedules helper
|
||||||
|
"""
|
||||||
usage_to_comnet = {
|
usage_to_comnet = {
|
||||||
cte.RESIDENTIAL: 'C-12 Residential',
|
cte.RESIDENTIAL: 'C-12 Residential',
|
||||||
cte.INDUSTRY: 'C-10 Warehouse',
|
cte.INDUSTRY: 'C-10 Warehouse',
|
||||||
|
|
|
@ -9,7 +9,9 @@ from city_model_structure.iot.concordia_energy_sensor import ConcordiaEnergySens
|
||||||
|
|
||||||
|
|
||||||
class ConcordiaEnergyConsumption(ConcordiaFileReport):
|
class ConcordiaEnergyConsumption(ConcordiaFileReport):
|
||||||
|
"""
|
||||||
|
Concordia energy consumption sensor class
|
||||||
|
"""
|
||||||
def __init__(self, city, end_point, base_path):
|
def __init__(self, city, end_point, base_path):
|
||||||
super().__init__(city, end_point, base_path, 'concordia_energy_db.json')
|
super().__init__(city, end_point, base_path, 'concordia_energy_db.json')
|
||||||
for city_object in city.city_objects:
|
for city_object in city.city_objects:
|
||||||
|
|
|
@ -11,8 +11,10 @@ import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
class ConcordiaFileReport:
|
class ConcordiaFileReport:
|
||||||
|
"""
|
||||||
|
Concordia file report for sensors base class
|
||||||
|
"""
|
||||||
def __init__(self, city, end_point, base_path, db_file):
|
def __init__(self, city, end_point, base_path, db_file):
|
||||||
|
|
||||||
self._city_object = []
|
self._city_object = []
|
||||||
self._city_objects_cluster = []
|
self._city_objects_cluster = []
|
||||||
self._sensors = []
|
self._sensors = []
|
||||||
|
@ -34,7 +36,7 @@ class ConcordiaFileReport:
|
||||||
buffer = ""
|
buffer = ""
|
||||||
with open(end_point.resolve()) as data:
|
with open(end_point.resolve()) as data:
|
||||||
for line in data:
|
for line in data:
|
||||||
line = ConcordiaFileReport.clean_line(line)
|
line = ConcordiaFileReport._clean_line(line)
|
||||||
if metadata:
|
if metadata:
|
||||||
fields = line.split(',')
|
fields = line.split(',')
|
||||||
if len(fields) > 2:
|
if len(fields) > 2:
|
||||||
|
@ -45,34 +47,33 @@ class ConcordiaFileReport:
|
||||||
if "End of Report" in line:
|
if "End of Report" in line:
|
||||||
content = False
|
content = False
|
||||||
if content:
|
if content:
|
||||||
line = ConcordiaFileReport.merge_date_time(line)
|
line = ConcordiaFileReport._merge_date_time(line)
|
||||||
buffer = buffer + line + '\n'
|
buffer = buffer + line + '\n'
|
||||||
if line is '':
|
if line == '':
|
||||||
metadata = False
|
metadata = False
|
||||||
content = True
|
content = True
|
||||||
measures = pd.read_csv(io.StringIO(buffer), sep=',')
|
measures = pd.read_csv(io.StringIO(buffer), sep=',')
|
||||||
measures["Date time"] = pd.to_datetime(measures["Date time"])
|
measures["Date time"] = pd.to_datetime(measures["Date time"])
|
||||||
self._measures = ConcordiaFileReport.force_format(measures)
|
self._measures = ConcordiaFileReport._force_format(measures)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def clean_line(line):
|
def _clean_line(line):
|
||||||
return line.replace('"', '').replace('\n', '')
|
return line.replace('"', '').replace('\n', '')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def merge_date_time(line):
|
def _merge_date_time(line):
|
||||||
fields = line.split(',')
|
fields = line.split(',')
|
||||||
date = fields[0]
|
date = fields[0]
|
||||||
time = fields[1]
|
time = fields[1]
|
||||||
if '<>' in date:
|
if '<>' in date:
|
||||||
return line.replace(f'{date},{time}', 'Date time')
|
return line.replace(f'{date},{time}', 'Date time')
|
||||||
else:
|
date_fields = date.split('/')
|
||||||
date_fields = date.split('/')
|
format_date_time = f'"{int(date_fields[2])}-{int(date_fields[0]):02d}-{int(date_fields[1]):02d} {time}"'
|
||||||
format_date_time = f'"{int(date_fields[2])}-{int(date_fields[0]):02d}-{int(date_fields[1]):02d} {time}"'
|
return line.replace(f'{date},{time}', format_date_time)
|
||||||
return line.replace(f'{date},{time}', format_date_time)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def force_format(df):
|
def _force_format(df):
|
||||||
for head in df.head():
|
for head in df.head():
|
||||||
if 'Date time' not in head:
|
if 'Date time' not in head:
|
||||||
df = df.astype({head: 'float64'})
|
df = df.astype({head: 'float64'})
|
||||||
return df
|
return df
|
||||||
|
|
|
@ -9,6 +9,9 @@ from city_model_structure.iot.concordia_gas_flow_sensor import ConcordiaGasFlowS
|
||||||
|
|
||||||
|
|
||||||
class ConcordiaGasFlow(ConcordiaFileReport):
|
class ConcordiaGasFlow(ConcordiaFileReport):
|
||||||
|
"""
|
||||||
|
Concordia gas flow sensor class
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, city, end_point, base_path):
|
def __init__(self, city, end_point, base_path):
|
||||||
super().__init__(city, end_point, base_path, 'concordia_gas_flow_db.json')
|
super().__init__(city, end_point, base_path, 'concordia_gas_flow_db.json')
|
||||||
|
|
|
@ -9,7 +9,9 @@ from city_model_structure.iot.concordia_temperature_sensor import ConcordiaTempe
|
||||||
|
|
||||||
|
|
||||||
class ConcordiaTemperature(ConcordiaFileReport):
|
class ConcordiaTemperature(ConcordiaFileReport):
|
||||||
|
"""
|
||||||
|
Concordia temperature sensor class
|
||||||
|
"""
|
||||||
def __init__(self, city, end_point, base_path):
|
def __init__(self, city, end_point, base_path):
|
||||||
super().__init__(city, end_point, base_path, 'concordia_temperature_db.json')
|
super().__init__(city, end_point, base_path, 'concordia_temperature_db.json')
|
||||||
for city_object in city.city_objects:
|
for city_object in city.city_objects:
|
||||||
|
|
|
@ -58,12 +58,12 @@ class CaUsageParameters(HftUsageInterface):
|
||||||
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
|
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
|
||||||
# Therefore, this walk around has been done.
|
# Therefore, this walk around has been done.
|
||||||
internal_gains = []
|
internal_gains = []
|
||||||
for ig in archetype.internal_gains:
|
for archetype_internal_gain in archetype.internal_gains:
|
||||||
internal_gain = InternalGains()
|
internal_gain = InternalGains()
|
||||||
internal_gain.average_internal_gain = ig.average_internal_gain
|
internal_gain.average_internal_gain = archetype_internal_gain.average_internal_gain
|
||||||
internal_gain.convective_fraction = ig.convective_fraction
|
internal_gain.convective_fraction = archetype_internal_gain.convective_fraction
|
||||||
internal_gain.radiative_fraction = ig.radiative_fraction
|
internal_gain.radiative_fraction = archetype_internal_gain.radiative_fraction
|
||||||
internal_gain.latent_fraction = ig.latent_fraction
|
internal_gain.latent_fraction = archetype_internal_gain.latent_fraction
|
||||||
internal_gains.append(internal_gain)
|
internal_gains.append(internal_gain)
|
||||||
usage_zone.internal_gains = internal_gains
|
usage_zone.internal_gains = internal_gains
|
||||||
usage_zone.heating_setpoint = archetype.heating_setpoint
|
usage_zone.heating_setpoint = archetype.heating_setpoint
|
||||||
|
|
|
@ -8,6 +8,9 @@ import helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class UsageHelper:
|
class UsageHelper:
|
||||||
|
"""
|
||||||
|
Usage helpre class
|
||||||
|
"""
|
||||||
usage_to_hft = {
|
usage_to_hft = {
|
||||||
cte.RESIDENTIAL: 'residential',
|
cte.RESIDENTIAL: 'residential',
|
||||||
cte.INDUSTRY: 'industry',
|
cte.INDUSTRY: 'industry',
|
||||||
|
|
|
@ -13,6 +13,7 @@ class HftUsageInterface:
|
||||||
"""
|
"""
|
||||||
HftUsageInterface abstract class
|
HftUsageInterface abstract class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, base_path, usage_file='ca_library_reduced.xml'):
|
def __init__(self, base_path, usage_file='ca_library_reduced.xml'):
|
||||||
path = str(base_path / usage_file)
|
path = str(base_path / usage_file)
|
||||||
self._usage_archetypes = []
|
self._usage_archetypes = []
|
||||||
|
@ -44,17 +45,17 @@ class HftUsageInterface:
|
||||||
if 'domestic_hot_water' in zone_usage_type['endUses']:
|
if 'domestic_hot_water' in zone_usage_type['endUses']:
|
||||||
# liters to cubic meters
|
# liters to cubic meters
|
||||||
dhw_average_volume_pers_day = float(
|
dhw_average_volume_pers_day = float(
|
||||||
zone_usage_type['endUses']['domestic_hot_water']['averageVolumePerPersAndDay'])/1000
|
zone_usage_type['endUses']['domestic_hot_water']['averageVolumePerPersAndDay']) / 1000
|
||||||
dhw_preparation_temperature = zone_usage_type['endUses']['domestic_hot_water']['preparationTemperature']
|
dhw_preparation_temperature = zone_usage_type['endUses']['domestic_hot_water']['preparationTemperature']
|
||||||
electrical_app_average_consumption_sqm_year = None
|
electrical_app_average_consumption_sqm_year = None
|
||||||
if 'all_electrical_appliances' in zone_usage_type['endUses']:
|
if 'all_electrical_appliances' in zone_usage_type['endUses']:
|
||||||
if 'averageConsumptionPerSqmAndYear' in zone_usage_type['endUses']['all_electrical_appliances']:
|
if 'averageConsumptionPerSqmAndYear' in zone_usage_type['endUses']['all_electrical_appliances']:
|
||||||
# kWh to J
|
# kWh to J
|
||||||
electrical_app_average_consumption_sqm_year = \
|
electrical_app_average_consumption_sqm_year = \
|
||||||
float(zone_usage_type['endUses']['all_electrical_appliances']['averageConsumptionPerSqmAndYear'])/3.6
|
float(zone_usage_type['endUses']['all_electrical_appliances']['averageConsumptionPerSqmAndYear']) / 3.6
|
||||||
|
|
||||||
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
|
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
|
||||||
# There are no more internal gains? How is it saved when more than one???
|
# There are no more internal gains? How is it saved when more than one???
|
||||||
internal_gains = []
|
internal_gains = []
|
||||||
if 'internGains' in zone_usage_type['occupancy']:
|
if 'internGains' in zone_usage_type['occupancy']:
|
||||||
latent_fraction = zone_usage_type['occupancy']['internGains']['latentFraction']
|
latent_fraction = zone_usage_type['occupancy']['internGains']['latentFraction']
|
||||||
|
@ -93,7 +94,7 @@ class HftUsageInterface:
|
||||||
|
|
||||||
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
|
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
|
||||||
# There are no more internal gains? How is it saved when more than one???
|
# There are no more internal gains? How is it saved when more than one???
|
||||||
# for internal_gain in usage_zone.internal_gains:
|
# for internal_gain in usage_zone.internal_gains:
|
||||||
internal_gains = usage_zone.internal_gains[0]
|
internal_gains = usage_zone.internal_gains[0]
|
||||||
latent_fraction = internal_gains.latent_fraction
|
latent_fraction = internal_gains.latent_fraction
|
||||||
convective_fraction = internal_gains.convective_fraction
|
convective_fraction = internal_gains.convective_fraction
|
||||||
|
@ -111,14 +112,15 @@ class HftUsageInterface:
|
||||||
if 'ventilation' in usage_zone_variant['endUses'] and usage_zone_variant['endUses']['ventilation'] is not None:
|
if 'ventilation' in usage_zone_variant['endUses'] and usage_zone_variant['endUses']['ventilation'] is not None:
|
||||||
if 'mechanicalAirChangeRate' in usage_zone_variant['endUses']['ventilation']:
|
if 'mechanicalAirChangeRate' in usage_zone_variant['endUses']['ventilation']:
|
||||||
mechanical_air_change = usage_zone_variant['endUses']['ventilation']['mechanicalAirChangeRate']
|
mechanical_air_change = usage_zone_variant['endUses']['ventilation']['mechanicalAirChangeRate']
|
||||||
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
|
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
|
||||||
# There are no more internal gains? How is it saved when more than one???
|
# There are no more internal gains? How is it saved when more than one???
|
||||||
if 'schedules' in usage_zone_variant:
|
if 'schedules' in usage_zone_variant:
|
||||||
if 'usageHoursPerDay' in usage_zone_variant['schedules']:
|
if 'usageHoursPerDay' in usage_zone_variant['schedules']:
|
||||||
hours_day = usage_zone_variant['schedules']['usageHoursPerDay']
|
hours_day = usage_zone_variant['schedules']['usageHoursPerDay']
|
||||||
if 'usageDaysPerYear' in usage_zone_variant['schedules']:
|
if 'usageDaysPerYear' in usage_zone_variant['schedules']:
|
||||||
days_year = usage_zone_variant['schedules']['usageDaysPerYear']
|
days_year = usage_zone_variant['schedules']['usageDaysPerYear']
|
||||||
if 'internalGains' in usage_zone_variant['schedules'] and usage_zone_variant['schedules']['internGains'] is not None:
|
if 'internalGains' in usage_zone_variant['schedules'] and usage_zone_variant['schedules'][
|
||||||
|
'internGains'] is not None:
|
||||||
internal_gains = []
|
internal_gains = []
|
||||||
if 'latentFraction' in usage_zone_variant['schedules']['internGains']:
|
if 'latentFraction' in usage_zone_variant['schedules']['internGains']:
|
||||||
latent_fraction = usage_zone_variant['schedules']['internGains']['latentFraction']
|
latent_fraction = usage_zone_variant['schedules']['internGains']['latentFraction']
|
||||||
|
@ -137,6 +139,3 @@ class HftUsageInterface:
|
||||||
electrical_app_average_consumption_sqm_year=electrical_app_average_consumption_sqm_year,
|
electrical_app_average_consumption_sqm_year=electrical_app_average_consumption_sqm_year,
|
||||||
mechanical_air_change=mechanical_air_change)
|
mechanical_air_change=mechanical_air_change)
|
||||||
return usage_zone_archetype
|
return usage_zone_archetype
|
||||||
|
|
||||||
def enrich_buildings(self):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
|
@ -58,12 +58,12 @@ class HftUsageParameters(HftUsageInterface):
|
||||||
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
|
# usage_zone.internal_gains when writing usage_zone.internal_gains = archetype.internal_gains.
|
||||||
# Therefore, this walk around has been done.
|
# Therefore, this walk around has been done.
|
||||||
internal_gains = []
|
internal_gains = []
|
||||||
for ig in archetype.internal_gains:
|
for archetype_internal_gain in archetype.internal_gains:
|
||||||
internal_gain = InternalGains()
|
internal_gain = InternalGains()
|
||||||
internal_gain.average_internal_gain = ig.average_internal_gain
|
internal_gain.average_internal_gain = archetype_internal_gain.average_internal_gain
|
||||||
internal_gain.convective_fraction = ig.convective_fraction
|
internal_gain.convective_fraction = archetype_internal_gain.convective_fraction
|
||||||
internal_gain.radiative_fraction = ig.radiative_fraction
|
internal_gain.radiative_fraction = archetype_internal_gain.radiative_fraction
|
||||||
internal_gain.latent_fraction = ig.latent_fraction
|
internal_gain.latent_fraction = archetype_internal_gain.latent_fraction
|
||||||
internal_gains.append(internal_gain)
|
internal_gains.append(internal_gain)
|
||||||
usage_zone.internal_gains = internal_gains
|
usage_zone.internal_gains = internal_gains
|
||||||
usage_zone.heating_setpoint = archetype.heating_setpoint
|
usage_zone.heating_setpoint = archetype.heating_setpoint
|
||||||
|
|
|
@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
import pandas as pd
|
||||||
import helpers.constants as cte
|
import helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ class DatWeatherParameters:
|
||||||
"""
|
"""
|
||||||
DatWeatherParameters class
|
DatWeatherParameters class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, city, path):
|
def __init__(self, city, path):
|
||||||
self._weather_values = None
|
self._weather_values = None
|
||||||
self._city = city
|
self._city = city
|
||||||
|
@ -23,7 +24,7 @@ class DatWeatherParameters:
|
||||||
|
|
||||||
if self._weather_values is None:
|
if self._weather_values is None:
|
||||||
try:
|
try:
|
||||||
self._weather_values = pd.read_csv(self._path, sep='\s+', header=None,
|
self._weather_values = pd.read_csv(self._path, sep=r'\s+', header=None,
|
||||||
names=['hour', 'global_horiz', 'temperature', 'diffuse', 'beam', 'empty'])
|
names=['hour', 'global_horiz', 'temperature', 'diffuse', 'beam', 'empty'])
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
sys.stderr.write(f'Error: weather file {self._path} not found\n')
|
sys.stderr.write(f'Error: weather file {self._path} not found\n')
|
||||||
|
|
|
@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
import pandas as pd
|
||||||
import helpers.constants as cte
|
import helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ class EpwWeatherParameters:
|
||||||
file.close()
|
file.close()
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
sys.stderr.write(f'Error: weather file {self._path} not found. Please download it from '
|
sys.stderr.write(f'Error: weather file {self._path} not found. Please download it from '
|
||||||
f'https://energyplus.net/weather and place it in folder data\weather\epw\n')
|
f'https://energyplus.net/weather and place it in folder data\\weather\\epw\n')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -7,7 +7,7 @@ import math
|
||||||
import helpers.constants as cte
|
import helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class Weather(object):
|
class Weather:
|
||||||
"""
|
"""
|
||||||
Weather class
|
Weather class
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,9 +5,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
import pandas as pd
|
||||||
import helpers.constants as cte
|
import helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ from imports.weather_factory import WeatherFactory
|
||||||
from exports.exports_factory import ExportsFactory
|
from exports.exports_factory import ExportsFactory
|
||||||
|
|
||||||
|
|
||||||
class MyTestCase(TestCase):
|
class TestC40(TestCase):
|
||||||
"""
|
"""
|
||||||
C40 TestCase 1
|
C40 TestCase 1
|
||||||
"""
|
"""
|
||||||
|
@ -31,26 +31,29 @@ class MyTestCase(TestCase):
|
||||||
return self._city_gml
|
return self._city_gml
|
||||||
|
|
||||||
def test_c40_enrichment(self):
|
def test_c40_enrichment(self):
|
||||||
|
"""
|
||||||
|
Enrich the C40 building
|
||||||
|
"""
|
||||||
file = 'C40_Final.gml'
|
file = 'C40_Final.gml'
|
||||||
base_path = (Path(__file__).parent.parent / 'data' / 'weather').resolve()
|
base_path = (Path(__file__).parent.parent / 'data' / 'weather').resolve()
|
||||||
weather_file_name = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw'
|
weather_file_name = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw'
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
for tz in building.thermal_zones:
|
for thermal_zone in building.thermal_zones:
|
||||||
for tb in tz.thermal_boundaries:
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||||
tb.hi = 10
|
thermal_boundary.hi = 10
|
||||||
tb.he = 25
|
thermal_boundary.he = 25
|
||||||
for opening in tb.thermal_openings:
|
for thermal_opening in thermal_boundary.thermal_openings:
|
||||||
opening.hi = 10
|
thermal_opening.hi = 10
|
||||||
opening.he = 25
|
thermal_opening.he = 25
|
||||||
building.function = 'residential'
|
building.function = 'residential'
|
||||||
ConstructionFactory('nrel', city).enrich()
|
ConstructionFactory('nrel', city).enrich()
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
print(building.name, building.function, len(building.surfaces))
|
print(building.name, building.function, len(building.surfaces))
|
||||||
print(building.volume)
|
print(building.volume)
|
||||||
for tz in building.thermal_zones:
|
for thermal_zone in building.thermal_zones:
|
||||||
print(tz.volume)
|
print(thermal_zone.volume)
|
||||||
print(tz.floor_area)
|
print(thermal_zone.floor_area)
|
||||||
|
|
||||||
WeatherFactory('epw', city, base_path=base_path, file_name=weather_file_name).enrich()
|
WeatherFactory('epw', city, base_path=base_path, file_name=weather_file_name).enrich()
|
||||||
ExportsFactory('idf', city, 'c:\Documents\idf').export()
|
ExportsFactory('idf', city, r'c:\Documents\idf').export()
|
|
@ -40,13 +40,13 @@ class TestConstructionFactory(TestCase):
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.function = GeometryHelper.pluto_to_function[building.function]
|
building.function = GeometryHelper.pluto_to_function[building.function]
|
||||||
for tz in building.thermal_zones:
|
for thermal_zone in building.thermal_zones:
|
||||||
for tb in tz.thermal_boundaries:
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||||
tb.hi = 10
|
thermal_boundary.hi = 10
|
||||||
tb.he = 25
|
thermal_boundary.he = 25
|
||||||
for opening in tb.thermal_openings:
|
for thermal_opening in thermal_boundary.thermal_openings:
|
||||||
opening.hi = 10
|
thermal_opening.hi = 10
|
||||||
opening.he = 25
|
thermal_opening.he = 25
|
||||||
# case 1: NREL
|
# case 1: NREL
|
||||||
ConstructionFactory('nrel', city).enrich()
|
ConstructionFactory('nrel', city).enrich()
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
|
@ -62,12 +62,15 @@ class TestConstructionFactory(TestCase):
|
||||||
self.assertIsNotNone(thermal_zone.infiltration_rate_system_off, 'infiltration_rate_system_off is none')
|
self.assertIsNotNone(thermal_zone.infiltration_rate_system_off, 'infiltration_rate_system_off is none')
|
||||||
self.assertIsNotNone(thermal_zone.thermal_boundaries, 'thermal_boundaries is none')
|
self.assertIsNotNone(thermal_zone.thermal_boundaries, 'thermal_boundaries is none')
|
||||||
for thermal_boundary in thermal_zone.thermal_boundaries:
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||||
if thermal_boundary.surface.type is not 'Ground':
|
if thermal_boundary.surface.type != 'Ground':
|
||||||
self.assertIsNotNone(thermal_boundary.outside_solar_absorptance, 'outside_solar_absorptance is none')
|
self.assertIsNotNone(thermal_boundary.outside_solar_absorptance, 'outside_solar_absorptance is none')
|
||||||
self.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none')
|
self.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none')
|
||||||
print(thermal_boundary.layers)
|
print(thermal_boundary.layers)
|
||||||
|
|
||||||
def test_city_with_construction_reduced_library(self):
|
def test_city_with_construction_reduced_library(self):
|
||||||
|
"""
|
||||||
|
Enrich the city with the construction reduced library and verify it
|
||||||
|
"""
|
||||||
file = 'one_building_in_kelowna.gml'
|
file = 'one_building_in_kelowna.gml'
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
|
|
|
@ -64,13 +64,25 @@ class TestExports(TestCase):
|
||||||
ExportsFactory(export_type, self._complete_city, self._output_path).export()
|
ExportsFactory(export_type, self._complete_city, self._output_path).export()
|
||||||
|
|
||||||
def test_obj_export(self):
|
def test_obj_export(self):
|
||||||
|
"""
|
||||||
|
export to obj
|
||||||
|
"""
|
||||||
self._export('obj', False)
|
self._export('obj', False)
|
||||||
|
|
||||||
def test_stl_export(self):
|
def test_stl_export(self):
|
||||||
|
"""
|
||||||
|
export to stl
|
||||||
|
"""
|
||||||
self._export('stl', False)
|
self._export('stl', False)
|
||||||
|
|
||||||
def test_energy_ade_export(self):
|
def test_energy_ade_export(self):
|
||||||
|
"""
|
||||||
|
export to energy ADE
|
||||||
|
"""
|
||||||
self._export('energy_ade')
|
self._export('energy_ade')
|
||||||
|
|
||||||
def test_sra_export(self):
|
def test_sra_export(self):
|
||||||
|
"""
|
||||||
|
export to SRA
|
||||||
|
"""
|
||||||
self._export('sra')
|
self._export('sra')
|
||||||
|
|
|
@ -7,6 +7,7 @@ from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from imports.geometry_factory import GeometryFactory
|
from imports.geometry_factory import GeometryFactory
|
||||||
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
from imports.geometry.helpers.geometry_helper import GeometryHelper
|
||||||
|
from city_model_structure.building_demand.thermal_opening import ThermalOpening
|
||||||
|
|
||||||
|
|
||||||
class TestGeometryFactory(TestCase):
|
class TestGeometryFactory(TestCase):
|
||||||
|
@ -156,6 +157,7 @@ class TestGeometryFactory(TestCase):
|
||||||
for thermal_zone in building.thermal_zones:
|
for thermal_zone in building.thermal_zones:
|
||||||
self.assertIsNot(len(thermal_zone.thermal_boundaries), 0, 'no building thermal_boundaries defined')
|
self.assertIsNot(len(thermal_zone.thermal_boundaries), 0, 'no building thermal_boundaries defined')
|
||||||
for thermal_boundary in thermal_zone.thermal_boundaries:
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||||
|
thermal_opening: ThermalOpening
|
||||||
for thermal_opening in thermal_boundary.thermal_openings:
|
for thermal_opening in thermal_boundary.thermal_openings:
|
||||||
self.assertIsNone(thermal_opening.frame_ratio, 'thermal_opening frame_ratio was initialized')
|
self.assertIsNone(thermal_opening.frame_ratio, 'thermal_opening frame_ratio was initialized')
|
||||||
self.assertIsNone(thermal_opening.g_value, 'thermal_opening g_value was initialized')
|
self.assertIsNone(thermal_opening.g_value, 'thermal_opening g_value was initialized')
|
||||||
|
@ -167,7 +169,8 @@ class TestGeometryFactory(TestCase):
|
||||||
self.assertIsNone(thermal_opening.front_side_solar_transmittance_at_normal_incidence,
|
self.assertIsNone(thermal_opening.front_side_solar_transmittance_at_normal_incidence,
|
||||||
'thermal_opening front_side_solar_transmittance_at_normal_incidence was initialized')
|
'thermal_opening front_side_solar_transmittance_at_normal_incidence was initialized')
|
||||||
self.assertIsNone(thermal_opening.thickness, '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')
|
self.assertRaises(Exception, lambda: thermal_opening.overall_u_value,
|
||||||
|
'thermal_opening u_value was initialized')
|
||||||
self.assertIsNone(thermal_opening.overall_u_value, 'thermal_opening overall_u_value was initialized')
|
self.assertIsNone(thermal_opening.overall_u_value, 'thermal_opening overall_u_value was initialized')
|
||||||
self.assertIsNone(thermal_opening.hi, 'thermal_opening hi was initialized')
|
self.assertIsNone(thermal_opening.hi, 'thermal_opening hi was initialized')
|
||||||
self.assertIsNone(thermal_opening.he, 'thermal_opening he was initialized')
|
self.assertIsNone(thermal_opening.he, 'thermal_opening he was initialized')
|
||||||
|
@ -227,6 +230,9 @@ class TestGeometryFactory(TestCase):
|
||||||
|
|
||||||
# obj
|
# obj
|
||||||
def test_import_obj(self):
|
def test_import_obj(self):
|
||||||
|
"""
|
||||||
|
Test obj import
|
||||||
|
"""
|
||||||
file = 'kelowna.obj'
|
file = 'kelowna.obj'
|
||||||
city = self._get_obj(file)
|
city = self._get_obj(file)
|
||||||
self.assertIsNotNone(city, 'city is none')
|
self.assertIsNotNone(city, 'city is none')
|
||||||
|
@ -240,6 +246,6 @@ class TestGeometryFactory(TestCase):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
file_path = (self._example_path / 'subway.osm').resolve()
|
file_path = (self._example_path / 'subway.osm').resolve()
|
||||||
subway_entrances = self._features = GeometryFactory('osm_subway', file_path).features
|
city = GeometryFactory('osm_subway', file_path).city
|
||||||
self.assertIsNotNone(subway_entrances, 'subway entrances is none')
|
self.assertIsNotNone(city, 'subway entrances is none')
|
||||||
self.assertEqual(len(subway_entrances), 20, 'Wrong number of subway entrances')
|
self.assertEqual(len(city.city_objects), 20, 'Wrong number of subway entrances')
|
||||||
|
|
|
@ -23,20 +23,22 @@ class TestSchedulesFactory(TestCase):
|
||||||
Configure test environment
|
Configure test environment
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self._city_gml = None
|
|
||||||
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
||||||
|
|
||||||
def _get_citygml(self, file):
|
def _get_citygml(self, file):
|
||||||
file_path = (self._example_path / file).resolve()
|
file_path = (self._example_path / file).resolve()
|
||||||
self._city = GeometryFactory('citygml', file_path).city
|
_city = GeometryFactory('citygml', file_path).city
|
||||||
ConstructionFactory('nrel', self._city).enrich()
|
ConstructionFactory('nrel', _city).enrich()
|
||||||
self.assertIsNotNone(self._city, 'city is none')
|
self.assertIsNotNone(_city, 'city is none')
|
||||||
for building in self._city.buildings:
|
for building in _city.buildings:
|
||||||
building.function = GeometryHelper.hft_to_function[building.function]
|
building.function = GeometryHelper.hft_to_function[building.function]
|
||||||
UsageFactory('hft', self._city).enrich()
|
UsageFactory('hft', _city).enrich()
|
||||||
return self._city
|
return _city
|
||||||
|
|
||||||
def test_comnet_archetypes(self):
|
def test_comnet_archetypes(self):
|
||||||
|
"""
|
||||||
|
Enrich the city with commet schedule archetypes and verify it
|
||||||
|
"""
|
||||||
file = (self._example_path / 'one_building_in_kelowna.gml').resolve()
|
file = (self._example_path / 'one_building_in_kelowna.gml').resolve()
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
occupancy_handler = 'comnet'
|
occupancy_handler = 'comnet'
|
||||||
|
@ -48,6 +50,9 @@ class TestSchedulesFactory(TestCase):
|
||||||
self.assertTrue(usage_zone.schedules)
|
self.assertTrue(usage_zone.schedules)
|
||||||
|
|
||||||
def test_doe_idf_archetypes(self):
|
def test_doe_idf_archetypes(self):
|
||||||
|
"""
|
||||||
|
Enrich the city with doe_idf schedule archetypes and verify it
|
||||||
|
"""
|
||||||
file = (self._example_path / 'C40_Final.gml').resolve()
|
file = (self._example_path / 'C40_Final.gml').resolve()
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
occupancy_handler = 'doe_idf'
|
occupancy_handler = 'doe_idf'
|
||||||
|
@ -57,4 +62,3 @@ class TestSchedulesFactory(TestCase):
|
||||||
for schedule in usage_zone.schedules:
|
for schedule in usage_zone.schedules:
|
||||||
print(schedule)
|
print(schedule)
|
||||||
print(usage_zone.schedules[schedule])
|
print(usage_zone.schedules[schedule])
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,9 @@ Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
import pandas as pd
|
|
||||||
from city_model_structure.city import City
|
|
||||||
from city_model_structure.building import Building
|
from city_model_structure.building import Building
|
||||||
from city_model_structure.buildings_cluster import BuildingsCluster
|
from city_model_structure.buildings_cluster import BuildingsCluster
|
||||||
|
from city_model_structure.city import City
|
||||||
from imports.sensors_factory import SensorsFactory
|
from imports.sensors_factory import SensorsFactory
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,6 +46,9 @@ class TestSensorsFactory(TestCase):
|
||||||
return city
|
return city
|
||||||
|
|
||||||
def test_city_with_sensors(self):
|
def test_city_with_sensors(self):
|
||||||
|
"""
|
||||||
|
Load concordia sensors and verify it
|
||||||
|
"""
|
||||||
SensorsFactory('cec', self._city, self._end_point).enrich()
|
SensorsFactory('cec', self._city, self._end_point).enrich()
|
||||||
SensorsFactory('cgf', self._city, self._end_point).enrich()
|
SensorsFactory('cgf', self._city, self._end_point).enrich()
|
||||||
SensorsFactory('ct', self._city, self._end_point).enrich()
|
SensorsFactory('ct', self._city, self._end_point).enrich()
|
||||||
|
|
|
@ -20,14 +20,13 @@ class TestUsageFactory(TestCase):
|
||||||
Configure test environment
|
Configure test environment
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self._city_gml = None
|
|
||||||
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
||||||
|
|
||||||
def _get_citygml(self, file):
|
def _get_citygml(self, file):
|
||||||
file_path = (self._example_path / file).resolve()
|
file_path = (self._example_path / file).resolve()
|
||||||
self._city = GeometryFactory('citygml', file_path).city
|
_city = GeometryFactory('citygml', file_path).city
|
||||||
self.assertIsNotNone(self._city, 'city is none')
|
self.assertIsNotNone(_city, 'city is none')
|
||||||
return self._city
|
return _city
|
||||||
|
|
||||||
def test_city_with_usage(self):
|
def test_city_with_usage(self):
|
||||||
"""
|
"""
|
||||||
|
|
2
pylintrc
2
pylintrc
|
@ -325,6 +325,8 @@ good-names=i,
|
||||||
y,
|
y,
|
||||||
z,
|
z,
|
||||||
s,
|
s,
|
||||||
|
df,
|
||||||
|
id
|
||||||
_
|
_
|
||||||
|
|
||||||
# Good variable names regexes, separated by a comma. If names match any regex,
|
# Good variable names regexes, separated by a comma. If names match any regex,
|
||||||
|
|
|
@ -8,7 +8,7 @@ from unittest import TestCase
|
||||||
from imports.geometry_factory import GeometryFactory
|
from imports.geometry_factory import GeometryFactory
|
||||||
|
|
||||||
|
|
||||||
class MyTestCase(TestCase):
|
class TestBuildings(TestCase):
|
||||||
"""
|
"""
|
||||||
TestBuilding TestCase 1
|
TestBuilding TestCase 1
|
||||||
"""
|
"""
|
||||||
|
@ -28,6 +28,9 @@ class MyTestCase(TestCase):
|
||||||
return self._city_gml
|
return self._city_gml
|
||||||
|
|
||||||
def test_storeys_division(self):
|
def test_storeys_division(self):
|
||||||
|
"""
|
||||||
|
Test storeys division
|
||||||
|
"""
|
||||||
file = 'kelowna.gml'
|
file = 'kelowna.gml'
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
i = 0
|
i = 0
|
||||||
|
|
|
@ -74,6 +74,9 @@ class TestGeometryFactory(TestCase):
|
||||||
self.assertEqual(counter, 1, f'{counter} buildings had errors when triangulating surfaces')
|
self.assertEqual(counter, 1, f'{counter} buildings had errors when triangulating surfaces')
|
||||||
|
|
||||||
def test_stuttgart_gml(self):
|
def test_stuttgart_gml(self):
|
||||||
|
"""
|
||||||
|
Tests stuttgart gml
|
||||||
|
"""
|
||||||
file = '20190815_mitte_out_MC_FloursurfaceADD.gml'
|
file = '20190815_mitte_out_MC_FloursurfaceADD.gml'
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
print(f'city name: {city.name}')
|
print(f'city name: {city.name}')
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
"""
|
|
||||||
TestOccupancyFactory test and validate the city model structure schedules parameters
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|
||||||
"""
|
|
||||||
from pathlib import Path
|
|
||||||
from unittest import TestCase
|
|
||||||
from imports.geometry_factory import GeometryFactory
|
|
||||||
from imports.construction_factory import ConstructionFactory
|
|
||||||
from imports.usage_factory import UsageFactory
|
|
||||||
from imports.schedules_factory import SchedulesFactory
|
|
||||||
from exports.exports_factory import ExportsFactory
|
|
||||||
import os
|
|
||||||
import glob
|
|
||||||
|
|
||||||
|
|
||||||
class TestIdf(TestCase):
|
|
||||||
"""
|
|
||||||
Test IDF Class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
"""
|
|
||||||
Test setup
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
self._city_gml = None
|
|
||||||
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
|
||||||
self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
|
|
||||||
|
|
||||||
def _get_city(self):
|
|
||||||
if self._city_gml is None:
|
|
||||||
file_path = (self._example_path / 'pluto_building.gml').resolve()
|
|
||||||
self._city_gml = GeometryFactory('citygml', file_path).city
|
|
||||||
ConstructionFactory('us_new_york', self._city_gml)
|
|
||||||
UsageFactory('us_new_york', self._city_gml)
|
|
||||||
UsageFactory('us_new_york', self._city_gml)
|
|
||||||
SchedulesFactory('demo', self._city_gml)
|
|
||||||
return self._city_gml
|
|
||||||
|
|
||||||
def test_idf_blocks(self):
|
|
||||||
idd_file_path = (self._example_path / 'energy+.idd').resolve()
|
|
||||||
idf_file_path = (self._example_path / 'minimal.idf').resolve()
|
|
||||||
epw_file_path = (self._example_path / 'montreal.epw').resolve()
|
|
||||||
idf = IdfHelper(idf_file_path, idd_file_path, epw_file_path)
|
|
||||||
city = self._get_city()
|
|
||||||
for building in city.buildings:
|
|
||||||
idf.add_block(building)
|
|
||||||
test_prefix = 'test_idf_blocks'
|
|
||||||
idf.run(self._output_path, output_prefix=test_prefix, keep_file=self._output_path)
|
|
||||||
eso_file_path = (self._output_path / f'{test_prefix}out.eso')
|
|
||||||
heating, cooling = idf.read_eso(str(eso_file_path))
|
|
||||||
self.assertEqual(len(heating), len(cooling), "Cooling and Heating doesn't contains the same amount of values")
|
|
||||||
self.assertNotEqual(len(heating), 0, "Cooling and Heating series are empty")
|
|
||||||
file_list = glob.glob(str(Path(self._output_path / '*').resolve()))
|
|
||||||
for file_path in file_list:
|
|
||||||
os.remove(file_path)
|
|
||||||
|
|
||||||
def test_idf_surfaces(self):
|
|
||||||
idd_file_path = (self._example_path / 'energy+.idd').resolve()
|
|
||||||
idf_file_path = (self._example_path / 'minimal.idf').resolve()
|
|
||||||
epw_file_path = (self._example_path / 'montreal.epw').resolve()
|
|
||||||
|
|
||||||
idf = IdfHelper(idf_file_path, idd_file_path, epw_file_path)
|
|
||||||
city = self._get_city()
|
|
||||||
for building in city.buildings:
|
|
||||||
idf.add_surfaces(building)
|
|
||||||
idf.add_schedule(building)
|
|
||||||
idf.add_occupancy()
|
|
||||||
test_prefix = 'test_idf_blocks'
|
|
||||||
idf.run(self._output_path, output_prefix=test_prefix, keep_file=self._output_path)
|
|
||||||
eso_file_path = (self._output_path / f'{test_prefix}out.eso')
|
|
||||||
heating, cooling = idf.read_eso(str(eso_file_path))
|
|
||||||
self.assertEqual(len(heating), len(cooling), "Cooling and Heating doesn't contains the same amount of values")
|
|
||||||
self.assertNotEqual(len(heating), 0, "Cooling and Heating series are empty")
|
|
||||||
file_list = glob.glob(str(Path(self._output_path / '*').resolve()))
|
|
||||||
for file_path in file_list:
|
|
||||||
os.remove(file_path)
|
|
|
@ -31,6 +31,9 @@ class TestWeatherFactory(TestCase):
|
||||||
return self._city_gml
|
return self._city_gml
|
||||||
|
|
||||||
def test_weather_xls(self):
|
def test_weather_xls(self):
|
||||||
|
"""
|
||||||
|
Enrich the city with xls weather file and verify it
|
||||||
|
"""
|
||||||
file_path = (Path(__file__).parent / 'tests_data' / 'iso_52016_1_2017_lod2.gml').resolve()
|
file_path = (Path(__file__).parent / 'tests_data' / 'iso_52016_1_2017_lod2.gml').resolve()
|
||||||
city_with_weather = self._get_citygml(file_path)
|
city_with_weather = self._get_citygml(file_path)
|
||||||
WeatherFactory('xls', city_with_weather, base_path=self._example_path).enrich()
|
WeatherFactory('xls', city_with_weather, base_path=self._example_path).enrich()
|
||||||
|
@ -41,6 +44,9 @@ class TestWeatherFactory(TestCase):
|
||||||
self.assertFalse(values.empty, 'wrong value global horizontal')
|
self.assertFalse(values.empty, 'wrong value global horizontal')
|
||||||
|
|
||||||
def test_weather_epw(self):
|
def test_weather_epw(self):
|
||||||
|
"""
|
||||||
|
Enrich the city with epw weather and verify it
|
||||||
|
"""
|
||||||
file_path = (Path(__file__).parent / 'tests_data' / 'one_building_in_kelowna.gml').resolve()
|
file_path = (Path(__file__).parent / 'tests_data' / 'one_building_in_kelowna.gml').resolve()
|
||||||
city_with_weather = self._get_citygml(file_path)
|
city_with_weather = self._get_citygml(file_path)
|
||||||
_file_name = 'CAN_BC_Summerland.717680_CWEC.epw'
|
_file_name = 'CAN_BC_Summerland.717680_CWEC.epw'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user