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.window import Window
from hub.catalog_factories.data_models.construction.material import Material from hub.catalog_factories.data_models.construction.material import Material
from hub.catalog_factories.data_models.construction.layer import Layer from hub.catalog_factories.data_models.construction.layer import Layer
import hub.helpers.constants as cte
class EilatCatalog(Catalog): class EilatCatalog(Catalog):
@ -121,8 +120,8 @@ class EilatCatalog(Catalog):
construction_period = archetype['period_of_construction'] construction_period = archetype['period_of_construction']
average_storey_height = archetype['average_storey_height'] average_storey_height = archetype['average_storey_height']
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges'] 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_off = archetype['infiltration_rate_for_ventilation_system_off']
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on'] / cte.HOUR_TO_SECONDS infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on']
archetype_constructions = [] archetype_constructions = []
for archetype_construction in 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.window import Window
from hub.catalog_factories.data_models.construction.material import Material from hub.catalog_factories.data_models.construction.material import Material
from hub.catalog_factories.data_models.construction.layer import Layer from hub.catalog_factories.data_models.construction.layer import Layer
import hub.helpers.constants as cte
class NrcanCatalog(Catalog): class NrcanCatalog(Catalog):
@ -122,8 +121,8 @@ class NrcanCatalog(Catalog):
average_storey_height = archetype['average_storey_height'] average_storey_height = archetype['average_storey_height']
thermal_capacity = float(archetype['thermal_capacity']) * 1000 thermal_capacity = float(archetype['thermal_capacity']) * 1000
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges'] 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_off = archetype['infiltration_rate_for_ventilation_system_off']
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on'] / cte.HOUR_TO_SECONDS infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on']
archetype_constructions = [] archetype_constructions = []
for archetype_construction in 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.content import Content
from hub.catalog_factories.data_models.construction.archetype import Archetype from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.construction.construction_helper import ConstructionHelper from hub.catalog_factories.construction.construction_helper import ConstructionHelper
import hub.helpers.constants as cte
class NrelCatalog(Catalog): class NrelCatalog(Catalog):
@ -125,10 +124,10 @@ class NrelCatalog(Catalog):
indirect_heated_ratio = float(archetype['indirect_heated_ratio']['#text']) indirect_heated_ratio = float(archetype['indirect_heated_ratio']['#text'])
infiltration_rate_for_ventilation_system_off = float( infiltration_rate_for_ventilation_system_off = float(
archetype['infiltration_rate_for_ventilation_system_off']['#text'] archetype['infiltration_rate_for_ventilation_system_off']['#text']
) / cte.HOUR_TO_SECONDS )
infiltration_rate_for_ventilation_system_on = float( infiltration_rate_for_ventilation_system_on = float(
archetype['infiltration_rate_for_ventilation_system_on']['#text'] archetype['infiltration_rate_for_ventilation_system_on']['#text']
) / cte.HOUR_TO_SECONDS )
archetype_constructions = [] archetype_constructions = []
for archetype_construction in archetype['constructions']['construction']: for archetype_construction in archetype['constructions']['construction']:

View File

@ -120,7 +120,7 @@ class Archetype:
@property @property
def infiltration_rate_for_ventilation_system_off(self): 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: float
""" """
return self._infiltration_rate_for_ventilation_system_off return self._infiltration_rate_for_ventilation_system_off
@ -128,7 +128,7 @@ class Archetype:
@property @property
def infiltration_rate_for_ventilation_system_on(self): 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: float
""" """
return self._infiltration_rate_for_ventilation_system_on return self._infiltration_rate_for_ventilation_system_on
@ -147,8 +147,8 @@ class Archetype:
'thermal capacity [J/m3K]': self.thermal_capacity, 'thermal capacity [J/m3K]': self.thermal_capacity,
'extra loses due to thermal bridges [W/m2K]': self.extra_loses_due_to_thermal_bridges, 'extra loses due to thermal bridges [W/m2K]': self.extra_loses_due_to_thermal_bridges,
'indirect heated ratio': self.indirect_heated_ratio, '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 off [ACH]': 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 on [ACH]': self.infiltration_rate_for_ventilation_system_on,
'constructions': _constructions 'constructions': _constructions
} }
} }

View File

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

View File

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

View File

@ -65,7 +65,7 @@ class Usage:
@property @property
def mechanical_air_change(self) -> Union[None, float]: 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: None or float
""" """
return self._mechanical_air_change return self._mechanical_air_change

View File

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

View File

