Updated branch with master origin

This commit is contained in:
Peter Yefi 2023-03-01 20:42:23 -05:00
commit c0c3dc4694
35 changed files with 26457 additions and 824 deletions

View File

@ -22,15 +22,14 @@ class ConstructionHelper:
}
_nrcan_surfaces_types_to_hub_types = {
'Wall_Outdoors': cte.WALL,
'RoofCeiling_Outdoors': cte.ROOF,
'Floor_Outdoors': cte.ATTIC_FLOOR,
'Window_Outdoors': cte.WINDOW,
'Skylight_Outdoors': cte.SKYLIGHT,
'Door_Outdoors': cte.DOOR,
'Wall_Ground': cte.GROUND_WALL,
'RoofCeiling_Ground': cte.GROUND_WALL,
'Floor_Ground': cte.GROUND
'OutdoorsWall': cte.WALL,
'OutdoorsRoofCeiling': cte.ROOF,
'OutdoorsFloor': cte.ATTIC_FLOOR,
'Window': cte.WINDOW,
'Skylight': cte.SKYLIGHT,
'GroundWall': cte.GROUND_WALL,
'GroundRoofCeiling': cte.GROUND_WALL,
'GroundFloor': cte.GROUND
}
@property

View File

@ -6,119 +6,227 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import json
import urllib.request
import xmltodict
from pathlib import Path
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.usages.content import Content
from hub.catalog_factories.data_models.construction.content import Content
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
from hub.catalog_factories.data_models.construction.construction import Construction
from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.data_models.construction.window import Window
from hub.catalog_factories.data_models.construction.material import Material
from hub.catalog_factories.data_models.construction.layer import Layer
class NrcanCatalog(Catalog):
def __init__(self, path):
path = str(path / 'nrcan.xml')
self._content = None
self._g_value_per_hdd = []
self._thermal_transmittance_per_hdd_and_surface = {}
self._window_ratios = {}
with open(path) as xml:
self._metadata = xmltodict.parse(xml.read())
self._base_url_archetypes = self._metadata['nrcan']['@base_url_archetypes']
self._base_url_construction = self._metadata['nrcan']['@base_url_construction']
self._load_window_ratios()
self._load_construction_values()
self._content = Content(self._load_archetypes())
_path_archetypes = Path(path / 'nrcan_archetypes.json').resolve()
_path_constructions = (path / 'nrcan_constructions.json')
with open(_path_archetypes, 'r') as file:
self._archetypes = json.load(file)
with open(_path_constructions, 'r') as file:
self._constructions = json.load(file)
def _load_window_ratios(self):
for standard in self._metadata['nrcan']['standards_per_function']['standard']:
url = f'{self._base_url_archetypes}{standard["file_location"]}'
# todo: read from file
self._window_ratios = {'Mean': 0.2, 'North': 0.2, 'East': 0.2, 'South': 0.2, 'West': 0.2}
self._catalog_windows = self._load_windows()
self._catalog_materials = self._load_materials()
self._catalog_constructions = self._load_constructions()
self._catalog_archetypes = self._load_archetypes()
def _load_construction_values(self):
for standard in self._metadata['nrcan']['standards_per_period']['standard']:
g_value_url = f'{self._base_url_construction}{standard["g_value_location"]}'
punc = '()<?:'
with urllib.request.urlopen(g_value_url) as json_file:
text = json.load(json_file)['tables']['SHGC']['table'][0]['formula']
values = ''.join([o for o in list(text) if o not in punc]).split()
for index in range(int((len(values) - 1)/3)):
self._g_value_per_hdd.append([values[3*index+1], values[3*index+2]])
self._g_value_per_hdd.append(['15000', values[len(values)-1]])
# store the full catalog data model in self._content
self._content = Content(self._catalog_archetypes,
self._catalog_constructions,
self._catalog_materials,
self._catalog_windows)
construction_url = f'{self._base_url_construction}{standard["constructions_location"]}'
with urllib.request.urlopen(construction_url) as json_file:
cases = json.load(json_file)['tables']['surface_thermal_transmittance']['table']
# W/m2K
for case in cases:
surface = \
ConstructionHelper().nrcan_surfaces_types_to_hub_types[f"{case['surface']}_{case['boundary_condition']}"]
thermal_transmittance_per_hdd = []
text = case['formula']
values = ''.join([o for o in list(text) if o not in punc]).split()
for index in range(int((len(values) - 1)/3)):
thermal_transmittance_per_hdd.append([values[3*index+1], values[3*index+2]])
thermal_transmittance_per_hdd.append(['15000', values[len(values)-1]])
self._thermal_transmittance_per_hdd_and_surface[surface] = thermal_transmittance_per_hdd
def _load_windows(self):
_catalog_windows = []
windows = self._constructions['transparent_surfaces']
for window in windows:
name = list(window.keys())[0]
window_id = name
g_value = window[name]['shgc']
window_type = window[name]['type']
frame_ratio = window[name]['frame_ratio']
overall_u_value = window[name]['u_value']
_catalog_windows.append(Window(window_id, frame_ratio, g_value, overall_u_value, name, window_type))
return _catalog_windows
def _load_constructions(self, window_ratio_standard, construction_standard):
constructions = []
# todo: we need to save the total transmittance somehow, we don't do it yet in our archetypes
# todo: it has to be selected the specific thermal_transmittance from
# self._thermal_transmittance_per_hdd_and_surface and window_ratios from self._window_ratios for each standard case
for i, surface_type in enumerate(self._thermal_transmittance_per_hdd_and_surface):
constructions.append(Construction(i, surface_type, None, None, self._window_ratios))
return constructions
def _load_materials(self):
_catalog_materials = []
materials = self._constructions['materials']
for material in materials:
name = list(material.keys())[0]
material_id = name
no_mass = material[name]['no_mass']
thermal_resistance = None
conductivity = None
density = None
specific_heat = None
solar_absorptance = None
thermal_absorptance = None
visible_absorptance = None
if no_mass:
thermal_resistance = material[name]['thermal_resistance']
else:
solar_absorptance = material[name]['solar_absorptance']
thermal_absorptance = str(1 - float(material[name]['thermal_emittance']))
visible_absorptance = material[name]['visible_absorptance']
conductivity = material[name]['conductivity']
density = material[name]['density']
specific_heat = material[name]['specific_heat']
_material = Material(material_id,
name,
solar_absorptance,
thermal_absorptance,
visible_absorptance,
no_mass,
thermal_resistance,
conductivity,
density,
specific_heat)
_catalog_materials.append(_material)
return _catalog_materials
def _load_constructions(self):
_catalog_constructions = []
constructions = self._constructions['opaque_surfaces']
for construction in constructions:
name = list(construction.keys())[0]
construction_id = name
construction_type = ConstructionHelper().nrcan_surfaces_types_to_hub_types[construction[name]['type']]
layers = []
for layer in construction[name]['layers']:
layer_id = layer
layer_name = layer
material_id = layer
thickness = construction[name]['layers'][layer]
for material in self._catalog_materials:
if str(material_id) == str(material.id):
layers.append(Layer(layer_id, layer_name, material, thickness))
break
_catalog_constructions.append(Construction(construction_id, construction_type, name, layers))
return _catalog_constructions
def _load_archetypes(self):
archetypes = []
archetype_id = 0
for window_ratio_standard in self._metadata['nrcan']['standards_per_function']['standard']:
for construction_standard in self._metadata['nrcan']['standards_per_period']['standard']:
archetype_id += 1
function = window_ratio_standard['@function']
climate_zone = 'Montreal'
construction_period = construction_standard['@period_of_construction']
constructions = self._load_constructions(window_ratio_standard, construction_standard)
archetypes.append(Archetype(archetype_id,
None,
function,
climate_zone,
construction_period,
constructions,
None,
None,
None,
None,
None,
None))
return archetypes
_catalog_archetypes = []
archetypes = self._archetypes['archetypes']
for archetype in archetypes:
archetype_id = f'{archetype["function"]}_{archetype["period_of_construction"]}_{archetype["climate_zone"]}'
function = archetype['function']
name = archetype_id
climate_zone = archetype['climate_zone']
construction_period = archetype['period_of_construction']
average_storey_height = archetype['average_storey_height']
thermal_capacity = str(float(archetype['thermal_capacity']) * 1000)
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges']
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off']
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on']
archetype_constructions = []
for archetype_construction in archetype['constructions']:
archetype_construction_type = ConstructionHelper().nrcan_surfaces_types_to_hub_types[archetype_construction]
archetype_construction_name = archetype['constructions'][archetype_construction]['opaque_surface_name']
for construction in self._catalog_constructions:
if archetype_construction_type == construction.type and construction.name == archetype_construction_name:
_construction = None
_window = None
_window_ratio = None
if 'transparent_surface_name' in archetype['constructions'][archetype_construction].keys():
_window_ratio = archetype['constructions'][archetype_construction]['transparent_ratio']
_window_id = archetype['constructions'][archetype_construction]['transparent_surface_name']
for window in self._catalog_windows:
if _window_id == window.id:
_window = window
break
_construction = Construction(construction.id,
construction.type,
construction.name,
construction.layers,
_window_ratio,
_window)
archetype_constructions.append(_construction)
break
_catalog_archetypes.append(Archetype(archetype_id,
name,
function,
climate_zone,
construction_period,
archetype_constructions,
average_storey_height,
thermal_capacity,
extra_loses_due_to_thermal_bridges,
None,
infiltration_rate_for_ventilation_system_off,
infiltration_rate_for_ventilation_system_on))
return _catalog_archetypes
def names(self, category=None):
"""
Get the catalog elements names
:parm: for usage catalog category filter does nothing as there is only one category (usages)
:parm: optional category filter
"""
_names = {'usages': []}
for usage in self._content.usages:
_names['usages'].append(usage.name)
if category is None:
_names = {'archetypes': [], 'constructions': [], 'materials': [], 'windows': []}
for archetype in self._content.archetypes:
_names['archetypes'].append(archetype.name)
for construction in self._content.constructions:
_names['constructions'].append(construction.name)
for material in self._content.materials:
_names['materials'].append(material.name)
for window in self._content.windows:
_names['windows'].append(window.name)
else:
_names = {category: []}
if category.lower() == 'archetypes':
for archetype in self._content.archetypes:
_names[category].append(archetype.name)
elif category.lower() == 'constructions':
for construction in self._content.constructions:
_names[category].append(construction.name)
elif category.lower() == 'materials':
for material in self._content.materials:
_names[category].append(material.name)
elif category.lower() == 'windows':
for window in self._content.windows:
_names[category].append(window.name)
else:
raise ValueError(f'Unknown category [{category}]')
return _names
def entries(self, category=None):
"""
Get the catalog elements
:parm: for usage catalog category filter does nothing as there is only one category (usages)
:parm: optional category filter
"""
return self._content
if category is None:
return self._content
else:
if category.lower() == 'archetypes':
return self._content.archetypes
elif category.lower() == 'constructions':
return self._content.constructions
elif category.lower() == 'materials':
return self._content.materials
elif category.lower() == 'windows':
return self._content.windows
else:
raise ValueError(f'Unknown category [{category}]')
def get_entry(self, name):
"""
Get one catalog element by names
:parm: entry name
"""
for usage in self._content.usages:
if usage.name.lower() == name.lower():
return usage
for entry in self._content.archetypes:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.constructions:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.materials:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.windows:
if entry.name.lower() == name.lower():
return entry
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -38,7 +38,7 @@ class Archetype:
def id(self):
"""
Get archetype id
:return: int
:return: str
"""
return self._id
@ -85,7 +85,7 @@ class Archetype:
@property
def average_storey_height(self):
"""
Get archetype average storey height
Get archetype average storey height in m
:return: float
"""
return self._average_storey_height
@ -93,23 +93,23 @@ class Archetype:
@property
def thermal_capacity(self):
"""
Get archetype thermal capacity
:return: int
Get archetype thermal capacity in J/m3K
:return: float
"""
return self._thermal_capacity
@property
def extra_loses_due_to_thermal_bridges(self):
"""
Get archetype extra loses due to thermal bridges
:return: int
Get archetype extra loses due to thermal bridges in W/m2K
:return: float
"""
return self._extra_loses_due_to_thermal_bridges
@property
def indirect_heated_ratio(self):
"""
Get archetype indirect heat ratio
Get archetype indirect heated area ratio
:return: float
"""
return self._indirect_heated_ratio
@ -117,7 +117,7 @@ class Archetype:
@property
def infiltration_rate_for_ventilation_system_off(self):
"""
Get archetype infiltration rate for ventilation system off
Get archetype infiltration rate for ventilation system off in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_off
@ -125,7 +125,7 @@ class Archetype:
@property
def infiltration_rate_for_ventilation_system_on(self):
"""
Get archetype infiltration rate for ventilation system on
Get archetype infiltration rate for ventilation system on in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_on

