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
"""
def __init__(self, surface, delimits):
def __init__(self, surface, thermal_zones):
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,
# review for LOD3 and LOD4
self._thermal_openings = None
@ -50,12 +50,12 @@ class ThermalBoundary:
return self._surface
@property
def delimits(self) -> List[ThermalZone]:
def thermal_zones(self) -> List[ThermalZone]:
"""
Get the thermal zones delimited by the thermal boundary
:return: [ThermalZone]
"""
return self._delimits
return self._thermal_zones
@property
def azimuth(self):

View File

@ -7,10 +7,10 @@ import numpy as np
import xmltodict
from city_model_structure.city import City
from city_model_structure.building import Building
from city_model_structure.parts_consisting_building import PartsConsistingBuilding
from helpers.geometry_helper import GeometryHelper
from imports.geometry.citygml_classes.citygml_lod2 import CityGmlLod2
from imports.geometry.citygml_classes.citygml_lod1 import CityGmlLod1
from city_model_structure.parts_consisting_building import PartsConsistingBuilding
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
Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
@ -18,14 +19,6 @@ class CityGmlLod1(CityGmlBase):
def _multi_curve(cls, o):
pass
@classmethod
def _multi_surface(cls, o):
pass
@classmethod
def _solid(cls, o):
pass
def __init__(self, o):
super().__init__()
self._o = o
@ -35,14 +28,16 @@ class CityGmlLod1(CityGmlBase):
def _identify(cls, o):
if 'lod1Solid' in o:
return cls._solid(o)
elif 'lod1MultiSurface' in o:
if 'lod1MultiSurface' in o:
return cls._multi_surface(o)
raise NotImplementedError(o)
@staticmethod
def _solid(o):
@classmethod
def _solid(cls, o):
try:
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']]
except TypeError:
solid_points = [
@ -51,9 +46,10 @@ class CityGmlLod1(CityGmlBase):
return [Surface(Polygon(sp), Polygon(sp)) for sp in solid_points]
@staticmethod
def _multi_surface(o):
@classmethod
def _multi_surface(cls, o):
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']]
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
Copyright © 2021 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
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.attributes.polygon import Polygon
from imports.geometry.helpers.geometry_helper import GeometryHelper
class CityGmlLod2(CityGmlBase):
@ -23,10 +24,11 @@ class CityGmlLod2(CityGmlBase):
def _identify(cls, o):
if 'lod2Solid' in o:
return cls._solid(o)
elif 'lod2MultiSurface' in o:
if 'lod2MultiSurface' in o:
return cls._multi_surface(o)
elif 'lod2MultiCurve' in o:
if 'lod2MultiCurve' in o:
return cls._multi_curve(o)
raise NotImplementedError(o)
@staticmethod
def _surface_encoding(surfaces):

View File

@ -8,6 +8,9 @@ import helpers.constants as cte
class GeometryHelper:
"""
Geometry helper
"""
# function
pluto_to_function = {
'A0': 'single family house',
@ -307,22 +310,13 @@ class GeometryHelper:
points = points.reshape(rows, 3)
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
def gml_surface_to_libs(surface):
"""
Transform citygml surface names into libs names
"""
if surface == 'WallSurface':
return 'Wall'
elif surface == 'GroundSurface':
if surface == 'GroundSurface':
return 'Ground'
else:
return 'Roof'
return 'Roof'

View File

@ -21,8 +21,8 @@ class Obj:
with open(path, 'r') as file:
self._scene = trimesh.exchange.load.load(file, file_type='obj', force='scene')
self._corners = self._scene.bounds_corners
_bound_corner_min = None
_bound_corner_max = None
_bound_corner_min = []
_bound_corner_max = []
for corner in self._corners:
if _bound_corner_min is None:
_bound_corner_min = corner
@ -40,10 +40,16 @@ class Obj:
@property
def scene(self) -> Scene:
"""
Obj scene
"""
return self._scene
@property
def city(self) -> City:
"""
Create a city out of an obj file
"""
if self._city is None:
# todo: refactor this method to clearly choose the obj type
# 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
"""
import sys
import xmltodict
from pyproj import Transformer
from city_model_structure.city import City
from city_model_structure.subway_entrance import SubwayEntrance
class OsmSubway:
"""
Open street map subway
"""
def __init__(self, path):
self._city = None
self._subway_entrances = []
with open(path) as osm:
self._osm = xmltodict.parse(osm.read(), force_list='tag')
@ -24,5 +31,24 @@ class OsmSubway:
self._subway_entrances.append(subway_entrance)
@property
def subway_entrances(self):
return self._subway_entrances
def city(self) -> City:
"""
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
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_object import CityObject
from imports.geometry.citygml import CityGml
from imports.geometry.osm_subway import OsmSubway
from imports.geometry.obj import Obj
from imports.geometry.osm_subway import OsmSubway
class GeometryFactory:
@ -24,21 +22,13 @@ class GeometryFactory:
def _citygml(self):
return CityGml(self._path).city
@property
def _stl(self):
raise Exception('Not implemented')
@property
def _obj(self):
return Obj(self._path).scene
return Obj(self._path).city
@property
def _geojson(self):
raise Exception('Not implemented')
@property
def _bim(self):
raise Exception('Not implemented')
def _osm_subway(self):
return OsmSubway(self._path).city
@property
def city(self) -> City:
@ -47,37 +37,3 @@ class GeometryFactory:
:return: City
"""
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:
"""
Commet based schedules
"""
def __init__(self, city, base_path):
self._city = city
self._comnet_schedules_path = base_path / 'comnet_archetypes.xlsx'

