Quality improvements

This commit is contained in:
Guille Gutierrez 2021-08-27 12:51:30 -04:00
parent 312a9c34be
commit 62bca29a82
35 changed files with 227 additions and 268 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,7 +69,6 @@ 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)
@ -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

View File

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

View File

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

View File

@ -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,33 +47,32 @@ 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'})

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = []
@ -118,7 +119,8 @@ class HftUsageInterface:
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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):
""" """

View File

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

View File

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

View File

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

View File

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

View File

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