View File

@ -21,7 +21,7 @@ class Construction:
def id(self):
"""
Get construction id
:return: int
:return: str
"""
return self._id
@ -53,7 +53,7 @@ class Construction:
def window_ratio(self):
"""
Get construction window ratio
:return: float
:return: dict
"""
return self._window_ratio

View File

@ -17,7 +17,7 @@ class Layer:
def id(self):
"""
Get layer id
:return: int
:return: str
"""
return self._id

View File

@ -32,7 +32,7 @@ class Material:
def id(self):
"""
Get material id
:return: int
:return: str
"""
return self._id

View File

@ -7,12 +7,13 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class Window:
def __init__(self, window_id, frame_ratio, g_value, overall_u_value, name):
def __init__(self, window_id, frame_ratio, g_value, overall_u_value, name, window_type=None):
self._id = window_id
self._frame_ratio = frame_ratio
self._g_value = g_value
self._overall_u_value = overall_u_value
self._name = name
self._type = window_type
@property
def id(self):
@ -53,3 +54,11 @@ class Window:
:return: float
"""
return self._overall_u_value
@property
def type(self):
"""
Get transparent surface type, 'window' or 'skylight'
:return: str
"""
return self.type

View File

@ -17,9 +17,6 @@ class Plane:
"""
def __init__(self, origin, normal):
# todo: other options to define the plane:
# by two lines
# by three points
self._origin = origin
self._normal = normal
self._equation = None