View File

@ -23,12 +23,12 @@ class DoeIdf:
def __init__(self, city, base_path):
self._hours = []
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._city = city
self._idf_schedules_path = base_path / 'ASHRAE901_OfficeSmall_STD2019_Buffalo.idf'
with open(self._idf_schedules_path, 'r') as f:
idf = parseidf.parse(f.read())
with open(self._idf_schedules_path, 'r') as file:
idf = parseidf.parse(file.read())
self._load_schedule(idf, 'small_office')
self._load_schedule(idf, 'residential')
@ -69,9 +69,8 @@ class DoeIdf:
if hour == hour_formatted:
hour_index += index
break
else:
entry = days_schedules[hours_values + 1]
schedules_day[f'{days_schedules[day_index]}'].append(entry)
entry = days_schedules[hours_values + 1]
schedules_day[f'{days_schedules[day_index]}'].append(entry)
if 'Weekdays' in days_schedules[day_index]:
data['WD'] = []
@ -101,9 +100,9 @@ class DoeIdf:
data['Sat'].append(entry)
elif 'Sunday' in days_schedules[day_index]:
data['Sun'] = []
for entry in schedules_day[f'{days_schedules[day_index]}']:
data['Sun'].append(entry)
data['Sun'] = []
for entry in schedules_day[f'{days_schedules[day_index]}']:
data['Sun'].append(entry)
else:
continue
df = pd.DataFrame(data, index=rows)
@ -113,4 +112,3 @@ class DoeIdf:
if usage_zone.schedules is None:
usage_zone.schedules = {}
usage_zone.schedules[schedule_type] = df

View File

@ -9,6 +9,9 @@ import helpers.constants as cte
class SchedulesHelper:
"""
Schedules helper
"""
usage_to_comnet = {
cte.RESIDENTIAL: 'C-12 Residential',
cte.INDUSTRY: 'C-10 Warehouse',

View File

@ -9,7 +9,9 @@ from city_model_structure.iot.concordia_energy_sensor import ConcordiaEnergySens
class ConcordiaEnergyConsumption(ConcordiaFileReport):
"""
Concordia energy consumption sensor class
"""
def __init__(self, city, end_point, base_path):
super().__init__(city, end_point, base_path, 'concordia_energy_db.json')
for city_object in city.city_objects:

View File

@ -11,8 +11,10 @@ import pandas as pd
class ConcordiaFileReport:
"""
Concordia file report for sensors base class
"""
def __init__(self, city, end_point, base_path, db_file):
self._city_object = []
self._city_objects_cluster = []
self._sensors = []
@ -34,7 +36,7 @@ class ConcordiaFileReport:
buffer = ""
with open(end_point.resolve()) as data:
for line in data:
line = ConcordiaFileReport.clean_line(line)
line = ConcordiaFileReport._clean_line(line)
if metadata:
fields = line.split(',')
if len(fields) > 2:
@ -45,34 +47,33 @@ class ConcordiaFileReport:
if "End of Report" in line:
content = False
if content:
line = ConcordiaFileReport.merge_date_time(line)
line = ConcordiaFileReport._merge_date_time(line)
buffer = buffer + line + '\n'
if line is '':
if line == '':
metadata = False
content = True
measures = pd.read_csv(io.StringIO(buffer), sep=',')
measures["Date time"] = pd.to_datetime(measures["Date time"])
self._measures = ConcordiaFileReport.force_format(measures)
self._measures = ConcordiaFileReport._force_format(measures)
@staticmethod
def clean_line(line):
def _clean_line(line):
return line.replace('"', '').replace('\n', '')
@staticmethod
def merge_date_time(line):
def _merge_date_time(line):
fields = line.split(',')
date = fields[0]
time = fields[1]
if '<>' in date:
return line.replace(f'{date},{time}', 'Date time')
else:
date_fields = date.split('/')
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)
date_fields = date.split('/')
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)
@staticmethod
def force_format(df):
def _force_format(df):
for head in df.head():
if 'Date time' not in head:
df = df.astype({head: 'float64'})
return df
return df

