Compare commits

...

71 Commits

Author SHA1 Message Date
7bd7b680b3 Update hub/version.py 2024-12-12 14:14:34 -05:00
Guille
765784135d Correct old ep export and optimize code 2024-12-12 20:09:58 +01:00
08e7f68adf Update hub/version.py 2024-12-07 02:48:32 -05:00
Guille
464abea93a Correct package 2024-12-07 08:46:05 +01:00
7d057ece81 Update hub/version.py 2024-12-04 09:45:28 -05:00
04f24e9d91 Merge pull request 'main' (#79) from main into feature/cerc_idf
Reviewed-on: #79
2024-12-04 02:09:57 -05:00
4da206761a Update hub/version.py 2024-12-04 01:10:53 -05:00
0f6a2a5b8f Update hub/version.py 2024-12-04 00:26:16 -05:00
766eba2cb7 Merge pull request 'Remove usages_percentage in favor of usages' (#78) from fix/remove-usages_percentage into main
Reviewed-on: #78
2024-12-04 00:11:05 -05:00
Connor Brackley
103923b272 Changed sql usage type to JSON 2024-12-03 18:41:54 -05:00
Connor Brackley
a492a9eb0a Remove usages_percentage in favor of usages 2024-12-03 17:28:00 -05:00
5ec1708a2c Update hub/version.py 2024-12-03 00:42:54 -05:00
1bac29118e bug fix in result reading 2024-12-03 06:41:13 +01:00
246e3442a6 Merge branch 'main' into feature/cerc_idf 2024-12-03 05:35:09 +01:00
7831af9144 Update hub/version.py 2024-12-02 14:57:29 -05:00
06532adbb9 bug fix 2024-12-02 20:56:06 +01:00
fba7effd52 bug fix 2024-12-02 20:53:45 +01:00
5ca4a802cd Update hub/version.py 2024-12-02 14:14:28 -05:00
f4598ac946 bug fix 2024-12-02 20:13:56 +01:00
1f3d981ace Merge branch 'main' into feature/cerc_idf 2024-11-30 07:33:26 +01:00
f3454bbb72 bug fix 2024-11-30 07:32:46 +01:00
20b7929519 Update hub/version.py 2024-11-29 00:24:27 -05:00
d6032b06a4 Merge pull request 'fix/multi-useage' (#77) from fix/multi-useage into main
Reviewed-on: #77
2024-11-29 00:23:59 -05:00
Connor Brackley
f0a72919ff Fix typos 2024-11-28 22:30:25 +00:00
faa2c772ba Merge remote-tracking branch 'origin/main' 2024-11-28 22:08:47 +01:00
90353cde16 handle error in wwr 2024-11-28 22:08:34 +01:00
fb10e89248 Update hub/exports/building_energy/idf.py 2024-11-28 15:52:23 -05:00
b9cb69ec05 Try to correct the importer 2024-11-28 21:46:21 +01:00
Connor Brackley
da819ad9d0 Minor bug fixes 2024-11-27 22:56:39 +00:00
Connor Brackley
44e6820ce6 Improve documentation and error handling 2024-11-27 22:06:22 +00:00
Connor Brackley
66dbda5525 Update usage handling in thermal zones 2024-11-27 22:06:03 +00:00
383bcc976f Update hub/version.py 2024-11-27 12:35:23 -05:00
0d44e38985 Merge pull request 'fix: total_installed_capacity attribute added to PvGeneration class, idf modified, redundant palma file removed' (#76) from feature/pv_epw_fix into main
Reviewed-on: #76
2024-11-27 12:32:58 -05:00
f4b4d0551f fix: total_installed_capacity attribute added to PvGeneration class, idf modified, redundant palma file removed 2024-11-27 18:16:40 +01:00
Connor Brackley
e0d1f1f8fb Added multi-usage to tests 2024-11-25 22:53:07 +00:00
Connor Brackley
2c6f602a2e Bug fixes 2024-11-25 22:42:54 +00:00
Vagrant
1449298a25 Update multi-usage methods to work with usage geojson input and parsers 2024-11-24 06:48:35 +00:00
c2a5cc2d5c Correct output names 2024-11-22 06:51:54 +01:00
b9c6594591 Update hub/version.py 2024-11-20 05:16:06 -05:00
76b67b38df Merge pull request 'feature/pv_workflow' (#75) from feature/pv_workflow into main
Reviewed-on: #75
2024-11-20 05:15:26 -05:00
2e7f4f1fe3 fix: montreal_custom systems moved to montreal_future catalogue 2024-11-17 15:29:19 +01:00
ddf10fb2ae feat: catalogues and importers are modified to be able to be implemented with PV workflow 2024-11-15 13:58:11 +01:00
f94ce25394 Partial correction of output names and result imports 2024-11-12 07:04:57 +01:00
8552b7cbd1 Bug fix 2024-11-08 06:58:23 +01:00
14404fbf04 Include oriol's infiltration changes into cerc_idf and remove empty file 2024-11-08 06:41:15 +01:00
c804c5ee6a Merge branch 'main' into feature/cerc_idf 2024-10-29 22:02:08 +01:00
3db3acd3c6 update version number 2024-10-29 22:00:57 +01:00
ddf4631c59 test 2024-10-29 21:52:38 +01:00
15aaf2a337 Merge pull request 'feat: Palma catalogues and importers are added' (#73) from feature/palma into main
Reviewed-on: #73
2024-10-29 16:46:17 -04:00
7ad16ba640 feat: Palma catalogues and importers are added 2024-10-29 11:36:47 +01:00
f42bb64b85 revert 3dd64143ab
revert Merge pull request 'feat: all the catalogues, importers, data and tests of palma are added' (#72) from feature/palma into main

Reviewed-on: #72
2024-10-22 14:27:35 -04:00
3dd64143ab Merge pull request 'feat: all the catalogues, importers, data and tests of palma are added' (#72) from feature/palma into main
Reviewed-on: #72
2024-10-21 17:32:20 -04:00
164ffbf9c8 feat: all the catalogues, importers, data and tests of palma are added 2024-10-21 23:30:10 +02:00
bf4018a649 Update version number 2024-10-20 17:39:54 +02:00
6c7f652390 Merge pull request 'fix: the small bug in test units is resolved, the construction and usage factories can be loaded without any order' (#71) from small_bugs_in_user_tests into main
Reviewed-on: #71
2024-10-20 11:15:40 -04:00
6020964899 Validation in progress 2024-10-17 06:13:23 +02:00
841a6136bb Validation in progress 2024-10-15 06:12:11 +02:00
68d2bef9ec Validation in progress 2024-10-15 05:24:33 +02:00
afe5e433ea complete refactor 2024-10-03 15:40:02 +02:00
16b0726db7 correct refactor 2024-10-03 13:56:01 +02:00
b915dbdead Merge branch 'main' into feature/cerc_idf 2024-10-03 13:29:29 +02:00
cd7ac9378e Merge branch 'main' into feature/cerc_idf 2024-10-03 13:16:38 +02:00
0157f47bdc Refactor completed 2024-09-30 16:26:19 +02:00
8687b1257d Merge branch 'main' into feature/cerc_idf 2024-09-30 15:17:31 +02:00
78aa84c338 Partial refactor 2024-09-30 15:15:57 +02:00
dc98b634e8 add weather file to the EnergyBuildingsExportsFactory 2024-09-27 14:33:51 +02:00
27514d4d77 cerc idf implementation refactoring and added systems 2024-09-23 17:52:52 +02:00
5e384c8185 cerc idf implementation refactoring and added systems 2024-09-18 06:56:04 +02:00
62c9a5aab7 cerc idf implementation 2024-09-16 17:34:43 +02:00
cc2ee61ada inputs completed 2024-09-13 06:55:12 +02:00
5401064905 cerc_idf basic implementation 2024-09-12 06:57:15 +02:00
95 changed files with 9957 additions and 788 deletions

View File

@ -0,0 +1,242 @@
"""
Palma construction catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Cecilia Pérez Pérez cperez@irec.cat
"""
import json
from pathlib import Path
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.construction.content import Content
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
from hub.catalog_factories.data_models.construction.construction import Construction
from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.data_models.construction.window import Window
from hub.catalog_factories.data_models.construction.material import Material
from hub.catalog_factories.data_models.construction.layer import Layer
import hub.helpers.constants as cte
class PalmaCatalog(Catalog):
"""
Palma catalog class
"""
def __init__(self, path):
_path_archetypes = Path(path / 'palma_archetypes.json').resolve()
_path_constructions = (path / 'palma_constructions.json').resolve()
with open(_path_archetypes, 'r', encoding='utf-8') as file:
self._archetypes = json.load(file)
with open(_path_constructions, 'r', encoding='utf-8') as file:
self._constructions = json.load(file)
self._catalog_windows = self._load_windows()
self._catalog_materials = self._load_materials()
self._catalog_constructions = self._load_constructions()
self._catalog_archetypes = self._load_archetypes()
# store the full catalog data model in self._content
self._content = Content(self._catalog_archetypes,
self._catalog_constructions,
self._catalog_materials,
self._catalog_windows)
def _load_windows(self):
_catalog_windows = []
windows = self._constructions['transparent_surfaces']
for window in windows:
name = list(window.keys())[0]
window_id = name
g_value = window[name]['shgc']
window_type = window[name]['type']
frame_ratio = window[name]['frame_ratio']
overall_u_value = window[name]['u_value']
_catalog_windows.append(Window(window_id, frame_ratio, g_value, overall_u_value, name, window_type))
return _catalog_windows
def _load_materials(self):
_catalog_materials = []
materials = self._constructions['materials']
for material in materials:
name = list(material.keys())[0]
material_id = name
no_mass = material[name]['no_mass']
thermal_resistance = None
conductivity = None
density = None
specific_heat = None
solar_absorptance = None
thermal_absorptance = None
visible_absorptance = None
if no_mass:
thermal_resistance = material[name]['thermal_resistance']
else:
solar_absorptance = material[name]['solar_absorptance']
thermal_absorptance = str(1 - float(material[name]['thermal_emittance']))
visible_absorptance = material[name]['visible_absorptance']
conductivity = material[name]['conductivity']
density = material[name]['density']
specific_heat = material[name]['specific_heat']
_material = Material(material_id,
name,
solar_absorptance,
thermal_absorptance,
visible_absorptance,
no_mass,
thermal_resistance,
conductivity,
density,
specific_heat)
_catalog_materials.append(_material)
return _catalog_materials
def _load_constructions(self):
_catalog_constructions = []
constructions = self._constructions['opaque_surfaces']
for construction in constructions:
name = list(construction.keys())[0]
construction_id = name
construction_type = ConstructionHelper().nrcan_surfaces_types_to_hub_types[construction[name]['type']]
layers = []
for layer in construction[name]['layers']:
layer_id = layer
layer_name = layer
material_id = layer
thickness = construction[name]['layers'][layer]
for material in self._catalog_materials:
if str(material_id) == str(material.id):
layers.append(Layer(layer_id, layer_name, material, thickness))
break
_catalog_constructions.append(Construction(construction_id, construction_type, name, layers))
return _catalog_constructions
def _load_archetypes(self):
_catalog_archetypes = []
archetypes = self._archetypes['archetypes']
for archetype in archetypes:
archetype_id = f'{archetype["function"]}_{archetype["period_of_construction"]}_{archetype["climate_zone"]}'
function = archetype['function']
name = archetype_id
climate_zone = archetype['climate_zone']
construction_period = archetype['period_of_construction']
average_storey_height = archetype['average_storey_height']
thermal_capacity = float(archetype['thermal_capacity']) * 1000
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges']
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off'] / cte.HOUR_TO_SECONDS
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on'] / cte.HOUR_TO_SECONDS
infiltration_rate_area_for_ventilation_system_off = (
archetype['infiltration_rate_area_for_ventilation_system_off'] * 1
)
infiltration_rate_area_for_ventilation_system_on = (
archetype['infiltration_rate_area_for_ventilation_system_on'] * 1
)
archetype_constructions = []
for archetype_construction in archetype['constructions']:
archetype_construction_type = ConstructionHelper().nrcan_surfaces_types_to_hub_types[archetype_construction]
archetype_construction_name = archetype['constructions'][archetype_construction]['opaque_surface_name']
for construction in self._catalog_constructions:
if archetype_construction_type == construction.type and construction.name == archetype_construction_name:
_construction = None
_window = None
_window_ratio = None
if 'transparent_surface_name' in archetype['constructions'][archetype_construction].keys():
_window_ratio = archetype['constructions'][archetype_construction]['transparent_ratio']
_window_id = archetype['constructions'][archetype_construction]['transparent_surface_name']
for window in self._catalog_windows:
if _window_id == window.id:
_window = window
break
_construction = Construction(construction.id,
construction.type,
construction.name,
construction.layers,
_window_ratio,
_window)
archetype_constructions.append(_construction)
break
_catalog_archetypes.append(Archetype(archetype_id,
name,
function,
climate_zone,
construction_period,
archetype_constructions,
average_storey_height,
thermal_capacity,
extra_loses_due_to_thermal_bridges,
None,
infiltration_rate_for_ventilation_system_off,
infiltration_rate_for_ventilation_system_on,
infiltration_rate_area_for_ventilation_system_off,
infiltration_rate_area_for_ventilation_system_on))
return _catalog_archetypes
def names(self, category=None):
"""
Get the catalog elements names
:parm: optional category filter
"""
if category is None:
_names = {'archetypes': [], 'constructions': [], 'materials': [], 'windows': []}
for archetype in self._content.archetypes:
_names['archetypes'].append(archetype.name)
for construction in self._content.constructions:
_names['constructions'].append(construction.name)
for material in self._content.materials:
_names['materials'].append(material.name)
for window in self._content.windows:
_names['windows'].append(window.name)
else:
_names = {category: []}
if category.lower() == 'archetypes':
for archetype in self._content.archetypes:
_names[category].append(archetype.name)
elif category.lower() == 'constructions':
for construction in self._content.constructions:
_names[category].append(construction.name)
elif category.lower() == 'materials':
for material in self._content.materials:
_names[category].append(material.name)
elif category.lower() == 'windows':
for window in self._content.windows:
_names[category].append(window.name)
else:
raise ValueError(f'Unknown category [{category}]')
return _names
def entries(self, category=None):
"""
Get the catalog elements
:parm: optional category filter
"""
if category is None:
return self._content
if category.lower() == 'archetypes':
return self._content.archetypes
if category.lower() == 'constructions':
return self._content.constructions
if category.lower() == 'materials':
return self._content.materials
if category.lower() == 'windows':
return self._content.windows
raise ValueError(f'Unknown category [{category}]')
def get_entry(self, name):
"""
Get one catalog element by names
:parm: entry name
"""
for entry in self._content.archetypes:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.constructions:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.materials:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.windows:
if entry.name.lower() == name.lower():
return entry
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -11,6 +11,7 @@ from typing import TypeVar
from hub.catalog_factories.construction.nrcan_catalog import NrcanCatalog from hub.catalog_factories.construction.nrcan_catalog import NrcanCatalog
from hub.catalog_factories.construction.nrel_catalog import NrelCatalog from hub.catalog_factories.construction.nrel_catalog import NrelCatalog
from hub.catalog_factories.construction.eilat_catalog import EilatCatalog from hub.catalog_factories.construction.eilat_catalog import EilatCatalog
from hub.catalog_factories.construction.palma_catalog import PalmaCatalog
from hub.helpers.utils import validate_import_export_type from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog') Catalog = TypeVar('Catalog')
@ -48,6 +49,13 @@ class ConstructionCatalogFactory:
""" """
return EilatCatalog(self._path) return EilatCatalog(self._path)
@property
def _palma(self):
"""
Retrieve Palma catalog
"""
return PalmaCatalog(self._path)
@property @property
def catalog(self) -> Catalog: def catalog(self) -> Catalog:
""" """

View File

@ -15,11 +15,20 @@ class Archetype:
""" """
Archetype class Archetype class
""" """
def __init__(self, name, systems):
def __init__(self, name, systems, archetype_cluster_id=None):
self._cluster_id = archetype_cluster_id
self._name = name self._name = name
self._systems = systems self._systems = systems
@property
def cluster_id(self):
"""
Get id
:return: string
"""
return self._cluster_id
@property @property
def name(self): def name(self):
""" """
@ -43,8 +52,9 @@ class Archetype:
_systems.append(_system.to_dictionary()) _systems.append(_system.to_dictionary())
content = { content = {
'Archetype': { 'Archetype': {
'cluster_id': self.cluster_id,
'name': self.name, 'name': self.name,
'systems': _systems 'systems': _systems
}
} }
}
return content return content

View File

@ -17,8 +17,9 @@ class PvGenerationSystem(GenerationSystem):
def __init__(self, system_id, name, system_type, model_name=None, manufacturer=None, electricity_efficiency=None, def __init__(self, system_id, name, system_type, model_name=None, manufacturer=None, electricity_efficiency=None,
nominal_electricity_output=None, nominal_ambient_temperature=None, nominal_cell_temperature=None, nominal_electricity_output=None, nominal_ambient_temperature=None, nominal_cell_temperature=None,
nominal_radiation=None, standard_test_condition_cell_temperature=None, nominal_radiation=None, standard_test_condition_cell_temperature=None,
standard_test_condition_maximum_power=None, cell_temperature_coefficient=None, width=None, height=None, standard_test_condition_maximum_power=None, standard_test_condition_radiation=None,
distribution_systems=None, energy_storage_systems=None): cell_temperature_coefficient=None, width=None, height=None, distribution_systems=None,
energy_storage_systems=None):
super().__init__(system_id=system_id, name=name, model_name=model_name, super().__init__(system_id=system_id, name=name, model_name=model_name,
manufacturer=manufacturer, fuel_type='renewable', distribution_systems=distribution_systems, manufacturer=manufacturer, fuel_type='renewable', distribution_systems=distribution_systems,
energy_storage_systems=energy_storage_systems) energy_storage_systems=energy_storage_systems)
@ -30,6 +31,7 @@ class PvGenerationSystem(GenerationSystem):
self._nominal_radiation = nominal_radiation self._nominal_radiation = nominal_radiation
self._standard_test_condition_cell_temperature = standard_test_condition_cell_temperature self._standard_test_condition_cell_temperature = standard_test_condition_cell_temperature
self._standard_test_condition_maximum_power = standard_test_condition_maximum_power self._standard_test_condition_maximum_power = standard_test_condition_maximum_power
self._standard_test_condition_radiation = standard_test_condition_radiation
self._cell_temperature_coefficient = cell_temperature_coefficient self._cell_temperature_coefficient = cell_temperature_coefficient
self._width = width self._width = width
self._height = height self._height = height
@ -98,6 +100,15 @@ class PvGenerationSystem(GenerationSystem):
""" """
return self._standard_test_condition_maximum_power return self._standard_test_condition_maximum_power
@property
def standard_test_condition_radiation(self):
"""
Get standard test condition cell temperature of PV panels in W/m2
:return: float
"""
return self._standard_test_condition_radiation
@property @property
def cell_temperature_coefficient(self): def cell_temperature_coefficient(self):
""" """
@ -143,6 +154,7 @@ class PvGenerationSystem(GenerationSystem):
'nominal radiation [W/m2]': self.nominal_radiation, 'nominal radiation [W/m2]': self.nominal_radiation,
'standard test condition cell temperature [Celsius]': self.standard_test_condition_cell_temperature, 'standard test condition cell temperature [Celsius]': self.standard_test_condition_cell_temperature,
'standard test condition maximum power [W]': self.standard_test_condition_maximum_power, 'standard test condition maximum power [W]': self.standard_test_condition_maximum_power,
'standard test condition radiation [W/m2]': self.standard_test_condition_radiation,
'cell temperature coefficient': self.cell_temperature_coefficient, 'cell temperature coefficient': self.cell_temperature_coefficient,
'width': self.width, 'width': self.width,
'height': self.height, 'height': self.height,

View File

@ -119,7 +119,7 @@ class ThermalStorageSystem(EnergyStorageSystem):
'height [m]': self.height, 'height [m]': self.height,
'layers': _layers, 'layers': _layers,
'maximum operating temperature [Celsius]': self.maximum_operating_temperature, 'maximum operating temperature [Celsius]': self.maximum_operating_temperature,
'storage_medium': self.storage_medium.to_dictionary(), 'storage_medium': _medias,
'heating coil capacity [W]': self.heating_coil_capacity 'heating coil capacity [W]': self.heating_coil_capacity
} }
} }

View File

@ -69,10 +69,10 @@ class MontrealCustomCatalog(Catalog):
storage_system = ThermalStorageSystem(equipment_id) storage_system = ThermalStorageSystem(equipment_id)
storage_systems = [storage_system] storage_systems = [storage_system]
if model_name == 'PV system': if model_name == 'PV system':
system_type = 'Photovoltaic' system_type = 'photovoltaic'
generation_system = PvGenerationSystem(equipment_id, generation_system = PvGenerationSystem(equipment_id,
name=None, name=None,
system_type= system_type, system_type=system_type,
model_name=model_name, model_name=model_name,
electricity_efficiency=electricity_efficiency, electricity_efficiency=electricity_efficiency,
energy_storage_systems=storage_systems energy_storage_systems=storage_systems

View File

@ -30,7 +30,8 @@ class MontrealFutureSystemCatalogue(Catalog):
path = str(path / 'montreal_future_systems.xml') path = str(path / 'montreal_future_systems.xml')
with open(path, 'r', encoding='utf-8') as xml: with open(path, 'r', encoding='utf-8') as xml:
self._archetypes = xmltodict.parse(xml.read(), self._archetypes = xmltodict.parse(xml.read(),
force_list=['pv_generation_component', 'templateStorages', 'demand']) force_list=['pv_generation_component', 'templateStorages', 'demand',
'system', 'system_id'])
self._storage_components = self._load_storage_components() self._storage_components = self._load_storage_components()
self._generation_components = self._load_generation_components() self._generation_components = self._load_generation_components()
@ -49,7 +50,7 @@ class MontrealFutureSystemCatalogue(Catalog):
'non_pv_generation_component'] 'non_pv_generation_component']
if non_pv_generation_components is not None: if non_pv_generation_components is not None:
for non_pv in non_pv_generation_components: for non_pv in non_pv_generation_components:
system_id = non_pv['system_id'] system_id = non_pv['generation_system_id']
name = non_pv['name'] name = non_pv['name']
system_type = non_pv['system_type'] system_type = non_pv['system_type']
model_name = non_pv['model_name'] model_name = non_pv['model_name']
@ -181,7 +182,7 @@ class MontrealFutureSystemCatalogue(Catalog):
'pv_generation_component'] 'pv_generation_component']
if pv_generation_components is not None: if pv_generation_components is not None:
for pv in pv_generation_components: for pv in pv_generation_components:
system_id = pv['system_id'] system_id = pv['generation_system_id']
name = pv['name'] name = pv['name']
system_type = pv['system_type'] system_type = pv['system_type']
model_name = pv['model_name'] model_name = pv['model_name']
@ -193,6 +194,7 @@ class MontrealFutureSystemCatalogue(Catalog):
nominal_radiation = pv['nominal_radiation'] nominal_radiation = pv['nominal_radiation']
standard_test_condition_cell_temperature = pv['standard_test_condition_cell_temperature'] standard_test_condition_cell_temperature = pv['standard_test_condition_cell_temperature']
standard_test_condition_maximum_power = pv['standard_test_condition_maximum_power'] standard_test_condition_maximum_power = pv['standard_test_condition_maximum_power']
standard_test_condition_radiation = pv['standard_test_condition_radiation']
cell_temperature_coefficient = pv['cell_temperature_coefficient'] cell_temperature_coefficient = pv['cell_temperature_coefficient']
width = pv['width'] width = pv['width']
height = pv['height'] height = pv['height']
@ -215,6 +217,7 @@ class MontrealFutureSystemCatalogue(Catalog):
standard_test_condition_cell_temperature= standard_test_condition_cell_temperature=
standard_test_condition_cell_temperature, standard_test_condition_cell_temperature,
standard_test_condition_maximum_power=standard_test_condition_maximum_power, standard_test_condition_maximum_power=standard_test_condition_maximum_power,
standard_test_condition_radiation=standard_test_condition_radiation,
cell_temperature_coefficient=cell_temperature_coefficient, cell_temperature_coefficient=cell_temperature_coefficient,
width=width, width=width,
height=height, height=height,
@ -379,6 +382,7 @@ class MontrealFutureSystemCatalogue(Catalog):
_system_archetypes = [] _system_archetypes = []
system_clusters = self._archetypes['EnergySystemCatalog']['system_archetypes']['system_archetype'] system_clusters = self._archetypes['EnergySystemCatalog']['system_archetypes']['system_archetype']
for system_cluster in system_clusters: for system_cluster in system_clusters:
archetype_id = system_cluster['@cluster_id']
name = system_cluster['name'] name = system_cluster['name']
systems = system_cluster['systems']['system_id'] systems = system_cluster['systems']['system_id']
integer_system_ids = [int(item) for item in systems] integer_system_ids = [int(item) for item in systems]
@ -386,7 +390,7 @@ class MontrealFutureSystemCatalogue(Catalog):
for system_archetype in self._systems: for system_archetype in self._systems:
if int(system_archetype.id) in integer_system_ids: if int(system_archetype.id) in integer_system_ids:
_systems.append(system_archetype) _systems.append(system_archetype)
_system_archetypes.append(Archetype(name=name, systems=_systems)) _system_archetypes.append(Archetype(archetype_cluster_id=archetype_id, name=name, systems=_systems))
return _system_archetypes return _system_archetypes
def _load_materials(self): def _load_materials(self):

View File

@ -0,0 +1,520 @@
"""
Palma energy system catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
import xmltodict
from pathlib import Path
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem
from hub.catalog_factories.data_models.energy_systems.system import System
from hub.catalog_factories.data_models.energy_systems.content import Content
from hub.catalog_factories.data_models.energy_systems.non_pv_generation_system import NonPvGenerationSystem
from hub.catalog_factories.data_models.energy_systems.pv_generation_system import PvGenerationSystem
from hub.catalog_factories.data_models.energy_systems.thermal_storage_system import ThermalStorageSystem
from hub.catalog_factories.data_models.energy_systems.performance_curves import PerformanceCurves
from hub.catalog_factories.data_models.energy_systems.archetype import Archetype
from hub.catalog_factories.data_models.construction.material import Material
from hub.catalog_factories.data_models.construction.layer import Layer
class PalmaSystemCatalogue(Catalog):
"""
North america energy system catalog class
"""
def __init__(self, path):
path = str(path / 'palma_systems.xml')
with open(path, 'r', encoding='utf-8') as xml:
self._archetypes = xmltodict.parse(xml.read(),
force_list=['pv_generation_component', 'demand'])
self._storage_components = self._load_storage_components()
self._generation_components = self._load_generation_components()
self._energy_emission_components = self._load_emission_equipments()
self._distribution_components = self._load_distribution_equipments()
self._systems = self._load_systems()
self._system_archetypes = self._load_archetypes()
self._content = Content(self._system_archetypes,
self._systems,
generations=self._generation_components,
distributions=self._distribution_components)
def _load_generation_components(self):
generation_components = []
non_pv_generation_components = self._archetypes['EnergySystemCatalog']['energy_generation_components'][
'non_pv_generation_component']
if non_pv_generation_components is not None:
for non_pv in non_pv_generation_components:
system_id = non_pv['system_id']
name = non_pv['name']
system_type = non_pv['system_type']
model_name = non_pv['model_name']
manufacturer = non_pv['manufacturer']
fuel_type = non_pv['fuel_type']
distribution_systems = non_pv['distribution_systems']
energy_storage_systems = None
if non_pv['energy_storage_systems'] is not None:
storage_component = non_pv['energy_storage_systems']['storage_id']
storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_component)
energy_storage_systems = storage_systems
nominal_heat_output = non_pv['nominal_heat_output']
maximum_heat_output = non_pv['maximum_heat_output']
minimum_heat_output = non_pv['minimum_heat_output']
source_medium = non_pv['source_medium']
supply_medium = non_pv['supply_medium']
heat_efficiency = non_pv['heat_efficiency']
nominal_cooling_output = non_pv['nominal_cooling_output']
maximum_cooling_output = non_pv['maximum_cooling_output']
minimum_cooling_output = non_pv['minimum_cooling_output']
cooling_efficiency = non_pv['cooling_efficiency']
electricity_efficiency = non_pv['electricity_efficiency']
source_temperature = non_pv['source_temperature']
source_mass_flow = non_pv['source_mass_flow']
nominal_electricity_output = non_pv['nominal_electricity_output']
maximum_heat_supply_temperature = non_pv['maximum_heat_supply_temperature']
minimum_heat_supply_temperature = non_pv['minimum_heat_supply_temperature']
maximum_cooling_supply_temperature = non_pv['maximum_cooling_supply_temperature']
minimum_cooling_supply_temperature = non_pv['minimum_cooling_supply_temperature']
heat_output_curve = None
heat_fuel_consumption_curve = None
heat_efficiency_curve = None
cooling_output_curve = None
cooling_fuel_consumption_curve = None
cooling_efficiency_curve = None
if non_pv['heat_output_curve'] is not None:
curve_type = non_pv['heat_output_curve']['curve_type']
dependant_variable = non_pv['heat_output_curve']['dependant_variable']
parameters = non_pv['heat_output_curve']['parameters']
coefficients = list(non_pv['heat_output_curve']['coefficients'].values())
heat_output_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
if non_pv['heat_fuel_consumption_curve'] is not None:
curve_type = non_pv['heat_fuel_consumption_curve']['curve_type']
dependant_variable = non_pv['heat_fuel_consumption_curve']['dependant_variable']
parameters = non_pv['heat_fuel_consumption_curve']['parameters']
coefficients = list(non_pv['heat_fuel_consumption_curve']['coefficients'].values())
heat_fuel_consumption_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
if non_pv['heat_efficiency_curve'] is not None:
curve_type = non_pv['heat_efficiency_curve']['curve_type']
dependant_variable = non_pv['heat_efficiency_curve']['dependant_variable']
parameters = non_pv['heat_efficiency_curve']['parameters']
coefficients = list(non_pv['heat_efficiency_curve']['coefficients'].values())
heat_efficiency_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
if non_pv['cooling_output_curve'] is not None:
curve_type = non_pv['cooling_output_curve']['curve_type']
dependant_variable = non_pv['cooling_output_curve']['dependant_variable']
parameters = non_pv['cooling_output_curve']['parameters']
coefficients = list(non_pv['cooling_output_curve']['coefficients'].values())
cooling_output_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
if non_pv['cooling_fuel_consumption_curve'] is not None:
curve_type = non_pv['cooling_fuel_consumption_curve']['curve_type']
dependant_variable = non_pv['cooling_fuel_consumption_curve']['dependant_variable']
parameters = non_pv['cooling_fuel_consumption_curve']['parameters']
coefficients = list(non_pv['cooling_fuel_consumption_curve']['coefficients'].values())
cooling_fuel_consumption_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
if non_pv['cooling_efficiency_curve'] is not None:
curve_type = non_pv['cooling_efficiency_curve']['curve_type']
dependant_variable = non_pv['cooling_efficiency_curve']['dependant_variable']
parameters = non_pv['cooling_efficiency_curve']['parameters']
coefficients = list(non_pv['cooling_efficiency_curve']['coefficients'].values())
cooling_efficiency_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
dhw = None
if non_pv['domestic_hot_water'] is not None:
if non_pv['domestic_hot_water'] == 'True':
dhw = True
else:
dhw = False
reversible = None
if non_pv['reversible'] is not None:
if non_pv['reversible'] == 'True':
reversible = True
else:
reversible = False
dual_supply = None
if non_pv['simultaneous_heat_cold'] is not None:
if non_pv['simultaneous_heat_cold'] == 'True':
dual_supply = True
else:
dual_supply = False
non_pv_component = NonPvGenerationSystem(system_id=system_id,
name=name,
system_type=system_type,
model_name=model_name,
manufacturer=manufacturer,
fuel_type=fuel_type,
nominal_heat_output=nominal_heat_output,
maximum_heat_output=maximum_heat_output,
minimum_heat_output=minimum_heat_output,
source_medium=source_medium,
supply_medium=supply_medium,
heat_efficiency=heat_efficiency,
nominal_cooling_output=nominal_cooling_output,
maximum_cooling_output=maximum_cooling_output,
minimum_cooling_output=minimum_cooling_output,
cooling_efficiency=cooling_efficiency,
electricity_efficiency=electricity_efficiency,
source_temperature=source_temperature,
source_mass_flow=source_mass_flow,
nominal_electricity_output=nominal_electricity_output,
maximum_heat_supply_temperature=maximum_heat_supply_temperature,
minimum_heat_supply_temperature=minimum_heat_supply_temperature,
maximum_cooling_supply_temperature=maximum_cooling_supply_temperature,
minimum_cooling_supply_temperature=minimum_cooling_supply_temperature,
heat_output_curve=heat_output_curve,
heat_fuel_consumption_curve=heat_fuel_consumption_curve,
heat_efficiency_curve=heat_efficiency_curve,
cooling_output_curve=cooling_output_curve,
cooling_fuel_consumption_curve=cooling_fuel_consumption_curve,
cooling_efficiency_curve=cooling_efficiency_curve,
distribution_systems=distribution_systems,
energy_storage_systems=energy_storage_systems,
domestic_hot_water=dhw,
reversible=reversible,
simultaneous_heat_cold=dual_supply)
generation_components.append(non_pv_component)
pv_generation_components = self._archetypes['EnergySystemCatalog']['energy_generation_components'][
'pv_generation_component']
if pv_generation_components is not None:
for pv in pv_generation_components:
system_id = pv['system_id']
name = pv['name']
system_type = pv['system_type']
model_name = pv['model_name']
manufacturer = pv['manufacturer']
electricity_efficiency = pv['electricity_efficiency']
nominal_electricity_output = pv['nominal_electricity_output']
nominal_ambient_temperature = pv['nominal_ambient_temperature']
nominal_cell_temperature = pv['nominal_cell_temperature']
nominal_radiation = pv['nominal_radiation']
standard_test_condition_cell_temperature = pv['standard_test_condition_cell_temperature']
standard_test_condition_maximum_power = pv['standard_test_condition_maximum_power']
standard_test_condition_radiation = pv['standard_test_condition_radiation']
cell_temperature_coefficient = pv['cell_temperature_coefficient']
width = pv['width']
height = pv['height']
distribution_systems = pv['distribution_systems']
energy_storage_systems = None
if pv['energy_storage_systems'] is not None:
storage_component = pv['energy_storage_systems']['storage_id']
storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_component)
energy_storage_systems = storage_systems
pv_component = PvGenerationSystem(system_id=system_id,
name=name,
system_type=system_type,
model_name=model_name,
manufacturer=manufacturer,
electricity_efficiency=electricity_efficiency,
nominal_electricity_output=nominal_electricity_output,
nominal_ambient_temperature=nominal_ambient_temperature,
nominal_cell_temperature=nominal_cell_temperature,
nominal_radiation=nominal_radiation,
standard_test_condition_cell_temperature=
standard_test_condition_cell_temperature,
standard_test_condition_maximum_power=standard_test_condition_maximum_power,
standard_test_condition_radiation=standard_test_condition_radiation,
cell_temperature_coefficient=cell_temperature_coefficient,
width=width,
height=height,
distribution_systems=distribution_systems,
energy_storage_systems=energy_storage_systems)
generation_components.append(pv_component)
return generation_components
def _load_distribution_equipments(self):
_equipments = []
distribution_systems = self._archetypes['EnergySystemCatalog']['distribution_systems']['distribution_system']
if distribution_systems is not None:
for distribution_system in distribution_systems:
system_id = None
model_name = None
system_type = None
supply_temperature = None
distribution_consumption_fix_flow = None
distribution_consumption_variable_flow = None
heat_losses = None
generation_systems = None
energy_storage_systems = None
emission_systems = None
distribution_equipment = DistributionSystem(system_id=system_id,
model_name=model_name,
system_type=system_type,
supply_temperature=supply_temperature,
distribution_consumption_fix_flow=distribution_consumption_fix_flow,
distribution_consumption_variable_flow=
distribution_consumption_variable_flow,
heat_losses=heat_losses,
generation_systems=generation_systems,
energy_storage_systems=energy_storage_systems,
emission_systems=emission_systems
)
_equipments.append(distribution_equipment)
return _equipments
def _load_emission_equipments(self):
_equipments = []
dissipation_systems = self._archetypes['EnergySystemCatalog']['dissipation_systems']['dissipation_system']
if dissipation_systems is not None:
for dissipation_system in dissipation_systems:
system_id = None
model_name = None
system_type = None
parasitic_energy_consumption = 0
emission_system = EmissionSystem(system_id=system_id,
model_name=model_name,
system_type=system_type,
parasitic_energy_consumption=parasitic_energy_consumption)
_equipments.append(emission_system)
return _equipments
def _load_storage_components(self):
storage_components = []
thermal_storages = self._archetypes['EnergySystemCatalog']['energy_storage_components']['thermalStorages']
for tes in thermal_storages:
storage_id = tes['storage_id']
type_energy_stored = tes['type_energy_stored']
model_name = tes['model_name']
manufacturer = tes['manufacturer']
storage_type = tes['storage_type']
volume = tes['physical_characteristics']['volume']
height = tes['physical_characteristics']['height']
maximum_operating_temperature = tes['maximum_operating_temperature']
materials = self._load_materials()
insulation_material_id = tes['insulation']['material_id']
insulation_material = self._search_material(materials, insulation_material_id)
material_id = tes['physical_characteristics']['material_id']
tank_material = self._search_material(materials, material_id)
thickness = float(tes['insulation']['insulationThickness']) / 100 # from cm to m
insulation_layer = Layer(None, 'insulation', insulation_material, thickness)
thickness = float(tes['physical_characteristics']['tankThickness']) / 100 # from cm to m
tank_layer = Layer(None, 'tank', tank_material, thickness)
media = self._load_media()
media_id = tes['storage_medium']['medium_id']
medium = self._search_media(media, media_id)
layers = [insulation_layer, tank_layer]
nominal_capacity = tes['nominal_capacity']
losses_ratio = tes['losses_ratio']
heating_coil_capacity = tes['heating_coil_capacity']
storage_component = ThermalStorageSystem(storage_id=storage_id,
model_name=model_name,
type_energy_stored=type_energy_stored,
manufacturer=manufacturer,
storage_type=storage_type,
nominal_capacity=nominal_capacity,
losses_ratio=losses_ratio,
volume=volume,
height=height,
layers=layers,
maximum_operating_temperature=maximum_operating_temperature,
storage_medium=medium,
heating_coil_capacity=heating_coil_capacity)
storage_components.append(storage_component)
return storage_components
def _load_systems(self):
base_path = Path(Path(__file__).parent.parent.parent / 'data/energy_systems')
_catalog_systems = []
systems = self._archetypes['EnergySystemCatalog']['systems']['system']
for system in systems:
system_id = system['id']
name = system['name']
demands = system['demands']['demand']
generation_components = system['components']['generation_id']
generation_systems = self._search_generation_equipment(self._load_generation_components(), generation_components)
configuration_schema = None
if system['schema'] is not None:
configuration_schema = Path(base_path / system['schema'])
energy_system = System(system_id=system_id,
name=name,
demand_types=demands,
generation_systems=generation_systems,
distribution_systems=None,
configuration_schema=configuration_schema)
_catalog_systems.append(energy_system)
return _catalog_systems
def _load_archetypes(self):
_system_archetypes = []
system_clusters = self._archetypes['EnergySystemCatalog']['system_archetypes']['system_archetype']
for system_cluster in system_clusters:
name = system_cluster['name']
systems = system_cluster['systems']['system_id']
integer_system_ids = [int(item) for item in systems]
_systems = []
for system_archetype in self._systems:
if int(system_archetype.id) in integer_system_ids:
_systems.append(system_archetype)
_system_archetypes.append(Archetype(name=name, systems=_systems))
return _system_archetypes
def _load_materials(self):
materials = []
_materials = self._archetypes['EnergySystemCatalog']['materials']['material']
for _material in _materials:
material_id = _material['material_id']
name = _material['name']
conductivity = _material['conductivity']
solar_absorptance = _material['solar_absorptance']
thermal_absorptance = _material['thermal_absorptance']
density = _material['density']
specific_heat = _material['specific_heat']
no_mass = _material['no_mass']
visible_absorptance = _material['visible_absorptance']
thermal_resistance = _material['thermal_resistance']
material = Material(material_id,
name,
solar_absorptance=solar_absorptance,
thermal_absorptance=thermal_absorptance,
density=density,
conductivity=conductivity,
thermal_resistance=thermal_resistance,
visible_absorptance=visible_absorptance,
no_mass=no_mass,
specific_heat=specific_heat)
materials.append(material)
return materials
@staticmethod
def _search_material(materials, material_id):
_material = None
for material in materials:
if int(material.id) == int(material_id):
_material = material
break
if _material is None:
raise ValueError(f'Material with the id = [{material_id}] not found in catalog ')
return _material
def _load_media(self):
media = []
_media = [self._archetypes['EnergySystemCatalog']['media']['medium']]
for _medium in _media:
medium_id = _medium['medium_id']
density = _medium['density']
name = _medium['name']
conductivity = _medium['conductivity']
solar_absorptance = _medium['solar_absorptance']
thermal_absorptance = _medium['thermal_absorptance']
specific_heat = _medium['specific_heat']
no_mass = _medium['no_mass']
visible_absorptance = _medium['visible_absorptance']
thermal_resistance = _medium['thermal_resistance']
medium = Material(material_id=medium_id,
name=name,
solar_absorptance=solar_absorptance,
thermal_absorptance=thermal_absorptance,
visible_absorptance=visible_absorptance,
no_mass=no_mass,
thermal_resistance=thermal_resistance,
conductivity=conductivity,
density=density,
specific_heat=specific_heat)
media.append(medium)
return media
@staticmethod
def _search_media(media, medium_id):
_medium = None
for medium in media:
if int(medium.id) == int(medium_id):
_medium = medium
break
if _medium is None:
raise ValueError(f'media with the id = [{medium_id}] not found in catalog ')
return _medium
@staticmethod
def _search_generation_equipment(generation_systems, generation_id):
_generation_systems = []
if isinstance(generation_id, list):
integer_ids = [int(item) for item in generation_id]
for generation in generation_systems:
if int(generation.id) in integer_ids:
_generation_systems.append(generation)
else:
integer_id = int(generation_id)
for generation in generation_systems:
if int(generation.id) == integer_id:
_generation_systems.append(generation)
if len(_generation_systems) == 0:
_generation_systems = None
raise ValueError(f'The system with the following id is not found in catalog [{generation_id}]')
return _generation_systems
@staticmethod
def _search_storage_equipment(storage_systems, storage_id):
_storage_systems = []
for storage in storage_systems:
if storage.id in storage_id:
_storage_systems.append(storage)
if len(_storage_systems) == 0:
_storage_systems = None
raise ValueError(f'The system with the following id is not found in catalog [{storage_id}]')
return _storage_systems
def names(self, category=None):
"""
Get the catalog elements names
:parm: optional category filter
"""
if category is None:
_names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'storage_equipments': []}
for archetype in self._content.archetypes:
_names['archetypes'].append(archetype.name)
for system in self._content.systems:
_names['systems'].append(system.name)
for equipment in self._content.generation_equipments:
_names['generation_equipments'].append(equipment.name)
else:
_names = {category: []}
if category.lower() == 'archetypes':
for archetype in self._content.archetypes:
_names[category].append(archetype.name)
elif category.lower() == 'systems':
for system in self._content.systems:
_names[category].append(system.name)
elif category.lower() == 'generation_equipments':
for system in self._content.generation_equipments:
_names[category].append(system.name)
else:
raise ValueError(f'Unknown category [{category}]')
return _names
def entries(self, category=None):
"""
Get the catalog elements
:parm: optional category filter
"""
if category is None:
return self._content
if category.lower() == 'archetypes':
return self._content.archetypes
if category.lower() == 'systems':
return self._content.systems
if category.lower() == 'generation_equipments':
return self._content.generation_equipments
raise ValueError(f'Unknown category [{category}]')
def get_entry(self, name):
"""
Get one catalog element by names
:parm: entry name
"""
for entry in self._content.archetypes:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.systems:
if entry.name.lower() == name.lower():
return entry
for entry in self._content.generation_equipments:
if entry.name.lower() == name.lower():
return entry
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -10,6 +10,7 @@ from typing import TypeVar
from hub.catalog_factories.energy_systems.montreal_custom_catalog import MontrealCustomCatalog from hub.catalog_factories.energy_systems.montreal_custom_catalog import MontrealCustomCatalog
from hub.catalog_factories.energy_systems.montreal_future_system_catalogue import MontrealFutureSystemCatalogue from hub.catalog_factories.energy_systems.montreal_future_system_catalogue import MontrealFutureSystemCatalogue
from hub.catalog_factories.energy_systems.palma_system_catalgue import PalmaSystemCatalogue
from hub.helpers.utils import validate_import_export_type from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog') Catalog = TypeVar('Catalog')
@ -40,6 +41,13 @@ class EnergySystemsCatalogFactory:
""" """
return MontrealFutureSystemCatalogue(self._path) return MontrealFutureSystemCatalogue(self._path)
@property
def _palma(self):
"""
Retrieve Palma catalog
"""
return PalmaSystemCatalogue(self._path)
@property @property
def catalog(self) -> Catalog: def catalog(self) -> Catalog:
""" """

View File

@ -0,0 +1,227 @@
"""
Palma usage catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Cecilia Pérez cperez@irec.cat
"""
import json
import urllib.request
from pathlib import Path
import xmltodict
import hub.helpers.constants as cte
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.usages.appliances import Appliances
from hub.catalog_factories.data_models.usages.content import Content
from hub.catalog_factories.data_models.usages.lighting import Lighting
from hub.catalog_factories.data_models.usages.occupancy import Occupancy
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
from hub.catalog_factories.data_models.usages.schedule import Schedule
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
from hub.catalog_factories.data_models.usages.usage import Usage
from hub.catalog_factories.usage.usage_helper import UsageHelper
class PalmaCatalog(Catalog):
"""
Palma catalog class
"""
def __init__(self, path):
self._schedules_path = Path(path / 'palma_schedules.json').resolve()
self._space_types_path = Path(path / 'palma_space_types.json').resolve()
self._space_compliance_path = Path(path / 'palma_space_compliance.json').resolve()
self._content = None
self._schedules = {}
self._load_schedules()
self._content = Content(self._load_archetypes())
@staticmethod
def _extract_schedule(raw):
nrcan_schedule_type = raw['category']
if 'Heating' in raw['name'] and 'Water' not in raw['name']:
nrcan_schedule_type = f'{nrcan_schedule_type} Heating'
elif 'Cooling' in raw['name']:
nrcan_schedule_type = f'{nrcan_schedule_type} Cooling'
if nrcan_schedule_type not in UsageHelper().nrcan_schedule_type_to_hub_schedule_type:
return None
hub_type = UsageHelper().nrcan_schedule_type_to_hub_schedule_type[nrcan_schedule_type]
data_type = UsageHelper().nrcan_data_type_to_hub_data_type[raw['units']]
time_step = UsageHelper().nrcan_time_to_hub_time[raw['type']]
# nrcan only uses daily range for the schedules
time_range = cte.DAY
day_types = UsageHelper().nrcan_day_type_to_hub_days[raw['day_types']]
return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types)
def _load_schedules(self):
_schedule_types = []
with open(self._schedules_path, 'r') as f:
schedules_type = json.load(f)
for schedule_type in schedules_type['tables']['schedules']['table']:
schedule = PalmaCatalog._extract_schedule(schedule_type)
if schedule_type['name'] not in _schedule_types:
_schedule_types.append(schedule_type['name'])
if schedule is not None:
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_schedules(self, name):
schedule = None
if name in self._schedules:
schedule = self._schedules[name]
return schedule
def _load_archetypes(self):
usages = []
with open(self._space_types_path, 'r') as f:
space_types = json.load(f)['tables']['space_types']['table']
space_types = [st for st in space_types if st['space_type'] == 'WholeBuilding']
with open(self._space_compliance_path, 'r') as f:
space_types_compliance = json.load(f)['tables']['space_compliance']['table']
space_types_compliance = [st for st in space_types_compliance if st['space_type'] == 'WholeBuilding']
space_types_dictionary = {}
for space_type in space_types_compliance:
usage_type = space_type['building_type']
# people/m2
occupancy_density = space_type['occupancy_per_area_people_per_m2']
# W/m2
lighting_density = space_type['lighting_per_area_w_per_m2']
# W/m2
appliances_density = space_type['electric_equipment_per_area_w_per_m2']
# peak flow in gallons/h/m2
domestic_hot_water_peak_flow = (
space_type['service_water_heating_peak_flow_per_area'] *
cte.GALLONS_TO_QUBIC_METERS / cte.HOUR_TO_SECONDS
)
space_types_dictionary[usage_type] = {'occupancy_per_area': occupancy_density,
'lighting_per_area': lighting_density,
'electric_equipment_per_area': appliances_density,
'service_water_heating_peak_flow_per_area': domestic_hot_water_peak_flow
}
for space_type in space_types:
usage_type = space_type['building_type']
space_type_compliance = space_types_dictionary[usage_type]
occupancy_density = space_type_compliance['occupancy_per_area']
sensible_convective_internal_gain = space_type['sensible_convective_internal_gain']
sensible_radiative_internal_gain = space_type['sensible_radiative_internal_gain']
latent_internal_gain = space_type['latent_internal_gain']
lighting_density = space_type_compliance['lighting_per_area']
appliances_density = space_type_compliance['electric_equipment_per_area']
domestic_hot_water_peak_flow = space_type_compliance['service_water_heating_peak_flow_per_area']
occupancy_schedule_name = space_type['occupancy_schedule']
lighting_schedule_name = space_type['lighting_schedule']
appliance_schedule_name = space_type['electric_equipment_schedule']
hvac_schedule_name = space_type['exhaust_schedule']
if hvac_schedule_name and 'FAN' in hvac_schedule_name:
hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan')
if not hvac_schedule_name:
hvac_schedule_name = 'default_HVAC_schedule'
heating_setpoint_schedule_name = space_type['heating_setpoint_schedule']
cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule']
domestic_hot_water_schedule_name = space_type['service_water_heating_schedule']
occupancy_schedule = self._get_schedules(occupancy_schedule_name)
lighting_schedule = self._get_schedules(lighting_schedule_name)
appliance_schedule = self._get_schedules(appliance_schedule_name)
heating_schedule = self._get_schedules(heating_setpoint_schedule_name)
cooling_schedule = self._get_schedules(cooling_setpoint_schedule_name)
hvac_availability = self._get_schedules(hvac_schedule_name)
domestic_hot_water_load_schedule = self._get_schedules(domestic_hot_water_schedule_name)
# ACH -> 1/s
mechanical_air_change = space_type['ventilation_air_changes'] / cte.HOUR_TO_SECONDS
# cfm/ft2 to m3/m2.s
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
# cfm/person to m3/m2.s
ventilation_rate += space_type['ventilation_per_person'] / (
pow(cte.METERS_TO_FEET, 3) * cte.MINUTES_TO_SECONDS
) * occupancy_density
lighting_radiative_fraction = space_type['lighting_fraction_radiant']
lighting_convective_fraction = 0
if lighting_radiative_fraction is not None:
lighting_convective_fraction = 1 - lighting_radiative_fraction
lighting_latent_fraction = 0
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
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
domestic_hot_water_service_temperature = space_type['service_water_heating_target_temperature']
occupancy = Occupancy(occupancy_density,
sensible_convective_internal_gain,
sensible_radiative_internal_gain,
latent_internal_gain,
occupancy_schedule)
lighting = Lighting(lighting_density,
lighting_convective_fraction,
lighting_radiative_fraction,
lighting_latent_fraction,
lighting_schedule)
appliances = Appliances(appliances_density,
appliances_convective_fraction,
appliances_radiative_fraction,
appliances_latent_fraction,
appliance_schedule)
thermal_control = ThermalControl(None,
None,
None,
hvac_availability,
heating_schedule,
cooling_schedule)
domestic_hot_water = DomesticHotWater(None,
domestic_hot_water_peak_flow,
domestic_hot_water_service_temperature,
domestic_hot_water_load_schedule)
hours_day = None
days_year = None
usages.append(Usage(usage_type,
hours_day,
days_year,
mechanical_air_change,
ventilation_rate,
occupancy,
lighting,
appliances,
thermal_control,
domestic_hot_water))
return usages
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")

View File

@ -11,6 +11,7 @@ from typing import TypeVar
from hub.catalog_factories.usage.comnet_catalog import ComnetCatalog from hub.catalog_factories.usage.comnet_catalog import ComnetCatalog
from hub.catalog_factories.usage.nrcan_catalog import NrcanCatalog from hub.catalog_factories.usage.nrcan_catalog import NrcanCatalog
from hub.catalog_factories.usage.eilat_catalog import EilatCatalog from hub.catalog_factories.usage.eilat_catalog import EilatCatalog
from hub.catalog_factories.usage.palma_catalog import PalmaCatalog
from hub.helpers.utils import validate_import_export_type from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog') Catalog = TypeVar('Catalog')
@ -42,6 +43,13 @@ class UsageCatalogFactory:
# nrcan retrieves the data directly from github # nrcan retrieves the data directly from github
return NrcanCatalog(self._path) return NrcanCatalog(self._path)
@property
def _palma(self):
"""
Retrieve Palma catalog
"""
return PalmaCatalog(self._path)
@property @property
def _eilat(self): def _eilat(self):
""" """

View File

@ -27,7 +27,7 @@ class Building(CityObject):
""" """
Building(CityObject) class Building(CityObject) class
""" """
def __init__(self, name, surfaces, year_of_construction, function, terrains=None, city=None): def __init__(self, name, surfaces, year_of_construction, function, usages=None, terrains=None, city=None):
super().__init__(name, surfaces) super().__init__(name, surfaces)
self._city = city self._city = city
self._households = None self._households = None
@ -36,6 +36,7 @@ class Building(CityObject):
self._terrains = terrains self._terrains = terrains
self._year_of_construction = year_of_construction self._year_of_construction = year_of_construction
self._function = function self._function = function
self._usages = usages
self._average_storey_height = None self._average_storey_height = None
self._storeys_above_ground = None self._storeys_above_ground = None
self._floor_area = None self._floor_area = None
@ -92,6 +93,7 @@ class Building(CityObject):
logging.error('Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type) logging.error('Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type)
self._domestic_hot_water_peak_load = None self._domestic_hot_water_peak_load = None
self._fuel_consumption_breakdown = {} self._fuel_consumption_breakdown = {}
self._systems_archetype_cluster_id = None
self._pv_generation = {} self._pv_generation = {}
@property @property
@ -256,7 +258,17 @@ class Building(CityObject):
:param value: str :param value: str
""" """
if value is not None: if value is not None:
self._function = str(value) self._function = value
@property
def usages(self) -> Union[None, list]:
"""
Get building usages, if none, assume usage is function
:return: None or list of functions
"""
if self._usages is None and self._function is not None:
self._usages = [{'usage': self._function, 'ratio': 1 }]
return self._usages
@property @property
def average_storey_height(self) -> Union[None, float]: def average_storey_height(self) -> Union[None, float]:
@ -292,7 +304,10 @@ class Building(CityObject):
""" """
if self._storeys_above_ground is None: if self._storeys_above_ground is None:
if self.eave_height is not None and self.average_storey_height is not None: if self.eave_height is not None and self.average_storey_height is not None:
self._storeys_above_ground = int(self.eave_height / self.average_storey_height) storeys_above_ground = int(self.eave_height / self.average_storey_height)
if storeys_above_ground == 0:
storeys_above_ground += 1
self._storeys_above_ground = storeys_above_ground
return self._storeys_above_ground return self._storeys_above_ground
@storeys_above_ground.setter @storeys_above_ground.setter
@ -590,19 +605,6 @@ class Building(CityObject):
""" """
self._city = value self._city = value
@property
def usages_percentage(self):
"""
Get the usages and percentages for the building
"""
_usage = ''
for internal_zone in self.internal_zones:
if internal_zone.usages is None:
continue
for usage in internal_zone.usages:
_usage = f'{_usage}{usage.name}_{usage.percentage} '
return _usage.rstrip()
@property @property
def energy_systems(self) -> Union[None, List[EnergySystem]]: def energy_systems(self) -> Union[None, List[EnergySystem]]:
""" """
@ -736,41 +738,42 @@ class Building(CityObject):
return self._distribution_systems_electrical_consumption return self._distribution_systems_electrical_consumption
for energy_system in self.energy_systems: for energy_system in self.energy_systems:
distribution_systems = energy_system.distribution_systems distribution_systems = energy_system.distribution_systems
for distribution_system in distribution_systems: if distribution_systems is not None:
emission_systems = distribution_system.emission_systems for distribution_system in distribution_systems:
parasitic_energy_consumption = 0 emission_systems = distribution_system.emission_systems
if emission_systems is not None: parasitic_energy_consumption = 0
for emission_system in emission_systems: if emission_systems is not None:
parasitic_energy_consumption += emission_system.parasitic_energy_consumption for emission_system in emission_systems:
consumption_variable_flow = distribution_system.distribution_consumption_variable_flow parasitic_energy_consumption += emission_system.parasitic_energy_consumption
for demand_type in energy_system.demand_types: consumption_variable_flow = distribution_system.distribution_consumption_variable_flow
if demand_type.lower() == cte.HEATING.lower(): for demand_type in energy_system.demand_types:
if _peak_load_type == cte.HEATING.lower(): if demand_type.lower() == cte.HEATING.lower():
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow if _peak_load_type == cte.HEATING.lower():
for heating_demand_key in self.heating_demand: _consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
_consumption = [0]*len(self.heating_demand[heating_demand_key]) for heating_demand_key in self.heating_demand:
_demand = self.heating_demand[heating_demand_key] _consumption = [0]*len(self.heating_demand[heating_demand_key])
for i, _ in enumerate(_consumption): _demand = self.heating_demand[heating_demand_key]
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i] for i, _ in enumerate(_consumption):
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption _consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
if demand_type.lower() == cte.COOLING.lower(): self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
if _peak_load_type == cte.COOLING.lower(): if demand_type.lower() == cte.COOLING.lower():
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow if _peak_load_type == cte.COOLING.lower():
for demand_key in self.cooling_demand: _consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
_consumption = self._distribution_systems_electrical_consumption[demand_key] for demand_key in self.cooling_demand:
_demand = self.cooling_demand[demand_key] _consumption = self._distribution_systems_electrical_consumption[demand_key]
for i, _ in enumerate(_consumption): _demand = self.cooling_demand[demand_key]
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i] for i, _ in enumerate(_consumption):
self._distribution_systems_electrical_consumption[demand_key] = _consumption _consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
self._distribution_systems_electrical_consumption[demand_key] = _consumption
for key, item in self._distribution_systems_electrical_consumption.items(): for key, item in self._distribution_systems_electrical_consumption.items():
for i in range(0, len(item)): for i in range(0, len(item)):
_working_hours_value = _working_hours[key] _working_hours_value = _working_hours[key]
if len(item) == 12: if len(item) == 12:
_working_hours_value = _working_hours[key][i] _working_hours_value = _working_hours[key][i]
self._distribution_systems_electrical_consumption[key][i] += ( self._distribution_systems_electrical_consumption[key][i] += (
_peak_load * _consumption_fix_flow * _working_hours_value * cte.WATTS_HOUR_TO_JULES _peak_load * _consumption_fix_flow * _working_hours_value * cte.WATTS_HOUR_TO_JULES
) )
return self._distribution_systems_electrical_consumption return self._distribution_systems_electrical_consumption
@ -863,53 +866,87 @@ class Building(CityObject):
Get energy consumption of different sectors Get energy consumption of different sectors
return: dict return: dict
""" """
fuel_breakdown = {cte.ELECTRICITY: {cte.LIGHTING: self.lighting_electrical_demand[cte.YEAR][0], fuel_breakdown = {cte.ELECTRICITY: {cte.LIGHTING: self.lighting_electrical_demand[cte.YEAR][0] if self.lighting_electrical_demand else 0,
cte.APPLIANCES: self.appliances_electrical_demand[cte.YEAR][0]}} cte.APPLIANCES: self.appliances_electrical_demand[cte.YEAR][0] if self.appliances_electrical_demand else 0}}
energy_systems = self.energy_systems energy_systems = self.energy_systems
for energy_system in energy_systems: if energy_systems is not None:
demand_types = energy_system.demand_types for energy_system in energy_systems:
generation_systems = energy_system.generation_systems demand_types = energy_system.demand_types
for demand_type in demand_types: generation_systems = energy_system.generation_systems
for generation_system in generation_systems: for demand_type in demand_types:
if generation_system.system_type != cte.PHOTOVOLTAIC: for generation_system in generation_systems:
if generation_system.fuel_type not in fuel_breakdown: if generation_system.system_type != cte.PHOTOVOLTAIC:
fuel_breakdown[generation_system.fuel_type] = {} if generation_system.fuel_type not in fuel_breakdown:
if demand_type in generation_system.energy_consumption: fuel_breakdown[generation_system.fuel_type] = {}
fuel_breakdown[f'{generation_system.fuel_type}'][f'{demand_type}'] = ( if demand_type in generation_system.energy_consumption:
generation_system.energy_consumption)[f'{demand_type}'][cte.YEAR][0] fuel_breakdown[f'{generation_system.fuel_type}'][f'{demand_type}'] = (
storage_systems = generation_system.energy_storage_systems generation_system.energy_consumption)[f'{demand_type}'][cte.YEAR][0]
if storage_systems: storage_systems = generation_system.energy_storage_systems
for storage_system in storage_systems: if storage_systems:
if storage_system.type_energy_stored == 'thermal' and storage_system.heating_coil_energy_consumption: for storage_system in storage_systems:
fuel_breakdown[cte.ELECTRICITY][f'{demand_type}'] += storage_system.heating_coil_energy_consumption[cte.YEAR][0] if storage_system.type_energy_stored == 'thermal' and storage_system.heating_coil_energy_consumption:
#TODO: When simulation models of all energy system archetypes are created, this part can be removed fuel_breakdown[cte.ELECTRICITY][f'{demand_type}'] += (
heating_fuels = [] storage_system.heating_coil_energy_consumption)[f'{demand_type}'][cte.YEAR][0]
dhw_fuels = [] #TODO: When simulation models of all energy system archetypes are created, this part can be removed
for energy_system in self.energy_systems: heating_fuels = []
if cte.HEATING in energy_system.demand_types: dhw_fuels = []
for generation_system in energy_system.generation_systems: for energy_system in self.energy_systems:
heating_fuels.append(generation_system.fuel_type) if cte.HEATING in energy_system.demand_types:
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types: for generation_system in energy_system.generation_systems:
for generation_system in energy_system.generation_systems: heating_fuels.append(generation_system.fuel_type)
dhw_fuels.append(generation_system.fuel_type) if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
for key in fuel_breakdown: for generation_system in energy_system.generation_systems:
if key == cte.ELECTRICITY and cte.COOLING not in fuel_breakdown[key]: dhw_fuels.append(generation_system.fuel_type)
for energy_system in energy_systems: for key in fuel_breakdown:
if cte.COOLING in energy_system.demand_types and cte.COOLING not in fuel_breakdown[key]: if key == cte.ELECTRICITY and cte.COOLING not in fuel_breakdown[key]:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.fuel_type][cte.COOLING] = self.cooling_consumption[cte.YEAR][0]
for fuel in heating_fuels:
if cte.HEATING not in fuel_breakdown[fuel]:
for energy_system in energy_systems: for energy_system in energy_systems:
if cte.HEATING in energy_system.demand_types: if cte.COOLING in energy_system.demand_types and cte.COOLING not in fuel_breakdown[key]:
for generation_system in energy_system.generation_systems: if self.cooling_consumption:
fuel_breakdown[generation_system.fuel_type][cte.HEATING] = self.heating_consumption[cte.YEAR][0] fuel_breakdown[energy_system.generation_systems[0].fuel_type][cte.COOLING] = self.cooling_consumption[cte.YEAR][0]
for fuel in dhw_fuels: for fuel in heating_fuels:
if cte.DOMESTIC_HOT_WATER not in fuel_breakdown[fuel]: if cte.HEATING not in fuel_breakdown[fuel]:
for energy_system in energy_systems: for energy_system in energy_systems:
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types: if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems: if self.heating_consumption:
fuel_breakdown[generation_system.fuel_type][cte.DOMESTIC_HOT_WATER] = self.domestic_hot_water_consumption[cte.YEAR][0] fuel_breakdown[energy_system.generation_systems[0].fuel_type][cte.HEATING] = self.heating_consumption[cte.YEAR][0]
for fuel in dhw_fuels:
if cte.DOMESTIC_HOT_WATER not in fuel_breakdown[fuel]:
for energy_system in energy_systems:
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
if self.domestic_hot_water_consumption:
fuel_breakdown[energy_system.generation_systems[0].fuel_type][cte.DOMESTIC_HOT_WATER] = self.domestic_hot_water_consumption[cte.YEAR][0]
self._fuel_consumption_breakdown = fuel_breakdown self._fuel_consumption_breakdown = fuel_breakdown
return self._fuel_consumption_breakdown return self._fuel_consumption_breakdown
@property
def energy_systems_archetype_cluster_id(self):
"""
Get energy systems archetype id
:return: str
"""
return self._systems_archetype_cluster_id
@energy_systems_archetype_cluster_id.setter
def energy_systems_archetype_cluster_id(self, value):
"""
Set energy systems archetype id
:param value: str
"""
self._systems_archetype_cluster_id = value
@property
def pv_generation(self):
"""
temporary attribute to get the onsite pv generation in W
:return: dict
"""
return self._pv_generation
@pv_generation.setter
def pv_generation(self, value):
"""
temporary attribute to set the onsite pv generation in W
:param value: float
"""
self._pv_generation = value

View File

@ -135,6 +135,8 @@ class InternalZone:
if self.thermal_archetype is None: if self.thermal_archetype is None:
return None # there are no archetype return None # there are no archetype
_number_of_storeys = int(self.volume / self.area / self.thermal_archetype.average_storey_height) _number_of_storeys = int(self.volume / self.area / self.thermal_archetype.average_storey_height)
if _number_of_storeys == 0:
_number_of_storeys = 1
_thermal_zone = ThermalZone(_thermal_boundaries, self, self.volume, self.area, _number_of_storeys) _thermal_zone = ThermalZone(_thermal_boundaries, self, self.volume, self.area, _number_of_storeys)
for thermal_boundary in _thermal_zone.thermal_boundaries: for thermal_boundary in _thermal_zone.thermal_boundaries:
thermal_boundary.thermal_zones = [_thermal_zone] thermal_boundary.thermal_zones = [_thermal_zone]

View File

@ -157,6 +157,7 @@ class Surface:
if self._inclination is None: if self._inclination is None:
self._inclination = np.arccos(self.perimeter_polygon.normal[2]) self._inclination = np.arccos(self.perimeter_polygon.normal[2])
return self._inclination return self._inclination
@property @property
def type(self): def type(self):
""" """

View File

@ -34,7 +34,7 @@ class ThermalZone:
volume, volume,
footprint_area, footprint_area,
number_of_storeys, number_of_storeys,
usage_name=None): usages=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
@ -51,10 +51,6 @@ class ThermalZone:
self._view_factors_matrix = None self._view_factors_matrix = None
self._total_floor_area = None self._total_floor_area = None
self._number_of_storeys = number_of_storeys self._number_of_storeys = number_of_storeys
self._usage_name = usage_name
self._usage_from_parent = False
if usage_name is None:
self._usage_from_parent = True
self._hours_day = None self._hours_day = None
self._days_year = None self._days_year = None
self._mechanical_air_change = None self._mechanical_air_change = None
@ -64,7 +60,12 @@ class ThermalZone:
self._internal_gains = None self._internal_gains = None
self._thermal_control = None self._thermal_control = None
self._domestic_hot_water = None self._domestic_hot_water = None
self._usages = None self._usage_name = None
self._usages = usages
self._usage_from_parent = False
if usages is None:
self._usage_from_parent = True
@property @property
def parent_internal_zone(self) -> InternalZone: def parent_internal_zone(self) -> InternalZone:
@ -77,24 +78,11 @@ class ThermalZone:
@property @property
def usages(self): def usages(self):
""" """
Get the thermal zone usages including percentage with the format [percentage]-usage_[percentage]-usage... Get the thermal zone usages
Eg: 70-office_30-residential
:return: str :return: str
""" """
if self._usage_from_parent: if self._usage_from_parent:
self._usages = copy.deepcopy(self._parent_internal_zone.usages) self._usages = copy.deepcopy(self._parent_internal_zone.usages)
else:
values = self._usage_name.split('_')
usages = []
for value in values:
usages.append(value.split('-'))
self._usages = []
for parent_usage in self._parent_internal_zone.usages:
for value in usages:
if parent_usage.name == value[1]:
new_usage = copy.deepcopy(parent_usage)
new_usage.percentage = float(value[0]) / 100
self._usages.append(new_usage)
return self._usages return self._usages
@property @property

View File

@ -22,14 +22,13 @@ class PvGenerationSystem(GenerationSystem):
self._nominal_radiation = None self._nominal_radiation = None
self._standard_test_condition_cell_temperature = None self._standard_test_condition_cell_temperature = None
self._standard_test_condition_maximum_power = None self._standard_test_condition_maximum_power = None
self._standard_test_condition_radiation = None
self._cell_temperature_coefficient = None self._cell_temperature_coefficient = None
self._width = None self._width = None
self._height = None self._height = None
self._electricity_power = None self._electricity_power_output = {}
self._tilt_angle = None self._tilt_angle = None
self._surface_azimuth = None self._installed_capacity = None
self._solar_altitude_angle = None
self._solar_azimuth_angle = None
@property @property
def nominal_electricity_output(self): def nominal_electricity_output(self):
@ -143,6 +142,22 @@ class PvGenerationSystem(GenerationSystem):
""" """
self._standard_test_condition_maximum_power = value self._standard_test_condition_maximum_power = value
@property
def standard_test_condition_radiation(self):
"""
Get standard test condition radiation in W/m2
:return: float
"""
return self._standard_test_condition_radiation
@standard_test_condition_radiation.setter
def standard_test_condition_radiation(self, value):
"""
Set standard test condition radiation in W/m2
:param value: float
"""
self._standard_test_condition_radiation = value
@property @property
def cell_temperature_coefficient(self): def cell_temperature_coefficient(self):
""" """
@ -192,49 +207,33 @@ class PvGenerationSystem(GenerationSystem):
self._height = value self._height = value
@property @property
def electricity_power(self): def electricity_power_output(self):
""" """
Get electricity_power in W Get electricity_power in W
:return: float :return: float
""" """
return self._electricity_power return self._electricity_power_output
@electricity_power.setter @electricity_power_output.setter
def electricity_power(self, value): def electricity_power_output(self, value):
""" """
Set electricity_power in W Set electricity_power in W
:param value: float :param value: float
""" """
self._electricity_power = value self._electricity_power_output = value
@property @property
def tilt_angle(self): def installed_capacity(self):
""" """
Get tilt angle of PV system in degrees Get the total installed nominal capacity in W
:return: float :return: float
""" """
return self._tilt_angle return self._installed_capacity
@tilt_angle.setter @installed_capacity.setter
def tilt_angle(self, value): def installed_capacity(self, value):
""" """
Set PV system tilt angle in degrees Set the total installed nominal capacity in W
:param value: float :param value: float
""" """
self._tilt_angle = value self._installed_capacity = value
@property
def surface_azimuth(self):
"""
Get surface azimuth angle of PV system in degrees. 0 is North
:return: float
"""
return self._surface_azimuth
@surface_azimuth.setter
def surface_azimuth(self, value):
"""
Set PV system tilt angle in degrees
:param value: float
"""
self._surface_azimuth = value

View File

@ -0,0 +1,774 @@
{
"archetypes": [
{
"function": "Large multifamily building",
"period_of_construction": "2021_2050",
"climate_zone": "B3",
"average_storey_height": 3.57,
"thermal_capacity": 83.018,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0005,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "PA1_PA2_2021_2050_FACEXT",
"transparent_surface_name": "PA1_PA2_2021_2050_WIN1",
"transparent_ratio": {
"north": "60",
"east": "5",
"south": "60",
"west": "5"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "PA1_PA2_2021_2050_ROOF",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "PA1_PA2_2021_2050_FLOOR"
},
"GroundWall": {
"opaque_surface_name": "PA1_PA2_2021_2050_FACEXT"
},
"GroundRoofCeiling": {
"opaque_surface_name": "PA1_PA2_2021_2050_FLOORINT"
}
}
},
{
"function": "Medium multifamily building",
"period_of_construction": "2021_2050",
"climate_zone": "B3",
"average_storey_height": 3.57,
"thermal_capacity": 83.018,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0005,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "PA1_PA2_2021_2050_FACEXT",
"transparent_surface_name": "PA1_PA2_2021_2050_WIN1",
"transparent_ratio": {
"north": "60",
"east": "5",
"south": "60",
"west": "5"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "PA1_PA2_2021_2050_ROOF",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "PA1_PA2_2021_2050_FLOOR"
},
"GroundWall": {
"opaque_surface_name": "PA1_PA2_2021_2050_FACEXT"
},
"GroundRoofCeiling": {
"opaque_surface_name": "PA1_PA2_2021_2050_FLOORINT"
}
}
},
{
"function": "Small multifamily building",
"period_of_construction": "2021_2050",
"climate_zone": "B3",
"average_storey_height": 3.57,
"thermal_capacity": 83.018,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0005,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "PA1_PA2_2021_2050_FACEXT",
"transparent_surface_name": "PA1_PA2_2021_2050_WIN1",
"transparent_ratio": {
"north": "60",
"east": "5",
"south": "60",
"west": "5"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "PA1_PA2_2021_2050_ROOF",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "PA1_PA2_2021_2050_FLOOR"
},
"GroundWall": {
"opaque_surface_name": "PA1_PA2_2021_2050_FACEXT"
},
"GroundRoofCeiling": {
"opaque_surface_name": "PA1_PA2_2021_2050_FLOORINT"
}
}
},
{
"function": "Single-family building",
"period_of_construction": "2021_2050",
"climate_zone": "B3",
"average_storey_height": 3.57,
"thermal_capacity": 83.018,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0005,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "PA1_PA2_2021_2050_FACEXT",
"transparent_surface_name": "PA1_PA2_2021_2050_WIN1",
"transparent_ratio": {
"north": "60",
"east": "5",
"south": "60",
"west": "5"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "PA1_PA2_2021_2050_ROOF",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "PA1_PA2_2021_2050_FLOOR"
},
"GroundWall": {
"opaque_surface_name": "PA1_PA2_2021_2050_FACEXT"
},
"GroundRoofCeiling": {
"opaque_surface_name": "PA1_PA2_2021_2050_FLOORINT"
}
}
},
{
"function": "Large multifamily building",
"period_of_construction": "1961_1980",
"climate_zone": "B3",
"average_storey_height": 3.57,
"thermal_capacity": 3000,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0045,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "PA1_PA2_1961_1980_FACEXT1",
"transparent_surface_name": "PA1_PA2_1961_1980_WIN1",
"transparent_ratio": {
"north": "60",
"east": "60",
"south": "60",
"west": "60"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "PA1_PA2_1961_1980_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "PA1_PA2_1961_1980_FLOOR1"
},
"GroundWall": {
"opaque_surface_name": "PA1_PA2_1961_1980_FACEXT1"
},
"GroundRoofCeiling": {
"opaque_surface_name": "PA1_PA2_1961_1980_FLOOR4"
}
}
},
{
"function": "Large multifamily building",
"period_of_construction": "1981_2007",
"climate_zone": "B3",
"average_storey_height": 3.2,
"thermal_capacity": 3179,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.003,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "E_1981_2007_FACEXT1",
"transparent_surface_name": "E_1981_2007_WIN1",
"transparent_ratio": {
"north": "45",
"east": "45",
"south": "45",
"west": "45"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "E_1981_2007_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "E_1981_2007_FLOORGR1"
}
}
},
{
"function": "Medium multifamily building",
"period_of_construction": "1800_1900",
"climate_zone": "B3",
"average_storey_height": 4.39,
"thermal_capacity": 3330,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.006,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "A_B1900_FACEXT1",
"transparent_surface_name": "A_B1900_WIN2",
"transparent_ratio": {
"north": "20",
"east": "20",
"south": "20",
"west": "20"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "A_B1900_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "A_B1900_FLOORGR1"
}
}
},
{
"function": "Medium multifamily building",
"period_of_construction": "1901_1940",
"climate_zone": "B3",
"average_storey_height": 3.65,
"thermal_capacity": 3420,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.006,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "B_1901_1940_FACEXT1",
"transparent_surface_name": "B_1901_1940_WIN1",
"transparent_ratio": {
"north": "40",
"east": "40",
"south": "40",
"west": "40"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "B_1901_1940_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "B_1901_1940_FLOORGR1"
}
}
},
{
"function": "Medium multifamily building",
"period_of_construction": "1941_1960",
"climate_zone": "B3",
"average_storey_height": 3.6,
"thermal_capacity": 3000,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0055,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "C_1941_1960_FACEXT1",
"transparent_surface_name": "C_1941_1960_WIN1",
"transparent_ratio": {
"north": "30",
"east": "30",
"south": "30",
"west": "30"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "C_1941_1960_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "C_1941_1960_FLOORGR1"
}
}
},
{
"function": "Medium multifamily building",
"period_of_construction": "1961_1980",
"climate_zone": "B3",
"average_storey_height": 4.5,
"thermal_capacity": 3540,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0045,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "PA1_PA2_1961_1980_FACEXT1",
"transparent_surface_name": "PA1_PA2_1961_1980_WIN1",
"transparent_ratio": {
"north": "55",
"east": "55",
"south": "55",
"west": "55"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "PA1_PA2_1961_1980_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "PA1_PA2_1961_1980_FLOOR1"
}
}
},
{
"function": "Medium multifamily building",
"period_of_construction": "1981_2007",
"climate_zone": "B3",
"average_storey_height": 3.2,
"thermal_capacity": 3179,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.003,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "E_1981_2007_FACEXT1",
"transparent_surface_name": "E_1981_2007_WIN1",
"transparent_ratio": {
"north": "45",
"east": "45",
"south": "45",
"west": "45"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "E_1981_2007_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "E_1981_2007_FLOORGR1"
}
}
},
{
"function": "Medium multifamily building",
"period_of_construction": "2008_2014",
"climate_zone": "B3",
"average_storey_height": 2.75,
"thermal_capacity": 3290,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0015,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "F_2008_2014_FACEXT1",
"transparent_surface_name": "F_2008_2014_WIN1",
"transparent_ratio": {
"north": "40",
"east": "40",
"south": "40",
"west": "40"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "F_2008_2014_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "F_2008_2014_FLOORGR1"
}
}
},
{
"function": "Small multifamily building",
"period_of_construction": "1800_1980",
"climate_zone": "B3",
"average_storey_height": 3.8,
"thermal_capacity": 3527.9,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.006,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "PA3_PA4_1901_1940_FACEXT1",
"transparent_surface_name": "PA3_PA4_1901_1940_WIN1",
"transparent_ratio": {
"north": "40",
"east": "40",
"south": "40",
"west": "40"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "PA3_PA4_1901_1940_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "PA3_PA4_1901_1940_FLOORGR1"
}
}
},
{
"function": "Small multifamily building",
"period_of_construction": "1981_2007",
"climate_zone": "B3",
"average_storey_height": 3.2,
"thermal_capacity": 3179,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.003,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "E_1981_2007_FACEXT1",
"transparent_surface_name": "E_1981_2007_WIN1",
"transparent_ratio": {
"north": "45",
"east": "45",
"south": "45",
"west": "45"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "E_1981_2007_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "E_1981_2007_FLOORGR1"
}
}
},
{
"function": "Small multifamily building",
"period_of_construction": "2008_2014",
"climate_zone": "B3",
"average_storey_height": 2.75,
"thermal_capacity": 3290,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0015,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "F_2008_2014_FACEXT1",
"transparent_surface_name": "F_2008_2014_WIN1",
"transparent_ratio": {
"north": "40",
"east": "40",
"south": "40",
"west": "40"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "F_2008_2014_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "F_2008_2014_FLOORGR1"
}
}
},
{
"function": "Small multifamily building",
"period_of_construction": "2015_2019",
"climate_zone": "B3",
"average_storey_height": 2.75,
"thermal_capacity": 3290,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0005,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "G_2015_2019_FACEXT1",
"transparent_surface_name": "G_2015_2019_WIN1",
"transparent_ratio": {
"north": "40",
"east": "40",
"south": "40",
"west": "40"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "G_2015_2019_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "G_2015_2019_FLOORGR1"
}
}
},
{
"function": "Single-family building",
"period_of_construction": "1800_1980",
"climate_zone": "B3",
"average_storey_height": 3.68,
"thermal_capacity": 4400,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.006,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "PA3_PA4_1901_1940_FACEXT1",
"transparent_surface_name": "PA3_PA4_1901_1940_WIN1",
"transparent_ratio": {
"north": "40",
"east": "40",
"south": "40",
"west": "40"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "PA3_PA4_1901_1940_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "PA3_PA4_1901_1940_FLOORGR1"
}
}
},
{
"function": "Single-family building",
"period_of_construction": "1981_2007",
"climate_zone": "B3",
"average_storey_height": 3.2,
"thermal_capacity": 3179,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.003,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "E_1981_2007_FACEXT1",
"transparent_surface_name": "E_1981_2007_WIN1",
"transparent_ratio": {
"north": "45",
"east": "45",
"south": "45",
"west": "45"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "E_1981_2007_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "E_1981_2007_FLOORGR1"
}
}
},
{
"function": "Single-family building",
"period_of_construction": "2008_2014",
"climate_zone": "B3",
"average_storey_height": 3.75,
"thermal_capacity": 3200,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0015,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "F_2008_2014_FACEXT1",
"transparent_surface_name": "F_2008_2014_WIN1",
"transparent_ratio": {
"north": "60",
"east": "60",
"south": "60",
"west": "60"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "F_2008_2014_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "F_2008_2014_FLOORGR1"
}
}
},
{
"function": "Single-family building",
"period_of_construction": "2015_2019",
"climate_zone": "B3",
"average_storey_height": 3.75,
"thermal_capacity": 3200,
"extra_loses_due_thermal_bridges": 0.1,
"infiltration_rate_for_ventilation_system_on": 0,
"infiltration_rate_for_ventilation_system_off": 0.9,
"infiltration_rate_area_for_ventilation_system_on": 0,
"infiltration_rate_area_for_ventilation_system_off": 0.0005,
"constructions": {
"OutdoorsWall": {
"opaque_surface_name": "G_2015_2019_FACEXT1",
"transparent_surface_name": "G_2015_2019_WIN1",
"transparent_ratio": {
"north": "60",
"east": "60",
"south": "60",
"west": "60"
}
},
"OutdoorsRoofCeiling": {
"opaque_surface_name": "G_2015_2019_ROOF1",
"transparent_surface_name": null,
"transparent_ratio": {
"north": null,
"east": null,
"south": null,
"west": null
}
},
"GroundFloor": {
"opaque_surface_name": "G_2015_2019_FLOORGR1"
}
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -198,7 +198,7 @@
<equipments> <equipments>
<generation_id>3</generation_id> <generation_id>3</generation_id>
<distribution_id>8</distribution_id> <distribution_id>8</distribution_id>
g </equipments> </equipments>
</system> </system>
<system id="5"> <system id="5">
<name>Single zone packaged rooftop unit with electrical resistance furnace and baseboards and fuel boiler for acs</name> <name>Single zone packaged rooftop unit with electrical resistance furnace and baseboards and fuel boiler for acs</name>
@ -240,7 +240,7 @@ g </equipments>
<demand>domestic_hot_water</demand> <demand>domestic_hot_water</demand>
</demands> </demands>
<equipments> <equipments>
<generation_id>2</generation_id> <generation_id>1</generation_id>
<distribution_id>3</distribution_id> <distribution_id>3</distribution_id>
</equipments> </equipments>
</system> </system>
@ -302,7 +302,7 @@ g </equipments>
</demands> </demands>
<equipments> <equipments>
<generation_id>5</generation_id> <generation_id>5</generation_id>
<distribution_id>6</distribution_id> <distribution_id>4</distribution_id>
</equipments> </equipments>
</system> </system>
<system id="15"> <system id="15">

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,809 @@
<?xml version="1.0" encoding="UTF-8"?>
<EnergySystemCatalog>
<schemas_path>./schemas/</schemas_path>
<media>
<medium>
<medium_id>1</medium_id>
<name>Water</name>
<solar_absorptance/>
<thermal_absorptance/>
<visible_absorptance/>
<no_mass/>
<thermal_resistance/>
<density>981.0</density>
<specific_heat>4180.0</specific_heat>
<conductivity>0.6</conductivity>
</medium>
</media>
<energy_generation_components>
<non_pv_generation_component>
<system_id>1</system_id>
<name>Natural-Gas Boiler</name>
<system_type>boiler</system_type>
<model_name/>
<manufacturer/>
<nominal_heat_output/>
<minimum_heat_output/>
<maximum_heat_output/>
<heat_efficiency>0.7</heat_efficiency>
<reversible>False</reversible>
<fuel_type>natural gas</fuel_type>
<source_medium/>
<supply_medium/>
<nominal_cooling_output/>
<minimum_cooling_output/>
<maximum_cooling_output/>
<cooling_efficiency/>
<electricity_efficiency/>
<source_temperature/>
<source_mass_flow/>
<nominal_electricity_output/>
<maximum_heat_supply_temperature/>
<minimum_heat_supply_temperature/>
<maximum_cooling_supply_temperature/>
<minimum_cooling_supply_temperature/>
<heat_output_curve/>
<heat_fuel_consumption_curve/>
<heat_efficiency_curve/>
<cooling_output_curve/>
<cooling_fuel_consumption_curve/>
<cooling_efficiency_curve/>
<distribution_systems/>
<energy_storage_systems/>
<domestic_hot_water>True</domestic_hot_water>
<heat_supply_temperature/>
<cooling_supply_temperature/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</non_pv_generation_component>
<non_pv_generation_component>
<system_id>2</system_id>
<name>Joule</name>
<system_type>joule</system_type>
<model_name/>
<manufacturer/>
<nominal_heat_output/>
<minimum_heat_output/>
<maximum_heat_output/>
<heat_efficiency>1</heat_efficiency>
<reversible>False</reversible>
<fuel_type>electricity</fuel_type>
<source_medium/>
<supply_medium/>
<nominal_cooling_output/>
<minimum_cooling_output/>
<maximum_cooling_output/>
<cooling_efficiency/>
<electricity_efficiency/>
<source_temperature/>
<source_mass_flow/>
<nominal_electricity_output/>
<maximum_heat_supply_temperature/>
<minimum_heat_supply_temperature/>
<maximum_cooling_supply_temperature/>
<minimum_cooling_supply_temperature/>
<heat_output_curve/>
<heat_fuel_consumption_curve/>
<heat_efficiency_curve/>
<cooling_output_curve/>
<cooling_fuel_consumption_curve/>
<cooling_efficiency_curve/>
<distribution_systems/>
<energy_storage_systems/>
<domestic_hot_water>True</domestic_hot_water>
<heat_supply_temperature/>
<cooling_supply_temperature/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</non_pv_generation_component>
<non_pv_generation_component>
<system_id>3</system_id>
<name>Heat Pump</name>
<system_type>heat pump</system_type>
<model_name/>
<manufacturer/>
<nominal_heat_output/>
<minimum_heat_output/>
<maximum_heat_output/>
<heat_efficiency>2</heat_efficiency>
<reversible>True</reversible>
<fuel_type>electricity</fuel_type>
<source_medium>Air</source_medium>
<supply_medium>Water</supply_medium>
<nominal_cooling_output/>
<minimum_cooling_output/>
<maximum_cooling_output/>
<cooling_efficiency>2</cooling_efficiency>
<electricity_efficiency/>
<source_temperature/>
<source_mass_flow/>
<nominal_electricity_output/>
<maximum_heat_supply_temperature/>
<minimum_heat_supply_temperature/>
<maximum_cooling_supply_temperature/>
<minimum_cooling_supply_temperature/>
<heat_output_curve/>
<heat_fuel_consumption_curve/>
<heat_efficiency_curve/>
<cooling_output_curve/>
<cooling_fuel_consumption_curve/>
<cooling_efficiency_curve/>
<distribution_systems/>
<energy_storage_systems/>
<domestic_hot_water>False</domestic_hot_water>
<heat_supply_temperature/>
<cooling_supply_temperature/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</non_pv_generation_component>
<non_pv_generation_component>
<system_id>4</system_id>
<name>Butane Heater</name>
<system_type>butane heater</system_type>
<model_name/>
<manufacturer/>
<nominal_heat_output/>
<minimum_heat_output/>
<maximum_heat_output/>
<heat_efficiency>0.7</heat_efficiency>
<reversible>False</reversible>
<fuel_type>butane</fuel_type>
<source_medium/>
<supply_medium/>
<nominal_cooling_output/>
<minimum_cooling_output/>
<maximum_cooling_output/>
<cooling_efficiency/>
<electricity_efficiency/>
<source_temperature/>
<source_mass_flow/>
<nominal_electricity_output/>
<maximum_heat_supply_temperature/>
<minimum_heat_supply_temperature/>
<maximum_cooling_supply_temperature/>
<minimum_cooling_supply_temperature/>
<heat_output_curve/>
<heat_fuel_consumption_curve/>
<heat_efficiency_curve/>
<cooling_output_curve/>
<cooling_fuel_consumption_curve/>
<cooling_efficiency_curve/>
<distribution_systems/>
<energy_storage_systems/>
<domestic_hot_water>True</domestic_hot_water>
<heat_supply_temperature/>
<cooling_supply_temperature/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</non_pv_generation_component>
<non_pv_generation_component>
<system_id>5</system_id>
<name>Split</name>
<system_type>split</system_type>
<model_name/>
<manufacturer/>
<nominal_heat_output/>
<minimum_heat_output/>
<maximum_heat_output/>
<heat_efficiency/>
<reversible>False</reversible>
<fuel_type>electricity</fuel_type>
<source_medium/>
<supply_medium/>
<nominal_cooling_output/>
<minimum_cooling_output/>
<maximum_cooling_output/>
<cooling_efficiency>2</cooling_efficiency>
<electricity_efficiency/>
<source_temperature/>
<source_mass_flow/>
<nominal_electricity_output/>
<maximum_heat_supply_temperature/>
<minimum_heat_supply_temperature/>
<maximum_cooling_supply_temperature/>
<minimum_cooling_supply_temperature/>
<heat_output_curve/>
<heat_fuel_consumption_curve/>
<heat_efficiency_curve/>
<cooling_output_curve/>
<cooling_fuel_consumption_curve/>
<cooling_efficiency_curve/>
<distribution_systems/>
<energy_storage_systems/>
<domestic_hot_water>False</domestic_hot_water>
<heat_supply_temperature/>
<cooling_supply_temperature/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</non_pv_generation_component>
<non_pv_generation_component>
<system_id>6</system_id>
<name>Domestic Hot Water Heat Pump</name>
<system_type>heat pump</system_type>
<model_name/>
<manufacturer/>
<nominal_heat_output/>
<minimum_heat_output/>
<maximum_heat_output/>
<heat_efficiency>3</heat_efficiency>
<reversible>False</reversible>
<fuel_type>electricity</fuel_type>
<source_medium>Air</source_medium>
<supply_medium>Water</supply_medium>
<nominal_cooling_output/>
<minimum_cooling_output/>
<maximum_cooling_output/>
<cooling_efficiency/>
<electricity_efficiency/>
<source_temperature/>
<source_mass_flow/>
<nominal_electricity_output/>
<maximum_heat_supply_temperature/>
<minimum_heat_supply_temperature/>
<maximum_cooling_supply_temperature/>
<minimum_cooling_supply_temperature/>
<heat_output_curve/>
<heat_fuel_consumption_curve/>
<heat_efficiency_curve/>
<cooling_output_curve/>
<cooling_fuel_consumption_curve/>
<cooling_efficiency_curve/>
<distribution_systems/>
<energy_storage_systems/>
<domestic_hot_water>True</domestic_hot_water>
<heat_supply_temperature/>
<cooling_supply_temperature/>
<simultaneous_heat_cold/>
</non_pv_generation_component>
<pv_generation_component>
<system_id>7</system_id>
<name>template Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name/>
<manufacturer/>
<nominal_electricity_output/>
<electricity_efficiency>0.2</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>45</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>500</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.3</cell_temperature_coefficient>
<width>2.0</width>
<height>1.0</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>8</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>RE400CAA Pure 2</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>305</nominal_electricity_output>
<electricity_efficiency>0.206</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>400</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>1.86</width>
<height>1.04</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>9</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>RE410CAA Pure 2</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>312</nominal_electricity_output>
<electricity_efficiency>0.211</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>410</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>1.86</width>
<height>1.04</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>10</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>RE420CAA Pure 2</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>320</nominal_electricity_output>
<electricity_efficiency>0.217</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>420</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>1.86</width>
<height>1.04</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>11</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>RE430CAA Pure 2</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>327</nominal_electricity_output>
<electricity_efficiency>0.222</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>430</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>1.86</width>
<height>1.04</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>12</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>REC600AA Pro M</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>457</nominal_electricity_output>
<electricity_efficiency>0.211</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>600</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>2.17</width>
<height>1.3</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>13</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>REC610AA Pro M</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>464</nominal_electricity_output>
<electricity_efficiency>0.215</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>610</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>2.17</width>
<height>1.3</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>14</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>REC620AA Pro M</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>472</nominal_electricity_output>
<electricity_efficiency>0.218</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>620</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>2.17</width>
<height>1.3</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>15</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>REC630AA Pro M</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>480</nominal_electricity_output>
<electricity_efficiency>0.222</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>630</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>2.17</width>
<height>1.3</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
<pv_generation_component>
<system_id>16</system_id>
<name>Photovoltaic Module</name>
<system_type>photovoltaic</system_type>
<model_name>REC640AA Pro M</model_name>
<manufacturer>REC</manufacturer>
<nominal_electricity_output>487</nominal_electricity_output>
<electricity_efficiency>0.215</electricity_efficiency>
<nominal_ambient_temperature>20</nominal_ambient_temperature>
<nominal_cell_temperature>44</nominal_cell_temperature>
<nominal_radiation>800</nominal_radiation>
<standard_test_condition_cell_temperature>25</standard_test_condition_cell_temperature>
<standard_test_condition_radiation>1000</standard_test_condition_radiation>
<standard_test_condition_maximum_power>640</standard_test_condition_maximum_power>
<cell_temperature_coefficient>0.24</cell_temperature_coefficient>
<width>2.17</width>
<height>1.3</height>
<distribution_systems/>
<energy_storage_systems/>
<simultaneous_heat_cold>False</simultaneous_heat_cold>
</pv_generation_component>
</energy_generation_components>
<energy_storage_components>
<thermalStorages>
<storage_id>6</storage_id>
<name>template Hot Water Storage Tank</name>
<type_energy_stored>thermal</type_energy_stored>
<model_name/>
<manufacturer/>
<maximum_operating_temperature>95.0</maximum_operating_temperature>
<insulation>
<material_id>1</material_id>
<insulationThickness>90.0</insulationThickness>
</insulation>
<physical_characteristics>
<material_id>2</material_id>
<tankThickness>0</tankThickness>
<height>1.5</height>
<tankMaterial>Steel</tankMaterial>
<volume/>
</physical_characteristics>
<storage_medium>
<medium_id>1</medium_id>
</storage_medium>
<storage_type>sensible</storage_type>
<nominal_capacity/>
<losses_ratio/>
<heating_coil_capacity/>
</thermalStorages>
<thermalStorages>
<storage_id>7</storage_id>
<name>template Hot Water Storage Tank with Heating Coil</name>
<type_energy_stored>thermal</type_energy_stored>
<model_name/>
<manufacturer/>
<maximum_operating_temperature>95.0</maximum_operating_temperature>
<insulation>
<material_id>1</material_id>
<insulationThickness>90.0</insulationThickness>
</insulation>
<physical_characteristics>
<material_id>2</material_id>
<tankThickness>0</tankThickness>
<height>1.5</height>
<tankMaterial>Steel</tankMaterial>
<volume/>
</physical_characteristics>
<storage_medium>
<medium_id>1</medium_id>
</storage_medium>
<storage_type>sensible</storage_type>
<nominal_capacity/>
<losses_ratio/>
<heating_coil_capacity>5000</heating_coil_capacity>
</thermalStorages>
</energy_storage_components>
<materials>
<material>
<material_id>1</material_id>
<name>Polyurethane</name>
<solar_absorptance/>
<thermal_absorptance/>
<visible_absorptance/>
<no_mass/>
<thermal_resistance/>
<density/>
<specific_heat/>
<conductivity>0.028</conductivity>
</material>
<material>
<material_id>2</material_id>
<name>Steel</name>
<solar_absorptance/>
<thermal_absorptance/>
<visible_absorptance/>
<no_mass/>
<thermal_resistance/>
<density/>
<specific_heat/>
<conductivity>18</conductivity>
</material>
</materials>
<distribution_systems>
<distribution_system/>
</distribution_systems>
<dissipation_systems>
<dissipation_system/>
</dissipation_systems>
<systems>
<system>
<id>1</id>
<name>Central gas system</name>
<schema/>
<demands>
<demand>heating</demand>
<demand>domestic_hot_water</demand>
</demands>
<components>
<generation_id>1</generation_id>
</components>
</system>
<system>
<id>2</id>
<name>Central Joule system</name>
<schema/>
<demands>
<demand>heating</demand>
<demand>domestic_hot_water</demand>
</demands>
<components>
<generation_id>2</generation_id>
</components>
</system>
<system>
<id>3</id>
<name>Central butane system</name>
<schema/>
<demands>
<demand>heating</demand>
<demand>domestic_hot_water</demand>
</demands>
<components>
<generation_id>4</generation_id>
</components>
</system>
<system>
<id>4</id>
<name>Single zone split system</name>
<schema/>
<demands>
<demand>cooling</demand>
</demands>
<components>
<generation_id>5</generation_id>
</components>
</system>
<system>
<id>5</id>
<name>4 pipe heat pump system</name>
<schema/>
<demands>
<demand>heating</demand>
<demand>cooling</demand>
</demands>
<components>
<generation_id>3</generation_id>
</components>
</system>
<system>
<id>6</id>
<name>PV</name>
<schema/>
<demands>
<demand>electricity</demand>
</demands>
<components>
<generation_id>7</generation_id>
</components>
</system>
<system>
<id>7</id>
<name>Gas heating</name>
<schema/>
<demands>
<demand>heating</demand>
</demands>
<components>
<generation_id>1</generation_id>
</components>
</system>
<system>
<id>8</id>
<name>Electrical heating</name>
<schema/>
<demands>
<demand>heating</demand>
</demands>
<components>
<generation_id>2</generation_id>
</components>
</system>
<system>
<id>9</id>
<name>Butane heating</name>
<schema/>
<demands>
<demand>heating</demand>
</demands>
<components>
<generation_id>4</generation_id>
</components>
</system>
<system>
<id>10</id>
<name>Gas hot water system</name>
<schema/>
<demands>
<demand>domestic_hot_water</demand>
</demands>
<components>
<generation_id>1</generation_id>
</components>
</system>
<system>
<id>11</id>
<name>Electrical hot water system</name>
<schema/>
<demands>
<demand>domestic_hot_water</demand>
</demands>
<components>
<generation_id>2</generation_id>
</components>
</system>
<system>
<id>12</id>
<name>Butane hot water system</name>
<schema/>
<demands>
<demand>domestic_hot_water</demand>
</demands>
<components>
<generation_id>4</generation_id>
</components>
</system>
<system>
<id>13</id>
<name>Heat Pump hot water system</name>
<schema/>
<demands>
<demand>domestic_hot_water</demand>
</demands>
<components>
<generation_id>6</generation_id>
</components>
</system>
</systems>
<system_archetypes>
<system_archetype id="1">
<name>Gas boiler for heating and hot water heater with split cooling</name>
<systems>
<system_id>1</system_id>
<system_id>4</system_id>
</systems>
</system_archetype>
<system_archetype id="2">
<name>Joule heater for heating and hot water heater with split cooling</name>
<systems>
<system_id>2</system_id>
<system_id>4</system_id>
</systems>
</system_archetype>
<system_archetype id="3">
<name>Butane heater for heating and hot water heater with split cooling</name>
<systems>
<system_id>3</system_id>
<system_id>4</system_id>
</systems>
</system_archetype>
<system_archetype id="4">
<name>Gas heating</name>
<systems>
<system_id>1</system_id>
</systems>
</system_archetype>
<system_archetype id="5">
<name>Electrical joule heating</name>
<systems>
<system_id>2</system_id>
</systems>
</system_archetype>
<system_archetype id="6">
<name>Butane heating</name>
<systems>
<system_id>3</system_id>
</systems>
</system_archetype>
<system_archetype id="7">
<name>Heat pump with gas water heater</name>
<systems>
<system_id>5</system_id>
<system_id>7</system_id>
</systems>
</system_archetype>
<system_archetype id="8">
<name>Heat pump with joule water heater</name>
<systems>
<system_id>5</system_id>
<system_id>8</system_id>
</systems>
</system_archetype>
<system_archetype id="9">
<name>Heat pump with butane water heater</name>
<systems>
<system_id>5</system_id>
<system_id>9</system_id>
</systems>
</system_archetype>
<system_archetype id="10">
<name>Heat pump with gas water heater and rooftop PV</name>
<systems>
<system_id>5</system_id>
<system_id>7</system_id>
<system_id>6</system_id>
</systems>
</system_archetype>
<system_archetype id="11">
<name>Heat pump with joule water heater and rooftop PV</name>
<systems>
<system_id>5</system_id>
<system_id>8</system_id>
<system_id>6</system_id>
</systems>
</system_archetype>
<system_archetype id="12">
<name>Rooftop PV</name>
<systems>
<system_id>6</system_id>
</systems>
</system_archetype>
<system_archetype id="13">
<name>Joule heater with split cooling and gas hot water</name>
<systems>
<system_id>4</system_id>
<system_id>8</system_id>
<system_id>10</system_id>
</systems>
</system_archetype>
<system_archetype id="14">
<name>Joule heater with split cooling and butane hot water</name>
<systems>
<system_id>4</system_id>
<system_id>8</system_id>
<system_id>12</system_id>
</systems>
</system_archetype>
<system_archetype id="15">
<name>PV and heat pump</name>
<systems>
<system_id>5</system_id>
<system_id>6</system_id>
<system_id>13</system_id>
</systems>
</system_archetype>
</system_archetypes>
</EnergySystemCatalog>

View File

@ -0,0 +1,904 @@
{
"tables": {
"schedules": {
"data_type": "table",
"refs": [
"DBHE CTE Tabla b-Anejo D"
],
"table": [
{
"name": "DBHE-CTE-Occupancy-sensible",
"category": "Occupancy",
"units": "FRACTION",
"day_types": "Default|Wkdy",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1,
1,
1,
1,
1,
1,
0.25,
0.25,
0.25,
0.25,
0.25,
0.25,
0.25,
0.25,
0.5,
0.5,
0.5,
0.5,
0.5,
0.5,
0.5,
0.5,
0.5,
1
]
},
{
"name": "DBHE-CTE-Occupancy-sensible",
"category": "Occupancy",
"units": "FRACTION",
"day_types": "Sat",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
]
},
{
"name": "DBHE-CTE-Occupancy-sensible",
"category": "Occupancy",
"units": "FRACTION",
"day_types": "Sun|Hol",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
]
},
{
"name": "DBHE-CTE-Occupancy-latent",
"category": "Occupancy",
"units": "FRACTION",
"day_types": "Default|Wkdy",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1,
1,
1,
1,
1,
1,
0.25,
0.25,
0.25,
0.25,
0.25,
0.25,
0.25,
0.25,
0.5,
0.5,
0.5,
0.5,
0.5,
0.5,
0.5,
0.5,
0.5,
1
]
},
{
"name": "DBHE-CTE-Occupancy-latent",
"category": "Occupancy",
"units": "FRACTION",
"day_types": "Sat",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
]
},
{
"name": "DBHE-CTE-Occupancy-latent",
"category": "Occupancy",
"units": "FRACTION",
"day_types": "Sun|Hol",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
]
},
{
"name": "DBHE-CTE-Lighting",
"category": "Lighting",
"units": "FRACTION",
"day_types": "Default|Wkdy",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.5,
1,
1,
1,
1,
1,
0.5
]
},
{
"name": "DBHE-CTE-Lighting",
"category": "Lighting",
"units": "FRACTION",
"day_types": "Sat",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.5,
1,
1,
1,
1,
1,
0.5
]
},
{
"name": "DBHE-CTE-Lighting",
"category": "Lighting",
"units": "FRACTION",
"day_types": "Sun|Hol",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.5,
1,
1,
1,
1,
1,
0.5
]
},
{
"name": "DBHE-CTE-Equipment",
"category": "Equipment",
"units": "FRACTION",
"day_types": "Default|Wkdy",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.5,
1,
1,
1,
1,
1,
0.5
]
},
{
"name": "DBHE-CTE-Equipment",
"category": "Equipment",
"units": "FRACTION",
"day_types": "Sat",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.5,
1,
1,
1,
1,
1,
0.5
]
},
{
"name": "DBHE-CTE-Equipment",
"category": "Equipment",
"units": "FRACTION",
"day_types": "Sun|Hol",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.5,
1,
1,
1,
1,
1,
0.5
]
},
{
"name": "DBHE-CTE-Thermostat Setpoint-Heating",
"category": "Thermostat Setpoint",
"units": "TEMPERATURE",
"day_types": "Default|Wkdy",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
17.0,
17.0,
17.0,
17.0,
17.0,
17.0,
17.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
21.0,
20.0,
17.0,
17.0
]
},
{
"name": "DBHE-CTE-Thermostat Setpoint-Heating",
"category": "Thermostat Setpoint",
"units": "TEMPERATURE",
"day_types": "Sat",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
22.0,
18.0,
18.0,
18.0,
18.0,
18.0,
18.0,
20.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0
]
},
{
"name": "DBHE-CTE-Thermostat Setpoint-Heating",
"category": "Thermostat Setpoint",
"units": "TEMPERATURE",
"day_types": "Sun|Hol",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
22.0,
18.0,
18.0,
18.0,
18.0,
18.0,
18.0,
20.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0,
22.0
]
},
{
"name": "DBHE-CTE-Thermostat Setpoint-Cooling",
"category": "Thermostat Setpoint",
"units": "TEMPERATURE",
"day_types": "Default|Wkdy",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
28.0,
28.0,
28.0,
28.0,
28.0,
28.0,
28.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
28.0,
28.0
]
},
{
"name": "DBHE-CTE-Thermostat Setpoint-Cooling",
"category": "Thermostat Setpoint",
"units": "TEMPERATURE",
"day_types": "Sat",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
28.0,
28.0,
28.0,
28.0,
28.0,
28.0,
28.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
28.0,
28.0
]
},
{
"name": "DBHE-CTE-Thermostat Setpoint-Cooling",
"category": "Thermostat Setpoint",
"units": "TEMPERATURE",
"day_types": "Sun|Hol",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
28.0,
28.0,
28.0,
28.0,
28.0,
28.0,
28.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
25.0,
28.0,
28.0
]
},
{
"name": "Always On",
"category": "Unknown",
"units": null,
"day_types": "Default",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Constant",
"notes": null,
"values": [
1.0
]
},
{
"name": "default_HVAC_schedule",
"category": "Fan",
"units": "ON_OFF",
"day_types": "Default|Wkdy",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
]
},
{
"name": "default_HVAC_schedule",
"category": "Fan",
"units": "ON_OFF",
"day_types": "Sat",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
]
},
{
"name": "default_HVAC_schedule",
"category": "Fan",
"units": "ON_OFF",
"day_types": "Sun|Hol",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
]
},
{
"name": "DBHE-CTE-Service Water Heating",
"category": "Service Water Heating",
"units": "FRACTION",
"day_types": "Default|Wkdy",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.01,
0.00,
0.00,
0.00,
0.00,
0.01,
0.03,
0.1,
0.07,
0.07,
0.06,
0.06,
0.05,
0.05,
0.04,
0.03,
0.04,
0.04,
0.05,
0.07,
0.06,
0.06,
0.05,
0.05
]
},
{
"name": "DBHE-CTE-Service Water Heating",
"category": "Service Water Heating",
"units": "FRACTION",
"day_types": "Sat",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.01,
0.00,
0.00,
0.00,
0.00,
0.01,
0.03,
0.1,
0.07,
0.07,
0.06,
0.06,
0.05,
0.05,
0.04,
0.03,
0.04,
0.04,
0.05,
0.07,
0.06,
0.06,
0.05,
0.05
]
},
{
"name": "DBHE-CTE-Service Water Heating",
"category": "Service Water Heating",
"units": "FRACTION",
"day_types": "Sun|Hol",
"start_date": "2014-01-01T00:00:00+00:00",
"end_date": "2014-12-31T00:00:00+00:00",
"type": "Hourly",
"notes": null,
"values": [
0.01,
0.00,
0.00,
0.00,
0.00,
0.01,
0.03,
0.1,
0.07,
0.07,
0.06,
0.06,
0.05,
0.05,
0.04,
0.03,
0.04,
0.04,
0.05,
0.07,
0.06,
0.06,
0.05,
0.05
]
}
]
}}}

View File

@ -0,0 +1,30 @@
{
"tables": {
"space_compliance": {
"data_type": "table",
"refs": {
"lighting_per_area_w_per_m2": "DBHE-CTE Tabla b-Anejo D",
"occupancy_per_area_people_per_m2": "DBHE CTE Tabla b-Anejo D",
"occupancy_schedule": "DBHE-CTE Tabla b-Anejo D",
"electric_equipment_per_area_w_per_m2": "DBHE CTE Tabla b-Anejo D"
},
"tolerance": {
"lighting_per_area_w_per_m2": 1,
"occupancy_per_area_people_per_m2": 3,
"occupancy_schedule": null,
"electric_equipment_per_area_w_per_m2": 1
},
"table": [
{
"template": "DBHE-CTE",
"building_type": "residential",
"space_type": "WholeBuilding",
"lighting_per_area_w_per_m2": 4.4,
"occupancy_per_area_people_per_m2": 0.014333333,
"occupancy_schedule": "DBHE-CTE-Occupancy",
"electric_equipment_per_area_w_per_m2": 4.4,
"service_water_heating_peak_flow_per_area": 0.02272990107962068
}]
}
}
}

View File

@ -0,0 +1,97 @@
{
"tables": {
"space_types": {
"data_type": "table",
"refs": [
"assumption"
],
"table": [
{
"building_type": "residential",
"space_type": "WholeBuilding",
"rgb": "255_255_255",
"lighting_standard": "DBHE-CTE",
"lighting_primary_space_type": "residential",
"lighting_secondary_space_type": "WholeBuilding",
"lighting_per_area": 4.4,
"lighting_per_person": null,
"additional_lighting_per_area": null,
"rel_absence_occ": 0.0,
"personal_control": 0.0,
"occ_sense": 0.0,
"lighting_fraction_to_return_air": 0.0,
"lighting_fraction_radiant": 0.5,
"lighting_fraction_visible": 0.2,
"lighting_fraction_replaceable": null,
"lpd_fractionlinear_fluorescent": 1.0,
"lpd_fractioncompact_fluorescent": null,
"lpd_fractionhigh_bay": null,
"lpd_fractionspecialty_lighting": null,
"lpd_fractionexit_lighting": null,
"lighting_schedule": "DBHE-CTE-Lighting",
"compact_fluorescent_lighting_schedule": null,
"high_bay_lighting_schedule": null,
"specialty_lighting_schedule": null,
"exit_lighting_schedule": null,
"target_illuminance_setpoint": 125,
"target_illuminance_setpoint_ref": null,
"psa_nongeometry_fraction": null,
"ssa_nongeometry_fraction": null,
"ventilation_standard": null,
"ventilation_primary_space_type": "residential",
"ventilation_secondary_space_type": "WholeBuilding",
"ventilation_per_area": 0,
"ventilation_per_person": 0,
"ventilation_air_changes": 0.4,
"minimum_total_air_changes": null,
"occupancy_per_area": 2.15,
"occupancy_schedule": "DBHE-CTE-Occupancy-sensible",
"occupancy_activity_schedule": null,
"infiltration_per_exterior_area": 0.4,
"infiltration_per_exterior_wall_area": null,
"infiltration_air_changes": null,
"infiltration_schedule": "Always On",
"infiltration_schedule_perimeter": null,
"gas_equipment_per_area": null,
"gas_equipment_fraction_latent": null,
"gas_equipment_fraction_radiant": null,
"gas_equipment_fraction_lost": null,
"gas_equipment_schedule": null,
"electric_equipment_per_area": 4.4,
"electric_equipment_fraction_latent": 0.0,
"electric_equipment_fraction_radiant": 0.5,
"electric_equipment_fraction_lost": 0.0,
"electric_equipment_schedule": "DBHE-CTE-Equipment",
"additional_electric_equipment_schedule": null,
"additional_gas_equipment_schedule": null,
"heating_setpoint_schedule": "DBHE-CTE-Thermostat Setpoint-Heating",
"cooling_setpoint_schedule": "DBHE-CTE-Thermostat Setpoint-Cooling",
"service_water_heating_peak_flow_rate": null,
"service_water_heating_area": null,
"service_water_heating_peak_flow_per_area": 0.009385225,
"service_water_heating_target_temperature": 60.0,
"service_water_heating_fraction_sensible": null,
"service_water_heating_fraction_latent": null,
"service_water_heating_schedule": "DBHE-CTE-Service Water Heating",
"exhaust_per_area": null,
"exhaust_fan_efficiency": null,
"exhaust_fan_power": null,
"exhaust_fan_pressure_rise": null,
"exhaust_fan_maximum_flow_rate": null,
"exhaust_schedule": null,
"balanced_exhaust_fraction_schedule": null,
"is_residential": null,
"necb_hvac_system_selection_type": "residential",
"necb_schedule_type": "G",
"notes": null,
"ventilation_occupancy_rate_people_per_1000ft2": 10,
"ventilation_occupancy_standard": null,
"ventilation_standard_space_type": null,
"sensible_convective_internal_gain": 0.86,
"sensible_radiative_internal_gain": 1.29,
"latent_internal_gain": 1.36
}
]
}
}
}

View File

@ -0,0 +1,248 @@
"""
Cerc Idf exports one city or some buildings to idf format
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Guillermo.GutierrezMorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Oriol Gavalda Torrellas oriol.gavalda@concordia.ca
"""
import copy
import os
import shutil
import subprocess
import hub.exports.building_energy.idf_helper as idf_cte
import hub.helpers.constants as cte
from hub.city_model_structure.attributes.schedule import Schedule
from hub.exports.building_energy.idf_helper.idf_appliance import IdfAppliance
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
from hub.exports.building_energy.idf_helper.idf_construction import IdfConstruction
from hub.exports.building_energy.idf_helper.idf_dhw import IdfDhw
from hub.exports.building_energy.idf_helper.idf_file_schedule import IdfFileSchedule
from hub.exports.building_energy.idf_helper.idf_heating_system import IdfHeatingSystem
from hub.exports.building_energy.idf_helper.idf_infiltration import IdfInfiltration
from hub.exports.building_energy.idf_helper.idf_lighting import IdfLighting
from hub.exports.building_energy.idf_helper.idf_material import IdfMaterial
from hub.exports.building_energy.idf_helper.idf_occupancy import IdfOccupancy
from hub.exports.building_energy.idf_helper.idf_schedule import IdfSchedule
from hub.exports.building_energy.idf_helper.idf_shading import IdfShading
from hub.exports.building_energy.idf_helper.idf_surfaces import IdfSurfaces
from hub.exports.building_energy.idf_helper.idf_thermostat import IdfThermostat
from hub.exports.building_energy.idf_helper.idf_ventilation import IdfVentilation
from hub.exports.building_energy.idf_helper.idf_window import IdfWindow
from hub.exports.building_energy.idf_helper.idf_windows_constructions import IdfWindowsConstructions
from hub.exports.building_energy.idf_helper.idf_windows_material import IdfWindowsMaterial
from hub.exports.building_energy.idf_helper.idf_zone import IdfZone
class CercIdf(IdfBase):
"""
Exports city to IDF
"""
_schedules_added_to_idf = {}
_materials_added_to_idf = {}
_windows_added_to_idf = {}
_constructions_added_to_idf = {}
_thermostat_added_to_idf = {}
def __init__(self, city, output_path, idf_file_path, idd_file_path, epw_file_path, target_buildings=None):
super().__init__(city, output_path, idf_file_path, idd_file_path, epw_file_path, target_buildings)
self._add_surfaces = IdfSurfaces.add
self._add_file_schedule = IdfFileSchedule.add
self._add_idf_schedule = IdfSchedule.add
self._add_construction = IdfConstruction.add
self._add_material = IdfMaterial.add
self._add_windows_material = IdfWindowsMaterial.add
self._add_windows_constructions = IdfWindowsConstructions.add
self._add_occupancy = IdfOccupancy.add
self._add_lighting = IdfLighting.add
self._add_appliance = IdfAppliance.add
self._add_infiltration = IdfInfiltration.add
self._add_infiltration_surface = IdfInfiltration.add_surface
self._add_ventilation = IdfVentilation.add
self._add_zone = IdfZone.add
self._add_thermostat = IdfThermostat.add
self._add_heating_system = IdfHeatingSystem.add
self._add_dhw = IdfDhw.add
self._add_shading = IdfShading.add
self._add_windows = IdfWindow.add
with open(self._idf_file_path, 'r', encoding='UTF-8') as base_idf:
lines = base_idf.readlines()
# Change city name
comment = f' !- Name'
field = f' Buildings in {self._city.name},'.ljust(26, ' ')
lines[15] = f'{field}{comment}\n'
with open(self._output_file_path, 'w', encoding='UTF-8') as self._idf_file:
self._idf_file.writelines(lines)
self._export()
def _create_geometry_rules(self):
file = self._files['constructions']
self._write_to_idf_format(file, idf_cte.GLOBAL_GEOMETRY_RULES)
self._write_to_idf_format(file, 'UpperLeftCorner', 'Starting Vertex Position')
self._write_to_idf_format(file, 'CounterClockWise', 'Vertex Entry Direction')
self._write_to_idf_format(file, 'World', 'Coordinate System', ';')
def _merge_files(self):
for file in self._files.values():
file.close()
for path in self._file_paths.values():
with open(path, 'r', encoding='UTF-8') as file:
lines = file.readlines()
self._idf_file.writelines(lines)
for path in self._file_paths.values():
os.unlink(path)
def _add_outputs(self):
with open(self._outputs_file_path, 'r', encoding='UTF-8') as base_idf:
lines = base_idf.readlines()
self._idf_file.writelines(lines)
@staticmethod
def _create_infiltration_schedules(thermal_zone):
_infiltration_schedules = []
if thermal_zone.thermal_control is None:
return []
for hvac_availability_schedule in thermal_zone.thermal_control.hvac_availability_schedules:
_schedule = Schedule()
_schedule.type = cte.INFILTRATION
_schedule.data_type = cte.FRACTION
_schedule.time_step = cte.HOUR
_schedule.time_range = cte.DAY
_schedule.day_types = copy.deepcopy(hvac_availability_schedule.day_types)
_infiltration_values = []
for hvac_value in hvac_availability_schedule.values:
if hvac_value == 0:
_infiltration_values.append(1.0)
else:
if thermal_zone.infiltration_rate_system_off == 0:
_infiltration_values.append(0.0)
else:
_infiltration_values.append(
thermal_zone.infiltration_rate_system_on / thermal_zone.infiltration_rate_system_off)
_schedule.values = _infiltration_values
_infiltration_schedules.append(_schedule)
return _infiltration_schedules
@staticmethod
def _create_ventilation_schedules(thermal_zone):
_ventilation_schedules = []
if thermal_zone.thermal_control is None:
return []
for hvac_availability_schedule in thermal_zone.thermal_control.hvac_availability_schedules:
_schedule = Schedule()
_schedule.type = cte.VENTILATION
_schedule.data_type = cte.FRACTION
_schedule.time_step = cte.HOUR
_schedule.time_range = cte.DAY
_schedule.day_types = copy.deepcopy(hvac_availability_schedule.day_types)
_ventilation_schedules = thermal_zone.thermal_control.hvac_availability_schedules
return _ventilation_schedules
@staticmethod
def _create_constant_value_schedules(value, amount):
_schedule = Schedule()
_schedule.type = ''
_schedule.data_type = cte.ANY_NUMBER
_schedule.time_step = cte.HOUR
_schedule.time_range = cte.DAY
_schedule.day_types = ['monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday',
'holiday',
'winter_design_day',
'summer_design_day']
_schedule.values = [value for _ in range(0, amount)]
return [_schedule]
def _export(self):
for building in self._city.buildings:
is_target = building.name in self._target_buildings or building.name in self._adjacent_buildings
for internal_zone in building.internal_zones:
if internal_zone.thermal_zones_from_internal_zones is None:
is_target = False
continue
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
if is_target:
service_temperature = thermal_zone.domestic_hot_water.service_temperature
usage = thermal_zone.usage_name
occ = thermal_zone.occupancy
if occ.occupancy_density == 0:
total_heat = 0
else:
total_heat = (
occ.sensible_convective_internal_gain +
occ.sensible_radiative_internal_gain +
occ.latent_internal_gain
) / occ.occupancy_density
self._add_idf_schedule(self, usage, 'Infiltration', self._create_infiltration_schedules(thermal_zone))
self._add_idf_schedule(self, usage, 'Ventilation', self._create_ventilation_schedules(thermal_zone))
self._add_idf_schedule(self, usage, 'Occupancy', thermal_zone.occupancy.occupancy_schedules)
self._add_idf_schedule(self, usage, 'HVAC AVAIL', thermal_zone.thermal_control.hvac_availability_schedules)
self._add_idf_schedule(self, usage, 'Heating thermostat',
thermal_zone.thermal_control.heating_set_point_schedules)
self._add_idf_schedule(self, usage, 'Cooling thermostat',
thermal_zone.thermal_control.cooling_set_point_schedules)
self._add_idf_schedule(self, usage, 'Lighting', thermal_zone.lighting.schedules)
self._add_idf_schedule(self, usage, 'Appliance', thermal_zone.appliances.schedules)
self._add_idf_schedule(self, usage, 'DHW_prof', thermal_zone.domestic_hot_water.schedules)
self._add_idf_schedule(self, usage, 'DHW_temp',
self._create_constant_value_schedules(service_temperature, 24))
self._add_idf_schedule(self, usage, 'Activity Level', self._create_constant_value_schedules(total_heat, 24))
self._add_file_schedule(self, usage, 'cold_temp',
self._create_constant_value_schedules(building.cold_water_temperature[cte.HOUR],
24))
for thermal_boundary in thermal_zone.thermal_boundaries:
self._add_material(self, thermal_boundary)
self._add_construction(self, thermal_boundary)
for thermal_opening in thermal_boundary.thermal_openings:
self._add_windows_material(self, thermal_boundary, thermal_opening)
self._add_windows_constructions(self, thermal_boundary)
self._add_zone(self, thermal_zone, building.name)
self._add_occupancy(self, thermal_zone, building.name)
self._add_lighting(self, thermal_zone, building.name)
self._add_appliance(self, thermal_zone, building.name)
if self._calculate_with_new_infiltration: # ToDo: Check with oriol if we want to keep the old method too
self._add_infiltration_surface(self, thermal_zone, building.name)
else:
self._add_infiltration(self, thermal_zone, building.name)
self._add_ventilation(self, thermal_zone, building.name)
self._add_thermostat(self, thermal_zone)
self._add_heating_system(self, thermal_zone, building.name)
self._add_dhw(self, thermal_zone, building.name)
if is_target:
self._add_surfaces(self, building, building.name)
self._add_windows(self, building)
else:
self._add_shading(self, building)
self._create_output_control_lighting() # Add lighting control to the lighting
# Create base values
self._create_geometry_rules()
# Merge files
self._merge_files()
self._add_outputs()
@property
def _energy_plus(self):
return shutil.which('energyplus')
def run(self):
cmd = [self._energy_plus,
'--weather', self._epw_file_path,
'--output-directory', self._output_path,
'--idd', self._idd_file_path,
'--expandobjects',
'--readvars',
'--output-prefix', f'{self._city.name}_',
self._output_file_path]
subprocess.run(cmd, cwd=self._output_path)

View File

@ -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'] = building.usages_percentage building_dic['bldg:Building']['bldg:usage'] = 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'] = {

View File

@ -8,10 +8,12 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
""" """
import copy import copy
import datetime import datetime
import glob import shutil
import os import subprocess
from pathlib import Path from pathlib import Path
from geomeppy import IDF from geomeppy import IDF
import hub.helpers.constants as cte import hub.helpers.constants as cte
from hub.city_model_structure.attributes.schedule import Schedule from hub.city_model_structure.attributes.schedule import Schedule
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
@ -107,6 +109,7 @@ class Idf:
else: else:
for building_name in target_buildings: for building_name in target_buildings:
building = city.city_object(building_name) building = city.city_object(building_name)
print('Name: ', building_name)
if building.neighbours is not None: if building.neighbours is not None:
self._adjacent_buildings += building.neighbours self._adjacent_buildings += building.neighbours
self._export() self._export()
@ -444,7 +447,7 @@ class Idf:
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#InteriorEquipment' subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#InteriorEquipment'
self._idf.newidfobject(self._APPLIANCES, self._idf.newidfobject(self._APPLIANCES,
Fuel_Type=fuel_type, Fuel_Type=fuel_type,
Name=f'{zone_name}_appliance', Name=zone_name,
Zone_or_ZoneList_or_Space_or_SpaceList_Name=zone_name, Zone_or_ZoneList_or_Space_or_SpaceList_Name=zone_name,
Schedule_Name=f'Appliance schedules {thermal_zone.usage_name}', Schedule_Name=f'Appliance schedules {thermal_zone.usage_name}',
Design_Level_Calculation_Method=method, Design_Level_Calculation_Method=method,
@ -467,7 +470,7 @@ class Idf:
def _add_infiltration_surface(self, thermal_zone, zone_name): def _add_infiltration_surface(self, thermal_zone, zone_name):
schedule = f'INF_CONST schedules {thermal_zone.usage_name}' schedule = f'INF_CONST schedules {thermal_zone.usage_name}'
_infiltration = thermal_zone.infiltration_rate_area_system_off*1 _infiltration = thermal_zone.infiltration_rate_area_system_off* cte.INFILTRATION_75PA_TO_4PA
self._idf.newidfobject(self._INFILTRATION, self._idf.newidfobject(self._INFILTRATION,
Name=f'{zone_name}_infiltration', Name=f'{zone_name}_infiltration',
Zone_or_ZoneList_or_Space_or_SpaceList_Name=zone_name, Zone_or_ZoneList_or_Space_or_SpaceList_Name=zone_name,
@ -501,7 +504,7 @@ class Idf:
) )
def _rename_building(self, city_name): def _rename_building(self, city_name):
name = str(str(city_name.encode("utf-8"))) name = str(city_name.encode("utf-8"))
for building in self._idf.idfobjects[self._BUILDING]: for building in self._idf.idfobjects[self._BUILDING]:
building.Name = f'Buildings in {name}' building.Name = f'Buildings in {name}'
building['Solar_Distribution'] = 'FullExterior' building['Solar_Distribution'] = 'FullExterior'
@ -528,11 +531,12 @@ class Idf:
self._remove_sizing_periods() self._remove_sizing_periods()
self._rename_building(self._city.name) self._rename_building(self._city.name)
self._lod = self._city.level_of_detail.geometry self._lod = self._city.level_of_detail.geometry
is_target = False
for building in self._city.buildings: for building in self._city.buildings:
is_target = building.name in self._target_buildings or building.name in self._adjacent_buildings is_target = building.name in self._target_buildings or building.name in self._adjacent_buildings
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
if internal_zone.thermal_zones_from_internal_zones is None: if internal_zone.thermal_zones_from_internal_zones is None:
self._target_buildings.remoidf_surface_typeve(building.name) self._target_buildings.remove(building.name)
is_target = False is_target = False
continue continue
for thermal_zone in internal_zone.thermal_zones_from_internal_zones: for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
@ -586,9 +590,7 @@ class Idf:
if self._export_type == "Surfaces": if self._export_type == "Surfaces":
if is_target: if is_target:
if building.thermal_zones_from_internal_zones is not None: if building.thermal_zones_from_internal_zones is not None:
start = datetime.datetime.now()
self._add_surfaces(building, building.name) self._add_surfaces(building, building.name)
print(f'add surfaces {datetime.datetime.now() - start}')
else: else:
self._add_pure_geometry(building, building.name) self._add_pure_geometry(building, building.name)
else: else:
@ -651,14 +653,26 @@ class Idf:
self._idf.removeidfobject(window) self._idf.removeidfobject(window)
self._idf.saveas(str(self._output_file)) self._idf.saveas(str(self._output_file))
for building in self._city.buildings:
if self._export_type == "Surfaces":
if is_target and building.thermal_zones_from_internal_zones is not None:
self._add_surfaces(building, building.name)
return self._idf return self._idf
@property
def _energy_plus(self):
return shutil.which('energyplus')
def run(self): def run(self):
""" cmd = [self._energy_plus,
Start the energy plus simulation '--weather', self._epw_file_path,
""" '--output-directory', self._output_path,
self._idf.run(expandobjects=False, readvars=True, output_directory=self._output_path, '--idd', self._idd_file_path,
output_prefix=f'{self._city.name}_') '--expandobjects',
'--readvars',
'--output-prefix', f'{self._city.name}_',
self._idf_file_path]
subprocess.run(cmd, cwd=self._output_path)
def _add_block(self, building): def _add_block(self, building):
_points = self._matrix_to_2d_list(building.foot_print.coordinates) _points = self._matrix_to_2d_list(building.foot_print.coordinates)
@ -727,7 +741,10 @@ class Idf:
else: else:
# idf only allows setting wwr for external walls # idf only allows setting wwr for external walls
wwr = 0 wwr = 0
self._idf.set_wwr(wwr) try:
self._idf.set_wwr(wwr, construction='window_construction_1')
except ValueError:
self._idf.set_wwr(0, construction='window_construction_1')
def _add_surfaces(self, building, zone_name): def _add_surfaces(self, building, zone_name):
for thermal_zone in building.thermal_zones_from_internal_zones: for thermal_zone in building.thermal_zones_from_internal_zones:
@ -758,13 +775,11 @@ class Idf:
else: else:
construction_name = f'{boundary.construction_name} {boundary.parent_surface.type}' construction_name = f'{boundary.construction_name} {boundary.parent_surface.type}'
_kwargs['Construction_Name'] = construction_name _kwargs['Construction_Name'] = construction_name
start = datetime.datetime.now()
surface = self._idf.newidfobject(self._SURFACE, **_kwargs) surface = self._idf.newidfobject(self._SURFACE, **_kwargs)
coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates, coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates,
self._city.lower_corner) self._city.lower_corner)
surface.setcoords(coordinates) surface.setcoords(coordinates)
if self._lod >= 3: if self._lod >= 3:
for internal_zone in building.internal_zones: for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones: for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
@ -776,7 +791,10 @@ class Idf:
for surface in building.surfaces: for surface in building.surfaces:
if surface.type == cte.WALL: if surface.type == cte.WALL:
wwr = surface.associated_thermal_boundaries[0].window_ratio wwr = surface.associated_thermal_boundaries[0].window_ratio
self._idf.set_wwr(wwr, construction='window_construction_1') try:
self._idf.set_wwr(wwr, construction='window_construction_1')
except ValueError:
self._idf.set_wwr(0, construction='window_construction_1')
def _add_windows_by_vertices(self, boundary): def _add_windows_by_vertices(self, boundary):
raise NotImplementedError raise NotImplementedError

View File

@ -0,0 +1,62 @@
!- Linux Line endings
Version,
24.1; !- Version Identifier
SimulationControl,
No, !- Do Zone Sizing Calculation
No, !- Do System Sizing Calculation
No, !- Do Plant Sizing Calculation
No, !- Run Simulation for Sizing Periods
Yes, !- Run Simulation for Weather File Run Periods
No, !- Do HVAC Sizing Simulation for Sizing Periods
1; !- Maximum Number of HVAC Sizing Simulation Passes
Building,
Buildings in #CITY#, !- Name
0, !- North Axis
Suburbs, !- Terrain
0.04, !- Loads Convergence Tolerance Value
0.4, !- Temperature Convergence Tolerance Value
FullExterior, !- Solar Distribution
25, !- Maximum Number of Warmup Days
6; !- Minimum Number of Warmup Days
Timestep,
4; !- Number of Timesteps per Hour
RunPeriod,
Run Period 1, !- Name
1, !- Begin Month
1, !- Begin Day of Month
, !- Begin Year
12, !- End Month
31, !- End Day of Month
, !- End Year
Tuesday, !- Day of Week for Start Day
Yes, !- Use Weather File Holidays and Special Days
Yes, !- Use Weather File Daylight Saving Period
No, !- Apply Weekend Holiday Rule
Yes, !- Use Weather File Rain Indicators
Yes; !- Use Weather File Snow Indicators
SCHEDULETYPELIMITS,
Any Number, !- Name
, !- Lower Limit Value
, !- Upper Limit Value
, !- Numeric Type
Dimensionless; !- Unit Type
SCHEDULETYPELIMITS,
Fraction, !- Name
0, !- Lower Limit Value
1, !- Upper Limit Value
Continuous, !- Numeric Type
Dimensionless; !- Unit Type
SCHEDULETYPELIMITS,
On/Off, !- Name
0, !- Lower Limit Value
1, !- Upper Limit Value
Discrete, !- Numeric Type
Dimensionless; !- Unit Type

View File

@ -0,0 +1,74 @@
Output:Table:SummaryReports,
AnnualBuildingUtilityPerformanceSummary, !- Report 1 Name
DemandEndUseComponentsSummary, !- Report 2 Name
SensibleHeatGainSummary, !- Report 3 Name
InputVerificationandResultsSummary, !- Report 4 Name
AdaptiveComfortSummary, !- Report 5 Name
Standard62.1Summary, !- Report 6 Name
ClimaticDataSummary, !- Report 7 Name
EquipmentSummary, !- Report 8 Name
EnvelopeSummary, !- Report 9 Name
LightingSummary, !- Report 10 Name
HVACSizingSummary, !- Report 11 Name
SystemSummary, !- Report 12 Name
ComponentSizingSummary, !- Report 13 Name
OutdoorAirSummary, !- Report 14 Name
ObjectCountSummary, !- Report 15 Name
EndUseEnergyConsumptionOtherFuelsMonthly, !- Report 16 Name
PeakEnergyEndUseOtherFuelsMonthly; !- Report 17 Name
OutputControl:Table:Style,
CommaAndHTML, !- Column Separator
JtoKWH; !- Unit Conversion
OUTPUT:VARIABLE,
*, !- Key Value
Zone Ideal Loads Supply Air Total Heating Energy, !- Variable Name
Hourly; !- Reporting Frequency
OUTPUT:VARIABLE,
*, !- Key Value
Zone Ideal Loads Supply Air Total Cooling Energy, !- Variable Name
Hourly; !- Reporting Frequency
OUTPUT:VARIABLE,
*, !- Key Value
Water Use Equipment Heating Rate, !- Variable Name
Hourly; !- Reporting Frequency
OUTPUT:VARIABLE,
*, !- Key Value
Zone Lights Electricity Rate, !- Variable Name
Hourly; !- Reporting Frequency
OUTPUT:VARIABLE,
*, !- Key Value
Other Equipment Electricity Rate, !- Variable Name
Hourly; !- Reporting Frequency
OUTPUT:VARIABLE,
*, !- Key Value
Zone Air Temperature, !- Variable Name
Hourly; !- Reporting Frequency
OUTPUT:VARIABLE,
*, !- Key Value
Zone Air Relative Humidity, !- Variable Name
Hourly; !- Reporting Frequency
Output:Meter,
DISTRICTHEATING:Facility, !- Key Name
hourly; !- Reporting Frequency
Output:Meter,
DISTRICTCOOLING:Facility, !- Key Name
hourly; !- Reporting Frequency
Output:Meter,
InteriorEquipment:Electricity, !- Key Name
hourly; !- Reporting Frequency
Output:Meter,
InteriorLights:Electricity, !- Key Name
hourly; !- Reporting Frequency

View File

@ -0,0 +1,60 @@
import hub.helpers.constants as cte
BUILDING_SURFACE = '\nBUILDINGSURFACE:DETAILED,\n'
WINDOW_SURFACE = '\nFENESTRATIONSURFACE:DETAILED,\n'
COMPACT_SCHEDULE = '\nSCHEDULE:COMPACT,\n'
FILE_SCHEDULE = '\nSCHEDULE:FILE,\n'
NOMASS_MATERIAL = '\nMATERIAL:NOMASS,\n'
SOLID_MATERIAL = '\nMATERIAL,\n'
WINDOW_MATERIAL = '\nWINDOWMATERIAL:SIMPLEGLAZINGSYSTEM,\n'
CONSTRUCTION = '\nCONSTRUCTION,\n'
ZONE = '\nZONE,\n'
GLOBAL_GEOMETRY_RULES = '\nGlobalGeometryRules,\n'
PEOPLE = '\nPEOPLE,\n'
LIGHTS = '\nLIGHTS,\n'
APPLIANCES = '\nOTHEREQUIPMENT,\n'
OUTPUT_CONTROL = '\nOutputControl:IlluminanceMap:Style,\n'
INFILTRATION = '\nZONEINFILTRATION:DESIGNFLOWRATE,\n'
VENTILATION = '\nZONEVENTILATION:DESIGNFLOWRATE,\n'
THERMOSTAT = '\nHVACTEMPLATE:THERMOSTAT,\n'
IDEAL_LOAD_SYSTEM = '\nHVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM,\n'
DHW = '\nWATERUSE:EQUIPMENT,\n'
SHADING = '\nSHADING:BUILDING:DETAILED,\n'
AUTOCALCULATE = 'autocalculate'
ROUGHNESS = 'MediumRough'
OUTDOORS = 'Outdoors'
GROUND = 'Ground'
SURFACE = 'Surface'
SUN_EXPOSED = 'SunExposed'
WIND_EXPOSED = 'WindExposed'
NON_SUN_EXPOSED = 'NoSun'
NON_WIND_EXPOSED = 'NoWind'
EMPTY = ''
idf_surfaces_dictionary = {
cte.WALL: 'wall',
cte.GROUND: 'floor',
cte.ROOF: 'roof'
}
idf_type_limits = {
cte.ON_OFF: 'on/off',
cte.FRACTION: 'Fraction',
cte.ANY_NUMBER: 'Any Number',
cte.CONTINUOUS: 'Continuous',
cte.DISCRETE: 'Discrete'
}
idf_day_types = {
cte.MONDAY: 'Monday',
cte.TUESDAY: 'Tuesday',
cte.WEDNESDAY: 'Wednesday',
cte.THURSDAY: 'Thursday',
cte.FRIDAY: 'Friday',
cte.SATURDAY: 'Saturday',
cte.SUNDAY: 'Sunday',
cte.HOLIDAY: 'Holidays',
cte.WINTER_DESIGN_DAY: 'WinterDesignDay',
cte.SUMMER_DESIGN_DAY: 'SummerDesignDay'
}

View File

@ -0,0 +1,26 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfAppliance(IdfBase):
@staticmethod
def add(self, thermal_zone, zone_name):
schedule_name = f'Appliance schedules {thermal_zone.usage_name}'
storeys_number = int(thermal_zone.total_floor_area / thermal_zone.footprint_area)
watts_per_zone_floor_area = thermal_zone.appliances.density * storeys_number
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#InteriorEquipment'
file = self._files['appliances']
self._write_to_idf_format(file, idf_cte.APPLIANCES)
self._write_to_idf_format(file, zone_name, 'Name')
self._write_to_idf_format(file, 'Electricity', 'Fuel Type')
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
self._write_to_idf_format(file, schedule_name, 'Schedule Name')
self._write_to_idf_format(file, 'Watts/Area', 'Design Level Calculation Method')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Design Level')
self._write_to_idf_format(file, watts_per_zone_floor_area, 'Power per Zone Floor Area')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Power per Person')
self._write_to_idf_format(file, thermal_zone.appliances.latent_fraction, 'Fraction Latent')
self._write_to_idf_format(file, thermal_zone.appliances.radiative_fraction, 'Fraction Radiant')
self._write_to_idf_format(file, 0, 'Fraction Lost')
self._write_to_idf_format(file, 0, 'Carbon Dioxide Generation Rate')
self._write_to_idf_format(file, subcategory, 'EndUse Subcategory', ';')

View File

@ -0,0 +1,78 @@
import os
from pathlib import Path
import hub.exports.building_energy.idf_helper as idf_cte
class IdfBase:
def __init__(self, city, output_path, idf_file_path, idd_file_path, epw_file_path, target_buildings=None,
_calculate_with_new_infiltration=True):
self._city = city
self._output_path = str(output_path.resolve())
self._output_file_path = str((output_path / f'{city.name}.idf').resolve())
self._file_paths = {
'schedules': str((output_path / 'schedules.idf').resolve()),
'file_schedules': str((output_path / 'file_schedules.idf').resolve()),
'solid_materials': str((output_path / 'solid_materials.idf').resolve()),
'nomass_materials': str((output_path / 'nomass_materials.idf').resolve()),
'window_materials': str((output_path / 'window_materials.idf').resolve()),
'constructions': str((output_path / 'constructions.idf').resolve()),
'zones': str((output_path / 'zones.idf').resolve()),
'surfaces': str((output_path / 'surfaces.idf').resolve()),
'fenestration': str((output_path / 'fenestration.idf').resolve()),
'occupancy': str((output_path / 'occupancy.idf').resolve()),
'lighting': str((output_path / 'lights.idf').resolve()),
'appliances': str((output_path / 'appliances.idf').resolve()),
'shading': str((output_path / 'shading.idf').resolve()),
'infiltration': str((output_path / 'infiltration.idf').resolve()),
'ventilation': str((output_path / 'ventilation.idf').resolve()),
'thermostat': str((output_path / 'thermostat.idf').resolve()),
'ideal_load_system': str((output_path / 'ideal_load_system.idf').resolve()),
'dhw': str((output_path / 'dhw.idf').resolve()),
}
self._files = {}
for key, value in self._file_paths.items():
self._files[key] = open(value, 'w', encoding='UTF-8')
self._idd_file_path = str(idd_file_path)
self._idf_file_path = str(idf_file_path)
self._outputs_file_path = str(Path(idf_file_path).parent / 'outputs.idf')
self._epw_file_path = str(epw_file_path)
self._target_buildings = target_buildings
self._adjacent_buildings = []
if target_buildings is None:
self._target_buildings = [building.name for building in self._city.buildings]
else:
for building_name in target_buildings:
building = city.city_object(building_name)
if building.neighbours is not None:
self._adjacent_buildings += building.neighbours
self._calculate_with_new_infiltration = _calculate_with_new_infiltration
def _create_output_control_lighting(self):
file = self._files['appliances']
self._write_to_idf_format(file, idf_cte.OUTPUT_CONTROL)
self._write_to_idf_format(file, 'Comma', 'Column Separator', ';')
@staticmethod
def _write_to_idf_format(file, field, comment='', eol=','):
if comment != '':
comment = f' !- {comment}'
field = f' {field}{eol}'.ljust(26, ' ')
file.write(f'{field}{comment}\n')
else:
file.write(f'{field}{comment}')
@staticmethod
def _matrix_to_list(points, lower_corner):
lower_x = lower_corner[0]
lower_y = lower_corner[1]
lower_z = lower_corner[2]
points_list = []
for point in points:
point_tuple = (point[0] - lower_x, point[1] - lower_y, point[2] - lower_z)
points_list.append(point_tuple)
return points_list

View File

@ -0,0 +1,56 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.city_model_structure.building_demand.layer import Layer
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfConstruction(IdfBase):
@staticmethod
def _add_solid_material(self, layer):
file = self._files['solid_materials']
self._write_to_idf_format(file, idf_cte.SOLID_MATERIAL)
self._write_to_idf_format(file, layer.material_name, 'Name')
self._write_to_idf_format(file, idf_cte.ROUGHNESS, 'Roughness')
self._write_to_idf_format(file, layer.thickness, 'Thickness')
self._write_to_idf_format(file, layer.conductivity, 'Conductivity')
self._write_to_idf_format(file, layer.density, 'Density')
self._write_to_idf_format(file, layer.specific_heat, 'Specific Heat')
self._write_to_idf_format(file, layer.thermal_absorptance, 'Thermal Absorptance')
self._write_to_idf_format(file, layer.solar_absorptance, 'Solar Absorptance')
self._write_to_idf_format(file, layer.visible_absorptance, 'Visible Absorptance', ';')
@staticmethod
def _add_default_material(self):
layer = Layer()
layer.material_name = 'DefaultMaterial'
layer.thickness = 0.1
layer.conductivity = 0.1
layer.density = 1000
layer.specific_heat = 1000
layer.thermal_absorptance = 0.9
layer.solar_absorptance = 0.9
layer.visible_absorptance = 0.7
IdfConstruction._add_solid_material(self, layer)
return layer
@staticmethod
def add(self, thermal_boundary):
if thermal_boundary.layers is None:
thermal_boundary.layers = [IdfConstruction._add_default_material(self)]
name = f'{thermal_boundary.construction_name} {thermal_boundary.parent_surface.type}'
if name not in self._constructions_added_to_idf:
self._constructions_added_to_idf[name] = True
file = self._files['constructions']
self._write_to_idf_format(file, idf_cte.CONSTRUCTION)
self._write_to_idf_format(file, name, 'Name')
eol = ','
if len(thermal_boundary.layers) == 1:
eol = ';'
self._write_to_idf_format(file, thermal_boundary.layers[0].material_name, 'Outside Layer', eol)
for i in range(1, len(thermal_boundary.layers) - 1):
comment = f'Layer {i + 1}'
material_name = thermal_boundary.layers[i].material_name
if i == len(thermal_boundary.layers) - 2:
eol = ';'
self._write_to_idf_format(file, material_name, comment, eol)

View File

@ -0,0 +1,21 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfDhw(IdfBase):
@staticmethod
def add(self, thermal_zone, zone_name):
peak_flow_rate = thermal_zone.domestic_hot_water.peak_flow * thermal_zone.total_floor_area
flow_rate_schedule = f'DHW_prof schedules {thermal_zone.usage_name}'
dhw_schedule = f'DHW_temp schedules {thermal_zone.usage_name}'
cold_temp_schedule = f'cold_temp schedules {thermal_zone.usage_name}'
file = self._files['dhw']
self._write_to_idf_format(file, idf_cte.DHW)
self._write_to_idf_format(file, zone_name, 'Name')
self._write_to_idf_format(file, zone_name, 'EndUse Subcategory')
self._write_to_idf_format(file, peak_flow_rate, 'Peak Flow Rate')
self._write_to_idf_format(file, flow_rate_schedule, 'Flow Rate Fraction Schedule Name')
self._write_to_idf_format(file, dhw_schedule, 'Target Temperature Schedule Name')
self._write_to_idf_format(file, dhw_schedule, 'Hot Water Supply Temperature Schedule Name')
self._write_to_idf_format(file, cold_temp_schedule, 'Cold Water Supply Temperature Schedule Name')
self._write_to_idf_format(file, zone_name, 'Zone Name', ';')

View File

@ -0,0 +1,30 @@
from pathlib import Path
import hub.helpers.constants as cte
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfFileSchedule(IdfBase):
@staticmethod
def add(self, usage, schedule_type, schedules):
schedule_name = f'{schedule_type} schedules {usage}'
for schedule in schedules:
if schedule_name not in self._schedules_added_to_idf:
self._schedules_added_to_idf[schedule_name] = True
file_name = str(
(Path(self._output_path) / f'{schedule_type} schedules {usage.replace("/", "_")}.csv').resolve())
with open(file_name, 'w', encoding='utf8') as file:
for value in schedule.values[0]:
file.write(f'{value},\n')
file = self._files['file_schedules']
self._write_to_idf_format(file, idf_cte.FILE_SCHEDULE)
self._write_to_idf_format(file, schedule_name, 'Name')
self._write_to_idf_format(file, idf_cte.idf_type_limits[schedule.data_type], 'Schedule Type Limits Name')
self._write_to_idf_format(file, Path(file_name).name, 'File Name')
self._write_to_idf_format(file, 1, 'Column Number')
self._write_to_idf_format(file, 0, 'Rows to Skip at Top')
self._write_to_idf_format(file, 8760, 'Number of Hours of Data')
self._write_to_idf_format(file, 'Comma', 'Column Separator')
self._write_to_idf_format(file, 'No', 'Interpolate to Timestep')
self._write_to_idf_format(file, '60', 'Minutes per Item')
self._write_to_idf_format(file, 'Yes', 'Adjust Schedule for Daylight Savings', ';')

View File

@ -0,0 +1,41 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfHeatingSystem(IdfBase):
@staticmethod
def add(self, thermal_zone, zone_name):
availability_schedule = f'HVAC AVAIL SCHEDULES {thermal_zone.usage_name}'
thermostat_name = f'Thermostat {thermal_zone.usage_name}'
file = self._files['ideal_load_system']
self._write_to_idf_format(file, idf_cte.IDEAL_LOAD_SYSTEM)
self._write_to_idf_format(file, zone_name, 'Zone Name')
self._write_to_idf_format(file, thermostat_name, 'Template Thermostat Name')
self._write_to_idf_format(file, availability_schedule, 'System Availability Schedule Name')
self._write_to_idf_format(file, 50, 'Maximum Heating Supply Air Temperature')
self._write_to_idf_format(file, 13, 'Minimum Cooling Supply Air Temperature')
self._write_to_idf_format(file, 0.0156, 'Maximum Heating Supply Air Humidity Ratio')
self._write_to_idf_format(file, 0.0077, 'Minimum Cooling Supply Air Humidity Ratio')
self._write_to_idf_format(file, 'NoLimit', 'Heating Limit')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Heating Air Flow Rate')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Sensible Heating Capacity')
self._write_to_idf_format(file, 'NoLimit', 'Cooling Limit')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Cooling Air Flow Rate')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Total Cooling Capacity')
self._write_to_idf_format(file, availability_schedule, 'Heating Availability Schedule Name')
self._write_to_idf_format(file, availability_schedule, 'Cooling Availability Schedule Name')
self._write_to_idf_format(file, 'ConstantSensibleHeatRatio', 'Dehumidification Control Type')
self._write_to_idf_format(file, 0.7, 'Cooling Sensible Heat Ratio')
self._write_to_idf_format(file, 60, 'Dehumidification Setpoint')
self._write_to_idf_format(file, 'None', 'Humidification Control Type')
self._write_to_idf_format(file, 30, 'Humidification Setpoint')
self._write_to_idf_format(file, 'None', 'Outdoor Air Method')
self._write_to_idf_format(file, 0.00944, 'Outdoor Air Flow Rate per Person')
self._write_to_idf_format(file, 0.0, 'Outdoor Air Flow Rate per Zone Floor Area')
self._write_to_idf_format(file, 0, 'Outdoor Air Flow Rate per Zone')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Design Specification Outdoor Air Object Name')
self._write_to_idf_format(file, 'None', 'Demand Controlled Ventilation Type')
self._write_to_idf_format(file, 'NoEconomizer', 'Outdoor Air Economizer Type')
self._write_to_idf_format(file, 'None', 'Heat Recovery Type')
self._write_to_idf_format(file, 0.70, 'Sensible Heat Recovery Effectiveness')
self._write_to_idf_format(file, 0.65, 'Latent Heat Recovery Effectiveness', ';')

View File

@ -0,0 +1,32 @@
import hub.exports.building_energy.idf_helper as idf_cte
import hub.helpers.constants as cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfInfiltration(IdfBase):
@staticmethod
def add(self, thermal_zone, zone_name):
IdfInfiltration._add_infiltration(self, thermal_zone, zone_name, 'AirChanges/Hour', cte.HOUR_TO_SECONDS)
@staticmethod
def add_surface(self, thermal_zone, zone_name):
IdfInfiltration._add_infiltration(self, thermal_zone, zone_name, 'Flow/ExteriorWallArea', cte.INFILTRATION_75PA_TO_4PA)
@staticmethod
def _add_infiltration(self, thermal_zone, zone_name, calculation_method, multiplier):
schedule_name = f'Infiltration schedules {thermal_zone.usage_name}'
infiltration = thermal_zone.infiltration_rate_system_off * multiplier
file = self._files['infiltration']
self._write_to_idf_format(file, idf_cte.INFILTRATION)
self._write_to_idf_format(file, zone_name, 'Name')
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
self._write_to_idf_format(file, schedule_name, 'Schedule Name')
self._write_to_idf_format(file, calculation_method, 'Design Flow Rate Calculation Method')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Design Flow Rate')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Flow Rate per Floor Area')
self._write_to_idf_format(file, infiltration, 'Flow Rate per Exterior Surface Area')
self._write_to_idf_format(file, infiltration, 'Air Changes per Hour')
self._write_to_idf_format(file, 1, 'Constant Term Coefficient')
self._write_to_idf_format(file, 0, 'Temperature Term Coefficient')
self._write_to_idf_format(file, 0, 'Velocity Term Coefficient')
self._write_to_idf_format(file, 0, 'Velocity Squared Term Coefficient', ';')

View File

@ -0,0 +1,28 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfLighting(IdfBase):
@staticmethod
def add(self, thermal_zone, zone_name):
storeys_number = int(thermal_zone.total_floor_area / thermal_zone.footprint_area)
watts_per_zone_floor_area = thermal_zone.lighting.density * storeys_number
subcategory = f'ELECTRIC EQUIPMENT#{zone_name}#GeneralLights'
schedule_name = f'Lighting schedules {thermal_zone.usage_name}'
file = self._files['lighting']
self._write_to_idf_format(file, idf_cte.LIGHTS)
self._write_to_idf_format(file, f'{zone_name}_lights', 'Name')
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
self._write_to_idf_format(file, schedule_name, 'Schedule Name')
self._write_to_idf_format(file, 'Watts/Area', 'Design Level Calculation Method')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Lighting Level')
self._write_to_idf_format(file, watts_per_zone_floor_area, 'Watts per Zone Floor Area')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Watts per Person')
self._write_to_idf_format(file, 0, 'Return Air Fraction')
self._write_to_idf_format(file, thermal_zone.lighting.radiative_fraction, 'Fraction Radiant')
self._write_to_idf_format(file, 0, 'Fraction Visible')
self._write_to_idf_format(file, 1, 'Fraction Replaceable')
self._write_to_idf_format(file, subcategory, 'EndUse Subcategory')
self._write_to_idf_format(file, 'No', 'Return Air Fraction Calculated from Plenum Temperature')
self._write_to_idf_format(file, 0, 'Return Air Fraction Function of Plenum Temperature Coefficient 1')
self._write_to_idf_format(file, 0, 'Return Air Fraction Function of Plenum Temperature Coefficient 2', ';')

View File

@ -0,0 +1,39 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfMaterial(IdfBase):
@staticmethod
def _add_solid_material(self, layer):
file = self._files['solid_materials']
self._write_to_idf_format(file, idf_cte.SOLID_MATERIAL)
self._write_to_idf_format(file, layer.material_name, 'Name')
self._write_to_idf_format(file, idf_cte.ROUGHNESS, 'Roughness')
self._write_to_idf_format(file, layer.thickness, 'Thickness')
self._write_to_idf_format(file, layer.conductivity, 'Conductivity')
self._write_to_idf_format(file, layer.density, 'Density')
self._write_to_idf_format(file, layer.specific_heat, 'Specific Heat')
self._write_to_idf_format(file, layer.thermal_absorptance, 'Thermal Absorptance')
self._write_to_idf_format(file, layer.solar_absorptance, 'Solar Absorptance')
self._write_to_idf_format(file, layer.visible_absorptance, 'Visible Absorptance', ';')
@staticmethod
def _add_nomass_material(self, layer):
file = self._files['nomass_materials']
self._write_to_idf_format(file, idf_cte.NOMASS_MATERIAL)
self._write_to_idf_format(file, layer.material_name, 'Name')
self._write_to_idf_format(file, idf_cte.ROUGHNESS, 'Roughness')
self._write_to_idf_format(file, layer.thermal_resistance, 'Thermal Resistance')
self._write_to_idf_format(file, 0.9, 'Thermal Absorptance')
self._write_to_idf_format(file, 0.7, 'Solar Absorptance')
self._write_to_idf_format(file, 0.7, 'Visible Absorptance', ';')
@staticmethod
def add(self, thermal_boundary):
for layer in thermal_boundary.layers:
if layer.material_name not in self._materials_added_to_idf:
self._materials_added_to_idf[layer.material_name] = True
if layer.no_mass:
IdfMaterial._add_nomass_material(self, layer)
else:
IdfMaterial._add_solid_material(self, layer)

View File

@ -0,0 +1,47 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfOccupancy(IdfBase):
@staticmethod
def add(self, thermal_zone, zone_name):
number_of_people = thermal_zone.occupancy.occupancy_density * thermal_zone.total_floor_area
fraction_radiant = 0
total_sensible = (
thermal_zone.occupancy.sensible_radiative_internal_gain + thermal_zone.occupancy.sensible_convective_internal_gain
)
if total_sensible != 0:
fraction_radiant = thermal_zone.occupancy.sensible_radiative_internal_gain / total_sensible
occupancy_schedule = f'Occupancy schedules {thermal_zone.usage_name}'
activity_level_schedule = f'Activity Level schedules {thermal_zone.usage_name}'
file = self._files['occupancy']
self._write_to_idf_format(file, idf_cte.PEOPLE)
self._write_to_idf_format(file, f'{zone_name}_occupancy', 'Name')
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
self._write_to_idf_format(file, occupancy_schedule, 'Number of People Schedule Name')
self._write_to_idf_format(file, 'People', 'Number of People Calculation Method')
self._write_to_idf_format(file, number_of_people, 'Number of People')
self._write_to_idf_format(file, idf_cte.EMPTY, 'People per Floor Area')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Floor Area per Person')
self._write_to_idf_format(file, fraction_radiant, 'Fraction Radiant')
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Sensible Heat Fraction')
self._write_to_idf_format(file, activity_level_schedule, 'Activity Level Schedule Name')
self._write_to_idf_format(file, '3.82e-08', 'Carbon Dioxide Generation Rate')
self._write_to_idf_format(file, 'No', 'Enable ASHRAE 55 Comfort Warnings')
self._write_to_idf_format(file, 'EnclosureAveraged', 'Mean Radiant Temperature Calculation Type')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Surface NameAngle Factor List Name')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Work Efficiency Schedule Name')
self._write_to_idf_format(file, 'ClothingInsulationSchedule', 'Clothing Insulation Calculation Method')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Clothing Insulation Calculation Method Schedule Name')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Clothing Insulation Schedule Name')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Air Velocity Schedule Name')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 1 Type')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 2 Type')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 3 Type')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 4 Type')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 5 Type')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 6 Type')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Thermal Comfort Model 7 Type')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Ankle Level Air Velocity Schedule Name')
self._write_to_idf_format(file, '15.56', 'Cold Stress Temperature Threshold')
self._write_to_idf_format(file, '30', 'Heat Stress Temperature Threshold', ';')

View File

@ -0,0 +1,30 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfSchedule(IdfBase):
@staticmethod
def add(self, usage, schedule_type, schedules):
if len(schedules) < 1:
return
schedule_name = f'{schedule_type} schedules {usage}'
if schedule_name not in self._schedules_added_to_idf:
self._schedules_added_to_idf[schedule_name] = True
file = self._files['schedules']
self._write_to_idf_format(file, idf_cte.COMPACT_SCHEDULE)
self._write_to_idf_format(file, schedule_name, 'Name')
self._write_to_idf_format(file, idf_cte.idf_type_limits[schedules[0].data_type], 'Schedule Type Limits Name')
self._write_to_idf_format(file, 'Through: 12/31', 'Field 1')
counter = 1
for j, schedule in enumerate(schedules):
_val = schedule.values
_new_field = ''
for day_type in schedule.day_types:
_new_field += f' {idf_cte.idf_day_types[day_type]}'
self._write_to_idf_format(file, f'For:{_new_field}', f'Field {j * 25 + 2}')
counter += 1
for i, _ in enumerate(_val):
self._write_to_idf_format(file, f'Until: {i + 1:02d}:00,{_val[i]}', f'Field {j * 25 + 3 + i}')
counter += 1
self._write_to_idf_format(file, 'For AllOtherDays', f'Field {counter + 1}')
self._write_to_idf_format(file, 'Until: 24:00,0.0', f'Field {counter + 2}', ';')

View File

@ -0,0 +1,25 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfShading(IdfBase):
@staticmethod
def add(self, building):
name = building.name
file = self._files['shading']
for s, surface in enumerate(building.surfaces):
self._write_to_idf_format(file, idf_cte.SHADING)
self._write_to_idf_format(file, f'{name}_{s}', 'Name')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Transmittance Schedule Name')
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Number of Vertices')
eol = ','
coordinates = self._matrix_to_list(surface.solid_polygon.coordinates, self._city.lower_corner)
coordinates_length = len(coordinates)
for i, coordinate in enumerate(coordinates):
vertex = i + 1
if vertex == coordinates_length:
eol = ';'
self._write_to_idf_format(file, coordinate[0], f'Vertex {vertex} Xcoordinate')
self._write_to_idf_format(file, coordinate[1], f'Vertex {vertex} Ycoordinate')
self._write_to_idf_format(file, coordinate[2], f'Vertex {vertex} Zcoordinate', eol)

View File

@ -0,0 +1,52 @@
import hub.exports.building_energy.idf_helper as idf_cte
import hub.helpers.constants as cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfSurfaces(IdfBase):
@staticmethod
def add(self, building, zone_name):
zone_name = f'{zone_name}'
file = self._files['surfaces']
for thermal_zone in building.thermal_zones_from_internal_zones:
for index, boundary in enumerate(thermal_zone.thermal_boundaries):
surface_type = idf_cte.idf_surfaces_dictionary[boundary.parent_surface.type]
outside_boundary_condition = idf_cte.OUTDOORS
sun_exposure = idf_cte.SUN_EXPOSED
wind_exposure = idf_cte.WIND_EXPOSED
outside_boundary_condition_object = idf_cte.EMPTY
name = f'Building_{building.name}_surface_{index}'
construction_name = f'{boundary.construction_name} {boundary.parent_surface.type}'
space_name = idf_cte.EMPTY
if boundary.parent_surface.type == cte.GROUND:
outside_boundary_condition = idf_cte.GROUND
sun_exposure = idf_cte.NON_SUN_EXPOSED
wind_exposure = idf_cte.NON_WIND_EXPOSED
if boundary.parent_surface.percentage_shared is not None and boundary.parent_surface.percentage_shared > 0.5:
outside_boundary_condition_object = f'Building_{building.name}_surface_{index}'
outside_boundary_condition = idf_cte.SURFACE
sun_exposure = idf_cte.NON_SUN_EXPOSED
wind_exposure = idf_cte.NON_WIND_EXPOSED
self._write_to_idf_format(file, idf_cte.BUILDING_SURFACE)
self._write_to_idf_format(file, name, 'Name')
self._write_to_idf_format(file, surface_type, 'Surface Type')
self._write_to_idf_format(file, construction_name, 'Construction Name')
self._write_to_idf_format(file, zone_name, 'Zone Name')
self._write_to_idf_format(file, space_name, 'Space Name')
self._write_to_idf_format(file, outside_boundary_condition, 'Outside Boundary Condition')
self._write_to_idf_format(file, outside_boundary_condition_object, 'Outside Boundary Condition Object')
self._write_to_idf_format(file, sun_exposure, 'Sun Exposure')
self._write_to_idf_format(file, wind_exposure, 'Wind Exposure')
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'View Factor to Ground')
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Number of Vertices')
coordinates = self._matrix_to_list(boundary.parent_surface.solid_polygon.coordinates,
self._city.lower_corner)
eol = ','
coordinates_length = len(coordinates)
for i, coordinate in enumerate(coordinates):
vertex = i + 1
if vertex == coordinates_length:
eol = ';'
self._write_to_idf_format(file, coordinate[0], f'Vertex {vertex} Xcoordinate')
self._write_to_idf_format(file, coordinate[1], f'Vertex {vertex} Ycoordinate')
self._write_to_idf_format(file, coordinate[2], f'Vertex {vertex} Zcoordinate', eol)

View File

@ -0,0 +1,18 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfThermostat(IdfBase):
@staticmethod
def add(self, thermal_zone):
thermostat_name = f'Thermostat {thermal_zone.usage_name}'
heating_schedule = f'Heating thermostat schedules {thermal_zone.usage_name}'
cooling_schedule = f'Cooling thermostat schedules {thermal_zone.usage_name}'
if thermostat_name not in self._thermostat_added_to_idf:
self._thermostat_added_to_idf[thermostat_name] = True
file = self._files['thermostat']
self._write_to_idf_format(file, idf_cte.THERMOSTAT)
self._write_to_idf_format(file, thermostat_name, 'Name')
self._write_to_idf_format(file, heating_schedule, 'Heating Setpoint Schedule Name')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Constant Heating Setpoint')
self._write_to_idf_format(file, cooling_schedule, 'Cooling Setpoint Schedule Name', ';')

View File

@ -0,0 +1,38 @@
import hub.exports.building_energy.idf_helper as idf_cte
import hub.helpers.constants as cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfVentilation(IdfBase):
@staticmethod
def add(self, thermal_zone, zone_name):
schedule_name = f'Ventilation schedules {thermal_zone.usage_name}'
air_change = thermal_zone.mechanical_air_change * cte.HOUR_TO_SECONDS
file = self._files['ventilation']
self._write_to_idf_format(file, idf_cte.VENTILATION)
self._write_to_idf_format(file, f'{zone_name}_ventilation', 'Name')
self._write_to_idf_format(file, zone_name, 'Zone or ZoneList or Space or SpaceList Name')
self._write_to_idf_format(file, schedule_name, 'Schedule Name')
self._write_to_idf_format(file, 'AirChanges/Hour', 'Design Flow Rate Calculation Method')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Design Flow Rate')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Flow Rate per Floor Area')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Flow Rate per Person')
self._write_to_idf_format(file, air_change, 'Air Changes per Hour')
self._write_to_idf_format(file, 'Natural', 'Ventilation Type')
self._write_to_idf_format(file, 0, 'Fan Pressure Rise')
self._write_to_idf_format(file, 1, 'Fan Total Efficiency')
self._write_to_idf_format(file, 1, 'Constant Term Coefficient')
self._write_to_idf_format(file, 0, 'Temperature Term Coefficient')
self._write_to_idf_format(file, 0, 'Velocity Term Coefficient')
self._write_to_idf_format(file, 0, 'Velocity Squared Term Coefficient')
self._write_to_idf_format(file, -100, 'Minimum Indoor Temperature')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Minimum Indoor Temperature Schedule Name')
self._write_to_idf_format(file, 100, 'Maximum Indoor Temperature')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Indoor Temperature Schedule Name')
self._write_to_idf_format(file, -100, 'Delta Temperature')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Delta Temperature Schedule Name')
self._write_to_idf_format(file, -100, 'Minimum Outdoor Temperature')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Minimum Outdoor Temperature Schedule Name')
self._write_to_idf_format(file, 100, 'Maximum Outdoor Temperature')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Maximum Outdoor Temperature Schedule Name')
self._write_to_idf_format(file, 40, 'Maximum Wind Speed', ';')

View File

@ -0,0 +1,64 @@
import logging
import hub.exports.building_energy.idf_helper as idf_cte
import hub.helpers.constants as cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfWindow(IdfBase):
@staticmethod
def _to_window_surface(self, surface):
window_ratio = surface.associated_thermal_boundaries[0].window_ratio
x = 0
y = 1
z = 2
coordinates = self._matrix_to_list(surface.solid_polygon.coordinates, self._city.lower_corner)
min_z = surface.lower_corner[z]
max_z = surface.upper_corner[z]
middle = (max_z - min_z) / 2
distance = (max_z - min_z) * window_ratio
new_max_z = middle + distance / 2
new_min_z = middle - distance / 2
for index, coordinate in enumerate(coordinates):
if coordinate[z] == max_z:
coordinates[index] = (coordinate[x], coordinate[y], new_max_z)
elif coordinate[z] == min_z:
coordinates[index] = (coordinate[x], coordinate[y], new_min_z)
else:
logging.warning('Z coordinate not in top or bottom during window creation')
return coordinates
@staticmethod
def add(self, building):
file = self._files['fenestration']
for thermal_zone in building.thermal_zones_from_internal_zones:
for index, boundary in enumerate(thermal_zone.thermal_boundaries):
building_surface_name = f'Building_{building.name}_surface_{index}'
is_exposed = boundary.parent_surface.type == cte.WALL
if boundary.parent_surface.percentage_shared is not None and boundary.parent_surface.percentage_shared > 0.5 or boundary.window_ratio == 0:
is_exposed = False
if not is_exposed:
continue
name = f'Building_{building.name}_window_{index}'
construction_name = f'{boundary.construction_name}_window_construction'
self._write_to_idf_format(file, idf_cte.WINDOW_SURFACE)
self._write_to_idf_format(file, name, 'Name')
self._write_to_idf_format(file, 'Window', 'Surface Type')
self._write_to_idf_format(file, construction_name, 'Construction Name')
self._write_to_idf_format(file, building_surface_name, 'Building Surface Name')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Outside Boundary Condition Object')
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'View Factor to Ground')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Frame and Divider Name')
self._write_to_idf_format(file, '1.0', 'Multiplier')
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Number of Vertices')
coordinates = IdfWindow._to_window_surface(self, boundary.parent_surface)
eol = ','
coordinates_length = len(coordinates)
for i, coordinate in enumerate(coordinates):
vertex = i + 1
if vertex == coordinates_length:
eol = ';'
self._write_to_idf_format(file, coordinate[0], f'Vertex {vertex} Xcoordinate')
self._write_to_idf_format(file, coordinate[1], f'Vertex {vertex} Ycoordinate')
self._write_to_idf_format(file, coordinate[2], f'Vertex {vertex} Zcoordinate', eol)

View File

@ -0,0 +1,17 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfWindowsConstructions(IdfBase):
@staticmethod
def add(self, thermal_boundary):
name = f'{thermal_boundary.construction_name}_window'
if name not in self._windows_added_to_idf:
return # Material not added or already assigned to construction
construction_name = f'{thermal_boundary.construction_name}_window_construction'
if construction_name not in self._constructions_added_to_idf:
self._constructions_added_to_idf[construction_name] = True
file = self._files['constructions']
self._write_to_idf_format(file, idf_cte.CONSTRUCTION)
self._write_to_idf_format(file, construction_name, 'Name')
self._write_to_idf_format(file, name, 'Outside Layer', ';')

View File

@ -0,0 +1,15 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfWindowsMaterial(IdfBase):
@staticmethod
def add(self, thermal_boundary, thermal_opening):
name = f'{thermal_boundary.construction_name}_window'
if name not in self._windows_added_to_idf:
self._windows_added_to_idf[name] = True
file = self._files['window_materials']
self._write_to_idf_format(file, idf_cte.WINDOW_MATERIAL)
self._write_to_idf_format(file, name, 'Name')
self._write_to_idf_format(file, thermal_opening.overall_u_value, 'UFactor')
self._write_to_idf_format(file, thermal_opening.g_value, 'Solar Heat Gain Coefficient', ';')

View File

@ -0,0 +1,22 @@
import hub.exports.building_energy.idf_helper as idf_cte
from hub.exports.building_energy.idf_helper.idf_base import IdfBase
class IdfZone(IdfBase):
@staticmethod
def add(self, thermal_zone, zone_name):
file = self._files['zones']
self._write_to_idf_format(file, idf_cte.ZONE)
self._write_to_idf_format(file, zone_name, 'Name')
self._write_to_idf_format(file, 0, 'Direction of Relative North')
self._write_to_idf_format(file, 0, 'X Origin')
self._write_to_idf_format(file, 0, 'Y Origin')
self._write_to_idf_format(file, 0, 'Z Origin')
self._write_to_idf_format(file, 1, 'Type')
self._write_to_idf_format(file, 1, 'Multiplier')
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Ceiling Height')
self._write_to_idf_format(file, thermal_zone.volume, 'Volume')
self._write_to_idf_format(file, idf_cte.AUTOCALCULATE, 'Floor Area')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Zone Inside Convection Algorithm')
self._write_to_idf_format(file, idf_cte.EMPTY, 'Zone Outside Convection Algorithm')
self._write_to_idf_format(file, 'Yes', 'Part of Total Floor Area', ';')

View File

@ -11,6 +11,7 @@ import requests
from hub.exports.building_energy.energy_ade import EnergyAde from hub.exports.building_energy.energy_ade import EnergyAde
from hub.exports.building_energy.idf import Idf from hub.exports.building_energy.idf import Idf
from hub.exports.building_energy.cerc_idf import CercIdf
from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance from hub.exports.building_energy.insel.insel_monthly_energy_balance import InselMonthlyEnergyBalance
from hub.helpers.utils import validate_import_export_type from hub.helpers.utils import validate_import_export_type
from hub.imports.weather.helpers.weather import Weather as wh from hub.imports.weather.helpers.weather import Weather as wh
@ -20,6 +21,7 @@ class EnergyBuildingsExportsFactory:
""" """
Energy Buildings exports factory class Energy Buildings exports factory class
""" """
def __init__(self, handler, city, path, custom_insel_block='d18599', target_buildings=None, weather_file=None): def __init__(self, handler, city, path, custom_insel_block='d18599', target_buildings=None, weather_file=None):
self._city = city self._city = city
self._export_type = '_' + handler.lower() self._export_type = '_' + handler.lower()
@ -62,6 +64,17 @@ class EnergyBuildingsExportsFactory:
return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'), return Idf(self._city, self._path, (idf_data_path / 'Minimal.idf'), (idf_data_path / 'Energy+.idd'),
self._weather_file, target_buildings=self._target_buildings) self._weather_file, target_buildings=self._target_buildings)
@property
def _cerc_idf(self):
idf_data_path = (Path(__file__).parent / './building_energy/idf_files/').resolve()
url = wh().epw_file(self._city.region_code)
weather_path = (Path(__file__).parent.parent / f'data/weather/epw/{url.rsplit("/", 1)[1]}').resolve()
if not weather_path.exists():
with open(weather_path, 'wb') as epw_file:
epw_file.write(requests.get(url, allow_redirects=True).content)
return CercIdf(self._city, self._path, (idf_data_path / 'base.idf'), (idf_data_path / 'Energy+.idd'), weather_path,
target_buildings=self._target_buildings)
@property @property
def _insel_monthly_energy_balance(self): def _insel_monthly_energy_balance(self):
""" """

View File

@ -77,8 +77,8 @@ class CesiumjsTileset:
'function': { 'function': {
'type': 'STRING' 'type': 'STRING'
}, },
'usages_percentage': { 'usages': {
'type': 'STRING' 'type': 'LIST'
} }
} }
} }
@ -146,7 +146,7 @@ class CesiumjsTileset:
'max_height': building.max_height, 'max_height': building.max_height,
'year_of_construction': building.year_of_construction, 'year_of_construction': building.year_of_construction,
'function': building.function, 'function': building.function,
'usages_percentage': building.usages_percentage 'usages': building.usages
} }
}, },
'content': { 'content': {

View File

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

View File

@ -24,7 +24,7 @@ BTU_H_TO_WATTS = 0.29307107
KILO_WATTS_HOUR_TO_JULES = 3600000 KILO_WATTS_HOUR_TO_JULES = 3600000
WATTS_HOUR_TO_JULES = 3600 WATTS_HOUR_TO_JULES = 3600
GALLONS_TO_QUBIC_METERS = 0.0037854117954011185 GALLONS_TO_QUBIC_METERS = 0.0037854117954011185
INFILTRATION_75PA_TO_4PA = (4 / 75) ** 0.65
# time # time
SECOND = 'second' SECOND = 'second'
@ -185,6 +185,19 @@ DAYS_A_MONTH = {JANUARY: 31,
NOVEMBER: 30, NOVEMBER: 30,
DECEMBER: 31} DECEMBER: 31}
HOURS_A_MONTH = {JANUARY: 744,
FEBRUARY: 672,
MARCH: 744,
APRIL: 720,
MAY: 744,
JUNE: 720,
JULY: 744,
AUGUST: 744,
SEPTEMBER: 720,
OCTOBER: 744,
NOVEMBER: 720,
DECEMBER: 744}
# data types # data types
ANY_NUMBER = 'any_number' ANY_NUMBER = 'any_number'
FRACTION = 'fraction' FRACTION = 'fraction'
@ -294,6 +307,7 @@ GAS = 'Gas'
DIESEL = 'Diesel' DIESEL = 'Diesel'
COAL = 'Coal' COAL = 'Coal'
BIOMASS = 'Biomass' BIOMASS = 'Biomass'
BUTANE = 'Butane'
AIR = 'Air' AIR = 'Air'
WATER = 'Water' WATER = 'Water'
GEOTHERMAL = 'Geothermal' GEOTHERMAL = 'Geothermal'
@ -302,10 +316,14 @@ GRID = 'Grid'
ONSITE_ELECTRICITY = 'Onsite Electricity' ONSITE_ELECTRICITY = 'Onsite Electricity'
PHOTOVOLTAIC = 'Photovoltaic' PHOTOVOLTAIC = 'Photovoltaic'
BOILER = 'Boiler' BOILER = 'Boiler'
FURNACE = 'Furnace'
HEAT_PUMP = 'Heat Pump' HEAT_PUMP = 'Heat Pump'
BASEBOARD = 'Baseboard' BASEBOARD = 'Baseboard'
ELECTRICITY_GENERATOR = 'Electricity generator' ELECTRICITY_GENERATOR = 'Electricity generator'
CHILLER = 'Chiller' CHILLER = 'Chiller'
SPLIT = 'Split'
JOULE = 'Joule'
BUTANE_HEATER = 'Butane Heater'
SENSIBLE = 'sensible' SENSIBLE = 'sensible'
LATENT = 'Latent' LATENT = 'Latent'
LITHIUMION = 'Lithium Ion' LITHIUMION = 'Lithium Ion'

View File

@ -0,0 +1,30 @@
"""
Dictionaries module for hub function to Palma construction function
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Cecilia Pérez cperez@irec.cat
"""
import hub.helpers.constants as cte
class HubFunctionToPalmaConstructionFunction:
"""
Hub function to Palma construction function class
"""
def __init__(self):
self._dictionary = {
cte.RESIDENTIAL: 'V',
cte.SINGLE_FAMILY_HOUSE: 'Single-family building',
cte.HIGH_RISE_APARTMENT: 'Large multifamily building',
cte.MID_RISE_APARTMENT: 'Medium multifamily building',
cte.MULTI_FAMILY_HOUSE: 'Small multifamily building'
}
@property
def dictionary(self) -> dict:
"""
Get the dictionary
:return: {}
"""
return self._dictionary

View File

@ -0,0 +1,51 @@
"""
Dictionaries module for hub usage to Palma usage
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Cecilia Pérez cperez@irec.cat
"""
"""
Codification of uses from cadastre:
U: store-parking. Residential Use
S: store-parking. Industrial Use
V: Residential
I: Industrial
O: Offices
C: Comercial
K: Sportive center
T: Shows
G: Leisure and Hostelry
Y: Health and charity
E: Culture
R: Religion
M: Urbanization work, gardening and undeveloped land
P: Singular building
B: Farm warehouse
J: Farm Industry
Z: Farm-related
"""
import hub.helpers.constants as cte
class HubUsageToPalmaUsage:
"""
Hub usage to Palma usage class
"""
def __init__(self):
self._dictionary = {
cte.RESIDENTIAL: 'residential',
cte.SINGLE_FAMILY_HOUSE: 'residential',
cte.HIGH_RISE_APARTMENT: 'residential',
cte.MID_RISE_APARTMENT: 'residential',
cte.MULTI_FAMILY_HOUSE: 'residential'
}
@property
def dictionary(self) -> dict:
"""
Get the dictionary
:return: {}
"""
return self._dictionary

View File

@ -12,12 +12,17 @@ class MontrealCustomFuelToHubFuel:
""" """
Montreal custom fuel to hub fuel class Montreal custom fuel to hub fuel class
""" """
def __init__(self): def __init__(self):
self._dictionary = { self._dictionary = {
'gas': cte.GAS, 'gas': cte.GAS,
'electricity': cte.ELECTRICITY, 'natural gas': cte.GAS,
'renewable': cte.RENEWABLE 'biomass': cte.BIOMASS,
} 'electricity': cte.ELECTRICITY,
'renewable': cte.RENEWABLE,
'butane': cte.BUTANE,
'diesel': cte.DIESEL
}
@property @property
def dictionary(self) -> dict: def dictionary(self) -> dict:

View File

@ -15,11 +15,15 @@ class MontrealGenerationSystemToHubEnergyGenerationSystem:
def __init__(self): def __init__(self):
self._dictionary = { self._dictionary = {
'boiler': cte.BOILER, 'boiler': cte.BOILER,
'furnace': cte.BASEBOARD, 'furnace': cte.FURNACE,
'cooler': cte.CHILLER, 'cooler': cte.CHILLER,
'electricity generator': cte.ELECTRICITY_GENERATOR, 'electricity generator': cte.ELECTRICITY_GENERATOR,
'PV system': cte.PHOTOVOLTAIC, 'photovoltaic': cte.PHOTOVOLTAIC,
'heat pump': cte.HEAT_PUMP 'heat pump': cte.HEAT_PUMP,
'joule': cte.JOULE,
'split': cte.SPLIT,
'butane heater': cte.BUTANE_HEATER
} }
@property @property

View File

@ -0,0 +1,31 @@
"""
Dictionaries module for Palma function to hub function
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Cecilia Pérez cperez@irec.cat
"""
import hub.helpers.constants as cte
class PalmaFunctionToHubFunction:
"""
Palma function to hub function class
"""
def __init__(self):
self._dictionary = {'Residential': cte.RESIDENTIAL,
'Single-family building': cte.SINGLE_FAMILY_HOUSE,
'Large multifamily building': cte.HIGH_RISE_APARTMENT,
'Medium multifamily building': cte.MID_RISE_APARTMENT,
'Small multifamily building': cte.MULTI_FAMILY_HOUSE,
'V': cte.RESIDENTIAL
}
@property
def dictionary(self) -> dict:
"""
Get the dictionary
:return: {}
"""
return self._dictionary

View File

@ -26,6 +26,9 @@ from hub.helpers.data.north_america_demand_type_to_hub_energy_demand_type import
from hub.helpers.data.north_america_system_to_hub_energy_generation_system import NorthAmericaSystemToHubEnergyGenerationSystem from hub.helpers.data.north_america_system_to_hub_energy_generation_system import NorthAmericaSystemToHubEnergyGenerationSystem
from hub.helpers.data.north_america_custom_fuel_to_hub_fuel import NorthAmericaCustomFuelToHubFuel from hub.helpers.data.north_america_custom_fuel_to_hub_fuel import NorthAmericaCustomFuelToHubFuel
from hub.helpers.data.north_america_storage_system_to_hub_storage import NorthAmericaStorageSystemToHubEnergyStorage from hub.helpers.data.north_america_storage_system_to_hub_storage import NorthAmericaStorageSystemToHubEnergyStorage
from hub.helpers.data.palma_function_to_hub_function import PalmaFunctionToHubFunction
from hub.helpers.data.hub_usage_to_palma_usage import HubUsageToPalmaUsage
from hub.helpers.data.hub_function_to_palma_construction_function import HubFunctionToPalmaConstructionFunction
class Dictionaries: class Dictionaries:
@ -65,6 +68,14 @@ class Dictionaries:
""" """
return HubUsageToEilatUsage().dictionary return HubUsageToEilatUsage().dictionary
@property
def hub_usage_to_palma_usage(self) -> dict:
"""
Hub usage to Palma usage, transformation dictionary
:return: dict
"""
return HubUsageToPalmaUsage().dictionary
@property @property
def hub_function_to_nrcan_construction_function(self) -> dict: def hub_function_to_nrcan_construction_function(self) -> dict:
""" """
@ -88,6 +99,13 @@ class Dictionaries:
:return: dict :return: dict
""" """
return HubFunctionToNrelConstructionFunction().dictionary return HubFunctionToNrelConstructionFunction().dictionary
@property
def hub_function_to_palma_construction_function(self) -> dict:
"""
Get hub function to Palma construction function, transformation dictionary
:return: dict
"""
return HubFunctionToPalmaConstructionFunction().dictionary
@property @property
def pluto_function_to_hub_function(self) -> dict: def pluto_function_to_hub_function(self) -> dict:
@ -105,6 +123,14 @@ class Dictionaries:
""" """
return HftFunctionToHubFunction().dictionary return HftFunctionToHubFunction().dictionary
@property
def palma_function_to_hub_function(self) -> dict:
"""
Get Palma function to hub function, transformation dictionary
:return: dict
"""
return PalmaFunctionToHubFunction().dictionary
@property @property
def montreal_function_to_hub_function(self) -> dict: def montreal_function_to_hub_function(self) -> dict:
""" """

View File

@ -0,0 +1,31 @@
class ListUsageToHub:
"""
Eilat function to hub function class
"""
def __init__(self, function_dictionary=None):
self._function_dictionary = function_dictionary
def _apply_function_dictionary(self, usages):
function_dictionary = self._function_dictionary
if function_dictionary is not None:
for usage in usages:
if usage['usage'] in function_dictionary:
usage['usage'] = function_dictionary[usage['usage']]
return usages
def parse(self, usages) -> list[dict]:
"""
Get the dictionary
:return: {}
"""
usages = [{"usage": str(i["usage"]), "ratio": float(i["ratio"])} for i in usages]
usages = self._apply_function_dictionary(usages)
return usages

View File

@ -0,0 +1,19 @@
class StringUsageToHub:
"""
Eilat function to hub function class
"""
def parse(self, usages) -> list[dict]:
"""
Parse usage string in form residential-80_commercial-20
:usages: str
:return: {}
"""
parsed_usages = []
for usage in usages.split('_'):
usage_dict = {"usage": str(usage.split('-')[0]), "ratio": float(usage.split('-')[1])/100}
parsed_usages.append(usage_dict)
return parsed_usages

View File

@ -0,0 +1,31 @@
"""
Dictionaries module saves all transformations of functions and usages to access the catalogs
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.helpers.parsers.list_usage_to_hub import ListUsageToHub
from hub.helpers.parsers.string_usage_to_hub import StringUsageToHub
class UsageParsers:
"""
Dictionaries class
"""
@staticmethod
def string_usage_to_hub() -> object:
"""
Hub usage to HfT usage, transformation dictionary
:return: dict
"""
return StringUsageToHub().parse
@staticmethod
def list_usage_to_hub(function_dictionary=None) -> object:
"""
Hub usage to HfT usage, transformation dictionary
:return: dict
"""
return ListUsageToHub(function_dictionary).parse

View File

@ -65,6 +65,10 @@ class ConstructionHelper:
'Eilat': 'BWh' 'Eilat': 'BWh'
} }
_reference_city_to_palma_climate_zone ={
'Palma': 'B3'
}
@staticmethod @staticmethod
def yoc_to_nrel_standard(year_of_construction): def yoc_to_nrel_standard(year_of_construction):
""" """
@ -107,3 +111,13 @@ class ConstructionHelper:
:return: str :return: str
""" """
return ConstructionHelper._reference_city_to_israel_climate_zone[reference_city] return ConstructionHelper._reference_city_to_israel_climate_zone[reference_city]
@staticmethod
def city_to_palma_climate_zone(reference_city):
"""
City name to Palma climate zone
:param reference_city: str
:return: str
"""
return ConstructionHelper._reference_city_to_palma_climate_zone[reference_city]

View File

@ -33,21 +33,10 @@ class NrcanPhysicsParameters:
city = self._city city = self._city
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
for building in city.buildings: for building in city.buildings:
main_function = None if building.function not in Dictionaries().hub_function_to_nrcan_construction_function:
functions = building.function.split('_') logging.error('Building %s has an unknown building function %s', building.name, building.function)
if len(functions) > 1:
maximum_percentage = 0
for function in functions:
percentage_and_function = function.split('-')
if float(percentage_and_function[0]) > maximum_percentage:
maximum_percentage = float(percentage_and_function[0])
main_function = percentage_and_function[-1]
else:
main_function = functions[-1]
if main_function not in Dictionaries().hub_function_to_nrcan_construction_function:
logging.error('Building %s has an unknown building function %s', building.name, main_function)
continue continue
function = Dictionaries().hub_function_to_nrcan_construction_function[main_function] function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
try: try:
archetype = self._search_archetype(nrcan_catalog, function, building.year_of_construction, self._climate_zone) archetype = self._search_archetype(nrcan_catalog, function, building.year_of_construction, self._climate_zone)

View File

@ -0,0 +1,107 @@
"""
PalmaPhysicsParameters import the construction and material information defined by Palma
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Cecilia Pérez Pérez cperez@irec.cat
"""
import logging
from hub.catalog_factories.construction_catalog_factory import ConstructionCatalogFactory
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
from hub.city_model_structure.building_demand.construction import Construction
from hub.city_model_structure.building_demand.layer import Layer
from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction.helpers.construction_helper import ConstructionHelper
class PalmaPhysicsParameters:
"""
PalmaPhysicsParameters class
"""
def __init__(self, city, divide_in_storeys=False):
self._city = city
self._divide_in_storeys = divide_in_storeys
self._climate_zone = ConstructionHelper.city_to_palma_climate_zone(city.climate_reference_city)
def enrich_buildings(self):
"""
Returns the city with the construction parameters assigned to the buildings
"""
city = self._city
palma_catalog = ConstructionCatalogFactory('palma').catalog
for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_palma_construction_function:
logging.error('Building %s has an unknown building function %s', building.name, building.function)
continue
function = Dictionaries().hub_function_to_palma_construction_function[building.function]
try:
archetype = self._search_archetype(palma_catalog, function, building.year_of_construction, self._climate_zone)
except KeyError:
logging.error('Building %s has unknown construction archetype for building function: %s '
'[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, self._climate_zone)
continue
thermal_archetype = ThermalArchetype()
self._assign_values(thermal_archetype, archetype)
for internal_zone in building.internal_zones:
internal_zone.thermal_archetype = thermal_archetype
@staticmethod
def _search_archetype(nrcan_catalog, function, year_of_construction, climate_zone):
nrcan_archetypes = nrcan_catalog.entries('archetypes')
for building_archetype in nrcan_archetypes:
construction_period_limits = building_archetype.construction_period.split('_')
if int(construction_period_limits[0]) <= int(year_of_construction) <= int(construction_period_limits[1]):
if str(function) == str(building_archetype.function) and climate_zone == str(building_archetype.climate_zone):
return building_archetype
raise KeyError('archetype not found')
@staticmethod
def _assign_values(thermal_archetype, catalog_archetype):
thermal_archetype.average_storey_height = catalog_archetype.average_storey_height
thermal_archetype.extra_loses_due_to_thermal_bridges = catalog_archetype.extra_loses_due_to_thermal_bridges
thermal_archetype.thermal_capacity = catalog_archetype.thermal_capacity
thermal_archetype.indirect_heated_ratio = 0
thermal_archetype.infiltration_rate_for_ventilation_system_on = catalog_archetype.infiltration_rate_for_ventilation_system_on
thermal_archetype.infiltration_rate_for_ventilation_system_off = catalog_archetype.infiltration_rate_for_ventilation_system_off
thermal_archetype.infiltration_rate_area_for_ventilation_system_on = catalog_archetype.infiltration_rate_area_for_ventilation_system_on
thermal_archetype.infiltration_rate_area_for_ventilation_system_off = catalog_archetype.infiltration_rate_area_for_ventilation_system_off
_constructions = []
for catalog_construction in catalog_archetype.constructions:
construction = Construction()
construction.type = catalog_construction.type
construction.name = catalog_construction.name
if catalog_construction.window_ratio is not None:
for _orientation in catalog_construction.window_ratio:
if catalog_construction.window_ratio[_orientation] is None:
catalog_construction.window_ratio[_orientation] = 0
construction.window_ratio = catalog_construction.window_ratio
_layers = []
for layer_archetype in catalog_construction.layers:
layer = Layer()
layer.thickness = layer_archetype.thickness
archetype_material = layer_archetype.material
layer.material_name = archetype_material.name
layer.no_mass = archetype_material.no_mass
if archetype_material.no_mass:
layer.thermal_resistance = archetype_material.thermal_resistance
else:
layer.density = archetype_material.density
layer.conductivity = archetype_material.conductivity
layer.specific_heat = archetype_material.specific_heat
layer.solar_absorptance = archetype_material.solar_absorptance
layer.thermal_absorptance = archetype_material.thermal_absorptance
layer.visible_absorptance = archetype_material.visible_absorptance
_layers.append(layer)
construction.layers = _layers
if catalog_construction.window is not None:
window_archetype = catalog_construction.window
construction.window_type = window_archetype.name
construction.window_frame_ratio = window_archetype.frame_ratio
construction.window_g_value = window_archetype.g_value
construction.window_overall_u_value = window_archetype.overall_u_value
_constructions.append(construction)
thermal_archetype.constructions = _constructions

View File

@ -10,6 +10,7 @@ from hub.helpers.utils import validate_import_export_type
from hub.imports.construction.nrcan_physics_parameters import NrcanPhysicsParameters from hub.imports.construction.nrcan_physics_parameters import NrcanPhysicsParameters
from hub.imports.construction.nrel_physics_parameters import NrelPhysicsParameters from hub.imports.construction.nrel_physics_parameters import NrelPhysicsParameters
from hub.imports.construction.eilat_physics_parameters import EilatPhysicsParameters from hub.imports.construction.eilat_physics_parameters import EilatPhysicsParameters
from hub.imports.construction.palma_physics_parameters import PalmaPhysicsParameters
class ConstructionFactory: class ConstructionFactory:
@ -48,6 +49,15 @@ class ConstructionFactory:
for building in self._city.buildings: for building in self._city.buildings:
building.level_of_detail.construction = 2 building.level_of_detail.construction = 2
def _palma(self):
"""
Enrich the city by using Palma information
"""
PalmaPhysicsParameters(self._city).enrich_buildings()
self._city.level_of_detail.construction = 2
for building in self._city.buildings:
building.level_of_detail.construction = 2
def enrich(self): def enrich(self):
""" """
Enrich the city given to the class using the class given handler Enrich the city given to the class using the class given handler

View File

@ -3,6 +3,7 @@ Montreal custom energy system importer
SPDX - License - Identifier: LGPL - 3.0 - or -later SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Project Contributor Saeed Ranjbar saeed.ranjbar@concordia.ca
""" """
import logging import logging
@ -83,9 +84,9 @@ class MontrealCustomEnergySystemParameters:
def _create_generation_systems(archetype_system): def _create_generation_systems(archetype_system):
_generation_systems = [] _generation_systems = []
for archetype_generation_system in archetype_system.generation_systems: for archetype_generation_system in archetype_system.generation_systems:
if archetype_generation_system.system_type == 'Photovoltaic': if archetype_generation_system.system_type == 'photovoltaic':
_generation_system = PvGenerationSystem() _generation_system = PvGenerationSystem()
_type = 'PV system' _type = archetype_generation_system.system_type
_generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[ _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[
_type] _type]
_fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type] _fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type]
@ -136,14 +137,14 @@ class MontrealCustomEnergySystemParameters:
_distribution_system.distribution_consumption_variable_flow = \ _distribution_system.distribution_consumption_variable_flow = \
archetype_distribution_system.distribution_consumption_variable_flow archetype_distribution_system.distribution_consumption_variable_flow
_distribution_system.heat_losses = archetype_distribution_system.heat_losses _distribution_system.heat_losses = archetype_distribution_system.heat_losses
_emission_system = None _generic_emission_system = None
if archetype_distribution_system.emission_systems is not None: if archetype_distribution_system.emission_systems is not None:
_emission_systems = [] _emission_systems = []
for emission_system in archetype_distribution_system.emission_systems: for emission_system in archetype_distribution_system.emission_systems:
_emission_system = EmissionSystem() _generic_emission_system = EmissionSystem()
_emission_system.parasitic_energy_consumption = emission_system.parasitic_energy_consumption _generic_emission_system.parasitic_energy_consumption = emission_system.parasitic_energy_consumption
_emission_systems.append(_emission_system) _emission_systems.append(_generic_emission_system)
_distribution_system.emission_systems = _emission_systems _distribution_system.emission_systems = _emission_systems
_distribution_systems.append(_distribution_system) _distribution_systems.append(_distribution_system)
return _distribution_systems return _distribution_systems

View File

@ -43,6 +43,7 @@ class MontrealFutureEnergySystemParameters:
archetype_name = building.energy_systems_archetype_name archetype_name = building.energy_systems_archetype_name
try: try:
archetype = self._search_archetypes(montreal_custom_catalog, archetype_name) archetype = self._search_archetypes(montreal_custom_catalog, archetype_name)
building.energy_systems_archetype_cluster_id = archetype.cluster_id
except KeyError: except KeyError:
logging.error('Building %s has unknown energy system archetype for system name %s', building.name, logging.error('Building %s has unknown energy system archetype for system name %s', building.name,
archetype_name) archetype_name)
@ -87,12 +88,12 @@ class MontrealFutureEnergySystemParameters:
archetype_generation_systems = archetype_system.generation_systems archetype_generation_systems = archetype_system.generation_systems
if archetype_generation_systems is not None: if archetype_generation_systems is not None:
for archetype_generation_system in archetype_system.generation_systems: for archetype_generation_system in archetype_system.generation_systems:
if archetype_generation_system.system_type == 'Photovoltaic': if archetype_generation_system.system_type == 'photovoltaic':
_generation_system = PvGenerationSystem() _generation_system = PvGenerationSystem()
_generation_system.name = archetype_generation_system.name _generation_system.name = archetype_generation_system.name
_generation_system.model_name = archetype_generation_system.model_name _generation_system.model_name = archetype_generation_system.model_name
_generation_system.manufacturer = archetype_generation_system.manufacturer _generation_system.manufacturer = archetype_generation_system.manufacturer
_type = 'PV system' _type = archetype_generation_system.system_type
_generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type] _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type]
_fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type] _fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type]
_generation_system.fuel_type = _fuel_type _generation_system.fuel_type = _fuel_type
@ -103,15 +104,21 @@ class MontrealFutureEnergySystemParameters:
_generation_system.nominal_radiation = archetype_generation_system.nominal_radiation _generation_system.nominal_radiation = archetype_generation_system.nominal_radiation
_generation_system.standard_test_condition_cell_temperature = archetype_generation_system.standard_test_condition_cell_temperature _generation_system.standard_test_condition_cell_temperature = archetype_generation_system.standard_test_condition_cell_temperature
_generation_system.standard_test_condition_maximum_power = archetype_generation_system.standard_test_condition_maximum_power _generation_system.standard_test_condition_maximum_power = archetype_generation_system.standard_test_condition_maximum_power
_generation_system.standard_test_condition_radiation = archetype_generation_system.standard_test_condition_radiation
_generation_system.cell_temperature_coefficient = archetype_generation_system.cell_temperature_coefficient _generation_system.cell_temperature_coefficient = archetype_generation_system.cell_temperature_coefficient
_generation_system.width = archetype_generation_system.width _generation_system.width = archetype_generation_system.width
_generation_system.height = archetype_generation_system.height _generation_system.height = archetype_generation_system.height
_generation_system.tilt_angle = self._city.latitude _generation_system.tilt_angle = self._city.latitude
_generic_storage_system = None _generic_storage_system = None
if archetype_generation_system.energy_storage_systems is not None: if archetype_generation_system.energy_storage_systems is not None:
_generic_storage_system = ElectricalStorageSystem() _storage_systems = []
_generic_storage_system.type_energy_stored = 'electrical' for storage_system in archetype_generation_system.energy_storage_systems:
_generation_system.energy_storage_systems = [_generic_storage_system] if storage_system.type_energy_stored == 'electrical':
_generic_storage_system = ElectricalStorageSystem()
_generic_storage_system.type_energy_stored = 'electrical'
_storage_systems.append(_generic_storage_system)
_generation_system.energy_storage_systems = _storage_systems
else: else:
_generation_system = NonPvGenerationSystem() _generation_system = NonPvGenerationSystem()
_generation_system.name = archetype_generation_system.name _generation_system.name = archetype_generation_system.name
@ -119,7 +126,7 @@ class MontrealFutureEnergySystemParameters:
_generation_system.manufacturer = archetype_generation_system.manufacturer _generation_system.manufacturer = archetype_generation_system.manufacturer
_type = archetype_generation_system.system_type _type = archetype_generation_system.system_type
_generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type] _generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type]
_fuel_type = Dictionaries().north_america_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type] _fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type]
_generation_system.fuel_type = _fuel_type _generation_system.fuel_type = _fuel_type
_generation_system.nominal_heat_output = archetype_generation_system.nominal_heat_output _generation_system.nominal_heat_output = archetype_generation_system.nominal_heat_output
_generation_system.nominal_cooling_output = archetype_generation_system.nominal_cooling_output _generation_system.nominal_cooling_output = archetype_generation_system.nominal_cooling_output
@ -185,14 +192,14 @@ class MontrealFutureEnergySystemParameters:
_distribution_system.distribution_consumption_variable_flow = \ _distribution_system.distribution_consumption_variable_flow = \
archetype_distribution_system.distribution_consumption_variable_flow archetype_distribution_system.distribution_consumption_variable_flow
_distribution_system.heat_losses = archetype_distribution_system.heat_losses _distribution_system.heat_losses = archetype_distribution_system.heat_losses
_emission_system = None _generic_emission_system = None
if archetype_distribution_system.emission_systems is not None: if archetype_distribution_system.emission_systems is not None:
_emission_systems = [] _emission_systems = []
for emission_system in archetype_distribution_system.emission_systems: for emission_system in archetype_distribution_system.emission_systems:
_emission_system = EmissionSystem() _generic_emission_system = EmissionSystem()
_emission_system.parasitic_energy_consumption = emission_system.parasitic_energy_consumption _generic_emission_system.parasitic_energy_consumption = emission_system.parasitic_energy_consumption
_emission_systems.append(_emission_system) _emission_systems.append(_generic_emission_system)
_distribution_system.emission_systems = _emission_systems _distribution_system.emission_systems = _emission_systems
_distribution_systems.append(_distribution_system) _distribution_systems.append(_distribution_system)
return _distribution_systems return _distribution_systems