View File

@ -28,7 +28,7 @@ class Material:
def id(self):
"""
Get material id
:return: int
:return: str
"""
return self._id
@ -36,9 +36,9 @@ class Material:
def id(self, value):
"""
Set material id
:param value: int
:param value: str
"""
self._id = int(value)
self._id = value
@property
def name(self):

View File

@ -287,7 +287,6 @@ class Surface:
"""
Raises not implemented error
"""
# todo: check https://trimsh.org/trimesh.collision.html as an option to implement this method
raise NotImplementedError
def divide(self, z):

View File

@ -120,7 +120,7 @@ class ThermalZone:
@property
def effective_thermal_capacity(self) -> Union[None, float]:
"""
Get thermal zone effective thermal capacity in J/m2K
Get thermal zone effective thermal capacity in J/m3K
:return: None or float
"""
return self._effective_thermal_capacity
@ -128,7 +128,7 @@ class ThermalZone:
@effective_thermal_capacity.setter
def effective_thermal_capacity(self, value):
"""
Set thermal zone effective thermal capacity in J/m2K
Set thermal zone effective thermal capacity in J/m3K
:param value: float
"""
if value is not None:

View File

@ -482,3 +482,5 @@ class City:
:return: LevelOfDetail
"""
return self._level_of_detail

View File

@ -5,11 +5,13 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from __future__ import annotations
from typing import List, Union
from hub.city_model_structure.iot.sensor import Sensor
from hub.city_model_structure.building_demand.surface import Surface
from hub.city_model_structure.attributes.polyhedron import Polyhedron
from hub.helpers.configuration_helper import ConfigurationHelper
@ -33,6 +35,7 @@ class CityObject:
self._diffuse = dict()
self._beam = dict()
self._sensors = []
self._neighbours = None
@property
def name(self):
@ -224,3 +227,17 @@ class CityObject:
:param value: [Sensor]
"""
self._sensors = value
@property
def neighbours(self) -> Union[None, List[CityObject]]:
"""
Get the list of neighbour_objects and their properties associated to the current city_object
"""
return self._neighbours
@neighbours.setter
def neighbours(self, value):
"""
Set the list of neighbour_objects and their properties associated to the current city_object
"""
self._neighbours = value