@ -41,7 +41,7 @@ class Building(CityObject):
self._floor_area = None self._floor_area = None
self._roof_type = None self._roof_type = None
self._internal_zones = None self._internal_zones = None
self._thermal_zones_from_internal_zones = None self._thermal_zones = None
self._shell = None self._shell = None
self._aliases = [] self._aliases = []
self._type = 'building' self._type = 'building'
@ -114,24 +114,26 @@ class Building(CityObject):
:return: [InternalZone] :return: [InternalZone]
""" """
if self._internal_zones is None: 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._internal_zones = [InternalZone(self.surfaces, self.floor_area, self.volume, _number_of_storeys)]
return self._internal_zones return self._internal_zones
@property @property
def thermal_zones_from_internal_zones(self) -> Union[None, List[ThermalZone]]: def thermal_zones(self) -> Union[None, List[ThermalZone]]:
""" """
Get building thermal zones 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] :return: [ThermalZone]
""" """
if self._thermal_zones_from_internal_zones is None: if self._thermal_zones is None:
self._thermal_zones_from_internal_zones = [] self._thermal_zones = []
for internal_zone in self.internal_zones: for internal_zone in self.internal_zones:
if internal_zone.thermal_zones_from_internal_zones is None: if internal_zone.thermal_zones is None:
self._thermal_zones_from_internal_zones = None self._thermal_zones = None
return self._thermal_zones_from_internal_zones return self._thermal_zones
self._thermal_zones_from_internal_zones.append(internal_zone.thermal_zones_from_internal_zones[0]) for thermal_zone in internal_zone.thermal_zones:
return self._thermal_zones_from_internal_zones self._thermal_zones.append(thermal_zone)
return self._thermal_zones
@property @property
def grounds(self) -> List[Surface]: def grounds(self) -> List[Surface]:
@ -259,15 +261,6 @@ class Building(CityObject):
Get building average storey height in meters Get building average storey height in meters
:return: None or float :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 return self._average_storey_height
@average_storey_height.setter @average_storey_height.setter
@ -318,7 +311,7 @@ class Building(CityObject):
@property @property
def heating_demand(self) -> dict: def heating_demand(self) -> dict:
""" """
Get heating demand in J Get heating demand in Wh
:return: dict{[float]} :return: dict{[float]}
""" """
return self._heating_demand return self._heating_demand
@ -326,7 +319,7 @@ class Building(CityObject):
@heating_demand.setter @heating_demand.setter
def heating_demand(self, value): def heating_demand(self, value):
""" """
Set heating demand in J Set heating demand in Wh
:param value: dict{[float]} :param value: dict{[float]}
""" """
self._heating_demand = value self._heating_demand = value
@ -334,7 +327,7 @@ class Building(CityObject):
@property @property
def cooling_demand(self) -> dict: def cooling_demand(self) -> dict:
""" """
Get cooling demand in J Get cooling demand in Wh
:return: dict{[float]} :return: dict{[float]}
""" """
return self._cooling_demand return self._cooling_demand
@ -342,7 +335,7 @@ class Building(CityObject):
@cooling_demand.setter @cooling_demand.setter
def cooling_demand(self, value): def cooling_demand(self, value):
""" """
Set cooling demand in J Set cooling demand in Wh
:param value: dict{[float]} :param value: dict{[float]}
""" """
self._cooling_demand = value self._cooling_demand = value
@ -350,7 +343,7 @@ class Building(CityObject):
@property @property
def lighting_electrical_demand(self) -> dict: def lighting_electrical_demand(self) -> dict:
""" """
Get lighting electrical demand in J Get lighting electrical demand in Wh
:return: dict{[float]} :return: dict{[float]}
""" """
return self._lighting_electrical_demand return self._lighting_electrical_demand
@ -358,7 +351,7 @@ class Building(CityObject):
@lighting_electrical_demand.setter @lighting_electrical_demand.setter
def lighting_electrical_demand(self, value): def lighting_electrical_demand(self, value):
""" """
Set lighting electrical demand in J Set lighting electrical demand in Wh
:param value: dict{[float]} :param value: dict{[float]}
""" """
self._lighting_electrical_demand = value self._lighting_electrical_demand = value
@ -366,7 +359,7 @@ class Building(CityObject):
@property @property
def appliances_electrical_demand(self) -> dict: def appliances_electrical_demand(self) -> dict:
""" """
Get appliances electrical demand in J Get appliances electrical demand in Wh
:return: dict{[float]} :return: dict{[float]}
""" """
return self._appliances_electrical_demand return self._appliances_electrical_demand
@ -374,7 +367,7 @@ class Building(CityObject):
@appliances_electrical_demand.setter @appliances_electrical_demand.setter
def appliances_electrical_demand(self, value): def appliances_electrical_demand(self, value):
""" """
Set appliances electrical demand in J Set appliances electrical demand in Wh
:param value: dict{[float]} :param value: dict{[float]}
""" """
self._appliances_electrical_demand = value self._appliances_electrical_demand = value
@ -382,7 +375,7 @@ class Building(CityObject):
@property @property
def domestic_hot_water_heat_demand(self) -> dict: 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: dict{[float]}
""" """
return self._domestic_hot_water_heat_demand return self._domestic_hot_water_heat_demand
@ -390,7 +383,7 @@ class Building(CityObject):
@domestic_hot_water_heat_demand.setter @domestic_hot_water_heat_demand.setter
def domestic_hot_water_heat_demand(self, value): 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]} :param value: dict{[float]}
""" """
self._domestic_hot_water_heat_demand = value self._domestic_hot_water_heat_demand = value
@ -403,8 +396,7 @@ class Building(CityObject):
""" """
results = {} results = {}
peak_lighting = 0 peak_lighting = 0
peak = 0 for thermal_zone in self.thermal_zones:
for thermal_zone in self.thermal_zones_from_internal_zones:
lighting = thermal_zone.lighting lighting = thermal_zone.lighting
for schedule in lighting.schedules: for schedule in lighting.schedules:
peak = max(schedule.values) * lighting.density * thermal_zone.total_floor_area peak = max(schedule.values) * lighting.density * thermal_zone.total_floor_area
@ -422,8 +414,7 @@ class Building(CityObject):
""" """
results = {} results = {}
peak_appliances = 0 peak_appliances = 0
peak = 0 for thermal_zone in self.thermal_zones:
for thermal_zone in self.thermal_zones_from_internal_zones:
appliances = thermal_zone.appliances appliances = thermal_zone.appliances
for schedule in appliances.schedules: for schedule in appliances.schedules:
peak = max(schedule.values) * appliances.density * thermal_zone.total_floor_area 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 monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
if monthly_values is None: if monthly_values is None:
return None return None
# todo: @Pilar!!!! results[cte.MONTH] = monthly_values
results[cte.MONTH] = monthly_values * cte.WATTS_HOUR_TO_JULES
results[cte.YEAR] = [max(monthly_values)] results[cte.YEAR] = [max(monthly_values)]
return results return results
@ -465,8 +455,7 @@ class Building(CityObject):
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
if monthly_values is None: if monthly_values is None:
return None return None
# todo: @Pilar!!!! results[cte.MONTH] = monthly_values
results[cte.MONTH] = monthly_values * cte.WATTS_HOUR_TO_JULES
results[cte.YEAR] = [max(monthly_values)] results[cte.YEAR] = [max(monthly_values)]
return results return results
@ -620,7 +609,7 @@ class Building(CityObject):
@property @property
def heating_consumption(self): 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 return: dict
""" """
if len(self._heating_consumption) == 0: if len(self._heating_consumption) == 0:
@ -636,7 +625,7 @@ class Building(CityObject):
@property @property
def cooling_consumption(self): 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 return: dict
""" """
if len(self._cooling_consumption) == 0: if len(self._cooling_consumption) == 0:
@ -652,7 +641,7 @@ class Building(CityObject):
@property @property
def domestic_hot_water_consumption(self): 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 return: dict
""" """
if len(self._domestic_hot_water_consumption) == 0: if len(self._domestic_hot_water_consumption) == 0:
@ -668,7 +657,7 @@ class Building(CityObject):
def _calculate_working_hours(self): def _calculate_working_hours(self):
_working_hours = {} _working_hours = {}
for internal_zone in self.internal_zones: 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 = {} _working_hours_per_thermal_zone = {}
for schedule in thermal_zone.thermal_control.hvac_availability_schedules: for schedule in thermal_zone.thermal_control.hvac_availability_schedules:
_working_hours_per_schedule = [0] * len(schedule.values) _working_hours_per_schedule = [0] * len(schedule.values)
@ -694,7 +683,7 @@ class Building(CityObject):
@property @property
def distribution_systems_electrical_consumption(self): 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 return: dict
""" """
if len(self._distribution_systems_electrical_consumption) != 0: if len(self._distribution_systems_electrical_consumption) != 0:
@ -769,7 +758,7 @@ class Building(CityObject):
@property @property
def onsite_electrical_production(self): def onsite_electrical_production(self):
""" """
Get total electricity produced onsite in J Get total electricity produced onsite in Wh
return: dict 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 import uuid
from typing import Union, List from typing import Union, List
from hub.city_model_structure.building_demand.usage import Usage 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_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.attributes.polyhedron import Polyhedron
from hub.city_model_structure.energy_systems.hvac_system import HvacSystem
class InternalZone: class InternalZone:
""" """
InternalZone class InternalZone class
""" """
def __init__(self, surfaces, area, volume, number_of_storeys=None): def __init__(self, surfaces, area):
self._surfaces = surfaces self._surfaces = surfaces
self._id = None self._id = None
self._geometry = None self._geometry = None
self._volume = volume self._volume = None
self._area = area self._area = area
self._number_of_storeys = number_of_storeys self._thermal_zones = None
self._thermal_zones_from_internal_zones = None
self._usages = None self._usages = None
self._thermal_archetype = None self._hvac_system = None
@property @property
def id(self): def id(self):
@ -66,7 +64,7 @@ class InternalZone:
Get internal zone volume in cubic meters Get internal zone volume in cubic meters
:return: float :return: float
""" """
return self._volume return self.geometry.volume
@property @property
def area(self): def area(self):
@ -76,18 +74,10 @@ class InternalZone:
""" """
return self._area return self._area
@property
def mean_height(self):
"""
Get internal zone mean height in meters
:return: float
"""
return self.volume / self.area
@property @property
def usages(self) -> [Usage]: def usages(self) -> [Usage]:
""" """
Get usage archetypes Get internal zone usage zones
:return: [Usage] :return: [Usage]
""" """
return self._usages return self._usages
@ -95,53 +85,39 @@ class InternalZone:
@usages.setter @usages.setter
def usages(self, value): def usages(self, value):
""" """
Set usage archetypes Set internal zone usage zones
:param value: [Usage] :param value: [Usage]
""" """
self._usages = value self._usages = value
@property @property
def thermal_archetype(self) -> ThermalArchetype: def hvac_system(self) -> Union[None, HvacSystem]:
""" """
Get thermal archetype parameters Get HVAC system installed for this thermal zone
:return: ThermalArchetype :return: None or HvacSystem
""" """
return self._thermal_archetype return self._hvac_system
@thermal_archetype.setter @hvac_system.setter
def thermal_archetype(self, value): def hvac_system(self, value):
""" """
Set thermal archetype parameters Set HVAC system installed for this thermal zone
:param value: ThermalArchetype :param value: HvacSystem
""" """
self._thermal_archetype = value self._hvac_system = value
@property @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] :return: [ThermalZone]
""" """
_thermal_boundaries = [] return self._thermal_zones
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
@thermal_zones_from_internal_zones.setter @thermal_zones.setter
def thermal_zones_from_internal_zones(self, value): def thermal_zones(self, value):
""" """
Set city object thermal zones as one per internal zone Set city object thermal zones
:param value: [ThermalZone] :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 Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
import uuid import uuid
from typing import Union from typing import Union
from hub.city_model_structure.building_demand.material import Material
class Layer: class Layer:
@ -14,17 +14,9 @@ class Layer:
Layer class Layer class
""" """
def __init__(self): def __init__(self):
self._material = None
self._thickness = None self._thickness = None
self._id = 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 @property
def id(self): def id(self):
@ -36,6 +28,22 @@ class Layer:
self._id = uuid.uuid4() self._id = uuid.uuid4()
return self._id 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 @property
def thickness(self) -> Union[None, float]: def thickness(self) -> Union[None, float]:
""" """
@ -52,155 +60,3 @@ class Layer:
""" """
if value is not None: if value is not None:
self._thickness = float(value) 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 @property
def global_irradiance(self) -> dict: def global_irradiance(self) -> dict:
""" """
Get global irradiance on surface in J/m2 Get global irradiance on surface in Wh/m2
:return: dict :return: dict
""" """
return self._global_irradiance return self._global_irradiance
@ -186,7 +186,7 @@ class Surface:
@global_irradiance.setter @global_irradiance.setter
def global_irradiance(self, value): def global_irradiance(self, value):
""" """
Set global irradiance on surface in J/m2 Set global irradiance on surface in Wh/m2
:param value: dict :param value: dict
""" """
self._global_irradiance = value 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 uuid
import math
from typing import List, Union, TypeVar from typing import List, Union, TypeVar
import logging
from hub.helpers.configuration_helper import ConfigurationHelper as ch from hub.helpers.configuration_helper import ConfigurationHelper as ch
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.city_model_structure.building_demand.layer import Layer from hub.city_model_structure.building_demand.layer import Layer
@ -37,8 +35,7 @@ class ThermalBoundary:
self._construction_name = None self._construction_name = None
self._thickness = None self._thickness = None
self._internal_surface = None self._internal_surface = None
self._external_surface = None self._window_ratio = None
self._window_ratio = 0
self._window_ratio_to_be_calculated = False self._window_ratio_to_be_calculated = False
if self._windows_areas is not None: if self._windows_areas is not None:
self._window_ratio_to_be_calculated = True self._window_ratio_to_be_calculated = True
@ -56,7 +53,7 @@ class ThermalBoundary:
@property @property
def parent_surface(self) -> Surface: 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: Surface
""" """
return self._parent_surface return self._parent_surface
@ -95,7 +92,7 @@ class ThermalBoundary:
self._thickness = 0.0 self._thickness = 0.0
if self.layers is not None: if self.layers is not None:
for layer in self.layers: for layer in self.layers:
if not layer.no_mass: if not layer.material.no_mass:
self._thickness += layer.thickness self._thickness += layer.thickness
return self._thickness return self._thickness
@ -151,21 +148,24 @@ class ThermalBoundary:
else: else:
_area = self.opaque_area * self.window_ratio / (1-self.window_ratio) _area = self.opaque_area * self.window_ratio / (1-self.window_ratio)
_thermal_opening.area = _area _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 return self._thermal_openings
@property @property
def _construction_archetype(self): def construction_name(self) -> Union[None, str]:
construction_archetypes = self.thermal_zones[0].parent_internal_zone.thermal_archetype.constructions """
for construction_archetype in construction_archetypes: Get construction name
if str(self.type) == str(construction_archetype.type): :return: None or str
return construction_archetype """
return None 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 @property
def layers(self) -> List[Layer]: def layers(self) -> List[Layer]:
@ -173,13 +173,16 @@ class ThermalBoundary:
Get thermal boundary layers Get thermal boundary layers
:return: [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 return self._layers
@layers.setter
def layers(self, value):
"""
Set thermal boundary layers
:param value: [Layer]
"""
self._layers = value
@property @property
def type(self): def type(self):
""" """
@ -206,23 +209,18 @@ class ThermalBoundary:
for window_area in self.windows_areas: for window_area in self.windows_areas:
total_window_area += window_area total_window_area += window_area
self._window_ratio = total_window_area / (self.opaque_area + total_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 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 @property
def windows_areas(self) -> [float]: def windows_areas(self) -> [float]:
""" """
@ -247,10 +245,10 @@ class ThermalBoundary:
r_value = 1.0/h_i + 1.0/h_e r_value = 1.0/h_i + 1.0/h_e
try: try:
for layer in self.layers: for layer in self.layers:
if layer.no_mass: if layer.material.no_mass:
r_value += float(layer.thermal_resistance) r_value += float(layer.material.thermal_resistance)
else: 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 self._u_value = 1.0/r_value
except TypeError: except TypeError:
raise TypeError('Constructions layers are not initialized') from TypeError raise TypeError('Constructions layers are not initialized') from TypeError
@ -307,18 +305,4 @@ class ThermalBoundary:
""" """
if self._internal_surface is None: if self._internal_surface is None:
self._internal_surface = self.parent_surface.inverse 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 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 ThermalZone class
""" """
def __init__(self, thermal_boundaries, def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage_name=None):
parent_internal_zone,
volume,
footprint_area,
number_of_storeys,
usage_name=None):
self._id = None self._id = None
self._parent_internal_zone = parent_internal_zone self._parent_internal_zone = parent_internal_zone
self._footprint_area = footprint_area self._footprint_area = footprint_area
@ -48,7 +43,6 @@ class ThermalZone:
self._ordinate_number = None self._ordinate_number = None
self._view_factors_matrix = None self._view_factors_matrix = None
self._total_floor_area = None self._total_floor_area = None
self._number_of_storeys = number_of_storeys
self._usage_name = usage_name self._usage_name = usage_name
self._usage_from_parent = False self._usage_from_parent = False
if usage_name is None: if usage_name is None:
@ -64,14 +58,6 @@ class ThermalZone:
self._domestic_hot_water = None self._domestic_hot_water = None
self._usages = 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 @property
def usages(self): def usages(self):
""" """
@ -127,45 +113,83 @@ class ThermalZone:
Get thermal zone additional thermal bridge u value per footprint area W/m2K Get thermal zone additional thermal bridge u value per footprint area W/m2K
:return: None or float :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 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 @property
def effective_thermal_capacity(self) -> Union[None, float]: def effective_thermal_capacity(self) -> Union[None, float]:
""" """
Get thermal zone effective thermal capacity in J/m3K Get thermal zone effective thermal capacity in J/m3K
:return: None or float :return: None or float
""" """
self._effective_thermal_capacity = self._parent_internal_zone.thermal_archetype.thermal_capacity
return self._effective_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 @property
def indirectly_heated_area_ratio(self) -> Union[None, float]: def indirectly_heated_area_ratio(self) -> Union[None, float]:
""" """
Get thermal zone indirectly heated area ratio Get thermal zone indirectly heated area ratio
:return: None or float :return: None or float
""" """
self._indirectly_heated_area_ratio = self._parent_internal_zone.thermal_archetype.indirect_heated_ratio
return self._indirectly_heated_area_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 @property
def infiltration_rate_system_on(self): 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 :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 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 @property
def infiltration_rate_system_off(self): 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 :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 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 @property
def volume(self): def volume(self):
""" """
@ -197,44 +221,16 @@ class ThermalZone:
Get thermal zone view factors matrix Get thermal zone view factors matrix
:return: [[float]] :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 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 @property
def usage_name(self) -> Union[None, str]: def usage_name(self) -> Union[None, str]:
""" """
@ -289,7 +285,7 @@ class ThermalZone:
@property @property
def mechanical_air_change(self) -> Union[None, float]: 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 :return: None or float
""" """
if self.usages is None: if self.usages is None:
@ -657,8 +653,15 @@ class ThermalZone:
@property @property
def total_floor_area(self): 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 :return: float
""" """
self._total_floor_area = self.footprint_area * self._number_of_storeys
return self._total_floor_area 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 @property
def mechanical_air_change(self) -> Union[None, float]: 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: None or float
""" """
return self._mechanical_air_change return self._mechanical_air_change
@ -181,7 +181,7 @@ class Usage:
@mechanical_air_change.setter @mechanical_air_change.setter
def mechanical_air_change(self, value): 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 :param value: float
""" """
if value is not None: 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 @volume.setter
def volume(self, value): def volume(self, value):
"""
Set city object volume in cubic meters
:param value: float
"""
self._volume = value self._volume = value
@property @property
@ -208,7 +204,7 @@ class CityObject:
@property @property
def global_horizontal(self) -> dict: 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: dict{dict{[float]}}
""" """
return self._global_horizontal return self._global_horizontal
@ -216,7 +212,7 @@ class CityObject:
@global_horizontal.setter @global_horizontal.setter
def global_horizontal(self, value): 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]}} :param value: dict{dict{[float]}}
""" """
self._global_horizontal = value self._global_horizontal = value
@ -224,7 +220,7 @@ class CityObject:
@property @property
def diffuse(self) -> dict: 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: dict{dict{[float]}}
""" """
return self._diffuse return self._diffuse
@ -232,7 +228,7 @@ class CityObject:
@diffuse.setter @diffuse.setter
def diffuse(self, value): 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]}} :param value: dict{dict{[float]}}
""" """
self._diffuse = value self._diffuse = value
@ -240,7 +236,7 @@ class CityObject:
@property @property
def beam(self) -> dict: 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: dict{dict{[float]}}
""" """
return self._beam return self._beam
@ -248,7 +244,7 @@ class CityObject:
@beam.setter @beam.setter
def beam(self, value): 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]}} :param value: dict{dict{[float]}}
""" """
self._beam = value self._beam = value

