Refactor and code quality improvements

This commit is contained in:
Guille Gutierrez 2023-05-30 17:13:49 -04:00
parent 82b72e78c7
commit 891b660824
123 changed files with 826 additions and 766 deletions

View File

View File

View File

@ -15,304 +15,304 @@ getEClassifier = partial(Ecore.getEClassifier, searchspace=eClassifiers)
Management = EEnum('Management', literals=['Intensive', 'Extensive', 'SemiIntensive', 'NA']) Management = EEnum('Management', literals=['Intensive', 'Extensive', 'SemiIntensive', 'NA'])
Roughness = EEnum('Roughness', literals=['VeryRough', 'Rough', Roughness = EEnum('Roughness', literals=['VeryRough', 'Rough',
'MediumRough', 'MediumSmooth', 'Smooth', 'VerySmooth']) 'MediumRough', 'MediumSmooth', 'Smooth', 'VerySmooth'])
class Soil(EObject, metaclass=MetaEClass): class Soil(EObject, metaclass=MetaEClass):
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True) name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
roughness = EAttribute(eType=Roughness, unique=True, derived=False, roughness = EAttribute(eType=Roughness, unique=True, derived=False,
changeable=True, default_value=Roughness.MediumRough) changeable=True, default_value=Roughness.MediumRough)
conductivityOfDrySoil = EAttribute( conductivityOfDrySoil = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='1.0 W/(m*K)') eType=EString, unique=True, derived=False, changeable=True, default_value='1.0 W/(m*K)')
densityOfDrySoil = EAttribute(eType=EString, unique=True, derived=False, densityOfDrySoil = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='1100 kg/m³') changeable=True, default_value='1100 kg/m³')
specificHeatOfDrySoil = EAttribute( specificHeatOfDrySoil = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='1200 J/(kg*K)') eType=EString, unique=True, derived=False, changeable=True, default_value='1200 J/(kg*K)')
thermalAbsorptance = EAttribute(eType=EString, unique=True, thermalAbsorptance = EAttribute(eType=EString, unique=True,
derived=False, changeable=True, default_value='0.9') derived=False, changeable=True, default_value='0.9')
solarAbsorptance = EAttribute(eType=EString, unique=True, solarAbsorptance = EAttribute(eType=EString, unique=True,
derived=False, changeable=True, default_value='0.7') derived=False, changeable=True, default_value='0.7')
visibleAbsorptance = EAttribute(eType=EString, unique=True, visibleAbsorptance = EAttribute(eType=EString, unique=True,
derived=False, changeable=True, default_value='0.75') derived=False, changeable=True, default_value='0.75')
saturationVolumetricMoistureContent = EAttribute( saturationVolumetricMoistureContent = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='0.0') eType=EString, unique=True, derived=False, changeable=True, default_value='0.0')
residualVolumetricMoistureContent = EAttribute( residualVolumetricMoistureContent = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='0.05') eType=EString, unique=True, derived=False, changeable=True, default_value='0.05')
initialVolumetricMoistureContent = EAttribute( initialVolumetricMoistureContent = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='0.1') eType=EString, unique=True, derived=False, changeable=True, default_value='0.1')
def __init__(self, *, name=None, roughness=None, conductivityOfDrySoil=None, densityOfDrySoil=None, specificHeatOfDrySoil=None, thermalAbsorptance=None, solarAbsorptance=None, visibleAbsorptance=None, saturationVolumetricMoistureContent=None, residualVolumetricMoistureContent=None, initialVolumetricMoistureContent=None): def __init__(self, *, name=None, roughness=None, conductivityOfDrySoil=None, densityOfDrySoil=None, specificHeatOfDrySoil=None, thermalAbsorptance=None, solarAbsorptance=None, visibleAbsorptance=None, saturationVolumetricMoistureContent=None, residualVolumetricMoistureContent=None, initialVolumetricMoistureContent=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if name is not None: if name is not None:
self.name = name self.name = name
if roughness is not None: if roughness is not None:
self.roughness = roughness self.roughness = roughness
if conductivityOfDrySoil is not None: if conductivityOfDrySoil is not None:
self.conductivityOfDrySoil = conductivityOfDrySoil self.conductivityOfDrySoil = conductivityOfDrySoil
if densityOfDrySoil is not None: if densityOfDrySoil is not None:
self.densityOfDrySoil = densityOfDrySoil self.densityOfDrySoil = densityOfDrySoil
if specificHeatOfDrySoil is not None: if specificHeatOfDrySoil is not None:
self.specificHeatOfDrySoil = specificHeatOfDrySoil self.specificHeatOfDrySoil = specificHeatOfDrySoil
if thermalAbsorptance is not None: if thermalAbsorptance is not None:
self.thermalAbsorptance = thermalAbsorptance self.thermalAbsorptance = thermalAbsorptance
if solarAbsorptance is not None: if solarAbsorptance is not None:
self.solarAbsorptance = solarAbsorptance self.solarAbsorptance = solarAbsorptance
if visibleAbsorptance is not None: if visibleAbsorptance is not None:
self.visibleAbsorptance = visibleAbsorptance self.visibleAbsorptance = visibleAbsorptance
if saturationVolumetricMoistureContent is not None: if saturationVolumetricMoistureContent is not None:
self.saturationVolumetricMoistureContent = saturationVolumetricMoistureContent self.saturationVolumetricMoistureContent = saturationVolumetricMoistureContent
if residualVolumetricMoistureContent is not None: if residualVolumetricMoistureContent is not None:
self.residualVolumetricMoistureContent = residualVolumetricMoistureContent self.residualVolumetricMoistureContent = residualVolumetricMoistureContent
if initialVolumetricMoistureContent is not None: if initialVolumetricMoistureContent is not None:
self.initialVolumetricMoistureContent = initialVolumetricMoistureContent self.initialVolumetricMoistureContent = initialVolumetricMoistureContent
class Plant(EObject, metaclass=MetaEClass): class Plant(EObject, metaclass=MetaEClass):
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True) name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
height = EAttribute(eType=EString, unique=True, derived=False, height = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='0.1 m') changeable=True, default_value='0.1 m')
leafAreaIndex = EAttribute(eType=EString, unique=True, derived=False, leafAreaIndex = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='2.5') changeable=True, default_value='2.5')
leafReflectivity = EAttribute(eType=EString, unique=True, leafReflectivity = EAttribute(eType=EString, unique=True,
derived=False, changeable=True, default_value='0.1') derived=False, changeable=True, default_value='0.1')
leafEmissivity = EAttribute(eType=EString, unique=True, derived=False, leafEmissivity = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='0.9') changeable=True, default_value='0.9')
minimalStomatalResistance = EAttribute( minimalStomatalResistance = EAttribute(
eType=EString, unique=True, derived=False, changeable=True, default_value='100.0 s/m') eType=EString, unique=True, derived=False, changeable=True, default_value='100.0 s/m')
co2Sequestration = EAttribute(eType=EString, unique=True, derived=False, co2Sequestration = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='kgCO₂eq') changeable=True, default_value='kgCO₂eq')
growsOn = EReference(ordered=True, unique=True, containment=False, derived=False, upper=-1) growsOn = EReference(ordered=True, unique=True, containment=False, derived=False, upper=-1)
def __init__(self, *, name=None, height=None, leafAreaIndex=None, leafReflectivity=None, leafEmissivity=None, minimalStomatalResistance=None, growsOn=None, co2Sequestration=None): def __init__(self, *, name=None, height=None, leafAreaIndex=None, leafReflectivity=None, leafEmissivity=None, minimalStomatalResistance=None, growsOn=None, co2Sequestration=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if name is not None: if name is not None:
self.name = name self.name = name
if height is not None: if height is not None:
self.height = height self.height = height
if leafAreaIndex is not None: if leafAreaIndex is not None:
self.leafAreaIndex = leafAreaIndex self.leafAreaIndex = leafAreaIndex
if leafReflectivity is not None: if leafReflectivity is not None:
self.leafReflectivity = leafReflectivity self.leafReflectivity = leafReflectivity
if leafEmissivity is not None: if leafEmissivity is not None:
self.leafEmissivity = leafEmissivity self.leafEmissivity = leafEmissivity
if minimalStomatalResistance is not None: if minimalStomatalResistance is not None:
self.minimalStomatalResistance = minimalStomatalResistance self.minimalStomatalResistance = minimalStomatalResistance
if co2Sequestration is not None: if co2Sequestration is not None:
self.co2Sequestration = co2Sequestration self.co2Sequestration = co2Sequestration
if growsOn: if growsOn:
self.growsOn.extend(growsOn) self.growsOn.extend(growsOn)
class SupportEnvelope(EObject, metaclass=MetaEClass): class SupportEnvelope(EObject, metaclass=MetaEClass):
roughness = EAttribute(eType=Roughness, unique=True, derived=False, roughness = EAttribute(eType=Roughness, unique=True, derived=False,
changeable=True, default_value=Roughness.MediumRough) changeable=True, default_value=Roughness.MediumRough)
solarAbsorptance = EAttribute(eType=EDouble, unique=True, solarAbsorptance = EAttribute(eType=EDouble, unique=True,
derived=False, changeable=True, default_value=0.0)
conductivity = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
visibleAbsorptance = EAttribute(eType=EDouble, unique=True,
derived=False, changeable=True, default_value=0.0)
specificHeat = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
density = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
thermalAbsorptance = EAttribute(eType=EDouble, unique=True,
derived=False, changeable=True, default_value=0.0) derived=False, changeable=True, default_value=0.0)
conductivity = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
visibleAbsorptance = EAttribute(eType=EDouble, unique=True,
derived=False, changeable=True, default_value=0.0)
specificHeat = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
density = EAttribute(eType=EDouble, unique=True, derived=False,
changeable=True, default_value=0.0)
thermalAbsorptance = EAttribute(eType=EDouble, unique=True,
derived=False, changeable=True, default_value=0.0)
def __init__(self, *, roughness=None, solarAbsorptance=None, conductivity=None, visibleAbsorptance=None, specificHeat=None, density=None, thermalAbsorptance=None): def __init__(self, *, roughness=None, solarAbsorptance=None, conductivity=None, visibleAbsorptance=None, specificHeat=None, density=None, thermalAbsorptance=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if roughness is not None: if roughness is not None:
self.roughness = roughness self.roughness = roughness
if solarAbsorptance is not None: if solarAbsorptance is not None:
self.solarAbsorptance = solarAbsorptance self.solarAbsorptance = solarAbsorptance
if conductivity is not None: if conductivity is not None:
self.conductivity = conductivity self.conductivity = conductivity
if visibleAbsorptance is not None: if visibleAbsorptance is not None:
self.visibleAbsorptance = visibleAbsorptance self.visibleAbsorptance = visibleAbsorptance
if specificHeat is not None: if specificHeat is not None:
self.specificHeat = specificHeat self.specificHeat = specificHeat
if density is not None: if density is not None:
self.density = density self.density = density
if thermalAbsorptance is not None: if thermalAbsorptance is not None:
self.thermalAbsorptance = thermalAbsorptance self.thermalAbsorptance = thermalAbsorptance
class GreeneryCatalog(EObject, metaclass=MetaEClass): class GreeneryCatalog(EObject, metaclass=MetaEClass):
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True) name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
description = EAttribute(eType=EString, unique=True, derived=False, changeable=True) description = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
source = EAttribute(eType=EString, unique=True, derived=False, changeable=True) source = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
plantCategories = EReference(ordered=True, unique=True, plantCategories = EReference(ordered=True, unique=True,
containment=True, derived=False, upper=-1) containment=True, derived=False, upper=-1)
vegetationCategories = EReference(ordered=True, unique=True, vegetationCategories = EReference(ordered=True, unique=True,
containment=True, derived=False, upper=-1) containment=True, derived=False, upper=-1)
soils = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1) soils = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
def __init__(self, *, name=None, description=None, source=None, plantCategories=None, vegetationCategories=None, soils=None): def __init__(self, *, name=None, description=None, source=None, plantCategories=None, vegetationCategories=None, soils=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if name is not None: if name is not None:
self.name = name self.name = name
if description is not None: if description is not None:
self.description = description self.description = description
if source is not None: if source is not None:
self.source = source self.source = source
if plantCategories: if plantCategories:
self.plantCategories.extend(plantCategories) self.plantCategories.extend(plantCategories)
if vegetationCategories: if vegetationCategories:
self.vegetationCategories.extend(vegetationCategories) self.vegetationCategories.extend(vegetationCategories)
if soils: if soils:
self.soils.extend(soils) self.soils.extend(soils)
class PlantCategory(EObject, metaclass=MetaEClass): class PlantCategory(EObject, metaclass=MetaEClass):
"""Excluding (that is non-overlapping) categories like Trees, Hedeges, Grasses that help users finding a specific biol. plant species.""" """Excluding (that is non-overlapping) categories like Trees, Hedeges, Grasses that help users finding a specific biol. plant species."""
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True) name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1) plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
def __init__(self, *, name=None, plants=None): def __init__(self, *, name=None, plants=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if name is not None: if name is not None:
self.name = name self.name = name
if plants: if plants:
self.plants.extend(plants) self.plants.extend(plants)
class IrrigationSchedule(EObject, metaclass=MetaEClass): class IrrigationSchedule(EObject, metaclass=MetaEClass):
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True) name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
def __init__(self, *, name=None): def __init__(self, *, name=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if name is not None: if name is not None:
self.name = name self.name = name
class Vegetation(EObject, metaclass=MetaEClass): class Vegetation(EObject, metaclass=MetaEClass):
"""Plant life or total plant cover (as of an area)""" """Plant life or total plant cover (as of an area)"""
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True) name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
thicknessOfSoil = EAttribute(eType=EString, unique=True, derived=False, thicknessOfSoil = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='20 cm') changeable=True, default_value='20 cm')
management = EAttribute(eType=Management, unique=True, derived=False, management = EAttribute(eType=Management, unique=True, derived=False,
changeable=True, default_value=Management.NA) changeable=True, default_value=Management.NA)
airGap = EAttribute(eType=EString, unique=True, derived=False, airGap = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='0.0 cm') changeable=True, default_value='0.0 cm')
soil = EReference(ordered=True, unique=True, containment=False, derived=False) soil = EReference(ordered=True, unique=True, containment=False, derived=False)
plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1) plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
def __init__(self, *, name=None, thicknessOfSoil=None, soil=None, plants=None, management=None, airGap=None): def __init__(self, *, name=None, thicknessOfSoil=None, soil=None, plants=None, management=None, airGap=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if name is not None: if name is not None:
self.name = name self.name = name
if thicknessOfSoil is not None: if thicknessOfSoil is not None:
self.thicknessOfSoil = thicknessOfSoil self.thicknessOfSoil = thicknessOfSoil
if management is not None: if management is not None:
self.management = management self.management = management
if airGap is not None: if airGap is not None:
self.airGap = airGap self.airGap = airGap
if soil is not None: if soil is not None:
self.soil = soil self.soil = soil
if plants: if plants:
self.plants.extend(plants) self.plants.extend(plants)
class VegetationCategory(EObject, metaclass=MetaEClass): class VegetationCategory(EObject, metaclass=MetaEClass):
"""Excluding (that is non-overlapping) categories to help users finding a specific vegetation template.""" """Excluding (that is non-overlapping) categories to help users finding a specific vegetation template."""
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True) name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
vegetationTemplates = EReference(ordered=True, unique=True, vegetationTemplates = EReference(ordered=True, unique=True,
containment=True, derived=False, upper=-1) containment=True, derived=False, upper=-1)
def __init__(self, *, vegetationTemplates=None, name=None): def __init__(self, *, vegetationTemplates=None, name=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if name is not None: if name is not None:
self.name = name self.name = name
if vegetationTemplates: if vegetationTemplates:
self.vegetationTemplates.extend(vegetationTemplates) self.vegetationTemplates.extend(vegetationTemplates)
class PlantPercentage(EObject, metaclass=MetaEClass): class PlantPercentage(EObject, metaclass=MetaEClass):
percentage = EAttribute(eType=EString, unique=True, derived=False, percentage = EAttribute(eType=EString, unique=True, derived=False,
changeable=True, default_value='100') changeable=True, default_value='100')
plant = EReference(ordered=True, unique=True, containment=False, derived=False) plant = EReference(ordered=True, unique=True, containment=False, derived=False)
def __init__(self, *, percentage=None, plant=None): def __init__(self, *, percentage=None, plant=None):
# if kwargs: # if kwargs:
# raise AttributeError('unexpected arguments: {}'.format(kwargs)) # raise AttributeError('unexpected arguments: {}'.format(kwargs))
super().__init__() super().__init__()
if percentage is not None: if percentage is not None:
self.percentage = percentage self.percentage = percentage
if plant is not None: if plant is not None:
self.plant = plant self.plant = plant

View File

@ -4,12 +4,12 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
import logging
from pathlib import Path from pathlib import Path
from typing import TypeVar from typing import TypeVar
from hub.catalog_factories.greenery.greenery_catalog import GreeneryCatalog from hub.catalog_factories.greenery.greenery_catalog import GreeneryCatalog
from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog') Catalog = TypeVar('Catalog')
@ -19,9 +19,8 @@ class GreeneryCatalogFactory:
""" """
def __init__(self, handler, base_path=None): def __init__(self, handler, base_path=None):
if base_path is None: if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/greenery') base_path = (Path(__file__).parent.parent / 'data/greenery').resolve()
self._handler = '_' + handler.lower() self._handler = '_' + handler.lower()
class_funcs = validate_import_export_type(GreeneryCatalogFactory, handler)
self._path = base_path self._path = base_path
@property @property

View File

View File

@ -148,13 +148,13 @@ class ComnetCatalog(Catalog):
if day == cte.SATURDAY: if day == cte.SATURDAY:
start = start + 1 start = start + 1
end = end + 1 end = end + 1
elif day == cte.SUNDAY or day == cte.HOLIDAY: elif day in (cte.SUNDAY, cte.HOLIDAY):
start = start + 2 start = start + 2
end = end + 2 end = end + 2
_schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0] _schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0]
_schedule = [] _schedule = []
for day in _schedule_values: for day in _schedule_values:
if schedule_name == 'ClgSetPt' or schedule_name == 'HtgSetPt' or schedule_name == 'WtrHtrSetPt': if schedule_name in ('ClgSetPt', 'HtgSetPt', 'WtrHtrSetPt'):
# to celsius # to celsius
if 'n.a.' in _schedule_values[day]: if 'n.a.' in _schedule_values[day]:
_schedule_values[day] = None _schedule_values[day] = None