View File

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<nrcan base_url_archetypes="https://raw.githubusercontent.com/canmet-energy/necb-2011-baselines/master/output/"
base_url_construction="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/">
<standards_per_period>
<standard period_of_construction="1000_1979">
<constructions_location>BTAPPRE1980/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAPPRE1980/data/window_characteristics.json</g_value_location>
</standard>
<standard period_of_construction="1980_2010">
<constructions_location>BTAP1980TO2010/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
</standard>
<standard period_of_construction="2011_2016">
<constructions_location>NECB2011/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
</standard>
<standard period_of_construction="2017_2019">
<constructions_location>NECB2017/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
</standard>
<standard period_of_construction="2020_3000">
<constructions_location>NECB2020/data/surface_thermal_transmittance.json</constructions_location>
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
</standard>
</standards_per_period>
<standards_per_function>
<standard function="FullServiceRestaurant">
<file_location>FullServiceRestaurant/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/8414706d-3ba9-4d70-ad3c-4db62d865e1b-os-report.html</file_location>
</standard>
<standard function="HighriseApartment">
<file_location>HighriseApartment/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/83ab3764-046e-48a8-85cd-a3c0ac761efa-os-report.html</file_location>
</standard>
<standard function="Hospital">
<file_location>Hospital/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/210dac7e-2d51-40a9-bc78-ad0bc1c57a89-os-report.html</file_location>
</standard>
<standard function="LargeHotel">
<file_location>LargeHotel/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/d0185276-7fe0-4da9-bb5d-8c8a7c13c405-os-report.html</file_location>
</standard>
<standard function="LargeOffice">
<file_location>LargeOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/2da33707-50a7-4554-91ed-c5fdbc1ce3b9-os-report.html</file_location>
</standard>
<standard function="MediumOffice">
<file_location>MediumOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/65d97bf8-8749-410b-b53d-5a9c60e0227c-os-report.html</file_location>
</standard>
<standard function="MidriseApartment">
<file_location>MidriseApartment/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/19518153-9c28-4e40-8bbd-98ef949c1bdb-os-report.html</file_location>
</standard>
<standard function="Outpatient">
<file_location>Outpatient/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/deab93c7-d086-432d-bb90-33c8c4e1fab3-os-report.html</file_location>
</standard>
<standard function="PrimarySchool">
<file_location>PrimarySchool/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/87f45397-5ef4-4df9-be41-d33c4b6d2fb7-os-report.html</file_location>
</standard>
<standard function="QuickServiceRestaurant">
<file_location>QuickServiceRestaurant/CAN_PQ_Montreal.Intl.AP.716270_CWEC/ 0bc55858-a81b-4d07-9923-1d84e8a23194-os-report.html</file_location>
</standard>
<standard function="RetailStandalone">
<file_location>RetailStandalone/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/a3643bcb-0eea-47d4-b6b9-253ed188ec0c-os-report.html</file_location>
</standard>
<standard function="RetailStripmall">
<file_location>RetailStripmall/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/ebaf5a16-00af-49de-9672-6b373fc825be-os-report.html</file_location>
</standard>
<standard function="SecondarySchool">
<file_location>SecondarySchool/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/3a4f105f-93ed-4b8b-9eb3-c8ca40c5de6e-os-report.html</file_location>
</standard>
<standard function="SmallHotel">
<file_location>SmallHotel/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/dff0a3fc-d9e5-4866-9e6a-dee9a0da60b2-os-report.html</file_location>
</standard>
<standard function="SmallOffice">
<file_location>SmallOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/a9a3669d-beb8-4951-aa11-c27dbc61a344-os-report.html</file_location>
</standard>
<standard function="Warehouse">
<file_location>Warehouse/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/569ec649-8017-4a3c-bd0a-337eba3ec488-os-report.html</file_location>
</standard>
</standards_per_function>
</nrcan>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,14 @@ from hub.imports.weather.helpers.weather import Weather
import hub.helpers.constants as cte
_CONSTRUCTION_CODE = {
cte.WALL: '1',
cte.GROUND: '2',
cte.ROOF: '3',
cte.INTERIOR_WALL: '5',
cte.GROUND_WALL: '6',
cte.ATTIC_FLOOR: '7',
cte.INTERIOR_SLAB: '8'
}
cte.WALL: '1',
cte.GROUND: '2',
cte.ROOF: '3',
cte.INTERIOR_WALL: '5',
cte.GROUND_WALL: '6',
cte.ATTIC_FLOOR: '7',
cte.INTERIOR_SLAB: '8'
}
class InselMonthlyEnergyBalance(Insel):
@ -35,8 +35,10 @@ class InselMonthlyEnergyBalance(Insel):
self._insel_files_paths.append(building.name + '.insel')
file_name_out = building.name + '.out'
output_path = Path(self._path / file_name_out).resolve()
self._contents.append(self.generate_meb_template(building, output_path, self._radiation_calculation_method,
self._weather_format))
if building.internal_zones is not None:
self._contents.append(
self.generate_meb_template(building, output_path, self._radiation_calculation_method,self._weather_format)
)
self._export()
def _export(self):
@ -71,9 +73,10 @@ class InselMonthlyEnergyBalance(Insel):
internal_zone = building.internal_zones[0]
thermal_zone = internal_zone.thermal_zones[0]
parameters.append(f'{thermal_zone.indirectly_heated_area_ratio} % BP(6) Indirectly heated area ratio')
parameters.append(f'{thermal_zone.effective_thermal_capacity / 3600} % BP(7) Effective heat capacity (Wh/m2K)')
parameters.append(f'{thermal_zone.effective_thermal_capacity / 3600 / building.average_storey_height}'
f' % BP(7) Effective heat capacity (Wh/m2K)')
parameters.append(f'{thermal_zone.additional_thermal_bridge_u_value} '
f'% BP(8) Additional U-value for heat bridge (Wh/m2K)')
f'% BP(8) Additional U-value for heat bridge (W/m2K)')
parameters.append('1 % BP(9) Usage type (0=standard, 1=IWU)')
# ZONES AND SURFACES
@ -85,7 +88,7 @@ class InselMonthlyEnergyBalance(Insel):
total_internal_gain = 0
for ig in usage.internal_gains:
total_internal_gain += float(ig.average_internal_gain) * \
(float(ig.convective_fraction) + float(ig.radiative_fraction))
(float(ig.convective_fraction) + float(ig.radiative_fraction))
parameters.append(f'{total_internal_gain} % BP(12) #2 Internal gains of zone {i + 1}')
parameters.append(f'{usage.thermal_control.mean_heating_set_point} % BP(13) #3 Heating setpoint temperature '
f'zone {i + 1} (degree Celsius)')

View File

@ -46,7 +46,10 @@ class DBFactory:
return self._application.get_by_uuid(application_uuid)
def user_info(self, name, password, application_id):
return self._user.get_by_name_application_and_password(name, password, application_id)
return self._user.get_by_name_application_id_and_password(name, password, application_id)
def user_login(self, name, password, application_uuid):
return self._user.get_by_name_application_uuid_and_password(name, password, application_uuid)
def building_info(self, name, city_id):
return self._city_object.get_by_name_and_city(name, city_id)

View File