View File

@ -69,7 +69,7 @@ class GenericDistributionSystem:
def distribution_consumption_variable_flow(self): def distribution_consumption_variable_flow(self):
""" """
Get distribution_consumption if the pump or fan work at variable mass or volume flow in ratio 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: float
""" """
return self._distribution_consumption_variable_flow return self._distribution_consumption_variable_flow
@ -78,7 +78,7 @@ class GenericDistributionSystem:
def distribution_consumption_variable_flow(self, value): def distribution_consumption_variable_flow(self, value):
""" """
Set distribution_consumption if the pump or fan work at variable mass or volume flow in ratio 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 :return: float
""" """
self._distribution_consumption_variable_flow = value 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): def _thermal_zones(self, building, city):
thermal_zones = [] thermal_zones = []
for internal_zone in building.internal_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 = [] usages = []
for usage in internal_zone.usages: for usage in internal_zone.usages:
usages.append({'@xlink:href': f'#GML_{usage.id}'}) usages.append({'@xlink:href': f'#GML_{usage.id}'})

View File

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

View File

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

View File

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

View File

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

View File

@ -46,11 +46,12 @@ class LoadsCalculation:
load_renovation_sensible = 0 load_renovation_sensible = 0
for usage in thermal_zone.usages: for usage in thermal_zone.usages:
load_renovation_sensible += cte.AIR_DENSITY * cte.AIR_HEAT_CAPACITY * usage.mechanical_air_change \ 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 = ( load_infiltration_sensible = (
cte.AIR_DENSITY * cte.AIR_HEAT_CAPACITY * thermal_zone.infiltration_rate_system_off * thermal_zone.volume cte.AIR_DENSITY * cte.AIR_HEAT_CAPACITY * thermal_zone.infiltration_rate_system_off * thermal_zone.volume /
* (internal_temperature - ambient_temperature) cte.HOUR_TO_MINUTES / cte.MINUTES_TO_SECONDS * (internal_temperature - ambient_temperature)
) )
load_ventilation = load_renovation_sensible + load_infiltration_sensible load_ventilation = load_renovation_sensible + load_infiltration_sensible
@ -64,7 +65,7 @@ class LoadsCalculation:
""" """
heating_load_transmitted = 0 heating_load_transmitted = 0
for internal_zone in self._building.internal_zones: 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 internal_temperature = thermal_zone.thermal_control.mean_heating_set_point
heating_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature, heating_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature,
ground_temperature) ground_temperature)
@ -77,7 +78,7 @@ class LoadsCalculation:
""" """
cooling_load_transmitted = 0 cooling_load_transmitted = 0
for internal_zone in self._building.internal_zones: 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 internal_temperature = thermal_zone.thermal_control.mean_cooling_set_point
cooling_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature, cooling_load_transmitted += self._get_load_transmitted(thermal_zone, internal_temperature, ambient_temperature,
ground_temperature) ground_temperature)
@ -90,7 +91,7 @@ class LoadsCalculation:
""" """
heating_ventilation_load = 0 heating_ventilation_load = 0
for internal_zone in self._building.internal_zones: 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 internal_temperature = thermal_zone.thermal_control.mean_heating_set_point
heating_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature) heating_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature)
return heating_ventilation_load return heating_ventilation_load
@ -102,7 +103,7 @@ class LoadsCalculation:
""" """
cooling_ventilation_load = 0 cooling_ventilation_load = 0
for internal_zone in self._building.internal_zones: 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 internal_temperature = thermal_zone.thermal_control.mean_cooling_set_point
cooling_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature) cooling_ventilation_load += self._get_load_ventilation(thermal_zone, internal_temperature, ambient_temperature)
return cooling_ventilation_load return cooling_ventilation_load
@ -116,7 +117,7 @@ class LoadsCalculation:
cooling_load_lighting = 0 cooling_load_lighting = 0
cooling_load_equipment_sensible = 0 cooling_load_equipment_sensible = 0
for internal_zone in self._building.internal_zones: 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 cooling_load_occupancy_sensible += (thermal_zone.occupancy.sensible_convective_internal_gain
+ thermal_zone.occupancy.sensible_radiative_internal_gain) \ + thermal_zone.occupancy.sensible_radiative_internal_gain) \
* thermal_zone.footprint_area * thermal_zone.footprint_area
@ -138,10 +139,10 @@ class LoadsCalculation:
""" """
cooling_load_radiation = 0 cooling_load_radiation = 0
for internal_zone in self._building.internal_zones: 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_boundary in thermal_zone.thermal_boundaries:
for thermal_opening in thermal_boundary.thermal_openings: 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 += ( cooling_load_radiation += (
thermal_opening.area * (1 - thermal_opening.frame_ratio) * thermal_opening.g_value * 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 logging
import math
import hub.helpers.constants as cte
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory 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.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class EilatPhysicsParameters: class EilatPhysicsParameters:
@ -33,7 +35,7 @@ class EilatPhysicsParameters:
eilat_catalog = ConstructionCatalogFactory('eilat').catalog eilat_catalog = ConstructionCatalogFactory('eilat').catalog
for building in city.buildings: for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_eilat_construction_function.keys(): 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 continue
function = Dictionaries().hub_function_to_eilat_construction_function[building.function] function = Dictionaries().hub_function_to_eilat_construction_function[building.function]
try: try:
@ -44,10 +46,29 @@ class EilatPhysicsParameters:
f'[%s], building year of construction: %s and climate zone %s', building.name, function, f'[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, self._climate_zone) building.function, building.year_of_construction, self._climate_zone)
continue 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: 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 @staticmethod
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone): def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
@ -60,51 +81,133 @@ class EilatPhysicsParameters:
raise KeyError('archetype not found') raise KeyError('archetype not found')
@staticmethod @staticmethod
def _assign_values(thermal_archetype, catalog_archetype): def _search_construction_in_archetype(archetype, construction_type):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height construction_archetypes = archetype.constructions
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges for construction_archetype in construction_archetypes:
thermal_archetype.indirect_heated_ratio = 0 if str(construction_type) == str(construction_archetype.type):
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on return construction_archetype
thermal_archetype.infiltration_rate_for_ventilation_system_off = catalog_archetype.infiltration_rate_for_ventilation_system_off return None
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
if catalog_construction.window is not None: def _assign_values(self, thermal_zones, archetype):
window_archetype = catalog_construction.window for thermal_zone in thermal_zones:
construction.window_frame_ratio = window_archetype.frame_ratio thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
construction.window_g_value = window_archetype.g_value effective_thermal_capacity = 0
construction.window_overall_u_value = window_archetype.overall_u_value thermal_zone.indirectly_heated_area_ratio = 0
_constructions.append(construction) thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_archetype.constructions = _constructions thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
thermal_archetype.thermal_capacity = effective_thermal_capacity 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 Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from hub.helpers import constants as cte
class ConstructionHelper: class ConstructionHelper:
""" """

View File

@ -6,13 +6,15 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
import logging import logging
import math
import hub.helpers.constants as cte
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory 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.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class NrcanPhysicsParameters: class NrcanPhysicsParameters:
@ -33,7 +35,7 @@ class NrcanPhysicsParameters:
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
for building in city.buildings: for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_nrcan_construction_function.keys(): 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 continue
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function] function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
try: try:
@ -44,10 +46,29 @@ class NrcanPhysicsParameters:
f'[%s], building year of construction: %s and climate zone %s', building.name, function, f'[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, self._climate_zone) building.function, building.year_of_construction, self._climate_zone)
continue 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: 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 @staticmethod
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone): def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
@ -60,45 +81,126 @@ class NrcanPhysicsParameters:
raise KeyError('archetype not found') raise KeyError('archetype not found')
@staticmethod @staticmethod
def _assign_values(thermal_archetype, catalog_archetype): def _search_construction_in_archetype(archetype, construction_type):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height construction_archetypes = archetype.constructions
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges for construction_archetype in construction_archetypes:
thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity if str(construction_type) == str(construction_archetype.type):
thermal_archetype.indirect_heated_ratio = 0 return construction_archetype
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on return None
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
if catalog_construction.window is not None: def _assign_values(self, thermal_zones, archetype):
window_archetype = catalog_construction.window for thermal_zone in thermal_zones:
construction.window_frame_ratio = window_archetype.frame_ratio thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
construction.window_g_value = window_archetype.g_value thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
construction.window_overall_u_value = window_archetype.overall_u_value thermal_zone.indirectly_heated_area_ratio = 0
_constructions.append(construction) thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_archetype.constructions = _constructions 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 import logging
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory 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.layer import Layer
from hub.city_model_structure.building_demand.material import Material
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper from hub.imports.construction.helpers.construction_helper import ConstructionHelper
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
class NrelPhysicsParameters: class NrelPhysicsParameters:
@ -44,10 +44,28 @@ class NrelPhysicsParameters:
f' and climate zone {self._climate_zone}\n') f' and climate zone {self._climate_zone}\n')
continue continue
thermal_archetype = ThermalArchetype() # if building has no thermal zones defined from geometry, and the building will be divided in storeys,
self._assign_values(thermal_archetype, archetype) # 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: 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 @staticmethod
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone): def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
@ -62,46 +80,111 @@ class NrelPhysicsParameters:
raise KeyError('archetype not found') raise KeyError('archetype not found')
@staticmethod @staticmethod
def _assign_values(thermal_archetype, catalog_archetype): def _search_construction_in_archetype(archetype, construction_type):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height construction_archetypes = archetype.constructions
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges for construction_archetype in construction_archetypes:
thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity if str(construction_type) == str(construction_archetype.type):
thermal_archetype.indirect_heated_ratio = catalog_archetype.indirect_heated_ratio return construction_archetype
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on return None
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
if catalog_construction.window is not None: def _assign_values(self, thermal_zones, archetype):
window_archetype = catalog_construction.window for thermal_zone in thermal_zones:
construction.window_frame_ratio = window_archetype.frame_ratio thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
construction.window_g_value = window_archetype.g_value thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
construction.window_overall_u_value = window_archetype.overall_u_value thermal_zone.indirectly_heated_area_ratio = archetype.indirect_heated_ratio
_constructions.append(construction) thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
thermal_archetype.constructions = _constructions 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() demand = str(line).replace("['", '').replace("']", '').split()
for i in range(0, 2): for i in range(0, 2):
if demand[i] != 'NaN': 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) demand[i] = str(aux)
else: else:
demand[i] = '0' demand[i] = '0'
@ -43,12 +43,12 @@ class InselMonthlyEnergyBalance:
domestic_hot_water_demand = [] domestic_hot_water_demand = []
lighting_demand = [] lighting_demand = []
appliances_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 domestic_hot_water_demand = [0] * 12
lighting_demand = [0] * 12 lighting_demand = [0] * 12
appliances_demand = [0] * 12 appliances_demand = [0] * 12
else: 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 area = thermal_zone.total_floor_area
cold_water = building.cold_water_temperature[cte.MONTH] cold_water = building.cold_water_temperature[cte.MONTH]
peak_flow = thermal_zone.domestic_hot_water.peak_flow peak_flow = thermal_zone.domestic_hot_water.peak_flow
@ -66,8 +66,7 @@ class InselMonthlyEnergyBalance:
for value in schedule.values: for value in schedule.values:
total_day += value total_day += value
for day_type in schedule.day_types: for day_type in schedule.day_types:
total_lighting += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] \ total_lighting += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * lighting_density
* lighting_density / cte.WATTS_HOUR_TO_JULES
lighting_demand.append(total_lighting * area) lighting_demand.append(total_lighting * area)
for schedule in thermal_zone.appliances.schedules: for schedule in thermal_zone.appliances.schedules:
@ -75,8 +74,7 @@ class InselMonthlyEnergyBalance:
for value in schedule.values: for value in schedule.values:
total_day += value total_day += value
for day_type in schedule.day_types: for day_type in schedule.day_types:
total_appliances += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] \ total_appliances += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * appliances_density
* appliances_density / cte.WATTS_HOUR_TO_JULES
appliances_demand.append(total_appliances * area) appliances_demand.append(total_appliances * area)
for schedule in thermal_zone.domestic_hot_water.schedules: for schedule in thermal_zone.domestic_hot_water.schedules:
@ -85,8 +83,7 @@ class InselMonthlyEnergyBalance:
total_day += value total_day += value
for day_type in schedule.day_types: for day_type in schedule.day_types:
demand = ( demand = (
peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY * (service_temperature - cold_water[month])
* (service_temperature - cold_water[month]) / cte.WATTS_HOUR_TO_JULES
) )
total_dhw_demand += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * demand total_dhw_demand += total_day * cte.WEEK_DAYS_A_MONTH[day_type][month] * demand
domestic_hot_water_demand.append(total_dhw_demand * area) domestic_hot_water_demand.append(total_dhw_demand * area)
@ -100,15 +97,14 @@ class InselMonthlyEnergyBalance:
def enrich(self): 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 :return: None
""" """
for building in self._city.buildings: for building in self._city.buildings:
file_name = building.name + '.out' file_name = building.name + '.out'
insel_output_file_path = Path(self._base_path / file_name).resolve() insel_output_file_path = Path(self._base_path / file_name).resolve()
if insel_output_file_path.is_file(): if insel_output_file_path.is_file():
building.heating_demand[cte.MONTH], building.cooling_demand[cte.MONTH] \ building.heating_demand[cte.MONTH], building.cooling_demand[cte.MONTH] = self._conditioning_demand(insel_output_file_path)
= self._conditioning_demand(insel_output_file_path)
building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.MONTH])] building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.MONTH])]
building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.MONTH])] building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.MONTH])]
self._dhw_and_electric_demand() self._dhw_and_electric_demand()

