Compare commits

..

No commits in common. "ab81edc33d07fd6c6d404137b27de98c6643dca7" and "7cf926bc5b42de36780751ebf7714b86acf55b0c" have entirely different histories.

68 changed files with 2478 additions and 948 deletions

View File

@ -15,7 +15,6 @@ from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.data_models.construction.window import Window
from hub.catalog_factories.data_models.construction.material import Material
from hub.catalog_factories.data_models.construction.layer import Layer
import hub.helpers.constants as cte
class EilatCatalog(Catalog):
@ -121,8 +120,8 @@ class EilatCatalog(Catalog):
construction_period = archetype['period_of_construction']
average_storey_height = archetype['average_storey_height']
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges']
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off'] / cte.HOUR_TO_SECONDS
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on'] / cte.HOUR_TO_SECONDS
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off']
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on']
archetype_constructions = []
for archetype_construction in archetype['constructions']:

View File

@ -15,7 +15,6 @@ from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.data_models.construction.window import Window
from hub.catalog_factories.data_models.construction.material import Material
from hub.catalog_factories.data_models.construction.layer import Layer
import hub.helpers.constants as cte
class NrcanCatalog(Catalog):
@ -122,8 +121,8 @@ class NrcanCatalog(Catalog):
average_storey_height = archetype['average_storey_height']
thermal_capacity = float(archetype['thermal_capacity']) * 1000
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges']
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off'] / cte.HOUR_TO_SECONDS
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on'] / cte.HOUR_TO_SECONDS
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off']
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on']
archetype_constructions = []
for archetype_construction in archetype['constructions']:

View File

@ -15,7 +15,6 @@ from hub.catalog_factories.data_models.construction.construction import Construc
from hub.catalog_factories.data_models.construction.content import Content
from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
import hub.helpers.constants as cte
class NrelCatalog(Catalog):
@ -125,10 +124,10 @@ class NrelCatalog(Catalog):
indirect_heated_ratio = float(archetype['indirect_heated_ratio']['#text'])
infiltration_rate_for_ventilation_system_off = float(
archetype['infiltration_rate_for_ventilation_system_off']['#text']
) / cte.HOUR_TO_SECONDS
)
infiltration_rate_for_ventilation_system_on = float(
archetype['infiltration_rate_for_ventilation_system_on']['#text']
) / cte.HOUR_TO_SECONDS
)
archetype_constructions = []
for archetype_construction in archetype['constructions']['construction']:

View File

@ -120,7 +120,7 @@ class Archetype:
@property
def infiltration_rate_for_ventilation_system_off(self):
"""
Get archetype infiltration rate for ventilation system off in 1/s
Get archetype infiltration rate for ventilation system off in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_off
@ -128,7 +128,7 @@ class Archetype:
@property
def infiltration_rate_for_ventilation_system_on(self):
"""
Get archetype infiltration rate for ventilation system on in 1/s
Get archetype infiltration rate for ventilation system on in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_on
@ -147,8 +147,8 @@ class Archetype:
'thermal capacity [J/m3K]': self.thermal_capacity,
'extra loses due to thermal bridges [W/m2K]': self.extra_loses_due_to_thermal_bridges,
'indirect heated ratio': self.indirect_heated_ratio,
'infiltration rate for ventilation off [1/s]': self.infiltration_rate_for_ventilation_system_off,
'infiltration rate for ventilation on [1/s]': self.infiltration_rate_for_ventilation_system_on,
'infiltration rate for ventilation off [ACH]': self.infiltration_rate_for_ventilation_system_off,
'infiltration rate for ventilation on [ACH]': self.infiltration_rate_for_ventilation_system_on,
'constructions': _constructions
}
}

View File

@ -27,7 +27,7 @@ class Income:
@property
def construction_subsidy(self) -> Union[None, float]:
"""
Get subsidy for construction in percentage %
Get subsidy for construction in percentage
:return: None or float
"""
return self._construction_subsidy
@ -35,7 +35,7 @@ class Income:
@property
def hvac_subsidy(self) -> Union[None, float]:
"""
Get subsidy for HVAC system in percentage %
Get subsidy for HVAC system in percentage
:return: None or float
"""
return self._hvac_subsidy

View File

@ -24,7 +24,7 @@ class Appliances:
@property
def density(self) -> Union[None, float]:
"""
Get appliances density in W/m2
Get appliances density in Watts per m2
:return: None or float
"""
return self._density

View File

@ -65,7 +65,7 @@ class Usage:
@property
def mechanical_air_change(self) -> Union[None, float]:
"""
Get usage zone mechanical air change in air change per second (1/s)
Get usage zone mechanical air change in air change per hour (ACH)
:return: None or float
"""
return self._mechanical_air_change

View File

@ -134,8 +134,8 @@ class NrcanCatalog(Catalog):
hvac_availability = self._get_schedules(hvac_schedule_name)
domestic_hot_water_load_schedule = self._get_schedules(domestic_hot_water_schedule_name)
# ACH -> 1/s
mechanical_air_change = space_type['ventilation_air_changes'] / cte.HOUR_TO_SECONDS
# ACH
mechanical_air_change = space_type['ventilation_air_changes']
# cfm/ft2 to m3/m2.s
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
# cfm/person to m3/m2.s

View File

@ -41,7 +41,7 @@ class Building(CityObject):
self._floor_area = None
self._roof_type = None
self._internal_zones = None
self._thermal_zones_from_internal_zones = None
self._thermal_zones = None
self._shell = None
self._aliases = []
self._type = 'building'
@ -114,24 +114,26 @@ class Building(CityObject):
:return: [InternalZone]
"""
if self._internal_zones is None:
_number_of_storeys = self.eave_height * self.volume / self.floor_area
self._internal_zones = [InternalZone(self.surfaces, self.floor_area, self.volume, _number_of_storeys)]
self._internal_zones = [InternalZone(self.surfaces, self.floor_area)]
return self._internal_zones
@property
def thermal_zones_from_internal_zones(self) -> Union[None, List[ThermalZone]]:
def thermal_zones(self) -> Union[None, List[ThermalZone]]:
"""
Get building thermal zones
For Lod up to 3, there can be more than one thermal zone per internal zone.
In LoD 4, there can be more than one internal zone, and therefore, only one thermal zone per internal zone
:return: [ThermalZone]
"""
if self._thermal_zones_from_internal_zones is None:
self._thermal_zones_from_internal_zones = []
if self._thermal_zones is None:
self._thermal_zones = []
for internal_zone in self.internal_zones:
if internal_zone.thermal_zones_from_internal_zones is None:
self._thermal_zones_from_internal_zones = None
return self._thermal_zones_from_internal_zones
self._thermal_zones_from_internal_zones.append(internal_zone.thermal_zones_from_internal_zones[0])
return self._thermal_zones_from_internal_zones
if internal_zone.thermal_zones is None:
self._thermal_zones = None
return self._thermal_zones
for thermal_zone in internal_zone.thermal_zones:
self._thermal_zones.append(thermal_zone)
return self._thermal_zones
@property
def grounds(self) -> List[Surface]:
@ -259,15 +261,6 @@ class Building(CityObject):
Get building average storey height in meters
:return: None or float
"""
if len(self.internal_zones) > 1:
self._average_storey_height = 0
for internal_zone in self.internal_zones:
self._average_storey_height += internal_zone.mean_height / len(self.internal_zones)
else:
if self.internal_zones[0].thermal_archetype is None:
self._average_storey_height = None
else:
self._average_storey_height = self.internal_zones[0].thermal_archetype.average_storey_height
return self._average_storey_height
@average_storey_height.setter
@ -318,7 +311,7 @@ class Building(CityObject):
@property
def heating_demand(self) -> dict:
"""
Get heating demand in J
Get heating demand in Wh
:return: dict{[float]}
"""
return self._heating_demand
@ -326,7 +319,7 @@ class Building(CityObject):
@heating_demand.setter
def heating_demand(self, value):
"""
Set heating demand in J
Set heating demand in Wh
:param value: dict{[float]}
"""
self._heating_demand = value
@ -334,7 +327,7 @@ class Building(CityObject):
@property
def cooling_demand(self) -> dict:
"""
Get cooling demand in J
Get cooling demand in Wh
:return: dict{[float]}
"""
return self._cooling_demand
@ -342,7 +335,7 @@ class Building(CityObject):
@cooling_demand.setter
def cooling_demand(self, value):
"""
Set cooling demand in J
Set cooling demand in Wh
:param value: dict{[float]}
"""
self._cooling_demand = value
@ -350,7 +343,7 @@ class Building(CityObject):
@property
def lighting_electrical_demand(self) -> dict:
"""
Get lighting electrical demand in J
Get lighting electrical demand in Wh
:return: dict{[float]}
"""
return self._lighting_electrical_demand
@ -358,7 +351,7 @@ class Building(CityObject):
@lighting_electrical_demand.setter
def lighting_electrical_demand(self, value):
"""
Set lighting electrical demand in J
Set lighting electrical demand in Wh
:param value: dict{[float]}
"""
self._lighting_electrical_demand = value
@ -366,7 +359,7 @@ class Building(CityObject):
@property
def appliances_electrical_demand(self) -> dict:
"""
Get appliances electrical demand in J
Get appliances electrical demand in Wh
:return: dict{[float]}
"""
return self._appliances_electrical_demand
@ -374,7 +367,7 @@ class Building(CityObject):
@appliances_electrical_demand.setter
def appliances_electrical_demand(self, value):
"""
Set appliances electrical demand in J
Set appliances electrical demand in Wh
:param value: dict{[float]}
"""
self._appliances_electrical_demand = value
@ -382,7 +375,7 @@ class Building(CityObject):
@property
def domestic_hot_water_heat_demand(self) -> dict:
"""
Get domestic hot water heat demand in J
Get domestic hot water heat demand in Wh
:return: dict{[float]}
"""
return self._domestic_hot_water_heat_demand
@ -390,7 +383,7 @@ class Building(CityObject):
@domestic_hot_water_heat_demand.setter
def domestic_hot_water_heat_demand(self, value):
"""
Set domestic hot water heat demand in J
Set domestic hot water heat demand in Wh
:param value: dict{[float]}
"""
self._domestic_hot_water_heat_demand = value
@ -403,8 +396,7 @@ class Building(CityObject):
"""
results = {}
peak_lighting = 0
peak = 0
for thermal_zone in self.thermal_zones_from_internal_zones:
for thermal_zone in self.thermal_zones:
lighting = thermal_zone.lighting
for schedule in lighting.schedules:
peak = max(schedule.values) * lighting.density * thermal_zone.total_floor_area
@ -422,8 +414,7 @@ class Building(CityObject):
"""
results = {}
peak_appliances = 0
peak = 0
for thermal_zone in self.thermal_zones_from_internal_zones:
for thermal_zone in self.thermal_zones:
appliances = thermal_zone.appliances
for schedule in appliances.schedules:
peak = max(schedule.values) * appliances.density * thermal_zone.total_floor_area
@ -447,8 +438,7 @@ class Building(CityObject):
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
if monthly_values is None:
return None
# todo: @Pilar!!!!
results[cte.MONTH] = monthly_values * cte.WATTS_HOUR_TO_JULES
results[cte.MONTH] = monthly_values
results[cte.YEAR] = [max(monthly_values)]
return results
@ -465,8 +455,7 @@ class Building(CityObject):
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
if monthly_values is None:
return None
# todo: @Pilar!!!!
results[cte.MONTH] = monthly_values * cte.WATTS_HOUR_TO_JULES
results[cte.MONTH] = monthly_values
results[cte.YEAR] = [max(monthly_values)]
return results
@ -620,7 +609,7 @@ class Building(CityObject):
@property
def heating_consumption(self):
"""
Get energy consumption for heating according to the heating system installed in J
Get energy consumption for heating according to the heating system installed in Wh
return: dict
"""
if len(self._heating_consumption) == 0:
@ -636,7 +625,7 @@ class Building(CityObject):
@property
def cooling_consumption(self):
"""
Get energy consumption for cooling according to the cooling system installed in J
Get energy consumption for cooling according to the cooling system installed in Wh
return: dict
"""
if len(self._cooling_consumption) == 0:
@ -652,7 +641,7 @@ class Building(CityObject):
@property
def domestic_hot_water_consumption(self):
"""
Get energy consumption for domestic according to the domestic hot water system installed in J
Get energy consumption for domestic according to the domestic hot water system installed in Wh
return: dict
"""
if len(self._domestic_hot_water_consumption) == 0:
@ -668,7 +657,7 @@ class Building(CityObject):
def _calculate_working_hours(self):
_working_hours = {}
for internal_zone in self.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
_working_hours_per_thermal_zone = {}
for schedule in thermal_zone.thermal_control.hvac_availability_schedules:
_working_hours_per_schedule = [0] * len(schedule.values)
@ -694,7 +683,7 @@ class Building(CityObject):
@property
def distribution_systems_electrical_consumption(self):
"""
Get total electricity consumption for distribution and emission systems in J
Get total electricity consumption for distribution and emission systems in Wh
return: dict
"""
if len(self._distribution_systems_electrical_consumption) != 0:
@ -769,7 +758,7 @@ class Building(CityObject):
@property
def onsite_electrical_production(self):
"""
Get total electricity produced onsite in J
Get total electricity produced onsite in Wh
return: dict
"""

View File