@ -125,6 +125,7 @@ AUTOMOTIVE_FACILITY = 'automotive facility'
PARKING_GARAGE = 'parking garage'
RELIGIOUS = 'religious'
NON_HEATED = 'non-heated'
DATACENTER = 'datacenter'
LIGHTING = 'Lights'
OCCUPANCY = 'Occupancy'

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,36 @@ from trimesh import intersections
from hub.city_model_structure.attributes.polygon import Polygon
from hub.city_model_structure.attributes.polyhedron import Polyhedron
from hub.helpers.location import Location
from hub.helpers.configuration_helper import ConfigurationHelper
from PIL import Image
class MapPoint:
def __init__(self, x, y):
self._x = int(x)
self._y = int(y)
@property
def x(self):
return self._x
@property
def y(self):
return self._y
def __str__(self):
return f'({self.x}, {self.y})'
def __len__(self):
return 1
def __getitem__(self, index):
if index == 0:
return self._x
elif index == 1:
return self._y
else:
raise IndexError('Index error')
class GeometryHelper:
@ -29,15 +58,51 @@ class GeometryHelper:
self._area_delta = area_delta
@staticmethod
def adjacent_locations(location1, location2):
"""
Determine when two attributes may be adjacent or not based in the dis
:param location1:
:param location2:
:return: Boolean
"""
max_distance = ConfigurationHelper().max_location_distance_for_shared_walls
return GeometryHelper.distance_between_points(location1, location2) < max_distance
def coordinate_to_map_point(coordinate, city):
return MapPoint(((city.upper_corner[0] - coordinate[0]) * 0.5), ((city.upper_corner[1] - coordinate[1]) * 0.5))
@staticmethod
def city_mapping(city, building_names=None, plot=False):
if building_names is None:
building_names = [b.name for b in city.buildings]
x = int((city.upper_corner[0] - city.lower_corner[0]) * 0.5) + 1
y = int((city.upper_corner[1] - city.lower_corner[1]) * 0.5) + 1
city_map = [['' for _ in range(y + 1)] for _ in range(x + 1)]
img = Image.new('RGB', (x + 1, y + 1), "black") # create a new black image
city_image = img.load() # create the pixel map
for building_name in building_names:
building = city.city_object(building_name)
for ground in building.grounds:
length = len(ground.perimeter_polygon.coordinates) - 1
for i, coordinate in enumerate(ground.perimeter_polygon.coordinates):
j = i + 1
if i == length:
j = 0
next_coordinate = ground.perimeter_polygon.coordinates[j]
point = GeometryHelper.coordinate_to_map_point(coordinate, city)
distance = GeometryHelper.distance_between_points(coordinate, next_coordinate)
if distance == 0:
continue
delta_x = (coordinate[0] - next_coordinate[0]) / (distance / 0.5)
delta_y = (coordinate[1] - next_coordinate[1]) / (distance / 0.5)
for k in range(0, int(distance)):
x = MapPoint(point.x + (delta_x * k), point.y + (delta_y * k)).x
y = MapPoint(point.x + (delta_x * k), point.y + (delta_y * k)).y
if city_map[x][y] == '':
city_map[x][y] = building.name
city_image[x, y] = (100, 0, 0)
elif city_map[x][y] != building.name:
neighbour = city.city_object(city_map[x][y])
if building.neighbours is None:
building.neighbours = [neighbour]
elif neighbour not in building.neighbours:
building.neighbours.append(neighbour)
if neighbour.neighbours is None:
neighbour.neighbours = [building]
elif building not in neighbour.neighbours:
neighbour.neighbours.append(building)
if plot:
img.show()
@staticmethod
def segment_list_to_trimesh(lines) -> Trimesh:
@ -148,6 +213,6 @@ class GeometryHelper:
"""
power = 0
for dimension in range(0, len(vertex1)):
power += math.pow(vertex2[dimension]-vertex1[dimension], 2)
power += math.pow(vertex2[dimension] - vertex1[dimension], 2)
distance = math.sqrt(power)
return distance

View File

@ -47,6 +47,10 @@ class ConstructionHelper:
cte.ROOF: 'roof'
}
_reference_city_to_nrcan_climate_zone = {
'Montreal': '6'
}
@staticmethod
def yoc_to_nrel_standard(year_of_construction):
"""
@ -68,9 +72,9 @@ class ConstructionHelper:
:return: str
"""
# todo: Dummy function that needs to be implemented
reference_city = 'Baltimore'
reference_city = 'Montreal'
if city is not None:
reference_city = 'Baltimore'
reference_city = 'Montreal'
return reference_city
@staticmethod
@ -80,5 +84,15 @@ class ConstructionHelper:
:param city: str
:return: str
"""
reference_city = ConstructionHelper.city_to_reference_city(city)
reference_city = 'Baltimore'
return ConstructionHelper._reference_city_to_nrel_climate_zone[reference_city]
@staticmethod
def city_to_nrcan_climate_zone(city):
"""
City name to NRCAN climate zone
:param city: str
:return: str
"""
reference_city = ConstructionHelper.city_to_reference_city(city)
return ConstructionHelper._reference_city_to_nrcan_climate_zone[reference_city]

View File