View File

@ -4,10 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import sys
import hub.helpers.constants as cte
from typing import Dict from typing import Dict
import hub.helpers.constants as cte
class UsageHelper: class UsageHelper:
""" """
@ -92,41 +92,49 @@ class UsageHelper:
@property @property
def nrcan_day_type_to_hub_days(self): def nrcan_day_type_to_hub_days(self):
"""
Get a dictionary to convert nrcan day types to hub day types
"""
return self._nrcan_day_type_to_hub_days return self._nrcan_day_type_to_hub_days
@property @property
def nrcan_schedule_type_to_hub_schedule_type(self): def nrcan_schedule_type_to_hub_schedule_type(self):
"""
Get a dictionary to convert nrcan schedule types to hub schedule types
"""
return self._nrcan_schedule_type_to_hub_schedule_type return self._nrcan_schedule_type_to_hub_schedule_type
@property @property
def nrcan_data_type_to_hub_data_type(self): def nrcan_data_type_to_hub_data_type(self):
"""
Get a dictionary to convert nrcan data types to hub data types
"""
return self._nrcan_data_type_to_hub_data_type return self._nrcan_data_type_to_hub_data_type
@property @property
def nrcan_time_to_hub_time(self): def nrcan_time_to_hub_time(self):
"""
Get a dictionary to convert nrcan time to hub time
"""
return self._nrcan_time_to_hub_time return self._nrcan_time_to_hub_time
@property @property
def comnet_data_type_to_hub_data_type(self): def comnet_data_type_to_hub_data_type(self) -> Dict:
"""
Get a dictionary to convert comnet data types to hub data types
"""
return self._comnet_data_type_to_hub_data_type return self._comnet_data_type_to_hub_data_type
@property @property
def comnet_schedules_key_to_comnet_schedules(self) -> Dict: def comnet_schedules_key_to_comnet_schedules(self) -> Dict:
"""
Get a dictionary to convert hub schedules to comnet schedules
"""
return self._comnet_schedules_key_to_comnet_schedules return self._comnet_schedules_key_to_comnet_schedules
@property @property
def comnet_days(self): def comnet_days(self) -> [str]:
"""
Get the list of days used in comnet
"""
return self._comnet_days return self._comnet_days
@staticmethod
def schedules_key(usage):
"""
Get Comnet schedules key from the list found in the Comnet usage file
:param usage: str
:return: str
"""
try:
return UsageHelper._comnet_schedules_key_to_comnet_schedules[usage]
except KeyError:
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
'done changing the keywords.\n')

View File

View File

@ -45,14 +45,13 @@ class Plane:
:return: (A, B, C, D) :return: (A, B, C, D)
""" """
if self._equation is None: if self._equation is None:
a = self.normal[0] a = self.normal[0]
b = self.normal[1] b = self.normal[1]
c = self.normal[2] c = self.normal[2]
d = ((-1 * self.origin.coordinates[0]) * self.normal[0]) d = -1 * self.origin.coordinates[0] * self.normal[0]
d += ((-1 * self.origin.coordinates[1]) * self.normal[1]) d += -1 * self.origin.coordinates[1] * self.normal[1]
d += ((-1 * self.origin.coordinates[2]) * self.normal[2]) d += -1 * self.origin.coordinates[2] * self.normal[2]
self._equation = (a, b, c, d) self._equation = a, b, c, d
return self._equation return self._equation
def distance_to_point(self, point): def distance_to_point(self, point):

View File

@ -31,7 +31,7 @@ class Point:
:return: float :return: float
""" """
power = 0 power = 0
for dimension in range(0, len(self.coordinates)): for dimension in enumerate(self.coordinates):
power += math.pow(other_point.coordinates[dimension]-self.coordinates[dimension], 2) power += math.pow(other_point.coordinates[dimension]-self.coordinates[dimension], 2)
distance = math.sqrt(power) distance = math.sqrt(power)
return distance return distance

View File

@ -6,20 +6,21 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from __future__ import annotations from __future__ import annotations
import logging import logging
import math import math
import sys import sys
from typing import List from typing import List
import numpy as np import numpy as np
from trimesh import Trimesh
import trimesh.intersections
import trimesh.creation import trimesh.creation
import trimesh.geometry import trimesh.geometry
import trimesh.intersections
from shapely.geometry.polygon import Polygon as shapley_polygon from shapely.geometry.polygon import Polygon as shapley_polygon
from trimesh import Trimesh
from hub.city_model_structure.attributes.plane import Plane from hub.city_model_structure.attributes.plane import Plane
from hub.city_model_structure.attributes.point import Point from hub.city_model_structure.attributes.point import Point
import hub.helpers.constants as cte
class Polygon: class Polygon:
@ -69,44 +70,6 @@ class Polygon:
""" """
return self._coordinates return self._coordinates
def contains_point(self, point):
"""
Determines if the given point is contained by the current polygon
:return: boolean
"""
# fixme: This method doesn't seems to work.
n = len(self.vertices)
angle_sum = 0
for i in range(0, n):
vector_0 = self.vertices[i]
vector_1 = self.vertices[(i+1) % n]
# set to origin
vector_0[0] = vector_0[0] - point.coordinates[0]
vector_0[1] = vector_0[1] - point.coordinates[1]
vector_0[2] = vector_0[2] - point.coordinates[2]
vector_1[0] = vector_1[0] - point.coordinates[0]
vector_1[1] = vector_1[1] - point.coordinates[1]
vector_1[2] = vector_1[2] - point.coordinates[2]
module = np.linalg.norm(vector_0) * np.linalg.norm(vector_1)
scalar_product = np.dot(vector_0, vector_1)
angle = np.pi/2
if module != 0:
angle = abs(np.arcsin(scalar_product / module))
angle_sum += angle
return abs(angle_sum - math.pi*2) < cte.EPSILON
def contains_polygon(self, polygon):
"""
Determines if the given polygon is contained by the current polygon
:return: boolean
"""
for point in polygon.points:
if not self.contains_point(point):
return False
return True
@property @property
def points_list(self) -> np.ndarray: def points_list(self) -> np.ndarray:
""" """
@ -142,12 +105,12 @@ class Polygon:
if self._area is None: if self._area is None:
self._area = 0 self._area = 0
for triangle in self.triangles: for triangle in self.triangles:
ab = np.zeros(3) a_b = np.zeros(3)
ac = np.zeros(3) a_c = np.zeros(3)
for i in range(0, 3): for i in range(0, 3):
ab[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i] a_b[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
ac[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i] a_c[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
self._area += np.linalg.norm(np.cross(ab, ac)) / 2 self._area += np.linalg.norm(np.cross(a_b, a_c)) / 2
return self._area return self._area
@area.setter @area.setter
@ -217,7 +180,11 @@ class Polygon:
return -alpha return -alpha
@staticmethod @staticmethod
def triangle_mesh(vertices, normal): def triangle_mesh(vertices, normal) -> Trimesh:
"""
Get the triangulated mesh for the polygon
:return: Trimesh
"""
min_x = 1e16 min_x = 1e16
min_y = 1e16 min_y = 1e16
min_z = 1e16 min_z = 1e16
@ -246,8 +213,7 @@ class Polygon:
polygon = shapley_polygon(coordinates) polygon = shapley_polygon(coordinates)
try: try:
_, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
vertices_2d, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
mesh = Trimesh(vertices=vertices, faces=faces) mesh = Trimesh(vertices=vertices, faces=faces)
@ -267,13 +233,17 @@ class Polygon:
return mesh return mesh
except ValueError: except ValueError:
logging.error(f'Not able to triangulate polygon\n') logging.error('Not able to triangulate polygon\n')
_vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0]] _vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
_faces = [[0, 1, 2]] _faces = [[0, 1, 2]]
return Trimesh(vertices=_vertices, faces=_faces) return Trimesh(vertices=_vertices, faces=_faces)
@property @property
def triangles(self) -> List[Polygon]: def triangles(self) -> List[Polygon]:
"""
Triangulate the polygon and return a list of triangular polygons
:return: [Polygon]
"""
if self._triangles is None: if self._triangles is None:
self._triangles = [] self._triangles = []
_mesh = self.triangle_mesh(self.coordinates, self.normal) _mesh = self.triangle_mesh(self.coordinates, self.normal)
@ -336,7 +306,7 @@ class Polygon:
def _reshape(self, triangles) -> Polygon: def _reshape(self, triangles) -> Polygon:
edges_list = [] edges_list = []
for i in range(0, len(triangles)): for i in enumerate(triangles):
for edge in triangles[i].edges: for edge in triangles[i].edges:
if not self._edge_in_edges_list(edge, edges_list): if not self._edge_in_edges_list(edge, edges_list):
edges_list.append(edge) edges_list.append(edge)
@ -421,13 +391,14 @@ class Polygon:
if len(points) != 3: if len(points) != 3:
sub_polygons = polygon.triangles sub_polygons = polygon.triangles
# todo: I modified this! To be checked @Guille # todo: I modified this! To be checked @Guille
if len(sub_polygons) >= 1: if len(sub_polygons) < 1:
for sub_polygon in sub_polygons: continue
face = [] for sub_polygon in sub_polygons:
points = sub_polygon.coordinates face = []
for point in points: points = sub_polygon.coordinates
face.append(self._position_of(point, face)) for point in points:
self._faces.append(face) face.append(self._position_of(point, face))
self._faces.append(face)
else: else:
for point in points: for point in points:
face.append(self._position_of(point, face)) face.append(self._position_of(point, face))
@ -440,7 +411,7 @@ class Polygon:
:return: int :return: int
""" """
vertices = self.vertices vertices = self.vertices
for i in range(len(vertices)): for i in enumerate(vertices):
# ensure not duplicated vertex # ensure not duplicated vertex
power = 0 power = 0
vertex2 = vertices[i] vertex2 = vertices[i]

View File

@ -41,10 +41,10 @@ class Polyhedron:
:return: int :return: int
""" """
vertices = self.vertices vertices = self.vertices
for i in range(len(vertices)): for i, vertex in enumerate(vertices):
# ensure not duplicated vertex # ensure not duplicated vertex
power = 0 power = 0
vertex2 = vertices[i] vertex2 = vertex
for dimension in range(0, 3): for dimension in range(0, 3):
power += math.pow(vertex2[dimension] - point[dimension], 2) power += math.pow(vertex2[dimension] - point[dimension], 2)
distance = math.sqrt(power) distance = math.sqrt(power)
@ -92,13 +92,14 @@ class Polyhedron:
points = polygon.coordinates points = polygon.coordinates
if len(points) != 3: if len(points) != 3:
sub_polygons = polygon.triangles sub_polygons = polygon.triangles
if len(sub_polygons) >= 1: if len(sub_polygons) < 1:
for sub_polygon in sub_polygons: continue
face = [] for sub_polygon in sub_polygons:
points = sub_polygon.coordinates face = []
for point in points: points = sub_polygon.coordinates
face.append(self._position_of(point, face)) for point in points:
self._faces.append(face) face.append(self._position_of(point, face))
self._faces.append(face)
else: else:
for point in points: for point in points:
face.append(self._position_of(point, face)) face.append(self._position_of(point, face))