View File

@ -34,8 +34,7 @@ class SimplifiedRadiosityAlgorithm:
for key in self._results: for key in self._results:
_irradiance = {} _irradiance = {}
header_name = key.split(':') header_name = key.split(':')
# todo: @Pilar!!!!!!!!!!!!!!!!!!!!!!!! result = self._results[key]
result = self._results[key] / cte.WATTS_HOUR_TO_JULES
city_object_name = header_name[1] city_object_name = header_name[1]
building = self._city.city_object(city_object_name) building = self._city.city_object(city_object_name)
surface_id = header_name[2] 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 # 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. # usage.occupancy when writing usage.occupancy = archetype.occupancy.
# Same happens for lighting and appliances. Therefore, this walk around has been done. # 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()
_occupancy.occupancy_density = archetype.occupancy.occupancy_density _occupancy.occupancy_density = archetype.occupancy.occupancy_density
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain _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 # 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. # usage.occupancy when writing usage.occupancy = archetype.occupancy.
# Same happens for lighting and appliances. Therefore, this walk around has been done. # 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()
_occupancy.occupancy_density = archetype.occupancy.occupancy_density _occupancy.occupancy_density = archetype.occupancy.occupancy_density
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain _occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain

View File

@ -92,11 +92,11 @@ class NrcanUsageParameters:
@staticmethod @staticmethod
def _assign_values(usage, archetype, volume_per_area, cold_water_temperature): def _assign_values(usage, archetype, volume_per_area, cold_water_temperature):
if archetype.mechanical_air_change > 0: if archetype.mechanical_air_change > 0:
# 1/s # ACH
usage.mechanical_air_change = archetype.mechanical_air_change usage.mechanical_air_change = archetype.mechanical_air_change
elif archetype.ventilation_rate > 0: elif archetype.ventilation_rate > 0:
# m3/m2.s to 1/s # m3/m2.s to ACH
usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area * cte.HOUR_TO_SECONDS
else: else:
usage.mechanical_air_change = 0 usage.mechanical_air_change = 0
_occupancy = Occupancy() _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']) # 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 # 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.external_temperature[cte.HOUR] = self._weather_values['dry_bulb_temperature_c']
building.global_horizontal[cte.HOUR] = self._weather_values[ building.global_horizontal[cte.HOUR] = self._weather_values['global_horizontal_radiation_wh_m2']
'global_horizontal_radiation_wh_m2'] / cte.WATTS_HOUR_TO_JULES building.diffuse[cte.HOUR] = self._weather_values['diffuse_horizontal_radiation_wh_m2']
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']
building.beam[cte.HOUR] = self._weather_values['direct_normal_radiation_wh_m2'] / cte.WATTS_HOUR_TO_JULES
building.cold_water_temperature[cte.HOUR] = wh().cold_water_temperature(building.external_temperature[cte.HOUR]) 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 # create the monthly and yearly values out of the hourly