@ -4,8 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import math
import sys
import hub.helpers.constants as cte
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material
@ -22,25 +24,23 @@ class NrcanPhysicsParameters:
self._city = city
self._path = base_path
self._divide_in_storeys = divide_in_storeys
self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name)
self._climate_zone = ConstructionHelper.city_to_nrcan_climate_zone(city.name)
def enrich_buildings(self):
"""
Returns the city with the construction parameters assigned to the buildings
"""
city = self._city
canel_catalog = ConstructionCatalogFactory('nrcan').catalog
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
for building in city.buildings:
try:
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
archetype = self._search_archetype(canel_catalog, function, building.year_of_construction,
self._climate_zone)
archetype = self._search_archetype(nrcan_catalog, function, building.year_of_construction, self._climate_zone)
except KeyError:
sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: '
f'{building.function} and building year of construction: {building.year_of_construction} '
f'and climate zone reference norm {self._climate_zone}\n')
f'{building.function}, building year of construction: {building.year_of_construction} '
f'and climate zone {self._climate_zone}\n')
return
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:
@ -65,12 +65,10 @@ class NrcanPhysicsParameters:
self._calculate_view_factors(thermal_zone)
@staticmethod
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
nrel_archetypes = nrel_catalog.entries('archetypes')
for building_archetype in nrel_archetypes:
construction_period_limits = building_archetype.construction_period.split(' - ')
if construction_period_limits[1] == 'PRESENT':
construction_period_limits[1] = 3000
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
nrcan_archetypes = nrcan_catalog.entries('archetypes')
for building_archetype in nrcan_archetypes:
construction_period_limits = building_archetype.construction_period.split('_')
if int(construction_period_limits[0]) <= int(year_of_construction) < int(construction_period_limits[1]):
if (str(function) == str(building_archetype.function)) and \
(climate_zone == str(building_archetype.climate_zone)):
@ -89,14 +87,28 @@ class NrcanPhysicsParameters:
for thermal_zone in thermal_zones:
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
thermal_zone.indirectly_heated_area_ratio = archetype.indirect_heated_ratio
thermal_zone.indirectly_heated_area_ratio = 0
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
for thermal_boundary in thermal_zone.thermal_boundaries:
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
thermal_boundary.construction_name = construction_archetype.name
try:
thermal_boundary.window_ratio = construction_archetype.window_ratio
thermal_boundary.window_ratio = 0
if thermal_boundary.type == cte.WALL or thermal_boundary.type == cte.ROOF:
if construction_archetype.window is not None:
if math.pi / 4 <= thermal_boundary.parent_surface.azimuth < 3 * math.pi / 4:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['east']) / 100
elif 3 * math.pi / 4 <= thermal_boundary.parent_surface.azimuth < 5 * math.pi / 4:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['south']) / 100
elif 5 * math.pi / 4 <= thermal_boundary.parent_surface.azimuth < 7 * math.pi / 4:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['west']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['north']) / 100
except ValueError:
# This is the normal operation way when the windows are defined in the geometry
continue

View File

@ -19,11 +19,12 @@ class CityGml:
"""
CityGml class
"""
def __init__(self,
path,
extrusion_height_field=None,
year_of_construction_field='yearOfConstruction',
function_field='function',
year_of_construction_field=None,
function_field=None,
function_to_hub=None):
self._city = None
self._lod = None
@ -31,9 +32,11 @@ class CityGml:
self._lod2_tags = ['lod2Solid', 'lod2MultiSurface', 'lod2MultiCurve']
self._extrusion_height_field = extrusion_height_field
self._function_to_hub = function_to_hub
self._year_of_construction_field = year_of_construction_field
if function_field is None:
function_field = 'function'
if year_of_construction_field is None:
year_of_construction_field = 'yearOfConstruction'
self._year_of_construction_field = year_of_construction_field
self._function_field = function_field
self._lower_corner = None

View File

@ -64,7 +64,7 @@ class Geojson:
for zone, surface_coordinates in enumerate(surfaces_coordinates):
points = GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(surface_coordinates))
polygon = Polygon(points)
surfaces.append(Surface(polygon, polygon))
surfaces.append(Surface(polygon, polygon, surface_type=cte.GROUND))
buildings.append(Building(f'{name}_zone_{zone}', surfaces, year_of_construction, function))
return buildings
@ -112,6 +112,7 @@ class Geojson:
Get city out of a Geojson file
"""
if self._city is None:
missing_functions = []
buildings = []
building_id = 0
for feature in self._geojson['features']:
@ -126,7 +127,12 @@ class Geojson:
function = feature['properties'][self._function_field]
if self._function_to_hub is not None:
# use the transformation dictionary to retrieve the proper function
function = self._function_to_hub[function]
if function in self._function_to_hub:
function = self._function_to_hub[function]
else:
if function not in missing_functions:
missing_functions.append(function)
function = function
geometry = feature['geometry']
if 'id' in feature:
building_name = feature['id']
@ -157,4 +163,6 @@ class Geojson:
for building in buildings:
self._city.add_city_object(building)
self._city.level_of_detail.geometry = lod
if len(missing_functions) > 0:
print(f'There are unknown functions {missing_functions}')
return self._city

View File

@ -35,8 +35,8 @@ class InselMonthlyEnergyBalance:
demand[i] = '0'
heating.append(demand[0])
cooling.append(demand[1])
monthly_heating = pd.DataFrame(heating, columns=[cte.INSEL_MEB])
monthly_cooling = pd.DataFrame(cooling, columns=[cte.INSEL_MEB])
monthly_heating = pd.DataFrame(heating, columns=[cte.INSEL_MEB]).astype(float)
monthly_cooling = pd.DataFrame(cooling, columns=[cte.INSEL_MEB]).astype(float)
return monthly_heating, monthly_cooling
def enrich(self):
@ -46,8 +46,8 @@ class InselMonthlyEnergyBalance:
if insel_output_file_path.is_file():
building.heating[cte.MONTH], building.cooling[cte.MONTH] = self._demand(insel_output_file_path)
building.heating[cte.YEAR] = pd.DataFrame(
[building.heating[cte.MONTH][cte.INSEL_MEB].sum()], columns=[cte.INSEL_MEB]
[building.heating[cte.MONTH][cte.INSEL_MEB].astype(float).sum()], columns=[cte.INSEL_MEB]
)
building.cooling[cte.YEAR] = pd.DataFrame(
[building.cooling[cte.MONTH][cte.INSEL_MEB].sum()], columns=[cte.INSEL_MEB]
[building.cooling[cte.MONTH][cte.INSEL_MEB].astype(float).sum()], columns=[cte.INSEL_MEB]
)

View File

@ -4,7 +4,8 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project CoderPeter Yefi peteryefi@gmail.com
"""
from hub.persistence import User as UserRepository
from hub.persistence import User
from hub.persistence import UserRoles
@ -14,7 +15,7 @@ class UserFactory:
"""
def __init__(self, db_name, app_env, dotenv_path):
self._user_repo = UserRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
self._user_repo = User(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
def create_user(self, name: str, application_id: int, password: str, role: UserRoles):
"""

View File