View File

@ -45,17 +45,17 @@ class Building(CityObject):
self._shell = None self._shell = None
self._aliases = None self._aliases = None
self._type = 'building' self._type = 'building'
self._cold_water_temperature = dict() self._cold_water_temperature = {}
self._heating = dict() self._heating = {}
self._cooling = dict() self._cooling = {}
self._lighting_electrical_demand = dict() self._lighting_electrical_demand = {}
self._appliances_electrical_demand = dict() self._appliances_electrical_demand = {}
self._domestic_hot_water_heat_demand = dict() self._domestic_hot_water_heat_demand = {}
self._heating_consumption = dict() self._heating_consumption = {}
self._cooling_consumption = dict() self._cooling_consumption = {}
self._domestic_hot_water_consumption = dict() self._domestic_hot_water_consumption = {}
self._distribution_systems_electrical_consumption = dict() self._distribution_systems_electrical_consumption = {}
self._onsite_electrical_production = dict() self._onsite_electrical_production = {}
self._eave_height = None self._eave_height = None
self._energy_systems = None self._energy_systems = None
self._systems_archetype_name = None self._systems_archetype_name = None
@ -86,7 +86,8 @@ class Building(CityObject):
elif surface.type == cte.INTERIOR_SLAB: elif surface.type == cte.INTERIOR_SLAB:
self._interior_slabs.append(surface) self._interior_slabs.append(surface)
else: else:
logging.error(f'Building {self.name} [{self.aliases}] has an unexpected surface type {surface.type}.\n') error = f'Building {self.name} [{self.aliases}] has an unexpected surface type {surface.type}.\n'
logging.error(error)
@property @property
def shell(self) -> Polyhedron: def shell(self) -> Polyhedron:
@ -612,11 +613,11 @@ class Building(CityObject):
if len(_working_hours) == 0: if len(_working_hours) == 0:
_working_hours = _working_hours_per_thermal_zone _working_hours = _working_hours_per_thermal_zone
else: else:
for key in _working_hours.keys(): for key, item in _working_hours.items():
saved_values = _working_hours_per_thermal_zone[key] saved_values = _working_hours_per_thermal_zone[key]
for i, value in enumerate(_working_hours[key]): for i, value in enumerate(item):
if saved_values[i] == 1: if saved_values[i] == 1:
_working_hours[key][i] = 1 value = 1
_total_hours = 0 _total_hours = 0
for key in _working_hours: for key in _working_hours:
_total_hours += _working_hours[key] * cte.DAYS_A_YEAR[key] _total_hours += _working_hours[key] * cte.DAYS_A_YEAR[key]
@ -628,43 +629,44 @@ class Building(CityObject):
Get total electricity consumption for distribution and emission systems in Wh Get total electricity consumption for distribution and emission systems in Wh
return: dict return: dict
""" """
if len(self._distribution_systems_electrical_consumption) == 0: if len(self._distribution_systems_electrical_consumption) != 0:
_peak_load = self.heating_peak_load[cte.YEAR]['heating peak loads'][0] return self._distribution_systems_electrical_consumption
_peak_load_type = cte.HEATING _peak_load = self.heating_peak_load[cte.YEAR]['heating peak loads'][0]
if _peak_load < self.cooling_peak_load[cte.YEAR]['cooling peak loads'][0]: _peak_load_type = cte.HEATING
_peak_load = self.cooling_peak_load[cte.YEAR]['cooling peak loads'][0] if _peak_load < self.cooling_peak_load[cte.YEAR]['cooling peak loads'][0]:
_peak_load_type = cte.COOLING _peak_load = self.cooling_peak_load[cte.YEAR]['cooling peak loads'][0]
_peak_load_type = cte.COOLING
_consumption_fix_flow = 0 _consumption_fix_flow = 0
for energy_system in self.energy_systems: for energy_system in self.energy_systems:
emission_system = energy_system.emission_system.generic_emission_system emission_system = energy_system.emission_system.generic_emission_system
parasitic_energy_consumption = emission_system.parasitic_energy_consumption parasitic_energy_consumption = emission_system.parasitic_energy_consumption
distribution_system = energy_system.distribution_system.generic_distribution_system distribution_system = energy_system.distribution_system.generic_distribution_system
consumption_variable_flow = distribution_system.distribution_consumption_variable_flow consumption_variable_flow = distribution_system.distribution_consumption_variable_flow
for demand_type in energy_system.demand_types: for demand_type in energy_system.demand_types:
if demand_type.lower() == cte.HEATING: if demand_type.lower() == cte.HEATING:
if _peak_load_type == cte.HEATING: if _peak_load_type == cte.HEATING:
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow _consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
for heating_demand_key in self.heating: for heating_demand_key in self.heating:
_consumption = [0]*len(self.heating) _consumption = [0]*len(self.heating)
_demand = self.heating[heating_demand_key][cte.INSEL_MEB] _demand = self.heating[heating_demand_key][cte.INSEL_MEB]
for i in range(0, len(_consumption)): for i in enumerate(_consumption):
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i] _consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
if demand_type.lower() == cte.COOLING: if demand_type.lower() == cte.COOLING:
if _peak_load_type == cte.COOLING: if _peak_load_type == cte.COOLING:
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow _consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
for demand_key in self.cooling: for demand_key in self.cooling:
_consumption = self._distribution_systems_electrical_consumption[demand_key] _consumption = self._distribution_systems_electrical_consumption[demand_key]
_demand = self.cooling[demand_key][cte.INSEL_MEB] _demand = self.cooling[demand_key][cte.INSEL_MEB]
for i in range(0, len(_consumption)): for i in enumerate(_consumption):
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i] _consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
self._distribution_systems_electrical_consumption[demand_key] = _consumption self._distribution_systems_electrical_consumption[demand_key] = _consumption
for key in self._distribution_systems_electrical_consumption: for key, item in self._distribution_systems_electrical_consumption.items():
for i in range(0, len(self._distribution_systems_electrical_consumption[key])): for i in range(0, len(item)):
self._distribution_systems_electrical_consumption[key][i] += _peak_load * _consumption_fix_flow \ self._distribution_systems_electrical_consumption[key][i] += _peak_load * _consumption_fix_flow \
* self._calculate_working_hours() * self._calculate_working_hours()
return self._distribution_systems_electrical_consumption return self._distribution_systems_electrical_consumption
def _calculate_consumption(self, consumption_type, demand): def _calculate_consumption(self, consumption_type, demand):
@ -673,7 +675,7 @@ class Building(CityObject):
for energy_system in self.energy_systems: for energy_system in self.energy_systems:
for demand_type in energy_system.demand_types: for demand_type in energy_system.demand_types:
if demand_type.lower() == consumption_type.lower(): if demand_type.lower() == consumption_type.lower():
if consumption_type == cte.HEATING or consumption_type == cte.DOMESTIC_HOT_WATER: if consumption_type in (cte.HEATING, cte.DOMESTIC_HOT_WATER):
coefficient_of_performance = energy_system.generation_system.generic_generation_system.heat_efficiency coefficient_of_performance = energy_system.generation_system.generic_generation_system.heat_efficiency
elif consumption_type == cte.COOLING: elif consumption_type == cte.COOLING:
coefficient_of_performance = energy_system.generation_system.generic_generation_system.cooling_efficiency coefficient_of_performance = energy_system.generation_system.generic_generation_system.cooling_efficiency

View File

@ -10,8 +10,8 @@ from __future__ import annotations
import math import math
import uuid import uuid
import numpy as np
from typing import List, Union from typing import List, Union
import numpy as np
from hub.city_model_structure.attributes.polygon import Polygon from hub.city_model_structure.attributes.polygon import Polygon
from hub.city_model_structure.attributes.plane import Plane from hub.city_model_structure.attributes.plane import Plane
from hub.city_model_structure.attributes.point import Point from hub.city_model_structure.attributes.point import Point
@ -34,7 +34,7 @@ class Surface:
self._area = None self._area = None
self._lower_corner = None self._lower_corner = None
self._upper_corner = None self._upper_corner = None
self._global_irradiance = dict() self._global_irradiance = {}
self._perimeter_polygon = perimeter_polygon self._perimeter_polygon = perimeter_polygon
self._holes_polygons = holes_polygons self._holes_polygons = holes_polygons
self._solid_polygon = solid_polygon self._solid_polygon = solid_polygon

View File

@ -226,7 +226,7 @@ class ThermalBoundary:
r_value += float(layer.thickness) / float(layer.material.conductivity) r_value += float(layer.thickness) / float(layer.material.conductivity)
self._u_value = 1.0/r_value self._u_value = 1.0/r_value
except TypeError: except TypeError:
raise Exception('Constructions layers are not initialized') from TypeError raise TypeError('Constructions layers are not initialized') from TypeError
return self._u_value return self._u_value
@u_value.setter @u_value.setter

View File