View File

@ -60,7 +60,7 @@ class CityObject(Models):
self.wall_area = wall_area self.wall_area = wall_area
window_ratio = 0 window_ratio = 0
for internal_zone in building.internal_zones: 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: for thermal_boundary in thermal_zone.thermal_boundaries:
window_ratio = thermal_boundary.window_ratio window_ratio = thermal_boundary.window_ratio
break break

View File

@ -106,7 +106,7 @@ class TestConstructionFactory(TestCase):
self.assertIsNotNone(building.shell, 'building shell is none') self.assertIsNotNone(building.shell, 'building shell is none')
def _check_thermal_zones(self, internal_zone): 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.id, 'thermal_zone id is none')
self.assertIsNotNone(thermal_zone.footprint_area, 'thermal_zone floor area 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') 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.thickness, 'thermal_boundary thickness is none')
self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type 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.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.assertIsNotNone(thermal_boundary.window_ratio, 'window_ratio is none')
self.assertIsNone(thermal_boundary.windows_areas, 'windows_areas is not none') self.assertIsNone(thermal_boundary.windows_areas, 'windows_areas is not none')
self.assertIsNotNone(thermal_boundary.u_value, 'u_value is 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): def _check_thermal_openings(self, thermal_boundary):
for thermal_opening in thermal_boundary.thermal_openings: for thermal_opening in thermal_boundary.thermal_openings:
self.assertIsNotNone(thermal_opening.id, 'thermal opening id is not none') 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.area, 'thermal opening area is not none')
self.assertIsNotNone(thermal_opening.frame_ratio, 'thermal opening frame_ratio is 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.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.overall_u_value, 'thermal opening overall_u_value is none')
self.assertIsNotNone(thermal_opening.hi, 'thermal opening hi 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.he, 'thermal opening he is none')
self.assertIsNotNone(thermal_opening.construction_name, 'thermal opening construction_name is none')
def _check_surfaces(self, thermal_boundary): def _check_surfaces(self, thermal_boundary):
external_surface = thermal_boundary.external_surface external_surface = thermal_boundary.parent_surface
internal_surface = thermal_boundary.internal_surface internal_surface = thermal_boundary.internal_surface
self.assertIsNotNone(external_surface.short_wave_reflectance, self.assertIsNotNone(external_surface.short_wave_reflectance,
'external surface short_wave_reflectance id is not none') 'external surface short_wave_reflectance id is not none')
@ -181,7 +184,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone) 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) self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -199,7 +202,25 @@ class TestConstructionFactory(TestCase):
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone) 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) self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -217,7 +238,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone) 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) self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -235,7 +256,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone) 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) self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -256,7 +277,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone) 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) self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -278,7 +299,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone) 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) self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
@ -300,7 +321,7 @@ class TestConstructionFactory(TestCase):
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone) 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) self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none')