View File

@ -0,0 +1,216 @@
"""
Montreal future system importer
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
import logging
import copy
from hub.catalog_factories.energy_systems_catalog_factory import EnergySystemsCatalogFactory
from hub.city_model_structure.energy_systems.energy_system import EnergySystem
from hub.city_model_structure.energy_systems.distribution_system import DistributionSystem
from hub.city_model_structure.energy_systems.non_pv_generation_system import NonPvGenerationSystem
from hub.city_model_structure.energy_systems.pv_generation_system import PvGenerationSystem
from hub.city_model_structure.energy_systems.electrical_storage_system import ElectricalStorageSystem
from hub.city_model_structure.energy_systems.thermal_storage_system import ThermalStorageSystem
from hub.city_model_structure.energy_systems.emission_system import EmissionSystem
from hub.helpers.dictionaries import Dictionaries
class PalmaEnergySystemParameters:
"""
MontrealCustomEnergySystemParameters class
"""
def __init__(self, city):
self._city = city
def enrich_buildings(self):
"""
Returns the city with the system parameters assigned to the buildings
:return:
"""
city = self._city
montreal_custom_catalog = EnergySystemsCatalogFactory('palma').catalog
if city.generic_energy_systems is None:
_generic_energy_systems = {}
else:
_generic_energy_systems = city.generic_energy_systems
for building in city.buildings:
archetype_name = building.energy_systems_archetype_name
try:
archetype = self._search_archetypes(montreal_custom_catalog, archetype_name)
except KeyError:
logging.error('Building %s has unknown energy system archetype for system name %s', building.name,
archetype_name)
continue
if archetype.name not in _generic_energy_systems:
_generic_energy_systems = self._create_generic_systems_list(archetype, _generic_energy_systems)
city.generic_energy_systems = _generic_energy_systems
self._assign_energy_systems_to_buildings(city)
@staticmethod
def _search_archetypes(catalog, name):
archetypes = catalog.entries('archetypes')
for building_archetype in archetypes:
if str(name) == str(building_archetype.name):
return building_archetype
raise KeyError('archetype not found')
def _create_generic_systems_list(self, archetype, _generic_energy_systems):
building_systems = []
for archetype_system in archetype.systems:
energy_system = EnergySystem()
_hub_demand_types = []
for demand_type in archetype_system.demand_types:
_hub_demand_types.append(Dictionaries().montreal_demand_type_to_hub_energy_demand_type[demand_type])
energy_system.name = archetype_system.name
energy_system.demand_types = _hub_demand_types
energy_system.configuration_schema = archetype_system.configuration_schema
energy_system.generation_systems = self._create_generation_systems(archetype_system)
if energy_system.distribution_systems is not None:
energy_system.distribution_systems = self._create_distribution_systems(archetype_system)
building_systems.append(energy_system)
_generic_energy_systems[archetype.name] = building_systems
return _generic_energy_systems
def _create_generation_systems(self, archetype_system):
_generation_systems = []
archetype_generation_systems = archetype_system.generation_systems
if archetype_generation_systems is not None:
for archetype_generation_system in archetype_system.generation_systems:
if archetype_generation_system.system_type == 'photovoltaic':
_generation_system = PvGenerationSystem()
_generation_system.name = archetype_generation_system.name
_generation_system.model_name = archetype_generation_system.model_name
_generation_system.manufacturer = archetype_generation_system.manufacturer
_type = archetype_generation_system.system_type
_generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type]
_fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type]
_generation_system.fuel_type = _fuel_type
_generation_system.electricity_efficiency = archetype_generation_system.electricity_efficiency
_generation_system.nominal_electricity_output = archetype_generation_system.nominal_electricity_output
_generation_system.nominal_ambient_temperature = archetype_generation_system.nominal_ambient_temperature
_generation_system.nominal_cell_temperature = archetype_generation_system.nominal_cell_temperature
_generation_system.nominal_radiation = archetype_generation_system.nominal_radiation
_generation_system.standard_test_condition_cell_temperature = archetype_generation_system.standard_test_condition_cell_temperature
_generation_system.standard_test_condition_maximum_power = archetype_generation_system.standard_test_condition_maximum_power
_generation_system.standard_test_condition_radiation = archetype_generation_system.standard_test_condition_radiation
_generation_system.cell_temperature_coefficient = archetype_generation_system.cell_temperature_coefficient
_generation_system.width = archetype_generation_system.width
_generation_system.height = archetype_generation_system.height
_generation_system.tilt_angle = self._city.latitude
_generic_storage_system = None
if archetype_generation_system.energy_storage_systems is not None:
_storage_systems = []
for storage_system in archetype_generation_system.energy_storage_systems:
if storage_system.type_energy_stored == 'electrical':
_generic_storage_system = ElectricalStorageSystem()
_generic_storage_system.type_energy_stored = 'electrical'
_storage_systems.append(_generic_storage_system)
_generation_system.energy_storage_systems = _storage_systems
else:
_generation_system = NonPvGenerationSystem()
_generation_system.name = archetype_generation_system.name
_generation_system.model_name = archetype_generation_system.model_name
_generation_system.manufacturer = archetype_generation_system.manufacturer
_type = archetype_generation_system.system_type
_generation_system.system_type = Dictionaries().montreal_generation_system_to_hub_energy_generation_system[_type]
_fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[archetype_generation_system.fuel_type]
_generation_system.fuel_type = _fuel_type
_generation_system.nominal_heat_output = archetype_generation_system.nominal_heat_output
_generation_system.nominal_cooling_output = archetype_generation_system.nominal_cooling_output
_generation_system.maximum_heat_output = archetype_generation_system.maximum_heat_output
_generation_system.minimum_heat_output = archetype_generation_system.minimum_heat_output
_generation_system.maximum_cooling_output = archetype_generation_system.maximum_cooling_output
_generation_system.minimum_cooling_output = archetype_generation_system.minimum_cooling_output
_generation_system.source_temperature = archetype_generation_system.source_temperature
_generation_system.source_mass_flow = archetype_generation_system.source_mass_flow
_generation_system.supply_medium = archetype_generation_system.supply_medium
_generation_system.maximum_heat_supply_temperature = archetype_generation_system.maximum_heat_supply_temperature
_generation_system.maximum_cooling_supply_temperature = archetype_generation_system.maximum_cooling_supply_temperature
_generation_system.minimum_heat_supply_temperature = archetype_generation_system.minimum_heat_supply_temperature
_generation_system.minimum_cooling_supply_temperature = archetype_generation_system.minimum_cooling_supply_temperature
_generation_system.heat_output_curve = archetype_generation_system.heat_output_curve
_generation_system.heat_fuel_consumption_curve = archetype_generation_system.heat_fuel_consumption_curve
_generation_system.heat_efficiency_curve = archetype_generation_system.heat_efficiency_curve
_generation_system.cooling_output_curve = archetype_generation_system.cooling_output_curve
_generation_system.cooling_fuel_consumption_curve = archetype_generation_system.cooling_fuel_consumption_curve
_generation_system.cooling_efficiency_curve = archetype_generation_system.cooling_efficiency_curve
_generation_system.domestic_hot_water = archetype_generation_system.domestic_hot_water
_generation_system.nominal_electricity_output = archetype_generation_system.nominal_electricity_output
_generation_system.source_medium = archetype_generation_system.source_medium
_generation_system.heat_efficiency = archetype_generation_system.heat_efficiency
_generation_system.cooling_efficiency = archetype_generation_system.cooling_efficiency
_generation_system.electricity_efficiency = archetype_generation_system.electricity_efficiency
_generation_system.reversibility = archetype_generation_system.reversibility
_generic_storage_system = None
if archetype_generation_system.energy_storage_systems is not None:
_storage_systems = []
for storage_system in archetype_generation_system.energy_storage_systems:
if storage_system.type_energy_stored == 'electrical':
_generic_storage_system = ElectricalStorageSystem()
_generic_storage_system.type_energy_stored = 'electrical'
else:
_generic_storage_system = ThermalStorageSystem()
_generic_storage_system.type_energy_stored = storage_system.type_energy_stored
_generic_storage_system.height = storage_system.height
_generic_storage_system.layers = storage_system.layers
_generic_storage_system.storage_medium = storage_system.storage_medium
_generic_storage_system.heating_coil_capacity = storage_system.heating_coil_capacity
_storage_systems.append(_generic_storage_system)
_generation_system.energy_storage_systems = _storage_systems
if archetype_generation_system.domestic_hot_water:
_generation_system.domestic_hot_water = True
if archetype_generation_system.reversibility:
_generation_system.reversibility = True
if archetype_generation_system.simultaneous_heat_cold:
_generation_system.simultaneous_heat_cold = True
_generation_systems.append(_generation_system)
return _generation_systems
@staticmethod
def _create_distribution_systems(archetype_system):
_distribution_systems = []
archetype_distribution_systems = archetype_system.distribution_systems
if archetype_distribution_systems is not None:
for archetype_distribution_system in archetype_system.distribution_systems:
_distribution_system = DistributionSystem()
_distribution_system.type = archetype_distribution_system.type
_distribution_system.distribution_consumption_fix_flow = \
archetype_distribution_system.distribution_consumption_fix_flow
_distribution_system.distribution_consumption_variable_flow = \
archetype_distribution_system.distribution_consumption_variable_flow
_distribution_system.heat_losses = archetype_distribution_system.heat_losses
_generic_emission_system = None
if archetype_distribution_system.emission_systems is not None:
_emission_systems = []
for emission_system in archetype_distribution_system.emission_systems:
_generic_emission_system = EmissionSystem()
_generic_emission_system.parasitic_energy_consumption = emission_system.parasitic_energy_consumption
_emission_systems.append(_generic_emission_system)
_distribution_system.emission_systems = _emission_systems
_distribution_systems.append(_distribution_system)
return _distribution_systems
@staticmethod
def _assign_energy_systems_to_buildings(city):
for building in city.buildings:
_building_energy_systems = []
energy_systems_cluster_name = building.energy_systems_archetype_name
if str(energy_systems_cluster_name) == 'nan':
break
_generic_building_energy_systems = city.generic_energy_systems[energy_systems_cluster_name]
for _generic_building_energy_system in _generic_building_energy_systems:
_building_energy_systems.append(copy.deepcopy(_generic_building_energy_system))
building.energy_systems = _building_energy_systems

View File

@ -11,6 +11,7 @@ from hub.helpers.utils import validate_import_export_type
from hub.imports.energy_systems.montreal_custom_energy_system_parameters import MontrealCustomEnergySystemParameters from hub.imports.energy_systems.montreal_custom_energy_system_parameters import MontrealCustomEnergySystemParameters
from hub.imports.energy_systems.north_america_custom_energy_system_parameters import NorthAmericaCustomEnergySystemParameters from hub.imports.energy_systems.north_america_custom_energy_system_parameters import NorthAmericaCustomEnergySystemParameters
from hub.imports.energy_systems.montreal_future_energy_systems_parameters import MontrealFutureEnergySystemParameters from hub.imports.energy_systems.montreal_future_energy_systems_parameters import MontrealFutureEnergySystemParameters
from hub.imports.energy_systems.palma_energy_systems_parameters import PalmaEnergySystemParameters
class EnergySystemsFactory: class EnergySystemsFactory:
""" """
@ -52,6 +53,15 @@ class EnergySystemsFactory:
for building in self._city.buildings: for building in self._city.buildings:
building.level_of_detail.energy_systems = 2 building.level_of_detail.energy_systems = 2
def _palma(self):
"""
Enrich the city by using north america custom energy systems catalog information
"""
PalmaEnergySystemParameters(self._city).enrich_buildings()
self._city.level_of_detail.energy_systems = 2
for building in self._city.buildings:
building.level_of_detail.energy_systems = 2
def enrich(self): def enrich(self):
""" """
Enrich the city given to the class using the class given handler Enrich the city given to the class using the class given handler

View File

@ -35,6 +35,8 @@ class Geojson:
year_of_construction_field=None, year_of_construction_field=None,
function_field=None, function_field=None,
function_to_hub=None, function_to_hub=None,
usages_field=None,
usages_to_hub=None,
hub_crs=None hub_crs=None
): ):
self._hub_crs = hub_crs self._hub_crs = hub_crs
@ -52,6 +54,8 @@ class Geojson:
self._year_of_construction_field = year_of_construction_field self._year_of_construction_field = year_of_construction_field
self._function_field = function_field self._function_field = function_field
self._function_to_hub = function_to_hub self._function_to_hub = function_to_hub
self._usages_field = usages_field
self._usages_to_hub = usages_to_hub
with open(path, 'r', encoding='utf8') as json_file: with open(path, 'r', encoding='utf8') as json_file:
self._geojson = json.loads(json_file.read()) self._geojson = json.loads(json_file.read())
@ -117,45 +121,36 @@ class Geojson:
lod = 0 lod = 0
for feature in self._geojson['features']: for feature in self._geojson['features']:
extrusion_height = 0 extrusion_height = 0
if self._extrusion_height_field is not None: if self._extrusion_height_field is not None:
extrusion_height = float(feature['properties'][self._extrusion_height_field]) extrusion_height = float(feature['properties'][self._extrusion_height_field])
lod = 1 lod = 1
self._max_z = max(self._max_z, extrusion_height) self._max_z = max(self._max_z, extrusion_height)
year_of_construction = None year_of_construction = None
if self._year_of_construction_field is not None: if self._year_of_construction_field is not None:
year_of_construction = int(feature['properties'][self._year_of_construction_field]) year_of_construction = int(feature['properties'][self._year_of_construction_field])
function = None function = None
if self._function_field is not None: if self._function_field is not None:
function = str(feature['properties'][self._function_field]) function = str(feature['properties'][self._function_field])
if function == 'Mixed use' or function == 'mixed use':
function_parts = []
if 'usages' in feature['properties']:
usages = feature['properties']['usages']
for usage in usages:
if self._function_to_hub is not None and usage['usage'] in self._function_to_hub:
function_parts.append(f"{usage['percentage']}-{self._function_to_hub[usage['usage']]}")
else:
function_parts.append(f"{usage['percentage']}-{usage['usage']}")
else:
for key, value in feature['properties'].items():
if key.startswith("mixed_type_") and not key.endswith("_percentage"):
type_key = key
percentage_key = f"{key}_percentage"
if percentage_key in feature['properties']:
if self._function_to_hub is not None and feature['properties'][type_key] in self._function_to_hub:
usage_function = self._function_to_hub[feature['properties'][type_key]]
function_parts.append(f"{feature['properties'][percentage_key]}-{usage_function}")
else:
function_parts.append(f"{feature['properties'][percentage_key]}-{feature['properties'][type_key]}")
function = "_".join(function_parts)
if self._function_to_hub is not None: if self._function_to_hub is not None:
# use the transformation dictionary to retrieve the proper function
if function in self._function_to_hub: if function in self._function_to_hub:
function = self._function_to_hub[function] function = self._function_to_hub[function]
usages = None
if self._usages_field is not None:
if self._usages_field in feature['properties']:
usages = feature['properties'][self._usages_field]
if self._usages_to_hub is not None:
usages = self._usages_to_hub(usages)
geometry = feature['geometry'] geometry = feature['geometry']
building_aliases = [] building_aliases = []
if 'id' in feature: if 'id' in feature:
building_name = feature['id'] building_name = feature['id']
elif 'id' in feature['properties']:
building_name = feature['properties']['id']
else: else:
building_name = uuid.uuid4() building_name = uuid.uuid4()
if self._aliases_field is not None: if self._aliases_field is not None:
@ -168,6 +163,7 @@ class Geojson:
building_name, building_name,
building_aliases, building_aliases,
function, function,
usages,
year_of_construction, year_of_construction,
extrusion_height)) extrusion_height))
@ -176,6 +172,7 @@ class Geojson:
building_name, building_name,
building_aliases, building_aliases,
function, function,
usages,
year_of_construction, year_of_construction,
extrusion_height)) extrusion_height))
else: else:
@ -201,7 +198,7 @@ class Geojson:
transformed_coordinates = f'{transformed_coordinates} {transformed[self._X]} {transformed[self._Y]} 0.0' transformed_coordinates = f'{transformed_coordinates} {transformed[self._X]} {transformed[self._Y]} 0.0'
return transformed_coordinates.lstrip(' ') return transformed_coordinates.lstrip(' ')
def _parse_polygon(self, coordinates, building_name, building_aliases, function, year_of_construction, extrusion_height): def _parse_polygon(self, coordinates, building_name, building_aliases, function, usages, year_of_construction, extrusion_height):
surfaces = [] surfaces = []
for polygon_coordinates in coordinates: for polygon_coordinates in coordinates:
points = igh.points_from_string( points = igh.points_from_string(
@ -234,7 +231,7 @@ class Geojson:
polygon = Polygon(coordinates) polygon = Polygon(coordinates)
polygon.area = igh.ground_area(coordinates) polygon.area = igh.ground_area(coordinates)
surfaces[-1] = Surface(polygon, polygon) surfaces[-1] = Surface(polygon, polygon)
building = Building(f'{building_name}', surfaces, year_of_construction, function) building = Building(f'{building_name}', surfaces, year_of_construction, function, usages=usages)
for alias in building_aliases: for alias in building_aliases:
building.add_alias(alias) building.add_alias(alias)
if extrusion_height == 0: if extrusion_height == 0:
@ -269,13 +266,13 @@ class Geojson:
polygon = Polygon(wall_coordinates) polygon = Polygon(wall_coordinates)
wall = Surface(polygon, polygon) wall = Surface(polygon, polygon)
surfaces.append(wall) surfaces.append(wall)
building = Building(f'{building_name}', surfaces, year_of_construction, function) building = Building(f'{building_name}', surfaces, year_of_construction, function, usages=usages)
for alias in building_aliases: for alias in building_aliases:
building.add_alias(alias) building.add_alias(alias)
building.volume = volume building.volume = volume
return building return building
def _parse_multi_polygon(self, polygons_coordinates, building_name, building_aliases, function, year_of_construction, extrusion_height): def _parse_multi_polygon(self, polygons_coordinates, building_name, building_aliases, function, usages, year_of_construction, extrusion_height):
surfaces = [] surfaces = []
for coordinates in polygons_coordinates: for coordinates in polygons_coordinates:
for polygon_coordinates in coordinates: for polygon_coordinates in coordinates:
@ -308,7 +305,7 @@ class Geojson:
polygon = Polygon(coordinates) polygon = Polygon(coordinates)
polygon.area = igh.ground_area(coordinates) polygon.area = igh.ground_area(coordinates)
surfaces[-1] = Surface(polygon, polygon) surfaces[-1] = Surface(polygon, polygon)
building = Building(f'{building_name}', surfaces, year_of_construction, function) building = Building(f'{building_name}', surfaces, year_of_construction, function, usages=usages)
for alias in building_aliases: for alias in building_aliases:
building.add_alias(alias) building.add_alias(alias)
if extrusion_height == 0: if extrusion_height == 0:
@ -343,7 +340,7 @@ class Geojson:
polygon = Polygon(wall_coordinates) polygon = Polygon(wall_coordinates)
wall = Surface(polygon, polygon) wall = Surface(polygon, polygon)
surfaces.append(wall) surfaces.append(wall)
building = Building(f'{building_name}', surfaces, year_of_construction, function) building = Building(f'{building_name}', surfaces, year_of_construction, function, usages=usages)
for alias in building_aliases: for alias in building_aliases:
building.add_alias(alias) building.add_alias(alias)
building.volume = volume building.volume = volume

View File

@ -23,6 +23,8 @@ class GeometryFactory:
year_of_construction_field=None, year_of_construction_field=None,
function_field=None, function_field=None,
function_to_hub=None, function_to_hub=None,
usages_field=None,
usages_to_hub=None,
hub_crs=None): hub_crs=None):
self._file_type = '_' + file_type.lower() self._file_type = '_' + file_type.lower()
validate_import_export_type(GeometryFactory, file_type) validate_import_export_type(GeometryFactory, file_type)
@ -32,6 +34,8 @@ class GeometryFactory:
self._year_of_construction_field = year_of_construction_field self._year_of_construction_field = year_of_construction_field
self._function_field = function_field self._function_field = function_field
self._function_to_hub = function_to_hub self._function_to_hub = function_to_hub
self._usages_field = usages_field
self._usages_to_hub = usages_to_hub
self._hub_crs = hub_crs self._hub_crs = hub_crs
@property @property
@ -66,6 +70,8 @@ class GeometryFactory:
self._year_of_construction_field, self._year_of_construction_field,
self._function_field, self._function_field,
self._function_to_hub, self._function_to_hub,
self._usages_field,
self._usages_to_hub,
self._hub_crs).city self._hub_crs).city
@property @property

View File

@ -1,14 +1,12 @@
""" """
Insel monthly energy balance Cerc Idf result import
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 Saeed Ranjbar saeed.ranjbar@concordia.ca Project Coder Guille Guillermo.GutierrezMorote@concordia.ca
Project collaborator Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
""" """
from pathlib import Path
import csv import csv
from hub.helpers.monthly_values import MonthlyValues
import hub.helpers.constants as cte import hub.helpers.constants as cte
@ -16,62 +14,33 @@ class EnergyPlus:
""" """
Energy plus class Energy plus class
""" """
def __init__(self, city, base_path):
def _extract_fields_from_headers(self, headers):
for header in headers:
header_parts = header.split(':')
building_name = header_parts[0]
variable = ':'.join(header_parts[1:]).strip() # concat the rest and ensure that : it's reintroduced just in case
if variable == '':
continue
if building_name not in self._summary_variables:
self._building_energy_demands[variable] = [] # initialize the list of variables
else:
self._building_energy_demands[header] = []
def __init__(self, city, file_path):
self._city = city self._city = city
self._base_path = base_path self._building_energy_demands = {}
self._lines = []
self._summary_variables = ['DistrictCooling:Facility [J](Hourly)',
'InteriorEquipment:Electricity [J](Hourly)',
'InteriorLights:Electricity [J](Hourly) ']
@staticmethod with open(file_path, 'r', encoding='utf8') as csv_file:
def _building_energy_demands(energy_plus_output_file_path):
with open(Path(energy_plus_output_file_path).resolve(), 'r', encoding='utf8') as csv_file:
csv_output = csv.reader(csv_file) csv_output = csv.reader(csv_file)
headers = next(csv_output) self._headers = next(csv_output)
building_energy_demands = { self._extract_fields_from_headers(self._headers)
'Heating (J)': [],
'Cooling (J)': [],
'DHW (J)': [],
'Appliances (J)': [],
'Lighting (J)': []
}
heating_column_index = []
cooling_column_index = []
dhw_column_index = []
appliance_column_index = []
lighting_column_index = []
for index, header in enumerate(headers):
if "Total Heating" in header:
heating_column_index.append(index)
elif "Total Cooling" in header:
cooling_column_index.append(index)
elif "DHW" in header:
dhw_column_index.append(index)
elif "InteriorEquipment" in header:
appliance_column_index.append(index)
elif "InteriorLights" in header:
lighting_column_index.append(index)
for line in csv_output: for line in csv_output:
total_heating_demand = 0 self._lines.append(line)
total_cooling_demand = 0
total_dhw_demand = 0
total_appliance_demand = 0
total_lighting_demand = 0
for heating_index in heating_column_index:
total_heating_demand += float(line[heating_index])
building_energy_demands['Heating (J)'].append(total_heating_demand)
for cooling_index in cooling_column_index:
total_cooling_demand += float(line[cooling_index])
building_energy_demands['Cooling (J)'].append(total_cooling_demand)
for dhw_index in dhw_column_index:
total_dhw_demand += float(line[dhw_index]) * 3600
building_energy_demands['DHW (J)'].append(total_dhw_demand)
for appliance_index in appliance_column_index:
total_appliance_demand += float(line[appliance_index])
building_energy_demands['Appliances (J)'].append(total_appliance_demand)
for lighting_index in lighting_column_index:
total_lighting_demand += float(line[lighting_index])
building_energy_demands['Lighting (J)'].append(total_lighting_demand)
return building_energy_demands
def enrich(self): def enrich(self):
""" """
@ -79,27 +48,58 @@ class EnergyPlus:
:return: None :return: None
""" """
for building in self._city.buildings: for building in self._city.buildings:
file_name = f'{building.name}_out.csv' _energy_demands = {}
energy_plus_output_file_path = Path(self._base_path / file_name).resolve() for header in self._building_energy_demands:
if energy_plus_output_file_path.is_file(): print(header)
building_energy_demands = self._building_energy_demands(energy_plus_output_file_path) if header == 'Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)':
building.heating_demand[cte.HOUR] = building_energy_demands['Heating (J)'] field_name = f'{building.name} IDEAL LOADS AIR SYSTEM:{header}'
building.cooling_demand[cte.HOUR] = building_energy_demands['Cooling (J)'] elif header == 'Zone Ideal Loads Supply Air Total Cooling Energy [J](Hourly)':
building.domestic_hot_water_heat_demand[cte.HOUR] = building_energy_demands['DHW (J)'] field_name = f'{building.name} IDEAL LOADS AIR SYSTEM:{header}'
building.appliances_electrical_demand[cte.HOUR] = building_energy_demands['Appliances (J)'] else:
building.lighting_electrical_demand[cte.HOUR] = building_energy_demands['Lighting (J)'] field_name = f'{building.name}:{header}'
# todo: @Saeed, this a list of ONE value with the total energy of the year, exactly the same as cte.YEAR. position = -1
# You have to use the method to add hourly values from helpers/monthly_values if field_name in self._headers:
building.heating_demand[cte.MONTH] = MonthlyValues.get_total_month(building.heating_demand[cte.HOUR]) position = self._headers.index(field_name)
building.cooling_demand[cte.MONTH] = MonthlyValues.get_total_month(building.cooling_demand[cte.HOUR]) if position == -1:
building.domestic_hot_water_heat_demand[cte.MONTH] = ( continue
MonthlyValues.get_total_month(building.domestic_hot_water_heat_demand[cte.HOUR])) for line in self._lines:
building.appliances_electrical_demand[cte.MONTH] = ( if header not in _energy_demands.keys():
MonthlyValues.get_total_month(building.appliances_electrical_demand[cte.HOUR])) _energy_demands[header] = []
building.lighting_electrical_demand[cte.MONTH] = ( _energy_demands[header].append(line[position])
MonthlyValues.get_total_month(building.lighting_electrical_demand[cte.HOUR])) # print(building_energy_demands['Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)'])
building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.MONTH])] EnergyPlus._set_building_demands(building, _energy_demands)
building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.MONTH])]
building.domestic_hot_water_heat_demand[cte.YEAR] = [sum(building.domestic_hot_water_heat_demand[cte.MONTH])] @staticmethod
building.appliances_electrical_demand[cte.YEAR] = [sum(building.appliances_electrical_demand[cte.MONTH])] def _set_building_demands(building, energy_demands):
building.lighting_electrical_demand[cte.YEAR] = [sum(building.lighting_electrical_demand[cte.MONTH])] print(energy_demands.keys())
heating = [float(x) for x in energy_demands['Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)']]
cooling = [float(x) for x in energy_demands['Zone Ideal Loads Supply Air Total Cooling Energy [J](Hourly)']]
dhw = [float(x) * cte.WATTS_HOUR_TO_JULES for x in energy_demands['Water Use Equipment Heating Rate [W](Hourly)']]
appliances = [float(x) * cte.WATTS_HOUR_TO_JULES for x in energy_demands['Other Equipment Electricity Rate [W](Hourly)']]
lighting = [float(x) * cte.WATTS_HOUR_TO_JULES for x in energy_demands['Zone Lights Electricity Rate [W](Hourly)']]
building.heating_demand[cte.HOUR] = heating
building.cooling_demand[cte.HOUR] = cooling
building.domestic_hot_water_heat_demand[cte.HOUR] = dhw
building.appliances_electrical_demand[cte.HOUR] = appliances
building.lighting_electrical_demand[cte.HOUR] = lighting
building.heating_demand[cte.MONTH] = []
building.cooling_demand[cte.MONTH] = []
building.domestic_hot_water_heat_demand[cte.MONTH] = []
building.appliances_electrical_demand[cte.MONTH] = []
building.lighting_electrical_demand[cte.MONTH] = []
start = 0
for hours in cte.HOURS_A_MONTH.values():
end = hours + start
building.heating_demand[cte.MONTH].append(sum(building.heating_demand[cte.HOUR][start: end]))
building.cooling_demand[cte.MONTH].append(sum(building.cooling_demand[cte.HOUR][start: end]))
building.domestic_hot_water_heat_demand[cte.MONTH].append(sum(dhw[start: end]))
building.appliances_electrical_demand[cte.MONTH].append(sum(appliances[start: end]))
building.lighting_electrical_demand[cte.MONTH].append(sum(lighting[start: end]))
start = end
building.heating_demand[cte.YEAR] = [sum(building.heating_demand[cte.HOUR])]
building.cooling_demand[cte.YEAR] = [sum(building.cooling_demand[cte.HOUR])]
building.domestic_hot_water_heat_demand[cte.YEAR] = [sum(building.domestic_hot_water_heat_demand[cte.HOUR])]
building.appliances_electrical_demand[cte.YEAR] = [sum(building.appliances_electrical_demand[cte.HOUR])]
building.lighting_electrical_demand[cte.YEAR] = [sum(building.lighting_electrical_demand[cte.HOUR])]

View File

@ -22,9 +22,11 @@ class EnergyPlusMultipleBuildings:
with open(Path(energy_plus_output_file_path).resolve(), 'r', encoding='utf8') as csv_file: with open(Path(energy_plus_output_file_path).resolve(), 'r', encoding='utf8') as csv_file:
csv_output = list(csv.DictReader(csv_file)) csv_output = list(csv.DictReader(csv_file))
print(csv_output)
return
for building in self._city.buildings: for building in self._city.buildings:
building_name = building.name.upper() building_name = building.name.upper()
buildings_energy_demands[f'Building {building_name} Heating Demand (J)'] = [ buildings_energy_demands[f'Building {building_name} Heating Demand (J)'] = [
float( float(
row[f"{building_name} IDEAL LOADS AIR SYSTEM:Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)"]) row[f"{building_name} IDEAL LOADS AIR SYSTEM:Zone Ideal Loads Supply Air Total Heating Energy [J](Hourly)"])

View File

@ -8,6 +8,7 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
from pathlib import Path from pathlib import Path
from hub.helpers.utils import validate_import_export_type from hub.helpers.utils import validate_import_export_type
from hub.imports.results.energy_plus import EnergyPlus
from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance
from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
@ -60,6 +61,9 @@ class ResultFactory:
""" """
EnergyPlusMultipleBuildings(self._city, self._base_path).enrich() EnergyPlusMultipleBuildings(self._city, self._base_path).enrich()
def _cerc_idf(self):
EnergyPlus(self._city, self._base_path).enrich()
def enrich(self): def enrich(self):
""" """
Enrich the city given to the class using the usage factory given handler Enrich the city given to the class using the usage factory given handler

View File

@ -38,38 +38,36 @@ class ComnetUsageParameters:
city = self._city city = self._city
comnet_catalog = UsageCatalogFactory('comnet').catalog comnet_catalog = UsageCatalogFactory('comnet').catalog
for building in city.buildings: for building in city.buildings:
usages = []
comnet_archetype_usages = [] comnet_archetype_usages = []
building_functions = building.function.split('_') usages = building.usages
for function in building_functions:
usages.append(function.split('-'))
for usage in usages: for usage in usages:
comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[usage[-1]] comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[usage['usage']]
try: try:
comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name) comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name)
comnet_archetype_usages.append(comnet_archetype_usage) comnet_archetype_usages.append(comnet_archetype_usage)
except KeyError: except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, comnet_usage_name) logging.error('Building %s has unknown usage archetype for usage %s', building.name, comnet_usage_name)
continue continue
for (i, internal_zone) in enumerate(building.internal_zones): for (i, internal_zone) in enumerate(building.internal_zones):
internal_zone_usages = [] internal_zone_usages = []
if len(building.internal_zones) > 1: if len(building.internal_zones) > 1:
volume_per_area = 0 volume_per_area = 0
if internal_zone.area is None: if internal_zone.area is None:
logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s', logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s',
building.name, usages[i][-1]) building.name, usages[i]['usage'])
continue continue
if internal_zone.volume is None: if internal_zone.volume is None:
logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s', logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s',
building.name, usages[i][-1]) building.name, usages[i]['usage'])
continue continue
if internal_zone.area <= 0: if internal_zone.area <= 0:
logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s', logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s',
building.name, usages[i][-1]) building.name, usages[i]['usage'])
continue continue
volume_per_area += internal_zone.volume / internal_zone.area volume_per_area += internal_zone.volume / internal_zone.area
usage = Usage() usage = Usage()
usage.name = usages[i][-1] usage.name = usages[i]['usage']
self._assign_values(usage, comnet_archetype_usages[i], volume_per_area, building.cold_water_temperature) self._assign_values(usage, comnet_archetype_usages[i], volume_per_area, building.cold_water_temperature)
usage.percentage = 1 usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, comnet_archetype_usages[i]) self._calculate_reduced_values_from_extended_library(usage, comnet_archetype_usages[i])
@ -80,20 +78,24 @@ class ComnetUsageParameters:
logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for usage %s. ' logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for usage %s. '
'NRCAN construction data for the year %s is used to calculated number of storeys above ' 'NRCAN construction data for the year %s is used to calculated number of storeys above '
'ground', building.name, usages, building.year_of_construction) 'ground', building.name, usages, building.year_of_construction)
storeys_above_ground = self.average_storey_height_calculator(self._city, building) try:
storeys_above_ground = self.average_storey_height_calculator(self._city, building)
except ValueError as e:
logging.error(e)
continue
volume_per_area = building.volume / building.floor_area / storeys_above_ground volume_per_area = building.volume / building.floor_area / storeys_above_ground
for (j, mixed_usage) in enumerate(usages): for j, usage_type in enumerate(usages):
usage = Usage() usage = Usage()
usage.name = mixed_usage[-1] usage.name = usage_type['usage']
if len(usages) > 1: usage.percentage = float(usage_type['ratio'])
usage.percentage = float(mixed_usage[0]) / 100
else:
usage.percentage = 1
self._assign_values(usage, comnet_archetype_usages[j], volume_per_area, building.cold_water_temperature) self._assign_values(usage, comnet_archetype_usages[j], volume_per_area, building.cold_water_temperature)
self._calculate_reduced_values_from_extended_library(usage, comnet_archetype_usages[j]) self._calculate_reduced_values_from_extended_library(usage, comnet_archetype_usages[j])
internal_zone_usages.append(usage) internal_zone_usages.append(usage)
internal_zone.usages = internal_zone_usages internal_zone.usages = internal_zone_usages
@staticmethod @staticmethod
def _search_archetypes(comnet_catalog, usage_name): def _search_archetypes(comnet_catalog, usage_name):
comnet_archetypes = comnet_catalog.entries('archetypes').usages comnet_archetypes = comnet_catalog.entries('archetypes').usages
@ -270,20 +272,11 @@ class ComnetUsageParameters:
def average_storey_height_calculator(city, building): def average_storey_height_calculator(city, building):
climate_zone = ConstructionHelper.city_to_nrcan_climate_zone(city.climate_reference_city) climate_zone = ConstructionHelper.city_to_nrcan_climate_zone(city.climate_reference_city)
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
main_function = None
functions = building.function.split('_') if building.function not in Dictionaries().hub_function_to_nrcan_construction_function:
if len(functions) > 1: raise ValueError('Building %s has an unknown building function %s', building.name, building.function)
maximum_percentage = 0
for function in functions: function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
percentage_and_function = function.split('-')
if float(percentage_and_function[0]) > maximum_percentage:
maximum_percentage = float(percentage_and_function[0])
main_function = percentage_and_function[-1]
else:
main_function = functions[-1]
if main_function not in Dictionaries().hub_function_to_nrcan_construction_function:
logging.error('Building %s has an unknown building function %s', building.name, main_function)
function = Dictionaries().hub_function_to_nrcan_construction_function[main_function]
construction_archetype = None construction_archetype = None
average_storey_height = None average_storey_height = None
nrcan_archetypes = nrcan_catalog.entries('archetypes') nrcan_archetypes = nrcan_catalog.entries('archetypes')
@ -294,7 +287,7 @@ class ComnetUsageParameters:
construction_archetype = building_archetype construction_archetype = building_archetype
average_storey_height = building_archetype.average_storey_height average_storey_height = building_archetype.average_storey_height
if construction_archetype is None: if construction_archetype is None:
logging.error('Building %s has unknown construction archetype for building function: %s ' raise ValueError('Building %s has unknown construction archetype for building function: %s '
'[%s], building year of construction: %s and climate zone %s', building.name, function, '[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, climate_zone) building.function, building.year_of_construction, climate_zone)

View File

@ -37,21 +37,18 @@ class NrcanUsageParameters:
nrcan_catalog = UsageCatalogFactory('nrcan').catalog nrcan_catalog = UsageCatalogFactory('nrcan').catalog
comnet_catalog = UsageCatalogFactory('comnet').catalog comnet_catalog = UsageCatalogFactory('comnet').catalog
for building in city.buildings: for building in city.buildings:
usages = []
nrcan_archetype_usages = [] nrcan_archetype_usages = []
comnet_archetype_usages = [] comnet_archetype_usages = []
building_functions = building.function.split('_') usages = building.usages
for function in building_functions:
usages.append(function.split('-'))
for usage in usages: for usage in usages:
usage_name = Dictionaries().hub_usage_to_nrcan_usage[usage[-1]] usage_name = Dictionaries().hub_usage_to_nrcan_usage[usage['usage']]
try: try:
archetype_usage = self._search_archetypes(nrcan_catalog, usage_name) archetype_usage = self._search_archetypes(nrcan_catalog, usage_name)
nrcan_archetype_usages.append(archetype_usage) nrcan_archetype_usages.append(archetype_usage)
except KeyError: except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name) logging.error('Building %s has unknown usage archetype for usage %s', building.name, usage_name)
continue continue
comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[usage[-1]] comnet_usage_name = Dictionaries().hub_usage_to_comnet_usage[usage['usage']]
try: try:
comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name) comnet_archetype_usage = self._search_archetypes(comnet_catalog, comnet_usage_name)
comnet_archetype_usages.append(comnet_archetype_usage) comnet_archetype_usages.append(comnet_archetype_usage)
@ -65,19 +62,19 @@ class NrcanUsageParameters:
volume_per_area = 0 volume_per_area = 0
if internal_zone.area is None: if internal_zone.area is None:
logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s', logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s',
building.name, usages[i][-1]) building.name, usages[i]['usage'])
continue continue
if internal_zone.volume is None: if internal_zone.volume is None:
logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s', logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s',
building.name, usages[i][-1]) building.name, usages[i]['usage'])
continue continue
if internal_zone.area <= 0: if internal_zone.area <= 0:
logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s', logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s',
building.name, usages[i][-1]) building.name, usages[i]['usage'])
continue continue
volume_per_area += internal_zone.volume / internal_zone.area volume_per_area += internal_zone.volume / internal_zone.area
usage = Usage() usage = Usage()
usage.name = usages[i][-1] usage.name = usages[i]['usage']
self._assign_values(usage, nrcan_archetype_usages[i], volume_per_area, building.cold_water_temperature) self._assign_values(usage, nrcan_archetype_usages[i], volume_per_area, building.cold_water_temperature)
self._assign_comnet_extra_values(usage, comnet_archetype_usages[i], nrcan_archetype_usages[i].occupancy.occupancy_density) self._assign_comnet_extra_values(usage, comnet_archetype_usages[i], nrcan_archetype_usages[i].occupancy.occupancy_density)
usage.percentage = 1 usage.percentage = 1
@ -86,19 +83,21 @@ class NrcanUsageParameters:
else: else:
storeys_above_ground = building.storeys_above_ground storeys_above_ground = building.storeys_above_ground
if storeys_above_ground is None: if storeys_above_ground is None:
logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for usage %s. ' logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for function %s. '
'NRCAN construction data for the year %s is used to calculated number of storeys above ' 'NRCAN construction data for the year %s is used to calculated number of storeys above '
'ground', building.name, usages, building.year_of_construction) 'ground', building.name, building.function, building.year_of_construction)
storeys_above_ground = self.average_storey_height_calculator(self._city, building) try:
continue storeys_above_ground = self.average_storey_height_calculator(self._city, building)
except ValueError as e:
logging.error(e)
continue
volume_per_area = building.volume / building.floor_area / storeys_above_ground volume_per_area = building.volume / building.floor_area / storeys_above_ground
for (j, mixed_usage) in enumerate(usages): for j, usage_type in enumerate(usages):
usage = Usage() usage = Usage()
usage.name = mixed_usage[-1] usage.name = usage_type['usage']
if len(usages) > 1: usage.percentage = float(usage_type['ratio'])
usage.percentage = float(mixed_usage[0]) / 100
else:
usage.percentage = 1
self._assign_values(usage, nrcan_archetype_usages[j], volume_per_area, building.cold_water_temperature) self._assign_values(usage, nrcan_archetype_usages[j], volume_per_area, building.cold_water_temperature)
self._assign_comnet_extra_values(usage, comnet_archetype_usages[j], nrcan_archetype_usages[j].occupancy.occupancy_density) self._assign_comnet_extra_values(usage, comnet_archetype_usages[j], nrcan_archetype_usages[j].occupancy.occupancy_density)
self._calculate_reduced_values_from_extended_library(usage, nrcan_archetype_usages[j]) self._calculate_reduced_values_from_extended_library(usage, nrcan_archetype_usages[j])
@ -227,20 +226,11 @@ class NrcanUsageParameters:
def average_storey_height_calculator(city, building): def average_storey_height_calculator(city, building):
climate_zone = ConstructionHelper.city_to_nrcan_climate_zone(city.climate_reference_city) climate_zone = ConstructionHelper.city_to_nrcan_climate_zone(city.climate_reference_city)
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
main_function = None
functions = building.function.split('_') if building.function not in Dictionaries().hub_function_to_nrcan_construction_function:
if len(functions) > 1: raise ValueError('Building %s has an unknown building function %s', building.name, building.function)
maximum_percentage = 0
for function in functions: function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
percentage_and_function = function.split('-')
if float(percentage_and_function[0]) > maximum_percentage:
maximum_percentage = float(percentage_and_function[0])
main_function = percentage_and_function[-1]
else:
main_function = functions[-1]
if main_function not in Dictionaries().hub_function_to_nrcan_construction_function:
logging.error('Building %s has an unknown building function %s', building.name, main_function)
function = Dictionaries().hub_function_to_nrcan_construction_function[main_function]
construction_archetype = None construction_archetype = None
average_storey_height = None average_storey_height = None
nrcan_archetypes = nrcan_catalog.entries('archetypes') nrcan_archetypes = nrcan_catalog.entries('archetypes')
@ -251,7 +241,7 @@ class NrcanUsageParameters:
construction_archetype = building_archetype construction_archetype = building_archetype
average_storey_height = building_archetype.average_storey_height average_storey_height = building_archetype.average_storey_height
if construction_archetype is None: if construction_archetype is None:
logging.error('Building %s has unknown construction archetype for building function: %s ' raise ValueError('Building %s has unknown construction archetype for building function: %s '
'[%s], building year of construction: %s and climate zone %s', building.name, function, '[%s], building year of construction: %s and climate zone %s', building.name, function,
building.function, building.year_of_construction, climate_zone) building.function, building.year_of_construction, climate_zone)

View File

@ -0,0 +1,174 @@
"""
PalmaUsageParameters extracts the usage properties from Palma catalog and assigns to each building
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Cecilia Pérez cperez@irec.cat
"""
import logging
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.city_model_structure.building_demand.domestic_hot_water import DomesticHotWater
from hub.catalog_factories.usage_catalog_factory import UsageCatalogFactory
class PalmaUsageParameters:
"""
PalmaUsageParameters class
"""
def __init__(self, city):
self._city = city
def enrich_buildings(self):
"""
Returns the city with the usage parameters assigned to the buildings
:return:
"""
city = self._city
palma_catalog = UsageCatalogFactory('palma').catalog
for building in city.buildings:
palma_usage_name = Dictionaries().hub_usage_to_palma_usage[building.function]
try:
archetype_usage = self._search_archetypes(palma_catalog, palma_usage_name)
except KeyError:
logging.error('Building %s has unknown usage archetype for usage %s', building.name, palma_usage_name)
continue
for internal_zone in building.internal_zones:
if len(building.internal_zones) > 1:
volume_per_area = 0
if internal_zone.area is None:
logging.error('Building %s has internal zone area not defined, ACH cannot be calculated for usage %s',
building.name, palma_usage_name)
continue
if internal_zone.volume is None:
logging.error('Building %s has internal zone volume not defined, ACH cannot be calculated for usage %s',
building.name, palma_usage_name)
continue
if internal_zone.area <= 0:
logging.error('Building %s has internal zone area equal to 0, ACH cannot be calculated for usage %s',
building.name, palma_usage_name)
continue
volume_per_area += internal_zone.volume / internal_zone.area
else:
if building.storeys_above_ground is None:
logging.error('Building %s no number of storeys assigned, ACH cannot be calculated for usage %s',
building.name, palma_usage_name)
continue
volume_per_area = building.volume / building.floor_area / building.storeys_above_ground
usage = Usage()
usage.name = palma_usage_name
self._assign_values(usage, archetype_usage, volume_per_area, building.cold_water_temperature)
usage.percentage = 1
self._calculate_reduced_values_from_extended_library(usage, archetype_usage)
internal_zone.usages = [usage]
@staticmethod
def _search_archetypes(palma_catalog, usage_name):
archetypes = palma_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, archetype, volume_per_area, cold_water_temperature):
if archetype.mechanical_air_change > 0:
# 1/s
usage.mechanical_air_change = archetype.mechanical_air_change
elif archetype.ventilation_rate > 0:
# m3/m2.s to 1/s
usage.mechanical_air_change = archetype.ventilation_rate / volume_per_area
else:
usage.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.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.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.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.thermal_control = _control
_domestic_hot_water = DomesticHotWater()
_domestic_hot_water.peak_flow = archetype.domestic_hot_water.peak_flow
_domestic_hot_water.service_temperature = archetype.domestic_hot_water.service_temperature
density = None
if len(cold_water_temperature) > 0:
cold_temperature = cold_water_temperature[cte.YEAR][0]
density = (
archetype.domestic_hot_water.peak_flow * cte.WATER_DENSITY * cte.WATER_HEAT_CAPACITY *
(archetype.domestic_hot_water.service_temperature - cold_temperature)
)
_domestic_hot_water.density = density
_domestic_hot_water.schedules = archetype.domestic_hot_water.schedules
usage.domestic_hot_water = _domestic_hot_water
@staticmethod
def _calculate_reduced_values_from_extended_library(usage, 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.hours_day = total / 365
usage.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.thermal_control.mean_heating_set_point = max_heating_setpoint
usage.thermal_control.heating_set_back = min_heating_setpoint
usage.thermal_control.mean_cooling_set_point = min_cooling_setpoint

View File

@ -10,6 +10,7 @@ from hub.helpers.utils import validate_import_export_type
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 from hub.imports.usage.nrcan_usage_parameters import NrcanUsageParameters
from hub.imports.usage.eilat_usage_parameters import EilatUsageParameters from hub.imports.usage.eilat_usage_parameters import EilatUsageParameters
from hub.imports.usage.palma_usage_parameters import PalmaUsageParameters
class UsageFactory: class UsageFactory:
@ -48,6 +49,15 @@ class UsageFactory:
for building in self._city.buildings: for building in self._city.buildings:
building.level_of_detail.usage = 2 building.level_of_detail.usage = 2
def _palma(self):
"""
Enrich the city with Palma usage library
"""
PalmaUsageParameters(self._city).enrich_buildings()
self._city.level_of_detail.usage = 2
for building in self._city.buildings:
building.level_of_detail.usage = 2
def enrich(self): def enrich(self):
""" """
Enrich the city given to the class using the usage factory given handler Enrich the city given to the class using the usage factory given handler

View File

@ -110,12 +110,9 @@ class EpwWeatherParameters:
# new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw']) # new_value = pd.DataFrame(self._weather_values[['dry_bulb_temperature_c']].to_numpy(), columns=['epw'])
# number_invalid_records = new_value[new_value.epw == 99.9].count().epw # number_invalid_records = new_value[new_value.epw == 99.9].count().epw
building.external_temperature[cte.HOUR] = self._weather_values['dry_bulb_temperature_c'] building.external_temperature[cte.HOUR] = self._weather_values['dry_bulb_temperature_c']
building.global_horizontal[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES building.global_horizontal[cte.HOUR] = [x for x in self._weather_values['global_horizontal_radiation_wh_m2']]
for x in self._weather_values['global_horizontal_radiation_wh_m2']] building.diffuse[cte.HOUR] = [x for x in self._weather_values['diffuse_horizontal_radiation_wh_m2']]
building.diffuse[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES building.direct_normal[cte.HOUR] = [x for x in self._weather_values['direct_normal_radiation_wh_m2']]
for x in self._weather_values['diffuse_horizontal_radiation_wh_m2']]
building.direct_normal[cte.HOUR] = [x * cte.WATTS_HOUR_TO_JULES
for x in self._weather_values['direct_normal_radiation_wh_m2']]
building.beam[cte.HOUR] = [building.global_horizontal[cte.HOUR][i] - building.beam[cte.HOUR] = [building.global_horizontal[cte.HOUR][i] -
building.diffuse[cte.HOUR][i] building.diffuse[cte.HOUR][i]
for i in range(len(building.global_horizontal[cte.HOUR]))] for i in range(len(building.global_horizontal[cte.HOUR]))]

View File

@ -9,6 +9,7 @@ import datetime
import logging import logging
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
from sqlalchemy.dialects.postgresql import JSON
from sqlalchemy import DateTime from sqlalchemy import DateTime
from hub.city_model_structure.building import Building from hub.city_model_structure.building import Building
@ -27,7 +28,7 @@ class CityObject(Models):
type = Column(String, nullable=False) type = Column(String, nullable=False)
year_of_construction = Column(Integer, nullable=True) year_of_construction = Column(Integer, nullable=True)
function = Column(String, nullable=True) function = Column(String, nullable=True)
usage = Column(String, nullable=True) usage = Column(JSON, nullable=True)
volume = Column(Float, nullable=False) volume = Column(Float, nullable=False)
area = Column(Float, nullable=False) area = Column(Float, nullable=False)
total_heating_area = Column(Float, nullable=False) total_heating_area = Column(Float, nullable=False)
@ -46,7 +47,7 @@ class CityObject(Models):
self.type = building.type self.type = building.type
self.year_of_construction = building.year_of_construction self.year_of_construction = building.year_of_construction
self.function = building.function self.function = building.function
self.usage = building.usages_percentage self.usage = building.usages
self.volume = building.volume self.volume = building.volume
self.area = building.floor_area self.area = building.floor_area
self.roof_area = sum(roof.solid_polygon.area for roof in building.roofs) self.roof_area = sum(roof.solid_polygon.area for roof in building.roofs)

View File

@ -1,4 +1,4 @@
""" """
Hub version number Hub version number
""" """
__version__ = '0.2.0.11' __version__ = '0.3.0.5'

View File

@ -1,5 +1,5 @@
xmltodict xmltodict
numpy==1.26.4 numpy
trimesh[all] trimesh[all]
pyproj pyproj
pandas pandas

View File

@ -59,12 +59,14 @@ setup(
'hub.exports', 'hub.exports',
'hub.exports.building_energy', 'hub.exports.building_energy',
'hub.exports.building_energy.idf_files', 'hub.exports.building_energy.idf_files',
'hub.exports.building_energy.idf_helper',
'hub.exports.building_energy.insel', 'hub.exports.building_energy.insel',
'hub.exports.energy_systems', 'hub.exports.energy_systems',
'hub.exports.formats', 'hub.exports.formats',
'hub.helpers', 'hub.helpers',
'hub.helpers.peak_calculation', 'hub.helpers.peak_calculation',
'hub.helpers.data', 'hub.helpers.data',
'hub.helpers.parsers',
'hub.imports', 'hub.imports',
'hub.imports.construction', 'hub.imports.construction',
'hub.imports.construction.helpers', 'hub.imports.construction.helpers',

View File

@ -71,3 +71,23 @@ class TestConstructionCatalog(TestCase):
with self.assertRaises(IndexError): with self.assertRaises(IndexError):
catalog.get_entry('unknown') catalog.get_entry('unknown')
def test_palma_catalog(self):
catalog = ConstructionCatalogFactory('palma').catalog
catalog_categories = catalog.names()
constructions = catalog.names('constructions')
windows = catalog.names('windows')
materials = catalog.names('materials')
self.assertEqual(29, len(constructions['constructions']))
self.assertEqual(9, len(windows['windows']))
self.assertEqual(122, len(materials['materials']))
with self.assertRaises(ValueError):
catalog.names('unknown')
# retrieving all the entries should not raise any exceptions
for category in catalog_categories:
for value in catalog_categories[category]:
catalog.get_entry(value)
with self.assertRaises(IndexError):
catalog.get_entry('unknown')

View File

@ -306,3 +306,24 @@ class TestConstructionFactory(TestCase):
self.assertIsNotNone(thermal_boundary.layers, 'layers is none') self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary) self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary) self._check_surfaces(thermal_boundary)
def test_palma_construction_factory(self):
file = 'palma_test_file.geojson'
file_path = (self._example_path / file).resolve()
city = GeometryFactory(file_type='geojson',
path=file_path,
height_field='measuredHeight',
year_of_construction_field='yearOfConstruction',
function_field='usage',
function_to_hub=Dictionaries().palma_function_to_hub_function).city
ConstructionFactory('palma', city).enrich()
self._check_buildings(city)
for building in city.buildings:
for internal_zone in building.internal_zones:
self._check_thermal_zones(internal_zone)
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
self._check_thermal_boundaries(thermal_zone)
for thermal_boundary in thermal_zone.thermal_boundaries:
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)

View File

@ -17,6 +17,7 @@ from hub.exports.exports_factory import ExportsFactory
from hub.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.imports.construction_factory import ConstructionFactory from hub.imports.construction_factory import ConstructionFactory
from hub.imports.geometry_factory import GeometryFactory from hub.imports.geometry_factory import GeometryFactory
from hub.imports.results_factory import ResultFactory
from hub.imports.usage_factory import UsageFactory from hub.imports.usage_factory import UsageFactory
from hub.imports.weather_factory import WeatherFactory from hub.imports.weather_factory import WeatherFactory
@ -136,7 +137,6 @@ class TestExports(TestCase):
year_of_construction_field='ANNEE_CONS', year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI', function_field='CODE_UTILI',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city function_to_hub=Dictionaries().montreal_function_to_hub_function).city
self.assertIsNotNone(city, 'city is none') self.assertIsNotNone(city, 'city is none')
EnergyBuildingsExportsFactory('idf', city, self._output_path).export() EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
ConstructionFactory('nrcan', city).enrich() ConstructionFactory('nrcan', city).enrich()
@ -144,6 +144,42 @@ class TestExports(TestCase):
UsageFactory('nrcan', city).enrich() UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich() WeatherFactory('epw', city).enrich()
try: try:
EnergyBuildingsExportsFactory('idf', city, self._output_path, target_buildings=[1]).export() _idf = EnergyBuildingsExportsFactory('idf', city, self._output_path).export()
_idf.run()
except Exception:
self.fail("Idf ExportsFactory raised ExceptionType unexpectedly!")
def test_cerc_idf_export(self):
"""
export to IDF
"""
file = 'test.geojson'
file_path = (self._example_path / file).resolve()
city = GeometryFactory('geojson',
path=file_path,
height_field='citygml_me',
year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI',
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
self.assertIsNotNone(city, 'city is none')
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
WeatherFactory('epw', city).enrich()
try:
idf = EnergyBuildingsExportsFactory('cerc_idf', city, self._output_path).export()
idf.run()
csv_output_path = (self._output_path / f'{city.name}_out.csv').resolve()
ResultFactory('cerc_idf', city, csv_output_path).enrich()
self.assertTrue(csv_output_path.is_file())
for building in city.buildings:
self.assertIsNotNone(building.heating_demand)
self.assertIsNotNone(building.cooling_demand)
self.assertIsNotNone(building.domestic_hot_water_heat_demand)
self.assertIsNotNone(building.lighting_electrical_demand)
self.assertIsNotNone(building.appliances_electrical_demand)
total_demand = sum(building.heating_demand[cte.HOUR])
total_demand_month = sum(building.heating_demand[cte.MONTH])
self.assertAlmostEqual(total_demand, building.heating_demand[cte.YEAR][0], 2)
self.assertAlmostEqual(total_demand_month, building.heating_demand[cte.YEAR][0], 2)
except Exception: except Exception:
self.fail("Idf ExportsFactory raised ExceptionType unexpectedly!") self.fail("Idf ExportsFactory raised ExceptionType unexpectedly!")

View File

@ -92,42 +92,3 @@ class TestResultsImport(TestCase):
building.cooling_demand[cte.HOUR] = values building.cooling_demand[cte.HOUR] = values
self.assertIsNotNone(building.heating_peak_load) self.assertIsNotNone(building.heating_peak_load)
self.assertIsNotNone(building.cooling_peak_load) self.assertIsNotNone(building.cooling_peak_load)
def test_energy_plus_results_import(self):
ResultFactory('energy_plus_single_building', self._city, self._example_path).enrich()
for building in self._city.buildings:
csv_output_name = f'{building.name}_out.csv'
csv_output_path = (self._example_path / csv_output_name).resolve()
if csv_output_path.is_file():
self.assertEqual(building.name, '12')
self.assertIsNotNone(building.heating_demand)
self.assertIsNotNone(building.cooling_demand)
self.assertIsNotNone(building.domestic_hot_water_heat_demand)
self.assertIsNotNone(building.lighting_electrical_demand)
self.assertIsNotNone(building.appliances_electrical_demand)
total_demand = sum(building.heating_demand[cte.HOUR])
self.assertAlmostEqual(total_demand, building.heating_demand[cte.YEAR][0], 3)
total_demand = sum(building.heating_demand[cte.MONTH])
self.assertEqual(total_demand, building.heating_demand[cte.YEAR][0], 3)
if building.name != '12':
self.assertDictEqual(building.heating_demand, {})
self.assertDictEqual(building.cooling_demand, {})
self.assertDictEqual(building.domestic_hot_water_heat_demand, {})
self.assertDictEqual(building.lighting_electrical_demand, {})
self.assertDictEqual(building.appliances_electrical_demand, {})
def test_energy_plus_multiple_buildings_results_import(self):
ResultFactory('energy_plus_multiple_buildings', self._city, self._example_path).enrich()
csv_output_name = f'{self._city.name}_out.csv'
csv_output_path = (self._example_path / csv_output_name).resolve()
if csv_output_path.is_file():
for building in self._city.buildings:
self.assertIsNotNone(building.heating_demand)
self.assertIsNotNone(building.cooling_demand)
self.assertIsNotNone(building.domestic_hot_water_heat_demand)
self.assertIsNotNone(building.lighting_electrical_demand)
self.assertIsNotNone(building.appliances_electrical_demand)
total_demand = sum(building.heating_demand[cte.HOUR])
self.assertAlmostEqual(total_demand, building.heating_demand[cte.YEAR][0], 2)
total_demand = sum(building.heating_demand[cte.MONTH])
self.assertEqual(total_demand, building.heating_demand[cte.YEAR][0], 2)

View File

@ -39,11 +39,32 @@ class TestSystemsCatalog(TestCase):
catalog_categories = catalog.names() catalog_categories = catalog.names()
archetypes = catalog.names() archetypes = catalog.names()
self.assertEqual(15, len(archetypes['archetypes'])) self.assertEqual(34, len(archetypes['archetypes']))
systems = catalog.names('systems') systems = catalog.names('systems')
self.assertEqual(12, len(systems['systems'])) self.assertEqual(39, len(systems['systems']))
generation_equipments = catalog.names('generation_equipments') generation_equipments = catalog.names('generation_equipments')
self.assertEqual(27, len(generation_equipments['generation_equipments'])) self.assertEqual(49, len(generation_equipments['generation_equipments']))
with self.assertRaises(ValueError):
catalog.names('unknown')
# retrieving all the entries should not raise any exceptions
for category in catalog_categories:
for value in catalog_categories[category]:
catalog.get_entry(value)
with self.assertRaises(IndexError):
catalog.get_entry('unknown')
def test_palma_catalog(self):
catalog = EnergySystemsCatalogFactory('palma').catalog
catalog_categories = catalog.names()
archetypes = catalog.names()
self.assertEqual(15, len(archetypes['archetypes']))
systems = catalog.names('systems')
self.assertEqual(13, len(systems['systems']))
generation_equipments = catalog.names('generation_equipments')
self.assertEqual(16, len(generation_equipments['generation_equipments']))
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
catalog.names('unknown') catalog.names('unknown')
@ -54,4 +75,3 @@ class TestSystemsCatalog(TestCase):
with self.assertRaises(IndexError): with self.assertRaises(IndexError):
catalog.get_entry('unknown') catalog.get_entry('unknown')
print(catalog.entries())

View File

@ -114,7 +114,8 @@ class TestSystemsFactory(TestCase):
ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich() ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich()
for building in self._city.buildings: for building in self._city.buildings:
building.energy_systems_archetype_name = 'PV+ASHP+GasBoiler+TES' building.energy_systems_archetype_name = ('Central Hydronic Air and Gas Source Heating System with Unitary Split '
'Cooling and Air Source HP DHW and Grid Tied PV')
EnergySystemsFactory('montreal_future', self._city).enrich() EnergySystemsFactory('montreal_future', self._city).enrich()
# Need to assign energy systems to buildings: # Need to assign energy systems to buildings:
for building in self._city.buildings: for building in self._city.buildings:
@ -127,6 +128,44 @@ class TestSystemsFactory(TestCase):
_generation_system = cast(NonPvGenerationSystem, energy_system.generation_systems[0]) _generation_system = cast(NonPvGenerationSystem, energy_system.generation_systems[0])
_generation_system.nominal_cooling_output = building.cooling_peak_load[cte.YEAR][0] _generation_system.nominal_cooling_output = building.cooling_peak_load[cte.YEAR][0]
for building in self._city.buildings:
self.assertLess(0, building.heating_consumption[cte.YEAR][0])
self.assertLess(0, building.cooling_consumption[cte.YEAR][0])
self.assertLess(0, building.domestic_hot_water_consumption[cte.YEAR][0])
if 'PV' in building.energy_systems_archetype_name:
self.assertLess(0, building.onsite_electrical_production[cte.YEAR][0])
def test_palma_system_results(self):
"""
Enrich the city with the construction information and verify it
"""
ConstructionFactory('nrcan', self._city).enrich()
UsageFactory('nrcan', self._city).enrich()
WeatherFactory('epw', self._city).enrich()
ExportsFactory('sra', self._city, self._output_path).export()
sra_path = (self._output_path / f'{self._city.name}_sra.xml').resolve()
subprocess.run(['sra', str(sra_path)])
ResultFactory('sra', self._city, self._output_path).enrich()
EnergyBuildingsExportsFactory('insel_monthly_energy_balance', self._city, self._output_path).export()
for building in self._city.buildings:
insel_path = (self._output_path / f'{building.name}.insel')
subprocess.run(['insel', str(insel_path)])
ResultFactory('insel_monthly_energy_balance', self._city, self._output_path).enrich()
for building in self._city.buildings:
building.energy_systems_archetype_name = 'PV and heat pump'
EnergySystemsFactory('palma', self._city).enrich()
# Need to assign energy systems to buildings:
for building in self._city.buildings:
_building_energy_systems = []
for energy_system in building.energy_systems:
if cte.HEATING in energy_system.demand_types:
_generation_system = cast(NonPvGenerationSystem, energy_system.generation_systems[0])
_generation_system.nominal_heat_output = building.heating_peak_load[cte.YEAR][0]
if cte.COOLING in energy_system.demand_types:
_generation_system = cast(NonPvGenerationSystem, energy_system.generation_systems[0])
_generation_system.nominal_cooling_output = building.cooling_peak_load[cte.YEAR][0]
for building in self._city.buildings: for building in self._city.buildings:
self.assertLess(0, building.heating_consumption[cte.YEAR][0]) self.assertLess(0, building.heating_consumption[cte.YEAR][0])
self.assertLess(0, building.cooling_consumption[cte.YEAR][0]) self.assertLess(0, building.cooling_consumption[cte.YEAR][0])

View File

@ -21,3 +21,10 @@ class TestConstructionCatalog(TestCase):
self.assertIsNotNone(catalog, 'catalog is none') self.assertIsNotNone(catalog, 'catalog is none')
content = catalog.entries() content = catalog.entries()
self.assertEqual(34, len(content.usages), 'Wrong number of usages') self.assertEqual(34, len(content.usages), 'Wrong number of usages')
def test_palma_catalog(self):
catalog = UsageCatalogFactory('palma').catalog
self.assertIsNotNone(catalog, 'catalog is none')
content = catalog.entries()
#print(catalog.entries())
self.assertEqual(1, len(content.usages), 'Wrong number of usages')

View File

@ -11,6 +11,7 @@ from hub.imports.geometry_factory import GeometryFactory
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.helpers.dictionaries import Dictionaries from hub.helpers.dictionaries import Dictionaries
from hub.helpers.usage_parsers import UsageParsers
class TestUsageFactory(TestCase): class TestUsageFactory(TestCase):
@ -75,6 +76,40 @@ class TestUsageFactory(TestCase):
self.assertIsNotNone(usage.thermal_control.heating_set_back, 'control heating set back is none') self.assertIsNotNone(usage.thermal_control.heating_set_back, 'control heating set back is none')
self.assertIsNotNone(usage.thermal_control.mean_cooling_set_point, 'control cooling set point is none') self.assertIsNotNone(usage.thermal_control.mean_cooling_set_point, 'control cooling set point is none')
self.assertIsNotNone(usage.mechanical_air_change, 'mechanical air change is none')
self.assertIsNotNone(usage.thermal_control.heating_set_point_schedules,
'control heating set point schedule is none')
self.assertIsNotNone(usage.thermal_control.cooling_set_point_schedules,
'control cooling set point schedule is none')
self.assertIsNotNone(usage.occupancy, 'occupancy is none')
occupancy = usage.occupancy
self.assertIsNotNone(occupancy.occupancy_density, 'occupancy density is none')
self.assertIsNotNone(occupancy.latent_internal_gain, 'occupancy latent internal gain is none')
self.assertIsNotNone(occupancy.sensible_convective_internal_gain,
'occupancy sensible convective internal gain is none')
self.assertIsNotNone(occupancy.sensible_radiative_internal_gain,
'occupancy sensible radiant internal gain is none')
self.assertIsNotNone(occupancy.occupancy_schedules, 'occupancy schedule is none')
self.assertIsNotNone(usage.lighting, 'lighting is none')
lighting = usage.lighting
self.assertIsNotNone(lighting.density, 'lighting density is none')
self.assertIsNotNone(lighting.latent_fraction, 'lighting latent fraction is none')
self.assertIsNotNone(lighting.convective_fraction, 'lighting convective fraction is none')
self.assertIsNotNone(lighting.radiative_fraction, 'lighting radiant fraction is none')
self.assertIsNotNone(lighting.schedules, 'lighting schedule is none')
self.assertIsNotNone(usage.appliances, 'appliances is none')
appliances = usage.appliances
self.assertIsNotNone(appliances.density, 'appliances density is none')
self.assertIsNotNone(appliances.latent_fraction, 'appliances latent fraction is none')
self.assertIsNotNone(appliances.convective_fraction, 'appliances convective fraction is none')
self.assertIsNotNone(appliances.radiative_fraction, 'appliances radiant fraction is none')
self.assertIsNotNone(appliances.schedules, 'appliances schedule is none')
self.assertIsNotNone(usage.thermal_control.hvac_availability_schedules,
'control hvac availability is none')
self.assertIsNotNone(usage.domestic_hot_water.service_temperature,
'domestic hot water service temperature is none')
self.assertIsNotNone(usage.domestic_hot_water.schedules, 'domestic hot water schedules is none')
def test_import_comnet(self): def test_import_comnet(self):
""" """
Enrich the city with the usage information from comnet and verify it Enrich the city with the usage information from comnet and verify it
@ -83,7 +118,7 @@ class TestUsageFactory(TestCase):
city = self._get_citygml(file) city = self._get_citygml(file)
for building in city.buildings: for building in city.buildings:
building.function = Dictionaries().pluto_function_to_hub_function[building.function] building.function = Dictionaries().pluto_function_to_hub_function[building.function]
ConstructionFactory('nrcan', city).enrich()
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:
@ -91,40 +126,7 @@ class TestUsageFactory(TestCase):
self.assertIsNot(len(internal_zone.usages), 0, 'no building usage defined') self.assertIsNot(len(internal_zone.usages), 0, 'no building usage defined')
for usage in internal_zone.usages: for usage in internal_zone.usages:
self._check_usage(usage) self._check_usage(usage)
self.assertIsNotNone(usage.mechanical_air_change, 'mechanical air change is none')
self.assertIsNotNone(usage.thermal_control.heating_set_point_schedules,
'control heating set point schedule is none')
self.assertIsNotNone(usage.thermal_control.cooling_set_point_schedules,
'control cooling set point schedule is none')
self.assertIsNotNone(usage.occupancy, 'occupancy is none')
occupancy = usage.occupancy
self.assertIsNotNone(occupancy.occupancy_density, 'occupancy density is none')
self.assertIsNotNone(occupancy.latent_internal_gain, 'occupancy latent internal gain is none')
self.assertIsNotNone(occupancy.sensible_convective_internal_gain,
'occupancy sensible convective internal gain is none')
self.assertIsNotNone(occupancy.sensible_radiative_internal_gain,
'occupancy sensible radiant internal gain is none')
self.assertIsNotNone(occupancy.occupancy_schedules, 'occupancy schedule is none')
self.assertIsNotNone(usage.lighting, 'lighting is none')
lighting = usage.lighting
self.assertIsNotNone(lighting.density, 'lighting density is none')
self.assertIsNotNone(lighting.latent_fraction, 'lighting latent fraction is none')
self.assertIsNotNone(lighting.convective_fraction, 'lighting convective fraction is none')
self.assertIsNotNone(lighting.radiative_fraction, 'lighting radiant fraction is none')
self.assertIsNotNone(lighting.schedules, 'lighting schedule is none')
self.assertIsNotNone(usage.appliances, 'appliances is none')
appliances = usage.appliances
self.assertIsNotNone(appliances.density, 'appliances density is none')
self.assertIsNotNone(appliances.latent_fraction, 'appliances latent fraction is none')
self.assertIsNotNone(appliances.convective_fraction, 'appliances convective fraction is none')
self.assertIsNotNone(appliances.radiative_fraction, 'appliances radiant fraction is none')
self.assertIsNotNone(appliances.schedules, 'appliances schedule is none')
self.assertIsNotNone(usage.thermal_control.hvac_availability_schedules,
'control hvac availability is none')
self.assertIsNotNone(usage.domestic_hot_water.density, 'domestic hot water density is none') self.assertIsNotNone(usage.domestic_hot_water.density, 'domestic hot water density is none')
self.assertIsNotNone(usage.domestic_hot_water.service_temperature,
'domestic hot water service temperature is none')
self.assertIsNotNone(usage.domestic_hot_water.schedules, 'domestic hot water schedules is none')
def test_import_nrcan(self): def test_import_nrcan(self):
""" """
@ -148,37 +150,58 @@ class TestUsageFactory(TestCase):
self.assertIsNot(len(internal_zone.usages), 0, 'no building usage defined') self.assertIsNot(len(internal_zone.usages), 0, 'no building usage defined')
for usage in internal_zone.usages: for usage in internal_zone.usages:
self._check_usage(usage) self._check_usage(usage)
self.assertIsNotNone(usage.mechanical_air_change, 'mechanical air change is none')
self.assertIsNotNone(usage.thermal_control.heating_set_point_schedules, def test_import_palma(self):
'control heating set point schedule is none') """
self.assertIsNotNone(usage.thermal_control.cooling_set_point_schedules, Enrich the city with the usage information from palma and verify it
'control cooling set point schedule is none') """
self.assertIsNotNone(usage.occupancy, 'occupancy is none') file = 'palma_test_file.geojson'
occupancy = usage.occupancy file_path = (self._example_path / file).resolve()
self.assertIsNotNone(occupancy.occupancy_density, 'occupancy density is none') city = GeometryFactory('geojson',
self.assertIsNotNone(occupancy.latent_internal_gain, 'occupancy latent internal gain is none') path=file_path,
self.assertIsNotNone(occupancy.sensible_convective_internal_gain, height_field='measuredHeight',
'occupancy sensible convective internal gain is none') year_of_construction_field='yearOfConstruction',
self.assertIsNotNone(occupancy.sensible_radiative_internal_gain, function_field='usage',
'occupancy sensible radiant internal gain is none') function_to_hub=Dictionaries().palma_function_to_hub_function).city
self.assertIsNotNone(occupancy.occupancy_schedules, 'occupancy schedule is none')
self.assertIsNotNone(usage.lighting, 'lighting is none') ConstructionFactory('palma', city).enrich()
lighting = usage.lighting UsageFactory('palma', city).enrich()
self.assertIsNotNone(lighting.density, 'lighting density is none') self._check_buildings(city)
self.assertIsNotNone(lighting.latent_fraction, 'lighting latent fraction is none') for building in city.buildings:
self.assertIsNotNone(lighting.convective_fraction, 'lighting convective fraction is none') for internal_zone in building.internal_zones:
self.assertIsNotNone(lighting.radiative_fraction, 'lighting radiant fraction is none') if internal_zone.usages is not None:
self.assertIsNotNone(lighting.schedules, 'lighting schedule is none') self.assertIsNot(len(internal_zone.usages), 0, 'no building usage defined')
self.assertIsNotNone(usage.appliances, 'appliances is none') for usage in internal_zone.usages:
appliances = usage.appliances self._check_usage(usage)
self.assertIsNotNone(appliances.density, 'appliances density is none')
self.assertIsNotNone(appliances.latent_fraction, 'appliances latent fraction is none')
self.assertIsNotNone(appliances.convective_fraction, 'appliances convective fraction is none')
self.assertIsNotNone(appliances.radiative_fraction, 'appliances radiant fraction is none')
self.assertIsNotNone(appliances.schedules, 'appliances schedule is none')
self.assertIsNotNone(usage.thermal_control.hvac_availability_schedules,
'control hvac availability is none')
self.assertIsNotNone(usage.domestic_hot_water.peak_flow, 'domestic hot water peak flow is none') self.assertIsNotNone(usage.domestic_hot_water.peak_flow, 'domestic hot water peak flow is none')
self.assertIsNotNone(usage.domestic_hot_water.service_temperature,
'domestic hot water service temperature is none')
self.assertIsNotNone(usage.domestic_hot_water.schedules, 'domestic hot water schedules is none')
def test_import_nrcan_multiusage(self):
"""
Enrich the city with the usage information from nrcan and verify it
"""
file = 'test.geojson'
file_path = (self._example_path / file).resolve()
function_dictionary = Dictionaries().montreal_function_to_hub_function
usage_parser = UsageParsers().list_usage_to_hub(function_dictionary=function_dictionary)
city = GeometryFactory('geojson',
path=file_path,
height_field='citygml_me',
year_of_construction_field='ANNEE_CONS',
function_field='CODE_UTILI',
function_to_hub=function_dictionary,
usages_field='usages',
usages_to_hub=usage_parser).city
ConstructionFactory('nrcan', city).enrich()
UsageFactory('nrcan', city).enrich()
self._check_buildings(city)
for building in city.buildings:
for internal_zone in building.internal_zones:
if internal_zone.usages is not None:
self.assertIsNot(len(internal_zone.usages), 0, 'no building usage defined')
for usage in internal_zone.usages:
self._check_usage(usage)

View File

@ -0,0 +1,325 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"gml_id": "1701545DD7810B-7",
"name": "Build_1701545DD7810B-7",
"usage": "Medium multifamily building",
"yearOfConstruction": 1900,
"measuredHeight": 1.91,
"id": 10000139
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.670070724294205,
39.56930642367412,
10.59
],
[
2.670185785609704,
39.56929891118361,
10.59
],
[
2.670190100634483,
39.56934649857977,
8.68
],
[
2.670126975953838,
39.569351455373074,
8.68
],
[
2.670077594530873,
39.569355279790706,
8.68
],
[
2.670070724294205,
39.56930642367412,
10.59
]
]
]
}
},
{
"type": "Feature",
"properties": {
"gml_id": "1701556DD7810B-0",
"name": "Build_1701556DD7810B-0",
"usage": "Single-family building",
"yearOfConstruction": 1900,
"measuredHeight": 2.41,
"id": 10000187
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.670200083996169,
39.569672074284036,
11.45
],
[
2.670200346722237,
39.569665767718384,
11.45
],
[
2.670198829516351,
39.569641975838955,
11.45
],
[
2.670196767769449,
39.56961025322274,
9.04
],
[
2.670193356349873,
39.5695685251824,
11.45
],
[
2.670277913478355,
39.56956137655187,
9.04
],
[
2.670279246946909,
39.56957480589787,
11.45
],
[
2.67033655158975,
39.56956965230401,
9.04
],
[
2.670344584906827,
39.5696433805295,
11.45
],
[
2.670355415974015,
39.56964260031243,
11.45
],
[
2.670356972062089,
39.569658192795536,
11.45
],
[
2.670325184211198,
39.56965909377396,
11.45
],
[
2.670324202558058,
39.569645124800005,
11.45
],
[
2.670282742314197,
39.56964798062581,
9.04
],
[
2.670220439148762,
39.56965149812889,
11.45
],
[
2.670223258772483,
39.56967069837706,
11.45
],
[
2.670200083996169,
39.569672074284036,
11.45
]
]
]
}
},
{
"type": "Feature",
"properties": {
"gml_id": "1701557DD7810B",
"name": "Build_1701557DD7810B",
"usage": "Single-family building",
"yearOfConstruction": 1900,
"measuredHeight": 3.14,
"id": 10000205
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.670076001010665,
39.56959324111637,
12.07
],
[
2.670075832651971,
39.56957963486689,
8.93
],
[
2.670193356349873,
39.5695685251824,
12.07
],
[
2.670196767769449,
39.56961025322274,
8.93
],
[
2.670198829516351,
39.569641975838955,
8.93
],
[
2.670200346722237,
39.569665767718384,
12.07
],
[
2.670165875186915,
39.56966792249954,
12.07
],
[
2.670163320870091,
39.569641875065045,
12.07
],
[
2.670162763096683,
39.56963673752855,
12.07
],
[
2.670099057749991,
39.56964133224028,
12.07
],
[
2.670097648460491,
39.569619342754734,
12.07
],
[
2.670077380826434,
39.56962144772541,
12.07
],
[
2.670076001010665,
39.56959324111637,
12.07
]
]
]
}
},
{
"type": "Feature",
"properties": {
"gml_id": "1701548DD7810B-1",
"name": "Build_1701548DD7810B-1",
"usage": "Single-family building",
"yearOfConstruction": 1903,
"measuredHeight": 4.01,
"id": 10000230
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.670232581277104,
39.56952142176154,
12.83
],
[
2.670223774973652,
39.56943886109741,
8.82
],
[
2.670329525337772,
39.56943078141684,
8.82
],
[
2.670338924541374,
39.56951109114386,
8.82
],
[
2.670232581277104,
39.56952142176154,
12.83
]
]
]
}
},
{
"type": "Feature",
"properties": {
"gml_id": "1701548DD7810B-0",
"name": "Build_1701548DD7810B-0",
"usage": "Single-family building",
"yearOfConstruction": 1903,
"measuredHeight": 3.54,
"id": 10000246
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.670221550271632,
39.569416959403185,
12.6
],
[
2.670241580303924,
39.56941584488198,
12.6
],
[
2.670243380302281,
39.569429095343594,
12.6
],
[
2.67022299587959,
39.56943129011285,
12.6
],
[
2.670221550271632,
39.569416959403185,
12.6
]
]
]
}
}
]
}

File diff suppressed because one or more lines are too long