Quality improvements
This commit is contained in:
parent
312a9c34be
commit
62bca29a82
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]
|
|
@ -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):
|
||||
|
|
|
@ -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'
|
|
@ -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?
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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,7 +69,6 @@ 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)
|
||||
|
||||
|
@ -113,4 +112,3 @@ class DoeIdf:
|
|||
if usage_zone.schedules is None:
|
||||
usage_zone.schedules = {}
|
||||
usage_zone.schedules[schedule_type] = df
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,33 +47,32 @@ 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)
|
||||
|
||||
@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'})
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -8,6 +8,9 @@ import helpers.constants as cte
|
|||
|
||||
|
||||
class UsageHelper:
|
||||
"""
|
||||
Usage helpre class
|
||||
"""
|
||||
usage_to_hft = {
|
||||
cte.RESIDENTIAL: 'residential',
|
||||
cte.INDUSTRY: 'industry',
|
||||
|
|
|
@ -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 = []
|
||||
|
@ -118,7 +119,8 @@ class HftUsageInterface:
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -7,7 +7,7 @@ import math
|
|||
import helpers.constants as cte
|
||||
|
||||
|
||||
class Weather(object):
|
||||
class Weather:
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
from pathlib import Path
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import pandas as pd
|
||||
import helpers.constants as cte
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -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:
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
2
pylintrc
2
pylintrc
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}')
|
||||
|
|
|
@ -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
|
||||
|
||||
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'
|
||||
|
|
Loading…
Reference in New Issue
Block a user