View File

@ -51,8 +51,7 @@ class TestExports(TestCase):
_irradiance = {} _irradiance = {}
for key in self._results: for key in self._results:
header_name = key.split(':') header_name = key.split(':')
# todo: @Pilar!!!!!!!!!!!!!!!!!!!!!!!! result = self._results[key]
result = self._results[key] / cte.WATTS_HOUR_TO_JULES
city_object_name = header_name[1] city_object_name = header_name[1]
building = self._city.city_object(city_object_name) building = self._city.city_object(city_object_name)
surface_id = header_name[2] 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') self.assertIsNotNone(building.basement_heated, f'building {building.name} basement_heated is none')
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.area, f'internal zone {internal_zone.id} area is none') 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} ' self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, f'thermal zone {thermal_zone.id} '
f'indirectly_heated_area_ratio is none') f'indirectly_heated_area_ratio is none')
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, f'thermal zone {thermal_zone.id} ' 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: for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.type) self.assertIsNotNone(thermal_boundary.type)
self.assertIsNotNone(thermal_boundary.opaque_area) 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.u_value)
self.assertIsNotNone(thermal_boundary.thermal_openings) self.assertIsNotNone(thermal_boundary.thermal_openings)
if thermal_boundary.type is not cte.GROUND: 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: for usage in internal_zone.usages:
self.assertIsNotNone(usage.percentage, f'usage zone {usage.name} percentage is none') 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}, {'yearly_domestic_hot_water_consumption': yearly_domestic_hot_water_consumption},
{'monthly_distribution_systems_electrical_consumption': monthly_distribution_systems_electrical_consumption}, {'monthly_distribution_systems_electrical_consumption': monthly_distribution_systems_electrical_consumption},
{'yearly_distribution_systems_electrical_consumption': yearly_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}, {'monthly_on_site_electrical_production': monthly_on_site_electrical_production},
{'yearly_on_site_electrical_production': yearly_on_site_electrical_production * cte.WATTS_HOUR_TO_JULES} {'yearly_on_site_electrical_production': yearly_on_site_electrical_production}
]}) ]})
db_building_id = _building.id 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') self.assertIsNot(len(internal_zone.usages), 0, 'no building usages defined')
for usage in internal_zone.usages: for usage in internal_zone.usages:
self.assertIsNotNone(usage.id, 'usage id is none') 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) self._check_thermal_zone(thermal_zone)
def _check_buildings(self, city): def _check_buildings(self, city):
@ -46,7 +46,7 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(building.internal_zones, 'no internal zones created') self.assertIsNotNone(building.internal_zones, 'no internal zones created')
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.usages, 'usage zones are not defined') 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.basement_heated, 'building basement_heated is not none')
self.assertIsNone(building.attic_heated, 'building attic_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') self.assertIsNotNone(building.average_storey_height, 'building average_storey_height is none')
@ -105,7 +105,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet': if usage_key == 'comnet':
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: 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) self._check_extra_thermal_zone(thermal_zone)
# usage factory called first # usage factory called first
city = self._get_citygml(file) city = self._get_citygml(file)
@ -117,7 +117,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet': if usage_key == 'comnet':
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: 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) self._check_extra_thermal_zone(thermal_zone)
def _test_pluto(self, file): def _test_pluto(self, file):
@ -135,7 +135,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet': if usage_key == 'comnet':
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: 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) self._check_extra_thermal_zone(thermal_zone)
# usage factory called first # usage factory called first
city = self._get_citygml(file) city = self._get_citygml(file)
@ -147,7 +147,7 @@ class TestGeometryFactory(TestCase):
if usage_key == 'comnet': if usage_key == 'comnet':
for building in city.buildings: for building in city.buildings:
for internal_zone in building.internal_zones: 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) self._check_extra_thermal_zone(thermal_zone)
def test_enrichment(self): def test_enrichment(self):