View File

@ -9,6 +9,9 @@ from city_model_structure.iot.concordia_gas_flow_sensor import ConcordiaGasFlowS
class ConcordiaGasFlow(ConcordiaFileReport):
"""
Concordia gas flow sensor class
"""
def __init__(self, city, end_point, base_path):
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):
"""
Concordia temperature sensor class
"""
def __init__(self, city, end_point, base_path):
super().__init__(city, end_point, base_path, 'concordia_temperature_db.json')
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.
# Therefore, this walk around has been done.
internal_gains = []
for ig in archetype.internal_gains:
for archetype_internal_gain in archetype.internal_gains:
internal_gain = InternalGains()
internal_gain.average_internal_gain = ig.average_internal_gain
internal_gain.convective_fraction = ig.convective_fraction
internal_gain.radiative_fraction = ig.radiative_fraction
internal_gain.latent_fraction = ig.latent_fraction
internal_gain.average_internal_gain = archetype_internal_gain.average_internal_gain
internal_gain.convective_fraction = archetype_internal_gain.convective_fraction
internal_gain.radiative_fraction = archetype_internal_gain.radiative_fraction
internal_gain.latent_fraction = archetype_internal_gain.latent_fraction
internal_gains.append(internal_gain)
usage_zone.internal_gains = internal_gains
usage_zone.heating_setpoint = archetype.heating_setpoint

View File

@ -8,6 +8,9 @@ import helpers.constants as cte
class UsageHelper:
"""
Usage helpre class
"""
usage_to_hft = {
cte.RESIDENTIAL: 'residential',
cte.INDUSTRY: 'industry',

View File

@ -13,6 +13,7 @@ class HftUsageInterface:
"""
HftUsageInterface abstract class
"""
def __init__(self, base_path, usage_file='ca_library_reduced.xml'):
path = str(base_path / usage_file)
self._usage_archetypes = []
@ -44,17 +45,17 @@ class HftUsageInterface:
if 'domestic_hot_water' in zone_usage_type['endUses']:
# liters to cubic meters
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']
electrical_app_average_consumption_sqm_year = None
if 'all_electrical_appliances' in zone_usage_type['endUses']:
if 'averageConsumptionPerSqmAndYear' in zone_usage_type['endUses']['all_electrical_appliances']:
# kWh to J
electrical_app_average_consumption_sqm_year = \
float(zone_usage_type['endUses']['all_electrical_appliances']['averageConsumptionPerSqmAndYear'])/3.6
if 'averageConsumptionPerSqmAndYear' in zone_usage_type['endUses']['all_electrical_appliances']:
# kWh to J
electrical_app_average_consumption_sqm_year = \
float(zone_usage_type['endUses']['all_electrical_appliances']['averageConsumptionPerSqmAndYear']) / 3.6
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
# There are no more internal gains? How is it saved when more than one???
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
# There are no more internal gains? How is it saved when more than one???
internal_gains = []
if 'internGains' in zone_usage_type['occupancy']:
latent_fraction = zone_usage_type['occupancy']['internGains']['latentFraction']
@ -93,7 +94,7 @@ class HftUsageInterface:
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
# 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]
latent_fraction = internal_gains.latent_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 'mechanicalAirChangeRate' in usage_zone_variant['endUses']['ventilation']:
mechanical_air_change = usage_zone_variant['endUses']['ventilation']['mechanicalAirChangeRate']
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
# There are no more internal gains? How is it saved when more than one???
# todo: for internal_gain in usage_zone_variant['schedules']['internGains']:????????????????
# There are no more internal gains? How is it saved when more than one???
if 'schedules' in usage_zone_variant:
if 'usageHoursPerDay' in usage_zone_variant['schedules']:
hours_day = usage_zone_variant['schedules']['usageHoursPerDay']
if 'usageDaysPerYear' in usage_zone_variant['schedules']:
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 = []
if 'latentFraction' in usage_zone_variant['schedules']['internGains']:
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,
mechanical_air_change=mechanical_air_change)
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.
# Therefore, this walk around has been done.
internal_gains = []
for ig in archetype.internal_gains:
for archetype_internal_gain in archetype.internal_gains:
internal_gain = InternalGains()
internal_gain.average_internal_gain = ig.average_internal_gain
internal_gain.convective_fraction = ig.convective_fraction
internal_gain.radiative_fraction = ig.radiative_fraction
internal_gain.latent_fraction = ig.latent_fraction
internal_gain.average_internal_gain = archetype_internal_gain.average_internal_gain
internal_gain.convective_fraction = archetype_internal_gain.convective_fraction
internal_gain.radiative_fraction = archetype_internal_gain.radiative_fraction
internal_gain.latent_fraction = archetype_internal_gain.latent_fraction
internal_gains.append(internal_gain)
usage_zone.internal_gains = internal_gains
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
"""
import pandas as pd
from pathlib import Path
import sys
from pathlib import Path
import pandas as pd
import helpers.constants as cte
@ -14,6 +14,7 @@ class DatWeatherParameters:
"""
DatWeatherParameters class
"""
def __init__(self, city, path):
self._weather_values = None
self._city = city
@ -23,7 +24,7 @@ class DatWeatherParameters:
if self._weather_values is None:
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'])
except SystemExit:
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
"""
import pandas as pd
from pathlib import Path
import sys
from pathlib import Path
import pandas as pd
import helpers.constants as cte
@ -41,7 +41,7 @@ class EpwWeatherParameters:
file.close()
except SystemExit:
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()
try:

View File

@ -7,7 +7,7 @@ import math
import helpers.constants as cte
class Weather(object):
class Weather:
"""
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
"""
import pandas as pd
from pathlib import Path
import sys
from pathlib import Path
import pandas as pd
import helpers.constants as cte

View File

@ -11,7 +11,7 @@ from imports.weather_factory import WeatherFactory
from exports.exports_factory import ExportsFactory
class MyTestCase(TestCase):
class TestC40(TestCase):
"""
C40 TestCase 1
"""
@ -31,26 +31,29 @@ class MyTestCase(TestCase):
return self._city_gml
def test_c40_enrichment(self):
"""
Enrich the C40 building
"""
file = 'C40_Final.gml'
base_path = (Path(__file__).parent.parent / 'data' / 'weather').resolve()
weather_file_name = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw'
city = self._get_citygml(file)
for building in city.buildings:
for tz in building.thermal_zones:
for tb in tz.thermal_boundaries:
tb.hi = 10
tb.he = 25
for opening in tb.thermal_openings:
opening.hi = 10
opening.he = 25
for thermal_zone in building.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
thermal_boundary.hi = 10
thermal_boundary.he = 25
for thermal_opening in thermal_boundary.thermal_openings:
thermal_opening.hi = 10
thermal_opening.he = 25
building.function = 'residential'
ConstructionFactory('nrel', city).enrich()
for building in city.buildings:
print(building.name, building.function, len(building.surfaces))
print(building.volume)
for tz in building.thermal_zones:
print(tz.volume)
print(tz.floor_area)
for thermal_zone in building.thermal_zones:
print(thermal_zone.volume)
print(thermal_zone.floor_area)
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)
for building in city.buildings:
building.function = GeometryHelper.pluto_to_function[building.function]
for tz in building.thermal_zones:
for tb in tz.thermal_boundaries:
tb.hi = 10
tb.he = 25
for opening in tb.thermal_openings:
opening.hi = 10
opening.he = 25
for thermal_zone in building.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
thermal_boundary.hi = 10
thermal_boundary.he = 25
for thermal_opening in thermal_boundary.thermal_openings:
thermal_opening.hi = 10
thermal_opening.he = 25
# case 1: NREL
ConstructionFactory('nrel', city).enrich()
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.thermal_boundaries, 'thermal_boundaries is none')
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.window_ratio, 'window_ratio is none')
print(thermal_boundary.layers)
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'
city = self._get_citygml(file)
for building in city.buildings:

View File

@ -64,13 +64,25 @@ class TestExports(TestCase):
ExportsFactory(export_type, self._complete_city, self._output_path).export()
def test_obj_export(self):
"""
export to obj
"""
self._export('obj', False)
def test_stl_export(self):
"""
export to stl
"""
self._export('stl', False)
def test_energy_ade_export(self):
"""
export to energy ADE
"""
self._export('energy_ade')
def test_sra_export(self):
"""
export to SRA
"""
self._export('sra')

View File