@ -1,134 +0,0 @@
"""
Construction thermal parameters
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.city_model_structure.building_demand.layer import Layer
class Construction:
"""
Construction class
"""
def __init__(self):
self._type = None
self._layers = None
self._window_ratio = None
self._window_frame_ratio = None
self._window_g_value = None
self._window_overall_u_value = None
self._window_type = None
@property
def type(self):
"""
Get construction type
:return: str
"""
return self._type
@type.setter
def type(self, value):
"""
Set construction type
:param value: str
"""
self._type = value
@property
def layers(self) -> [Layer]:
"""
Get layers
:return: [layer]
"""
return self._layers
@layers.setter
def layers(self, value):
"""
Set layers
:param value: [layer]
"""
self._layers = value
@property
def window_ratio(self):
"""
Get window ratio
:return: dict
"""
return self._window_ratio
@window_ratio.setter
def window_ratio(self, value):
"""
Set window ratio
:param value: dict
"""
self._window_ratio = value
@property
def window_frame_ratio(self):
"""
Get window frame ratio
:return: float
"""
return self._window_frame_ratio
@window_frame_ratio.setter
def window_frame_ratio(self, value):
"""
Set window frame ratio
:param value: float
"""
self._window_frame_ratio = value
@property
def window_g_value(self):
"""
Get transparent surface g-value
:return: float
"""
return self._window_g_value
@window_g_value.setter
def window_g_value(self, value):
"""
Set transparent surface g-value
:param value: float
"""
self._window_g_value = value
@property
def window_overall_u_value(self):
"""
Get transparent surface overall U-value in W/m2K
:return: float
"""
return self._window_overall_u_value
@window_overall_u_value.setter
def window_overall_u_value(self, value):
"""
Set transparent surface overall U-value in W/m2K
:param value: float
"""
self._window_overall_u_value = value
@property
def window_type(self):
"""
Get transparent surface type, 'window' or 'skylight'
:return: str
"""
return self._window_type
@window_type.setter
def window_type(self, value):
"""
Set transparent surface type, 'window' or 'skylight'
:return: str
"""
self._window_type = value

View File

@ -8,26 +8,24 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
import uuid
from typing import Union, List
from hub.city_model_structure.building_demand.usage import Usage
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
from hub.city_model_structure.building_demand.thermal_boundary import ThermalBoundary
from hub.city_model_structure.attributes.polyhedron import Polyhedron
from hub.city_model_structure.energy_systems.hvac_system import HvacSystem
class InternalZone:
"""
InternalZone class
"""
def __init__(self, surfaces, area, volume, number_of_storeys=None):
def __init__(self, surfaces, area):
self._surfaces = surfaces
self._id = None
self._geometry = None
self._volume = volume
self._volume = None
self._area = area
self._number_of_storeys = number_of_storeys
self._thermal_zones_from_internal_zones = None
self._thermal_zones = None
self._usages = None
self._thermal_archetype = None
self._hvac_system = None
@property
def id(self):
@ -66,7 +64,7 @@ class InternalZone:
Get internal zone volume in cubic meters
:return: float
"""
return self._volume
return self.geometry.volume
@property
def area(self):
@ -76,18 +74,10 @@ class InternalZone:
"""
return self._area
@property
def mean_height(self):
"""
Get internal zone mean height in meters
:return: float
"""
return self.volume / self.area
@property
def usages(self) -> [Usage]:
"""
Get usage archetypes
Get internal zone usage zones
:return: [Usage]
"""
return self._usages
@ -95,53 +85,39 @@ class InternalZone:
@usages.setter
def usages(self, value):
"""
Set usage archetypes
Set internal zone usage zones
:param value: [Usage]
"""
self._usages = value
@property
def thermal_archetype(self) -> ThermalArchetype:
def hvac_system(self) -> Union[None, HvacSystem]:
"""
Get thermal archetype parameters
:return: ThermalArchetype
Get HVAC system installed for this thermal zone
:return: None or HvacSystem
"""
return self._thermal_archetype
return self._hvac_system
@thermal_archetype.setter
def thermal_archetype(self, value):
@hvac_system.setter
def hvac_system(self, value):
"""
Set thermal archetype parameters
:param value: ThermalArchetype
Set HVAC system installed for this thermal zone
:param value: HvacSystem
"""
self._thermal_archetype = value
self._hvac_system = value
@property
def thermal_zones_from_internal_zones(self) -> Union[None, List[ThermalZone]]:
def thermal_zones(self) -> Union[None, List[ThermalZone]]:
"""
Get building thermal zones as one per internal zone
Get building thermal zones
:return: [ThermalZone]
"""
_thermal_boundaries = []
for surface in self.surfaces:
if surface.holes_polygons is None:
windows_areas = None
else:
windows_areas = []
for hole in surface.holes_polygons:
windows_areas.append(hole.area)
_thermal_boundary = ThermalBoundary(surface, surface.solid_polygon.area, windows_areas)
_thermal_boundaries.append(_thermal_boundary)
_thermal_zone = ThermalZone(_thermal_boundaries, self, self.volume, self.area, self._number_of_storeys)
for thermal_boundary in _thermal_zone.thermal_boundaries:
thermal_boundary.thermal_zones = [_thermal_zone]
self._thermal_zones_from_internal_zones = [_thermal_zone]
return self._thermal_zones_from_internal_zones
return self._thermal_zones
@thermal_zones_from_internal_zones.setter
def thermal_zones_from_internal_zones(self, value):
@thermal_zones.setter
def thermal_zones(self, value):
"""
Set city object thermal zones as one per internal zone
Set city object thermal zones
:param value: [ThermalZone]
"""
self._thermal_zones_from_internal_zones = value
self._thermal_zones = value

View File

@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import uuid
from typing import Union
from hub.city_model_structure.building_demand.material import Material
class Layer:
@ -14,17 +14,9 @@ class Layer:
Layer class
"""
def __init__(self):
self._material = None
self._thickness = None
self._id = None
self._name = None
self._conductivity = None
self._specific_heat = None
self._density = None
self._solar_absorptance = None
self._thermal_absorptance = None
self._visible_absorptance = None
self._no_mass = False
self._thermal_resistance = None
@property
def id(self):
@ -36,6 +28,22 @@ class Layer:
self._id = uuid.uuid4()
return self._id
@property
def material(self) -> Material:
"""
Get layer material
:return: Material
"""
return self._material
@material.setter
def material(self, value):
"""
Set layer material
:param value: Material
"""
self._material = value
@property
def thickness(self) -> Union[None, float]:
"""
@ -52,155 +60,3 @@ class Layer:
"""
if value is not None:
self._thickness = float(value)
@property
def name(self):
"""
Get material name
:return: str
"""
return self._name
@name.setter
def name(self, value):
"""
Set material name
:param value: string
"""
self._name = str(value)
@property
def conductivity(self) -> Union[None, float]:
"""
Get material conductivity in W/mK
:return: None or float
"""
return self._conductivity
@conductivity.setter
def conductivity(self, value):
"""
Set material conductivity in W/mK
:param value: float
"""
if value is not None:
self._conductivity = float(value)
@property
def specific_heat(self) -> Union[None, float]:
"""
Get material conductivity in J/kgK
:return: None or float
"""
return self._specific_heat
@specific_heat.setter
def specific_heat(self, value):
"""
Get material conductivity in J/kgK
:param value: float
"""
if value is not None:
self._specific_heat = float(value)
@property
def density(self) -> Union[None, float]:
"""
Get material density in kg/m3
:return: None or float
"""
return self._density
@density.setter
def density(self, value):
"""
Set material density
:param value: float
"""
if value is not None:
self._density = float(value)
@property
def solar_absorptance(self) -> Union[None, float]:
"""
Get material solar absorptance
:return: None or float
"""
return self._solar_absorptance
@solar_absorptance.setter
def solar_absorptance(self, value):
"""
Set material solar absorptance
:param value: float
"""
if value is not None:
self._solar_absorptance = float(value)
@property
def thermal_absorptance(self) -> Union[None, float]:
"""
Get material thermal absorptance
:return: None or float
"""
return self._thermal_absorptance
@thermal_absorptance.setter
def thermal_absorptance(self, value):
"""
Set material thermal absorptance
:param value: float
"""
if value is not None:
self._thermal_absorptance = float(value)
@property
def visible_absorptance(self) -> Union[None, float]:
"""
Get material visible absorptance
:return: None or float
"""
return self._visible_absorptance
@visible_absorptance.setter
def visible_absorptance(self, value):
"""
Set material visible absorptance
:param value: float
"""
if value is not None:
self._visible_absorptance = float(value)
@property
def no_mass(self) -> Union[None, bool]:
"""
Get material no mass flag
:return: None or Boolean
"""
return self._no_mass
@no_mass.setter
def no_mass(self, value):
"""
Set material no mass flag
:param value: Boolean
"""
if value is not None:
self._no_mass = value
@property
def thermal_resistance(self) -> Union[None, float]:
"""
Get material thermal resistance in m2K/W
:return: None or float
"""
return self._thermal_resistance
@thermal_resistance.setter
def thermal_resistance(self, value):
"""
Set material thermal resistance in m2K/W
:param value: float
"""
if value is not None:
self._thermal_resistance = float(value)

View File

@ -0,0 +1,193 @@
"""
Material module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from typing import Union
class Material:
"""
Material class
"""
def __init__(self):
self._id = None
self._name = None
self._conductivity = None
self._specific_heat = None
self._density = None
self._solar_absorptance = None
self._thermal_absorptance = None
self._visible_absorptance = None
self._no_mass = False
self._thermal_resistance = None
@property
def id(self):
"""
Get material id
:return: str
"""
return self._id
@id.setter
def id(self, value):
"""
Set material id
:param value: str
"""
self._id = value
@property
def name(self):
"""
Get material name
:return: str
"""
return self._name
@name.setter
def name(self, value):
"""
Set material name
:param value: string
"""
self._name = str(value)
@property
def conductivity(self) -> Union[None, float]:
"""
Get material conductivity in W/mK
:return: None or float
"""
return self._conductivity
@conductivity.setter
def conductivity(self, value):
"""
Set material conductivity in W/mK
:param value: float
"""
if value is not None:
self._conductivity = float(value)
@property
def specific_heat(self) -> Union[None, float]:
"""
Get material conductivity in J/kgK
:return: None or float
"""
return self._specific_heat
@specific_heat.setter
def specific_heat(self, value):
"""
Get material conductivity in J/kgK
:param value: float
"""
if value is not None:
self._specific_heat = float(value)
@property
def density(self) -> Union[None, float]:
"""
Get material density in kg/m3
:return: None or float
"""
return self._density
@density.setter
def density(self, value):
"""
Set material density
:param value: float
"""
if value is not None:
self._density = float(value)
@property
def solar_absorptance(self) -> Union[None, float]:
"""
Get material solar absorptance
:return: None or float
"""
return self._solar_absorptance
@solar_absorptance.setter
def solar_absorptance(self, value):
"""
Set material solar absorptance
:param value: float
"""
if value is not None:
self._solar_absorptance = float(value)
@property
def thermal_absorptance(self) -> Union[None, float]:
"""
Get material thermal absorptance
:return: None or float
"""
return self._thermal_absorptance
@thermal_absorptance.setter
def thermal_absorptance(self, value):
"""
Set material thermal absorptance
:param value: float
"""
if value is not None:
self._thermal_absorptance = float(value)
@property
def visible_absorptance(self) -> Union[None, float]:
"""
Get material visible absorptance
:return: None or float
"""
return self._visible_absorptance
@visible_absorptance.setter
def visible_absorptance(self, value):
"""
Set material visible absorptance
:param value: float
"""
if value is not None:
self._visible_absorptance = float(value)
@property
def no_mass(self) -> Union[None, bool]:
"""
Get material no mass flag
:return: None or Boolean
"""
return self._no_mass
@no_mass.setter
def no_mass(self, value):
"""
Set material no mass flag
:param value: Boolean
"""
if value is not None:
self._no_mass = value
@property
def thermal_resistance(self) -> Union[None, float]:
"""
Get material thermal resistance in m2K/W
:return: None or float
"""
return self._thermal_resistance
@thermal_resistance.setter
def thermal_resistance(self, value):
"""
Set material thermal resistance in m2K/W
:param value: float
"""
if value is not None:
self._thermal_resistance = float(value)

View File

@ -178,7 +178,7 @@ class Surface:
@property
def global_irradiance(self) -> dict:
"""
Get global irradiance on surface in J/m2
Get global irradiance on surface in Wh/m2
:return: dict
"""
return self._global_irradiance
@ -186,7 +186,7 @@ class Surface:
@global_irradiance.setter
def global_irradiance(self, value):
"""
Set global irradiance on surface in J/m2
Set global irradiance on surface in Wh/m2
:param value: dict
"""
self._global_irradiance = value

View File

@ -1,134 +0,0 @@
"""
Thermal archetype module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.city_model_structure.building_demand.construction import Construction
class ThermalArchetype:
"""
ThermalArchetype class
"""
def __init__(self):
self._constructions = None
self._average_storey_height = None
self._thermal_capacity = None
self._extra_loses_due_to_thermal_bridges = None
self._indirect_heated_ratio = None
self._infiltration_rate_for_ventilation_system_off = None
self._infiltration_rate_for_ventilation_system_on = None
@property
def constructions(self) -> [Construction]:
"""
Get archetype constructions
:return: [Construction]
"""
return self._constructions
@constructions.setter
def constructions(self, value):
"""
Set archetype constructions
:param value: [Construction]
"""
self._constructions = value
@property
def average_storey_height(self):
"""
Get average storey height in m
:return: float
"""
return self._average_storey_height
@average_storey_height.setter
def average_storey_height(self, value):
"""
Set average storey height in m
:param value: float
"""
self._average_storey_height = value
@property
def thermal_capacity(self):
"""
Get thermal capacity in J/m3K
:return: float
"""
return self._thermal_capacity
@thermal_capacity.setter
def thermal_capacity(self, value):
"""
Set thermal capacity in J/m3K
:param value: float
"""
self._thermal_capacity = value
@property
def extra_loses_due_to_thermal_bridges(self):
"""
Get extra loses due to thermal bridges in W/m2K
:return: float
"""
return self._extra_loses_due_to_thermal_bridges
@extra_loses_due_to_thermal_bridges.setter
def extra_loses_due_to_thermal_bridges(self, value):
"""
Set extra loses due to thermal bridges in W/m2K
:param value: float
"""
self._extra_loses_due_to_thermal_bridges = value
@property
def indirect_heated_ratio(self):
"""
Get indirect heated area ratio
:return: float
"""
return self._indirect_heated_ratio
@indirect_heated_ratio.setter
def indirect_heated_ratio(self, value):
"""
Set indirect heated area ratio
:param value: float
"""
self._indirect_heated_ratio = value
@property
def infiltration_rate_for_ventilation_system_off(self):
"""
Get infiltration rate for ventilation system off in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_off
@infiltration_rate_for_ventilation_system_off.setter
def infiltration_rate_for_ventilation_system_off(self, value):
"""
Set infiltration rate for ventilation system off in ACH
:param value: float
"""
self._infiltration_rate_for_ventilation_system_off = value
@property
def infiltration_rate_for_ventilation_system_on(self):
"""
Get infiltration rate for ventilation system on in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_on
@infiltration_rate_for_ventilation_system_on.setter
def infiltration_rate_for_ventilation_system_on(self, value):
"""
Set infiltration rate for ventilation system on in ACH
:param value: float
"""
self._infiltration_rate_for_ventilation_system_on = value

View File