@ -19,10 +19,10 @@ class Configuration:
def __init__(self, db_name: str, dotenv_path: str, app_env='TEST'):
"""
:param db_name: database name
:param app_env: application environment, test or production
:param dotenv_path: the absolute path to dotenv file
"""
:param db_name: database name
:param app_env: application environment, test or production
:param dotenv_path: the absolute path to dotenv file
"""
try:
# load environmental variables
load_dotenv(dotenv_path=dotenv_path)

View File

@ -59,7 +59,9 @@ class City(Repository):
for building in city.buildings:
object_usage = ''
for internal_zone in building.internal_zones:
if internal_zone.usages is not None:
if internal_zone is None or internal_zone.usages is None:
object_usage = 'Unknown'
else:
for usage in internal_zone.usages:
object_usage = f'{object_usage}{usage.name}_{usage.percentage} '
object_usage = object_usage.rstrip()

View File

@ -9,6 +9,7 @@ from hub.persistence import Repository
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import select
from hub.persistence.models import User as Model
from hub.persistence.models import Application as ApplicationModel
from hub.persistence.models import UserRoles
from hub.helpers.auth import Auth
from typing import Union, Dict
@ -99,14 +100,14 @@ class User(Repository):
except SQLAlchemyError as err:
logger.error(f'Error while fetching user by name and application: {err}')
def get_by_name_application_and_password(self, name: str, password: str, application_id: int) -> [Model]:
def get_by_name_application_id_and_password(self, name: str, password: str, application_id: int) -> [Model]:
"""
Fetch user based on the email and password
:param name: User name
:param password: User password
:param application_id: User password
:return: [User] with the provided email and password
:return: [User]
"""
try:
user = self.session.execute(
@ -115,6 +116,22 @@ class User(Repository):
if user:
if Auth.check_password(password, user[0].password):
return user[0]
return {'message': 'invalid login information'}
except SQLAlchemyError as err:
logger.error(f'Error while fetching user by email: {err}')
def get_by_name_application_uuid_and_password(self, name: str, password: str, application_uuid: str) -> [Model]:
"""
Fetch user based on the email and password
:param name: User name
:param password: User password
:param application_uuid: Application uuid
:return: [User]
"""
try:
application = self.session.execute(
select(ApplicationModel).where(ApplicationModel.application_uuid == application_uuid)
).first()
return self.get_by_name_application_id_and_password(name, password, application[0].id)
except SQLAlchemyError as err:
logger.error(f'Error while fetching user by name: {err}')

View File

@ -3,6 +3,7 @@ TestConstructionCatalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Contributors Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from unittest import TestCase
@ -17,9 +18,29 @@ class TestConstructionCatalog(TestCase):
constructions = catalog.names('constructions')
windows = catalog.names('windows')
materials = catalog.names('materials')
self.assertTrue(len(constructions['constructions']), 24)
self.assertTrue(len(windows['windows']), 4)
self.assertTrue(len(materials['materials']), 19)
self.assertEqual(24, len(constructions['constructions']))
self.assertEqual(4, len(windows['windows']))
self.assertEqual(19, len(materials['materials']))
with self.assertRaises(ValueError):
catalog.names('unknown')
# retrieving all the entries should not raise any exceptions
for category in catalog_categories:
for value in catalog_categories[category]:
catalog.get_entry(value)
with self.assertRaises(IndexError):
catalog.get_entry('unknown')
def test_nrcan_catalog(self):
catalog = ConstructionCatalogFactory('nrcan').catalog
catalog_categories = catalog.names()
constructions = catalog.names('constructions')
windows = catalog.names('windows')
materials = catalog.names('materials')
self.assertEqual(180, len(constructions['constructions']))
self.assertEqual(36, len(windows['windows']))
self.assertEqual(192, len(materials['materials']))
with self.assertRaises(ValueError):
catalog.names('unknown')

View File

@ -113,8 +113,6 @@ class TestConstructionFactory(TestCase):
self.assertTrue(len(thermal_zone.thermal_boundaries) > 0, 'thermal_zone thermal_boundaries not defined')
self.assertIsNotNone(thermal_zone.additional_thermal_bridge_u_value, 'additional_thermal_bridge_u_value is none')
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, 'thermal_zone effective_thermal_capacity is none')
self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio,
'thermal_zone indirectly_heated_area_ratio is none')
self.assertIsNotNone(thermal_zone.infiltration_rate_system_off,
'thermal_zone infiltration_rate_system_off is none')
self.assertIsNotNone(thermal_zone.infiltration_rate_system_on, 'thermal_zone infiltration_rate_system_on is none')
@ -153,7 +151,7 @@ class TestConstructionFactory(TestCase):
def _check_thermal_openings(self, thermal_boundary):
for thermal_opening in thermal_boundary.thermal_openings:
self.assertIsNotNone(thermal_opening.id, 'thermal opening id is not none')
self.assertIsNotNone(thermal_opening.construction_name, 'thermal opening construction is not none')
self.assertIsNotNone(thermal_opening.construction_name, 'thermal opening construction is none')
self.assertIsNotNone(thermal_opening.area, 'thermal opening area is not none')
self.assertIsNotNone(thermal_opening.frame_ratio, 'thermal opening frame_ratio is none')
self.assertIsNotNone(thermal_opening.g_value, 'thermal opening g_value is none')
@ -176,10 +174,64 @@ class TestConstructionFactory(TestCase):
"""
Enrich the city with the construction information and verify it
"""
file = 'one_building_in_kelowna.gml'
city = self._get_citygml(file)
for building in city.buildings:
building.year_of_construction = 1980
building.function = self._internal_function('hft', building.function)
ConstructionFactory('nrcan', city).enrich()
self._check_buildings(city)
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
file = 'pluto_building.gml'
city = self._get_citygml(file)
for building in city.buildings:
building.year_of_construction = 2005
building.year_of_construction = 1980
building.function = self._internal_function('pluto', building.function)
ConstructionFactory('nrcan', city).enrich()
self._check_buildings(city)
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
file = 'one_building_in_kelowna.gml'
city = self._get_citygml(file)
for building in city.buildings:
building.year_of_construction = 2006
building.function = self._internal_function('hft', building.function)
ConstructionFactory('nrel', city).enrich()
self._check_buildings(city)
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
file = 'pluto_building.gml'
city = self._get_citygml(file)
for building in city.buildings:
building.year_of_construction = 2006
building.function = self._internal_function('pluto', building.function)
ConstructionFactory('nrel', city).enrich()
@ -194,6 +246,45 @@ class TestConstructionFactory(TestCase):
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
file = 'one_building_in_kelowna.gml'
city = self._get_citygml(file)
for building in city.buildings:
building.year_of_construction = 1980
building.function = self._internal_function('hft', building.function)
ConstructionFactory('nrcan', city).enrich()
self._check_buildings(city)
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
file_path = (self._example_path / 'concordia.geojson').resolve()
self._city = GeometryFactory('geojson',
path=file_path,
height_field='citygml_me',
year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
ConstructionFactory('nrcan', city).enrich()
self._check_buildings(city)
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
def test_archetype_not_found(self):
file = 'pluto_building.gml'
city = self._get_citygml(file)

View File

@ -4,8 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import datetime
from pathlib import Path
from unittest import TestCase
from hub.helpers.geometry_helper import GeometryHelper
from numpy import inf
@ -101,12 +103,11 @@ class TestGeometryFactory(TestCase):
:return: None
"""
file = 'FZK_Haus_LoD_2.gml'
city = self._get_city(file, 'citygml', year_of_construction_field='yearOfConstruction')
city = self._get_city(file, 'citygml')
self.assertTrue(len(city.buildings) == 1)
self._check_buildings(city)
for building in city.buildings:
self._check_surfaces(building)
building.year_of_construction = 2006
city = ConstructionFactory('nrel', city).enrich()
def test_import_rhino(self):
@ -141,8 +142,20 @@ class TestGeometryFactory(TestCase):
city = self._get_city(file, 'geojson',
height_field='citygml_me',
year_of_construction_field='ANNEE_CONS',
function_field='LIBELLE_UT')
function_field='CODE_UTILI')
hub.exports.exports_factory.ExportsFactory('obj', city, self._output_path).export()
self.assertEqual(207, len(city.buildings), 'wrong number of buildings')
self._check_buildings(city)
def test_map_neighbours(self):
"""
Test neighbours map creation
"""
file = 'concordia.geojson'
city = self._get_city(file, 'geojson',
height_field='citygml_me',
year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI')
GeometryHelper.city_mapping(city, plot=False)
self.assertTrue(False)

View File

@ -1 +1 @@
__version__ = '0.1.7.6'
__version__ = '0.1.7.8'

View File

@ -67,7 +67,6 @@ setup(
'hub.imports',
'hub.imports.construction',
'hub.imports.construction.helpers',
'hub.imports.construction.data_classes',
'hub.imports.energy_systems',
'hub.imports.geometry',
'hub.imports.geometry.citygml_classes',
@ -86,24 +85,24 @@ setup(
('hub', glob.glob('hub/requirements.txt')),
('hub/config', glob.glob('hub/config/*.ini')),
('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')),
('hub/data/construction.', glob.glob('hub/data/construction/*.xml')),
('hub/data/customized_imports/', glob.glob('hub/data/customized_imports/*.xml')),
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.xml')),
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.insel')),
('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.xlsx')),
('hub/data/energy_systems/*', glob.glob('hub/data/energy_systems/*.txt')),
('hub/data/energy_systems/*', glob.glob('hub/data/energy_systems/*.yaml')),
('hub/data/greenery/', glob.glob('hub/data/greenery/*.xml')),
('hub/data/life_cycle_assessment/', glob.glob('hub/data/life_cycle_assessment/*.xml')),
('hub/data/schedules/', glob.glob('hub/data/schedules/*.xml')),
('hub/data/schedules/', glob.glob('hub/data/schedules/*.xlsx')),
('hub/data/schedules/idf_files/', glob.glob('hub/data/schedules/idf_files/*.idf')),
('hub/data/sensors/', glob.glob('hub/data/sensors/*.json')),
('hub/data/usage/', glob.glob('hub/data/usage/*.xml')),
('hub/data/usage/', glob.glob('hub/data/usage/*.xlsx')),
('hub/data/weather/', glob.glob('hub/data/weather/*.dat')),
('hub/data/weather/epw/', glob.glob('hub/data/weather/epw/*.epw')),
('hub/data/weather/', glob.glob('hub/data/weather/*.dat')),
('hub/data/construction.', glob.glob('hub/data/construction/*')),
('hub/data/customized_imports', glob.glob('hub/data/customized_imports/*.xml')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xml')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.insel')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xlsx')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.txt')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.yaml')),
('hub/data/greenery', glob.glob('hub/data/greenery/*.xml')),
('hub/data/life_cycle_assessment', glob.glob('hub/data/life_cycle_assessment/*.xml')),
('hub/data/schedules', glob.glob('hub/data/schedules/*.xml')),
('hub/data/schedules', glob.glob('hub/data/schedules/*.xlsx')),
('hub/data/schedules/idf_files', glob.glob('hub/data/schedules/idf_files/*.idf')),
('hub/data/sensors', glob.glob('hub/data/sensors/*.json')),
('hub/data/usage', glob.glob('hub/data/usage/*.xml')),
('hub/data/usage', glob.glob('hub/data/usage/*.xlsx')),
('hub/data/weather', glob.glob('hub/data/weather/*.dat')),
('hub/data/weather/epw', glob.glob('hub/data/weather/epw/*.epw')),
('hub/data/weather', glob.glob('hub/data/weather/*.dat')),
('hub/exports/building_energy/idf_files', glob.glob('hub/exports/building_energy/idf_files/*.idf')),
('hub/exports/building_energy/idf_files', glob.glob('hub/exports/building_energy/idf_files/*.idd')),
('hub/helpers/data', glob.glob('hub/helpers/data/quebec_to_hub.json'))