@ -7,6 +7,7 @@ from pathlib import Path
from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.geometry.helpers.geometry_helper import GeometryHelper
from city_model_structure.building_demand.thermal_opening import ThermalOpening
class TestGeometryFactory(TestCase):
@ -156,6 +157,7 @@ class TestGeometryFactory(TestCase):
for thermal_zone in building.thermal_zones:
self.assertIsNot(len(thermal_zone.thermal_boundaries), 0, 'no building thermal_boundaries defined')
for thermal_boundary in thermal_zone.thermal_boundaries:
thermal_opening: ThermalOpening
for thermal_opening in thermal_boundary.thermal_openings:
self.assertIsNone(thermal_opening.frame_ratio, 'thermal_opening frame_ratio 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,
'thermal_opening front_side_solar_transmittance_at_normal_incidence 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.hi, 'thermal_opening hi was initialized')
self.assertIsNone(thermal_opening.he, 'thermal_opening he was initialized')
@ -227,6 +230,9 @@ class TestGeometryFactory(TestCase):
# obj
def test_import_obj(self):
"""
Test obj import
"""
file = 'kelowna.obj'
city = self._get_obj(file)
self.assertIsNotNone(city, 'city is none')
@ -240,6 +246,6 @@ class TestGeometryFactory(TestCase):
:return:
"""
file_path = (self._example_path / 'subway.osm').resolve()
subway_entrances = self._features = GeometryFactory('osm_subway', file_path).features
self.assertIsNotNone(subway_entrances, 'subway entrances is none')
self.assertEqual(len(subway_entrances), 20, 'Wrong number of subway entrances')
city = GeometryFactory('osm_subway', file_path).city
self.assertIsNotNone(city, 'subway entrances is none')
self.assertEqual(len(city.city_objects), 20, 'Wrong number of subway entrances')

View File

@ -23,20 +23,22 @@ class TestSchedulesFactory(TestCase):
Configure test environment
:return:
"""
self._city_gml = None
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('citygml', file_path).city
ConstructionFactory('nrel', self._city).enrich()
self.assertIsNotNone(self._city, 'city is none')
for building in self._city.buildings:
_city = GeometryFactory('citygml', file_path).city
ConstructionFactory('nrel', _city).enrich()
self.assertIsNotNone(_city, 'city is none')
for building in _city.buildings:
building.function = GeometryHelper.hft_to_function[building.function]
UsageFactory('hft', self._city).enrich()
return self._city
UsageFactory('hft', _city).enrich()
return _city
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()
city = self._get_citygml(file)
occupancy_handler = 'comnet'
@ -48,6 +50,9 @@ class TestSchedulesFactory(TestCase):
self.assertTrue(usage_zone.schedules)
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()
city = self._get_citygml(file)
occupancy_handler = 'doe_idf'
@ -57,4 +62,3 @@ class TestSchedulesFactory(TestCase):
for schedule in usage_zone.schedules:
print(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 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.buildings_cluster import BuildingsCluster
from city_model_structure.city import City
from imports.sensors_factory import SensorsFactory
@ -47,6 +46,9 @@ class TestSensorsFactory(TestCase):
return city
def test_city_with_sensors(self):
"""
Load concordia sensors and verify it
"""
SensorsFactory('cec', self._city, self._end_point).enrich()
SensorsFactory('cgf', 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
:return:
"""
self._city_gml = None
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def _get_citygml(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(self._city, 'city is none')
return self._city
_city = GeometryFactory('citygml', file_path).city
self.assertIsNotNone(_city, 'city is none')
return _city
def test_city_with_usage(self):
"""

View File

@ -325,6 +325,8 @@ good-names=i,
y,
z,
s,
df,
id
_
# 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
class MyTestCase(TestCase):
class TestBuildings(TestCase):
"""
TestBuilding TestCase 1
"""
@ -28,6 +28,9 @@ class MyTestCase(TestCase):
return self._city_gml
def test_storeys_division(self):
"""
Test storeys division
"""
file = 'kelowna.gml'
city = self._get_citygml(file)
i = 0

View File

@ -74,6 +74,9 @@ class TestGeometryFactory(TestCase):
self.assertEqual(counter, 1, f'{counter} buildings had errors when triangulating surfaces')
def test_stuttgart_gml(self):
"""
Tests stuttgart gml
"""
file = '20190815_mitte_out_MC_FloursurfaceADD.gml'
city = self._get_citygml(file)
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
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()
city_with_weather = self._get_citygml(file_path)
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')
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()
city_with_weather = self._get_citygml(file_path)
_file_name = 'CAN_BC_Summerland.717680_CWEC.epw'