@ -7,9 +7,7 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
"""
import uuid
import math
from typing import List, Union, TypeVar
import logging
from hub.helpers.configuration_helper import ConfigurationHelper as ch
import hub.helpers.constants as cte
from hub.city_model_structure.building_demand.layer import Layer
@ -37,8 +35,7 @@ class ThermalBoundary:
self._construction_name = None
self._thickness = None
self._internal_surface = None
self._external_surface = None
self._window_ratio = 0
self._window_ratio = None
self._window_ratio_to_be_calculated = False
if self._windows_areas is not None:
self._window_ratio_to_be_calculated = True
@ -56,7 +53,7 @@ class ThermalBoundary:
@property
def parent_surface(self) -> Surface:
"""
Get the surface that belongs to the thermal boundary, considered the external surface of that boundary
Get the surface that belongs to the thermal boundary
:return: Surface
"""
return self._parent_surface
@ -95,7 +92,7 @@ class ThermalBoundary:
self._thickness = 0.0
if self.layers is not None:
for layer in self.layers:
if not layer.no_mass:
if not layer.material.no_mass:
self._thickness += layer.thickness
return self._thickness
@ -151,21 +148,24 @@ class ThermalBoundary:
else:
_area = self.opaque_area * self.window_ratio / (1-self.window_ratio)
_thermal_opening.area = _area
self._thermal_openings = [_thermal_opening]
for thermal_opening in self._thermal_openings:
thermal_opening.g_value = self._construction_archetype.window_g_value
thermal_opening.overall_u_value = self._construction_archetype.window_overall_u_value
thermal_opening.frame_ratio = self._construction_archetype.window_frame_ratio
thermal_opening.construction_name = self._construction_archetype.window_type
return self._thermal_openings
@property
def _construction_archetype(self):
construction_archetypes = self.thermal_zones[0].parent_internal_zone.thermal_archetype.constructions
for construction_archetype in construction_archetypes:
if str(self.type) == str(construction_archetype.type):
return construction_archetype
return None
def construction_name(self) -> Union[None, str]:
"""
Get construction name
:return: None or str
"""
return self._construction_name
@construction_name.setter
def construction_name(self, value):
"""
Set construction name
:param value: str
"""
if value is not None:
self._construction_name = str(value)
@property
def layers(self) -> List[Layer]:
@ -173,13 +173,16 @@ class ThermalBoundary:
Get thermal boundary layers
:return: [Layers]
"""
if self._construction_archetype is not None:
self._layers = self._construction_archetype.layers
else:
logging.error('Layers not defined\n')
raise ValueError('Layers not defined')
return self._layers
@layers.setter
def layers(self, value):
"""
Set thermal boundary layers
:param value: [Layer]
"""
self._layers = value
@property
def type(self):
"""
@ -206,23 +209,18 @@ class ThermalBoundary:
for window_area in self.windows_areas:
total_window_area += window_area
self._window_ratio = total_window_area / (self.opaque_area + total_window_area)
else:
if self.type in (cte.WALL, cte.ROOF):
if -math.sqrt(2) / 2 < math.sin(self.parent_surface.azimuth) < math.sqrt(2) / 2:
if 0 < math.cos(self.parent_surface.azimuth):
self._window_ratio = \
float(self._construction_archetype.window_ratio['north']) / 100
else:
self._window_ratio = \
float(self._construction_archetype.window_ratio['south']) / 100
elif math.sqrt(2) / 2 <= math.sin(self._parent_surface.azimuth):
self._window_ratio = \
float(self._construction_archetype.window_ratio['east']) / 100
else:
self._window_ratio = \
float(self._construction_archetype.window_ratio['west']) / 100
return self._window_ratio
@window_ratio.setter
def window_ratio(self, value):
"""
Set thermal boundary window ratio
:param value: str
"""
if self._window_ratio_to_be_calculated:
raise ValueError('Window ratio cannot be assigned when the windows are defined in the geometry.')
self._window_ratio = float(value)
@property
def windows_areas(self) -> [float]:
"""
@ -247,10 +245,10 @@ class ThermalBoundary:
r_value = 1.0/h_i + 1.0/h_e
try:
for layer in self.layers:
if layer.no_mass:
r_value += float(layer.thermal_resistance)
if layer.material.no_mass:
r_value += float(layer.material.thermal_resistance)
else:
r_value += float(layer.thickness) / float(layer.conductivity)
r_value += float(layer.thickness) / float(layer.material.conductivity)
self._u_value = 1.0/r_value
except TypeError:
raise TypeError('Constructions layers are not initialized') from TypeError
@ -307,18 +305,4 @@ class ThermalBoundary:
"""
if self._internal_surface is None:
self._internal_surface = self.parent_surface.inverse
# The agreement is that the layers are defined from outside to inside
internal_layer = self.layers[len(self.layers) - 1]
self._internal_surface.short_wave_reflectance = 1 - internal_layer.solar_absorptance
self._internal_surface.long_wave_emittance = 1 - internal_layer.solar_absorptance
return self._internal_surface
@property
def external_surface(self) -> Surface:
if self._external_surface is None:
# The agreement is that the layers are defined from outside to inside
self._external_surface = self.parent_surface
self._external_surface.short_wave_reflectance = 1 - self.layers[0].solar_absorptance
self._external_surface.long_wave_emittance = 1 - self.layers[0].solar_absorptance
return self._external_surface

View File

@ -29,12 +29,7 @@ class ThermalZone:
ThermalZone class
"""
def __init__(self, thermal_boundaries,
parent_internal_zone,
volume,
footprint_area,
number_of_storeys,
usage_name=None):
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage_name=None):
self._id = None
self._parent_internal_zone = parent_internal_zone
self._footprint_area = footprint_area
@ -48,7 +43,6 @@ class ThermalZone:
self._ordinate_number = None
self._view_factors_matrix = None
self._total_floor_area = None
self._number_of_storeys = number_of_storeys
self._usage_name = usage_name
self._usage_from_parent = False
if usage_name is None:
@ -64,14 +58,6 @@ class ThermalZone:
self._domestic_hot_water = None
self._usages = None
@property
def parent_internal_zone(self) -> InternalZone:
"""
Get the internal zone to which this thermal zone belongs
:return: InternalZone
"""
return self._parent_internal_zone
@property
def usages(self):
"""
@ -127,45 +113,83 @@ class ThermalZone:
Get thermal zone additional thermal bridge u value per footprint area W/m2K
:return: None or float
"""
self._additional_thermal_bridge_u_value = self.parent_internal_zone.thermal_archetype.extra_loses_due_to_thermal_bridges
return self._additional_thermal_bridge_u_value
@additional_thermal_bridge_u_value.setter
def additional_thermal_bridge_u_value(self, value):
"""
Set thermal zone additional thermal bridge u value per footprint area W/m2K
:param value: float
"""
if value is not None:
self._additional_thermal_bridge_u_value = float(value)
@property
def effective_thermal_capacity(self) -> Union[None, float]:
"""
Get thermal zone effective thermal capacity in J/m3K
:return: None or float
"""
self._effective_thermal_capacity = self._parent_internal_zone.thermal_archetype.thermal_capacity
return self._effective_thermal_capacity
@effective_thermal_capacity.setter
def effective_thermal_capacity(self, value):
"""
Set thermal zone effective thermal capacity in J/m3K
:param value: float
"""
if value is not None:
self._effective_thermal_capacity = float(value)
@property
def indirectly_heated_area_ratio(self) -> Union[None, float]:
"""
Get thermal zone indirectly heated area ratio
:return: None or float
"""
self._indirectly_heated_area_ratio = self._parent_internal_zone.thermal_archetype.indirect_heated_ratio
return self._indirectly_heated_area_ratio
@indirectly_heated_area_ratio.setter
def indirectly_heated_area_ratio(self, value):
"""
Set thermal zone indirectly heated area ratio
:param value: float
"""
if value is not None:
self._indirectly_heated_area_ratio = float(value)
@property
def infiltration_rate_system_on(self):
"""
Get thermal zone infiltration rate system on in air changes per second (1/s)
Get thermal zone infiltration rate system on in air changes per hour (ACH)
:return: None or float
"""
self._infiltration_rate_system_on = self._parent_internal_zone.thermal_archetype.infiltration_rate_for_ventilation_system_on
return self._infiltration_rate_system_on
@infiltration_rate_system_on.setter
def infiltration_rate_system_on(self, value):
"""
Set thermal zone infiltration rate system on in air changes per hour (ACH)
:param value: float
"""
self._infiltration_rate_system_on = value
@property
def infiltration_rate_system_off(self):
"""
Get thermal zone infiltration rate system off in air changes per second (1/s)
Get thermal zone infiltration rate system off in air changes per hour (ACH)
:return: None or float
"""
self._infiltration_rate_system_off = self._parent_internal_zone.thermal_archetype.infiltration_rate_for_ventilation_system_off
return self._infiltration_rate_system_off
@infiltration_rate_system_off.setter
def infiltration_rate_system_off(self, value):
"""
Set thermal zone infiltration rate system on in air changes per hour (ACH)
:param value: float
"""
self._infiltration_rate_system_off = value
@property
def volume(self):
"""
@ -197,44 +221,16 @@ class ThermalZone:
Get thermal zone view factors matrix
:return: [[float]]
"""
# todo: review method if windows not in window_ratio but in geometry
if self._view_factors_matrix is None:
total_area = 0
for thermal_boundary in self.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in self.thermal_boundaries:
values = []
for thermal_boundary_2 in self.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in self.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in self.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in self.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in self.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
self._view_factors_matrix = view_factors_matrix
return self._view_factors_matrix
@view_factors_matrix.setter
def view_factors_matrix(self, value):
"""
Set thermal zone view factors matrix
:param value: [[float]]
"""
self._view_factors_matrix = value
@property
def usage_name(self) -> Union[None, str]:
"""
@ -289,7 +285,7 @@ class ThermalZone:
@property
def mechanical_air_change(self) -> Union[None, float]:
"""
Get thermal zone mechanical air change in air change per second (1/s)
Get thermal zone mechanical air change in air change per hour (ACH)
:return: None or float
"""
if self.usages is None:
@ -657,8 +653,15 @@ class ThermalZone:
@property
def total_floor_area(self):
"""
Get the total floor area of this thermal zone in m2
Get the total floor area of this thermal zone
:return: float
"""
self._total_floor_area = self.footprint_area * self._number_of_storeys
return self._total_floor_area
@total_floor_area.setter
def total_floor_area(self, value):
"""
Set the total floor area of this thermal zone
:param value: float
"""
self._total_floor_area = value

View File

@ -173,7 +173,7 @@ class Usage:
@property
def mechanical_air_change(self) -> Union[None, float]:
"""
Get usage zone mechanical air change in air change per second (1/s)
Get usage zone mechanical air change in air change per hour (ACH)
:return: None or float
"""
return self._mechanical_air_change
@ -181,7 +181,7 @@ class Usage:
@mechanical_air_change.setter
def mechanical_air_change(self, value):
"""
Set usage zone mechanical air change in air change per second (1/s)
Set usage zone mechanical air change in air change per hour (ACH)
:param value: float
"""
if value is not None:

View File

@ -0,0 +1,57 @@
"""
Bus system module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List
from hub.city_model_structure.city_object import CityObject
from hub.city_model_structure.attributes.polygon import Polygon
from hub.city_model_structure.transport.bus_network import BusNetwork
from hub.city_model_structure.transport.bus_node import BusNode
from hub.city_model_structure.transport.bus import Bus
class BusSystem(CityObject):
"""
BusSystem(CityObject) class
"""
def __init__(self, name, surfaces):
super().__init__(name, surfaces)
self._bus_routes = None
self._bus_network = None
self._buses = None
self._restricted_polygons = None
@property
def bus_routes(self) -> List[BusNode]:
"""
Add explanation here
:return: [BusNode]
"""
return self._bus_routes
@property
def bus_network(self) -> BusNetwork:
"""
Add explanation here
:return: BusNetwork
"""
return self._bus_network
@property
def buses(self) -> List[Bus]:
"""
Add explanation here
:return: [Bus]
"""
return self._buses
@property
def restricted_polygons(self) -> List[Polygon]:
"""
Add explanation here
:return: [Polygon]
"""
return self._restricted_polygons

View File

@ -81,10 +81,6 @@ class CityObject:
@volume.setter
def volume(self, value):
"""
Set city object volume in cubic meters
:param value: float
"""
self._volume = value
@property
@ -208,7 +204,7 @@ class CityObject:
@property
def global_horizontal(self) -> dict:
"""
Get global horizontal radiation surrounding the city object in J/m2
Get global horizontal radiation surrounding the city object in W/m2
:return: dict{dict{[float]}}
"""
return self._global_horizontal
@ -216,7 +212,7 @@ class CityObject:
@global_horizontal.setter
def global_horizontal(self, value):
"""
Set global horizontal radiation surrounding the city object in J/m2
Set global horizontal radiation surrounding the city object in W/m2
:param value: dict{dict{[float]}}
"""
self._global_horizontal = value
@ -224,7 +220,7 @@ class CityObject:
@property
def diffuse(self) -> dict:
"""
Get diffuse radiation surrounding the city object in J/m2
Get diffuse radiation surrounding the city object in W/m2
:return: dict{dict{[float]}}
"""
return self._diffuse
@ -232,7 +228,7 @@ class CityObject:
@diffuse.setter
def diffuse(self, value):
"""
Set diffuse radiation surrounding the city object in J/m2
Set diffuse radiation surrounding the city object in W/m2
:param value: dict{dict{[float]}}
"""
self._diffuse = value
@ -240,7 +236,7 @@ class CityObject:
@property
def beam(self) -> dict:
"""
Get beam radiation surrounding the city object in J/m2
Get beam radiation surrounding the city object in W/m2
:return: dict{dict{[float]}}
"""
return self._beam
@ -248,7 +244,7 @@ class CityObject:
@beam.setter
def beam(self, value):
"""
Set beam radiation surrounding the city object in J/m2
Set beam radiation surrounding the city object in W/m2
:param value: dict{dict{[float]}}
"""
self._beam = value

View File

@ -69,7 +69,7 @@ class GenericDistributionSystem:
def distribution_consumption_variable_flow(self):
"""
Get distribution_consumption if the pump or fan work at variable mass or volume flow in ratio
over energy produced (J/J)
over energy produced (Wh/Wh)
:return: float
"""
return self._distribution_consumption_variable_flow
@ -78,7 +78,7 @@ class GenericDistributionSystem:
def distribution_consumption_variable_flow(self, value):
"""
Set distribution_consumption if the pump or fan work at variable mass or volume flow in ratio
over energy produced (J/J)
over energy produced (Wh/Wh)
:return: float
"""
self._distribution_consumption_variable_flow = value