View File

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

View File

@ -62,7 +62,7 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(building.internal_zones, 'building internal zones is none') self.assertIsNotNone(building.internal_zones, 'building internal zones is none')
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self.assertIsNone(internal_zone.usages, 'usage zones are defined') 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.basement_heated, 'building basement_heated is not none')
self.assertIsNone(building.attic_heated, 'building attic_heated is not none') self.assertIsNone(building.attic_heated, 'building attic_heated is not none')
self.assertIsNone(building.terrains, 'building terrains is not none') self.assertIsNone(building.terrains, 'building terrains is not none')

View File

@ -51,8 +51,7 @@ class TestExports(TestCase):
_irradiance = {} _irradiance = {}
for key in self._results: for key in self._results:
header_name = key.split(':') header_name = key.split(':')
# todo: @Pilar!!!!!!!!!!!!!!!!!!!!!!!! result = self._results[key]
result = self._results[key] / cte.WATTS_HOUR_TO_JULES
city_object_name = header_name[1] city_object_name = header_name[1]
building = self._city.city_object(city_object_name) building = self._city.city_object(city_object_name)
surface_id = header_name[2] 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') self.assertIsNotNone(building.basement_heated, f'building {building.name} basement_heated is none')
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
self.assertIsNotNone(internal_zone.area, f'internal zone {internal_zone.id} area is none') 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} ' self.assertIsNotNone(thermal_zone.indirectly_heated_area_ratio, f'thermal zone {thermal_zone.id} '
f'indirectly_heated_area_ratio is none') f'indirectly_heated_area_ratio is none')
self.assertIsNotNone(thermal_zone.effective_thermal_capacity, f'thermal zone {thermal_zone.id} ' 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.u_value)
self.assertIsNotNone(thermal_boundary.thermal_openings) self.assertIsNotNone(thermal_boundary.thermal_openings)
if thermal_boundary.type is not cte.GROUND: 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: for usage in internal_zone.usages:
self.assertIsNotNone(usage.percentage, f'usage zone {usage.name} percentage is none') 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.heating_consumption[cte.YEAR][0])
self.assertLess(0, building.cooling_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.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])