@ -8,8 +8,9 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
import uuid import uuid
import copy import copy
import numpy
from typing import List, Union, TypeVar from typing import List, Union, TypeVar
import numpy
from hub.city_model_structure.building_demand.occupancy import Occupancy from hub.city_model_structure.building_demand.occupancy import Occupancy
from hub.city_model_structure.building_demand.appliances import Appliances from hub.city_model_structure.building_demand.appliances import Appliances
from hub.city_model_structure.building_demand.lighting import Lighting from hub.city_model_structure.building_demand.lighting import Lighting
@ -59,7 +60,11 @@ class ThermalZone:
@property @property
def usages(self): def usages(self):
# example 70-office_30-residential """
Get the thermal zone usages including percentage with the format [percentage]-usage_[percentage]-usage...
Eg: 70-office_30-residential
:return: str
"""
if self._usage_from_parent: if self._usage_from_parent:
self._usages = copy.deepcopy(self._parent_internal_zone.usages) self._usages = copy.deepcopy(self._parent_internal_zone.usages)
else: else:
@ -324,19 +329,19 @@ class ThermalZone:
_occupancy_reference = self.usages[0].occupancy _occupancy_reference = self.usages[0].occupancy
if _occupancy_reference.occupancy_schedules is not None: if _occupancy_reference.occupancy_schedules is not None:
_schedules = [] _schedules = []
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)): for schedule_index, schedule_value in enumerate(_occupancy_reference.occupancy_schedules):
schedule = Schedule() schedule = Schedule()
schedule.type = _occupancy_reference.occupancy_schedules[i_schedule].type schedule.type = schedule_value.type
schedule.day_types = _occupancy_reference.occupancy_schedules[i_schedule].day_types schedule.day_types = schedule_value.day_types
schedule.data_type = _occupancy_reference.occupancy_schedules[i_schedule].data_type schedule.data_type = schedule_value.data_type
schedule.time_step = _occupancy_reference.occupancy_schedules[i_schedule].time_step schedule.time_step = schedule_value.time_step
schedule.time_range = _occupancy_reference.occupancy_schedules[i_schedule].time_range schedule.time_range = schedule_value.time_range
new_values = [] new_values = []
for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)): for i_value, _ in enumerate(schedule_value.values):
_new_value = 0 _new_value = 0
for usage in self.usages: for usage in self.usages:
_new_value += usage.percentage * usage.occupancy.occupancy_schedules[i_schedule].values[i_value] _new_value += usage.percentage * usage.occupancy.occupancy_schedules[schedule_index].values[i_value]
new_values.append(_new_value) new_values.append(_new_value)
schedule.values = new_values schedule.values = new_values
_schedules.append(schedule) _schedules.append(schedule)
@ -385,19 +390,19 @@ class ThermalZone:
_lighting_reference = self.usages[0].lighting _lighting_reference = self.usages[0].lighting
if _lighting_reference.schedules is not None: if _lighting_reference.schedules is not None:
_schedules = [] _schedules = []
for i_schedule in range(0, len(_lighting_reference.schedules)): for schedule_index, schedule_value in enumerate(_lighting_reference.schedules):
schedule = Schedule() schedule = Schedule()
schedule.type = _lighting_reference.schedules[i_schedule].type schedule.type = schedule_value.type
schedule.day_types = _lighting_reference.schedules[i_schedule].day_types schedule.day_types = schedule_value.day_types
schedule.data_type = _lighting_reference.schedules[i_schedule].data_type schedule.data_type = schedule_value.data_type
schedule.time_step = _lighting_reference.schedules[i_schedule].time_step schedule.time_step = schedule_value.time_step
schedule.time_range = _lighting_reference.schedules[i_schedule].time_range schedule.time_range = schedule_value.time_range
new_values = [] new_values = []
for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)): for i_value, _ in enumerate(schedule_value.values):
_new_value = 0 _new_value = 0
for usage in self.usages: for usage in self.usages:
_new_value += usage.percentage * usage.lighting.schedules[i_schedule].values[i_value] _new_value += usage.percentage * usage.lighting.schedules[schedule_index].values[i_value]
new_values.append(_new_value) new_values.append(_new_value)
schedule.values = new_values schedule.values = new_values
_schedules.append(schedule) _schedules.append(schedule)
@ -446,19 +451,19 @@ class ThermalZone:
_appliances_reference = self.usages[0].appliances _appliances_reference = self.usages[0].appliances
if _appliances_reference.schedules is not None: if _appliances_reference.schedules is not None:
_schedules = [] _schedules = []
for i_schedule in range(0, len(_appliances_reference.schedules)): for schedule_index, schedule_value in enumerate(_appliances_reference.schedules):
schedule = Schedule() schedule = Schedule()
schedule.type = _appliances_reference.schedules[i_schedule].type schedule.type = schedule_value.type
schedule.day_types = _appliances_reference.schedules[i_schedule].day_types schedule.day_types = schedule_value.day_types
schedule.data_type = _appliances_reference.schedules[i_schedule].data_type schedule.data_type = schedule_value.data_type
schedule.time_step = _appliances_reference.schedules[i_schedule].time_step schedule.time_step = schedule_value.time_step
schedule.time_range = _appliances_reference.schedules[i_schedule].time_range schedule.time_range = schedule_value.time_range
new_values = [] new_values = []
for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)): for i_value, _ in enumerate(schedule_value.values):
_new_value = 0 _new_value = 0
for usage in self.usages: for usage in self.usages:
_new_value += usage.percentage * usage.appliances.schedules[i_schedule].values[i_value] _new_value += usage.percentage * usage.appliances.schedules[schedule_index].values[i_value]
new_values.append(_new_value) new_values.append(_new_value)
schedule.values = new_values schedule.values = new_values
_schedules.append(schedule) _schedules.append(schedule)
@ -510,12 +515,12 @@ class ThermalZone:
_schedules_defined = False _schedules_defined = False
break break
for day, _schedule in enumerate(internal_gain.schedules): for day, _schedule in enumerate(internal_gain.schedules):
for v, value in enumerate(_schedule.values): for v_index, value in enumerate(_schedule.values):
values[v, day] += value * usage.percentage values[v_index, day] += value * usage.percentage
if _schedules_defined: if _schedules_defined:
_schedules = [] _schedules = []
for day in range(0, len(_days)): for day, _ in enumerate(_days):
_schedule = copy.deepcopy(_base_schedule) _schedule = copy.deepcopy(_base_schedule)
_schedule.day_types = [_days[day]] _schedule.day_types = [_days[day]]
_schedule.values = values[:day] _schedule.values = values[:day]
@ -543,62 +548,62 @@ class ThermalZone:
if self.usages is None: if self.usages is None:
return None return None
if self._thermal_control is None: if self._thermal_control is not None:
self._thermal_control = ThermalControl() return self._thermal_control
_mean_heating_set_point = 0 self._thermal_control = ThermalControl()
_heating_set_back = 0 _mean_heating_set_point = 0
_mean_cooling_set_point = 0 _heating_set_back = 0
for usage in self.usages: _mean_cooling_set_point = 0
_mean_heating_set_point += usage.percentage * usage.thermal_control.mean_heating_set_point for usage in self.usages:
_heating_set_back += usage.percentage * usage.thermal_control.heating_set_back _mean_heating_set_point += usage.percentage * usage.thermal_control.mean_heating_set_point
_mean_cooling_set_point += usage.percentage * usage.thermal_control.mean_cooling_set_point _heating_set_back += usage.percentage * usage.thermal_control.heating_set_back
self._thermal_control.mean_heating_set_point = _mean_heating_set_point _mean_cooling_set_point += usage.percentage * usage.thermal_control.mean_cooling_set_point
self._thermal_control.heating_set_back = _heating_set_back self._thermal_control.mean_heating_set_point = _mean_heating_set_point
self._thermal_control.mean_cooling_set_point = _mean_cooling_set_point self._thermal_control.heating_set_back = _heating_set_back
self._thermal_control.mean_cooling_set_point = _mean_cooling_set_point
_thermal_control_reference = self.usages[0].thermal_control _thermal_control_reference = self.usages[0].thermal_control
_types_reference = [] _types_reference = []
if _thermal_control_reference.hvac_availability_schedules is not None: if _thermal_control_reference.hvac_availability_schedules is not None:
_types_reference.append([cte.HVAC_AVAILABILITY, _thermal_control_reference.hvac_availability_schedules]) _types_reference.append([cte.HVAC_AVAILABILITY, _thermal_control_reference.hvac_availability_schedules])
if _thermal_control_reference.heating_set_point_schedules is not None: if _thermal_control_reference.heating_set_point_schedules is not None:
_types_reference.append([cte.HEATING_SET_POINT, _thermal_control_reference.heating_set_point_schedules]) _types_reference.append([cte.HEATING_SET_POINT, _thermal_control_reference.heating_set_point_schedules])
if _thermal_control_reference.cooling_set_point_schedules is not None: if _thermal_control_reference.cooling_set_point_schedules is not None:
_types_reference.append([cte.COOLING_SET_POINT, _thermal_control_reference.cooling_set_point_schedules]) _types_reference.append([cte.COOLING_SET_POINT, _thermal_control_reference.cooling_set_point_schedules])
for i_type in range(0, len(_types_reference)): for i_type, _ in enumerate(_types_reference):
_schedules = [] _schedules = []
_schedule_type = _types_reference[i_type][1] _schedule_type = _types_reference[i_type][1]
for i_schedule in range(0, len(_schedule_type)): for i_schedule, schedule_value in enumerate(_schedule_type):
schedule = Schedule() schedule = Schedule()
schedule.type = _schedule_type[i_schedule].type schedule.type = schedule_value.type
schedule.day_types = _schedule_type[i_schedule].day_types schedule.day_types = schedule_value.day_types
schedule.data_type = _schedule_type[i_schedule].data_type schedule.data_type = schedule_value.data_type
schedule.time_step = _schedule_type[i_schedule].time_step schedule.time_step = schedule_value.time_step
schedule.time_range = _schedule_type[i_schedule].time_range schedule.time_range = schedule_value.time_range
new_values = []
for i_value in range(0, len(_schedule_type[i_schedule].values)):
_new_value = 0
for usage in self.usages:
if _types_reference[i_type][0] == cte.HVAC_AVAILABILITY:
_new_value += usage.percentage * \
usage.thermal_control.hvac_availability_schedules[i_schedule].values[i_value]
elif _types_reference[i_type][0] == cte.HEATING_SET_POINT:
_new_value += usage.percentage * \
usage.thermal_control.heating_set_point_schedules[i_schedule].values[i_value]
elif _types_reference[i_type][0] == cte.COOLING_SET_POINT:
_new_value += usage.percentage * \
usage.thermal_control.cooling_set_point_schedules[i_schedule].values[i_value]
new_values.append(_new_value)
schedule.values = new_values
_schedules.append(schedule)
if i_type == 0:
self._thermal_control.hvac_availability_schedules = _schedules
elif i_type == 1:
self._thermal_control.heating_set_point_schedules = _schedules
elif i_type == 2:
self._thermal_control.cooling_set_point_schedules = _schedules
new_values = []
for i_value, _ in enumerate(schedule_value.values):
_new_value = 0
for usage in self.usages:
if _types_reference[i_type][0] == cte.HVAC_AVAILABILITY:
_new_value += usage.percentage * \
usage.thermal_control.hvac_availability_schedules[i_schedule].values[i_value]
elif _types_reference[i_type][0] == cte.HEATING_SET_POINT:
_new_value += usage.percentage * \
usage.thermal_control.heating_set_point_schedules[i_schedule].values[i_value]
elif _types_reference[i_type][0] == cte.COOLING_SET_POINT:
_new_value += usage.percentage * \
usage.thermal_control.cooling_set_point_schedules[i_schedule].values[i_value]
new_values.append(_new_value)
schedule.values = new_values
_schedules.append(schedule)
if i_type == 0:
self._thermal_control.hvac_availability_schedules = _schedules
elif i_type == 1:
self._thermal_control.heating_set_point_schedules = _schedules
elif i_type == 2:
self._thermal_control.cooling_set_point_schedules = _schedules
return self._thermal_control return self._thermal_control
@property @property
@ -622,19 +627,19 @@ class ThermalZone:
_domestic_hot_water_reference = self.usages[0].domestic_hot_water _domestic_hot_water_reference = self.usages[0].domestic_hot_water
if _domestic_hot_water_reference.schedules is not None: if _domestic_hot_water_reference.schedules is not None:
_schedules = [] _schedules = []
for i_schedule in range(0, len(_domestic_hot_water_reference.schedules)): for schedule_index, schedule_value in enumerate(_domestic_hot_water_reference.schedules):
schedule = Schedule() schedule = Schedule()
schedule.type = _domestic_hot_water_reference.schedules[i_schedule].type schedule.type = schedule_value.type
schedule.day_types = _domestic_hot_water_reference.schedules[i_schedule].day_types schedule.day_types = schedule_value.day_types
schedule.data_type = _domestic_hot_water_reference.schedules[i_schedule].data_type schedule.data_type = schedule_value.data_type
schedule.time_step = _domestic_hot_water_reference.schedules[i_schedule].time_step schedule.time_step = schedule_value.time_step
schedule.time_range = _domestic_hot_water_reference.schedules[i_schedule].time_range schedule.time_range = schedule_value.time_range
new_values = [] new_values = []
for i_value in range(0, len(_domestic_hot_water_reference.schedules[i_schedule].values)): for i_value, _ in enumerate(schedule_value.values):
_new_value = 0 _new_value = 0
for usage in self.usages: for usage in self.usages:
_new_value += usage.percentage * usage.domestic_hot_water.schedules[i_schedule].values[i_value] _new_value += usage.percentage * usage.domestic_hot_water.schedules[schedule_index].values[i_value]
new_values.append(_new_value) new_values.append(_new_value)
schedule.values = new_values schedule.values = new_values
_schedules.append(schedule) _schedules.append(schedule)

View File

@ -8,29 +8,27 @@ Code contributors: Peter Yefi peteryefi@gmail.com
from __future__ import annotations from __future__ import annotations
import bz2 import bz2
import logging
import sys
import pickle
import math
import copy import copy
import pyproj import logging
from typing import List, Union import math
from pyproj import Transformer import pickle
from pathlib import Path from pathlib import Path
from typing import List, Union
import pyproj
from pandas import DataFrame from pandas import DataFrame
from pyproj import Transformer
from hub.city_model_structure.building import Building from hub.city_model_structure.building import Building
from hub.city_model_structure.buildings_cluster import BuildingsCluster
from hub.city_model_structure.city_object import CityObject from hub.city_model_structure.city_object import CityObject
from hub.city_model_structure.city_objects_cluster import CityObjectsCluster from hub.city_model_structure.city_objects_cluster import CityObjectsCluster
from hub.city_model_structure.buildings_cluster import BuildingsCluster from hub.city_model_structure.energy_system import EnergySystem
from hub.city_model_structure.iot.station import Station from hub.city_model_structure.iot.station import Station
from hub.city_model_structure.level_of_detail import LevelOfDetail from hub.city_model_structure.level_of_detail import LevelOfDetail
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
from hub.helpers.geometry_helper import GeometryHelper from hub.helpers.geometry_helper import GeometryHelper
from hub.helpers.location import Location from hub.helpers.location import Location
import hub.helpers.constants as cte
from hub.city_model_structure.energy_system import EnergySystem
import pandas as pd
class City: class City:
@ -70,11 +68,11 @@ class City:
if self._location is None: if self._location is None:
gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
try: try:
if self._srs_name in GeometryHelper.srs_transformations.keys(): if self._srs_name in GeometryHelper.srs_transformations:
self._srs_name = GeometryHelper.srs_transformations[self._srs_name] self._srs_name = GeometryHelper.srs_transformations[self._srs_name]
input_reference = pyproj.CRS(self.srs_name) # Projected coordinate system from input data input_reference = pyproj.CRS(self.srs_name) # Projected coordinate system from input data
except pyproj.exceptions.CRSError as err: except pyproj.exceptions.CRSError as err:
logging.error('Invalid projection reference system, please check the input data. (e.g. in CityGML files: srs_name)') logging.error('Invalid projection reference system, please check the input data.')
raise pyproj.exceptions.CRSError from err raise pyproj.exceptions.CRSError from err
transformer = Transformer.from_crs(input_reference, gps) transformer = Transformer.from_crs(input_reference, gps)
coordinates = transformer.transform(self.lower_corner[0], self.lower_corner[1]) coordinates = transformer.transform(self.lower_corner[0], self.lower_corner[1])
@ -90,7 +88,11 @@ class City:
return self._get_location().country return self._get_location().country
@property @property
def location(self): def location(self) -> Location:
"""
Get city location
:return: Location
"""
return self._get_location().city return self._get_location().city
@property @property
@ -203,8 +205,11 @@ class City:
return None return None
def add_building_alias(self, building, alias): def add_building_alias(self, building, alias):
"""
Add an alias to the building
"""
building_index = self._city_objects_dictionary[building.name] building_index = self._city_objects_dictionary[building.name]
if alias in self._city_objects_alias_dictionary.keys(): if alias in self._city_objects_alias_dictionary:
self._city_objects_alias_dictionary[alias].append(building_index) self._city_objects_alias_dictionary[alias].append(building_index)
else: else:
self._city_objects_alias_dictionary[alias] = [building_index] self._city_objects_alias_dictionary[alias] = [building_index]
@ -218,7 +223,6 @@ class City:
if new_city_object.type == 'building': if new_city_object.type == 'building':
if self._buildings is None: if self._buildings is None:
self._buildings = [] self._buildings = []
new_city_object._alias_dictionary = self._city_objects_alias_dictionary
self._buildings.append(new_city_object) self._buildings.append(new_city_object)
self._city_objects_dictionary[new_city_object.name] = len(self._buildings) - 1 self._city_objects_dictionary[new_city_object.name] = len(self._buildings) - 1
if new_city_object.aliases is not None: if new_city_object.aliases is not None:
@ -242,17 +246,17 @@ class City:
""" """
if city_object.type != 'building': if city_object.type != 'building':
raise NotImplementedError(city_object.type) raise NotImplementedError(city_object.type)
if self._buildings is None or self._buildings == []: if not self._buildings:
sys.stderr.write('Warning: impossible to remove city_object, the city is empty\n') logging.warning('impossible to remove city_object, the city is empty\n')
else: else:
if city_object in self._buildings: if city_object in self._buildings:
self._buildings.remove(city_object) self._buildings.remove(city_object)
# regenerate hash map # regenerate hash map
self._city_objects_dictionary.clear() self._city_objects_dictionary.clear()
self._city_objects_alias_dictionary.clear() self._city_objects_alias_dictionary.clear()
for i, city_object in enumerate(self._buildings): for i, _building in enumerate(self._buildings):
self._city_objects_dictionary[city_object.name] = i self._city_objects_dictionary[_building.name] = i
for alias in city_object.aliases: for alias in _building.aliases:
if alias in self._city_objects_alias_dictionary: if alias in self._city_objects_alias_dictionary:
self._city_objects_alias_dictionary[alias].append(i) self._city_objects_alias_dictionary[alias].append(i)
else: else:
@ -300,8 +304,8 @@ class City:
:param city_filename: destination city filename :param city_filename: destination city filename
:return: None :return: None
""" """
with bz2.BZ2File(city_filename, 'wb') as f: with bz2.BZ2File(city_filename, 'wb') as file:
pickle.dump(self, f) pickle.dump(self, file)
def region(self, center, radius) -> City: def region(self, center, radius) -> City:
""" """
@ -446,6 +450,10 @@ class City:
return copy.deepcopy(self) return copy.deepcopy(self)
def merge(self, city) -> City: def merge(self, city) -> City:
"""
Return a merged city combining the current city and the given one
:return: City
"""
raise NotImplementedError('This method needs to be reimplemented') raise NotImplementedError('This method needs to be reimplemented')
@property @property

View File

@ -37,11 +37,11 @@ class CityObject:
self._max_z = ConfigurationHelper().min_coordinate self._max_z = ConfigurationHelper().min_coordinate
self._centroid = None self._centroid = None
self._volume = None self._volume = None
self._external_temperature = dict() self._external_temperature = {}
self._ground_temperature = dict() self._ground_temperature = {}
self._global_horizontal = dict() self._global_horizontal = {}
self._diffuse = dict() self._diffuse = {}
self._beam = dict() self._beam = {}
self._sensors = [] self._sensors = []
self._neighbours = None self._neighbours = None

View File

@ -1,5 +1,5 @@
""" """
Energy control system definition Energy control system module
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca

View File

@ -1,5 +1,5 @@
""" """
Generic energy emission system definition Generic energy emission system module
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca

View File

@ -46,7 +46,7 @@ class HeatPump:
@hp_monthly_fossil_consumption.setter @hp_monthly_fossil_consumption.setter
def hp_monthly_fossil_consumption(self, value): def hp_monthly_fossil_consumption(self, value):
if type(value) is Series: if isinstance(value, Series):
self._hp_monthly_fossil_consumption = value self._hp_monthly_fossil_consumption = value
@property @property
@ -60,5 +60,5 @@ class HeatPump:
@hp_monthly_electricity_demand.setter @hp_monthly_electricity_demand.setter
def hp_monthly_electricity_demand(self, value): def hp_monthly_electricity_demand(self, value):
if type(value) == Series: if isinstance(value, Series):
self._hp_monthly_electricity_demand = value self._hp_monthly_electricity_demand = value

View File

@ -30,4 +30,3 @@ class HvacTerminalUnit:
""" """
if value is not None: if value is not None:
self._type = str(value) self._type = str(value)

View File

@ -1,5 +1,5 @@
""" """
Plant class Plant module
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
@ -10,6 +10,9 @@ from hub.city_model_structure.greenery.soil import Soil
class Plant: class Plant:
"""
Plant class
"""
def __init__(self, name, height, leaf_area_index, leaf_reflectivity, leaf_emissivity, minimal_stomatal_resistance, def __init__(self, name, height, leaf_area_index, leaf_reflectivity, leaf_emissivity, minimal_stomatal_resistance,
co2_sequestration, grows_on_soils): co2_sequestration, grows_on_soils):
self._name = name self._name = name

View File

@ -1,5 +1,5 @@
""" """
Soil class Soil module
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
@ -7,6 +7,9 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
class Soil: class Soil:
"""
Soil class
"""
def __init__(self, name, roughness, dry_conductivity, dry_density, dry_specific_heat, thermal_absorptance, def __init__(self, name, roughness, dry_conductivity, dry_density, dry_specific_heat, thermal_absorptance,
solar_absorptance, visible_absorptance, saturation_volumetric_moisture_content, solar_absorptance, visible_absorptance, saturation_volumetric_moisture_content,
residual_volumetric_moisture_content): residual_volumetric_moisture_content):

View File

@ -1,5 +1,5 @@
""" """
Vegetation class Vegetation module
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
@ -11,6 +11,9 @@ from hub.city_model_structure.greenery.plant import Plant
class Vegetation: class Vegetation:
"""
Vegetation class
"""
def __init__(self, name, soil, soil_thickness, plants): def __init__(self, name, soil, soil_thickness, plants):
self._name = name self._name = name
self._management = None self._management = None

View File

View File

@ -7,6 +7,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class SensorMeasure: class SensorMeasure:
"""
Sensor measure class
"""
def __init__(self, latitude, longitude, utc_timestamp, value): def __init__(self, latitude, longitude, utc_timestamp, value):
self._latitude = latitude self._latitude = latitude
self._longitude = longitude self._longitude = longitude

View File

@ -9,6 +9,9 @@ from enum import Enum
class SensorType(Enum): class SensorType(Enum):
"""
Sensor type enumeration
"""
HUMIDITY = 0 HUMIDITY = 0
TEMPERATURE = 1 TEMPERATURE = 1
CO2 = 2 CO2 = 2

View File

@ -1,5 +1,5 @@
""" """
Station Station module
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
@ -10,6 +10,9 @@ from hub.city_model_structure.iot.sensor import Sensor
class Station: class Station:
"""
Station class
"""
def __init__(self, station_id=None, _mobile=False): def __init__(self, station_id=None, _mobile=False):
self._id = station_id self._id = station_id
self._mobile = _mobile self._mobile = _mobile

0
hub/exports/__init__.py Normal file
View File

View File

View File

@ -93,7 +93,7 @@ class EnergyAde:
file_name = self._city.name + '_ade.gml' file_name = self._city.name + '_ade.gml'
file_path = Path(self._path / file_name).resolve() file_path = Path(self._path / file_name).resolve()
with open(file_path, 'w') as file: with open(file_path, 'w', encoding='utf8') as file:
file.write(xmltodict.unparse(energy_ade, pretty=True, short_empty_elements=True)) file.write(xmltodict.unparse(energy_ade, pretty=True, short_empty_elements=True))
@staticmethod @staticmethod

View File

@ -247,16 +247,16 @@ class Idf:
_new_field += f' {self.idf_day_types[day_type]}' _new_field += f' {self.idf_day_types[day_type]}'
_kwargs[f'Field_{j * 25 + 2}'] = f'For:{_new_field}' _kwargs[f'Field_{j * 25 + 2}'] = f'For:{_new_field}'
counter += 1 counter += 1
for i in range(0, len(_val)): for i, _ in enumerate(_val):
_kwargs[f'Field_{j * 25 + 3 + i}'] = f'Until: {i + 1:02d}:00,{_val[i]}' _kwargs[f'Field_{j * 25 + 3 + i}'] = f'Until: {i + 1:02d}:00,{_val[i]}'
counter += 1 counter += 1
_kwargs[f'Field_{counter + 1}'] = f'For AllOtherDays' _kwargs[f'Field_{counter + 1}'] = 'For AllOtherDays'
_kwargs[f'Field_{counter + 2}'] = f'Until: 24:00,0.0' _kwargs[f'Field_{counter + 2}'] = 'Until: 24:00,0.0'
self._idf.newidfobject(self._COMPACT_SCHEDULE, **_kwargs) self._idf.newidfobject(self._COMPACT_SCHEDULE, **_kwargs)
def _write_schedules_file(self, usage, schedule): def _write_schedules_file(self, usage, schedule):
file_name = str((Path(self._output_path) / f'{schedule.type} schedules {usage}.dat').resolve()) file_name = str((Path(self._output_path) / f'{schedule.type} schedules {usage}.dat').resolve())
with open(file_name, 'w') as file: with open(file_name, 'w', encoding='utf8') as file:
for value in schedule.values: for value in schedule.values:
file.write(f'{str(value)},\n') file.write(f'{str(value)},\n')
return file_name return file_name
@ -284,12 +284,14 @@ class Idf:
if schedule.Name == f'{schedule_type} schedules {usage}': if schedule.Name == f'{schedule_type} schedules {usage}':
return return
file_name = self._write_schedules_file(usage, new_schedules[0]) file_name = self._write_schedules_file(usage, new_schedules[0])
return self._add_file_schedule(usage, new_schedules[0], file_name) self._add_file_schedule(usage, new_schedules[0], file_name)
else: return
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
if schedule.Name == f'{schedule_type} schedules {usage}': for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
return if schedule.Name == f'{schedule_type} schedules {usage}':
return self._add_standard_compact_hourly_schedule(usage, schedule_type, new_schedules) return
self._add_standard_compact_hourly_schedule(usage, schedule_type, new_schedules)
return
def _add_construction(self, thermal_boundary): def _add_construction(self, thermal_boundary):
vegetation_name = f'{thermal_boundary.construction_name}_{thermal_boundary.parent_surface.vegetation.name}' vegetation_name = f'{thermal_boundary.construction_name}_{thermal_boundary.parent_surface.vegetation.name}'
@ -441,7 +443,7 @@ class Idf:
def _add_ventilation(self, thermal_zone, zone_name): def _add_ventilation(self, thermal_zone, zone_name):
for zone in self._idf.idfobjects["ZONE"]: for zone in self._idf.idfobjects["ZONE"]:
if zone.Name == f'{zone_name}_ventilation': if zone.Name == f'{zone_name}_ventilation':
return return
schedule = f'Ventilation schedules {thermal_zone.usage_name}' schedule = f'Ventilation schedules {thermal_zone.usage_name}'
#if schedule not in self._idf.idfobjects[self._HOURLY_SCHEDULE]: #if schedule not in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
# return # return

View File

@ -27,7 +27,9 @@ _NUMBER_DAYS_PER_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
class InselMonthlyEnergyBalance: class InselMonthlyEnergyBalance:
"""
Insel monthly energy balance class
"""
def __init__(self, city, path, radiation_calculation_method='sra', weather_format='epw'): def __init__(self, city, path, radiation_calculation_method='sra', weather_format='epw'):
self._city = city self._city = city
self._path = path self._path = path
@ -44,7 +46,7 @@ class InselMonthlyEnergyBalance:
if building.internal_zones is not None: if building.internal_zones is not None:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
if internal_zone.thermal_zones is None: if internal_zone.thermal_zones is None:
logging.error(f'Building {building.name} has missing values. Monthly Energy Balance cannot be processed\n') logging.warning(f'Building %s has missing values. Monthly Energy Balance cannot be processed', building.name)
break break
self._contents.append( self._contents.append(
self._generate_meb_template(building, output_path, self._radiation_calculation_method, self._weather_format) self._generate_meb_template(building, output_path, self._radiation_calculation_method, self._weather_format)
@ -65,33 +67,33 @@ class InselMonthlyEnergyBalance:
def _export(self): def _export(self):
for i_file, content in enumerate(self._contents): for i_file, content in enumerate(self._contents):
file_name = self._insel_files_paths[i_file] file_name = self._insel_files_paths[i_file]
with open(Path(self._path / file_name).resolve(), 'w') as insel_file: with open(Path(self._path / file_name).resolve(), 'w', encoding='utf8') as insel_file:
insel_file.write(content) insel_file.write(content)
return return
def _sanity_check(self): def _sanity_check(self):
levels_of_detail = self._city.level_of_detail levels_of_detail = self._city.level_of_detail
if levels_of_detail.geometry is None: if levels_of_detail.geometry is None:
raise Exception(f'Level of detail of geometry not assigned') raise AttributeError('Level of detail of geometry not assigned')
if levels_of_detail.geometry < 1: if levels_of_detail.geometry < 1:
raise Exception(f'Level of detail of geometry = {levels_of_detail.geometry}. Required minimum level 0.5') raise AttributeError(f'Level of detail of geometry = {levels_of_detail.geometry}. Required minimum level 0.5')
if levels_of_detail.construction is None: if levels_of_detail.construction is None:
raise Exception(f'Level of detail of construction not assigned') raise AttributeError('Level of detail of construction not assigned')
if levels_of_detail.construction < 1: if levels_of_detail.construction < 1:
raise Exception(f'Level of detail of construction = {levels_of_detail.construction}. Required minimum level 1') raise AttributeError(f'Level of detail of construction = {levels_of_detail.construction}. Required minimum level 1')
if levels_of_detail.usage is None: if levels_of_detail.usage is None:
raise Exception(f'Level of detail of usage not assigned') raise AttributeError('Level of detail of usage not assigned')
if levels_of_detail.usage < 1: if levels_of_detail.usage < 1:
raise Exception(f'Level of detail of usage = {levels_of_detail.usage}. Required minimum level 1') raise AttributeError(f'Level of detail of usage = {levels_of_detail.usage}. Required minimum level 1')
if levels_of_detail.weather is None: if levels_of_detail.weather is None:
raise Exception(f'Level of detail of weather not assigned') raise AttributeError('Level of detail of weather not assigned')
if levels_of_detail.weather < 1: if levels_of_detail.weather < 1:
raise Exception(f'Level of detail of weather = {levels_of_detail.weather}. Required minimum level 1') raise AttributeError(f'Level of detail of weather = {levels_of_detail.weather}. Required minimum level 1')
if levels_of_detail.surface_radiation is None: if levels_of_detail.surface_radiation is None:
raise Exception(f'Level of detail of surface radiation not assigned') raise AttributeError('Level of detail of surface radiation not assigned')
if levels_of_detail.surface_radiation < 1: if levels_of_detail.surface_radiation < 1:
raise Exception(f'Level of detail of surface radiation = {levels_of_detail.surface_radiation}. ' raise AttributeError(f'Level of detail of surface radiation = {levels_of_detail.surface_radiation}. '
f'Required minimum level 1') f'Required minimum level 1')
@staticmethod @staticmethod
def _generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format): def _generate_meb_template(building, insel_outputs_path, radiation_calculation_method, weather_format):

View File

@ -5,8 +5,8 @@ Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de uribarri pilar.monsalvete@concordia.ca
""" """
import logging
from pathlib import Path from pathlib import Path
from hub.exports.building_energy.energy_ade import EnergyAde from hub.exports.building_energy.energy_ade import EnergyAde
from hub.exports.building_energy.idf import Idf from hub.exports.building_energy.idf import Idf
from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance

View File

@ -49,8 +49,8 @@ class EnergySystemsExportFactory:
if self._source == 'air': if self._source == 'air':
return AirSourceHPExport(self._base_path, self._city, self._output_path, self._sim_type, self._demand_path)\ return AirSourceHPExport(self._base_path, self._city, self._output_path, self._sim_type, self._demand_path)\
.execute_insel(self._handler, self._hp_model, self._data_type) .execute_insel(self._handler, self._hp_model, self._data_type)
elif self._source == 'water':
return WaterToWaterHPExport(self._base_path, self._city, self._output_path, self._sim_type, self._demand_path)\ return WaterToWaterHPExport(self._base_path, self._city, self._output_path, self._sim_type, self._demand_path)\
.execute_insel(self._handler, self._hp_model) .execute_insel(self._handler, self._hp_model)
def export(self, source='air'): def export(self, source='air'):

View File

@ -5,8 +5,8 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
import logging
from pathlib import Path from pathlib import Path
from hub.exports.formats.obj import Obj from hub.exports.formats.obj import Obj
from hub.exports.formats.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm from hub.exports.formats.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
from hub.exports.formats.stl import Stl from hub.exports.formats.stl import Stl

View File

0
hub/helpers/__init__.py Normal file
View File

View File

View File

View File

@ -85,7 +85,7 @@ class ConstructionHelper:
:return: str :return: str
""" """
reference_city = ConstructionHelper.city_to_reference_city(city) reference_city = ConstructionHelper.city_to_reference_city(city)
if reference_city not in ConstructionHelper._reference_city_to_nrel_climate_zone.keys(): if reference_city not in ConstructionHelper._reference_city_to_nrel_climate_zone:
reference_city = 'Baltimore' reference_city = 'Baltimore'
return ConstructionHelper._reference_city_to_nrel_climate_zone[reference_city] return ConstructionHelper._reference_city_to_nrel_climate_zone[reference_city]

View File

@ -59,7 +59,7 @@ class StoreysGeneration:
return [storey.thermal_zone] return [storey.thermal_zone]
if number_of_storeys == 0: if number_of_storeys == 0:
raise Exception('Number of storeys cannot be 0') raise ArithmeticError('Number of storeys cannot be 0')
storeys = [] storeys = []
surfaces_child_last_storey = [] surfaces_child_last_storey = []
@ -106,7 +106,7 @@ class StoreysGeneration:
neighbours = ['storey_' + str(number_of_storeys - 2), None] neighbours = ['storey_' + str(number_of_storeys - 2), None]
volume = self._building.volume - total_volume volume = self._building.volume - total_volume
if volume < 0: if volume < 0:
raise Exception('Error in storeys creation, volume of last storey cannot be lower that 0') raise ArithmeticError('Error in storeys creation, volume of last storey cannot be lower that 0')
storeys.append(Storey(name, surfaces_child_last_storey, neighbours, volume, self._internal_zone, self._floor_area)) storeys.append(Storey(name, surfaces_child_last_storey, neighbours, volume, self._internal_zone, self._floor_area))
for storey in storeys: for storey in storeys:

View File

View File

@ -7,14 +7,14 @@ contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import io import io
import pandas as pd import itertools
from typing import List
from typing import Dict from typing import Dict
import pandas as pd
import numpy as np
from scipy.optimize import curve_fit
from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP from hub.city_model_structure.energy_systems.air_source_hp import AirSourceHP
from hub.city_model_structure.energy_system import EnergySystem from hub.city_model_structure.energy_system import EnergySystem
from scipy.optimize import curve_fit
import numpy as np
from typing import List
import itertools
class AirSourceHeatPumpParameters: class AirSourceHeatPumpParameters:
@ -24,7 +24,7 @@ class AirSourceHeatPumpParameters:
def __init__(self, city, base_path): def __init__(self, city, base_path):
self._city = city self._city = city
self._base_path = (base_path / 'heat_pumps/air_source.xlsx') self._base_path = (base_path / 'heat_pumps/air_source.xlsx').resolve()
def _read_file(self) -> Dict: def _read_file(self) -> Dict:
""" """
@ -38,7 +38,7 @@ class AirSourceHeatPumpParameters:
cooling_data = {} cooling_data = {}
heating_data = {} heating_data = {}
for sheet, dataframe in xl_file.items(): for sheet, _ in xl_file.items():
if 'Summary' in sheet: if 'Summary' in sheet:
continue continue
@ -68,7 +68,7 @@ class AirSourceHeatPumpParameters:
Enriches the city with information from file Enriches the city with information from file
""" """
heat_pump_data = self._read_file() heat_pump_data = self._read_file()
for (k_cool, v_cool), (k_heat, v_heat) in zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()): for (k_cool, v_cool), (_, v_heat) in zip(heat_pump_data["cooling"].items(), heat_pump_data["heating"].items()):
heat_pump = AirSourceHP() heat_pump = AirSourceHP()
heat_pump.model = k_cool heat_pump.model = k_cool
h_data = self._extract_heat_pump_data(v_heat) h_data = self._extract_heat_pump_data(v_heat)
@ -80,7 +80,7 @@ class AirSourceHeatPumpParameters:
heat_pump.heating_comp_power = h_data[1] heat_pump.heating_comp_power = h_data[1]
heat_pump.heating_capacity_coff = self._compute_coefficients(h_data) heat_pump.heating_capacity_coff = self._compute_coefficients(h_data)
energy_system = EnergySystem('{} capacity heat pump'.format(heat_pump.model), []) energy_system = EnergySystem(f'{heat_pump.model} capacity heat pump', [])
energy_system.air_source_hp = heat_pump energy_system.air_source_hp = heat_pump
self._city.add_city_object(energy_system) self._city.add_city_object(energy_system)
return self._city return self._city

View File

@ -43,7 +43,8 @@ class MontrealCustomEnergySystemParameters:
try: try:
archetype = self._search_archetypes(montreal_custom_catalog, archetype_name) archetype = self._search_archetypes(montreal_custom_catalog, archetype_name)
except KeyError: except KeyError:
logging.error(f'Building {building.name} has unknown energy system archetype for system name: {archetype_name}') logging.error('Building %s has unknown energy system archetype for system name %s', building.name,
archetype_name)
continue continue
building_systems = [] building_systems = []
@ -58,7 +59,7 @@ class MontrealCustomEnergySystemParameters:
energy_system.demand_types = _hub_demand_types energy_system.demand_types = _hub_demand_types
_generation_system = GenericGenerationSystem() _generation_system = GenericGenerationSystem()
archetype_generation_equipment = equipment.generation_system archetype_generation_equipment = equipment.generation_system
_type = str(equipment.name).split('_')[0] _type = str(equipment.name).split('_', maxsplit=1)[0]
_generation_system.type = Dictionaries().montreal_system_to_hub_energy_generation_system[ _generation_system.type = Dictionaries().montreal_system_to_hub_energy_generation_system[
_type] _type]
_generation_system.fuel_type = archetype_generation_equipment.fuel_type _generation_system.fuel_type = archetype_generation_equipment.fuel_type

View File

@ -23,7 +23,7 @@ class WaterToWaterHPParameters:
def __init__(self, city, base_path): def __init__(self, city, base_path):
self._city = city self._city = city
self._base_path = (base_path / 'heat_pumps/water_to_water.xlsx') self._base_path = (base_path / 'heat_pumps/water_to_water.xlsx').resolve()
def _read_file(self) -> Dict: def _read_file(self) -> Dict:
# todo: this method is keeping the excel file open and should be either corrected or removed # todo: this method is keeping the excel file open and should be either corrected or removed
@ -38,7 +38,7 @@ class WaterToWaterHPParameters:
'335': [6.62, 9.97, 12.93], '335': [6.62, 9.97, 12.93],
} }
for sheet, dataframe in heat_pump_dfs.items(): for sheet, _ in heat_pump_dfs.items():
df = heat_pump_dfs[sheet].dropna(axis=1, how='all') df = heat_pump_dfs[sheet].dropna(axis=1, how='all')
df = df.iloc[3:, 6:35] df = df.iloc[3:, 6:35]

View File

View File

@ -41,7 +41,7 @@ class CityGml:
self._lower_corner = None self._lower_corner = None
self._upper_corner = None self._upper_corner = None
with open(path) as gml: with open(path, 'r', encoding='utf8') as gml:
# Clean the namespaces is an important task to prevent wrong ns:field due poor citygml_classes implementations # Clean the namespaces is an important task to prevent wrong ns:field due poor citygml_classes implementations
force_list = ('cityObjectMember', 'curveMember', 'boundedBy', 'surfaceMember', 'consistsOfBuildingPart') force_list = ('cityObjectMember', 'curveMember', 'boundedBy', 'surfaceMember', 'consistsOfBuildingPart')
self._gml = xmltodict.parse(gml.read(), process_namespaces=True, xml_attribs=True, namespaces={ self._gml = xmltodict.parse(gml.read(), process_namespaces=True, xml_attribs=True, namespaces={
@ -123,7 +123,7 @@ class CityGml:
year_of_construction = city_object[self._year_of_construction_field] year_of_construction = city_object[self._year_of_construction_field]
if self._function_field in city_object: if self._function_field in city_object:
function = city_object[self._function_field] function = city_object[self._function_field]
if type(function) != str: if not isinstance(function, str):
function = function['#text'] function = function['#text']
if self._function_to_hub is not None: if self._function_to_hub is not None:
# use the transformation dictionary to retrieve the proper function # use the transformation dictionary to retrieve the proper function

View File

@ -74,7 +74,7 @@ class CityGmlLod2(CityGmlBase):
gml_points = gml_points_string.lstrip(' ') gml_points = gml_points_string.lstrip(' ')
solid_points = GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(gml_points)) solid_points = GeometryHelper.points_from_string(GeometryHelper.remove_last_point_from_string(gml_points))
polygon = Polygon(solid_points) polygon = Polygon(solid_points)
return Surface(polygon, polygon, surface_type=GeometryHelper.gml_surface_to_libs(surface_type)) return Surface(polygon, polygon, surface_type=GeometryHelper.gml_surface_to_hub(surface_type))
@classmethod @classmethod
def _multi_curve(cls, city_object_member): def _multi_curve(cls, city_object_member):

View File

@ -47,7 +47,7 @@ class Geojson:
self._year_of_construction_field = year_of_construction_field self._year_of_construction_field = year_of_construction_field
self._function_field = function_field self._function_field = function_field
self._function_to_hub = function_to_hub self._function_to_hub = function_to_hub
with open(path) as json_file: with open(path, 'r', encoding='utf8') as json_file:
self._geojson = json.loads(json_file.read()) self._geojson = json.loads(json_file.read())
def _save_bounds(self, x, y): def _save_bounds(self, x, y):
@ -98,8 +98,7 @@ class Geojson:
GeometryHelper.distance_between_points(line[0], neighbour_line[1])) / 2 GeometryHelper.distance_between_points(line[0], neighbour_line[1])) / 2
percentage_ground = line_shared / GeometryHelper.distance_between_points(line[0], line[1]) percentage_ground = line_shared / GeometryHelper.distance_between_points(line[0], line[1])
percentage_height = neighbour_height / building.max_height percentage_height = neighbour_height / building.max_height
if percentage_height > 1: percentage_height = min(percentage_height, 1)
percentage_height = 1
percentage += percentage_ground * percentage_height percentage += percentage_ground * percentage_height
wall.percentage_shared = percentage wall.percentage_shared = percentage
@ -215,40 +214,40 @@ class Geojson:
building.add_alias(alias) building.add_alias(alias)
if extrusion_height == 0: if extrusion_height == 0:
return building return building
else:
volume = 0 volume = 0
for ground in building.grounds: for ground in building.grounds:
volume += ground.solid_polygon.area * extrusion_height volume += ground.solid_polygon.area * extrusion_height
roof_coordinates = [] roof_coordinates = []
# adding a roof means invert the polygon coordinates and change the Z value # adding a roof means invert the polygon coordinates and change the Z value
for coordinate in ground.solid_polygon.coordinates: for coordinate in ground.solid_polygon.coordinates:
roof_coordinate = np.array([coordinate[0], coordinate[1], extrusion_height]) roof_coordinate = np.array([coordinate[0], coordinate[1], extrusion_height])
# insert the roof rotated already # insert the roof rotated already
roof_coordinates.insert(0, roof_coordinate) roof_coordinates.insert(0, roof_coordinate)
roof_polygon = Polygon(roof_coordinates) roof_polygon = Polygon(roof_coordinates)
roof_polygon.area = ground.solid_polygon.area roof_polygon.area = ground.solid_polygon.area
roof = Surface(roof_polygon, roof_polygon) roof = Surface(roof_polygon, roof_polygon)
surfaces.append(roof) surfaces.append(roof)
# adding a wall means add the point coordinates and the next point coordinates with Z's height and 0 # adding a wall means add the point coordinates and the next point coordinates with Z's height and 0
coordinates_length = len(roof.solid_polygon.coordinates) coordinates_length = len(roof.solid_polygon.coordinates)
for i, coordinate in enumerate(roof.solid_polygon.coordinates): for i, coordinate in enumerate(roof.solid_polygon.coordinates):
j = i + 1 j = i + 1
if j == coordinates_length: if j == coordinates_length:
j = 0 j = 0
next_coordinate = roof.solid_polygon.coordinates[j] next_coordinate = roof.solid_polygon.coordinates[j]
wall_coordinates = [ wall_coordinates = [
np.array([coordinate[0], coordinate[1], 0.0]), np.array([coordinate[0], coordinate[1], 0.0]),
np.array([next_coordinate[0], next_coordinate[1], 0.0]), np.array([next_coordinate[0], next_coordinate[1], 0.0]),
np.array([next_coordinate[0], next_coordinate[1], next_coordinate[2]]), np.array([next_coordinate[0], next_coordinate[1], next_coordinate[2]]),
np.array([coordinate[0], coordinate[1], coordinate[2]]) np.array([coordinate[0], coordinate[1], coordinate[2]])
] ]
polygon = Polygon(wall_coordinates) polygon = Polygon(wall_coordinates)
wall = Surface(polygon, polygon) wall = Surface(polygon, polygon)
surfaces.append(wall) surfaces.append(wall)
building = Building(f'{building_name}', surfaces, year_of_construction, function) building = Building(f'{building_name}', surfaces, year_of_construction, function)
for alias in building_aliases: for alias in building_aliases:
building.add_alias(alias) building.add_alias(alias)
building.volume = volume building.volume = volume
return building return building
def _parse_multi_polygon(self, polygons_coordinates, building_name, building_aliases, function, year_of_construction, extrusion_height): def _parse_multi_polygon(self, polygons_coordinates, building_name, building_aliases, function, year_of_construction, extrusion_height):
@ -289,38 +288,38 @@ class Geojson:
building.add_alias(alias) building.add_alias(alias)
if extrusion_height == 0: if extrusion_height == 0:
return building return building
else:
volume = 0 volume = 0
for ground in building.grounds: for ground in building.grounds:
volume += ground.solid_polygon.area * extrusion_height volume += ground.solid_polygon.area * extrusion_height
roof_coordinates = [] roof_coordinates = []
# adding a roof means invert the polygon coordinates and change the Z value # adding a roof means invert the polygon coordinates and change the Z value
for coordinate in ground.solid_polygon.coordinates: for coordinate in ground.solid_polygon.coordinates:
roof_coordinate = np.array([coordinate[0], coordinate[1], extrusion_height]) roof_coordinate = np.array([coordinate[0], coordinate[1], extrusion_height])
# insert the roof rotated already # insert the roof rotated already
roof_coordinates.insert(0, roof_coordinate) roof_coordinates.insert(0, roof_coordinate)
roof_polygon = Polygon(roof_coordinates) roof_polygon = Polygon(roof_coordinates)
roof_polygon.area = ground.solid_polygon.area roof_polygon.area = ground.solid_polygon.area
roof = Surface(roof_polygon, roof_polygon) roof = Surface(roof_polygon, roof_polygon)
surfaces.append(roof) surfaces.append(roof)
# adding a wall means add the point coordinates and the next point coordinates with Z's height and 0 # adding a wall means add the point coordinates and the next point coordinates with Z's height and 0
coordinates_length = len(roof.solid_polygon.coordinates) coordinates_length = len(roof.solid_polygon.coordinates)
for i, coordinate in enumerate(roof.solid_polygon.coordinates): for i, coordinate in enumerate(roof.solid_polygon.coordinates):
j = i + 1 j = i + 1
if j == coordinates_length: if j == coordinates_length:
j = 0 j = 0
next_coordinate = roof.solid_polygon.coordinates[j] next_coordinate = roof.solid_polygon.coordinates[j]
wall_coordinates = [ wall_coordinates = [
np.array([coordinate[0], coordinate[1], 0.0]), np.array([coordinate[0], coordinate[1], 0.0]),
np.array([next_coordinate[0], next_coordinate[1], 0.0]), np.array([next_coordinate[0], next_coordinate[1], 0.0]),
np.array([next_coordinate[0], next_coordinate[1], next_coordinate[2]]), np.array([next_coordinate[0], next_coordinate[1], next_coordinate[2]]),
np.array([coordinate[0], coordinate[1], coordinate[2]]) np.array([coordinate[0], coordinate[1], coordinate[2]])
] ]
polygon = Polygon(wall_coordinates) polygon = Polygon(wall_coordinates)
wall = Surface(polygon, polygon) wall = Surface(polygon, polygon)
surfaces.append(wall) surfaces.append(wall)
building = Building(f'{building_name}', surfaces, year_of_construction, function) building = Building(f'{building_name}', surfaces, year_of_construction, function)
for alias in building_aliases: for alias in building_aliases:
building.add_alias(alias) building.add_alias(alias)
building.volume = volume building.volume = volume
return building return building

View File

@ -58,7 +58,7 @@ class GPandas:
if self._city is None: if self._city is None:
self._city = City(self._lower_corner, self._upper_corner, self._srs_name) self._city = City(self._lower_corner, self._upper_corner, self._srs_name)
lod = 0 lod = 0
for scene_index, bldg in self._scene.iterrows(): for _, bldg in self._scene.iterrows():
polygon = bldg.geometry polygon = bldg.geometry
height = float(bldg['height']) height = float(bldg['height'])
building_mesh = trimesh.creation.extrude_polygon(polygon, height) building_mesh = trimesh.creation.extrude_polygon(polygon, height)
@ -72,7 +72,7 @@ class GPandas:
else: else:
function = cte.INDUSTRY function = cte.INDUSTRY
surfaces = [] surfaces = []
for face_index, face in enumerate(building_mesh.faces): for _, face in enumerate(building_mesh.faces):
points = [] points = []
for vertex_index in face: for vertex_index in face:
points.append(building_mesh.vertices[vertex_index]) points.append(building_mesh.vertices[vertex_index])

View File

View File

@ -8,7 +8,7 @@ import math
import sys import sys
import numpy as np import numpy as np
from numpy import ndarray
class GeometryHelper: class GeometryHelper:
""" """
@ -26,7 +26,7 @@ class GeometryHelper:
return points return points
@staticmethod @staticmethod
def gml_surface_to_libs(surface): def gml_surface_to_hub(surface):
""" """
Transform citygml surface names into hub names Transform citygml surface names into hub names
""" """
@ -38,21 +38,33 @@ class GeometryHelper:
@staticmethod @staticmethod
def points_from_string(coordinates) -> np.ndarray: def points_from_string(coordinates) -> np.ndarray:
"""
Creates a ndarray from a string
:return: [Point]
"""
points = np.fromstring(coordinates, dtype=float, sep=' ') points = np.fromstring(coordinates, dtype=float, sep=' ')
points = GeometryHelper.to_points_matrix(points) points = GeometryHelper.to_points_matrix(points)
return points return points
@staticmethod @staticmethod
def remove_last_point_from_string(points): def remove_last_point_from_string(points) -> [ndarray]:
"""
Return the point list without the last element
:return [ndarray]
"""
array = points.split(' ') array = points.split(' ')
res = " " res = " "
return res.join(array[0:len(array) - 3]) return res.join(array[0:len(array) - 3])
@staticmethod @staticmethod
def invert_points(points): def invert_points(points) -> [ndarray]:
"""
Invert the point list
:return: [ndarray]
"""
res = [] res = []
for point in points: for point in points:
res.insert(0,point) res.insert(0, point)
return res return res
@staticmethod @staticmethod

View File

@ -19,7 +19,7 @@ class Obj:
""" """
def __init__(self, path): def __init__(self, path):
self._city = None self._city = None
with open(path, 'r') as file: with open(path, 'r', encoding='utf8') as file:
self._scene = trimesh.exchange.load.load(file, file_type='obj', force='scene') self._scene = trimesh.exchange.load.load(file, file_type='obj', force='scene')
self._corners = self._scene.bounds_corners self._corners = self._scene.bounds_corners
_bound_corner_min = None _bound_corner_min = None
@ -70,7 +70,6 @@ class Obj:
obj = scene[key] obj = scene[key]
surfaces = [] surfaces = []
for face in obj.faces: for face in obj.faces:
# todo: review for obj with windows
points = [] points = []
for vertex_index in face: for vertex_index in face:
points.append(obj.vertices[vertex_index]) points.append(obj.vertices[vertex_index])

View File

@ -6,8 +6,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.capip
""" """
import numpy as np import numpy as np
from rhino3dm import * from rhino3dm import *
from rhino3dm._rhino3dm import Extrusion from rhino3dm._rhino3dm import Extrusion, MeshType, File3dm
from rhino3dm._rhino3dm import MeshType
from hub.city_model_structure.attributes.point import Point from hub.city_model_structure.attributes.point import Point
from hub.city_model_structure.attributes.polygon import Polygon from hub.city_model_structure.attributes.polygon import Polygon
@ -19,6 +18,9 @@ from hub.imports.geometry.helpers.geometry_helper import GeometryHelper
class Rhino: class Rhino:
"""
Rhino class
"""
def __init__(self, path): def __init__(self, path):
self._model = File3dm.Read(str(path)) self._model = File3dm.Read(str(path))
max_float = float(ConfigurationHelper().max_coordinate) max_float = float(ConfigurationHelper().max_coordinate)
@ -85,6 +87,10 @@ class Rhino:
@property @property
def city(self) -> City: def city(self) -> City:
"""
Return a city based in the rhino file
:return: City
"""
buildings = [] buildings = []
city_objects = [] # building and "windows" city_objects = [] # building and "windows"
windows = [] windows = []

View File

@ -95,3 +95,12 @@ class GeometryFactory:
:return: City :return: City
""" """
return getattr(self, self._file_type, lambda: None) return getattr(self, self._file_type, lambda: None)
@property
def city_debug(self) -> City:
"""
Enrich the city given to the class using the class given handler
:return: City
"""
print('rhino')
return Rhino(self._path).city

View File

View File

@ -21,12 +21,15 @@ class InselHeatPumpEnergyDemand:
""" """
self._city = city self._city = city
self._hp_model = hp_model self._hp_model = hp_model
with open(Path(base_path).resolve()) as csv_file: with open(Path(base_path).resolve(), 'r', encoding='utf8') as csv_file:
df = pd.read_csv(csv_file) df = pd.read_csv(csv_file)
self._monthly_electricity_demand = df.iloc[:, 1] self._monthly_electricity_demand = df.iloc[:, 1]
self._monthly_fossil_fuel_consumption = df.iloc[:, 2] self._monthly_fossil_fuel_consumption = df.iloc[:, 2]
def enrich(self): def enrich(self):
"""
Enrich the city with the heat pump information
"""
for energy_system in self._city.energy_systems: for energy_system in self._city.energy_systems:
if energy_system.air_source_hp is not None: if energy_system.air_source_hp is not None:
if energy_system.air_source_hp.model == self._hp_model: if energy_system.air_source_hp.model == self._hp_model:
@ -35,4 +38,3 @@ class InselHeatPumpEnergyDemand:
if energy_system.water_to_water_hp is not None: if energy_system.water_to_water_hp is not None:
if energy_system.water_to_water_hp.model == self._hp_model: if energy_system.water_to_water_hp.model == self._hp_model:
energy_system.water_to_water_hp.hp_monthly_electricity_demand = self._monthly_electricity_demand energy_system.water_to_water_hp.hp_monthly_electricity_demand = self._monthly_electricity_demand

View File

@ -5,8 +5,9 @@ Copyright © 2022 Concordia CERC group
Project Coder Guillermo.GutierrezMorote@concordia.ca Project Coder Guillermo.GutierrezMorote@concordia.ca
""" """
from pathlib import Path from pathlib import Path
import pandas as pd
import csv import csv
import pandas as pd
import hub.helpers.constants as cte import hub.helpers.constants as cte
@ -23,7 +24,7 @@ class InselMonthlyEnergyBalance:
def _conditioning_demand(insel_output_file_path): def _conditioning_demand(insel_output_file_path):
heating = [] heating = []
cooling = [] cooling = []
with open(Path(insel_output_file_path).resolve()) as csv_file: with open(Path(insel_output_file_path).resolve(), 'r', encoding='utf8') as csv_file:
csv_reader = csv.reader(csv_file) csv_reader = csv.reader(csv_file)
for line in csv_reader: for line in csv_reader:
demand = str(line).replace("['", '').replace("']", '').split() demand = str(line).replace("['", '').replace("']", '').split()
@ -108,6 +109,10 @@ class InselMonthlyEnergyBalance:
) )
def enrich(self): def enrich(self):
"""
Enrich the city by using the insel monthly energy balance output files
:return: None
"""
for building in self._city.buildings: for building in self._city.buildings:
file_name = building.name + '.out' file_name = building.name + '.out'
insel_output_file_path = Path(self._base_path / file_name).resolve() insel_output_file_path = Path(self._base_path / file_name).resolve()

View File

@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Guillermo.GutierrezMorote@concordia.ca Project Coder Guillermo.GutierrezMorote@concordia.ca
""" """
import calendar as cal
import pandas as pd import pandas as pd
import numpy as np import numpy as np
import calendar as cal
import hub.helpers.constants as cte import hub.helpers.constants as cte
@ -18,7 +18,7 @@ class SimplifiedRadiosityAlgorithm:
self._city = city self._city = city
self._base_path = base_path self._base_path = base_path
self._input_file_path = (self._base_path / f'{self._city.name}_sra_SW.out') self._input_file_path = (self._base_path / f'{self._city.name}_sra_SW.out').resolve()
self._month_hour = self._month_hour_data_frame self._month_hour = self._month_hour_data_frame
self._results = self._read_results() self._results = self._read_results()
self._radiation_list = [] self._radiation_list = []
@ -48,8 +48,8 @@ class SimplifiedRadiosityAlgorithm:
def _read_results(self): def _read_results(self):
try: try:
return pd.read_csv(self._input_file_path, sep='\s+', header=0) return pd.read_csv(self._input_file_path, sep='\s+', header=0)
except Exception: except FileNotFoundError as err:
raise Exception('No SRA output file found') raise FileNotFoundError('No SRA output file found') from err
@property @property
def _radiation(self) -> []: def _radiation(self) -> []:

View File

View File

@ -5,9 +5,8 @@ Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import copy import copy
import numpy
import logging import logging
import numpy
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.city_model_structure.building_demand.usage import Usage from hub.city_model_structure.building_demand.usage import Usage
@ -40,16 +39,16 @@ class ComnetUsageParameters:
try: try:
archetype_usage = self._search_archetypes(comnet_catalog, usage_name) archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
except KeyError: except KeyError:
logging.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}') logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name)
continue continue
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
if internal_zone.area is None: if internal_zone.area is None:
raise Exception('Internal zone area not defined, ACH cannot be calculated') raise TypeError('Internal zone area not defined, ACH cannot be calculated')
if internal_zone.volume is None: if internal_zone.volume is None:
raise Exception('Internal zone volume not defined, ACH cannot be calculated') raise TypeError('Internal zone volume not defined, ACH cannot be calculated')
if internal_zone.area <= 0: if internal_zone.area <= 0:
raise Exception('Internal zone area is zero, ACH cannot be calculated') raise TypeError('Internal zone area is zero, ACH cannot be calculated')
volume_per_area = internal_zone.volume / internal_zone.area volume_per_area = internal_zone.volume / internal_zone.area
usage = Usage() usage = Usage()
usage.name = usage_name usage.name = usage_name
@ -160,7 +159,7 @@ class ComnetUsageParameters:
@staticmethod @staticmethod
def _calculate_internal_gains(archetype): def _calculate_internal_gains(archetype):
_DAYS = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY] _days = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY]
_number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10] _number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10]
_mean_internal_gain = InternalGain() _mean_internal_gain = InternalGain()
@ -174,13 +173,13 @@ class ComnetUsageParameters:
_latent_heat_gain = archetype.occupancy.latent_internal_gain _latent_heat_gain = archetype.occupancy.latent_internal_gain
_convective_heat_gain = archetype.occupancy.sensible_convective_internal_gain _convective_heat_gain = archetype.occupancy.sensible_convective_internal_gain
_radiative_heat_gain = archetype.occupancy.sensible_radiative_internal_gain _radiative_heat_gain = archetype.occupancy.sensible_radiative_internal_gain
_total_heat_gain = (_latent_heat_gain + _convective_heat_gain + _radiative_heat_gain) _total_heat_gain = _latent_heat_gain + _convective_heat_gain + _radiative_heat_gain
_schedule_values = numpy.zeros([24, 8]) _schedule_values = numpy.zeros([24, 8])
_sum = 0 _sum = 0
for day, _schedule in enumerate(archetype.occupancy.schedules): for day, _schedule in enumerate(archetype.occupancy.schedules):
for v, value in enumerate(_schedule.values): for v_index, value in enumerate(_schedule.values):
_schedule_values[v, day] = value * _total_heat_gain _schedule_values[v_index, day] = value * _total_heat_gain
_sum += value * _total_heat_gain * _number_of_days_per_type[day] _sum += value * _total_heat_gain * _number_of_days_per_type[day]
_total_heat_gain += archetype.lighting.density + archetype.appliances.density _total_heat_gain += archetype.lighting.density + archetype.appliances.density
@ -198,13 +197,13 @@ class ComnetUsageParameters:
) )
for day, _schedule in enumerate(archetype.lighting.schedules): for day, _schedule in enumerate(archetype.lighting.schedules):
for v, value in enumerate(_schedule.values): for v_index, value in enumerate(_schedule.values):
_schedule_values[v, day] += value * archetype.lighting.density _schedule_values[v_index, day] += value * archetype.lighting.density
_sum += value * archetype.lighting.density * _number_of_days_per_type[day] _sum += value * archetype.lighting.density * _number_of_days_per_type[day]
for day, _schedule in enumerate(archetype.appliances.schedules): for day, _schedule in enumerate(archetype.appliances.schedules):
for v, value in enumerate(_schedule.values): for v_index, value in enumerate(_schedule.values):
_schedule_values[v, day] += value * archetype.appliances.density _schedule_values[v_index, day] += value * archetype.appliances.density
_sum += value * archetype.appliances.density * _number_of_days_per_type[day] _sum += value * archetype.appliances.density * _number_of_days_per_type[day]
_latent_fraction = 0 _latent_fraction = 0
@ -218,9 +217,9 @@ class ComnetUsageParameters:
_average_internal_gain = _sum / _total_heat_gain _average_internal_gain = _sum / _total_heat_gain
_schedules = [] _schedules = []
for day in range(0, len(_DAYS)): for day, current_day in enumerate(_days):
_schedule = copy.deepcopy(_base_schedule) _schedule = copy.deepcopy(_base_schedule)
_schedule.day_types = [_DAYS[day]] _schedule.day_types = [current_day]
_schedule.values = _schedule_values[:day] _schedule.values = _schedule_values[:day]
_schedules.append(_schedule) _schedules.append(_schedule)

View File

@ -39,36 +39,36 @@ class NrcanUsageParameters:
try: try:
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name) archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
except KeyError: except KeyError:
logging.error(f'Building {building.name} has unknown usage archetype for usage: {usage_name}\n') logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name)
continue continue
comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function] comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function]
try: try:
comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name) comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name)
except KeyError: except KeyError:
logging.error(f'Building {building.name} has unknown usage archetype for usage: {comnet_usage_name}\n') logging.error('Building %s has unknown usage archetype for usage %s', building.name, comnet_usage_name)
continue continue
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
if len(building.internal_zones) > 1: if len(building.internal_zones) > 1:
volume_per_area = 0 volume_per_area = 0
if internal_zone.area is None: if internal_zone.area is None:
logging.error(f'Building {building.name} has internal zone area not defined, ' logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s',
f'ACH cannot be calculated for usage: {usage_name}\n') building.name, usage_name)
continue continue
if internal_zone.volume is None: if internal_zone.volume is None:
logging.error(f'Building {building.name} has internal zone volume not defined, ' logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s',
f'ACH cannot be calculated for usage: {usage_name}\n') building.name, usage_name)
continue continue
if internal_zone.area <= 0: if internal_zone.area <= 0:
logging.error(f'Building {building.name} has internal zone area equal to 0, ' logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s',
f'ACH cannot be calculated for usage: {usage_name}\n') building.name, usage_name)
continue continue
volume_per_area += internal_zone.volume / internal_zone.area volume_per_area += internal_zone.volume / internal_zone.area
else: else:
if building.storeys_above_ground is None: if building.storeys_above_ground is None:
logging.error(f'Building {building.name} no number of storeys assigned, ' logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for usage %s',
f'ACH cannot be calculated for usage: {usage_name}\n') building.name, usage_name)
continue continue
volume_per_area = building.volume / building.floor_area / building.storeys_above_ground volume_per_area = building.volume / building.floor_area / building.storeys_above_ground

View File

View File

@ -22,27 +22,26 @@ class EpwWeatherParameters:
self._path = Path(path / file_name) self._path = Path(path / file_name)
try: try:
file = open(self._path, 'r') with open(self._path, 'r', encoding='utf8') as file:
line = file.readline().split(',') line = file.readline().split(',')
city.climate_reference_city = line[1] city.climate_reference_city = line[1]
city.latitude = line[6] city.latitude = line[6]
city.longitude = line[7] city.longitude = line[7]
city.time_zone = line[8] city.time_zone = line[8]
for i in range(0, 2): for i in range(0, 2):
_ = file.readline().split(',') _ = file.readline().split(',')
line = file.readline().split(',') line = file.readline().split(',')
number_records = int(line[1]) number_records = int(line[1])
ground_temperature = {} ground_temperature = {}
for i in range(0, number_records): for i in range(0, number_records):
depth_measurement_ground_temperature = line[i*16+2] depth_measurement_ground_temperature = line[i*16+2]
temperatures = [] temperatures = []
for j in range(0, 12): for j in range(0, 12):
temperatures.append(float(line[i*16+j+6])) temperatures.append(float(line[i*16+j+6]))
ground_temperature[depth_measurement_ground_temperature] = temperatures ground_temperature[depth_measurement_ground_temperature] = temperatures
file.close()
except SystemExit: except SystemExit:
logging.error(f'Error: weather file {self._path} not found. Please download it from ' logging.error('Error: weather file %s not found. Please download it from https://energyplus.net/weather and place'
f'https://energyplus.net/weather and place it in folder data\\weather\\epw\n') ' it in folder data\\weather\\epw', self._path)
sys.exit() sys.exit()
try: try:

View File

View File

@ -6,10 +6,10 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import math import math
import hub.helpers.constants as cte
import pandas as pd
import calendar as cal import calendar as cal
import pandas as pd
import numpy as np import numpy as np
import hub.helpers.constants as cte
class Weather: class Weather:
@ -65,6 +65,10 @@ class Weather:
return pd.DataFrame(cold_temperature, columns=['epw']) return pd.DataFrame(cold_temperature, columns=['epw'])
def get_monthly_mean_values(self, values): def get_monthly_mean_values(self, values):
"""
Get the monthly mean for the given values
:return: float
"""
out = None out = None
if values is not None: if values is not None:
if 'month' not in values.columns: if 'month' not in values.columns:
@ -75,9 +79,17 @@ class Weather:
@staticmethod @staticmethod
def get_yearly_mean_values(values): def get_yearly_mean_values(values):
"""
Get the yearly mean for the given values
:return: float
"""
return values.mean() return values.mean()
def get_total_month(self, values): def get_total_month(self, values):
"""
Get the total value the given values
:return: float
"""
out = None out = None
if values is not None: if values is not None:
if 'month' not in values.columns: if 'month' not in values.columns:

View File

@ -1,3 +0,0 @@
"""
Persistence package
"""

184
setup.py
View File

@ -16,97 +16,103 @@ install_requires.append('setuptools')
main_ns = {} main_ns = {}
version = convert_path('hub/version.py') version = convert_path('hub/version.py')
with open(version) as f: with open(version) as f:
exec(f.read(), main_ns) exec(f.read(), main_ns)
setup( setup(
name='cerc-hub', name='cerc-hub',
version=main_ns['__version__'], version=main_ns['__version__'],
description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers " description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers "
"to create better and sustainable cities", "to create better and sustainable cities",
long_description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help " long_description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help "
"researchers to create better and sustainable cities.\n\nDevelop at Concordia university in canada " "researchers to create better and sustainable cities.\n\nDevelop at Concordia university in canada "
"as part of the research group from the next generation cities institute our aim among others it's " "as part of the research group from the next generation cities institute our aim among others it's "
"to provide a comprehensive set of tools to help researchers and urban developers to make decisions " "to provide a comprehensive set of tools to help researchers and urban developers to make decisions "
"to improve the livability and efficiency of our cities", "to improve the livability and efficiency of our cities",
classifiers=[ classifiers=[
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python", "Programming Language :: Python",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
], ],
include_package_data=True, include_package_data=True,
packages=['hub', packages=['hub',
'hub.catalog_factories', 'hub.catalog_factories',
'hub.catalog_factories.construction', 'hub.catalog_factories.construction',
'hub.catalog_factories.data_models', 'hub.catalog_factories.cost',
'hub.catalog_factories.data_models.construction', 'hub.catalog_factories.data_models',
'hub.catalog_factories.data_models.greenery', 'hub.catalog_factories.data_models.construction',
'hub.catalog_factories.data_models.usages', 'hub.catalog_factories.data_models.cost',
'hub.catalog_factories.greenery', 'hub.catalog_factories.data_models.energy_systems',
'hub.catalog_factories.greenery.ecore_greenery', 'hub.catalog_factories.data_models.greenery',
'hub.catalog_factories.usage', 'hub.catalog_factories.data_models.usages',
'hub.city_model_structure', 'hub.catalog_factories.energy_systems',
'hub.city_model_structure.attributes', 'hub.catalog_factories.greenery',
'hub.city_model_structure.building_demand', 'hub.catalog_factories.greenery.ecore_greenery',
'hub.city_model_structure.energy_systems', 'hub.catalog_factories.usage',
'hub.city_model_structure.greenery', 'hub.city_model_structure',
'hub.city_model_structure.iot', 'hub.city_model_structure.attributes',
'hub.city_model_structure.transport', 'hub.city_model_structure.building_demand',
'hub.config', 'hub.city_model_structure.energy_systems',
'hub.data', 'hub.city_model_structure.greenery',
'hub.exports', 'hub.city_model_structure.iot',
'hub.exports.building_energy', 'hub.city_model_structure.transport',
'hub.exports.building_energy.idf_files', 'hub.config',
'hub.exports.building_energy.insel', 'hub.data',
'hub.exports.energy_systems', 'hub.exports',
'hub.exports.formats', 'hub.exports.building_energy',
'hub.helpers', 'hub.exports.building_energy.idf_files',
'hub.helpers.peak_calculation', 'hub.exports.building_energy.insel',
'hub.helpers.data', 'hub.exports.energy_systems',
'hub.imports', 'hub.exports.formats',
'hub.imports.construction', 'hub.helpers',
'hub.imports.construction.helpers', 'hub.helpers.peak_calculation',
'hub.imports.energy_systems', 'hub.helpers.data',
'hub.imports.geometry', 'hub.imports',
'hub.imports.geometry.citygml_classes', 'hub.imports.construction',
'hub.imports.geometry.helpers', 'hub.imports.construction.helpers',
'hub.imports.results', 'hub.imports.energy_systems',
'hub.imports.usage', 'hub.imports.geometry',
'hub.imports.weather', 'hub.imports.geometry.citygml_classes',
'hub.imports.weather.helpers', 'hub.imports.geometry.helpers',
'hub.persistence', 'hub.imports.results',
'hub.persistence.models', 'hub.imports.usage',
'hub.persistence.repositories', 'hub.imports.weather',
'hub.imports' 'hub.imports.weather.helpers',
], 'hub.persistence',
setup_requires=install_requires, 'hub.persistence.models',
install_requires=install_requires, 'hub.persistence.repositories',
data_files=[ 'hub.imports'
('hub', glob.glob('requirements.txt')), ],
('hub/config', glob.glob('hub/config/*.ini')), setup_requires=install_requires,
('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')), install_requires=install_requires,
('hub/data/construction.', glob.glob('hub/data/construction/*')), data_files=[
('hub/data/customized_imports', glob.glob('hub/data/customized_imports/*.xml')), ('hub', glob.glob('requirements.txt')),
('data/geolocation', glob.glob('hub/data/geolocation/*.txt')), ('hub/config', glob.glob('hub/config/*.ini')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xml')), ('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.insel')), ('hub/data/construction.', glob.glob('hub/data/construction/*')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xlsx')), ('hub/data/customized_imports', glob.glob('hub/data/customized_imports/*.xml')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.txt')), ('data/geolocation', glob.glob('hub/data/geolocation/*.txt')),
('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.yaml')), ('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xml')),
('hub/data/greenery', glob.glob('hub/data/greenery/*.xml')), ('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.insel')),
('hub/data/life_cycle_assessment', glob.glob('hub/data/life_cycle_assessment/*.xml')), ('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.xlsx')),
('hub/data/schedules', glob.glob('hub/data/schedules/*.xml')), ('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.txt')),
('hub/data/schedules', glob.glob('hub/data/schedules/*.xlsx')), ('hub/data/energy_systems', glob.glob('hub/data/energy_systems/*.yaml')),
('hub/data/schedules/idf_files', glob.glob('hub/data/schedules/idf_files/*.idf')), ('hub/data/greenery', glob.glob('hub/data/greenery/*.xml')),
('hub/data/sensors', glob.glob('hub/data/sensors/*.json')), ('hub/data/life_cycle_assessment', glob.glob('hub/data/life_cycle_assessment/*.xml')),
('hub/data/usage', glob.glob('hub/data/usage/*.xml')), ('hub/data/schedules', glob.glob('hub/data/schedules/*.xml')),
('hub/data/usage', glob.glob('hub/data/usage/*.xlsx')), ('hub/data/schedules', glob.glob('hub/data/schedules/*.xlsx')),
('hub/data/weather', glob.glob('hub/data/weather/*.dat')), ('hub/data/schedules/idf_files', glob.glob('hub/data/schedules/idf_files/*.idf')),
('hub/data/weather/epw', glob.glob('hub/data/weather/epw/*.epw')), ('hub/data/sensors', glob.glob('hub/data/sensors/*.json')),
('hub/data/weather', glob.glob('hub/data/weather/*.dat')), ('hub/data/usage', glob.glob('hub/data/usage/*.xml')),
('hub/exports/building_energy/idf_files', glob.glob('hub/exports/building_energy/idf_files/*.idf')), ('hub/data/usage', glob.glob('hub/data/usage/*.xlsx')),
('hub/exports/building_energy/idf_files', glob.glob('hub/exports/building_energy/idf_files/*.idd')), ('hub/data/weather', glob.glob('hub/data/weather/*.dat')),
('hub/helpers/data', glob.glob('hub/helpers/data/quebec_to_hub.json')) ('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'))
],
) )

View File

@ -72,7 +72,7 @@ class Control:
city_file = "tests_data/FZK_Haus_LoD_2.gml" city_file = "tests_data/FZK_Haus_LoD_2.gml"
weather_file = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw' weather_file = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw'
output_path = Path('./tests_outputs/').resolve() output_path = Path('tests_outputs/').resolve()
self._city = GeometryFactory('citygml', self._city = GeometryFactory('citygml',
city_file, city_file,
function_to_hub=Dictionaries().alkis_function_to_hub_function).city function_to_hub=Dictionaries().alkis_function_to_hub_function).city

Some files were not shown because too many files have changed in this diff Show More