forked from s_ranjbar/city_retrofit
Merge disaster:
I do expect a lot of errors in this merge, this will be review later on, please don't rebase into this one
This commit is contained in:
commit
2ebec93ab4
125
hub/catalog_factories/construction/nrcan_catalog.py
Normal file
125
hub/catalog_factories/construction/nrcan_catalog.py
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
"""
|
||||||
|
NRCAN construction catalog
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
import xmltodict
|
||||||
|
|
||||||
|
from hub.catalog_factories.catalog import Catalog
|
||||||
|
from hub.catalog_factories.data_models.usages.content import Content
|
||||||
|
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
|
||||||
|
from hub.catalog_factories.data_models.construction.construction import Construction
|
||||||
|
from hub.catalog_factories.data_models.construction.archetype import Archetype
|
||||||
|
|
||||||
|
|
||||||
|
class NrcanCatalog(Catalog):
|
||||||
|
def __init__(self, path):
|
||||||
|
path = str(path / 'nrcan.xml')
|
||||||
|
self._content = None
|
||||||
|
self._g_value_per_hdd = []
|
||||||
|
self._thermal_transmittance_per_hdd_and_surface = {}
|
||||||
|
self._window_ratios = {}
|
||||||
|
with open(path) as xml:
|
||||||
|
self._metadata = xmltodict.parse(xml.read())
|
||||||
|
self._base_url_archetypes = self._metadata['nrcan']['@base_url_archetypes']
|
||||||
|
self._base_url_construction = self._metadata['nrcan']['@base_url_construction']
|
||||||
|
self._load_window_ratios()
|
||||||
|
self._load_construction_values()
|
||||||
|
self._content = Content(self._load_archetypes())
|
||||||
|
|
||||||
|
def _load_window_ratios(self):
|
||||||
|
for standard in self._metadata['nrcan']['standards_per_function']['standard']:
|
||||||
|
url = f'{self._base_url_archetypes}{standard["file_location"]}'
|
||||||
|
# todo: read from file
|
||||||
|
self._window_ratios = {'Mean': 0.2, 'North': 0.2, 'East': 0.2, 'South': 0.2, 'West': 0.2}
|
||||||
|
|
||||||
|
def _load_construction_values(self):
|
||||||
|
for standard in self._metadata['nrcan']['standards_per_period']['standard']:
|
||||||
|
g_value_url = f'{self._base_url_construction}{standard["g_value_location"]}'
|
||||||
|
punc = '()<?:'
|
||||||
|
with urllib.request.urlopen(g_value_url) as json_file:
|
||||||
|
text = json.load(json_file)['tables']['SHGC']['table'][0]['formula']
|
||||||
|
values = ''.join([o for o in list(text) if o not in punc]).split()
|
||||||
|
for index in range(int((len(values) - 1)/3)):
|
||||||
|
self._g_value_per_hdd.append([values[3*index+1], values[3*index+2]])
|
||||||
|
self._g_value_per_hdd.append(['15000', values[len(values)-1]])
|
||||||
|
|
||||||
|
construction_url = f'{self._base_url_construction}{standard["constructions_location"]}'
|
||||||
|
print(construction_url)
|
||||||
|
with urllib.request.urlopen(construction_url) as json_file:
|
||||||
|
cases = json.load(json_file)['tables']['surface_thermal_transmittance']['table']
|
||||||
|
# W/m2K
|
||||||
|
for case in cases:
|
||||||
|
surface = \
|
||||||
|
ConstructionHelper().nrcan_surfaces_types_to_hub_types[f"{case['surface']}_{case['boundary_condition']}"]
|
||||||
|
thermal_transmittance_per_hdd = []
|
||||||
|
text = case['formula']
|
||||||
|
values = ''.join([o for o in list(text) if o not in punc]).split()
|
||||||
|
for index in range(int((len(values) - 1)/3)):
|
||||||
|
thermal_transmittance_per_hdd.append([values[3*index+1], values[3*index+2]])
|
||||||
|
thermal_transmittance_per_hdd.append(['15000', values[len(values)-1]])
|
||||||
|
self._thermal_transmittance_per_hdd_and_surface[surface] = thermal_transmittance_per_hdd
|
||||||
|
|
||||||
|
def _load_constructions(self, window_ratio_standard, construction_standard):
|
||||||
|
constructions = []
|
||||||
|
# todo: we need to save the total transmittance somehow, we don't do it yet in our archetypes
|
||||||
|
# todo: it has to be selected the specific thermal_transmittance from
|
||||||
|
# self._thermal_transmittance_per_hdd_and_surface and window_ratios from self._window_ratios for each standard case
|
||||||
|
for i, surface_type in enumerate(self._thermal_transmittance_per_hdd_and_surface):
|
||||||
|
constructions.append(Construction(i, surface_type, None, None, self._window_ratios))
|
||||||
|
return constructions
|
||||||
|
|
||||||
|
def _load_archetypes(self):
|
||||||
|
archetypes = []
|
||||||
|
archetype_id = 0
|
||||||
|
for window_ratio_standard in self._metadata['nrcan']['standards_per_function']['standard']:
|
||||||
|
for construction_standard in self._metadata['nrcan']['standards_per_period']['standard']:
|
||||||
|
archetype_id += 1
|
||||||
|
function = window_ratio_standard['@function']
|
||||||
|
climate_zone = 'Montreal'
|
||||||
|
construction_period = construction_standard['@period_of_construction']
|
||||||
|
constructions = self._load_constructions(window_ratio_standard, construction_standard)
|
||||||
|
archetypes.append(Archetype(archetype_id,
|
||||||
|
None,
|
||||||
|
function,
|
||||||
|
climate_zone,
|
||||||
|
construction_period,
|
||||||
|
constructions,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None))
|
||||||
|
return archetypes
|
||||||
|
|
||||||
|
def names(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements names
|
||||||
|
:parm: for usage catalog category filter does nothing as there is only one category (usages)
|
||||||
|
"""
|
||||||
|
_names = {'usages': []}
|
||||||
|
for usage in self._content.usages:
|
||||||
|
_names['usages'].append(usage.name)
|
||||||
|
return _names
|
||||||
|
|
||||||
|
def entries(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements
|
||||||
|
:parm: for usage catalog category filter does nothing as there is only one category (usages)
|
||||||
|
"""
|
||||||
|
return self._content
|
||||||
|
|
||||||
|
def get_entry(self, name):
|
||||||
|
"""
|
||||||
|
Get one catalog element by names
|
||||||
|
:parm: entry name
|
||||||
|
"""
|
||||||
|
for usage in self._content.usages:
|
||||||
|
if usage.name.lower() == name.lower():
|
||||||
|
return usage
|
||||||
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -14,9 +14,7 @@ from hub.catalog_factories.data_models.construction.layer import Layer
|
||||||
from hub.catalog_factories.data_models.construction.construction import Construction
|
from hub.catalog_factories.data_models.construction.construction import Construction
|
||||||
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_helpers import nrel_to_function
|
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
|
||||||
from hub.catalog_factories.construction.construction_helpers import reference_standard_to_construction_period
|
|
||||||
from hub.catalog_factories.construction.construction_helpers import nrel_surfaces_types_to_hub_types
|
|
||||||
|
|
||||||
|
|
||||||
class NrelCatalog(Catalog):
|
class NrelCatalog(Catalog):
|
||||||
|
@ -89,7 +87,7 @@ class NrelCatalog(Catalog):
|
||||||
constructions = self._constructions['library']['constructions']['construction']
|
constructions = self._constructions['library']['constructions']['construction']
|
||||||
for construction in constructions:
|
for construction in constructions:
|
||||||
construction_id = construction['@id']
|
construction_id = construction['@id']
|
||||||
construction_type = nrel_surfaces_types_to_hub_types[construction['@type']]
|
construction_type = ConstructionHelper().nrel_surfaces_types_to_hub_types[construction['@type']]
|
||||||
name = construction['@name']
|
name = construction['@name']
|
||||||
layers = []
|
layers = []
|
||||||
for layer in construction['layers']['layer']:
|
for layer in construction['layers']['layer']:
|
||||||
|
@ -111,10 +109,11 @@ class NrelCatalog(Catalog):
|
||||||
archetypes = self._archetypes['archetypes']['archetype']
|
archetypes = self._archetypes['archetypes']['archetype']
|
||||||
for archetype in archetypes:
|
for archetype in archetypes:
|
||||||
archetype_id = archetype['@id']
|
archetype_id = archetype['@id']
|
||||||
function = nrel_to_function[archetype['@building_type']]
|
function = archetype['@building_type']
|
||||||
name = f"{function} {archetype['@climate_zone']} {archetype['@reference_standard']}"
|
name = f"{function} {archetype['@climate_zone']} {archetype['@reference_standard']}"
|
||||||
climate_zone = archetype['@climate_zone']
|
climate_zone = archetype['@climate_zone']
|
||||||
construction_period = reference_standard_to_construction_period[archetype['@reference_standard']]
|
construction_period = \
|
||||||
|
ConstructionHelper().reference_standard_to_construction_period[archetype['@reference_standard']]
|
||||||
average_storey_height = archetype['average_storey_height']['#text']
|
average_storey_height = archetype['average_storey_height']['#text']
|
||||||
thermal_capacity = str(float(archetype['thermal_capacity']['#text']) * 1000)
|
thermal_capacity = str(float(archetype['thermal_capacity']['#text']) * 1000)
|
||||||
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_to_thermal_bridges']['#text']
|
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_to_thermal_bridges']['#text']
|
||||||
|
|
|
@ -8,6 +8,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
from hub.catalog_factories.construction.nrel_catalog import NrelCatalog
|
from hub.catalog_factories.construction.nrel_catalog import NrelCatalog
|
||||||
|
from hub.catalog_factories.construction.nrcan_catalog import NrcanCatalog
|
||||||
Catalog = TypeVar('Catalog')
|
Catalog = TypeVar('Catalog')
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +26,13 @@ class ConstructionCatalogFactory:
|
||||||
"""
|
"""
|
||||||
return NrelCatalog(self._path)
|
return NrelCatalog(self._path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _nrcan(self):
|
||||||
|
"""
|
||||||
|
Retrieve NREL catalog
|
||||||
|
"""
|
||||||
|
return NrcanCatalog(self._path)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def catalog(self) -> Catalog:
|
def catalog(self) -> Catalog:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class InternalGain:
|
class InternalGain:
|
||||||
"""
|
"""
|
||||||
InternalGain class
|
InternalGain class
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Usage:
|
||||||
lighting,
|
lighting,
|
||||||
appliances,
|
appliances,
|
||||||
thermal_control):
|
thermal_control):
|
||||||
self._usage = usage
|
self._name = usage
|
||||||
self._hours_day = hours_day
|
self._hours_day = hours_day
|
||||||
self._days_year = days_year
|
self._days_year = days_year
|
||||||
self._mechanical_air_change = mechanical_air_change
|
self._mechanical_air_change = mechanical_air_change
|
||||||
|
@ -34,12 +34,12 @@ class Usage:
|
||||||
self._thermal_control = thermal_control
|
self._thermal_control = thermal_control
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage(self) -> Union[None, str]:
|
def name(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
Get usage zone usage
|
Get usage zone usage name
|
||||||
:return: None or str
|
:return: None or str
|
||||||
"""
|
"""
|
||||||
return self._usage
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hours_day(self) -> Union[None, float]:
|
def hours_day(self) -> Union[None, float]:
|
||||||
|
|
|
@ -28,6 +28,7 @@ class ComnetCatalog(Catalog):
|
||||||
self._archetypes = self._read_archetype_file()
|
self._archetypes = self._read_archetype_file()
|
||||||
self._schedules = self._read_schedules_file()
|
self._schedules = self._read_schedules_file()
|
||||||
|
|
||||||
|
# todo: comment with @Guille, this hypotheses should go in the import factory?
|
||||||
sensible_convective = ch().comnet_occupancy_sensible_convective
|
sensible_convective = ch().comnet_occupancy_sensible_convective
|
||||||
sensible_radiative = ch().comnet_occupancy_sensible_radiant
|
sensible_radiative = ch().comnet_occupancy_sensible_radiant
|
||||||
lighting_convective = ch().comnet_lighting_convective
|
lighting_convective = ch().comnet_lighting_convective
|
||||||
|
@ -41,7 +42,8 @@ class ComnetCatalog(Catalog):
|
||||||
for schedule_key in self._archetypes['schedules_key']:
|
for schedule_key in self._archetypes['schedules_key']:
|
||||||
comnet_usage = schedule_key
|
comnet_usage = schedule_key
|
||||||
schedule_name = self._archetypes['schedules_key'][schedule_key]
|
schedule_name = self._archetypes['schedules_key'][schedule_key]
|
||||||
hours_day = self._calculate_hours_day(schedule_name)
|
hours_day = None
|
||||||
|
days_year = None
|
||||||
occupancy_archetype = self._archetypes['occupancy'][comnet_usage]
|
occupancy_archetype = self._archetypes['occupancy'][comnet_usage]
|
||||||
lighting_archetype = self._archetypes['lighting'][comnet_usage]
|
lighting_archetype = self._archetypes['lighting'][comnet_usage]
|
||||||
appliances_archetype = self._archetypes['plug loads'][comnet_usage]
|
appliances_archetype = self._archetypes['plug loads'][comnet_usage]
|
||||||
|
@ -86,29 +88,9 @@ class ComnetCatalog(Catalog):
|
||||||
self._schedules[schedule_name]['Receptacle'])
|
self._schedules[schedule_name]['Receptacle'])
|
||||||
|
|
||||||
# get thermal control
|
# get thermal control
|
||||||
max_heating_setpoint = cte.MIN_FLOAT
|
thermal_control = ThermalControl(None,
|
||||||
min_heating_setpoint = cte.MAX_FLOAT
|
None,
|
||||||
|
None,
|
||||||
for schedule in self._schedules[schedule_name]['HtgSetPt']:
|
|
||||||
if schedule.values is None:
|
|
||||||
max_heating_setpoint = None
|
|
||||||
min_heating_setpoint = None
|
|
||||||
break
|
|
||||||
if max(schedule.values) > max_heating_setpoint:
|
|
||||||
max_heating_setpoint = max(schedule.values)
|
|
||||||
if min(schedule.values) < min_heating_setpoint:
|
|
||||||
min_heating_setpoint = min(schedule.values)
|
|
||||||
|
|
||||||
min_cooling_setpoint = cte.MAX_FLOAT
|
|
||||||
for schedule in self._schedules[schedule_name]['ClgSetPt']:
|
|
||||||
if schedule.values is None:
|
|
||||||
min_cooling_setpoint = None
|
|
||||||
break
|
|
||||||
if min(schedule.values) < min_cooling_setpoint:
|
|
||||||
min_cooling_setpoint = min(schedule.values)
|
|
||||||
thermal_control = ThermalControl(max_heating_setpoint,
|
|
||||||
min_heating_setpoint,
|
|
||||||
min_cooling_setpoint,
|
|
||||||
self._schedules[schedule_name]['HVAC Avail'],
|
self._schedules[schedule_name]['HVAC Avail'],
|
||||||
self._schedules[schedule_name]['HtgSetPt'],
|
self._schedules[schedule_name]['HtgSetPt'],
|
||||||
self._schedules[schedule_name]['ClgSetPt']
|
self._schedules[schedule_name]['ClgSetPt']
|
||||||
|
@ -116,7 +98,7 @@ class ComnetCatalog(Catalog):
|
||||||
|
|
||||||
usages.append(Usage(comnet_usage,
|
usages.append(Usage(comnet_usage,
|
||||||
hours_day,
|
hours_day,
|
||||||
365,
|
days_year,
|
||||||
mechanical_air_change,
|
mechanical_air_change,
|
||||||
ventilation_rate,
|
ventilation_rate,
|
||||||
occupancy,
|
occupancy,
|
||||||
|
@ -202,16 +184,6 @@ class ComnetCatalog(Catalog):
|
||||||
'schedules_key': schedules_key
|
'schedules_key': schedules_key
|
||||||
}
|
}
|
||||||
|
|
||||||
def _calculate_hours_day(self, function):
|
|
||||||
days = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY, cte.SATURDAY, cte.SUNDAY, cte.HOLIDAY]
|
|
||||||
number_of_days_per_type = [51, 50, 50, 50, 50, 52, 52, 10]
|
|
||||||
total = 0
|
|
||||||
for schedule in self._schedules[function]['HVAC Avail']:
|
|
||||||
yearly_days = number_of_days_per_type[days.index(schedule.day_types[0])]
|
|
||||||
for value in schedule.values:
|
|
||||||
total += value * yearly_days
|
|
||||||
return total / 365
|
|
||||||
|
|
||||||
def names(self, category=None):
|
def names(self, category=None):
|
||||||
"""
|
"""
|
||||||
Get the catalog elements names
|
Get the catalog elements names
|
||||||
|
@ -219,7 +191,7 @@ class ComnetCatalog(Catalog):
|
||||||
"""
|
"""
|
||||||
_names = {'usages': []}
|
_names = {'usages': []}
|
||||||
for usage in self._content.usages:
|
for usage in self._content.usages:
|
||||||
_names['usages'].append(usage.usage)
|
_names['usages'].append(usage.name)
|
||||||
return _names
|
return _names
|
||||||
|
|
||||||
def entries(self, category=None):
|
def entries(self, category=None):
|
||||||
|
@ -235,6 +207,6 @@ class ComnetCatalog(Catalog):
|
||||||
:parm: entry name
|
:parm: entry name
|
||||||
"""
|
"""
|
||||||
for usage in self._content.usages:
|
for usage in self._content.usages:
|
||||||
if usage.usage.lower() == name.lower():
|
if usage.name.lower() == name.lower():
|
||||||
return usage
|
return usage
|
||||||
raise IndexError(f"{name} doesn't exists in the catalog")
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
||||||
|
|
|
@ -3,6 +3,7 @@ NRCAN usage catalog
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
@ -32,10 +33,6 @@ class NrcanCatalog(Catalog):
|
||||||
self._load_schedules()
|
self._load_schedules()
|
||||||
self._content = Content(self._load_archetypes())
|
self._content = Content(self._load_archetypes())
|
||||||
|
|
||||||
def _calculate_hours_day(self, function):
|
|
||||||
# todo: pilar need to check how to calculate this value
|
|
||||||
return 24
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_schedule(raw):
|
def _extract_schedule(raw):
|
||||||
nrcan_schedule_type = raw['category']
|
nrcan_schedule_type = raw['category']
|
||||||
|
@ -54,59 +51,84 @@ class NrcanCatalog(Catalog):
|
||||||
return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types)
|
return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types)
|
||||||
|
|
||||||
def _load_schedules(self):
|
def _load_schedules(self):
|
||||||
usage = self._metadata['nrcan']['standards']['usage']
|
usage = self._metadata['nrcan']
|
||||||
url = f'{self._base_url}{usage["schedules_location"]}'
|
url = f'{self._base_url}{usage["schedules_location"]}'
|
||||||
|
_schedule_types = []
|
||||||
with urllib.request.urlopen(url) as json_file:
|
with urllib.request.urlopen(url) as json_file:
|
||||||
schedules_type = json.load(json_file)
|
schedules_type = json.load(json_file)
|
||||||
for schedule_type in schedules_type['tables']['schedules']['table']:
|
for schedule_type in schedules_type['tables']['schedules']['table']:
|
||||||
schedule = NrcanCatalog._extract_schedule(schedule_type)
|
schedule = NrcanCatalog._extract_schedule(schedule_type)
|
||||||
|
if schedule_type['name'] not in _schedule_types:
|
||||||
|
_schedule_types.append(schedule_type['name'])
|
||||||
if schedule is not None:
|
if schedule is not None:
|
||||||
self._schedules[schedule_type['name']] = schedule
|
self._schedules[schedule_type['name']] = [schedule]
|
||||||
|
else:
|
||||||
|
if schedule is not None:
|
||||||
|
_schedules = self._schedules[schedule_type['name']]
|
||||||
|
_schedules.append(schedule)
|
||||||
|
self._schedules[schedule_type['name']] = _schedules
|
||||||
|
|
||||||
def _get_schedule(self, name):
|
def _get_schedules(self, name):
|
||||||
if name in self._schedules:
|
if name in self._schedules:
|
||||||
return self._schedules[name]
|
return self._schedules[name]
|
||||||
|
|
||||||
def _load_archetypes(self):
|
def _load_archetypes(self):
|
||||||
usages = []
|
usages = []
|
||||||
usage = self._metadata['nrcan']['standards']['usage']
|
name = self._metadata['nrcan']
|
||||||
url = f'{self._base_url}{usage["space_types_location"]}'
|
url = f'{self._base_url}{name["space_types_location"]}'
|
||||||
with urllib.request.urlopen(url) as json_file:
|
with urllib.request.urlopen(url) as json_file:
|
||||||
space_types = json.load(json_file)['tables']['space_types']['table']
|
space_types = json.load(json_file)['tables']['space_types']['table']
|
||||||
space_types = [st for st in space_types if st['building_type'] == 'Space Function']
|
# space_types = [st for st in space_types if st['building_type'] == 'Space Function']
|
||||||
|
space_types = [st for st in space_types if st['space_type'] == 'WholeBuilding']
|
||||||
for space_type in space_types:
|
for space_type in space_types:
|
||||||
usage_type = space_type['space_type']
|
# usage_type = space_type['space_type']
|
||||||
mechanical_air_change = space_type['ventilation_air_changes']
|
usage_type = space_type['building_type']
|
||||||
ventilation_rate = space_type['ventilation_per_area']
|
|
||||||
if ventilation_rate == 0:
|
|
||||||
ventilation_rate = space_type['ventilation_per_person']
|
|
||||||
hours_day = self._calculate_hours_day(usage_type)
|
|
||||||
days_year = 365
|
|
||||||
occupancy_schedule_name = space_type['occupancy_schedule']
|
occupancy_schedule_name = space_type['occupancy_schedule']
|
||||||
lighting_schedule_name = space_type['lighting_schedule']
|
lighting_schedule_name = space_type['lighting_schedule']
|
||||||
appliance_schedule_name = space_type['electric_equipment_schedule']
|
appliance_schedule_name = space_type['electric_equipment_schedule']
|
||||||
# thermal control
|
hvac_schedule_name = space_type['exhaust_schedule']
|
||||||
|
if 'FAN' in hvac_schedule_name:
|
||||||
|
hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan')
|
||||||
heating_setpoint_schedule_name = space_type['heating_setpoint_schedule']
|
heating_setpoint_schedule_name = space_type['heating_setpoint_schedule']
|
||||||
cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule']
|
cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule']
|
||||||
occupancy_schedule = self._get_schedule(occupancy_schedule_name)
|
occupancy_schedule = self._get_schedules(occupancy_schedule_name)
|
||||||
lighting_schedule = self._get_schedule(lighting_schedule_name)
|
lighting_schedule = self._get_schedules(lighting_schedule_name)
|
||||||
appliance_schedule = self._get_schedule(appliance_schedule_name)
|
appliance_schedule = self._get_schedules(appliance_schedule_name)
|
||||||
heating_schedule = self._get_schedule(heating_setpoint_schedule_name)
|
heating_schedule = self._get_schedules(heating_setpoint_schedule_name)
|
||||||
cooling_schedule = self._get_schedule(cooling_setpoint_schedule_name)
|
cooling_schedule = self._get_schedules(cooling_setpoint_schedule_name)
|
||||||
|
hvac_availability = self._get_schedules(hvac_schedule_name)
|
||||||
|
|
||||||
occupancy_density = space_type['occupancy_per_area']
|
occupancy_density = space_type['occupancy_per_area']
|
||||||
lighting_density = space_type['lighting_per_area']
|
|
||||||
|
# ACH
|
||||||
|
mechanical_air_change = space_type['ventilation_air_changes']
|
||||||
|
# cfm/ft2 to m3/m2.s
|
||||||
|
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
|
||||||
|
if ventilation_rate == 0:
|
||||||
|
# cfm/person to m3/m2.s
|
||||||
|
ventilation_rate = space_type['ventilation_per_person'] / occupancy_density\
|
||||||
|
/ (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
|
||||||
|
|
||||||
|
# W/sqft to W/m2
|
||||||
|
lighting_density = space_type['lighting_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET
|
||||||
lighting_radiative_fraction = space_type['lighting_fraction_radiant']
|
lighting_radiative_fraction = space_type['lighting_fraction_radiant']
|
||||||
|
lighting_convective_fraction = 0
|
||||||
if lighting_radiative_fraction is not None:
|
if lighting_radiative_fraction is not None:
|
||||||
lighting_convective_fraction = 1 - lighting_radiative_fraction
|
lighting_convective_fraction = 1 - lighting_radiative_fraction
|
||||||
lighting_latent_fraction = 0
|
lighting_latent_fraction = 0
|
||||||
appliances_density = space_type['electric_equipment_per_area']
|
# W/sqft to W/m2
|
||||||
|
appliances_density = space_type['electric_equipment_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET
|
||||||
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
|
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
|
||||||
if appliances_radiative_fraction is not None:
|
|
||||||
appliances_convective_fraction = 1 - appliances_radiative_fraction
|
|
||||||
appliances_latent_fraction = space_type['electric_equipment_fraction_latent']
|
appliances_latent_fraction = space_type['electric_equipment_fraction_latent']
|
||||||
|
appliances_convective_fraction = 0
|
||||||
|
if appliances_radiative_fraction is not None and appliances_latent_fraction is not None:
|
||||||
|
appliances_convective_fraction = 1 - appliances_radiative_fraction - appliances_latent_fraction
|
||||||
|
|
||||||
occupancy = Occupancy(occupancy_density, 0, 0, 0, occupancy_schedule)
|
occupancy = Occupancy(occupancy_density,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
occupancy_schedule)
|
||||||
lighting = Lighting(lighting_density,
|
lighting = Lighting(lighting_density,
|
||||||
lighting_convective_fraction,
|
lighting_convective_fraction,
|
||||||
lighting_radiative_fraction,
|
lighting_radiative_fraction,
|
||||||
|
@ -117,20 +139,14 @@ class NrcanCatalog(Catalog):
|
||||||
appliances_radiative_fraction,
|
appliances_radiative_fraction,
|
||||||
appliances_latent_fraction,
|
appliances_latent_fraction,
|
||||||
appliance_schedule)
|
appliance_schedule)
|
||||||
if heating_schedule is not None:
|
|
||||||
thermal_control = ThermalControl(max(heating_schedule.values),
|
|
||||||
min(heating_schedule.values),
|
|
||||||
min(cooling_schedule.values),
|
|
||||||
None,
|
|
||||||
heating_schedule,
|
|
||||||
cooling_schedule)
|
|
||||||
else:
|
|
||||||
thermal_control = ThermalControl(None,
|
thermal_control = ThermalControl(None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
hvac_availability,
|
||||||
None,
|
heating_schedule,
|
||||||
None)
|
cooling_schedule)
|
||||||
|
hours_day = None
|
||||||
|
days_year = None
|
||||||
usages.append(Usage(usage_type,
|
usages.append(Usage(usage_type,
|
||||||
hours_day,
|
hours_day,
|
||||||
days_year,
|
days_year,
|
||||||
|
@ -149,7 +165,7 @@ class NrcanCatalog(Catalog):
|
||||||
"""
|
"""
|
||||||
_names = {'usages': []}
|
_names = {'usages': []}
|
||||||
for usage in self._content.usages:
|
for usage in self._content.usages:
|
||||||
_names['usages'].append(usage.usage)
|
_names['usages'].append(usage.name)
|
||||||
return _names
|
return _names
|
||||||
|
|
||||||
def entries(self, category=None):
|
def entries(self, category=None):
|
||||||
|
@ -165,6 +181,6 @@ class NrcanCatalog(Catalog):
|
||||||
:parm: entry name
|
:parm: entry name
|
||||||
"""
|
"""
|
||||||
for usage in self._content.usages:
|
for usage in self._content.usages:
|
||||||
if usage.usage.lower() == name.lower():
|
if usage.name.lower() == name.lower():
|
||||||
return usage
|
return usage
|
||||||
raise IndexError(f"{name} doesn't exists in the catalog")
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
||||||
|
|
|
@ -19,6 +19,7 @@ class UsageHelper:
|
||||||
'Equipment': cte.APPLIANCES,
|
'Equipment': cte.APPLIANCES,
|
||||||
'Thermostat Setpoint Cooling': cte.COOLING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Cooling'
|
'Thermostat Setpoint Cooling': cte.COOLING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Cooling'
|
||||||
'Thermostat Setpoint Heating': cte.HEATING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Heating'
|
'Thermostat Setpoint Heating': cte.HEATING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Heating'
|
||||||
|
'Fan': cte.HVAC_AVAILABILITY
|
||||||
}
|
}
|
||||||
_nrcan_data_type_to_hub_data_type = {
|
_nrcan_data_type_to_hub_data_type = {
|
||||||
'FRACTION': cte.FRACTION,
|
'FRACTION': cte.FRACTION,
|
||||||
|
@ -58,31 +59,6 @@ class UsageHelper:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_usage_to_hft = {
|
|
||||||
cte.RESIDENTIAL: 'residential',
|
|
||||||
cte.SINGLE_FAMILY_HOUSE: 'Single family house',
|
|
||||||
cte.MULTI_FAMILY_HOUSE: 'Multi-family house',
|
|
||||||
cte.EDUCATION: 'education',
|
|
||||||
cte.SCHOOL_WITHOUT_SHOWER: 'school without shower',
|
|
||||||
cte.SCHOOL_WITH_SHOWER: 'school with shower',
|
|
||||||
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail',
|
|
||||||
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food',
|
|
||||||
cte.HOTEL: 'hotel',
|
|
||||||
cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)',
|
|
||||||
cte.DORMITORY: 'dormitory',
|
|
||||||
cte.INDUSTRY: 'industry',
|
|
||||||
cte.RESTAURANT: 'restaurant',
|
|
||||||
cte.HEALTH_CARE: 'health care',
|
|
||||||
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage',
|
|
||||||
cte.OFFICE_AND_ADMINISTRATION: 'office and administration',
|
|
||||||
cte.EVENT_LOCATION: 'event location',
|
|
||||||
cte.HALL: 'hall',
|
|
||||||
cte.SPORTS_LOCATION: 'sport location',
|
|
||||||
cte.LABOR: 'Labor',
|
|
||||||
cte.GREEN_HOUSE: 'green house',
|
|
||||||
cte.NON_HEATED: 'non-heated'
|
|
||||||
}
|
|
||||||
|
|
||||||
_comnet_days = [cte.MONDAY,
|
_comnet_days = [cte.MONDAY,
|
||||||
cte.TUESDAY,
|
cte.TUESDAY,
|
||||||
cte.WEDNESDAY,
|
cte.WEDNESDAY,
|
||||||
|
@ -92,31 +68,6 @@ class UsageHelper:
|
||||||
cte.SUNDAY,
|
cte.SUNDAY,
|
||||||
cte.HOLIDAY]
|
cte.HOLIDAY]
|
||||||
|
|
||||||
_usage_to_comnet = {
|
|
||||||
cte.RESIDENTIAL: 'BA Multifamily',
|
|
||||||
cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily',
|
|
||||||
cte.MULTI_FAMILY_HOUSE: 'BA Multifamily',
|
|
||||||
cte.EDUCATION: 'BA School/University',
|
|
||||||
cte.SCHOOL_WITHOUT_SHOWER: 'BA School/University',
|
|
||||||
cte.SCHOOL_WITH_SHOWER: 'BA School/University',
|
|
||||||
cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail',
|
|
||||||
cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail',
|
|
||||||
cte.HOTEL: 'BA Hotel',
|
|
||||||
cte.HOTEL_MEDIUM_CLASS: 'BA Hotel',
|
|
||||||
cte.DORMITORY: 'BA Dormitory',
|
|
||||||
cte.INDUSTRY: 'BA Manufacturing Facility',
|
|
||||||
cte.RESTAURANT: 'BA Dining: Family',
|
|
||||||
cte.HEALTH_CARE: 'BA Hospital',
|
|
||||||
cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Multifamily',
|
|
||||||
cte.OFFICE_AND_ADMINISTRATION: 'BA Office',
|
|
||||||
cte.EVENT_LOCATION: 'BA Convention Center',
|
|
||||||
cte.HALL: 'BA Convention Center',
|
|
||||||
cte.SPORTS_LOCATION: 'BA Sports Arena',
|
|
||||||
cte.LABOR: 'BA Gymnasium',
|
|
||||||
cte.GREEN_HOUSE: cte.GREEN_HOUSE,
|
|
||||||
cte.NON_HEATED: cte.NON_HEATED
|
|
||||||
}
|
|
||||||
|
|
||||||
_comnet_data_type_to_hub_data_type = {
|
_comnet_data_type_to_hub_data_type = {
|
||||||
'Fraction': cte.FRACTION,
|
'Fraction': cte.FRACTION,
|
||||||
'OnOff': cte.ON_OFF,
|
'OnOff': cte.ON_OFF,
|
||||||
|
@ -166,18 +117,6 @@ class UsageHelper:
|
||||||
def comnet_days(self):
|
def comnet_days(self):
|
||||||
return self._comnet_days
|
return self._comnet_days
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def comnet_from_hub_usage(usage):
|
|
||||||
"""
|
|
||||||
Get Comnet usage from the given internal usage key
|
|
||||||
:param usage: str
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return UsageHelper._usage_to_comnet[usage]
|
|
||||||
except KeyError:
|
|
||||||
sys.stderr.write('Error: keyword not found to translate from hub_usage to comnet usage.\n')
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def schedules_key(usage):
|
def schedules_key(usage):
|
||||||
"""
|
"""
|
||||||
|
@ -190,15 +129,3 @@ class UsageHelper:
|
||||||
except KeyError:
|
except KeyError:
|
||||||
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
|
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
|
||||||
'done changing the keywords.\n')
|
'done changing the keywords.\n')
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def hft_from_hub_usage(usage):
|
|
||||||
"""
|
|
||||||
Get HfT usage from the given internal usage key
|
|
||||||
:param usage: str
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return UsageHelper._usage_to_hft[usage]
|
|
||||||
except KeyError:
|
|
||||||
sys.stderr.write('Error: keyword not found to translate from hub_usage to hft usage.\n')
|
|
||||||
|
|
|
@ -397,8 +397,8 @@ class Building(CityObject):
|
||||||
if self.internal_zones is None:
|
if self.internal_zones is None:
|
||||||
return False
|
return False
|
||||||
for internal_zone in self.internal_zones:
|
for internal_zone in self.internal_zones:
|
||||||
if internal_zone.usage_zones is not None:
|
if internal_zone.usages is not None:
|
||||||
for usage_zone in internal_zone.usage_zones:
|
for usage_zone in internal_zone.usages:
|
||||||
if usage_zone.thermal_control is not None:
|
if usage_zone.thermal_control is not None:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -7,7 +7,7 @@ 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_zone import UsageZone
|
from hub.city_model_structure.building_demand.usage import Usage
|
||||||
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.attributes.polyhedron import Polyhedron
|
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
||||||
from hub.city_model_structure.energy_systems.hvac_system import HvacSystem
|
from hub.city_model_structure.energy_systems.hvac_system import HvacSystem
|
||||||
|
@ -24,7 +24,7 @@ class InternalZone:
|
||||||
self._volume = None
|
self._volume = None
|
||||||
self._area = area
|
self._area = area
|
||||||
self._thermal_zones = None
|
self._thermal_zones = None
|
||||||
self._usage_zones = None
|
self._usages = None
|
||||||
self._hvac_system = None
|
self._hvac_system = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -75,20 +75,20 @@ class InternalZone:
|
||||||
return self._area
|
return self._area
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage_zones(self) -> [UsageZone]:
|
def usages(self) -> [Usage]:
|
||||||
"""
|
"""
|
||||||
Get internal zone usage zones
|
Get internal zone usage zones
|
||||||
:return: [UsageZone]
|
:return: [UsageZone]
|
||||||
"""
|
"""
|
||||||
return self._usage_zones
|
return self._usages
|
||||||
|
|
||||||
@usage_zones.setter
|
@usages.setter
|
||||||
def usage_zones(self, value):
|
def usages(self, value):
|
||||||
"""
|
"""
|
||||||
Set internal zone usage zones
|
Set internal zone usage zones
|
||||||
:param value: [UsageZone]
|
:param value: [UsageZone]
|
||||||
"""
|
"""
|
||||||
self._usage_zones = value
|
self._usages = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_system(self) -> Union[None, HvacSystem]:
|
def hvac_system(self) -> Union[None, HvacSystem]:
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ThermalZone:
|
||||||
"""
|
"""
|
||||||
ThermalZone class
|
ThermalZone class
|
||||||
"""
|
"""
|
||||||
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage=None):
|
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, 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
|
||||||
|
@ -40,9 +40,9 @@ 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._usage = usage
|
self._usage_name = usage_name
|
||||||
self._usage_from_parent = False
|
self._usage_from_parent = False
|
||||||
if usage is None:
|
if usage_name is None:
|
||||||
self._usage_from_parent = True
|
self._usage_from_parent = True
|
||||||
self._hours_day = None
|
self._hours_day = None
|
||||||
self._days_year = None
|
self._days_year = None
|
||||||
|
@ -58,16 +58,16 @@ class ThermalZone:
|
||||||
def usage_zones(self):
|
def usage_zones(self):
|
||||||
# example 70-office_30-residential
|
# example 70-office_30-residential
|
||||||
if self._usage_from_parent:
|
if self._usage_from_parent:
|
||||||
self._usages = copy.deepcopy(self._parent_internal_zone.usage_zones)
|
self._usages = copy.deepcopy(self._parent_internal_zone.usages)
|
||||||
else:
|
else:
|
||||||
values = self._usage.split('_')
|
values = self._usage_name.split('_')
|
||||||
usages = []
|
usages = []
|
||||||
for value in values:
|
for value in values:
|
||||||
usages.append(value.split('-'))
|
usages.append(value.split('-'))
|
||||||
self._usages = []
|
self._usages = []
|
||||||
for parent_usage in self._parent_internal_zone.usage_zones:
|
for parent_usage in self._parent_internal_zone.usages:
|
||||||
for value in usages:
|
for value in usages:
|
||||||
if parent_usage.usage == value[1]:
|
if parent_usage.name == value[1]:
|
||||||
new_usage = copy.deepcopy(parent_usage)
|
new_usage = copy.deepcopy(parent_usage)
|
||||||
new_usage.percentage = float(value[0])/100
|
new_usage.percentage = float(value[0])/100
|
||||||
self._usages.append(new_usage)
|
self._usages.append(new_usage)
|
||||||
|
@ -224,19 +224,19 @@ class ThermalZone:
|
||||||
self._view_factors_matrix = value
|
self._view_factors_matrix = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage(self) -> Union[None, str]:
|
def usage_name(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
Get thermal zone usage
|
Get thermal zone usage name
|
||||||
:return: None or str
|
:return: None or str
|
||||||
"""
|
"""
|
||||||
if self._usage_from_parent:
|
if self._usage_from_parent:
|
||||||
if self._parent_internal_zone.usage_zones is None:
|
if self._parent_internal_zone.usages is None:
|
||||||
return None
|
return None
|
||||||
self._usage = ''
|
self._usage_name = ''
|
||||||
for usage_zone in self._parent_internal_zone.usage_zones:
|
for usage_zone in self._parent_internal_zone.usages:
|
||||||
self._usage += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.usage + '_'
|
self._usage_name += str(round(usage_zone.percentage * 100)) + '-' + usage_zone.name + '_'
|
||||||
self._usage = self._usage[:-1]
|
self._usage_name = self._usage_name[:-1]
|
||||||
return self._usage
|
return self._usage_name
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_schedule_of_day(requested_day_type, schedules):
|
def _get_schedule_of_day(requested_day_type, schedules):
|
||||||
|
@ -322,7 +322,13 @@ class ThermalZone:
|
||||||
if _occupancy_reference.occupancy_schedules is not None:
|
if _occupancy_reference.occupancy_schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)):
|
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)):
|
||||||
schedule = copy.deepcopy(_occupancy_reference.occupancy_schedules[i_schedule])
|
schedule = Schedule()
|
||||||
|
schedule.type = _occupancy_reference.occupancy_schedules[i_schedule].type
|
||||||
|
schedule.day_types = _occupancy_reference.occupancy_schedules[i_schedule].day_types
|
||||||
|
schedule.data_type = _occupancy_reference.occupancy_schedules[i_schedule].data_type
|
||||||
|
schedule.time_step = _occupancy_reference.occupancy_schedules[i_schedule].time_step
|
||||||
|
schedule.time_range = _occupancy_reference.occupancy_schedules[i_schedule].time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)):
|
for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
|
@ -374,7 +380,13 @@ class ThermalZone:
|
||||||
if _lighting_reference.schedules is not None:
|
if _lighting_reference.schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_lighting_reference.schedules)):
|
for i_schedule in range(0, len(_lighting_reference.schedules)):
|
||||||
schedule = copy.deepcopy(_lighting_reference.schedules[i_schedule])
|
schedule = Schedule()
|
||||||
|
schedule.type = _lighting_reference.schedules[i_schedule].type
|
||||||
|
schedule.day_types = _lighting_reference.schedules[i_schedule].day_types
|
||||||
|
schedule.data_type = _lighting_reference.schedules[i_schedule].data_type
|
||||||
|
schedule.time_step = _lighting_reference.schedules[i_schedule].time_step
|
||||||
|
schedule.time_range = _lighting_reference.schedules[i_schedule].time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)):
|
for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
|
@ -426,7 +438,13 @@ class ThermalZone:
|
||||||
if _appliances_reference.schedules is not None:
|
if _appliances_reference.schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_appliances_reference.schedules)):
|
for i_schedule in range(0, len(_appliances_reference.schedules)):
|
||||||
schedule = copy.deepcopy(_appliances_reference.schedules[i_schedule])
|
schedule = Schedule()
|
||||||
|
schedule.type = _appliances_reference.schedules[i_schedule].type
|
||||||
|
schedule.day_types = _appliances_reference.schedules[i_schedule].day_types
|
||||||
|
schedule.data_type = _appliances_reference.schedules[i_schedule].data_type
|
||||||
|
schedule.time_step = _appliances_reference.schedules[i_schedule].time_step
|
||||||
|
schedule.time_range = _appliances_reference.schedules[i_schedule].time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)):
|
for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
|
@ -535,7 +553,13 @@ class ThermalZone:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
_schedule_type = _types_reference[i_type][1]
|
_schedule_type = _types_reference[i_type][1]
|
||||||
for i_schedule in range(0, len(_schedule_type)):
|
for i_schedule in range(0, len(_schedule_type)):
|
||||||
schedule = copy.deepcopy(_schedule_type[i_schedule])
|
schedule = Schedule()
|
||||||
|
schedule.type = _schedule_type[i_schedule].type
|
||||||
|
schedule.day_types = _schedule_type[i_schedule].day_types
|
||||||
|
schedule.data_type = _schedule_type[i_schedule].data_type
|
||||||
|
schedule.time_step = _schedule_type[i_schedule].time_step
|
||||||
|
schedule.time_range = _schedule_type[i_schedule].time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_schedule_type[i_schedule].values)):
|
for i_value in range(0, len(_schedule_type[i_schedule].values)):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
|
|
246
hub/city_model_structure/building_demand/usage.py
Normal file
246
hub/city_model_structure/building_demand/usage.py
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
"""
|
||||||
|
Usage 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 Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
"""
|
||||||
|
import uuid
|
||||||
|
from typing import Union, List
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
from hub.city_model_structure.building_demand.occupancy import Occupancy
|
||||||
|
from hub.city_model_structure.building_demand.lighting import Lighting
|
||||||
|
from hub.city_model_structure.building_demand.appliances import Appliances
|
||||||
|
from hub.city_model_structure.building_demand.thermal_control import ThermalControl
|
||||||
|
from hub.city_model_structure.building_demand.internal_gain import InternalGain
|
||||||
|
|
||||||
|
|
||||||
|
class Usage:
|
||||||
|
"""
|
||||||
|
Usage class
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self._id = None
|
||||||
|
self._name = None
|
||||||
|
self._percentage = None
|
||||||
|
self._internal_gains = None
|
||||||
|
self._hours_day = None
|
||||||
|
self._days_year = None
|
||||||
|
self._mechanical_air_change = None
|
||||||
|
self._occupancy = None
|
||||||
|
self._lighting = None
|
||||||
|
self._appliances = None
|
||||||
|
self._thermal_control = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self):
|
||||||
|
"""
|
||||||
|
Get usage zone id, a universally unique identifier randomly generated
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
if self._id is None:
|
||||||
|
self._id = uuid.uuid4()
|
||||||
|
return self._id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> Union[None, str]:
|
||||||
|
"""
|
||||||
|
Get usage zone usage
|
||||||
|
:return: None or str
|
||||||
|
"""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value):
|
||||||
|
"""
|
||||||
|
Set usage zone usage
|
||||||
|
:param value: str
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._name = str(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def percentage(self):
|
||||||
|
"""
|
||||||
|
Get usage zone percentage in range[0,1]
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._percentage
|
||||||
|
|
||||||
|
@percentage.setter
|
||||||
|
def percentage(self, value):
|
||||||
|
"""
|
||||||
|
Set usage zone percentage in range[0,1]
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._percentage = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def internal_gains(self) -> List[InternalGain]:
|
||||||
|
"""
|
||||||
|
Calculates and returns the list of all internal gains defined
|
||||||
|
:return: InternalGains
|
||||||
|
"""
|
||||||
|
if self._internal_gains is None:
|
||||||
|
if self.occupancy is not None:
|
||||||
|
if self.occupancy.latent_internal_gain is not None:
|
||||||
|
_internal_gain = InternalGain()
|
||||||
|
_internal_gain.type = cte.OCCUPANCY
|
||||||
|
_total_heat_gain = (self.occupancy.sensible_convective_internal_gain
|
||||||
|
+ self.occupancy.sensible_radiative_internal_gain
|
||||||
|
+ self.occupancy.latent_internal_gain)
|
||||||
|
_internal_gain.average_internal_gain = _total_heat_gain
|
||||||
|
_internal_gain.latent_fraction = self.occupancy.latent_internal_gain / _total_heat_gain
|
||||||
|
_internal_gain.radiative_fraction = self.occupancy.sensible_radiative_internal_gain / _total_heat_gain
|
||||||
|
_internal_gain.convective_fraction = self.occupancy.sensible_convective_internal_gain / _total_heat_gain
|
||||||
|
_internal_gain.schedules = self.occupancy.occupancy_schedules
|
||||||
|
self._internal_gains = [_internal_gain]
|
||||||
|
if self.lighting is not None:
|
||||||
|
_internal_gain = InternalGain()
|
||||||
|
_internal_gain.type = cte.LIGHTING
|
||||||
|
_internal_gain.average_internal_gain = self.lighting.density
|
||||||
|
_internal_gain.latent_fraction = self.lighting.latent_fraction
|
||||||
|
_internal_gain.radiative_fraction = self.lighting.radiative_fraction
|
||||||
|
_internal_gain.convective_fraction = self.lighting.convective_fraction
|
||||||
|
_internal_gain.schedules = self.lighting.schedules
|
||||||
|
if self._internal_gains is not None:
|
||||||
|
self._internal_gains.append(_internal_gain)
|
||||||
|
else:
|
||||||
|
self._internal_gains = [_internal_gain]
|
||||||
|
if self.appliances is not None:
|
||||||
|
_internal_gain = InternalGain()
|
||||||
|
_internal_gain.type = cte.APPLIANCES
|
||||||
|
_internal_gain.average_internal_gain = self.appliances.density
|
||||||
|
_internal_gain.latent_fraction = self.appliances.latent_fraction
|
||||||
|
_internal_gain.radiative_fraction = self.appliances.radiative_fraction
|
||||||
|
_internal_gain.convective_fraction = self.appliances.convective_fraction
|
||||||
|
_internal_gain.schedules = self.appliances.schedules
|
||||||
|
if self._internal_gains is not None:
|
||||||
|
self._internal_gains.append(_internal_gain)
|
||||||
|
else:
|
||||||
|
self._internal_gains = [_internal_gain]
|
||||||
|
return self._internal_gains
|
||||||
|
|
||||||
|
@internal_gains.setter
|
||||||
|
def internal_gains(self, value):
|
||||||
|
"""
|
||||||
|
Set usage zone internal gains
|
||||||
|
:param value: [InternalGain]
|
||||||
|
"""
|
||||||
|
self._internal_gains = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hours_day(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get usage zone usage hours per day
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._hours_day
|
||||||
|
|
||||||
|
@hours_day.setter
|
||||||
|
def hours_day(self, value):
|
||||||
|
"""
|
||||||
|
Set usage zone usage hours per day
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._hours_day = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def days_year(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get usage zone usage days per year
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._days_year
|
||||||
|
|
||||||
|
@days_year.setter
|
||||||
|
def days_year(self, value):
|
||||||
|
"""
|
||||||
|
Set usage zone usage days per year
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._days_year = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mechanical_air_change(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get usage zone mechanical air change in air change per hour (ACH)
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._mechanical_air_change
|
||||||
|
|
||||||
|
@mechanical_air_change.setter
|
||||||
|
def mechanical_air_change(self, value):
|
||||||
|
"""
|
||||||
|
Set usage zone mechanical air change in air change per hour (ACH)
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._mechanical_air_change = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def occupancy(self) -> Union[None, Occupancy]:
|
||||||
|
"""
|
||||||
|
Get occupancy in the usage zone
|
||||||
|
:return: None or Occupancy
|
||||||
|
"""
|
||||||
|
return self._occupancy
|
||||||
|
|
||||||
|
@occupancy.setter
|
||||||
|
def occupancy(self, value):
|
||||||
|
"""
|
||||||
|
Set occupancy in the usage zone
|
||||||
|
:param value: Occupancy
|
||||||
|
"""
|
||||||
|
self._occupancy = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lighting(self) -> Union[None, Lighting]:
|
||||||
|
"""
|
||||||
|
Get lighting information
|
||||||
|
:return: None or Lighting
|
||||||
|
"""
|
||||||
|
return self._lighting
|
||||||
|
|
||||||
|
@lighting.setter
|
||||||
|
def lighting(self, value):
|
||||||
|
"""
|
||||||
|
Set lighting information
|
||||||
|
:param value: Lighting
|
||||||
|
"""
|
||||||
|
self._lighting = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def appliances(self) -> Union[None, Appliances]:
|
||||||
|
"""
|
||||||
|
Get appliances information
|
||||||
|
:return: None or Appliances
|
||||||
|
"""
|
||||||
|
return self._appliances
|
||||||
|
|
||||||
|
@appliances.setter
|
||||||
|
def appliances(self, value):
|
||||||
|
"""
|
||||||
|
Set appliances information
|
||||||
|
:param value: Appliances
|
||||||
|
"""
|
||||||
|
self._appliances = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def thermal_control(self) -> Union[None, ThermalControl]:
|
||||||
|
"""
|
||||||
|
Get thermal control of this thermal zone
|
||||||
|
:return: None or ThermalControl
|
||||||
|
"""
|
||||||
|
return self._thermal_control
|
||||||
|
|
||||||
|
@thermal_control.setter
|
||||||
|
def thermal_control(self, value):
|
||||||
|
"""
|
||||||
|
Set thermal control for this thermal zone
|
||||||
|
:param value: ThermalControl
|
||||||
|
"""
|
||||||
|
self._thermal_control = value
|
|
@ -42,7 +42,6 @@ class City:
|
||||||
self._buildings = None
|
self._buildings = None
|
||||||
self._subway_entrances = None
|
self._subway_entrances = None
|
||||||
self._srs_name = srs_name
|
self._srs_name = srs_name
|
||||||
self._geometry = GeometryHelper()
|
|
||||||
# todo: right now extracted at city level, in the future should be extracted also at building level if exist
|
# todo: right now extracted at city level, in the future should be extracted also at building level if exist
|
||||||
self._location = None
|
self._location = None
|
||||||
self._country_code = None
|
self._country_code = None
|
||||||
|
|
76
hub/data/construction/nrcan.xml
Normal file
76
hub/data/construction/nrcan.xml
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<nrcan base_url_archetypes="https://raw.githubusercontent.com/canmet-energy/necb-2011-baselines/master/output/"
|
||||||
|
base_url_construction="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/">
|
||||||
|
<standards_per_period>
|
||||||
|
<standard period_of_construction="1000_1979">
|
||||||
|
<constructions_location>BTAPPRE1980/data/surface_thermal_transmittance.json</constructions_location>
|
||||||
|
<g_value_location>BTAPPRE1980/data/window_characteristics.json</g_value_location>
|
||||||
|
</standard>
|
||||||
|
<standard period_of_construction="1980_2010">
|
||||||
|
<constructions_location>BTAP1980TO2010/data/surface_thermal_transmittance.json</constructions_location>
|
||||||
|
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
|
||||||
|
</standard>
|
||||||
|
<standard period_of_construction="2011_2016">
|
||||||
|
<constructions_location>NECB2011/data/surface_thermal_transmittance.json</constructions_location>
|
||||||
|
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
|
||||||
|
</standard>
|
||||||
|
<standard period_of_construction="2017_2019">
|
||||||
|
<constructions_location>NECB2017/data/surface_thermal_transmittance.json</constructions_location>
|
||||||
|
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
|
||||||
|
</standard>
|
||||||
|
<standard period_of_construction="2020_3000">
|
||||||
|
<constructions_location>NECB2020/data/surface_thermal_transmittance.json</constructions_location>
|
||||||
|
<g_value_location>BTAP1980TO2010/data/window_characteristics.json</g_value_location>
|
||||||
|
</standard>
|
||||||
|
</standards_per_period>
|
||||||
|
<standards_per_function>
|
||||||
|
<standard function="FullServiceRestaurant">
|
||||||
|
<file_location>FullServiceRestaurant/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/8414706d-3ba9-4d70-ad3c-4db62d865e1b-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="HighriseApartment">
|
||||||
|
<file_location>HighriseApartment/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/83ab3764-046e-48a8-85cd-a3c0ac761efa-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="Hospital">
|
||||||
|
<file_location>Hospital/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/210dac7e-2d51-40a9-bc78-ad0bc1c57a89-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="LargeHotel">
|
||||||
|
<file_location>LargeHotel/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/d0185276-7fe0-4da9-bb5d-8c8a7c13c405-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="LargeOffice">
|
||||||
|
<file_location>LargeOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/2da33707-50a7-4554-91ed-c5fdbc1ce3b9-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="MediumOffice">
|
||||||
|
<file_location>MediumOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/65d97bf8-8749-410b-b53d-5a9c60e0227c-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="MidriseApartment">
|
||||||
|
<file_location>MidriseApartment/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/19518153-9c28-4e40-8bbd-98ef949c1bdb-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="Outpatient">
|
||||||
|
<file_location>Outpatient/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/deab93c7-d086-432d-bb90-33c8c4e1fab3-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="PrimarySchool">
|
||||||
|
<file_location>PrimarySchool/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/87f45397-5ef4-4df9-be41-d33c4b6d2fb7-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="QuickServiceRestaurant">
|
||||||
|
<file_location>QuickServiceRestaurant/CAN_PQ_Montreal.Intl.AP.716270_CWEC/ 0bc55858-a81b-4d07-9923-1d84e8a23194-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="RetailStandalone">
|
||||||
|
<file_location>RetailStandalone/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/a3643bcb-0eea-47d4-b6b9-253ed188ec0c-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="RetailStripmall">
|
||||||
|
<file_location>RetailStripmall/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/ebaf5a16-00af-49de-9672-6b373fc825be-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="SecondarySchool">
|
||||||
|
<file_location>SecondarySchool/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/3a4f105f-93ed-4b8b-9eb3-c8ca40c5de6e-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="SmallHotel">
|
||||||
|
<file_location>SmallHotel/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/dff0a3fc-d9e5-4866-9e6a-dee9a0da60b2-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="SmallOffice">
|
||||||
|
<file_location>SmallOffice/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/a9a3669d-beb8-4951-aa11-c27dbc61a344-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
<standard function="Warehouse">
|
||||||
|
<file_location>Warehouse/CAN_PQ_Montreal.Intl.AP.716270_CWEC/os_report/569ec649-8017-4a3c-bd0a-337eba3ec488-os-report.html</file_location>
|
||||||
|
</standard>
|
||||||
|
</standards_per_function>
|
||||||
|
</nrcan>
|
|
@ -1,9 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<nrcan base_url="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/">
|
<nrcan base_url="https://raw.githubusercontent.com/NREL/openstudio-standards/master/lib/openstudio-standards/standards/necb/">
|
||||||
<standards>
|
|
||||||
<usage>
|
|
||||||
<space_types_location>NECB2020/data/space_types.json</space_types_location>
|
<space_types_location>NECB2020/data/space_types.json</space_types_location>
|
||||||
<schedules_location>NECB2015/data/schedules.json</schedules_location>
|
<schedules_location>NECB2015/data/schedules.json</schedules_location>
|
||||||
</usage>
|
|
||||||
</standards>
|
|
||||||
</nrcan>
|
</nrcan>
|
|
@ -169,7 +169,7 @@ class EnergyAde:
|
||||||
def _building_geometry(self, building, building_dic, city):
|
def _building_geometry(self, building, building_dic, city):
|
||||||
|
|
||||||
building_dic['bldg:Building']['bldg:function'] = building.function
|
building_dic['bldg:Building']['bldg:function'] = building.function
|
||||||
building_dic['bldg:Building']['bldg:usage'] = ', '.join([u.usage for u in building.usage_zones])
|
building_dic['bldg:Building']['bldg:usage'] = ', '.join([u.name for u in building.usages])
|
||||||
building_dic['bldg:Building']['bldg:yearOfConstruction'] = building.year_of_construction
|
building_dic['bldg:Building']['bldg:yearOfConstruction'] = building.year_of_construction
|
||||||
building_dic['bldg:Building']['bldg:roofType'] = building.roof_type
|
building_dic['bldg:Building']['bldg:roofType'] = building.roof_type
|
||||||
building_dic['bldg:Building']['bldg:measuredHeight'] = {
|
building_dic['bldg:Building']['bldg:measuredHeight'] = {
|
||||||
|
@ -266,7 +266,7 @@ class EnergyAde:
|
||||||
thermal_zones = []
|
thermal_zones = []
|
||||||
for index, thermal_zone in enumerate(building.thermal_zones):
|
for index, thermal_zone in enumerate(building.thermal_zones):
|
||||||
usage_zones = []
|
usage_zones = []
|
||||||
for usage_zone in thermal_zone.usage_zones:
|
for usage_zone in thermal_zone.usages:
|
||||||
usage_zones.append({'@xlink:href': f'#GML_{usage_zone.id}'})
|
usage_zones.append({'@xlink:href': f'#GML_{usage_zone.id}'})
|
||||||
thermal_zone_dic = {
|
thermal_zone_dic = {
|
||||||
'energy:ThermalZone': {
|
'energy:ThermalZone': {
|
||||||
|
|
|
@ -206,9 +206,9 @@ class Idf:
|
||||||
_schedule.values = _infiltration_values
|
_schedule.values = _infiltration_values
|
||||||
_infiltration_schedules.append(_schedule)
|
_infiltration_schedules.append(_schedule)
|
||||||
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
|
for schedule in self._idf.idfobjects[self._HOURLY_SCHEDULE]:
|
||||||
if schedule.Name == f'Infiltration schedules {thermal_zone.usage}':
|
if schedule.Name == f'Infiltration schedules {thermal_zone.usage_name}':
|
||||||
return
|
return
|
||||||
return self._add_standard_compact_hourly_schedule(thermal_zone.usage, 'Infiltration', _infiltration_schedules)
|
return self._add_standard_compact_hourly_schedule(thermal_zone.usage_name, 'Infiltration', _infiltration_schedules)
|
||||||
|
|
||||||
def _add_people_activity_level_schedules(self, thermal_zone):
|
def _add_people_activity_level_schedules(self, thermal_zone):
|
||||||
_occ = thermal_zone.occupancy
|
_occ = thermal_zone.occupancy
|
||||||
|
@ -218,9 +218,9 @@ class Idf:
|
||||||
_total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain
|
_total_heat = (_occ.sensible_convective_internal_gain + _occ.sensible_radiative_internal_gain
|
||||||
+ _occ.latent_internal_gain) / _occ.occupancy_density
|
+ _occ.latent_internal_gain) / _occ.occupancy_density
|
||||||
for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]:
|
for schedule in self._idf.idfobjects[self._COMPACT_SCHEDULE]:
|
||||||
if schedule.Name == f'Activity Level schedules {thermal_zone.usage}':
|
if schedule.Name == f'Activity Level schedules {thermal_zone.usage_name}':
|
||||||
return
|
return
|
||||||
_kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage}',
|
_kwargs = {'Name': f'Activity Level schedules {thermal_zone.usage_name}',
|
||||||
'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER],
|
'Schedule_Type_Limits_Name': self.idf_type_limits[cte.ANY_NUMBER],
|
||||||
'Field_1': 'Through: 12/31',
|
'Field_1': 'Through: 12/31',
|
||||||
'Field_2': 'For AllDays',
|
'Field_2': 'For AllDays',
|
||||||
|
@ -299,15 +299,15 @@ class Idf:
|
||||||
self._add_heating_system(thermal_zone, name)
|
self._add_heating_system(thermal_zone, name)
|
||||||
|
|
||||||
def _add_thermostat(self, thermal_zone):
|
def _add_thermostat(self, thermal_zone):
|
||||||
thermostat_name = f'Thermostat {thermal_zone.usage}'
|
thermostat_name = f'Thermostat {thermal_zone.usage_name}'
|
||||||
for thermostat in self._idf.idfobjects[self._THERMOSTAT]:
|
for thermostat in self._idf.idfobjects[self._THERMOSTAT]:
|
||||||
if thermostat.Name == thermostat_name:
|
if thermostat.Name == thermostat_name:
|
||||||
return thermostat
|
return thermostat
|
||||||
# todo: change schedules to schedule name and create schedules using the add_schedule function
|
# todo: change schedules to schedule name and create schedules using the add_schedule function
|
||||||
return self._idf.newidfobject(self._THERMOSTAT,
|
return self._idf.newidfobject(self._THERMOSTAT,
|
||||||
Name=thermostat_name,
|
Name=thermostat_name,
|
||||||
Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage}',
|
Heating_Setpoint_Schedule_Name=f'Heating thermostat schedules {thermal_zone.usage_name}',
|
||||||
Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage}')
|
Cooling_Setpoint_Schedule_Name=f'Cooling thermostat schedules {thermal_zone.usage_name}')
|
||||||
|
|
||||||
def _add_heating_system(self, thermal_zone, zone_name):
|
def _add_heating_system(self, thermal_zone, zone_name):
|
||||||
for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]:
|
for air_system in self._idf.idfobjects[self._IDEAL_LOAD_AIR_SYSTEM]:
|
||||||
|
@ -316,9 +316,9 @@ class Idf:
|
||||||
thermostat = self._add_thermostat(thermal_zone)
|
thermostat = self._add_thermostat(thermal_zone)
|
||||||
self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM,
|
self._idf.newidfobject(self._IDEAL_LOAD_AIR_SYSTEM,
|
||||||
Zone_Name=zone_name,
|
Zone_Name=zone_name,
|
||||||
System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}',
|
System_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
|
||||||
Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}',
|
Heating_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
|
||||||
Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage}',
|
Cooling_Availability_Schedule_Name=f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}',
|
||||||
Template_Thermostat_Name=thermostat.Name)
|
Template_Thermostat_Name=thermostat.Name)
|
||||||
|
|
||||||
def _add_occupancy(self, thermal_zone, zone_name):
|
def _add_occupancy(self, thermal_zone, zone_name):
|
||||||
|
@ -329,11 +329,11 @@ class Idf:
|
||||||
self._idf.newidfobject(self._PEOPLE,
|
self._idf.newidfobject(self._PEOPLE,
|
||||||
Name=f'{zone_name}_occupancy',
|
Name=f'{zone_name}_occupancy',
|
||||||
Zone_or_ZoneList_Name=zone_name,
|
Zone_or_ZoneList_Name=zone_name,
|
||||||
Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage}',
|
Number_of_People_Schedule_Name=f'Occupancy schedules {thermal_zone.usage_name}',
|
||||||
Number_of_People_Calculation_Method="People",
|
Number_of_People_Calculation_Method="People",
|
||||||
Number_of_People=number_of_people,
|
Number_of_People=number_of_people,
|
||||||
Fraction_Radiant=fraction_radiant,
|
Fraction_Radiant=fraction_radiant,
|
||||||
Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage}'
|
Activity_Level_Schedule_Name=f'Activity Level schedules {thermal_zone.usage_name}'
|
||||||
)
|
)
|
||||||
|
|
||||||
def _add_infiltration(self, thermal_zone, zone_name):
|
def _add_infiltration(self, thermal_zone, zone_name):
|
||||||
|
@ -343,7 +343,7 @@ class Idf:
|
||||||
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=f'Infiltration schedules {thermal_zone.usage}',
|
Schedule_Name=f'Infiltration schedules {thermal_zone.usage_name}',
|
||||||
Design_Flow_Rate_Calculation_Method='AirChanges/Hour',
|
Design_Flow_Rate_Calculation_Method='AirChanges/Hour',
|
||||||
Air_Changes_per_Hour=thermal_zone.mechanical_air_change
|
Air_Changes_per_Hour=thermal_zone.mechanical_air_change
|
||||||
)
|
)
|
||||||
|
@ -386,7 +386,7 @@ class Idf:
|
||||||
self._add_vegetation_material(thermal_boundary.parent_surface.vegetation)
|
self._add_vegetation_material(thermal_boundary.parent_surface.vegetation)
|
||||||
for thermal_opening in thermal_boundary.thermal_openings:
|
for thermal_opening in thermal_boundary.thermal_openings:
|
||||||
self._add_window_construction_and_material(thermal_opening)
|
self._add_window_construction_and_material(thermal_opening)
|
||||||
usage = thermal_zone.usage
|
usage = thermal_zone.usage_name
|
||||||
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:
|
||||||
self._add_infiltration_schedules(thermal_zone)
|
self._add_infiltration_schedules(thermal_zone)
|
||||||
self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
|
self._add_schedules(usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
|
||||||
|
@ -461,7 +461,7 @@ class Idf:
|
||||||
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
|
||||||
break
|
break
|
||||||
for usage_zone in thermal_zone.usage_zones:
|
for usage_zone in thermal_zone.usages:
|
||||||
surface.Zone_Name = usage_zone.id
|
surface.Zone_Name = usage_zone.id
|
||||||
break
|
break
|
||||||
break
|
break
|
||||||
|
|
|
@ -77,9 +77,9 @@ class InselMonthlyEnergyBalance(Insel):
|
||||||
parameters.append('1 % BP(9) Usage type (0=standard, 1=IWU)')
|
parameters.append('1 % BP(9) Usage type (0=standard, 1=IWU)')
|
||||||
|
|
||||||
# ZONES AND SURFACES
|
# ZONES AND SURFACES
|
||||||
parameters.append(f'{len(internal_zone.usage_zones)} % BP(10) Number of zones')
|
parameters.append(f'{len(internal_zone.usages)} % BP(10) Number of zones')
|
||||||
|
|
||||||
for i, usage_zone in enumerate(internal_zone.usage_zones):
|
for i, usage_zone in enumerate(internal_zone.usages):
|
||||||
percentage_usage = usage_zone.percentage
|
percentage_usage = usage_zone.percentage
|
||||||
parameters.append(f'{float(internal_zone.area) * percentage_usage} % BP(11) #1 Area of zone {i + 1} (m2)')
|
parameters.append(f'{float(internal_zone.area) * percentage_usage} % BP(11) #1 Area of zone {i + 1} (m2)')
|
||||||
total_internal_gain = 0
|
total_internal_gain = 0
|
||||||
|
|
|
@ -66,45 +66,64 @@ DOOR = 'Door'
|
||||||
SKYLIGHT = 'Skylight'
|
SKYLIGHT = 'Skylight'
|
||||||
|
|
||||||
# functions and usages
|
# functions and usages
|
||||||
|
RESIDENTIAL = 'residential'
|
||||||
SINGLE_FAMILY_HOUSE = 'single family house'
|
SINGLE_FAMILY_HOUSE = 'single family house'
|
||||||
MULTI_FAMILY_HOUSE = 'multifamily house'
|
MULTI_FAMILY_HOUSE = 'multifamily house'
|
||||||
ROW_HOSE = 'row house'
|
ROW_HOUSE = 'row house'
|
||||||
MID_RISE_APARTMENT = 'mid rise apartment'
|
MID_RISE_APARTMENT = 'mid rise apartment'
|
||||||
HIGH_RISE_APARTMENT = 'high rise apartment'
|
HIGH_RISE_APARTMENT = 'high rise apartment'
|
||||||
|
OFFICE_AND_ADMINISTRATION = 'office and administration'
|
||||||
SMALL_OFFICE = 'small office'
|
SMALL_OFFICE = 'small office'
|
||||||
MEDIUM_OFFICE = 'medium office'
|
MEDIUM_OFFICE = 'medium office'
|
||||||
LARGE_OFFICE = 'large office'
|
LARGE_OFFICE = 'large office'
|
||||||
|
COURTHOUSE = 'courthouse'
|
||||||
|
FIRE_STATION = 'fire station'
|
||||||
|
PENITENTIARY = 'penitentiary'
|
||||||
|
POLICE_STATION = 'police station'
|
||||||
|
POST_OFFICE = 'post office'
|
||||||
|
LIBRARY = 'library'
|
||||||
|
EDUCATION = 'education'
|
||||||
PRIMARY_SCHOOL = 'primary school'
|
PRIMARY_SCHOOL = 'primary school'
|
||||||
|
PRIMARY_SCHOOL_WITH_SHOWER = 'school with shower'
|
||||||
SECONDARY_SCHOOL = 'secondary school'
|
SECONDARY_SCHOOL = 'secondary school'
|
||||||
|
UNIVERSITY = 'university'
|
||||||
|
LABORATORY_AND_RESEARCH_CENTER = 'laboratory and research centers'
|
||||||
STAND_ALONE_RETAIL = 'stand alone retail'
|
STAND_ALONE_RETAIL = 'stand alone retail'
|
||||||
HOSPITAL = 'hospital'
|
HOSPITAL = 'hospital'
|
||||||
OUT_PATIENT_HEALTH_CARE = 'out-patient health care'
|
OUT_PATIENT_HEALTH_CARE = 'out-patient health care'
|
||||||
STRIP_MALL = 'strip mall'
|
|
||||||
SUPERMARKET = 'supermarket'
|
|
||||||
WAREHOUSE = 'warehouse'
|
|
||||||
QUICK_SERVICE_RESTAURANT = 'quick service restaurant'
|
|
||||||
FULL_SERVICE_RESTAURANT = 'full service restaurant'
|
|
||||||
SMALL_HOTEL = 'small hotel'
|
|
||||||
LARGE_HOTEL = 'large hotel'
|
|
||||||
RESIDENTIAL = 'residential'
|
|
||||||
EDUCATION = 'education'
|
|
||||||
SCHOOL_WITHOUT_SHOWER = 'school without shower'
|
|
||||||
SCHOOL_WITH_SHOWER = 'school with shower'
|
|
||||||
RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD = 'retail shop without refrigerated food'
|
|
||||||
RETAIL_SHOP_WITH_REFRIGERATED_FOOD = 'retail shop with refrigerated food'
|
|
||||||
HOTEL = 'hotel'
|
|
||||||
HOTEL_MEDIUM_CLASS = 'hotel medium class'
|
|
||||||
DORMITORY = 'dormitory'
|
|
||||||
INDUSTRY = 'industry'
|
|
||||||
RESTAURANT = 'restaurant'
|
|
||||||
HEALTH_CARE = 'health care'
|
HEALTH_CARE = 'health care'
|
||||||
RETIREMENT_HOME_OR_ORPHANAGE = 'retirement home or orphanage'
|
RETIREMENT_HOME_OR_ORPHANAGE = 'retirement home or orphanage'
|
||||||
OFFICE_AND_ADMINISTRATION = 'office and administration'
|
COMMERCIAL = 'commercial'
|
||||||
|
STRIP_MALL = 'strip mall'
|
||||||
|
SUPERMARKET = 'supermarket'
|
||||||
|
RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD = 'retail shop without refrigerated food'
|
||||||
|
RETAIL_SHOP_WITH_REFRIGERATED_FOOD = 'retail shop with refrigerated food'
|
||||||
|
RESTAURANT = 'restaurant'
|
||||||
|
QUICK_SERVICE_RESTAURANT = 'quick service restaurant'
|
||||||
|
FULL_SERVICE_RESTAURANT = 'full service restaurant'
|
||||||
|
HOTEL = 'hotel'
|
||||||
|
HOTEL_MEDIUM_CLASS = 'hotel medium class'
|
||||||
|
SMALL_HOTEL = 'small hotel'
|
||||||
|
LARGE_HOTEL = 'large hotel'
|
||||||
|
DORMITORY = 'dormitory'
|
||||||
EVENT_LOCATION = 'event location'
|
EVENT_LOCATION = 'event location'
|
||||||
|
CONVENTION_CENTER = 'convention center'
|
||||||
HALL = 'hall'
|
HALL = 'hall'
|
||||||
SPORTS_LOCATION = 'sports location'
|
|
||||||
LABOR = 'labor'
|
|
||||||
GREEN_HOUSE = 'green house'
|
GREEN_HOUSE = 'green house'
|
||||||
|
INDUSTRY = 'industry'
|
||||||
|
WORKSHOP = 'workshop'
|
||||||
|
WAREHOUSE = 'warehouse'
|
||||||
|
WAREHOUSE_REFRIGERATED = 'warehouse refrigerated'
|
||||||
|
SPORTS_LOCATION = 'sports location'
|
||||||
|
SPORTS_ARENA = 'sports arena'
|
||||||
|
GYMNASIUM = 'gymnasium'
|
||||||
|
MOTION_PICTURE_THEATRE = 'motion picture theatre'
|
||||||
|
MUSEUM = 'museum'
|
||||||
|
PERFORMING_ARTS_THEATRE = 'performing arts theatre'
|
||||||
|
TRANSPORTATION = 'transportation'
|
||||||
|
AUTOMOTIVE_FACILITY = 'automotive facility'
|
||||||
|
PARKING_GARAGE = 'parking garage'
|
||||||
|
RELIGIOUS = 'religious'
|
||||||
NON_HEATED = 'non-heated'
|
NON_HEATED = 'non-heated'
|
||||||
|
|
||||||
LIGHTING = 'Lights'
|
LIGHTING = 'Lights'
|
||||||
|
|
0
hub/helpers/dictionaries.py
Normal file
0
hub/helpers/dictionaries.py
Normal file
|
@ -29,7 +29,7 @@ class MonthlyToHourlyDemand:
|
||||||
# todo: this method and the insel model have to be reviewed for more than one thermal zone
|
# todo: this method and the insel model have to be reviewed for more than one thermal zone
|
||||||
external_temp = self._building.external_temperature[cte.HOUR]
|
external_temp = self._building.external_temperature[cte.HOUR]
|
||||||
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
|
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
|
||||||
for usage_zone in self._building.usage_zones:
|
for usage_zone in self._building.usages:
|
||||||
temp_set = float(usage_zone.heating_setpoint)-3
|
temp_set = float(usage_zone.heating_setpoint)-3
|
||||||
temp_back = float(usage_zone.heating_setback)-3
|
temp_back = float(usage_zone.heating_setback)-3
|
||||||
# todo: if these are data frames, then they should be called as (Occupancy should be in low case):
|
# todo: if these are data frames, then they should be called as (Occupancy should be in low case):
|
||||||
|
@ -90,7 +90,7 @@ class MonthlyToHourlyDemand:
|
||||||
# todo: this method and the insel model have to be reviewed for more than one thermal zone
|
# todo: this method and the insel model have to be reviewed for more than one thermal zone
|
||||||
external_temp = self._building.external_temperature[cte.HOUR]
|
external_temp = self._building.external_temperature[cte.HOUR]
|
||||||
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
|
# todo: review index depending on how the schedules are defined, either 8760 or 24 hours
|
||||||
for usage_zone in self._building.usage_zones:
|
for usage_zone in self._building.usages:
|
||||||
temp_set = float(usage_zone.cooling_setpoint)
|
temp_set = float(usage_zone.cooling_setpoint)
|
||||||
temp_back = 100
|
temp_back = 100
|
||||||
occupancy = Occupant().get_complete_year_schedule(usage_zone.schedules['Occupancy'])
|
occupancy = Occupant().get_complete_year_schedule(usage_zone.schedules['Occupancy'])
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
from hub.helpers import constants as cte
|
from hub.helpers import constants as cte
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,30 +13,6 @@ class ConstructionHelper:
|
||||||
Construction helper
|
Construction helper
|
||||||
"""
|
"""
|
||||||
# NREL
|
# NREL
|
||||||
_function_to_nrel = {
|
|
||||||
cte.RESIDENTIAL: 'residential',
|
|
||||||
cte.SINGLE_FAMILY_HOUSE: 'residential',
|
|
||||||
cte.MULTI_FAMILY_HOUSE: 'residential',
|
|
||||||
cte.ROW_HOSE: 'residential',
|
|
||||||
cte.MID_RISE_APARTMENT: 'midrise apartment',
|
|
||||||
cte.HIGH_RISE_APARTMENT: 'high-rise apartment',
|
|
||||||
cte.SMALL_OFFICE: 'small office',
|
|
||||||
cte.MEDIUM_OFFICE: 'medium office',
|
|
||||||
cte.LARGE_OFFICE: 'large office',
|
|
||||||
cte.PRIMARY_SCHOOL: 'primary school',
|
|
||||||
cte.SECONDARY_SCHOOL: 'secondary school',
|
|
||||||
cte.STAND_ALONE_RETAIL: 'stand-alone retail',
|
|
||||||
cte.HOSPITAL: 'hospital',
|
|
||||||
cte.OUT_PATIENT_HEALTH_CARE: 'outpatient healthcare',
|
|
||||||
cte.STRIP_MALL: 'strip mall',
|
|
||||||
cte.SUPERMARKET: 'supermarket',
|
|
||||||
cte.WAREHOUSE: 'warehouse',
|
|
||||||
cte.QUICK_SERVICE_RESTAURANT: 'quick service restaurant',
|
|
||||||
cte.FULL_SERVICE_RESTAURANT: 'full service restaurant',
|
|
||||||
cte.SMALL_HOTEL: 'small hotel',
|
|
||||||
cte.LARGE_HOTEL: 'large hotel'
|
|
||||||
}
|
|
||||||
|
|
||||||
_nrel_standards = {
|
_nrel_standards = {
|
||||||
'ASHRAE Std189': 1,
|
'ASHRAE Std189': 1,
|
||||||
'ASHRAE 90.1_2004': 2
|
'ASHRAE 90.1_2004': 2
|
||||||
|
@ -71,18 +47,6 @@ class ConstructionHelper:
|
||||||
cte.ROOF: 'roof'
|
cte.ROOF: 'roof'
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def nrel_from_libs_function(function):
|
|
||||||
"""
|
|
||||||
Get NREL function from the given internal function key
|
|
||||||
:param function: str
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return ConstructionHelper._function_to_nrel[function]
|
|
||||||
except KeyError:
|
|
||||||
sys.stderr.write('Error: keyword not found.\n')
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def yoc_to_nrel_standard(year_of_construction):
|
def yoc_to_nrel_standard(year_of_construction):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -49,7 +49,7 @@ class StoreysGeneration:
|
||||||
thermal_zones = [storey.thermal_zone]
|
thermal_zones = [storey.thermal_zone]
|
||||||
else:
|
else:
|
||||||
# internal thermal boundary -> two thermal zones
|
# internal thermal boundary -> two thermal zones
|
||||||
grad = np.rad2deg(thermal_boundary.inclination)
|
grad = np.rad2deg(thermal_boundary.parent_surface.inclination)
|
||||||
if grad >= 170:
|
if grad >= 170:
|
||||||
thermal_zones = [storey.thermal_zone, storey.neighbours[0]]
|
thermal_zones = [storey.thermal_zone, storey.neighbours[0]]
|
||||||
else:
|
else:
|
||||||
|
@ -116,7 +116,7 @@ class StoreysGeneration:
|
||||||
thermal_zones = [storey.thermal_zone]
|
thermal_zones = [storey.thermal_zone]
|
||||||
else:
|
else:
|
||||||
# internal thermal boundary -> two thermal zones
|
# internal thermal boundary -> two thermal zones
|
||||||
grad = np.rad2deg(thermal_boundary.inclination)
|
grad = np.rad2deg(thermal_boundary.parent_surface.inclination)
|
||||||
if grad >= 170:
|
if grad >= 170:
|
||||||
thermal_zones = [storey.thermal_zone, storey.neighbours[0]]
|
thermal_zones = [storey.thermal_zone, storey.neighbours[0]]
|
||||||
else:
|
else:
|
||||||
|
|
189
hub/imports/construction/nrcan_physics_parameters.py
Normal file
189
hub/imports/construction/nrcan_physics_parameters.py
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
"""
|
||||||
|
NrcanPhysicsParameters import the construction and material information defined by NRCAN
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
|
||||||
|
from hub.city_model_structure.building_demand.layer import Layer
|
||||||
|
from hub.city_model_structure.building_demand.material import Material
|
||||||
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
|
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
|
||||||
|
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
|
||||||
|
|
||||||
|
|
||||||
|
class NrcanPhysicsParameters:
|
||||||
|
"""
|
||||||
|
NrcanPhysicsParameters class
|
||||||
|
"""
|
||||||
|
def __init__(self, city, base_path, divide_in_storeys=False):
|
||||||
|
self._city = city
|
||||||
|
self._path = base_path
|
||||||
|
self._divide_in_storeys = divide_in_storeys
|
||||||
|
self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name)
|
||||||
|
|
||||||
|
def enrich_buildings(self):
|
||||||
|
"""
|
||||||
|
Returns the city with the construction parameters assigned to the buildings
|
||||||
|
"""
|
||||||
|
city = self._city
|
||||||
|
canel_catalog = ConstructionCatalogFactory('nrcan').catalog
|
||||||
|
for building in city.buildings:
|
||||||
|
try:
|
||||||
|
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
|
||||||
|
archetype = self._search_archetype(canel_catalog, function, building.year_of_construction,
|
||||||
|
self._climate_zone)
|
||||||
|
except KeyError:
|
||||||
|
sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: '
|
||||||
|
f'{building.function} and building year of construction: {building.year_of_construction} '
|
||||||
|
f'and climate zone reference norm {self._climate_zone}\n')
|
||||||
|
return
|
||||||
|
|
||||||
|
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
|
||||||
|
# one thermal zone per storey is assigned
|
||||||
|
if len(building.internal_zones) == 1:
|
||||||
|
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(float(building.eave_height) / float(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:
|
||||||
|
self._assign_values(internal_zone.thermal_zones, archetype)
|
||||||
|
for thermal_zone in internal_zone.thermal_zones:
|
||||||
|
self._calculate_view_factors(thermal_zone)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
|
||||||
|
nrel_archetypes = nrel_catalog.entries('archetypes')
|
||||||
|
for building_archetype in nrel_archetypes:
|
||||||
|
construction_period_limits = building_archetype.construction_period.split(' - ')
|
||||||
|
if construction_period_limits[1] == 'PRESENT':
|
||||||
|
construction_period_limits[1] = 3000
|
||||||
|
if int(construction_period_limits[0]) <= int(year_of_construction) < int(construction_period_limits[1]):
|
||||||
|
if (str(function) == str(building_archetype.function)) and \
|
||||||
|
(climate_zone == str(building_archetype.climate_zone)):
|
||||||
|
return building_archetype
|
||||||
|
raise KeyError('archetype not found')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_construction_in_archetype(archetype, construction_type):
|
||||||
|
construction_archetypes = archetype.constructions
|
||||||
|
for construction_archetype in construction_archetypes:
|
||||||
|
if str(construction_type) == str(construction_archetype.type):
|
||||||
|
return construction_archetype
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _assign_values(self, thermal_zones, archetype):
|
||||||
|
for thermal_zone in thermal_zones:
|
||||||
|
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
|
||||||
|
thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
|
||||||
|
thermal_zone.indirectly_heated_area_ratio = archetype.indirect_heated_ratio
|
||||||
|
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
|
||||||
|
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
|
||||||
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||||
|
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
|
||||||
|
thermal_boundary.construction_name = construction_archetype.name
|
||||||
|
try:
|
||||||
|
thermal_boundary.window_ratio = construction_archetype.window_ratio
|
||||||
|
except ValueError:
|
||||||
|
# This is the normal operation way when the windows are defined in the geometry
|
||||||
|
continue
|
||||||
|
thermal_boundary.layers = []
|
||||||
|
for layer_archetype in construction_archetype.layers:
|
||||||
|
layer = Layer()
|
||||||
|
layer.thickness = layer_archetype.thickness
|
||||||
|
material = Material()
|
||||||
|
archetype_material = layer_archetype.material
|
||||||
|
material.name = archetype_material.name
|
||||||
|
material.id = archetype_material.id
|
||||||
|
material.no_mass = archetype_material.no_mass
|
||||||
|
if archetype_material.no_mass:
|
||||||
|
material.thermal_resistance = archetype_material.thermal_resistance
|
||||||
|
else:
|
||||||
|
material.density = archetype_material.density
|
||||||
|
material.conductivity = archetype_material.conductivity
|
||||||
|
material.specific_heat = archetype_material.specific_heat
|
||||||
|
material.solar_absorptance = archetype_material.solar_absorptance
|
||||||
|
material.thermal_absorptance = archetype_material.thermal_absorptance
|
||||||
|
material.visible_absorptance = archetype_material.visible_absorptance
|
||||||
|
layer.material = material
|
||||||
|
thermal_boundary.layers.append(layer)
|
||||||
|
# The agreement is that the layers are defined from outside to inside
|
||||||
|
external_layer = construction_archetype.layers[0]
|
||||||
|
external_surface = thermal_boundary.parent_surface
|
||||||
|
external_surface.short_wave_reflectance = 1 - float(external_layer.material.solar_absorptance)
|
||||||
|
external_surface.long_wave_emittance = 1 - float(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 - float(internal_layer.material.solar_absorptance)
|
||||||
|
internal_surface.long_wave_emittance = 1 - float(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
|
||||||
|
building.storeys_above_ground = 1
|
||||||
|
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
|
||||||
|
divide_in_storeys=divide_in_storeys).thermal_zones
|
||||||
|
building.internal_zones[0].thermal_zones = thermal_zones
|
196
hub/imports/construction/nrel_physics_parameters.py
Normal file
196
hub/imports/construction/nrel_physics_parameters.py
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
"""
|
||||||
|
NrelPhysicsParameters import the construction and material information defined by NREL
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from hub.hub_logger import logger
|
||||||
|
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
|
||||||
|
from hub.city_model_structure.building_demand.layer import Layer
|
||||||
|
from hub.city_model_structure.building_demand.material import Material
|
||||||
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
|
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
|
||||||
|
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
|
||||||
|
|
||||||
|
|
||||||
|
class NrelPhysicsParameters:
|
||||||
|
"""
|
||||||
|
NrelPhysicsParameters class
|
||||||
|
"""
|
||||||
|
def __init__(self, city, base_path, divide_in_storeys=False):
|
||||||
|
self._city = city
|
||||||
|
self._path = base_path
|
||||||
|
self._divide_in_storeys = divide_in_storeys
|
||||||
|
print(city.name)
|
||||||
|
self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name)
|
||||||
|
|
||||||
|
def enrich_buildings(self):
|
||||||
|
"""
|
||||||
|
Returns the city with the construction parameters assigned to the buildings
|
||||||
|
"""
|
||||||
|
city = self._city
|
||||||
|
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
|
||||||
|
for building in city.buildings:
|
||||||
|
try:
|
||||||
|
function = Dictionaries().hub_function_to_nrel_construction_function[building.function]
|
||||||
|
archetype = self._search_archetype(nrel_catalog, function, building.year_of_construction,
|
||||||
|
self._climate_zone)
|
||||||
|
except KeyError:
|
||||||
|
logger.error(f'Building {building.name} has unknown archetype for building function: {building.function} '
|
||||||
|
f'and building year of construction: {building.year_of_construction} '
|
||||||
|
f'and climate zone reference norm {self._climate_zone}\n')
|
||||||
|
sys.stderr.write(f'Building {building.name} has unknown archetype for building function: {building.function} '
|
||||||
|
f'and building year of construction: {building.year_of_construction} '
|
||||||
|
f'and climate zone reference norm {self._climate_zone}\n')
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
|
||||||
|
# one thermal zone per storey is assigned
|
||||||
|
if len(building.internal_zones) == 1:
|
||||||
|
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(float(building.eave_height) / float(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:
|
||||||
|
self._assign_values(internal_zone.thermal_zones, archetype)
|
||||||
|
for thermal_zone in internal_zone.thermal_zones:
|
||||||
|
self._calculate_view_factors(thermal_zone)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
|
||||||
|
nrel_archetypes = nrel_catalog.entries('archetypes')
|
||||||
|
for building_archetype in nrel_archetypes:
|
||||||
|
construction_period_limits = building_archetype.construction_period.split(' - ')
|
||||||
|
if construction_period_limits[1] == 'PRESENT':
|
||||||
|
construction_period_limits[1] = 3000
|
||||||
|
if int(construction_period_limits[0]) <= int(year_of_construction) < int(construction_period_limits[1]):
|
||||||
|
if (str(function) == str(building_archetype.function)) and \
|
||||||
|
(climate_zone == str(building_archetype.climate_zone)):
|
||||||
|
return building_archetype
|
||||||
|
raise KeyError('archetype not found')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_construction_in_archetype(archetype, construction_type):
|
||||||
|
construction_archetypes = archetype.constructions
|
||||||
|
for construction_archetype in construction_archetypes:
|
||||||
|
if str(construction_type) == str(construction_archetype.type):
|
||||||
|
return construction_archetype
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _assign_values(self, thermal_zones, archetype):
|
||||||
|
for thermal_zone in thermal_zones:
|
||||||
|
thermal_zone.additional_thermal_bridge_u_value = archetype.extra_loses_due_to_thermal_bridges
|
||||||
|
thermal_zone.effective_thermal_capacity = archetype.thermal_capacity
|
||||||
|
thermal_zone.indirectly_heated_area_ratio = archetype.indirect_heated_ratio
|
||||||
|
thermal_zone.infiltration_rate_system_on = archetype.infiltration_rate_for_ventilation_system_on
|
||||||
|
thermal_zone.infiltration_rate_system_off = archetype.infiltration_rate_for_ventilation_system_off
|
||||||
|
for thermal_boundary in thermal_zone.thermal_boundaries:
|
||||||
|
construction_archetype = self._search_construction_in_archetype(archetype, thermal_boundary.type)
|
||||||
|
thermal_boundary.construction_name = construction_archetype.name
|
||||||
|
try:
|
||||||
|
thermal_boundary.window_ratio = construction_archetype.window_ratio
|
||||||
|
except ValueError:
|
||||||
|
# This is the normal operation way when the windows are defined in the geometry
|
||||||
|
continue
|
||||||
|
thermal_boundary.layers = []
|
||||||
|
for layer_archetype in construction_archetype.layers:
|
||||||
|
layer = Layer()
|
||||||
|
layer.thickness = layer_archetype.thickness
|
||||||
|
material = Material()
|
||||||
|
archetype_material = layer_archetype.material
|
||||||
|
material.name = archetype_material.name
|
||||||
|
material.id = archetype_material.id
|
||||||
|
material.no_mass = archetype_material.no_mass
|
||||||
|
if archetype_material.no_mass:
|
||||||
|
material.thermal_resistance = archetype_material.thermal_resistance
|
||||||
|
else:
|
||||||
|
material.density = archetype_material.density
|
||||||
|
material.conductivity = archetype_material.conductivity
|
||||||
|
material.specific_heat = archetype_material.specific_heat
|
||||||
|
material.solar_absorptance = archetype_material.solar_absorptance
|
||||||
|
material.thermal_absorptance = archetype_material.thermal_absorptance
|
||||||
|
material.visible_absorptance = archetype_material.visible_absorptance
|
||||||
|
layer.material = material
|
||||||
|
thermal_boundary.layers.append(layer)
|
||||||
|
# The agreement is that the layers are defined from outside to inside
|
||||||
|
external_layer = construction_archetype.layers[0]
|
||||||
|
external_surface = thermal_boundary.parent_surface
|
||||||
|
external_surface.short_wave_reflectance = 1 - float(external_layer.material.solar_absorptance)
|
||||||
|
external_surface.long_wave_emittance = 1 - float(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 - float(internal_layer.material.solar_absorptance)
|
||||||
|
internal_surface.long_wave_emittance = 1 - float(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
|
||||||
|
building.storeys_above_ground = 1
|
||||||
|
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
|
||||||
|
divide_in_storeys=divide_in_storeys).thermal_zones
|
||||||
|
building.internal_zones[0].thermal_zones = thermal_zones
|
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
UsPhysicsParameters import the construction and material information for US
|
NrelPhysicsParameters import the construction and material information defined by NREL
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
@ -7,33 +7,37 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from hub.imports.construction.nrel_physics_interface import NrelPhysicsInterface
|
from hub.hub_logger import logger
|
||||||
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.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.city_model_structure.building_demand.material import Material
|
||||||
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
|
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
|
||||||
from hub.hub_logger import logger
|
from hub.imports.construction.helpers.storeys_generation import StoreysGeneration
|
||||||
|
|
||||||
|
|
||||||
class UsPhysicsParameters(NrelPhysicsInterface):
|
class NrelPhysicsParameters:
|
||||||
"""
|
"""
|
||||||
UsPhysicsParameters class
|
NrelPhysicsParameters class
|
||||||
"""
|
"""
|
||||||
def __init__(self, city, base_path, divide_in_storeys=False):
|
def __init__(self, city, base_path, divide_in_storeys=False):
|
||||||
self._city = city
|
self._city = city
|
||||||
self._path = base_path
|
self._path = base_path
|
||||||
self._divide_in_storeys = divide_in_storeys
|
self._divide_in_storeys = divide_in_storeys
|
||||||
|
print(city.name)
|
||||||
self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name)
|
self._climate_zone = ConstructionHelper.city_to_nrel_climate_zone(city.name)
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
def enrich_buildings(self):
|
def enrich_buildings(self):
|
||||||
"""
|
"""
|
||||||
Returns the city with the construction parameters assigned to the buildings
|
Returns the city with the construction parameters assigned to the buildings
|
||||||
"""
|
"""
|
||||||
city = self._city
|
city = self._city
|
||||||
|
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
try:
|
try:
|
||||||
archetype = self._search_archetype(building.function, building.year_of_construction, self._climate_zone)
|
function = Dictionaries().hub_function_to_nrel_construction_function[building.function]
|
||||||
|
archetype = self._search_archetype(nrel_catalog, function, building.year_of_construction,
|
||||||
|
self._climate_zone)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
||||||
logger.error(f'Building {building.name} has unknown archetype for building function: {building.function} '
|
logger.error(f'Building {building.name} has unknown archetype for building function: {building.function} '
|
||||||
|
@ -69,8 +73,7 @@ class UsPhysicsParameters(NrelPhysicsInterface):
|
||||||
self._calculate_view_factors(thermal_zone)
|
self._calculate_view_factors(thermal_zone)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _search_archetype(function, year_of_construction, climate_zone):
|
def _search_archetype(nrel_catalog, function, year_of_construction, climate_zone):
|
||||||
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
|
|
||||||
nrel_archetypes = nrel_catalog.entries('archetypes')
|
nrel_archetypes = nrel_catalog.entries('archetypes')
|
||||||
for building_archetype in nrel_archetypes:
|
for building_archetype in nrel_archetypes:
|
||||||
construction_period_limits = building_archetype.construction_period.split(' - ')
|
construction_period_limits = building_archetype.construction_period.split(' - ')
|
||||||
|
@ -142,3 +145,53 @@ class UsPhysicsParameters(NrelPhysicsInterface):
|
||||||
thermal_opening.frame_ratio = window_archetype.frame_ratio
|
thermal_opening.frame_ratio = window_archetype.frame_ratio
|
||||||
thermal_opening.g_value = window_archetype.g_value
|
thermal_opening.g_value = window_archetype.g_value
|
||||||
thermal_opening.overall_u_value = window_archetype.overall_u_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
|
||||||
|
building.storeys_above_ground = 1
|
||||||
|
thermal_zones = StoreysGeneration(building, building.internal_zones[0],
|
||||||
|
divide_in_storeys=divide_in_storeys).thermal_zones
|
||||||
|
building.internal_zones[0].thermal_zones = thermal_zones
|
||||||
|
|
|
@ -3,14 +3,17 @@ ConstructionFactory (before PhysicsFactory) retrieve the specific construction m
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from hub.imports.construction.us_physics_parameters import UsPhysicsParameters
|
from hub.imports.construction.nrel_physics_parameters import NrelPhysicsParameters
|
||||||
|
from hub.imports.construction.nrcan_physics_parameters import NrcanPhysicsParameters
|
||||||
|
|
||||||
|
|
||||||
class ConstructionFactory:
|
class ConstructionFactory:
|
||||||
"""
|
"""
|
||||||
PhysicsFactor class
|
ConstructionFactory class
|
||||||
"""
|
"""
|
||||||
def __init__(self, handler, city, base_path=None):
|
def __init__(self, handler, city, base_path=None):
|
||||||
if base_path is None:
|
if base_path is None:
|
||||||
|
@ -23,7 +26,14 @@ class ConstructionFactory:
|
||||||
"""
|
"""
|
||||||
Enrich the city by using NREL information
|
Enrich the city by using NREL information
|
||||||
"""
|
"""
|
||||||
UsPhysicsParameters(self._city, self._base_path).enrich_buildings()
|
NrelPhysicsParameters(self._city, self._base_path).enrich_buildings()
|
||||||
|
self._city.level_of_detail.construction = 2
|
||||||
|
|
||||||
|
def _nrcan(self):
|
||||||
|
"""
|
||||||
|
Enrich the city by using NRCAN information
|
||||||
|
"""
|
||||||
|
NrcanPhysicsParameters(self._city, self._base_path).enrich_buildings()
|
||||||
self._city.level_of_detail.construction = 2
|
self._city.level_of_detail.construction = 2
|
||||||
|
|
||||||
def enrich(self):
|
def enrich(self):
|
||||||
|
@ -38,4 +48,4 @@ class ConstructionFactory:
|
||||||
Enrich the city given to the class using the class given handler
|
Enrich the city given to the class using the class given handler
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
UsPhysicsParameters(self._city, self._base_path).enrich_buildings()
|
NrelPhysicsParameters(self._city, self._base_path).enrich_buildings()
|
||||||
|
|
|
@ -54,7 +54,6 @@ class CityGml:
|
||||||
}, force_list=force_list)
|
}, force_list=force_list)
|
||||||
|
|
||||||
self._city_objects = None
|
self._city_objects = None
|
||||||
self._geometry = GeometryHelper()
|
|
||||||
if 'boundedBy' in self._gml['CityModel']:
|
if 'boundedBy' in self._gml['CityModel']:
|
||||||
for bound in self._gml['CityModel']['boundedBy']:
|
for bound in self._gml['CityModel']['boundedBy']:
|
||||||
envelope = bound['Envelope']
|
envelope = bound['Envelope']
|
||||||
|
|
|
@ -5,7 +5,6 @@ Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,276 +12,6 @@ class GeometryHelper:
|
||||||
"""
|
"""
|
||||||
Geometry helper
|
Geometry helper
|
||||||
"""
|
"""
|
||||||
# function
|
|
||||||
_pluto_to_function = {
|
|
||||||
'A0': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A1': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A2': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A3': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A4': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A5': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A6': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A7': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A8': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'A9': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'B1': cte.MULTI_FAMILY_HOUSE,
|
|
||||||
'B2': cte.MULTI_FAMILY_HOUSE,
|
|
||||||
'B3': cte.MULTI_FAMILY_HOUSE,
|
|
||||||
'B9': cte.MULTI_FAMILY_HOUSE,
|
|
||||||
'C0': cte.RESIDENTIAL,
|
|
||||||
'C1': cte.RESIDENTIAL,
|
|
||||||
'C2': cte.RESIDENTIAL,
|
|
||||||
'C3': cte.RESIDENTIAL,
|
|
||||||
'C4': cte.RESIDENTIAL,
|
|
||||||
'C5': cte.RESIDENTIAL,
|
|
||||||
'C6': cte.RESIDENTIAL,
|
|
||||||
'C7': cte.RESIDENTIAL,
|
|
||||||
'C8': cte.RESIDENTIAL,
|
|
||||||
'C9': cte.RESIDENTIAL,
|
|
||||||
'D0': cte.RESIDENTIAL,
|
|
||||||
'D1': cte.RESIDENTIAL,
|
|
||||||
'D2': cte.RESIDENTIAL,
|
|
||||||
'D3': cte.RESIDENTIAL,
|
|
||||||
'D4': cte.RESIDENTIAL,
|
|
||||||
'D5': cte.RESIDENTIAL,
|
|
||||||
'D6': cte.RESIDENTIAL,
|
|
||||||
'D7': cte.RESIDENTIAL,
|
|
||||||
'D8': cte.RESIDENTIAL,
|
|
||||||
'D9': cte.RESIDENTIAL,
|
|
||||||
'E1': cte.WAREHOUSE,
|
|
||||||
'E3': cte.WAREHOUSE,
|
|
||||||
'E4': cte.WAREHOUSE,
|
|
||||||
'E5': cte.WAREHOUSE,
|
|
||||||
'E7': cte.WAREHOUSE,
|
|
||||||
'E9': cte.WAREHOUSE,
|
|
||||||
'F1': cte.WAREHOUSE,
|
|
||||||
'F2': cte.WAREHOUSE,
|
|
||||||
'F4': cte.WAREHOUSE,
|
|
||||||
'F5': cte.WAREHOUSE,
|
|
||||||
'F8': cte.WAREHOUSE,
|
|
||||||
'F9': cte.WAREHOUSE,
|
|
||||||
'G0': cte.SMALL_OFFICE,
|
|
||||||
'G1': cte.SMALL_OFFICE,
|
|
||||||
'G2': cte.SMALL_OFFICE,
|
|
||||||
'G3': cte.SMALL_OFFICE,
|
|
||||||
'G4': cte.SMALL_OFFICE,
|
|
||||||
'G5': cte.SMALL_OFFICE,
|
|
||||||
'G6': cte.SMALL_OFFICE,
|
|
||||||
'G7': cte.SMALL_OFFICE,
|
|
||||||
'G8': cte.SMALL_OFFICE,
|
|
||||||
'G9': cte.SMALL_OFFICE,
|
|
||||||
'H1': cte.HOTEL,
|
|
||||||
'H2': cte.HOTEL,
|
|
||||||
'H3': cte.HOTEL,
|
|
||||||
'H4': cte.HOTEL,
|
|
||||||
'H5': cte.HOTEL,
|
|
||||||
'H6': cte.HOTEL,
|
|
||||||
'H7': cte.HOTEL,
|
|
||||||
'H8': cte.HOTEL,
|
|
||||||
'H9': cte.HOTEL,
|
|
||||||
'HB': cte.HOTEL,
|
|
||||||
'HH': cte.HOTEL,
|
|
||||||
'HR': cte.HOTEL,
|
|
||||||
'HS': cte.HOTEL,
|
|
||||||
'I1': cte.HOSPITAL,
|
|
||||||
'I2': cte.OUT_PATIENT_HEALTH_CARE,
|
|
||||||
'I3': cte.OUT_PATIENT_HEALTH_CARE,
|
|
||||||
'I4': cte.RESIDENTIAL,
|
|
||||||
'I5': cte.OUT_PATIENT_HEALTH_CARE,
|
|
||||||
'I6': cte.OUT_PATIENT_HEALTH_CARE,
|
|
||||||
'I7': cte.OUT_PATIENT_HEALTH_CARE,
|
|
||||||
'I9': cte.OUT_PATIENT_HEALTH_CARE,
|
|
||||||
'J1': cte.LARGE_OFFICE,
|
|
||||||
'J2': cte.LARGE_OFFICE,
|
|
||||||
'J3': cte.LARGE_OFFICE,
|
|
||||||
'J4': cte.LARGE_OFFICE,
|
|
||||||
'J5': cte.LARGE_OFFICE,
|
|
||||||
'J6': cte.LARGE_OFFICE,
|
|
||||||
'J7': cte.LARGE_OFFICE,
|
|
||||||
'J8': cte.LARGE_OFFICE,
|
|
||||||
'J9': cte.LARGE_OFFICE,
|
|
||||||
'K1': cte.STRIP_MALL,
|
|
||||||
'K2': cte.STRIP_MALL,
|
|
||||||
'K3': cte.STRIP_MALL,
|
|
||||||
'K4': cte.RESIDENTIAL,
|
|
||||||
'K5': cte.RESTAURANT,
|
|
||||||
'K6': cte.SUPERMARKET,
|
|
||||||
'K7': cte.SUPERMARKET,
|
|
||||||
'K8': cte.SUPERMARKET,
|
|
||||||
'K9': cte.SUPERMARKET,
|
|
||||||
'L1': cte.RESIDENTIAL,
|
|
||||||
'L2': cte.RESIDENTIAL,
|
|
||||||
'L3': cte.RESIDENTIAL,
|
|
||||||
'L8': cte.RESIDENTIAL,
|
|
||||||
'L9': cte.RESIDENTIAL,
|
|
||||||
'M1': cte.LARGE_OFFICE,
|
|
||||||
'M2': cte.LARGE_OFFICE,
|
|
||||||
'M3': cte.LARGE_OFFICE,
|
|
||||||
'M4': cte.LARGE_OFFICE,
|
|
||||||
'M9': cte.LARGE_OFFICE,
|
|
||||||
'N1': cte.RESIDENTIAL,
|
|
||||||
'N2': cte.RESIDENTIAL,
|
|
||||||
'N3': cte.RESIDENTIAL,
|
|
||||||
'N4': cte.RESIDENTIAL,
|
|
||||||
'N9': cte.RESIDENTIAL,
|
|
||||||
'O1': cte.SMALL_OFFICE,
|
|
||||||
'O2': cte.SMALL_OFFICE,
|
|
||||||
'O3': cte.SMALL_OFFICE,
|
|
||||||
'O4': cte.SMALL_OFFICE,
|
|
||||||
'O5': cte.SMALL_OFFICE,
|
|
||||||
'O6': cte.SMALL_OFFICE,
|
|
||||||
'O7': cte.SMALL_OFFICE,
|
|
||||||
'O8': cte.SMALL_OFFICE,
|
|
||||||
'O9': cte.SMALL_OFFICE,
|
|
||||||
'P1': cte.LARGE_OFFICE,
|
|
||||||
'P2': cte.HOTEL,
|
|
||||||
'P3': cte.SMALL_OFFICE,
|
|
||||||
'P4': cte.SMALL_OFFICE,
|
|
||||||
'P5': cte.SMALL_OFFICE,
|
|
||||||
'P6': cte.SMALL_OFFICE,
|
|
||||||
'P7': cte.LARGE_OFFICE,
|
|
||||||
'P8': cte.LARGE_OFFICE,
|
|
||||||
'P9': cte.SMALL_OFFICE,
|
|
||||||
'Q0': cte.SMALL_OFFICE,
|
|
||||||
'Q1': cte.SMALL_OFFICE,
|
|
||||||
'Q2': cte.SMALL_OFFICE,
|
|
||||||
'Q3': cte.SMALL_OFFICE,
|
|
||||||
'Q4': cte.SMALL_OFFICE,
|
|
||||||
'Q5': cte.SMALL_OFFICE,
|
|
||||||
'Q6': cte.SMALL_OFFICE,
|
|
||||||
'Q7': cte.SMALL_OFFICE,
|
|
||||||
'Q8': cte.SMALL_OFFICE,
|
|
||||||
'Q9': cte.SMALL_OFFICE,
|
|
||||||
'R0': cte.RESIDENTIAL,
|
|
||||||
'R1': cte.RESIDENTIAL,
|
|
||||||
'R2': cte.RESIDENTIAL,
|
|
||||||
'R3': cte.RESIDENTIAL,
|
|
||||||
'R4': cte.RESIDENTIAL,
|
|
||||||
'R5': cte.RESIDENTIAL,
|
|
||||||
'R6': cte.RESIDENTIAL,
|
|
||||||
'R7': cte.RESIDENTIAL,
|
|
||||||
'R8': cte.RESIDENTIAL,
|
|
||||||
'R9': cte.RESIDENTIAL,
|
|
||||||
'RA': cte.RESIDENTIAL,
|
|
||||||
'RB': cte.RESIDENTIAL,
|
|
||||||
'RC': cte.RESIDENTIAL,
|
|
||||||
'RD': cte.RESIDENTIAL,
|
|
||||||
'RG': cte.RESIDENTIAL,
|
|
||||||
'RH': cte.RESIDENTIAL,
|
|
||||||
'RI': cte.RESIDENTIAL,
|
|
||||||
'RK': cte.RESIDENTIAL,
|
|
||||||
'RM': cte.RESIDENTIAL,
|
|
||||||
'RR': cte.RESIDENTIAL,
|
|
||||||
'RS': cte.RESIDENTIAL,
|
|
||||||
'RW': cte.RESIDENTIAL,
|
|
||||||
'RX': cte.RESIDENTIAL,
|
|
||||||
'RZ': cte.RESIDENTIAL,
|
|
||||||
'S0': cte.RESIDENTIAL,
|
|
||||||
'S1': cte.RESIDENTIAL,
|
|
||||||
'S2': cte.RESIDENTIAL,
|
|
||||||
'S3': cte.RESIDENTIAL,
|
|
||||||
'S4': cte.RESIDENTIAL,
|
|
||||||
'S5': cte.RESIDENTIAL,
|
|
||||||
'S9': cte.RESIDENTIAL,
|
|
||||||
'U0': cte.WAREHOUSE,
|
|
||||||
'U1': cte.WAREHOUSE,
|
|
||||||
'U2': cte.WAREHOUSE,
|
|
||||||
'U3': cte.WAREHOUSE,
|
|
||||||
'U4': cte.WAREHOUSE,
|
|
||||||
'U5': cte.WAREHOUSE,
|
|
||||||
'U6': cte.WAREHOUSE,
|
|
||||||
'U7': cte.WAREHOUSE,
|
|
||||||
'U8': cte.WAREHOUSE,
|
|
||||||
'U9': cte.WAREHOUSE,
|
|
||||||
'W1': cte.PRIMARY_SCHOOL,
|
|
||||||
'W2': cte.PRIMARY_SCHOOL,
|
|
||||||
'W3': cte.SECONDARY_SCHOOL,
|
|
||||||
'W4': cte.SECONDARY_SCHOOL,
|
|
||||||
'W5': cte.SECONDARY_SCHOOL,
|
|
||||||
'W6': cte.SECONDARY_SCHOOL,
|
|
||||||
'W7': cte.SECONDARY_SCHOOL,
|
|
||||||
'W8': cte.PRIMARY_SCHOOL,
|
|
||||||
'W9': cte.SECONDARY_SCHOOL,
|
|
||||||
'Y1': cte.LARGE_OFFICE,
|
|
||||||
'Y2': cte.LARGE_OFFICE,
|
|
||||||
'Y3': cte.LARGE_OFFICE,
|
|
||||||
'Y4': cte.LARGE_OFFICE,
|
|
||||||
'Y5': cte.LARGE_OFFICE,
|
|
||||||
'Y6': cte.LARGE_OFFICE,
|
|
||||||
'Y7': cte.LARGE_OFFICE,
|
|
||||||
'Y8': cte.LARGE_OFFICE,
|
|
||||||
'Y9': cte.LARGE_OFFICE,
|
|
||||||
'Z1': cte.LARGE_OFFICE
|
|
||||||
}
|
|
||||||
_hft_to_function = {
|
|
||||||
'residential': cte.RESIDENTIAL,
|
|
||||||
'single family house': cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
'multifamily house': cte.MULTI_FAMILY_HOUSE,
|
|
||||||
'hotel': cte.HOTEL,
|
|
||||||
'hospital': cte.HOSPITAL,
|
|
||||||
'outpatient': cte.OUT_PATIENT_HEALTH_CARE,
|
|
||||||
'commercial': cte.SUPERMARKET,
|
|
||||||
'strip mall': cte.STRIP_MALL,
|
|
||||||
'warehouse': cte.WAREHOUSE,
|
|
||||||
'primary school': cte.PRIMARY_SCHOOL,
|
|
||||||
'secondary school': cte.SECONDARY_SCHOOL,
|
|
||||||
'office': cte.MEDIUM_OFFICE,
|
|
||||||
'large office': cte.LARGE_OFFICE
|
|
||||||
}
|
|
||||||
|
|
||||||
# usage
|
|
||||||
_function_to_usage = {
|
|
||||||
cte.RESIDENTIAL: cte.RESIDENTIAL,
|
|
||||||
cte.SINGLE_FAMILY_HOUSE: cte.SINGLE_FAMILY_HOUSE,
|
|
||||||
cte.MULTI_FAMILY_HOUSE: cte.MULTI_FAMILY_HOUSE,
|
|
||||||
cte.ROW_HOSE: cte.RESIDENTIAL,
|
|
||||||
cte.MID_RISE_APARTMENT: cte.RESIDENTIAL,
|
|
||||||
cte.HIGH_RISE_APARTMENT: cte.RESIDENTIAL,
|
|
||||||
cte.SMALL_OFFICE: cte.OFFICE_AND_ADMINISTRATION,
|
|
||||||
cte.MEDIUM_OFFICE: cte.OFFICE_AND_ADMINISTRATION,
|
|
||||||
cte.LARGE_OFFICE: cte.OFFICE_AND_ADMINISTRATION,
|
|
||||||
cte.PRIMARY_SCHOOL: cte.EDUCATION,
|
|
||||||
cte.SECONDARY_SCHOOL: cte.EDUCATION,
|
|
||||||
cte.STAND_ALONE_RETAIL: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
|
|
||||||
cte.HOSPITAL: cte.HEALTH_CARE,
|
|
||||||
cte.OUT_PATIENT_HEALTH_CARE: cte.HEALTH_CARE,
|
|
||||||
cte.STRIP_MALL: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
|
|
||||||
cte.SUPERMARKET: cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD,
|
|
||||||
cte.WAREHOUSE: cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD,
|
|
||||||
cte.QUICK_SERVICE_RESTAURANT: cte.RESTAURANT,
|
|
||||||
cte.FULL_SERVICE_RESTAURANT: cte.RESTAURANT,
|
|
||||||
cte.SMALL_HOTEL: cte.HOTEL,
|
|
||||||
cte.LARGE_HOTEL: cte.HOTEL,
|
|
||||||
cte.INDUSTRY:cte.INDUSTRY
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def libs_function_from_hft(building_hft_function):
|
|
||||||
"""
|
|
||||||
Get internal function from the given HfT function
|
|
||||||
:param building_hft_function: str
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
return GeometryHelper._hft_to_function[building_hft_function]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def libs_function_from_pluto(building_pluto_function):
|
|
||||||
"""
|
|
||||||
Get internal function from the given pluto function
|
|
||||||
:param building_pluto_function: str
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
return GeometryHelper._pluto_to_function[building_pluto_function]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def libs_usage_from_libs_function(building_function):
|
|
||||||
"""
|
|
||||||
Get the internal usage for the given internal building function
|
|
||||||
:param building_function: str
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
return GeometryHelper._function_to_usage[building_function]
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_points_matrix(points):
|
def to_points_matrix(points):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
"""
|
"""
|
||||||
ComnetUsageParameters model the usage properties
|
ComnetUsageParameters extracts the usage properties from Comnet catalog and assigns to each building
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
import copy
|
import copy
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict
|
|
||||||
import pandas as pd
|
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
|
@ -30,162 +28,7 @@ class ComnetUsageParameters:
|
||||||
"""
|
"""
|
||||||
def __init__(self, city, base_path):
|
def __init__(self, city, base_path):
|
||||||
self._city = city
|
self._city = city
|
||||||
self._base_path = str(base_path / 'comnet_archetypes.xlsx')
|
self._path = base_path
|
||||||
self._data = self._read_file()
|
|
||||||
self._comnet_schedules_path = str(base_path / 'comnet_schedules_archetypes.xlsx')
|
|
||||||
self._xls = pd.ExcelFile(self._comnet_schedules_path)
|
|
||||||
|
|
||||||
def _read_file(self) -> Dict:
|
|
||||||
"""
|
|
||||||
reads xlsx files containing usage information into a dictionary
|
|
||||||
:return : Dict
|
|
||||||
"""
|
|
||||||
number_usage_types = 33
|
|
||||||
xl_file = pd.ExcelFile(self._base_path)
|
|
||||||
file_data = pd.read_excel(xl_file, sheet_name="Modeling Data", usecols="A:AB", skiprows=[0, 1, 2],
|
|
||||||
nrows=number_usage_types)
|
|
||||||
|
|
||||||
lighting_data = {}
|
|
||||||
plug_loads_data = {}
|
|
||||||
occupancy_data = {}
|
|
||||||
ventilation_rate = {}
|
|
||||||
water_heating = {}
|
|
||||||
process_data = {}
|
|
||||||
schedules_key = {}
|
|
||||||
|
|
||||||
for j in range(0, number_usage_types):
|
|
||||||
usage_parameters = file_data.iloc[j]
|
|
||||||
usage_type = usage_parameters[0]
|
|
||||||
lighting_data[usage_type] = usage_parameters[1:6].values.tolist()
|
|
||||||
plug_loads_data[usage_type] = usage_parameters[8:13].values.tolist()
|
|
||||||
occupancy_data[usage_type] = usage_parameters[17:20].values.tolist()
|
|
||||||
ventilation_rate[usage_type] = usage_parameters[20:21].values.tolist()
|
|
||||||
water_heating[usage_type] = usage_parameters[23:24].values.tolist()
|
|
||||||
process_data[usage_type] = usage_parameters[24:26].values.tolist()
|
|
||||||
schedules_key[usage_type] = usage_parameters[27:28].values.tolist()
|
|
||||||
|
|
||||||
return {'lighting': lighting_data,
|
|
||||||
'plug loads': plug_loads_data,
|
|
||||||
'occupancy': occupancy_data,
|
|
||||||
'ventilation rate': ventilation_rate,
|
|
||||||
'water heating': water_heating,
|
|
||||||
'process': process_data,
|
|
||||||
'schedules_key': schedules_key}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_usage_type(comnet_usage, data, schedules_data):
|
|
||||||
_usage_zone = UsageZone()
|
|
||||||
|
|
||||||
# lighting
|
|
||||||
_lighting = Lighting()
|
|
||||||
_lighting.latent_fraction = ch().comnet_lighting_latent
|
|
||||||
_lighting.convective_fraction = ch().comnet_lighting_convective
|
|
||||||
_lighting.radiative_fraction = ch().comnet_lighting_radiant
|
|
||||||
_lighting.density = data['lighting'][comnet_usage][4]
|
|
||||||
|
|
||||||
# plug loads
|
|
||||||
_appliances = None
|
|
||||||
if data['plug loads'][comnet_usage][0] != 'n.a.':
|
|
||||||
_appliances = Appliances()
|
|
||||||
_appliances.latent_fraction = ch().comnet_plugs_latent
|
|
||||||
_appliances.convective_fraction = ch().comnet_plugs_convective
|
|
||||||
_appliances.radiative_fraction = ch().comnet_plugs_radiant
|
|
||||||
_appliances.density = data['plug loads'][comnet_usage][0]
|
|
||||||
|
|
||||||
# occupancy
|
|
||||||
_occupancy = Occupancy()
|
|
||||||
value = data['occupancy'][comnet_usage][0]
|
|
||||||
_occupancy.occupancy_density = 0
|
|
||||||
if value != 0:
|
|
||||||
_occupancy.occupancy_density = 1 / value
|
|
||||||
|
|
||||||
_occupancy.sensible_convective_internal_gain = data['occupancy'][comnet_usage][1] \
|
|
||||||
* ch().comnet_occupancy_sensible_convective
|
|
||||||
_occupancy.sensible_radiative_internal_gain = data['occupancy'][comnet_usage][1] \
|
|
||||||
* ch().comnet_occupancy_sensible_radiant
|
|
||||||
_occupancy.latent_internal_gain = data['occupancy'][comnet_usage][2]
|
|
||||||
|
|
||||||
_usage_zone.mechanical_air_change = data['ventilation rate'][comnet_usage][0]
|
|
||||||
|
|
||||||
schedules_usage = UsageHelper.schedules_key(data['schedules_key'][comnet_usage][0])
|
|
||||||
|
|
||||||
_extracted_data = pd.read_excel(schedules_data, sheet_name=schedules_usage, usecols="A:AA", skiprows=[0, 1, 2, 3],
|
|
||||||
nrows=39)
|
|
||||||
schedules = []
|
|
||||||
number_of_schedule_types = 13
|
|
||||||
schedules_per_schedule_type = 3
|
|
||||||
day_types = dict({'week_day': 0, 'saturday': 1, 'sunday': 2})
|
|
||||||
for schedule_types in range(0, number_of_schedule_types):
|
|
||||||
name = ''
|
|
||||||
data_type = ''
|
|
||||||
for schedule_day in range(0, schedules_per_schedule_type):
|
|
||||||
_schedule = Schedule()
|
|
||||||
_schedule.time_step = cte.HOUR
|
|
||||||
_schedule.time_range = cte.DAY
|
|
||||||
row_cells = _extracted_data.iloc[schedules_per_schedule_type * schedule_types + schedule_day]
|
|
||||||
if schedule_day == day_types['week_day']:
|
|
||||||
name = row_cells[0]
|
|
||||||
data_type = row_cells[1]
|
|
||||||
_schedule.day_types = [cte.MONDAY, cte.TUESDAY, cte.WEDNESDAY, cte.THURSDAY, cte.FRIDAY]
|
|
||||||
elif schedule_day == day_types['saturday']:
|
|
||||||
_schedule.day_types = [cte.SATURDAY]
|
|
||||||
else:
|
|
||||||
_schedule.day_types = [cte.SUNDAY, cte.HOLIDAY]
|
|
||||||
_schedule.type = name
|
|
||||||
_schedule.data_type = SchedulesHelper.data_type_from_comnet(data_type)
|
|
||||||
if _schedule.data_type == cte.ANY_NUMBER:
|
|
||||||
values = []
|
|
||||||
for cell in row_cells[schedules_per_schedule_type:].to_numpy():
|
|
||||||
values.append((float(cell) - 32.) * 5 / 9)
|
|
||||||
_schedule.values = values
|
|
||||||
else:
|
|
||||||
_schedule.values = row_cells[schedules_per_schedule_type:].to_numpy()
|
|
||||||
schedules.append(_schedule)
|
|
||||||
|
|
||||||
schedules_types = dict({'Occupancy': 0, 'Lights': 3, 'Receptacle': 6, 'Infiltration': 9, 'HVAC Avail': 12,
|
|
||||||
'ClgSetPt': 15, 'HtgSetPt': 18})
|
|
||||||
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['Occupancy']+pointer])
|
|
||||||
_occupancy.occupancy_schedules = _schedules
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['Lights']+pointer])
|
|
||||||
_lighting.schedules = _schedules
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['Receptacle']+pointer])
|
|
||||||
_appliances.schedules = _schedules
|
|
||||||
|
|
||||||
_usage_zone.occupancy = _occupancy
|
|
||||||
_usage_zone.lighting = _lighting
|
|
||||||
_usage_zone.appliances = _appliances
|
|
||||||
|
|
||||||
_control = ThermalControl()
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['HtgSetPt']+pointer])
|
|
||||||
_control.heating_set_point_schedules = _schedules
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['ClgSetPt']+pointer])
|
|
||||||
_control.cooling_set_point_schedules = _schedules
|
|
||||||
_schedules = []
|
|
||||||
for pointer in range(0, 3):
|
|
||||||
_schedules.append(schedules[schedules_types['HVAC Avail']+pointer])
|
|
||||||
_control.hvac_availability_schedules = _schedules
|
|
||||||
_usage_zone.thermal_control = _control
|
|
||||||
|
|
||||||
return _usage_zone
|
|
||||||
|
|
||||||
def _search_archetypes(self, libs_usage):
|
|
||||||
for item in self._data['lighting']:
|
|
||||||
comnet_usage = UsageHelper.comnet_from_libs_usage(libs_usage)
|
|
||||||
if comnet_usage == item:
|
|
||||||
usage_archetype = self._parse_usage_type(comnet_usage, self._data, self._xls)
|
|
||||||
return usage_archetype
|
|
||||||
return None
|
|
||||||
|
|
||||||
def enrich_buildings(self):
|
def enrich_buildings(self):
|
||||||
"""
|
"""
|
||||||
|
@ -193,14 +36,14 @@ class ComnetUsageParameters:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
city = self._city
|
city = self._city
|
||||||
|
comnet_catalog = UsageCatalogFactory('comnet').catalog
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
usage = GeometryHelper.libs_usage_from_libs_function(building.function)
|
usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function]
|
||||||
try:
|
try:
|
||||||
archetype_usage = self._search_archetypes(usage)
|
archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
sys.stderr.write(f'Building {building.name} has unknown archetype for building function:'
|
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:'
|
||||||
f' {building.function}, that assigns building usage as '
|
f' {building.function}')
|
||||||
f'{GeometryHelper.libs_usage_from_libs_function(building.function)}\n')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
for internal_zone in building.internal_zones:
|
for internal_zone in building.internal_zones:
|
||||||
|
@ -210,46 +53,46 @@ class ComnetUsageParameters:
|
||||||
raise Exception('Internal zone volume not defined, ACH cannot be calculated')
|
raise Exception('Internal zone volume not defined, ACH cannot be calculated')
|
||||||
if internal_zone.area <= 0:
|
if internal_zone.area <= 0:
|
||||||
raise Exception('Internal zone area is zero, ACH cannot be calculated')
|
raise Exception('Internal zone area is zero, ACH cannot be calculated')
|
||||||
if internal_zone.volume <= 0:
|
|
||||||
raise Exception('Internal zone volume is zero, ACH cannot be calculated')
|
|
||||||
volume_per_area = internal_zone.volume / internal_zone.area
|
volume_per_area = internal_zone.volume / internal_zone.area
|
||||||
usage_zone = UsageZone()
|
usage_zone = Usage()
|
||||||
usage_zone.usage = usage
|
usage_zone.name = usage_name
|
||||||
self._assign_values_usage_zone(usage_zone, archetype_usage, volume_per_area)
|
self._assign_values(usage_zone, archetype_usage, volume_per_area)
|
||||||
usage_zone.percentage = 1
|
usage_zone.percentage = 1
|
||||||
self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage)
|
self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage)
|
||||||
|
|
||||||
internal_zone.usage_zones = [usage_zone]
|
internal_zone.usages = [usage_zone]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _assign_values_usage_zone(usage_zone, archetype, volume_per_area):
|
def _search_archetypes(comnet_catalog, usage_name):
|
||||||
|
comnet_archetypes = comnet_catalog.entries('archetypes').usages
|
||||||
|
for building_archetype in comnet_archetypes:
|
||||||
|
if str(usage_name) == str(building_archetype.name):
|
||||||
|
return building_archetype
|
||||||
|
raise KeyError('archetype not found')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _assign_values(usage_zone, archetype, volume_per_area):
|
||||||
# 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_zone.occupancy when writing usage_zone.occupancy = archetype.occupancy.
|
# usage_zone.occupancy when writing usage_zone.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_zone.mechanical_air_change = archetype.mechanical_air_change * cte.METERS_TO_FEET ** 2 \
|
usage_zone.mechanical_air_change = archetype.ventilation_rate / volume_per_area \
|
||||||
* cte.HOUR_TO_MINUTES / cte.METERS_TO_FEET ** 3 / volume_per_area
|
* cte.HOUR_TO_MINUTES * cte.MINUTES_TO_SECONDS
|
||||||
_occupancy = Occupancy()
|
_occupancy = Occupancy()
|
||||||
_occupancy.occupancy_density = archetype.occupancy.occupancy_density * cte.METERS_TO_FEET**2
|
_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
|
||||||
* archetype.occupancy.occupancy_density \
|
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain
|
||||||
* cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS
|
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain
|
||||||
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain \
|
_occupancy.occupancy_schedules = archetype.occupancy.schedules
|
||||||
* archetype.occupancy.occupancy_density \
|
|
||||||
* cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS
|
|
||||||
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain \
|
|
||||||
* archetype.occupancy.occupancy_density \
|
|
||||||
* cte.METERS_TO_FEET**2 * cte.BTU_H_TO_WATTS
|
|
||||||
_occupancy.occupancy_schedules = archetype.occupancy.occupancy_schedules
|
|
||||||
usage_zone.occupancy = _occupancy
|
usage_zone.occupancy = _occupancy
|
||||||
_lighting = Lighting()
|
_lighting = Lighting()
|
||||||
_lighting.density = archetype.lighting.density / cte.METERS_TO_FEET ** 2
|
_lighting.density = archetype.lighting.density
|
||||||
_lighting.convective_fraction = archetype.lighting.convective_fraction
|
_lighting.convective_fraction = archetype.lighting.convective_fraction
|
||||||
_lighting.radiative_fraction = archetype.lighting.radiative_fraction
|
_lighting.radiative_fraction = archetype.lighting.radiative_fraction
|
||||||
_lighting.latent_fraction = archetype.lighting.latent_fraction
|
_lighting.latent_fraction = archetype.lighting.latent_fraction
|
||||||
_lighting.schedules = archetype.lighting.schedules
|
_lighting.schedules = archetype.lighting.schedules
|
||||||
usage_zone.lighting = _lighting
|
usage_zone.lighting = _lighting
|
||||||
_appliances = Appliances()
|
_appliances = Appliances()
|
||||||
_appliances.density = archetype.appliances.density / cte.METERS_TO_FEET ** 2
|
_appliances.density = archetype.appliances.density
|
||||||
_appliances.convective_fraction = archetype.appliances.convective_fraction
|
_appliances.convective_fraction = archetype.appliances.convective_fraction
|
||||||
_appliances.radiative_fraction = archetype.appliances.radiative_fraction
|
_appliances.radiative_fraction = archetype.appliances.radiative_fraction
|
||||||
_appliances.latent_fraction = archetype.appliances.latent_fraction
|
_appliances.latent_fraction = archetype.appliances.latent_fraction
|
||||||
|
@ -279,6 +122,31 @@ class ComnetUsageParameters:
|
||||||
usage_zone.hours_day = total / 365
|
usage_zone.hours_day = total / 365
|
||||||
usage_zone.days_year = 365
|
usage_zone.days_year = 365
|
||||||
|
|
||||||
|
max_heating_setpoint = cte.MIN_FLOAT
|
||||||
|
min_heating_setpoint = cte.MAX_FLOAT
|
||||||
|
|
||||||
|
for schedule in archetype.thermal_control.heating_set_point_schedules:
|
||||||
|
if schedule.values is None:
|
||||||
|
max_heating_setpoint = None
|
||||||
|
min_heating_setpoint = None
|
||||||
|
break
|
||||||
|
if max(schedule.values) > max_heating_setpoint:
|
||||||
|
max_heating_setpoint = max(schedule.values)
|
||||||
|
if min(schedule.values) < min_heating_setpoint:
|
||||||
|
min_heating_setpoint = min(schedule.values)
|
||||||
|
|
||||||
|
min_cooling_setpoint = cte.MAX_FLOAT
|
||||||
|
for schedule in archetype.thermal_control.cooling_set_point_schedules:
|
||||||
|
if schedule.values is None:
|
||||||
|
min_cooling_setpoint = None
|
||||||
|
break
|
||||||
|
if min(schedule.values) < min_cooling_setpoint:
|
||||||
|
min_cooling_setpoint = min(schedule.values)
|
||||||
|
|
||||||
|
usage_zone.thermal_control.mean_heating_set_point = max_heating_setpoint
|
||||||
|
usage_zone.thermal_control.heating_set_back = min_heating_setpoint
|
||||||
|
usage_zone.thermal_control.mean_cooling_set_point = min_cooling_setpoint
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _calculate_internal_gains(archetype):
|
def _calculate_internal_gains(archetype):
|
||||||
|
|
||||||
|
|
163
hub/imports/usage/nrcan_usage_parameters.py
Normal file
163
hub/imports/usage/nrcan_usage_parameters.py
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
"""
|
||||||
|
NrcanUsageParameters extracts the usage properties from NRCAN catalog and assigns to each building
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
|
from hub.city_model_structure.building_demand.usage import Usage
|
||||||
|
from hub.city_model_structure.building_demand.lighting import Lighting
|
||||||
|
from hub.city_model_structure.building_demand.occupancy import Occupancy
|
||||||
|
from hub.city_model_structure.building_demand.appliances import Appliances
|
||||||
|
from hub.city_model_structure.building_demand.thermal_control import ThermalControl
|
||||||
|
from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory
|
||||||
|
|
||||||
|
|
||||||
|
class NrcanUsageParameters:
|
||||||
|
"""
|
||||||
|
NrcanUsageParameters class
|
||||||
|
"""
|
||||||
|
def __init__(self, city, base_path):
|
||||||
|
self._city = city
|
||||||
|
self._path = base_path
|
||||||
|
|
||||||
|
def enrich_buildings(self):
|
||||||
|
"""
|
||||||
|
Returns the city with the usage parameters assigned to the buildings
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
city = self._city
|
||||||
|
nrcan_catalog = UsageCatalogFactory('nrcan').catalog
|
||||||
|
comnet_catalog = UsageCatalogFactory('comnet').catalog
|
||||||
|
|
||||||
|
for building in city.buildings:
|
||||||
|
usage_name = Dictionaries().hub_usage_to_nrcan_usage[building.function]
|
||||||
|
try:
|
||||||
|
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
|
||||||
|
except KeyError:
|
||||||
|
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:'
|
||||||
|
f' {building.function}')
|
||||||
|
return
|
||||||
|
|
||||||
|
usage_name = Dictionaries().hub_usage_to_comnet_usage[building.function]
|
||||||
|
try:
|
||||||
|
comnet_archetype_usage = self._search_archetypes(comnet_catalog, usage_name)
|
||||||
|
except KeyError:
|
||||||
|
sys.stderr.write(f'Building {building.name} has unknown usage archetype for building function:'
|
||||||
|
f' {building.function}')
|
||||||
|
return
|
||||||
|
|
||||||
|
for internal_zone in building.internal_zones:
|
||||||
|
if internal_zone.area is None:
|
||||||
|
raise Exception('Internal zone area not defined, ACH cannot be calculated')
|
||||||
|
if internal_zone.volume is None:
|
||||||
|
raise Exception('Internal zone volume not defined, ACH cannot be calculated')
|
||||||
|
if internal_zone.area <= 0:
|
||||||
|
raise Exception('Internal zone area is zero, ACH cannot be calculated')
|
||||||
|
volume_per_area = internal_zone.volume / internal_zone.area
|
||||||
|
usage_zone = Usage()
|
||||||
|
usage_zone.name = usage_name
|
||||||
|
self._assign_values(usage_zone, archetype_usage, volume_per_area)
|
||||||
|
self._assign_comnet_extra_values(usage_zone, comnet_archetype_usage)
|
||||||
|
usage_zone.percentage = 1
|
||||||
|
self._calculate_reduced_values_from_extended_library(usage_zone, archetype_usage)
|
||||||
|
|
||||||
|
internal_zone.usages = [usage_zone]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_archetypes(catalog, usage_name):
|
||||||
|
archetypes = catalog.entries('archetypes').usages
|
||||||
|
for building_archetype in archetypes:
|
||||||
|
if str(usage_name) == str(building_archetype.name):
|
||||||
|
return building_archetype
|
||||||
|
raise KeyError('archetype not found')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _assign_values(usage_zone, archetype, volume_per_area):
|
||||||
|
if archetype.mechanical_air_change > 0:
|
||||||
|
usage_zone.mechanical_air_change = archetype.mechanical_air_change
|
||||||
|
elif archetype.ventilation_rate > 0:
|
||||||
|
usage_zone.mechanical_air_change = archetype.ventilation_rate / volume_per_area \
|
||||||
|
* cte.HOUR_TO_MINUTES * cte.MINUTES_TO_SECONDS
|
||||||
|
else:
|
||||||
|
usage_zone.mechanical_air_change = 0
|
||||||
|
_occupancy = Occupancy()
|
||||||
|
_occupancy.occupancy_density = archetype.occupancy.occupancy_density
|
||||||
|
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain
|
||||||
|
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain
|
||||||
|
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain
|
||||||
|
_occupancy.occupancy_schedules = archetype.occupancy.schedules
|
||||||
|
usage_zone.occupancy = _occupancy
|
||||||
|
_lighting = Lighting()
|
||||||
|
_lighting.density = archetype.lighting.density
|
||||||
|
_lighting.convective_fraction = archetype.lighting.convective_fraction
|
||||||
|
_lighting.radiative_fraction = archetype.lighting.radiative_fraction
|
||||||
|
_lighting.latent_fraction = archetype.lighting.latent_fraction
|
||||||
|
_lighting.schedules = archetype.lighting.schedules
|
||||||
|
usage_zone.lighting = _lighting
|
||||||
|
_appliances = Appliances()
|
||||||
|
_appliances.density = archetype.appliances.density
|
||||||
|
_appliances.convective_fraction = archetype.appliances.convective_fraction
|
||||||
|
_appliances.radiative_fraction = archetype.appliances.radiative_fraction
|
||||||
|
_appliances.latent_fraction = archetype.appliances.latent_fraction
|
||||||
|
_appliances.schedules = archetype.appliances.schedules
|
||||||
|
usage_zone.appliances = _appliances
|
||||||
|
_control = ThermalControl()
|
||||||
|
_control.cooling_set_point_schedules = archetype.thermal_control.cooling_set_point_schedules
|
||||||
|
_control.heating_set_point_schedules = archetype.thermal_control.heating_set_point_schedules
|
||||||
|
_control.hvac_availability_schedules = archetype.thermal_control.hvac_availability_schedules
|
||||||
|
usage_zone.thermal_control = _control
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _assign_comnet_extra_values(usage_zone, archetype):
|
||||||
|
_occupancy = usage_zone.occupancy
|
||||||
|
_occupancy.sensible_radiative_internal_gain = archetype.occupancy.sensible_radiative_internal_gain
|
||||||
|
_occupancy.latent_internal_gain = archetype.occupancy.latent_internal_gain
|
||||||
|
_occupancy.sensible_convective_internal_gain = archetype.occupancy.sensible_convective_internal_gain
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _calculate_reduced_values_from_extended_library(usage_zone, archetype):
|
||||||
|
number_of_days_per_type = {'WD': 251, 'Sat': 52, 'Sun': 62}
|
||||||
|
total = 0
|
||||||
|
for schedule in archetype.thermal_control.hvac_availability_schedules:
|
||||||
|
if schedule.day_types[0] == cte.SATURDAY:
|
||||||
|
for value in schedule.values:
|
||||||
|
total += value * number_of_days_per_type['Sat']
|
||||||
|
elif schedule.day_types[0] == cte.SUNDAY:
|
||||||
|
for value in schedule.values:
|
||||||
|
total += value * number_of_days_per_type['Sun']
|
||||||
|
else:
|
||||||
|
for value in schedule.values:
|
||||||
|
total += value * number_of_days_per_type['WD']
|
||||||
|
|
||||||
|
usage_zone.hours_day = total / 365
|
||||||
|
usage_zone.days_year = 365
|
||||||
|
|
||||||
|
max_heating_setpoint = cte.MIN_FLOAT
|
||||||
|
min_heating_setpoint = cte.MAX_FLOAT
|
||||||
|
|
||||||
|
for schedule in archetype.thermal_control.heating_set_point_schedules:
|
||||||
|
if schedule.values is None:
|
||||||
|
max_heating_setpoint = None
|
||||||
|
min_heating_setpoint = None
|
||||||
|
break
|
||||||
|
if max(schedule.values) > max_heating_setpoint:
|
||||||
|
max_heating_setpoint = max(schedule.values)
|
||||||
|
if min(schedule.values) < min_heating_setpoint:
|
||||||
|
min_heating_setpoint = min(schedule.values)
|
||||||
|
|
||||||
|
min_cooling_setpoint = cte.MAX_FLOAT
|
||||||
|
for schedule in archetype.thermal_control.cooling_set_point_schedules:
|
||||||
|
if schedule.values is None:
|
||||||
|
min_cooling_setpoint = None
|
||||||
|
break
|
||||||
|
if min(schedule.values) < min_cooling_setpoint:
|
||||||
|
min_cooling_setpoint = min(schedule.values)
|
||||||
|
|
||||||
|
usage_zone.thermal_control.mean_heating_set_point = max_heating_setpoint
|
||||||
|
usage_zone.thermal_control.heating_set_back = min_heating_setpoint
|
||||||
|
usage_zone.thermal_control.mean_cooling_set_point = min_cooling_setpoint
|
|
@ -7,8 +7,8 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from hub.imports.usage.hft_usage_parameters import HftUsageParameters
|
|
||||||
from hub.imports.usage.comnet_usage_parameters import ComnetUsageParameters
|
from hub.imports.usage.comnet_usage_parameters import ComnetUsageParameters
|
||||||
|
from hub.imports.usage.nrcan_usage_parameters import NrcanUsageParameters
|
||||||
|
|
||||||
|
|
||||||
class UsageFactory:
|
class UsageFactory:
|
||||||
|
@ -22,19 +22,19 @@ class UsageFactory:
|
||||||
self._city = city
|
self._city = city
|
||||||
self._base_path = base_path
|
self._base_path = base_path
|
||||||
|
|
||||||
def _hft(self):
|
|
||||||
"""
|
|
||||||
Enrich the city with HFT usage library
|
|
||||||
"""
|
|
||||||
self._city.level_of_detail.usage = 2
|
|
||||||
return HftUsageParameters(self._city, self._base_path).enrich_buildings()
|
|
||||||
|
|
||||||
def _comnet(self):
|
def _comnet(self):
|
||||||
"""
|
"""
|
||||||
Enrich the city with COMNET usage library
|
Enrich the city with COMNET usage library
|
||||||
"""
|
"""
|
||||||
self._city.level_of_detail.usage = 2
|
self._city.level_of_detail.usage = 2
|
||||||
return ComnetUsageParameters(self._city, self._base_path).enrich_buildings()
|
ComnetUsageParameters(self._city, self._base_path).enrich_buildings()
|
||||||
|
|
||||||
|
def _nrcan(self):
|
||||||
|
"""
|
||||||
|
Enrich the city with NRCAN usage library
|
||||||
|
"""
|
||||||
|
self._city.level_of_detail.usage = 2
|
||||||
|
NrcanUsageParameters(self._city, self._base_path).enrich_buildings()
|
||||||
|
|
||||||
def enrich(self):
|
def enrich(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -9,7 +9,7 @@ from unittest import TestCase
|
||||||
|
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
from hub.imports.construction_factory import ConstructionFactory
|
from hub.imports.construction_factory import ConstructionFactory
|
||||||
from hub.imports.geometry.helpers.geometry_helper import GeometryHelper
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
|
|
||||||
|
|
||||||
class TestConstructionFactory(TestCase):
|
class TestConstructionFactory(TestCase):
|
||||||
|
@ -34,9 +34,9 @@ class TestConstructionFactory(TestCase):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _internal_function(function_format, original_function):
|
def _internal_function(function_format, original_function):
|
||||||
if function_format == 'hft':
|
if function_format == 'hft':
|
||||||
new_function = GeometryHelper.libs_function_from_hft(original_function)
|
new_function = Dictionaries().hft_function_to_hub_function[original_function]
|
||||||
elif function_format == 'pluto':
|
elif function_format == 'pluto':
|
||||||
new_function = GeometryHelper.libs_function_from_pluto(original_function)
|
new_function = Dictionaries().pluto_function_to_hub_function[original_function]
|
||||||
else:
|
else:
|
||||||
raise Exception('Function key not recognized. Implemented only "hft" and "pluto"')
|
raise Exception('Function key not recognized. Implemented only "hft" and "pluto"')
|
||||||
return new_function
|
return new_function
|
||||||
|
@ -51,7 +51,7 @@ class TestConstructionFactory(TestCase):
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.function = self._internal_function(function_format, building.function)
|
building.function = self._internal_function(function_format, building.function)
|
||||||
self.assertEqual(building.function, 'residential', 'format hft')
|
self.assertEqual('residential', building.function, 'format hft')
|
||||||
|
|
||||||
# case 2: Pluto
|
# case 2: Pluto
|
||||||
file = 'pluto_building.gml'
|
file = 'pluto_building.gml'
|
||||||
|
@ -59,7 +59,7 @@ class TestConstructionFactory(TestCase):
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.function = self._internal_function(function_format, building.function)
|
building.function = self._internal_function(function_format, building.function)
|
||||||
self.assertEqual(building.function, 'secondary school', 'format pluto')
|
self.assertEqual('education', building.function, 'format pluto')
|
||||||
|
|
||||||
# case 3: Alkis
|
# case 3: Alkis
|
||||||
file = 'one_building_in_kelowna_alkis.gml'
|
file = 'one_building_in_kelowna_alkis.gml'
|
||||||
|
@ -122,7 +122,7 @@ class TestConstructionFactory(TestCase):
|
||||||
self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none')
|
self.assertIsNone(thermal_zone.ordinate_number, 'thermal_zone ordinate number is not none')
|
||||||
self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none')
|
self.assertIsNotNone(thermal_zone.view_factors_matrix, 'thermal_zone view factors matrix is none')
|
||||||
self.assertIsNotNone(thermal_zone.total_floor_area, 'thermal zone total_floor_area is none')
|
self.assertIsNotNone(thermal_zone.total_floor_area, 'thermal zone total_floor_area is none')
|
||||||
self.assertIsNone(thermal_zone.usage, 'thermal_zone usage is not none')
|
self.assertIsNone(thermal_zone.usage_name, 'thermal_zone usage is not none')
|
||||||
self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none')
|
self.assertIsNone(thermal_zone.hours_day, 'thermal_zone hours a day is not none')
|
||||||
self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none')
|
self.assertIsNone(thermal_zone.days_year, 'thermal_zone days a year is not none')
|
||||||
self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none')
|
self.assertIsNone(thermal_zone.mechanical_air_change, 'thermal_zone mechanical air change is not none')
|
||||||
|
@ -180,7 +180,7 @@ class TestConstructionFactory(TestCase):
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.year_of_construction = 2005
|
building.year_of_construction = 2005
|
||||||
building.function = GeometryHelper.libs_function_from_pluto(building.function)
|
building.function = self._internal_function('pluto', building.function)
|
||||||
ConstructionFactory('nrel', city).enrich()
|
ConstructionFactory('nrel', city).enrich()
|
||||||
|
|
||||||
self._check_buildings(city)
|
self._check_buildings(city)
|
||||||
|
|
|
@ -7,7 +7,7 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
from hub.imports.geometry.helpers.geometry_helper import GeometryHelper
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
from hub.imports.usage_factory import UsageFactory
|
from hub.imports.usage_factory import UsageFactory
|
||||||
from hub.imports.construction_factory import ConstructionFactory
|
from hub.imports.construction_factory import ConstructionFactory
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ class TestGeometryFactory(TestCase):
|
||||||
self._check_buildings(city)
|
self._check_buildings(city)
|
||||||
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.assertIsNot(len(internal_zone.usage_zones), 0, 'no building usage_zones defined')
|
self.assertIsNot(len(internal_zone.usages), 0, 'no building usage_zones defined')
|
||||||
for usage_zone in internal_zone.usage_zones:
|
for usage_zone in internal_zone.usages:
|
||||||
self.assertIsNotNone(usage_zone.id, 'usage id is none')
|
self.assertIsNotNone(usage_zone.id, 'usage id is none')
|
||||||
for thermal_zone in internal_zone.thermal_zones:
|
for thermal_zone in internal_zone.thermal_zones:
|
||||||
self._check_thermal_zone(thermal_zone)
|
self._check_thermal_zone(thermal_zone)
|
||||||
|
@ -45,7 +45,7 @@ class TestGeometryFactory(TestCase):
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
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.usage_zones, 'usage zones are not defined')
|
self.assertIsNotNone(internal_zone.usages, 'usage zones are not defined')
|
||||||
self.assertIsNotNone(internal_zone.thermal_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')
|
||||||
|
@ -55,7 +55,7 @@ class TestGeometryFactory(TestCase):
|
||||||
|
|
||||||
def _check_thermal_zone(self, thermal_zone):
|
def _check_thermal_zone(self, thermal_zone):
|
||||||
self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none')
|
self.assertIsNotNone(thermal_zone.id, 'thermal_zone id is none')
|
||||||
self.assertIsNotNone(thermal_zone.usage, 'thermal_zone usage is not none')
|
self.assertIsNotNone(thermal_zone.usage_name, 'thermal_zone usage is not none')
|
||||||
self.assertIsNotNone(thermal_zone.hours_day, 'thermal_zone hours a day is none')
|
self.assertIsNotNone(thermal_zone.hours_day, 'thermal_zone hours a day is none')
|
||||||
self.assertIsNotNone(thermal_zone.days_year, 'thermal_zone days a year is none')
|
self.assertIsNotNone(thermal_zone.days_year, 'thermal_zone days a year is none')
|
||||||
self.assertIsNotNone(thermal_zone.occupancy, 'thermal_zone occupancy is none')
|
self.assertIsNotNone(thermal_zone.occupancy, 'thermal_zone occupancy is none')
|
||||||
|
@ -71,10 +71,10 @@ class TestGeometryFactory(TestCase):
|
||||||
def _prepare_case_usage_first(city, input_key, construction_key, usage_key):
|
def _prepare_case_usage_first(city, input_key, construction_key, usage_key):
|
||||||
if input_key == 'pluto':
|
if input_key == 'pluto':
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.function = GeometryHelper.libs_function_from_pluto(building.function)
|
building.function = Dictionaries().pluto_function_to_hub_function[building.function]
|
||||||
elif input_key == 'hft':
|
elif input_key == 'hft':
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.function = GeometryHelper.libs_function_from_hft(building.function)
|
building.function = Dictionaries().hft_function_to_hub_function[building.function]
|
||||||
UsageFactory(usage_key, city).enrich()
|
UsageFactory(usage_key, city).enrich()
|
||||||
ConstructionFactory(construction_key, city).enrich()
|
ConstructionFactory(construction_key, city).enrich()
|
||||||
|
|
||||||
|
@ -82,16 +82,17 @@ class TestGeometryFactory(TestCase):
|
||||||
def _prepare_case_construction_first(city, input_key, construction_key, usage_key):
|
def _prepare_case_construction_first(city, input_key, construction_key, usage_key):
|
||||||
if input_key == 'pluto':
|
if input_key == 'pluto':
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.function = GeometryHelper.libs_function_from_pluto(building.function)
|
building.function = Dictionaries().pluto_function_to_hub_function[building.function]
|
||||||
elif input_key == 'hft':
|
elif input_key == 'hft':
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.function = GeometryHelper.libs_function_from_hft(building.function)
|
building.function = Dictionaries().hft_function_to_hub_function[building.function]
|
||||||
|
print(construction_key, usage_key)
|
||||||
ConstructionFactory(construction_key, city).enrich()
|
ConstructionFactory(construction_key, city).enrich()
|
||||||
UsageFactory(usage_key, city).enrich()
|
UsageFactory(usage_key, city).enrich()
|
||||||
|
|
||||||
def _test_hft(self, file):
|
def _test_hft(self, file):
|
||||||
_construction_keys = ['nrel']
|
_construction_keys = ['nrel']
|
||||||
_usage_keys = ['comnet', 'hft']
|
_usage_keys = ['comnet', 'nrcan']
|
||||||
for construction_key in _construction_keys:
|
for construction_key in _construction_keys:
|
||||||
for usage_key in _usage_keys:
|
for usage_key in _usage_keys:
|
||||||
# construction factory called first
|
# construction factory called first
|
||||||
|
@ -121,7 +122,7 @@ class TestGeometryFactory(TestCase):
|
||||||
|
|
||||||
def _test_pluto(self, file):
|
def _test_pluto(self, file):
|
||||||
_construction_keys = ['nrel']
|
_construction_keys = ['nrel']
|
||||||
_usage_keys = ['comnet', 'hft']
|
_usage_keys = ['comnet', 'nrcan']
|
||||||
for construction_key in _construction_keys:
|
for construction_key in _construction_keys:
|
||||||
for usage_key in _usage_keys:
|
for usage_key in _usage_keys:
|
||||||
# construction factory called first
|
# construction factory called first
|
||||||
|
|
|
@ -10,7 +10,7 @@ from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
from hub.imports.geometry.helpers.geometry_helper import GeometryHelper
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
from hub.imports.construction_factory import ConstructionFactory
|
from hub.imports.construction_factory import ConstructionFactory
|
||||||
from hub.imports.usage_factory import UsageFactory
|
from hub.imports.usage_factory import UsageFactory
|
||||||
from hub.exports.exports_factory import ExportsFactory
|
from hub.exports.exports_factory import ExportsFactory
|
||||||
|
@ -48,7 +48,7 @@ class TestExports(TestCase):
|
||||||
file_path = (self._example_path / 'one_building_in_kelowna.gml').resolve()
|
file_path = (self._example_path / 'one_building_in_kelowna.gml').resolve()
|
||||||
self._complete_city = self._get_citygml(file_path)
|
self._complete_city = self._get_citygml(file_path)
|
||||||
for building in self._complete_city.buildings:
|
for building in self._complete_city.buildings:
|
||||||
building.function = GeometryHelper().libs_function_from_hft(building.function)
|
building.function = Dictionaries().hft_function_to_hub_function[building.function]
|
||||||
building.year_of_construction = 2006
|
building.year_of_construction = 2006
|
||||||
ConstructionFactory('nrel', self._complete_city).enrich()
|
ConstructionFactory('nrel', self._complete_city).enrich()
|
||||||
UsageFactory('ca', self._complete_city).enrich()
|
UsageFactory('ca', self._complete_city).enrich()
|
||||||
|
|
|
@ -59,7 +59,7 @@ class TestGeometryFactory(TestCase):
|
||||||
self.assertIsNotNone(building.roofs, 'building roofs is none')
|
self.assertIsNotNone(building.roofs, 'building roofs is none')
|
||||||
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.usage_zones, 'usage zones are defined')
|
self.assertIsNone(internal_zone.usages, 'usage zones are defined')
|
||||||
self.assertIsNone(internal_zone.thermal_zones, 'thermal zones are 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')
|
||||||
|
|
|
@ -133,13 +133,13 @@ class TestExports(TestCase):
|
||||||
if thermal_boundary.type is not cte.GROUND:
|
if thermal_boundary.type is not cte.GROUND:
|
||||||
self.assertIsNotNone(thermal_boundary.parent_surface.short_wave_reflectance)
|
self.assertIsNotNone(thermal_boundary.parent_surface.short_wave_reflectance)
|
||||||
|
|
||||||
for usage_zone in internal_zone.usage_zones:
|
for usage_zone in internal_zone.usages:
|
||||||
self.assertIsNotNone(usage_zone.percentage, f'usage zone {usage_zone.usage} percentage is none')
|
self.assertIsNotNone(usage_zone.percentage, f'usage zone {usage_zone.name} percentage is none')
|
||||||
self.assertIsNotNone(usage_zone.internal_gains, f'usage zone {usage_zone.usage} internal_gains is none')
|
self.assertIsNotNone(usage_zone.internal_gains, f'usage zone {usage_zone.name} internal_gains is none')
|
||||||
self.assertIsNotNone(usage_zone.thermal_control, f'usage zone {usage_zone.usage} thermal_control is none')
|
self.assertIsNotNone(usage_zone.thermal_control, f'usage zone {usage_zone.name} thermal_control is none')
|
||||||
self.assertIsNotNone(usage_zone.hours_day, f'usage zone {usage_zone.usage} hours_day is none')
|
self.assertIsNotNone(usage_zone.hours_day, f'usage zone {usage_zone.name} hours_day is none')
|
||||||
self.assertIsNotNone(usage_zone.days_year, f'usage zone {usage_zone.usage} days_year is none')
|
self.assertIsNotNone(usage_zone.days_year, f'usage zone {usage_zone.name} days_year is none')
|
||||||
self.assertIsNotNone(usage_zone.mechanical_air_change, f'usage zone {usage_zone.usage} '
|
self.assertIsNotNone(usage_zone.mechanical_air_change, f'usage zone {usage_zone.name} '
|
||||||
f'mechanical_air_change is none')
|
f'mechanical_air_change is none')
|
||||||
# export files
|
# export files
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -20,4 +20,4 @@ class TestConstructionCatalog(TestCase):
|
||||||
catalog = UsageCatalogFactory('nrcan').catalog
|
catalog = UsageCatalogFactory('nrcan').catalog
|
||||||
self.assertIsNotNone(catalog, 'catalog is none')
|
self.assertIsNotNone(catalog, 'catalog is none')
|
||||||
content = catalog.entries()
|
content = catalog.entries()
|
||||||
self.assertEqual(274, len(content.usages), 'Wrong number of usages')
|
self.assertEqual(34, len(content.usages), 'Wrong number of usages')
|
||||||
|
|
|
@ -9,7 +9,7 @@ from unittest import TestCase
|
||||||
|
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
from hub.imports.usage_factory import UsageFactory
|
from hub.imports.usage_factory import UsageFactory
|
||||||
from hub.imports.geometry.helpers.geometry_helper import GeometryHelper
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
|
|
||||||
|
|
||||||
class TestUsageFactory(TestCase):
|
class TestUsageFactory(TestCase):
|
||||||
|
@ -51,7 +51,7 @@ class TestUsageFactory(TestCase):
|
||||||
self.assertIsNotNone(building.walls, 'building walls is none')
|
self.assertIsNotNone(building.walls, 'building walls is none')
|
||||||
self.assertIsNotNone(building.roofs, 'building roofs is none')
|
self.assertIsNotNone(building.roofs, 'building roofs is none')
|
||||||
for internal_zone in building.internal_zones:
|
for internal_zone in building.internal_zones:
|
||||||
self.assertTrue(len(internal_zone.usage_zones) > 0, 'usage zones are not defined')
|
self.assertTrue(len(internal_zone.usages) > 0, 'usage zones are not defined')
|
||||||
self.assertIsNone(internal_zone.thermal_zones, 'thermal zones are 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')
|
||||||
|
@ -69,7 +69,7 @@ class TestUsageFactory(TestCase):
|
||||||
self.assertTrue(building.is_conditioned, 'building is not conditioned')
|
self.assertTrue(building.is_conditioned, 'building is not conditioned')
|
||||||
|
|
||||||
def _check_usage_zone(self, usage_zone):
|
def _check_usage_zone(self, usage_zone):
|
||||||
self.assertIsNotNone(usage_zone.usage, 'usage is none')
|
self.assertIsNotNone(usage_zone.name, 'usage is none')
|
||||||
self.assertIsNotNone(usage_zone.percentage, 'usage percentage is none')
|
self.assertIsNotNone(usage_zone.percentage, 'usage percentage is none')
|
||||||
self.assertIsNotNone(usage_zone.hours_day, 'hours per day is none')
|
self.assertIsNotNone(usage_zone.hours_day, 'hours per day is none')
|
||||||
self.assertIsNotNone(usage_zone.days_year, 'days per year is none')
|
self.assertIsNotNone(usage_zone.days_year, 'days per year is none')
|
||||||
|
@ -85,14 +85,14 @@ class TestUsageFactory(TestCase):
|
||||||
file = 'pluto_building.gml'
|
file = 'pluto_building.gml'
|
||||||
city = self._get_citygml(file)
|
city = self._get_citygml(file)
|
||||||
for building in city.buildings:
|
for building in city.buildings:
|
||||||
building.function = GeometryHelper.libs_function_from_pluto(building.function)
|
building.function = Dictionaries().pluto_function_to_hub_function[building.function]
|
||||||
|
|
||||||
UsageFactory('comnet', city).enrich()
|
UsageFactory('comnet', city).enrich()
|
||||||
self._check_buildings(city)
|
self._check_buildings(city)
|
||||||
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.assertIsNot(len(internal_zone.usage_zones), 0, 'no building usage_zones defined')
|
self.assertIsNot(len(internal_zone.usages), 0, 'no building usage_zones defined')
|
||||||
for usage_zone in internal_zone.usage_zones:
|
for usage_zone in internal_zone.usages:
|
||||||
self._check_usage_zone(usage_zone)
|
self._check_usage_zone(usage_zone)
|
||||||
self.assertIsNotNone(usage_zone.mechanical_air_change, 'mechanical air change is none')
|
self.assertIsNotNone(usage_zone.mechanical_air_change, 'mechanical air change is none')
|
||||||
self.assertIsNotNone(usage_zone.thermal_control.heating_set_point_schedules,
|
self.assertIsNotNone(usage_zone.thermal_control.heating_set_point_schedules,
|
||||||
|
@ -125,37 +125,3 @@ class TestUsageFactory(TestCase):
|
||||||
self.assertIsNotNone(appliances.schedules, 'appliances schedule is none')
|
self.assertIsNotNone(appliances.schedules, 'appliances schedule is none')
|
||||||
self.assertIsNotNone(usage_zone.thermal_control.hvac_availability_schedules,
|
self.assertIsNotNone(usage_zone.thermal_control.hvac_availability_schedules,
|
||||||
'control hvac availability is none')
|
'control hvac availability is none')
|
||||||
|
|
||||||
def test_import_hft(self):
|
|
||||||
"""
|
|
||||||
Enrich the city with the usage information from hft and verify it
|
|
||||||
"""
|
|
||||||
file = 'pluto_building.gml'
|
|
||||||
city = self._get_citygml(file)
|
|
||||||
for building in city.buildings:
|
|
||||||
building.function = GeometryHelper.libs_function_from_pluto(building.function)
|
|
||||||
|
|
||||||
UsageFactory('hft', city).enrich()
|
|
||||||
self._check_buildings(city)
|
|
||||||
for building in city.buildings:
|
|
||||||
for internal_zone in building.internal_zones:
|
|
||||||
self.assertIsNot(len(internal_zone.usage_zones), 0, 'no building usage_zones defined')
|
|
||||||
for usage_zone in internal_zone.usage_zones:
|
|
||||||
self._check_usage_zone(usage_zone)
|
|
||||||
self.assertIsNone(usage_zone.mechanical_air_change, 'mechanical air change is not none')
|
|
||||||
self.assertIsNotNone(usage_zone.thermal_control.heating_set_point_schedules,
|
|
||||||
'control heating set point schedule is none')
|
|
||||||
self.assertIsNotNone(usage_zone.thermal_control.cooling_set_point_schedules,
|
|
||||||
'control cooling set point schedule is none')
|
|
||||||
self.assertIsNotNone(usage_zone.occupancy, 'occupancy is none')
|
|
||||||
occupancy = usage_zone.occupancy
|
|
||||||
self.assertIsNotNone(occupancy.occupancy_density, 'occupancy density is none')
|
|
||||||
self.assertIsNone(occupancy.latent_internal_gain, 'occupancy latent internal gain is none')
|
|
||||||
self.assertIsNone(occupancy.sensible_convective_internal_gain,
|
|
||||||
'occupancy sensible convective internal gain is not none')
|
|
||||||
self.assertIsNone(occupancy.sensible_radiative_internal_gain,
|
|
||||||
'occupancy sensible radiant internal gain is not none')
|
|
||||||
self.assertIsNone(occupancy.occupancy_schedules, 'occupancy schedule is not none')
|
|
||||||
self.assertIsNone(occupancy.occupants, 'occupancy density is not none')
|
|
||||||
self.assertIsNone(usage_zone.lighting, 'lighting is not none')
|
|
||||||
self.assertIsNone(usage_zone.appliances, 'appliances is not none')
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user