View File

@ -0,0 +1,50 @@
"""
HvacSystem module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union, List
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
class HvacSystem:
"""
HvacSystem class
"""
def __init__(self):
self._type = None
self._thermal_zones = None
@property
def type(self) -> Union[None, str]:
"""
Get hvac system type
:return: None or str
"""
return self._type
@type.setter
def type(self, value):
"""
Set hvac system type
:param value: str
"""
if value is not None:
self._type = str(value)
@property
def thermal_zones(self) -> Union[None, List[ThermalZone]]:
"""
Get list of zones that this unit serves
:return: None or [ThermalZone]
"""
return self._thermal_zones
@thermal_zones.setter
def thermal_zones(self, value):
"""
Set list of zones that this unit serves
:param value: [ThermalZone]
"""
self._thermal_zones = value

View File

@ -0,0 +1,115 @@
"""
Bus module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.city_model_structure.attributes.schedule import Schedule
class Bus:
"""
Bus class
"""
def __init__(self):
self._maintenance_time = None
self._charging_time = None
self._recovery_time = None
self._vehicle_type = None
self._energy_consumption = None
self._trips_schedule = None
self._capacity = None
self._maintenance_cost = None
self._investment_cost = None
self._charging_range = None
self._maximum_travel_range = None
@property
def maintenance_time(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._maintenance_time
@property
def charging_time(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._charging_time
@property
def recovery_time(self):
"""
Add explanation here
:return: add type of variable here
"""
return self.maintenance_time + self.charging_time
@property
def vehicle_type(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._vehicle_type
@property
def energy_consumption(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._energy_consumption
@property
def trips_schedule(self) -> Schedule:
"""
Add explanation here
:return: add type of variable here
"""
return self._trips_schedule
@property
def capacity(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._capacity
@property
def maintenance_cost(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._maintenance_cost
@property
def investment_cost(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._investment_cost
@property
def charging_range(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._charging_range
@property
def maximum_travel_range(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._maximum_travel_range

View File

@ -0,0 +1,35 @@
"""
Bus depot module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.city_model_structure.transport.bus_node import BusNode
class BusDepot(BusNode):
"""
BusDepot class
"""
def __init__(self, name, coordinates, edges=None):
super().__init__(name, coordinates, edges=edges, node_type='BusDepot')
self._number_of_charging_poles = None
self._number_of_available_buses = None
@property
def number_of_charging_poles(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._number_of_charging_poles
@property
def number_of_available_buses(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._number_of_available_buses

View File

@ -0,0 +1,47 @@
"""
Bus edge module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List, TypeVar
from hub.city_model_structure.attributes.edge import Edge
BusNode = TypeVar('BusNode')
class BusEdge(Edge):
"""
BusEdge class
Each edge is unidirectional and starts at the "from" node and ends at the "to" node
"""
def __init__(self, name, nodes, edge_type='BusEdge'):
super().__init__(name, nodes)
self._edge_type = edge_type
self._average_travel_time = None
@property
def edge_type(self):
"""
Get the edge type
:return: str
"""
return self._edge_type
@property
def nodes(self) -> List[BusNode]:
"""
Get delimiting nodes for the edge
:return: [BusNode]
"""
return self._nodes
@property
def average_travel_time(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._average_travel_time

View File

@ -0,0 +1,44 @@
"""
Bus network module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List
from hub.city_model_structure.network import Network
from hub.city_model_structure.transport.bus_edge import BusEdge
from hub.city_model_structure.transport.bus_node import BusNode
class BusNetwork(Network):
"""
BusNetwork(Network) class
"""
def __init__(self, name, edges=None, nodes=None):
super().__init__(name, edges, nodes)
self._type = "BusNetwork"
@property
def type(self):
"""
Get network type
:return: str
"""
return self._type
@property
def edges(self) -> List[BusEdge]:
"""
Get network edges
:return: [BusEdge]
"""
return self._edges
@property
def nodes(self) -> List[BusNode]:
"""
Get network nodes
:return: [BusNode]
"""
return self._nodes

View File

@ -0,0 +1,56 @@
"""
Bus node module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List, TypeVar
from hub.city_model_structure.attributes.node import Node
from hub.city_model_structure.attributes.point import Point
BusEdge = TypeVar('BusEdge')
class BusNode(Node):
"""
BusNode class
"""
def __init__(self, name, coordinates, node_type='BusNode', edges=None):
super().__init__(name, edges)
self._coordinates = coordinates
self._node_type = node_type
@property
def node_type(self):
"""
Get node type
:return: str
"""
return self._node_type
@property
def coordinates(self) -> Point:
"""
Get node coordinates
:return: Point
"""
return self._coordinates
@coordinates.setter
def coordinates(self, value):
"""
Set node coordinates
:param value: Point
"""
self._coordinates = value
@property
def edges(self) -> List[BusEdge]:
"""
get edges delimited by the node
:return: [BusEdge]
"""
return self._edges

View File

@ -0,0 +1,56 @@
"""
Bus stop module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union
from hub.city_model_structure.transport.bus_node import BusNode
from hub.city_model_structure.transport.fast_charging_infrastructure import FastChargingInfrastructure
from hub.city_model_structure.attributes.schedule import Schedule
class BusStop(BusNode):
"""
BusStop class
"""
def __init__(self, name, coordinates, edges=None):
super().__init__(name, coordinates, edges=edges, node_type='BusStop')
self._time_table = None
self._average_hourly_passengers_demand = None
self._fast_charging_infrastructure = None
self._waiting_time = None
@property
def time_table(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._time_table
@property
def average_hourly_passengers_demand(self) -> Schedule:
"""
Add explanation here
:return: Schedule
"""
return self._average_hourly_passengers_demand
@property
def fast_charging_infrastructure(self) -> Union[None, FastChargingInfrastructure]:
"""
Add explanation here
:return: FastChargingInfrastructure
"""
return self._fast_charging_infrastructure
@property
def waiting_time(self):
"""
Add explanation here
:return: add type of variable here
"""
return self._waiting_time

View File

@ -0,0 +1,125 @@
"""
Connection module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille guille.gutierrezmorote@concordia.ca
"""
import ast
from typing import Union
from hub.city_model_structure.attributes.edge import Edge
from hub.city_model_structure.transport.lane import Lane
class Connection:
"""
Connection class
"""
def __init__(self):
self._from_edge = None
self._to_edge = None
self._from_lane = None
self._to_lane = None
self._pass = None
self._keep_clear = None
@property
def from_edge(self) -> Edge:
"""
Get "from" edge
:return: Edge
"""
return self._from_edge
@from_edge.setter
def from_edge(self, value):
"""
Set "from" edge
:param value: Edge
"""
self._from_edge = value
@property
def to_edge(self) -> Edge:
"""
Get "to" edge
:return: Edge
"""
return self._to_edge
@to_edge.setter
def to_edge(self, value):
"""
Set "to" edge
:param value: Edge
"""
self._to_edge = value
@property
def from_lane(self) -> Lane:
"""
Get "from" lane
:return: Lane
"""
return self._to_lane
@from_lane.setter
def from_lane(self, value):
"""
Set "from" lane
:param value: Lane
"""
self._from_lane = value
@property
def to_lane(self) -> Lane:
"""
Get "to" lane
:return: Lane
"""
return self._to_lane
@to_lane.setter
def to_lane(self, value):
"""
Set "to" lane
:param value: Lane
"""
self._to_lane = value
@property
def pass_not_wait(self) -> Union[None, bool]:
"""
Get if the vehicles which pass this (lane to lane) connection will not wait
:return: None or Boolean
"""
return self._pass
@pass_not_wait.setter
def pass_not_wait(self, value):
"""
Set if the vehicles which pass this (lane to lane) connection will not wait
:param value: Boolean
"""
if value is not None:
self._pass = ast.literal_eval(value)
@property
def keep_clear(self) -> Union[None, bool]:
"""
Get if vehicles which pass this (lane to lane) connection should keep the intersection clear
:return: None or Boolean
"""
return self._keep_clear
@keep_clear.setter
def keep_clear(self, value):
"""
Set if vehicles which pass this (lane to lane) connection should keep the intersection clear
:param value: Boolean
"""
if value is not None:
self._keep_clear = ast.literal_eval(value)

View File

@ -0,0 +1,74 @@
"""
Crossing module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille guille.gutierrezmorote@concordia.ca
"""
import ast
from typing import List, Union
from hub.city_model_structure.transport.traffic_node import TrafficNode
class Crossing(TrafficNode):
"""
Crossing class
"""
def __init__(self, name, coordinates, priority, width, shape=None, edges=None):
super().__init__(name, coordinates, edges=edges, node_type='Crossing')
self._priority = priority
self._width = width
self._shape = shape
@property
def priority(self) -> Union[None, bool]:
"""
Get whether the pedestrians have priority over the vehicles
:return: None or bool
"""
return self._priority
@priority.setter
def priority(self, value):
"""
Set whether the pedestrians have priority over the vehicles
:param value: bool
"""
if value is not None:
self._priority = ast.literal_eval(value)
@property
def width(self) -> Union[None, float]:
"""
Get crossing width in meters
:return: None or float
"""
return self._width
@width.setter
def width(self, value):
"""
Set crossing width in meters
:param value: float
"""
if value is not None:
self._width = float(value)
@property
def shape(self) -> Union[None, List[List[float]]]:
"""
Get the list of positions
:return: None or [[x, y, (z)]]
"""
return self._shape
@shape.setter
def shape(self, value):
"""
Set the list of positions
:param value: [[x, y, (z)]]
"""
if value is not None:
self._shape = [[float(i) for i in value]]

View File

@ -0,0 +1,27 @@
"""
Join module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille guille.gutierrezmorote@concordia.ca
"""
from hub.city_model_structure.transport.traffic_node import TrafficNode
class Join(TrafficNode):
"""
Join class
"""
def __init__(self, name, coordinates, nodes):
self._nodes = nodes
edges = []
prohibitions = []
connections = []
for node in self._nodes:
edges = edges + node.edges
prohibitions = prohibitions + node.prohibitions
connections = connections + node.connections
super().__init__(name, coordinates, edges=edges, prohibitions=prohibitions, connections=connections,
node_type='Join')

View File

@ -0,0 +1,144 @@
"""
Lane module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List, Union
class Lane:
"""
Lane class
"""
def __init__(self):
self._index = None
self._allow = None
self._disallow = None
self._change_left = None
self._change_right = None
self._speed = None
self._width = None
@property
def index(self) -> Union[None, int]:
"""
Get lane index
The enumeration index of the lane (0 is the rightmost lane, <NUMBER_LANES>-1 is the leftmost one)
:return: None or int
"""
return self._index
@index.setter
def index(self, value):
"""
Set lane index
The enumeration index of the lane (0 is the rightmost lane, <NUMBER_LANES>-1 is the leftmost one)
:param value: int
"""
if value is not None:
self._index = int(value)
@property
def allow(self) -> Union[None, List[str]]:
"""
Get the list of allowed vehicle classes
:return: None or [str]
"""
return self._allow
@allow.setter
def allow(self, value):
"""
Set the list of allowed vehicle classes setter
:param value: [str]
"""
if value is not None:
self._allow = [str(i) for i in value]
@property
def disallow(self) -> Union[None, List[str]]:
"""
Get the list of not allowed vehicle classes
:return: None or [str]
"""
return self._disallow
@disallow.setter
def disallow(self, value):
"""
Get the list of not allowed vehicle classes setter
:param value: [str]
"""
if value is not None:
self._disallow = [str(i) for i in value]
@property
def change_left(self) -> Union[None, List[str]]:
"""
Get the list of vehicle classes that may change left from this lane
:return: None or [str]
"""
return self._change_left
@change_left.setter
def change_left(self, value):
"""
Set the list of vehicle classes that may change left from this lane
:param value: [str]
"""
if value is not None:
self._change_left = [str(i) for i in value]
@property
def change_right(self) -> Union[None, List[str]]:
"""
Get the list of vehicle classes that may change right from this lane
:return: None or [str]
"""
return self._change_right
@change_right.setter
def change_right(self, value):
"""
Set the list of vehicle classes that may change right from this lane
:param value: [str]
"""
if value is not None:
self._change_right = [str(i) for i in value]
@property
def speed(self) -> Union[None, float]:
"""
Get the lane speed in m/s
:return: None or float
"""
return self._speed
@speed.setter
def speed(self, value):
"""
Set the lane speed in m/s
:param value: float
"""
if value is not None:
self._speed = float(value)
@property
def width(self) -> Union[None, float]:
"""
Get the lane width in meters
:return: None or float
"""
return self._width
@width.setter
def width(self, value):
"""
Set the lane width in meters
:param value: float
"""
if value is not None:
self._width = float(value)

View File

@ -0,0 +1,48 @@
"""
Origin-Destination edge module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List, TypeVar
from hub.city_model_structure.attributes.edge import Edge
from hub.city_model_structure.attributes.schedule import Schedule
OriginDestinationNode = TypeVar('OriginDestinationNode')
class OriginDestinationEdge(Edge):
"""
OriginDestinationEdge class
Each edge is unidirectional and starts at the "from" node and ends at the "to" node
"""
def __init__(self, name, nodes, edge_type='OriginDestinationEdge'):
super().__init__(name, nodes)
self._edge_type = edge_type
self._movement_schedule = None
@property
def edge_type(self):
"""
Get the edge type
:return: str
"""
return self._edge_type
@property
def nodes(self) -> List[OriginDestinationNode]:
"""
Get delimiting nodes for the edge
:return: [OriginDestinationNode]
"""
return self._nodes
@property
def movement_schedule(self) -> Schedule:
"""
Get the schedule of the movement of people along this edge
:return: Schedule
"""
return self._movement_schedule

View File

@ -0,0 +1,44 @@
"""
Origin-Destination network module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List
from hub.city_model_structure.network import Network
from hub.city_model_structure.transport.origin_destination_edge import OriginDestinationEdge
from hub.city_model_structure.transport.origin_destination_node import OriginDestinationNode
class OriginDestinationNetwork(Network):
"""
OriginDestinationNetwork(Network) class
"""
def __init__(self, name, edges=None, nodes=None):
super().__init__(name, edges, nodes)
self._type = "OriginDestinationNetwork"
@property
def type(self):
"""
Get network type
:return: str
"""
return self._type
@property
def edges(self) -> List[OriginDestinationEdge]:
"""
Get network edges
:return: [OriginDestinationEdge]
"""
return self._edges
@property
def nodes(self) -> List[OriginDestinationNode]:
"""
Get network nodes
:return: [OriginDestinationNode]
"""
return self._nodes

View File

@ -0,0 +1,85 @@
"""
Origin-Destination node module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List, TypeVar
from hub.city_model_structure.attributes.node import Node
from hub.city_model_structure.attributes.point import Point
from hub.city_model_structure.attributes.polygon import Polygon
from hub.city_model_structure.city_object import CityObject
OriginDestinationEdge = TypeVar('OriginDestinationEdge')
class OriginDestinationNode(Node):
"""
OriginDestinationNode class
"""
def __init__(self, name, coordinates, node_type='OriginDestinationNode', edges=None, polygon=None):
super().__init__(name, edges)
self._coordinates = coordinates
self._node_type = node_type
self._polygon = polygon
self._land_use_types = None
self._city_objects = None
@property
def node_type(self):
"""
Get node type
:return: str
"""
return self._node_type
@property
def coordinates(self) -> Point:
"""
Get node coordinates
:return: Point
"""
return self._coordinates
@coordinates.setter
def coordinates(self, value):
"""
Set node coordinates
:param value: Point
"""
self._coordinates = value
@property
def edges(self) -> List[OriginDestinationEdge]:
"""
get edges delimited by the node
:return: [OriginDestinationEdge]
"""
return self._edges
@property
def polygon(self) -> Polygon:
"""
Get node polygon that defines the zone represented by the node
:return: Polygon
"""
return self._polygon
@property
def land_use_types(self) -> dict:
"""
Get land use types inside the node polygon. It returns a dictionary with the types of land use together with the
percentage of the land that corresponds to each type
:return: {string : float}
"""
return self._land_use_types
@property
def city_objects(self) -> List[CityObject]:
"""
Get the list of city objects place inside the zone
:return: List[CityObject]
"""
return self._city_objects

View File

@ -0,0 +1,134 @@
"""
Phase module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List, Union
class Phase:
"""
Phase class
"""
def __init__(self):
self._duration = None
self._state = None
self._min_duration = None
self._max_duration = None
self._name = None
self._next = None
@property
def duration(self) -> Union[None, int]:
"""
Get phase duration in seconds
:return: None or int
"""
return self._duration
@duration.setter
def duration(self, value):
"""
Set phase duration in seconds
:param value: int
"""
if value is not None:
self._duration = int(value)
@property
def state(self) -> Union[None, List[str]]:
"""
Get the list of signal states
:return: None or [str]
"""
return self._state
@state.setter
def state(self, value):
"""
Set the list of signal states
:param value: [str]
"""
if value is not None:
self._state = [str(i) for i in value]
@property
def min_duration(self) -> Union[None, int]:
"""
Get phase minimum duration in seconds
:return: None or int
"""
if self._min_duration is None:
self._min_duration = self._duration
return self._min_duration
@min_duration.setter
def min_duration(self, value):
"""
Set phase minimum duration in seconds
:param value: int
"""
if value is not None:
self._min_duration = int(value)
@property
def max_duration(self) -> Union[None, int]:
"""
Get phase maximum duration in seconds
:return: None or int
"""
if self._max_duration is None:
self._max_duration = self._duration
return self._max_duration
@max_duration.setter
def max_duration(self, value):
"""
Set phase maximum duration in seconds
:param value: int
"""
if value is not None:
self._max_duration = int(value)
@property
def name(self) -> Union[None, str]:
"""
Get phase name
:return: None or str
"""
return self._name
@name.setter
def name(self, value):
"""
Set phase name
:param value: str
"""
if value is not None:
self._name = str(value)
@property
def next(self) -> Union[None, List[int]]:
"""
Get the next phase in the cycle after the current.
This is useful when adding extra transition phases to a traffic light plan which are not part of every cycle.
Traffic lights of type 'actuated' can make use of a list of indices for selecting among alternative
successor phases.
:return: None or [int]
"""
return self._next
@next.setter
def next(self, value):
"""
Get the next phase in the cycle after the current.
This is useful when adding extra transition phases to a traffic light plan which are not part of every cycle.
Traffic lights of type 'actuated' can make use of a list of indices for selecting among alternative
successor phases.
:param value: [int]
"""
if value is not None:
self._next = [int(i) for i in value]

View File

@ -0,0 +1,150 @@
"""
Traffic edge module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille guille.gutierrezmorote@concordia.ca
"""
from typing import List, Union
from hub.city_model_structure.attributes.edge import Edge
from hub.city_model_structure.transport.traffic_node import TrafficNode
from hub.city_model_structure.transport.lane import Lane
class TrafficEdge(Edge):
"""
TrafficEdge class
Each edge is unidirectional and starts at the "from" node and ends at the "to" node
"""
def __init__(self, name, nodes, priority, speed, lanes, length, allows=None, disallows=None, sidewalk_width=None,
edge_type='TrafficEdge'):
super().__init__(name, nodes)
self._edge_type = edge_type
self._lanes = lanes
self._priority = priority
self._speed = speed
self._length = length
self._allows = allows
self._disallows = disallows
self._sidewalk_width = sidewalk_width
@property
def edge_type(self):
"""
Get the edge type
:return: str
"""
return self._edge_type
@property
def nodes(self) -> List[TrafficNode]:
"""
Get delimiting nodes for the edge
:return: [TrafficNode]
"""
return self._nodes
@property
def lanes(self) -> List[Lane]:
"""
Get the lanes on an edge
:return: List[Lane]
"""
return self._lanes
@lanes.setter
def lanes(self, value):
"""
Set the lanes on an edge
:param value: List[Lane]
"""
self._lanes = value
@property
def priority(self) -> Union[None, int]:
"""
Get the priority between different road types.
It starts with one; higher numbers represent more important roads.
:return: None or int
"""
return self._priority
@priority.setter
def priority(self, value):
"""
Set the priority between different road types.
It starts with one; higher numbers represent more important roads.
:param value: int
"""
if value is not None:
self._priority = int(value)
@property
def speed(self) -> Union[None, float]:
"""
Get he speed limit in m/s
:return: None or float
"""
return self._speed
@speed.setter
def speed(self, value):
"""
Set the speed limit in m/s
:param value: float
"""
if value is not None:
self._speed = float(value)
@property
def length(self) -> Union[None, float]:
"""
Get the lane length in meters
:return: None or float
"""
return self._length
@length.setter
def length(self, value):
"""
Set the lane length in meters
:param value: float
"""
if value is not None:
self._length = float(value)
@property
def allows(self) -> Union[None, List[str]]:
"""
Get the list of allowed vehicle classes
:return: None or [str]
"""
return self._allows
@allows.setter
def allows(self, value):
"""
Set the list of allowed vehicle classes
:param value: [str]
"""
if value is not None:
self._allows = [str(i) for i in value]
@property
def disallows(self) -> Union[None, List[str]]:
"""
Get the list of not allowed vehicle classes
:return: None or [str]
"""
return self._disallows
@disallows.setter
def disallows(self, value):
"""
Set the list of not allowed vehicle classes
:param value: [str]
"""
if value is not None:
self._disallows = [str(i) for i in value]

View File

@ -0,0 +1,75 @@
"""
Traffic light module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille guille.gutierrezmorote@concordia.ca
"""
import ast
from typing import List, Union
from hub.city_model_structure.transport.phase import Phase
from hub.city_model_structure.transport.traffic_node import TrafficNode
class TrafficLight(TrafficNode):
"""
Traffic light class
"""
def __init__(self, name, coordinates, offset, phases=None, edges=None, right_on_red=False):
super().__init__(name, coordinates, edges=edges, node_type='TrafficLight')
if phases is None:
phases = []
self._right_on_red = right_on_red
self._offset = offset
self._phases = phases
@property
def right_on_red(self) -> Union[None, bool]:
"""
Get if is possible to turn right when the traffic light is red
:return: None or Boolean
"""
return self._right_on_red
@right_on_red.setter
def right_on_red(self, value):
"""
Get if is possible to turn right when the traffic light is red
:param value: Boolean
"""
if value is not None:
self._right_on_red = ast.literal_eval(value)
@property
def offset(self) -> Union[None, int]:
"""
Get program initial time offset
:return: None or int
"""
return self._offset
@offset.setter
def offset(self, value):
"""
Set program initial time offset
:param value: int
"""
if value is not None:
self._offset = int(value)
@property
def phases(self) -> List[Phase]:
"""
Get traffic light logic phases
:return: [Phase]
"""
return self._phases
@phases.setter
def phases(self, value):
"""
Set traffic light logic phases
:param value: [Phase]
"""
self._phases = value

View File

@ -0,0 +1,45 @@
"""
Traffic network module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille guille.gutierrezmorote@concordia.ca
"""
from typing import List
from hub.city_model_structure.network import Network
from hub.city_model_structure.transport.traffic_edge import TrafficEdge
from hub.city_model_structure.transport.traffic_node import TrafficNode
class TrafficNetwork(Network):
"""
TrafficNetwork(Network) class
"""
def __init__(self, name, edges=None, nodes=None):
super().__init__(name, edges, nodes)
self._type = "TrafficNetwork"
@property
def type(self):
"""
Get network type
:return: str
"""
return self._type
@property
def edges(self) -> List[TrafficEdge]:
"""
Get network edges
:return: [TrafficEdge]
"""
return self._edges
@property
def nodes(self) -> List[TrafficNode]:
"""
Get network nodes
:return: [TrafficNode]
"""
return self._nodes

View File

@ -0,0 +1,97 @@
"""
TrafficNode module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille guille.gutierrezmorote@concordia.ca
"""
from typing import List, TypeVar
from hub.city_model_structure.attributes.edge import Edge
from hub.city_model_structure.attributes.node import Node
from hub.city_model_structure.attributes.point import Point
Connection = TypeVar('Connection')
TrafficEdge = TypeVar('TrafficEdge')
class TrafficNode(Node):
"""
TrafficNode class
"""
def __init__(self, name, coordinates, node_type='TrafficNode', edges=None, prohibitions=None, connections=None):
super().__init__(name, edges)
if connections is None:
connections = []
if prohibitions is None:
prohibitions = []
self._coordinates = coordinates
self._prohibitions = prohibitions
self._connections = connections
self._node_type = node_type
@property
def node_type(self):
"""
Get node type
:return: str
"""
return self._node_type
@property
def coordinates(self) -> Point:
"""
Get node coordinates
:return: Point
"""
return self._coordinates
@coordinates.setter
def coordinates(self, value):
"""
Set node coordinates
:param value: Point
"""
self._coordinates = value
@property
def edges(self) -> List[TrafficEdge]:
"""
get edges delimited by the node
:return: [TrafficEdge]
"""
return self._edges
@property
def prohibitions(self) -> [(Edge, Edge)]:
"""
Get node prohibitions
:return: [(Edge, Edge)]
"""
return self._prohibitions
@prohibitions.setter
def prohibitions(self, value):
"""
Set node prohibitions
:param value: [(Edge, Edge)]
"""
self._prohibitions = value
@property
def connections(self) -> List[Connection]:
"""
Get node connections
:return: [Connection]
"""
return self._connections
@connections.setter
def connections(self, value):
"""
Set node connections
:param value: [Connection]
"""
self._connections = value

View File

@ -0,0 +1,37 @@
"""
Walkway node module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Guille guille.gutierrezmorote@concordia.ca
"""
from typing import List, Union
from hub.city_model_structure.transport.traffic_node import TrafficNode
class WalkwayNode(TrafficNode):
"""
WalkwayNode class
"""
def __init__(self, name, coordinates, edges=None, shape=None):
super().__init__(name, coordinates, edges=edges, node_type='WalkwayNode')
self._shape = shape
@property
def shape(self) -> Union[None, List[List[float]]]:
"""
Get the list of positions
:return: None or [[x, y, (z)]]
"""
return self._shape
@shape.setter
def shape(self, value):
"""
Set the list of positions
:param value: [[x, y, (z)]]
"""
if value is not None:
self._shape = [[float(i) for i in value]]

View File

@ -335,7 +335,7 @@ class EnergyAde:
def _thermal_zones(self, building, city):
thermal_zones = []
for internal_zone in building.internal_zones:
for index, thermal_zone in enumerate(internal_zone.thermal_zones_from_internal_zones):
for index, thermal_zone in enumerate(internal_zone.thermal_zones):
usages = []
for usage in internal_zone.usages:
usages.append({'@xlink:href': f'#GML_{usage.id}'})

View File

@ -448,24 +448,22 @@ class Idf:
def _add_infiltration(self, thermal_zone, zone_name):
schedule = f'Infiltration schedules {thermal_zone.usage_name}'
_infiltration = thermal_zone.infiltration_rate_system_off * cte.HOUR_TO_SECONDS
self._idf.newidfobject(self._INFILTRATION,
Name=f'{zone_name}_infiltration',
Zone_or_ZoneList_Name=zone_name,
Schedule_Name=schedule,
Design_Flow_Rate_Calculation_Method='AirChanges/Hour',
Air_Changes_per_Hour=_infiltration
Air_Changes_per_Hour=thermal_zone.infiltration_rate_system_off
)
def _add_ventilation(self, thermal_zone, zone_name):
schedule = f'Ventilation schedules {thermal_zone.usage_name}'
_air_change = thermal_zone.mechanical_air_change * cte.HOUR_TO_SECONDS
self._idf.newidfobject(self._VENTILATION,
Name=f'{zone_name}_ventilation',
Zone_or_ZoneList_Name=zone_name,
Schedule_Name=schedule,
Design_Flow_Rate_Calculation_Method='AirChanges/Hour',
Air_Changes_per_Hour=_air_change
Air_Changes_per_Hour=thermal_zone.mechanical_air_change
)
def _add_dhw(self, thermal_zone, zone_name):
@ -512,9 +510,9 @@ class Idf:
for building in self._city.buildings:
print('building name', building.name)
for internal_zone in building.internal_zones:
if internal_zone.thermal_zones_from_internal_zones is None:
if internal_zone.thermal_zones is None:
continue
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
self._add_construction(thermal_boundary)
if thermal_boundary.parent_surface.vegetation is not None:
@ -558,7 +556,7 @@ class Idf:
self._add_dhw(thermal_zone, building.name)
if self._export_type == "Surfaces":
if building.name in self._target_buildings or building.name in self._adjacent_buildings:
if building.internal_zones[0].thermal_zones_from_internal_zones is not None:
if building.internal_zones[0].thermal_zones is not None:
self._add_surfaces(building, building.name)
else:
self._add_pure_geometry(building, building.name)
@ -613,7 +611,7 @@ class Idf:
num_stories=int(building.storeys_above_ground))
for surface in self._idf.idfobjects[self._SURFACE]:
for thermal_zone in building.thermal_zones_from_internal_zones:
for thermal_zone in building.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
if surface.Type == self.idf_surfaces[boundary.surface.type]:
surface.Construction_Name = boundary.construction_name
@ -666,7 +664,7 @@ class Idf:
idf_surface.setcoords(coordinates)
if self._lod >= 3:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
self._add_windows_by_vertices(boundary)
else:
@ -676,7 +674,7 @@ class Idf:
def _add_surfaces(self, building, zone_name):
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
idf_surface_type = self.idf_surfaces[boundary.parent_surface.type]
outside_boundary_condition = 'Outdoors'
@ -713,7 +711,7 @@ class Idf:
if self._lod >= 3:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for boundary in thermal_zone.thermal_boundaries:
self._add_windows_by_vertices(boundary)
else:

View File

@ -42,7 +42,7 @@ class InselMonthlyEnergyBalance:
self._insel_files_paths.append(building.name + '.insel')
file_name_out = building.name + '.out'
output_path = Path(self._path / file_name_out).resolve()
if building.thermal_zones_from_internal_zones is None:
if building.thermal_zones is None:
logging.warning('Building %s has missing values. Monthly Energy Balance cannot be processed', building.name)
self._contents.append(
@ -124,7 +124,7 @@ class InselMonthlyEnergyBalance:
# todo: this method and the insel model have to be reviewed for more than one internal zone
internal_zone = building.internal_zones[0]
thermal_zone = internal_zone.thermal_zones_from_internal_zones[0]
thermal_zone = internal_zone.thermal_zones[0]
parameters.append(f'{thermal_zone.indirectly_heated_area_ratio} % BP(6) Indirectly heated area ratio')
parameters.append(f'{thermal_zone.effective_thermal_capacity / 3600 / building.average_storey_height}'
f' % BP(7) Effective heat capacity (Wh/m2K)')
@ -137,7 +137,7 @@ class InselMonthlyEnergyBalance:
for i, usage in enumerate(internal_zone.usages):
percentage_usage = usage.percentage
parameters.append(f'{internal_zone.thermal_zones_from_internal_zones[0].total_floor_area * percentage_usage} '
parameters.append(f'{internal_zone.thermal_zones[0].total_floor_area * percentage_usage} '
f'% BP(11) #1 Area of zone {i + 1} (m2)')
total_internal_gain = 0
for i_gain in usage.internal_gains:
@ -167,11 +167,11 @@ class InselMonthlyEnergyBalance:
infiltration_day = 0
for value in schedule.values:
if value == 0:
infiltration_day += internal_zone.thermal_zones_from_internal_zones[0].infiltration_rate_system_off / 24 * cte.HOUR_TO_SECONDS
infiltration_day += internal_zone.thermal_zones[0].infiltration_rate_system_off / 24
ventilation_day += 0
else:
ventilation_value = usage.mechanical_air_change * value * cte.HOUR_TO_SECONDS
infiltration_value = internal_zone.thermal_zones_from_internal_zones[0].infiltration_rate_system_off * value * cte.HOUR_TO_SECONDS
ventilation_value = usage.mechanical_air_change * value
infiltration_value = internal_zone.thermal_zones[0].infiltration_rate_system_off * value
if ventilation_value >= infiltration_value:
ventilation_day += ventilation_value / 24
infiltration_day += 0
@ -259,7 +259,7 @@ class InselMonthlyEnergyBalance:
if cte.MONTH not in surface.global_irradiance:
raise ValueError(f'surface: {surface.name} from building {building.name} has no global irradiance!')
global_irradiance = surface.global_irradiance[cte.MONTH] * cte.WATTS_HOUR_TO_JULES
global_irradiance = surface.global_irradiance[cte.MONTH]
for j in range(0, len(global_irradiance)):
parameters.append(f'{j + 1} '
f'{global_irradiance[j] / 24 / _NUMBER_DAYS_PER_MONTH[j]}')

View File

@ -66,9 +66,8 @@ class SimplifiedRadiosityAlgorithm:
else:
i = (total_days + day - 1) * 24 + hour - 1
representative_building = self._city.buildings[0]
_global = representative_building.global_horizontal[cte.HOUR][i] * cte.WATTS_HOUR_TO_JULES
_beam = representative_building.beam[cte.HOUR][i] * cte.WATTS_HOUR_TO_JULES
content += f'{day} {month} {hour} {_global} {_beam}\n'
content += f'{day} {month} {hour} {representative_building.global_horizontal[cte.HOUR][i]} ' \
f'{representative_building.beam[cte.HOUR][i]}\n'
with open(file, 'w', encoding='utf-8') as file:
file.write(content)

View File

@ -22,7 +22,6 @@ HOUR_TO_SECONDS = 3600
METERS_TO_FEET = 3.28084
BTU_H_TO_WATTS = 0.29307107
KILO_WATTS_HOUR_TO_JULES = 3600000
WATTS_HOUR_TO_JULES = 3600
GALLONS_TO_QUBIC_METERS = 0.0037854117954011185
# time

View File

@ -46,11 +46,12 @@ class LoadsCalculation:
load_renovation_sensible = 0
for usage in thermal_zone.usages:
load_renovation_sensible += cte.AIR_DENSITY * cte.AIR_HEAT_CAPACITY * usage.mechanical_air_change \
* thermal_zone.volume * (internal_temperature - ambient_temperature)
* thermal_zone.volume / cte.HOUR_TO_MINUTES / cte.MINUTES_TO_SECONDS \
* (internal_temperature - ambient_temperature)
load_infiltration_sensible = (
cte.AIR_DENSITY * cte.AIR_HEAT_CAPACITY * thermal_zone.infiltration_rate_system_off * thermal_zone.volume
* (internal_temperature - ambient_temperature)
cte.AIR_DENSITY * cte.AIR_HEAT_CAPACITY * thermal_zone.infiltration_rate_system_off * thermal_zone.volume /
cte.HOUR_TO_MINUTES / cte.MINUTES_TO_SECONDS * (internal_temperature - ambient_temperature)
)
load_ventilation = load_renovation_sensible + load_infiltration_sensible
@ -64,7 +65,7 @@ class LoadsCalculation:
"""
heating_load_transmitted = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_heating_set_point
heating_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature,
ground_temperature)
@ -77,7 +78,7 @@ class LoadsCalculation:
"""
cooling_load_transmitted = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_cooling_set_point
cooling_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature,
ground_temperature)
@ -90,7 +91,7 @@ class LoadsCalculation:
"""
heating_ventilation_load = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_heating_set_point
heating_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature)
return heating_ventilation_load
@ -102,7 +103,7 @@ class LoadsCalculation:
"""
cooling_ventilation_load = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
internal_temperature = thermal_zone.thermal_control.mean_cooling_set_point
cooling_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature)
return cooling_ventilation_load
@ -116,7 +117,7 @@ class LoadsCalculation:
cooling_load_lighting = 0
cooling_load_equipment_sensible = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
cooling_load_occupancy_sensible += (thermal_zone.occupancy.sensible_convective_internal_gain
+ thermal_zone.occupancy.sensible_radiative_internal_gain) \
* thermal_zone.footprint_area
@ -138,10 +139,10 @@ class LoadsCalculation:
"""
cooling_load_radiation = 0
for internal_zone in self._building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
radiation = thermal_boundary.parent_surface.global_irradiance[cte.HOUR][hour] * cte.WATTS_HOUR_TO_JULES
radiation = thermal_boundary.parent_surface.global_irradiance[cte.HOUR][hour]
cooling_load_radiation += (
thermal_opening.area * (1 - thermal_opening.frame_ratio) * thermal_opening.g_value * radiation
)

View File

@ -1,41 +0,0 @@
"""
Thermal zones creation module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class ThermalZonesCreation:
"""
PeakLoads class
"""
def __init__(self, building=None):
self._building = building
# # The agreement is that the layers are defined from outside to inside
# external_layer = catalog_construction.layers[0]
# external_surface = thermal_boundary.parent_surface
# external_surface.short_wave_reflectance = 1 - external_layer.material.solar_absorptance
# external_surface.long_wave_emittance = 1 - external_layer.material.solar_absorptance
# internal_layer = catalog_construction.layers[len(catalog_construction.layers) - 1]
# internal_surface = thermal_boundary.internal_surface
# internal_surface.short_wave_reflectance = 1 - internal_layer.material.solar_absorptance
# internal_surface.long_wave_emittance = 1 - internal_layer.material.solar_absorptance
@property
def thermal_zones_from_storeys(self):
"""
Create and get thermal zones as 1 per each storey
:return: [ThermalZone]
"""
raise NotImplementedError
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones_from_internal_zones = thermal_zones

View File

@ -6,13 +6,15 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import logging
import math
import hub.helpers.constants as cte
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.construction import Construction
from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class EilatPhysicsParameters:
@ -33,7 +35,7 @@ class EilatPhysicsParameters:
eilat_catalog = ConstructionCatalogFactory('eilat').catalog
for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_eilat_construction_function.keys():
logging.error(f'Building %s has an unknown building function %s', building.name, building.function)
logging.error(f'Building %s has an unknown building function %s', building.name, building.function )
continue
function = Dictionaries().hub_function_to_eilat_construction_function[building.function]
try:
@ -44,10 +46,29 @@ class EilatPhysicsParameters:
f'[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, self._climate_zone)
continue
thermal_archetype = ThermalArchetype()
self._assign_values(thermal_archetype, archetype)
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:
if building.internal_zones[0].thermal_zones is None:
self._create_storeys(building, archetype, self._divide_in_storeys)
if self._divide_in_storeys:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
else:
number_of_storeys = int(building.eave_height / building.average_storey_height)
thermal_zone = building.internal_zones[0].thermal_zones[0]
thermal_zone.total_floor_area = thermal_zone.footprint_area * number_of_storeys
else:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
for internal_zone in building.internal_zones:
internal_zone.thermal_archetype = thermal_archetype
self._assign_values(internal_zone.thermal_zones, archetype)
for thermal_zone in internal_zone.thermal_zones:
self._calculate_view_factors(thermal_zone)
@staticmethod
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
@ -60,51 +81,133 @@ class EilatPhysicsParameters:
raise KeyError('archetype not found')
@staticmethod
def _assign_values(thermal_archetype, catalog_archetype):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges
thermal_archetype.indirect_heated_ratio = 0
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on
thermal_archetype.infiltration_rate_for_ventilation_system_off = catalog_archetype.infiltration_rate_for_ventilation_system_off
effective_thermal_capacity = 0
_constructions = []
for catalog_construction in catalog_archetype.constructions:
construction = Construction()
construction.type = catalog_construction.type
if catalog_construction.window_ratio is not None:
for _orientation in catalog_construction.window_ratio:
if catalog_construction.window_ratio[_orientation] is None:
catalog_construction.window_ratio[_orientation] = 0
construction.window_ratio = catalog_construction.window_ratio
_layers = []
total_thickness = 0
for layer_archetype in catalog_construction.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
total_thickness += layer_archetype.thickness
archetype_material = layer_archetype.material
layer.name = archetype_material.name
layer.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
layer.thermal_resistance = archetype_material.thermal_resistance
else:
layer.density = archetype_material.density
layer.conductivity = archetype_material.conductivity
layer.specific_heat = archetype_material.specific_heat
effective_thermal_capacity += archetype_material.specific_heat \
* archetype_material.density * layer_archetype.thickness
layer.solar_absorptance = archetype_material.solar_absorptance
layer.thermal_absorptance = archetype_material.thermal_absorptance
layer.visible_absorptance = archetype_material.visible_absorptance
_layers.append(layer)
construction.layers = _layers
effective_thermal_capacity = effective_thermal_capacity / total_thickness
def _search_construction_in_archetype(archetype, construction_type):
construction_archetypes = archetype.constructions
for construction_archetype in construction_archetypes:
if str(construction_type) == str(construction_archetype.type):
return construction_archetype
return None
if catalog_construction.window is not None:
window_archetype = catalog_construction.window
construction.window_frame_ratio = window_archetype.frame_ratio
construction.window_g_value = window_archetype.g_value
construction.window_overall_u_value = window_archetype.overall_u_value
_constructions.append(construction)
thermal_archetype.constructions = _constructions
thermal_archetype.thermal_capacity = effective_thermal_capacity
def _assign_values(self, thermal_zones, archetype):
for thermal_zone in thermal_zones:
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
effective_thermal_capacity = 0
thermal_zone.indirectly_heated_area_ratio = 0
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
for thermal_boundary in thermal_zone.thermal_boundaries:
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
thermal_boundary.construction_name = f'{thermal_boundary.type}_{construction_archetype.name}'
try:
thermal_boundary.window_ratio = 0
if thermal_boundary.type in (cte.WALL, cte.ROOF):
if construction_archetype.window is not None:
if -math.sqrt(2) / 2 < math.sin(thermal_boundary.parent_surface.azimuth) < math.sqrt(2) / 2:
if 0 < math.cos(thermal_boundary.parent_surface.azimuth):
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['north']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['south']) / 100
elif math.sqrt(2) / 2 <= math.sin(thermal_boundary.parent_surface.azimuth):
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['east']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['west']) / 100
except ValueError:
# This is the normal operation way when the windows are defined in the geometry
continue
thermal_boundary.layers = []
total_thickness = 0
for layer_archetype in construction_archetype.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
total_thickness += layer_archetype.thickness
material = Material()
archetype_material = layer_archetype.material
material.name = archetype_material.name
material.id = archetype_material.id
material.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
material.thermal_resistance = archetype_material.thermal_resistance
else:
material.density = archetype_material.density
material.conductivity = archetype_material.conductivity
material.specific_heat = archetype_material.specific_heat
effective_thermal_capacity += archetype_material.specific_heat \
* archetype_material.density * layer_archetype.thickness
material.solar_absorptance = archetype_material.solar_absorptance
material.thermal_absorptance = archetype_material.thermal_absorptance
material.visible_absorptance = archetype_material.visible_absorptance
layer.material = material
thermal_boundary.layers.append(layer)
effective_thermal_capacity = effective_thermal_capacity / total_thickness
# The agreement is that the layers are defined from outside to inside
external_layer = construction_archetype.layers[0]
external_surface = thermal_boundary.parent_surface
external_surface.short_wave_reflectance = 1 - external_layer.material.solar_absorptance
external_surface.long_wave_emittance = 1 - external_layer.material.solar_absorptance
internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1]
internal_surface = thermal_boundary.internal_surface
internal_surface.short_wave_reflectance = 1 - internal_layer.material.solar_absorptance
internal_surface.long_wave_emittance = 1 - internal_layer.material.solar_absorptance
for thermal_opening in thermal_boundary.thermal_openings:
if construction_archetype.window is not None:
window_archetype = construction_archetype.window
thermal_opening.construction_name = window_archetype.name
thermal_opening.frame_ratio = window_archetype.frame_ratio
thermal_opening.g_value = window_archetype.g_value
thermal_opening.overall_u_value = window_archetype.overall_u_value
thermal_zone.effective_thermal_capacity = effective_thermal_capacity
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -5,6 +5,8 @@ Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.helpers import constants as cte
class ConstructionHelper:
"""

View File

@ -6,13 +6,15 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import logging
import math
import hub.helpers.constants as cte
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.construction import Construction
from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class NrcanPhysicsParameters:
@ -33,7 +35,7 @@ class NrcanPhysicsParameters:
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_nrcan_construction_function.keys():
logging.error(f'Building %s has an unknown building function %s', building.name, building.function)
logging.error(f'Building %s has an unknown building function %s', building.name, building.function )
continue
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
try:
@ -44,10 +46,29 @@ class NrcanPhysicsParameters:
f'[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, self._climate_zone)
continue
thermal_archetype = ThermalArchetype()
self._assign_values(thermal_archetype, archetype)
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:
if building.internal_zones[0].thermal_zones is None:
self._create_storeys(building, archetype, self._divide_in_storeys)
if self._divide_in_storeys:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
else:
number_of_storeys = int(building.eave_height / building.average_storey_height)
thermal_zone = building.internal_zones[0].thermal_zones[0]
thermal_zone.total_floor_area = thermal_zone.footprint_area * number_of_storeys
else:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
for internal_zone in building.internal_zones:
internal_zone.thermal_archetype = thermal_archetype
self._assign_values(internal_zone.thermal_zones, archetype)
for thermal_zone in internal_zone.thermal_zones:
self._calculate_view_factors(thermal_zone)
@staticmethod
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
@ -60,45 +81,126 @@ class NrcanPhysicsParameters:
raise KeyError('archetype not found')
@staticmethod
def _assign_values(thermal_archetype, catalog_archetype):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges
thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity
thermal_archetype.indirect_heated_ratio = 0
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on
thermal_archetype.infiltration_rate_for_ventilation_system_off = catalog_archetype.infiltration_rate_for_ventilation_system_off
_constructions = []
for catalog_construction in catalog_archetype.constructions:
construction = Construction()
construction.type = catalog_construction.type
if catalog_construction.window_ratio is not None:
for _orientation in catalog_construction.window_ratio:
if catalog_construction.window_ratio[_orientation] is None:
catalog_construction.window_ratio[_orientation] = 0
construction.window_ratio = catalog_construction.window_ratio
_layers = []
for layer_archetype in catalog_construction.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
archetype_material = layer_archetype.material
layer.name = archetype_material.name
layer.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
layer.thermal_resistance = archetype_material.thermal_resistance
else:
layer.density = archetype_material.density
layer.conductivity = archetype_material.conductivity
layer.specific_heat = archetype_material.specific_heat
layer.solar_absorptance = archetype_material.solar_absorptance
layer.thermal_absorptance = archetype_material.thermal_absorptance
layer.visible_absorptance = archetype_material.visible_absorptance
_layers.append(layer)
construction.layers = _layers
def _search_construction_in_archetype(archetype, construction_type):
construction_archetypes = archetype.constructions
for construction_archetype in construction_archetypes:
if str(construction_type) == str(construction_archetype.type):
return construction_archetype
return None
if catalog_construction.window is not None:
window_archetype = catalog_construction.window
construction.window_frame_ratio = window_archetype.frame_ratio
construction.window_g_value = window_archetype.g_value
construction.window_overall_u_value = window_archetype.overall_u_value
_constructions.append(construction)
thermal_archetype.constructions = _constructions
def _assign_values(self, thermal_zones, archetype):
for thermal_zone in thermal_zones:
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
thermal_zone.indirectly_heated_area_ratio = 0
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
for thermal_boundary in thermal_zone.thermal_boundaries:
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
thermal_boundary.construction_name = f'{thermal_boundary.type}_{construction_archetype.name}'
try:
thermal_boundary.window_ratio = 0
if thermal_boundary.type in ( cte.WALL, cte.ROOF):
if construction_archetype.window is not None:
if -math.sqrt(2) / 2 < math.sin(thermal_boundary.parent_surface.azimuth) < math.sqrt(2) / 2:
if 0 < math.cos(thermal_boundary.parent_surface.azimuth):
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['north']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['south']) / 100
elif math.sqrt(2) / 2 <= math.sin(thermal_boundary.parent_surface.azimuth):
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['east']) / 100
else:
thermal_boundary.window_ratio = \
float(construction_archetype.window_ratio['west']) / 100
except ValueError:
# This is the normal operation way when the windows are defined in the geometry
continue
thermal_boundary.layers = []
for layer_archetype in construction_archetype.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
material = Material()
archetype_material = layer_archetype.material
material.name = archetype_material.name
material.id = archetype_material.id
material.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
material.thermal_resistance = archetype_material.thermal_resistance
else:
material.density = archetype_material.density
material.conductivity = archetype_material.conductivity
material.specific_heat = archetype_material.specific_heat
material.solar_absorptance = archetype_material.solar_absorptance
material.thermal_absorptance = archetype_material.thermal_absorptance
material.visible_absorptance = archetype_material.visible_absorptance
layer.material = material
thermal_boundary.layers.append(layer)
# The agreement is that the layers are defined from outside to inside
external_layer = construction_archetype.layers[0]
external_surface = thermal_boundary.parent_surface
external_surface.short_wave_reflectance = 1 - external_layer.material.solar_absorptance
external_surface.long_wave_emittance = 1 - external_layer.material.solar_absorptance
internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1]
internal_surface = thermal_boundary.internal_surface
internal_surface.short_wave_reflectance = 1 - internal_layer.material.solar_absorptance
internal_surface.long_wave_emittance = 1 - internal_layer.material.solar_absorptance
for thermal_opening in thermal_boundary.thermal_openings:
if construction_archetype.window is not None:
window_archetype = construction_archetype.window
thermal_opening.construction_name = window_archetype.name
thermal_opening.frame_ratio = window_archetype.frame_ratio
thermal_opening.g_value = window_archetype.g_value
thermal_opening.overall_u_value = window_archetype.overall_u_value
# todo: verify windows
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -8,11 +8,11 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
import logging
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.construction import Construction
from hub.city_model_structure.building_demand.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class NrelPhysicsParameters:
@ -44,10 +44,28 @@ class NrelPhysicsParameters:
f' and climate zone {self._climate_zone}\n')
continue
thermal_archetype = ThermalArchetype()
self._assign_values(thermal_archetype, archetype)
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:
if building.internal_zones[0].thermal_zones is None:
self._create_storeys(building, archetype, self._divide_in_storeys)
if self._divide_in_storeys:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
else:
number_of_storeys = int(building.eave_height / building.average_storey_height)
thermal_zone = building.internal_zones[0].thermal_zones[0]
thermal_zone.total_floor_area = thermal_zone.footprint_area * number_of_storeys
else:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
thermal_zone.total_floor_area = thermal_zone.footprint_area
for internal_zone in building.internal_zones:
internal_zone.thermal_archetype = thermal_archetype
self._assign_values(internal_zone.thermal_zones, archetype)
for thermal_zone in internal_zone.thermal_zones:
self._calculate_view_factors(thermal_zone)
@staticmethod
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
@ -62,46 +80,111 @@ class NrelPhysicsParameters:
raise KeyError('archetype not found')
@staticmethod
def _assign_values(thermal_archetype, catalog_archetype):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges
thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity
thermal_archetype.indirect_heated_ratio = catalog_archetype.indirect_heated_ratio
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on
thermal_archetype.infiltration_rate_for_ventilation_system_off = catalog_archetype.infiltration_rate_for_ventilation_system_off
_constructions = []
for catalog_construction in catalog_archetype.constructions:
construction = Construction()
construction.type = catalog_construction.type
if catalog_construction.window_ratio is not None:
construction.window_ratio = {'north': catalog_construction.window_ratio,
'east': catalog_construction.window_ratio,
'south': catalog_construction.window_ratio,
'west': catalog_construction.window_ratio
}
_layers = []
for layer_archetype in catalog_construction.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
archetype_material = layer_archetype.material
layer.name = archetype_material.name
layer.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
layer.thermal_resistance = archetype_material.thermal_resistance
else:
layer.density = archetype_material.density
layer.conductivity = archetype_material.conductivity
layer.specific_heat = archetype_material.specific_heat
layer.solar_absorptance = archetype_material.solar_absorptance
layer.thermal_absorptance = archetype_material.thermal_absorptance
layer.visible_absorptance = archetype_material.visible_absorptance
_layers.append(layer)
construction.layers = _layers
def _search_construction_in_archetype(archetype, construction_type):
construction_archetypes = archetype.constructions
for construction_archetype in construction_archetypes:
if str(construction_type) == str(construction_archetype.type):
return construction_archetype
return None
if catalog_construction.window is not None:
window_archetype = catalog_construction.window
construction.window_frame_ratio = window_archetype.frame_ratio
construction.window_g_value = window_archetype.g_value
construction.window_overall_u_value = window_archetype.overall_u_value
_constructions.append(construction)
thermal_archetype.constructions = _constructions
def _assign_values(self, thermal_zones, archetype):
for thermal_zone in thermal_zones:
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
thermal_zone.indirectly_heated_area_ratio = archetype.indirect_heated_ratio
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
for thermal_boundary in thermal_zone.thermal_boundaries:
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
thermal_boundary.construction_name = construction_archetype.name
try:
thermal_boundary.window_ratio = construction_archetype.window_ratio
except ValueError:
# This is the normal operation way when the windows are defined in the geometry
continue
thermal_boundary.layers = []
for layer_archetype in construction_archetype.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
material = Material()
archetype_material = layer_archetype.material
material.name = archetype_material.name
material.id = archetype_material.id
material.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
material.thermal_resistance = archetype_material.thermal_resistance
else:
material.density = archetype_material.density
material.conductivity = archetype_material.conductivity
material.specific_heat = archetype_material.specific_heat
material.solar_absorptance = archetype_material.solar_absorptance
material.thermal_absorptance = archetype_material.thermal_absorptance
material.visible_absorptance = archetype_material.visible_absorptance
layer.material = material
thermal_boundary.layers.append(layer)
# The agreement is that the layers are defined from outside to inside
external_layer = construction_archetype.layers[0]
external_surface = thermal_boundary.parent_surface
external_surface.short_wave_reflectance = 1 - external_layer.material.solar_absorptance
external_surface.long_wave_emittance = 1 - external_layer.material.solar_absorptance
internal_layer = construction_archetype.layers[len(construction_archetype.layers) - 1]
internal_surface = thermal_boundary.internal_surface
internal_surface.short_wave_reflectance = 1 - internal_layer.material.solar_absorptance
internal_surface.long_wave_emittance = 1 - internal_layer.material.solar_absorptance
for thermal_opening in thermal_boundary.thermal_openings:
if construction_archetype.window is not None:
window_archetype = construction_archetype.window
thermal_opening.construction_name = window_archetype.name
thermal_opening.frame_ratio = window_archetype.frame_ratio
thermal_opening.g_value = window_archetype.g_value
thermal_opening.overall_u_value = window_archetype.overall_u_value
# todo: verify windows
@staticmethod
def _calculate_view_factors(thermal_zone):
"""
Get thermal zone view factors matrix
:return: [[float]]
"""
total_area = 0
for thermal_boundary in thermal_zone.thermal_boundaries:
total_area += thermal_boundary.opaque_area
for thermal_opening in thermal_boundary.thermal_openings:
total_area += thermal_opening.area
view_factors_matrix = []
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = 0
if thermal_boundary_1.id != thermal_boundary_2.id:
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings:
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
values.append(value)
view_factors_matrix.append(values)
for thermal_boundary_1 in thermal_zone.thermal_boundaries:
values = []
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
for thermal_boundary_2 in thermal_zone.thermal_boundaries:
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
values.append(value)
for thermal_boundary in thermal_zone.thermal_boundaries:
for thermal_opening_2 in thermal_boundary.thermal_openings:
value = 0
if thermal_opening_1.id != thermal_opening_2.id:
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
values.append(value)
view_factors_matrix.append(values)
thermal_zone.view_factors_matrix = view_factors_matrix
@staticmethod
def _create_storeys(building, archetype, divide_in_storeys):
building.average_storey_height = archetype.average_storey_height
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
divide_in_storeys=divide_in_storeys).thermal_zones
building.internal_zones[0].thermal_zones = thermal_zones

View File

@ -30,7 +30,7 @@ class InselMonthlyEnergyBalance:
demand = str(line).replace("['", '').replace("']", '').split()
for i in range(0, 2):
if demand[i] != 'NaN':
aux = float(demand[i]) * cte.WATTS_HOUR_TO_JULES * 1000 # kWh to J
aux = float(demand[i]) * 1000 # kWh to Wh
demand[i] = str(aux)
else:
demand[i] = '0'
@ -43,12 +43,12 @@ class InselMonthlyEnergyBalance:
domestic_hot_water_demand = []
lighting_demand = []
appliances_demand = []
if building.internal_zones[0].thermal_zones_from_internal_zones is None:
if building.internal_zones[0].thermal_zones is None:
domestic_hot_water_demand = [0] * 12
lighting_demand = [0] * 12
appliances_demand = [0] * 12
else:
thermal_zone = building.internal_zones[0].thermal_zones_from_internal_zones[0]
thermal_zone = building.internal_zones[0].thermal_zones[0]
area = thermal_zone.total_floor_area
cold_water = building.cold_water_temperature[cte.MONTH]
peak_flow = thermal_zone.domestic_hot_water.peak_flow
@ -66,8 +66,7 @@ class InselMonthlyEnergyBalance:
for value in schedule.values:
total_day += value
for day_type in schedule.day_types:
total_lighting += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] \
* lighting_density / cte.WATTS_HOUR_TO_JULES
total_lighting += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * lighting_density
lighting_demand.append(total_lighting * area)
for schedule in thermal_zone.appliances.schedules:
@ -75,8 +74,7 @@ class InselMonthlyEnergyBalance:
for value in schedule.values:
total_day += value
for day_type in schedule.day_types:
total_appliances += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] \
* appliances_density / cte.WATTS_HOUR_TO_JULES
total_appliances += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * appliances_density
appliances_demand.append(total_appliances * area)
for schedule in thermal_zone.domestic_hot_water.schedules:
@ -85,8 +83,7 @@ class InselMonthlyEnergyBalance:
total_day += value
for day_type in schedule.day_types:
demand = (
peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY
* (service_temperature - cold_water[month]) / cte.WATTS_HOUR_TO_JULES
peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * (service_temperature - cold_water[month])
)
total_dhw_demand += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * demand
domestic_hot_water_demand.append(total_dhw_demand * area)
@ -100,15 +97,14 @@ class InselMonthlyEnergyBalance:
def enrich(self):
"""
Enrich the city by using the insel monthly energy balance output files (J)
Enrich the city by using the insel monthly energy balance output files
:return: None
"""
for building in self._city.buildings:
file_name = building.name + '.out'
insel_output_file_path = Path(self._base_path / file_name).resolve()
if insel_output_file_path.is_file():
building.heating_demand[cte.MONTH], building.cooling_demand[cte.MONTH] \
= self._conditioning_demand(insel_output_file_path)
building.heating_demand[cte.MONTH], building.cooling_demand[cte.MONTH] = self._conditioning_demand(insel_output_file_path)
building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.MONTH])]
building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.MONTH])]
self._dhw_and_electric_demand()

View File

@ -34,8 +34,7 @@ class SimplifiedRadiosityAlgorithm:
for key in self._results:
_irradiance = {}
header_name = key.split(':')
# todo: @Pilar!!!!!!!!!!!!!!!!!!!!!!!!
result = self._results[key] / cte.WATTS_HOUR_TO_JULES
result = self._results[key]
city_object_name = header_name[1]
building = self._city.city_object(city_object_name)
surface_id = header_name[2]

View File

@ -71,7 +71,8 @@ class ComnetUsageParameters:
# Due to the fact that python is not a typed language, the wrong object type is assigned to
# usage.occupancy when writing usage.occupancy = archetype.occupancy.
# Same happens for lighting and appliances. Therefore, this walk around has been done.
usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area
usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area \
* cte.HOUR_TO_SECONDS
_occupancy = Occupancy()
_occupancy.occupancy_density = archetype.occupancy.occupancy_density
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain

View File

@ -71,7 +71,8 @@ class EilatUsageParameters:
# Due to the fact that python is not a typed language, the wrong object type is assigned to
# usage.occupancy when writing usage.occupancy = archetype.occupancy.
# Same happens for lighting and appliances. Therefore, this walk around has been done.
usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area
usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area \
* cte.HOUR_TO_SECONDS
_occupancy = Occupancy()
_occupancy.occupancy_density = archetype.occupancy.occupancy_density
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain

View File

@ -92,11 +92,11 @@ class NrcanUsageParameters:
@staticmethod
def _assign_values(usage, archetype, volume_per_area, cold_water_temperature):
if archetype.mechanical_air_change > 0:
# 1/s
# ACH
usage.mechanical_air_change = archetype.mechanical_air_change
elif archetype.ventilation_rate > 0:
# m3/m2.s to 1/s
usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area
# m3/m2.s to ACH
usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area * cte.HOUR_TO_SECONDS
else:
usage.mechanical_air_change = 0
_occupancy = Occupancy()

View File

@ -110,10 +110,9 @@ class EpwWeatherParameters:
# new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw'])
# number_invalid_records = new_value[new_value.epw == 99.9].count().epw
building.external_temperature[cte.HOUR] = self._weather_values['dry_bulb_temperature_c']
building.global_horizontal[cte.HOUR] = self._weather_values[
'global_horizontal_radiation_wh_m2'] / cte.WATTS_HOUR_TO_JULES
building.diffuse[cte.HOUR] = self._weather_values['diffuse_horizontal_radiation_wh_m2'] / cte.WATTS_HOUR_TO_JULES
building.beam[cte.HOUR] = self._weather_values['direct_normal_radiation_wh_m2'] / cte.WATTS_HOUR_TO_JULES
building.global_horizontal[cte.HOUR] = self._weather_values['global_horizontal_radiation_wh_m2']
building.diffuse[cte.HOUR] = self._weather_values['diffuse_horizontal_radiation_wh_m2']
building.beam[cte.HOUR] = self._weather_values['direct_normal_radiation_wh_m2']
building.cold_water_temperature[cte.HOUR] = wh().cold_water_temperature(building.external_temperature[cte.HOUR])
# create the monthly and yearly values out of the hourly

View File

@ -60,7 +60,7 @@ class CityObject(Models):
self.wall_area = wall_area
window_ratio = 0
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
window_ratio = thermal_boundary.window_ratio
break

View File

@ -106,7 +106,7 @@ class TestConstructionFactory(TestCase):
self.assertIsNotNone(building.shell, 'building shell is none')
def _check_thermal_zones(self, internal_zone):
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none')
self.assertIsNotNone(thermal_zone.footprint_area, 'thermal_zone floor area is none')
self.assertTrue(len(thermal_zone.thermal_boundaries) > 0, 'thermal_zone thermal_boundaries not defined')
@ -138,6 +138,7 @@ class TestConstructionFactory(TestCase):
self.assertIsNotNone(thermal_boundary.thickness, 'thermal_boundary thickness is none')
self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type is none')
self.assertIsNotNone(thermal_boundary.thermal_openings, 'thermal_openings is none')
self.assertIsNotNone(thermal_boundary.construction_name, 'construction_name is none')
self.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none')
self.assertIsNone(thermal_boundary.windows_areas, 'windows_areas is not none')
self.assertIsNotNone(thermal_boundary.u_value, 'u_value is none')
@ -149,15 +150,17 @@ class TestConstructionFactory(TestCase):
def _check_thermal_openings(self, thermal_boundary):
for thermal_opening in thermal_boundary.thermal_openings:
self.assertIsNotNone(thermal_opening.id, 'thermal opening id is not none')
self.assertIsNotNone(thermal_opening.construction_name, 'thermal opening construction is none')
self.assertIsNotNone(thermal_opening.area, 'thermal opening area is not none')
self.assertIsNotNone(thermal_opening.frame_ratio, 'thermal opening frame_ratio is none')
self.assertIsNotNone(thermal_opening.g_value, 'thermal opening g_value is none')
self.assertIsNotNone(thermal_opening.overall_u_value, 'thermal opening overall_u_value is none')
self.assertIsNotNone(thermal_opening.hi, 'thermal opening hi is none')
self.assertIsNotNone(thermal_opening.he, 'thermal opening he is none')
self.assertIsNotNone(thermal_opening.construction_name, 'thermal opening construction_name is none')
def _check_surfaces(self, thermal_boundary):
external_surface = thermal_boundary.external_surface
external_surface = thermal_boundary.parent_surface
internal_surface = thermal_boundary.internal_surface
self.assertIsNotNone(external_surface.short_wave_reflectance,
'external surface short_wave_reflectance id is not none')
@ -181,7 +184,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -199,7 +202,25 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
file = 'one_building_in_kelowna.gml'
city = self._get_citygml(file)
for building in city.buildings:
building.year_of_construction = 2006
building.function = self._internal_function('hft', building.function)
ConstructionFactory('nrel', city).enrich()
self._check_buildings(city)
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -217,7 +238,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -235,7 +256,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -256,7 +277,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -278,7 +299,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -300,7 +321,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')

View File

@ -51,8 +51,7 @@ class TestExports(TestCase):
_irradiance = {}
for key in self._results:
header_name = key.split(':')
# todo: @Pilar!!!!!!!!!!!!!!!!!!!!!!!!
result = self._results[key] / cte.WATTS_HOUR_TO_JULES
result = self._results[key]
city_object_name = header_name[1]
building = self._city.city_object(city_object_name)
surface_id = header_name[2]
@ -101,7 +100,7 @@ class TestExports(TestCase):
self.assertIsNotNone(building.basement_heated, f'building {building.name} basement_heated is none')
for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.area, f'internal zone {internal_zone.id} area is none')
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, f'thermal zone {thermal_zone.id} '
f'indirectly_heated_area_ratio is none')
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, f'thermal zone {thermal_zone.id} '
@ -114,12 +113,11 @@ class TestExports(TestCase):
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.type)
self.assertIsNotNone(thermal_boundary.opaque_area)
if thermal_boundary.type in (cte.WALL, cte.ROOF):
self.assertIsNotNone(thermal_boundary.window_ratio)
self.assertIsNotNone(thermal_boundary.window_ratio)
self.assertIsNotNone(thermal_boundary.u_value)
self.assertIsNotNone(thermal_boundary.thermal_openings)
if thermal_boundary.type is not cte.GROUND:
self.assertIsNotNone(thermal_boundary.external_surface.short_wave_reflectance)
self.assertIsNotNone(thermal_boundary.parent_surface.short_wave_reflectance)
for usage in internal_zone.usages:
self.assertIsNotNone(usage.percentage, f'usage zone {usage.name} percentage is none')

View File

@ -274,8 +274,8 @@ TestDBFactory
{'yearly_domestic_hot_water_consumption': yearly_domestic_hot_water_consumption},
{'monthly_distribution_systems_electrical_consumption': monthly_distribution_systems_electrical_consumption},
{'yearly_distribution_systems_electrical_consumption': yearly_distribution_systems_electrical_consumption},
{'monthly_on_site_electrical_production': monthly_on_site_electrical_production * cte.WATTS_HOUR_TO_JULES},
{'yearly_on_site_electrical_production': yearly_on_site_electrical_production * cte.WATTS_HOUR_TO_JULES}
{'monthly_on_site_electrical_production': monthly_on_site_electrical_production},
{'yearly_on_site_electrical_production': yearly_on_site_electrical_production}
]})
db_building_id = _building.id

View File

@ -38,7 +38,7 @@ class TestGeometryFactory(TestCase):
self.assertIsNot(len(internal_zone.usages), 0, 'no building usages defined')
for usage in internal_zone.usages:
self.assertIsNotNone(usage.id, 'usage id is none')
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_thermal_zone(thermal_zone)
def _check_buildings(self, city):
@ -46,7 +46,7 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(building.internal_zones, 'no internal zones created')
for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.usages, 'usage zones are not defined')
self.assertIsNotNone(internal_zone.thermal_zones_from_internal_zones, 'thermal zones are not defined')
self.assertIsNotNone(internal_zone.thermal_zones, 'thermal zones are not defined')
self.assertIsNone(building.basement_heated, 'building basement_heated is not none')
self.assertIsNone(building.attic_heated, 'building attic_heated is not none')
self.assertIsNotNone(building.average_storey_height, 'building average_storey_height is none')
@ -105,7 +105,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet':
for building in city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_extra_thermal_zone(thermal_zone)
# usage factory called first
city = self._get_citygml(file)
@ -117,7 +117,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet':
for building in city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_extra_thermal_zone(thermal_zone)
def _test_pluto(self, file):
@ -135,7 +135,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet':
for building in city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_extra_thermal_zone(thermal_zone)
# usage factory called first
city = self._get_citygml(file)
@ -147,7 +147,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet':
for building in city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self._check_extra_thermal_zone(thermal_zone)
def test_enrichment(self):

View File

@ -120,7 +120,6 @@ class TestExports(TestCase):
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
print(self._output_path)
try:
EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
except Exception:

View File

@ -62,7 +62,7 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(building.internal_zones, 'building internal zones is none')
for internal_zone in building.internal_zones:
self.assertIsNone(internal_zone.usages, 'usage zones are defined')
self.assertIsNone(internal_zone.thermal_archetype, 'thermal archetype is defined')
self.assertIsNone(internal_zone.thermal_zones, 'thermal zones are defined')
self.assertIsNone(building.basement_heated, 'building basement_heated is not none')
self.assertIsNone(building.attic_heated, 'building attic_heated is not none')
self.assertIsNone(building.terrains, 'building terrains is not none')

View File

@ -51,8 +51,7 @@ class TestExports(TestCase):
_irradiance = {}
for key in self._results:
header_name = key.split(':')
# todo: @Pilar!!!!!!!!!!!!!!!!!!!!!!!!
result = self._results[key] / cte.WATTS_HOUR_TO_JULES
result = self._results[key]
city_object_name = header_name[1]
building = self._city.city_object(city_object_name)
surface_id = header_name[2]
@ -101,7 +100,7 @@ class TestExports(TestCase):
self.assertIsNotNone(building.basement_heated, f'building {building.name} basement_heated is none')
for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.area, f'internal zone {internal_zone.id} area is none')
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
for thermal_zone in internal_zone.thermal_zones:
self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, f'thermal zone {thermal_zone.id} '
f'indirectly_heated_area_ratio is none')
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, f'thermal zone {thermal_zone.id} '
@ -118,7 +117,7 @@ class TestExports(TestCase):
self.assertIsNotNone(thermal_boundary.u_value)
self.assertIsNotNone(thermal_boundary.thermal_openings)
if thermal_boundary.type is not cte.GROUND:
self.assertIsNotNone(thermal_boundary.external_surface.short_wave_reflectance)
self.assertIsNotNone(thermal_boundary.parent_surface.short_wave_reflectance)
for usage in internal_zone.usages:
self.assertIsNotNone(usage.percentage, f'usage zone {usage.name} percentage is none')

View File

@ -115,4 +115,4 @@ class TestSystemsFactory(TestCase):
self.assertLess(0, building.heating_consumption[cte.YEAR][0])
self.assertLess(0, building.cooling_consumption[cte.YEAR][0])
self.assertLess(0, building.domestic_hot_water_consumption[cte.YEAR][0])
self.assertLess(0, building.onsite_electrical_production[cte.YEAR][0])
self.assertLess(0, building.onsite_electrical_production[cte.YEAR][0])