Compare commits

..

6 Commits

431 changed files with 814623 additions and 244103 deletions

View File

@ -9,4 +9,4 @@
**/hub/logs/
**/__pycache__/
**/.idea/
cerc_hub.egg-info

View File

@ -90,7 +90,7 @@ pylint --rcfile=pylintrc myfile.py
Before any pull request, the code must been manually and automatically tested to ensure at least some quality minimum. There are a few practices for unit tests that we believe are important, so we encourage you to follow it.
* The test should be cls-contained, which implies that your tests will prepare and clean up everything before and after the test execution.
* The test should be self-contained, which implies that your tests will prepare and clean up everything before and after the test execution.
* We encourage you to create if possible functional tests that cover the complete workflow of the implemented functionality.
* Maximize your code coverage by ensuring that you are testing as much of your code as possible.

View File

@ -58,7 +58,7 @@ section in persistence/README.md file.
as shown below:
```python
from hub.persistence.db_control import DBFactory
from hub.exports.db_factory import DBFactory
from pathlib import Path
dotenv_path = (Path(__file__).parent / '.env').resolve()

View File

@ -1,50 +0,0 @@
# LINUX_INSTALL
## Prepare your environment
### Install Miniconda
1. Get the link for the latest version of Miniconda from https://docs.conda.io/en/latest/miniconda.html
2. Download the installer using wget
````
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
````
3. Make the installer executable
````
chmod +x ./Miniconda3-latest-Linux-x86_64.sh
````
4. Run the installer
````
./Miniconda3-latest-Linux-x86_64.sh
````
5. Holder enter until you are prompted to accept the license terms. Enter yes.
6. Initialize the conda environment
````
conda init bash
````
7. Source .bashrc
````
source ~/.bashrc
````
8. Create a conda environment for the hub
````
conda create --name hub python=3.9.16
````
### Setup SRA
1. Get the sra binary and libshortwave.so library from Guille or Koa
2. Place the binary and the library into your directory of choice
3. Make a symlink for the binary and place it into /usr/local/bin/sra
````
sudo ln -s ~/sra /usr/local/bin/sra
````
4. Make a symlink for the library and place it into /usr/local/lib/libshortwave.so
````
sudo ln -s ~/libshortwave.so /usr/local/lib/libshortwave.so
````
### Setup INSEL
1. TBD
### Get a Python editor
You are welcome to use the Python editor of your preference. The CERC team generally uses PyCharm to develop the hub.
The latest version of PyCharm can be downloaded from [JetBrains website](https://www.jetbrains.com/pycharm/promo/?source=google&medium=cpc&campaign=14127625109&term=pycharm&content=536947779504&gad=1&gclid=CjwKCAjw0ZiiBhBKEiwA4PT9z2AxPfy39x_RcBqlYxJ6sm_s55T9qvA_sZ8ZfkhIVX6FOD-ySbmzARoCcpQQAvD_BwE).
For setup and installation instructions, please view the "Get a Python Editor"
from the [WINDOWS_INSTALL](https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/hub/src/branch/main/hub/WINDOWS_INSTALL.md)
documentation.

View File

@ -48,11 +48,11 @@ Use properties whenever it is possible. Encapsulate the access to all the calcul
```python
@property
def object_attribute(cls):
if cls._object_attribute is None:
cls._object_attribute = ...
def object_attribute(self):
if self._object_attribute is None:
self._object_attribute = ...
...
return cls._object_attribute
return self._object_attribute
```
@ -61,12 +61,12 @@ And like in the following example for read and write properties:
```python
@property
def object_changeable_attribute(cls):
return cls._object_changeable_attribute
def object_changeable_attribute(self):
return self._object_changeable_attribute
@object_changeable_attribute.setter
def object_changeable_attribute(cls, value):
cls._object_changeable_attribute = value
def object_changeable_attribute(self, value):
self._object_changeable_attribute = value
```
@ -75,11 +75,11 @@ If your method or attribute returns a complex object, use type hints as in this
```python
@property
def complex_object(cls) -> ComplexObject:
return cls._object_changeable_attribute
def complex_object(self) -> ComplexObject:
return self._object_changeable_attribute
def new_complex_object(cls, first_param, second_param) -> ComplexObject:
other_needed_property = cls.other_needed_property
def new_complex_object(self, first_param, second_param) -> ComplexObject:
other_needed_property = self.other_needed_property
return ComplexObject(first_param, second_param, other_needed_property)
```
@ -89,11 +89,11 @@ Always access your variable through the method and avoid to access directly.
```python
@property
def object_attribute(cls):
return cls._object_attribute
def object_attribute(self):
return self._object_attribute
def operation(cls, first_param, second_param):
return cls.object_attribute * 2
def operation(self, first_param, second_param):
return self.object_attribute * 2
```
@ -110,23 +110,23 @@ All public classes, properties, and methods must have code comments. Code commen
MyClass class perform models class operations
"""
def __init__(cls):
def __init__(self):
@property
def object_attribute(cls):
def object_attribute(self):
"""
Get my class object attribute
:return: int
"""
return cls._object_attribute
return self._object_attribute
def operation(cls, first_param, second_param):
def operation(self, first_param, second_param):
"""
Multiplies object_attribute by two
:return: int
"""
return cls.object_attribute * 2
return self.object_attribute * 2
```
@ -135,20 +135,20 @@ Comments at getters and setters always start with Get and Set, and identity the
```python
@property
def object_attribute(cls):
def object_attribute(self):
"""
Get object attribute
:return: int
"""
return cls._object_attribute
return self._object_attribute
@object_attribute.setter
def object_attribute(cls, value):
def object_attribute(self, value):
"""
Set object attribute
:param value: int
"""
cls._object_attribute = value
self._object_attribute = value
```
@ -157,12 +157,12 @@ Attributes with known units should be explicit in method's comment.
```python
@property
def distance(cls):
def distance(self):
"""
My class distance in meters
:return: float
"""
return cls._distance
return self._distance
```
#### To do's.

View File

@ -1,16 +1,20 @@
# Functions and usages internally recognized within the hub
The hub uses a list of building functions that are the only ones recognized. All new categories should be added to the dictionaries that translate from the input formats to the hub functions and from the hub functions to the output formats.
The hub uses a list of building functions a building usages that are the only ones recognized. All new categories should be added to the dictionaries that translate from the input formats to the libs functions. From the libs functions to the libs usages and from the libs usages and libs functions to the output formats.
Input formats accepted:
* Function:
* pluto
* hft
Output formats accepted:
* Function:
* nrel
* nrcan
* eilat
* Usage:
* nrcan
* ca
* hft
* comnet
* eilat
Libs_functions:
* single family house

View File

@ -62,14 +62,6 @@ To solve it, type 'Set-ExecutionPolicy Unrestricted' as shown in the image.
![create_sra](docs/img_windows_install/img_36.png)
### Install and setup INSEL
1. Get the INSEL installer from Guille or Koa
2. Run the installer to completion using the default installation path
3. Add the INSEL installation folder to the Path
![create_sra](docs/img_windows_install/img_41.png)
### Get a Python editor
1. You will need a python editor in order to import the existing Hub source code and to write your own python code.

View File

@ -8,13 +8,12 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class Catalog:
"""
Catalogs base class
catalog_factories will inherit from this class.
Catalogs base class not implemented instance of the Catalog base class, catalog_factories will inherit from this class.
"""
def names(self, category=None):
"""
Base property to return the catalog entries names.
Base property to return the catalog entries names
:return: Catalog names filter by category if provided
"""
raise NotImplementedError

View File

@ -1,9 +1,3 @@
"""
Construction helper module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
"""
from hub.helpers import constants as cte
@ -40,24 +34,12 @@ class ConstructionHelper:
@property
def reference_standard_to_construction_period(self):
"""
Get reference standard to construction period dictionary
:return: {}
"""
return self._reference_standard_to_construction_period
@property
def nrel_surfaces_types_to_hub_types(self):
"""
Get reference nrel surface type to hub type dictionary
:return: {}
"""
return self._nrel_surfaces_types_to_hub_types
@property
def nrcan_surfaces_types_to_hub_types(self):
"""
Get reference nrcan surface type to hub type dictionary
:return: {}
"""
return self._nrcan_surfaces_types_to_hub_types

View File

@ -1,238 +0,0 @@
"""
Eilat construction catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
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 EilatCatalog(Catalog):
"""
Eilat catalog class
"""
def __init__(self, path):
_path_archetypes = Path(path / 'eilat_archetypes.json').resolve()
_path_constructions = (path / 'eilat_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']
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
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,
None,
extra_loses_due_to_thermal_bridges,
None,
infiltration_rate_for_ventilation_system_off,
infiltration_rate_for_ventilation_system_on,
0,
0))
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

@ -15,19 +15,15 @@ from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.data_models.construction.window import Window
from hub.catalog_factories.data_models.construction.material import Material
from hub.catalog_factories.data_models.construction.layer import Layer
import hub.helpers.constants as cte
class NrcanCatalog(Catalog):
"""
Nrcan catalog class
"""
def __init__(self, path):
_path_archetypes = Path(path / 'nrcan_archetypes.json').resolve()
_path_constructions = (path / 'nrcan_constructions.json').resolve()
with open(_path_archetypes, 'r', encoding='utf-8') as file:
_path_constructions = (path / 'nrcan_constructions.json')
with open(_path_archetypes, 'r') as file:
self._archetypes = json.load(file)
with open(_path_constructions, 'r', encoding='utf-8') as file:
with open(_path_constructions, 'r') as file:
self._constructions = json.load(file)
self._catalog_windows = self._load_windows()
@ -120,20 +116,10 @@ class NrcanCatalog(Catalog):
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
thermal_capacity = str(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
)
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off']
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on']
archetype_constructions = []
for archetype_construction in archetype['constructions']:
@ -159,6 +145,7 @@ class NrcanCatalog(Catalog):
_window)
archetype_constructions.append(_construction)
break
_catalog_archetypes.append(Archetype(archetype_id,
name,
function,
@ -170,10 +157,7 @@ class NrcanCatalog(Catalog):
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
))
infiltration_rate_for_ventilation_system_on))
return _catalog_archetypes
def names(self, category=None):
@ -216,14 +200,16 @@ class NrcanCatalog(Catalog):
"""
if category is None:
return self._content
else:
if category.lower() == 'archetypes':
return self._content.archetypes
if category.lower() == 'constructions':
elif category.lower() == 'constructions':
return self._content.constructions
if category.lower() == 'materials':
elif category.lower() == 'materials':
return self._content.materials
if category.lower() == 'windows':
elif category.lower() == 'windows':
return self._content.windows
else:
raise ValueError(f'Unknown category [{category}]')
def get_entry(self, name):

View File

@ -5,8 +5,8 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pathlib import Path
import xmltodict
from pathlib import Path
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.construction.window import Window
from hub.catalog_factories.data_models.construction.material import Material
@ -15,19 +15,15 @@ from hub.catalog_factories.data_models.construction.construction import Construc
from hub.catalog_factories.data_models.construction.content import Content
from hub.catalog_factories.data_models.construction.archetype import Archetype
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
import hub.helpers.constants as cte
class NrelCatalog(Catalog):
"""
Nrel catalog class
"""
def __init__(self, path):
archetypes_path = str(Path(path / 'us_archetypes.xml').resolve())
constructions_path = str(Path(path / 'us_constructions.xml').resolve())
with open(constructions_path, 'r', encoding='utf-8') as xml:
with open(constructions_path) as xml:
self._constructions = xmltodict.parse(xml.read(), force_list=('material', 'window', 'construction', 'layer'))
with open(archetypes_path, 'r', encoding='utf-8') as xml:
with open(archetypes_path) as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list=('archetype', 'construction'))
self._catalog_windows = self._load_windows()
self._catalog_materials = self._load_materials()
@ -62,9 +58,9 @@ class NrelCatalog(Catalog):
thermal_absorptance = float(material['thermal_absorptance']['#text'])
visible_absorptance = float(material['visible_absorptance']['#text'])
no_mass = False
thermal_resistance = None
conductivity = None
density = None
thermal_resistance = None,
conductivity = None,
density = None,
specific_heat = None
if 'no_mass' in material and material['no_mass'] == 'true':
no_mass = True
@ -116,19 +112,16 @@ class NrelCatalog(Catalog):
function = archetype['@building_type']
name = f"{function} {archetype['@climate_zone']} {archetype['@reference_standard']}"
climate_zone = archetype['@climate_zone']
construction_period = ConstructionHelper().reference_standard_to_construction_period[
archetype['@reference_standard']
]
construction_period = \
ConstructionHelper().reference_standard_to_construction_period[archetype['@reference_standard']]
average_storey_height = float(archetype['average_storey_height']['#text'])
thermal_capacity = float(archetype['thermal_capacity']['#text']) * 1000
extra_loses_due_to_thermal_bridges = float(archetype['extra_loses_due_to_thermal_bridges']['#text'])
indirect_heated_ratio = float(archetype['indirect_heated_ratio']['#text'])
infiltration_rate_for_ventilation_system_off = float(
archetype['infiltration_rate_for_ventilation_system_off']['#text']
) / cte.HOUR_TO_SECONDS
infiltration_rate_for_ventilation_system_on = float(
archetype['infiltration_rate_for_ventilation_system_on']['#text']
) / cte.HOUR_TO_SECONDS
infiltration_rate_for_ventilation_system_off = \
float(archetype['infiltration_rate_for_ventilation_system_off']['#text'])
infiltration_rate_for_ventilation_system_on = \
float(archetype['infiltration_rate_for_ventilation_system_on']['#text'])
archetype_constructions = []
for archetype_construction in archetype['constructions']['construction']:
@ -162,9 +155,7 @@ class NrelCatalog(Catalog):
extra_loses_due_to_thermal_bridges,
indirect_heated_ratio,
infiltration_rate_for_ventilation_system_off,
infiltration_rate_for_ventilation_system_on,
0,
0))
infiltration_rate_for_ventilation_system_on))
return _catalog_archetypes
def names(self, category=None):
@ -207,14 +198,16 @@ class NrelCatalog(Catalog):
"""
if category is None:
return self._content
else:
if category.lower() == 'archetypes':
return self._content.archetypes
if category.lower() == 'constructions':
elif category.lower() == 'constructions':
return self._content.constructions
if category.lower() == 'materials':
elif category.lower() == 'materials':
return self._content.materials
if category.lower() == 'windows':
elif category.lower() == 'windows':
return self._content.windows
else:
raise ValueError(f'Unknown category [{category}]')
def get_entry(self, name):

View File

@ -1,242 +0,0 @@
"""
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

@ -7,25 +7,23 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
from pathlib import Path
from typing import TypeVar
from hub.catalog_factories.construction.nrcan_catalog import NrcanCatalog
from hub.catalog_factories.construction.nrel_catalog import NrelCatalog
from hub.catalog_factories.construction.eilat_catalog import EilatCatalog
from hub.catalog_factories.construction.palma_catalog import PalmaCatalog
from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
from hub.catalog_factories.construction.nrcan_catalog import NrcanCatalog
Catalog = TypeVar('Catalog')
class ConstructionCatalogFactory:
"""
Construction catalog factory class
"""
def __init__(self, handler, base_path=None):
def __init__(self, file_type, base_path=None):
if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/construction')
self._handler = '_' + handler.lower()
validate_import_export_type(ConstructionCatalogFactory, handler)
self._catalog_type = '_' + file_type.lower()
class_funcs = validate_import_export_type(ConstructionCatalogFactory)
if self._catalog_type not in class_funcs:
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._path = base_path
@property
@ -38,28 +36,14 @@ class ConstructionCatalogFactory:
@property
def _nrcan(self):
"""
Retrieve NRCAN catalog
Retrieve NREL catalog
"""
return NrcanCatalog(self._path)
@property
def _eilat(self):
"""
Retrieve Eilat catalog
"""
return EilatCatalog(self._path)
@property
def _palma(self):
"""
Retrieve Palma catalog
"""
return PalmaCatalog(self._path)
@property
def catalog(self) -> Catalog:
"""
Enrich the city given to the class using the class given handler
:return: Catalog
"""
return getattr(self, self._handler, lambda: None)
return getattr(self, self._catalog_type, lambda: None)

View File

@ -1,122 +1,117 @@
"""
Cost catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import xmltodict
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
from hub.catalog_factories.data_models.cost.envelope import Envelope
from hub.catalog_factories.data_models.cost.systems import Systems
from hub.catalog_factories.data_models.cost.hvac import Hvac
from hub.catalog_factories.data_models.cost.operational_cost import OperationalCost
from hub.catalog_factories.data_models.cost.income import Income
from hub.catalog_factories.data_models.cost.archetype import Archetype
from hub.catalog_factories.data_models.cost.content import Content
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
from hub.catalog_factories.data_models.cost.chapter import Chapter
from hub.catalog_factories.data_models.cost.item_description import ItemDescription
from hub.catalog_factories.data_models.cost.operational_cost import OperationalCost
from hub.catalog_factories.data_models.cost.fuel import Fuel
from hub.catalog_factories.data_models.cost.income import Income
class MontrealCustomCatalog(Catalog):
"""
Montreal custom catalog class
"""
def __init__(self, path):
path = (path / 'montreal_costs.xml').resolve()
with open(path, 'r', encoding='utf-8') as xml:
path = str(path / 'montreal_costs.xml')
with open(path) as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list='archetype')
# store the full catalog data model in self._content
self._content = Content(self._load_archetypes())
@staticmethod
def _item_with_threesome(entry, item_type):
_reposition = float(entry[item_type]['reposition']['#text'])
_reposition_unit = entry[item_type]['reposition']['@cost_unit']
_investment = float(entry[item_type]['investment_cost']['#text'])
_investment_unit = entry[item_type]['investment_cost']['@cost_unit']
_lifetime = float(entry[item_type]['lifetime_equipment']['#text'])
_item_description = ItemDescription(item_type,
initial_investment=_investment,
initial_investment_unit=_investment_unit,
reposition=_reposition,
reposition_unit=_reposition_unit,
lifetime=_lifetime)
return _item_description
@staticmethod
def _item_with_refurbishment_values(entry, item_type):
_refurbishment = float(entry[item_type]['refurbishment_cost']['#text'])
_refurbishment_unit = entry[item_type]['refurbishment_cost']['@cost_unit']
_item_description = ItemDescription(item_type,
refurbishment=_refurbishment,
refurbishment_unit=_refurbishment_unit)
return _item_description
def _get_threesome(entry):
_reposition = float(entry['reposition']['#text'])
_investment = float(entry['initial_investment']['#text'])
_lifetime = float(entry['lifetime_equipment']['#text'])
return _reposition, _investment, _lifetime
def _get_capital_costs(self, entry):
general_chapters = []
shell = entry['B_shell']
items_list = []
item_type = 'B10_superstructure'
item_description = self._item_with_refurbishment_values(shell, item_type)
items_list.append(item_description)
for item in shell['B20_envelope']:
item_type = item
item_description = self._item_with_refurbishment_values(shell['B20_envelope'], item_type)
items_list.append(item_description)
item_type = 'B3010_opaque_roof'
item_description = self._item_with_refurbishment_values(shell['B30_roofing'], item_type)
items_list.append(item_description)
general_chapters.append(Chapter('B_shell', items_list))
items_list = []
item_type = 'D301010_photovoltaic_system'
services = entry['D_services']
item_description = self._item_with_threesome(services['D30_hvac']['D3010_energy_supply'], item_type)
items_list.append(item_description)
item_type_list = ['D3020_heat_generating_systems', 'D3030_cooling_generation_systems', 'D3040_distribution_systems',
'D3080_other_hvac_ahu']
for item_type in item_type_list:
item_description = self._item_with_threesome(services['D30_hvac'], item_type)
items_list.append(item_description)
item_type = 'D5020_lighting_and_branch_wiring'
item_description = self._item_with_threesome(services['D50_electrical'], item_type)
items_list.append(item_description)
general_chapters.append(Chapter('D_services', items_list))
allowances = entry['Z_allowances_overhead_profit']
design_allowance = float(allowances['Z10_design_allowance']['#text']) / 100
overhead_and_profit = float(allowances['Z20_overhead_profit']['#text']) / 100
_capital_cost = CapitalCost(general_chapters, design_allowance, overhead_and_profit)
structural = float(entry['structural']['#text'])
sub_structural = float(entry['sub_structural']['#text'])
surface_finish = float(entry['surface_finish']['#text'])
engineer = float(entry['engineer']['#text'])
opaque_reposition, opaque_initial_investment, opaque_lifetime = \
self._get_threesome(entry['envelope']['opaque'])
transparent_reposition, transparent_initial_investment, transparent_lifetime = \
self._get_threesome(entry['envelope']['transparent'])
envelope = Envelope(opaque_reposition,
opaque_initial_investment,
opaque_lifetime,
transparent_reposition,
transparent_initial_investment,
transparent_lifetime)
heating_equipment_reposition, heating_equipment_initial_investment, heating_equipment_lifetime = \
self._get_threesome(entry['systems']['hvac']['heating_equipment_cost'])
heating_equipment_reposition = heating_equipment_reposition / 1000
heating_equipment_initial_investment = heating_equipment_initial_investment / 1000
cooling_equipment_reposition, cooling_equipment_initial_investment, cooling_equipment_lifetime = \
self._get_threesome(entry['systems']['hvac']['cooling_equipment_cost'])
cooling_equipment_reposition = cooling_equipment_reposition / 1000
cooling_equipment_initial_investment = cooling_equipment_initial_investment / 1000
general_hvac_equipment_reposition, general_hvac_equipment_initial_investment, general_hvac_equipment_lifetime = \
self._get_threesome(entry['systems']['hvac']['general_hvac_equipment_cost'])
general_hvac_equipment_reposition = general_hvac_equipment_reposition * 3600
general_hvac_equipment_initial_investment = general_hvac_equipment_initial_investment * 3600
hvac = Hvac(heating_equipment_reposition, heating_equipment_initial_investment, heating_equipment_lifetime,
cooling_equipment_reposition, cooling_equipment_initial_investment, cooling_equipment_lifetime,
general_hvac_equipment_reposition, general_hvac_equipment_initial_investment,
general_hvac_equipment_lifetime)
photovoltaic_system_reposition, photovoltaic_system_initial_investment, photovoltaic_system_lifetime = \
self._get_threesome(entry['systems']['photovoltaic_system'])
other_conditioning_systems_reposition, other_conditioning_systems_initial_investment, \
other_conditioning_systems_lifetime = self._get_threesome(entry['systems']['other_systems'])
lighting_reposition, lighting_initial_investment, lighting_lifetime = \
self._get_threesome(entry['systems']['lighting'])
systems = Systems(hvac,
photovoltaic_system_reposition,
photovoltaic_system_initial_investment,
photovoltaic_system_lifetime,
other_conditioning_systems_reposition,
other_conditioning_systems_initial_investment,
other_conditioning_systems_lifetime,
lighting_reposition,
lighting_initial_investment,
lighting_lifetime)
_capital_cost = CapitalCost(structural,
sub_structural,
envelope,
systems,
surface_finish,
engineer)
return _capital_cost
@staticmethod
def _get_operational_costs(entry):
fuels = []
for item in entry['fuels']['fuel']:
fuel_type = item['@fuel_type']
fuel_variable = float(item['variable']['#text'])
fuel_variable_units = item['variable']['@cost_unit']
fuel_fixed_monthly = None
fuel_fixed_peak = None
if fuel_type == 'electricity':
fuel_fixed_monthly = float(item['fixed_monthly']['#text'])
fuel_fixed_peak = float(item['fixed_power']['#text']) / 1000
elif fuel_type == 'gas':
fuel_fixed_monthly = float(item['fixed_monthly']['#text'])
fuel = Fuel(fuel_type,
fixed_monthly=fuel_fixed_monthly,
fixed_power=fuel_fixed_peak,
variable=fuel_variable,
variable_units=fuel_variable_units)
fuels.append(fuel)
fuel_type = entry['fuel']['@fuel_type']
fuel_fixed_operational_monthly = float(entry['fuel']['fixed']['fixed_monthly']['#text'])
fuel_fixed_operational_peak = float(entry['fuel']['fixed']['fixed_power']['#text']) / 1000
fuel_variable_operational = float(entry['fuel']['variable']['#text']) / 1000 / 3600
heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text']) / 1000
cooling_equipment_maintenance = float(entry['maintenance']['cooling_equipment']['#text']) / 1000
general_hvac_equipment_maintenance = float(entry['maintenance']['general_hvac_equipment']['#text']) * 3600
photovoltaic_system_maintenance = float(entry['maintenance']['photovoltaic_system']['#text'])
co2_emissions = float(entry['co2_cost']['#text'])
_operational_cost = OperationalCost(fuels,
other_systems_maintenance = float(entry['maintenance']['other_systems']['#text'])
co2_emissions = float(entry['CO2_cost']['#text'])
_operational_cost = OperationalCost(fuel_type,
fuel_fixed_operational_monthly,
fuel_fixed_operational_peak,
fuel_variable_operational,
heating_equipment_maintenance,
cooling_equipment_maintenance,
general_hvac_equipment_maintenance,
photovoltaic_system_maintenance,
other_systems_maintenance,
co2_emissions)
return _operational_cost
@ -126,31 +121,25 @@ class MontrealCustomCatalog(Catalog):
for archetype in archetypes:
function = archetype['@function']
municipality = archetype['@municipality']
country = archetype['@country']
lod = float(archetype['@lod'])
currency = archetype['currency']
currency = archetype['@currency']
capital_cost = self._get_capital_costs(archetype['capital_cost'])
operational_cost = self._get_operational_costs(archetype['operational_cost'])
end_of_life_cost = float(archetype['end_of_life_cost']['#text'])
construction = float(archetype['incomes']['subsidies']['construction']['#text'])
hvac = float(archetype['incomes']['subsidies']['hvac']['#text'])
photovoltaic_system = float(archetype['incomes']['subsidies']['photovoltaic']['#text'])
electricity_exports = float(archetype['incomes']['electricity_export']['#text']) / 1000 / 3600
reduction_tax = float(archetype['incomes']['tax_reduction']['#text']) / 100
income = Income(construction_subsidy=construction,
hvac_subsidy=hvac,
photovoltaic_subsidy=photovoltaic_system,
electricity_export=electricity_exports,
reductions_tax=reduction_tax)
_catalog_archetypes.append(Archetype(lod,
function,
construction = float(archetype['incomes']['subsidies']['construction_subsidy']['#text'])
hvac = float(archetype['incomes']['subsidies']['hvac_subsidy']['#text'])
photovoltaic_system = float(archetype['incomes']['subsidies']['photovoltaic_subsidy']['#text'])
electricity_exports = float(archetype['incomes']['energy_exports']['electricity']['#text']) / 1000 / 3600
heat_exports = float(archetype['incomes']['energy_exports']['heat']['#text']) / 1000 / 3600
co2 = float(archetype['incomes']['CO2_income']['#text'])
income = Income(construction, hvac, photovoltaic_system, electricity_exports, heat_exports, co2)
_catalog_archetypes.append(Archetype(function,
municipality,
country,
currency,
capital_cost,
operational_cost,
end_of_life_cost,
income))
return _catalog_archetypes
def names(self, category=None):

View File

@ -13,7 +13,7 @@ from hub.catalog_factories.cost.montreal_custom_catalog import MontrealCustomCat
Catalog = TypeVar('Catalog')
class CostsCatalogFactory:
class CostCatalogFactory:
"""
CostsCatalogFactory class
"""

View File

@ -9,9 +9,6 @@ from hub.catalog_factories.data_models.construction.construction import Construc
class Archetype:
"""
Archetype class
"""
def __init__(self, archetype_id,
name,
function,
@ -23,10 +20,7 @@ class Archetype:
extra_loses_due_to_thermal_bridges,
indirect_heated_ratio,
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
):
infiltration_rate_for_ventilation_system_on):
self._id = archetype_id
self._name = name
self._function = function
@ -39,8 +33,6 @@ class Archetype:
self._indirect_heated_ratio = indirect_heated_ratio
self._infiltration_rate_for_ventilation_system_off = infiltration_rate_for_ventilation_system_off
self._infiltration_rate_for_ventilation_system_on = infiltration_rate_for_ventilation_system_on
self._infiltration_rate_area_for_ventilation_system_off = infiltration_rate_area_for_ventilation_system_off
self._infiltration_rate_area_for_ventilation_system_on = infiltration_rate_area_for_ventilation_system_on
@property
def id(self):
@ -125,7 +117,7 @@ class Archetype:
@property
def infiltration_rate_for_ventilation_system_off(self):
"""
Get archetype infiltration rate for ventilation system off in 1/s
Get archetype infiltration rate for ventilation system off in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_off
@ -133,46 +125,7 @@ class Archetype:
@property
def infiltration_rate_for_ventilation_system_on(self):
"""
Get archetype infiltration rate for ventilation system on in 1/s
Get archetype infiltration rate for ventilation system on in ACH
:return: float
"""
return self._infiltration_rate_for_ventilation_system_on
@property
def infiltration_rate_area_for_ventilation_system_off(self):
"""
Get archetype infiltration rate for ventilation system off in m3/sm2
:return: float
"""
return self._infiltration_rate_area_for_ventilation_system_off
@property
def infiltration_rate_area_for_ventilation_system_on(self):
"""
Get archetype infiltration rate for ventilation system on in m3/sm2
:return: float
"""
return self._infiltration_rate_for_ventilation_system_on
def to_dictionary(self):
"""Class content to dictionary"""
_constructions = []
for _construction in self.constructions:
_constructions.append(_construction.to_dictionary())
content = {'Archetype': {'id': self.id,
'name': self.name,
'function': self.function,
'climate zone': self.climate_zone,
'period of construction': self.construction_period,
'average storey height [m]': self.average_storey_height,
'thermal capacity [J/m3K]': self.thermal_capacity,
'extra loses due to thermal bridges [W/m2K]': self.extra_loses_due_to_thermal_bridges,
'indirect heated ratio': self.indirect_heated_ratio,
'infiltration rate for ventilation off [1/s]': self.infiltration_rate_for_ventilation_system_off,
'infiltration rate for ventilation on [1/s]': self.infiltration_rate_for_ventilation_system_on,
'infiltration rate area for ventilation off [m3/sm2]': self.infiltration_rate_area_for_ventilation_system_off,
'infiltration rate area for ventilation on [m3/sm2]': self.infiltration_rate_area_for_ventilation_system_on,
'constructions': _constructions
}
}
return content

View File

@ -4,15 +4,11 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from hub.catalog_factories.data_models.construction.layer import Layer
from hub.catalog_factories.data_models.construction.window import Window
class Construction:
"""
Construction class
"""
def __init__(self, construction_id, construction_type, name, layers, window_ratio=None, window=None):
self._id = construction_id
self._type = construction_type
@ -69,20 +65,3 @@ class Construction:
"""
return self._window
def to_dictionary(self):
"""Class content to dictionary"""
_layers = []
for _layer in self.layers:
_layers.append(_layer.to_dictionary())
_window = None
if self.window is not None:
_window = self.window.to_dictionary()
content = {'Construction': {'id': self.id,
'name': self.name,
'type': self.type,
'window ratio': self.window_ratio,
'window': _window,
'layers': _layers
}
}
return content

View File

@ -7,9 +7,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class Content:
"""
Content class
"""
def __init__(self, archetypes, constructions, materials, windows):
self._archetypes = archetypes
self._constructions = constructions
@ -43,21 +40,3 @@ class Content:
All windows in the catalog
"""
return self._windows
def to_dictionary(self):
"""Class content to dictionary"""
_archetypes = []
for _archetype in self.archetypes:
_archetypes.append(_archetype.to_dictionary())
content = {'Archetypes': _archetypes}
return content
def __str__(self):
"""Print content"""
_archetypes = []
for _archetype in self.archetypes:
_archetypes.append(_archetype.to_dictionary())
content = {'Archetypes': _archetypes}
return str(content)

View File

@ -5,13 +5,8 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from hub.catalog_factories.data_models.construction.material import Material
class Layer:
"""
Layer class
"""
def __init__(self, layer_id, name, material, thickness):
self._id = layer_id
self._name = name
@ -35,7 +30,7 @@ class Layer:
return self._name
@property
def material(self) -> Material:
def material(self):
"""
Get layer material
:return: Material
@ -49,13 +44,3 @@ class Layer:
:return: None or float
"""
return self._thickness
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Layer': {'id': self.id,
'name': self.name,
'thickness [m]': self.thickness,
'material': self.material.to_dictionary()
}
}
return content

View File

@ -7,9 +7,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class Material:
"""
Material class
"""
def __init__(self, material_id,
name,
solar_absorptance,
@ -110,19 +107,3 @@ class Material:
:return: None or float
"""
return self._thermal_resistance
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Material': {'id': self.id,
'name': self.name,
'is no-mass': self.no_mass,
'density [kg/m3]': self.density,
'specific heat [J/kgK]': self.specific_heat,
'conductivity [W/mK]': self.conductivity,
'thermal resistance [m2K/W]': self.thermal_resistance,
'solar absorptance': self.solar_absorptance,
'thermal absorptance': self.thermal_absorptance,
'visible absorptance': self.visible_absorptance
}
}
return content

View File

@ -7,9 +7,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class Window:
"""
Window class
"""
def __init__(self, window_id, frame_ratio, g_value, overall_u_value, name, window_type=None):
self._id = window_id
self._frame_ratio = frame_ratio
@ -64,16 +61,4 @@ class Window:
Get transparent surface type, 'window' or 'skylight'
:return: str
"""
return self._type
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Window': {'id': self.id,
'name': self.name,
'type': self.type,
'frame ratio': self.frame_ratio,
'g-value': self.g_value,
'overall U value [W/m2K]': self.overall_u_value
}
}
return content
return self.type

View File

@ -1,8 +1,8 @@
"""
Archetype catalog Cost
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
"""
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
@ -11,24 +11,9 @@ from hub.catalog_factories.data_models.cost.income import Income
class Archetype:
"""
Archetype class
"""
def __init__(self,
lod,
function,
municipality,
country,
currency,
capital_cost,
operational_cost,
end_of_life_cost,
income):
self._lod = lod
def __init__(self, function, municipality, currency, capital_cost, operational_cost, end_of_life_cost, income):
self._function = function
self._municipality = municipality
self._country = country
self._currency = currency
self._capital_cost = capital_cost
self._operational_cost = operational_cost
@ -41,15 +26,7 @@ class Archetype:
Get name
:return: string
"""
return f'{self._country}_{self._municipality}_{self._function}_lod{self._lod}'
@property
def lod(self):
"""
Get level of detail of the catalog
:return: string
"""
return self._lod
return f'{self._municipality}_{self._function}'
@property
def function(self):
@ -67,14 +44,6 @@ class Archetype:
"""
return self._municipality
@property
def country(self):
"""
Get country
:return: string
"""
return self._country
@property
def currency(self):
"""
@ -102,7 +71,7 @@ class Archetype:
@property
def end_of_life_cost(self):
"""
Get end of life cost in given currency per m2
Get end of life cost in given currency
:return: float
"""
return self._end_of_life_cost
@ -114,19 +83,3 @@ class Archetype:
:return: Income
"""
return self._income
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Archetype': {'name': self.name,
'level of detail': self.lod,
'municipality': self.municipality,
'country': self.country,
'currency': self.currency,
'function': self.function,
'capital cost': self.capital_cost.to_dictionary(),
'operational cost': self.operational_cost.to_dictionary(),
'end of life cost [currency/m2]': self.end_of_life_cost,
'income': self.income.to_dictionary()
}
}
return content

View File

@ -1,66 +1,68 @@
"""
Capital costs included in the catalog
Cost catalog CapitalCost
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List
from hub.catalog_factories.data_models.cost.chapter import Chapter
from hub.catalog_factories.data_models.cost.envelope import Envelope
from hub.catalog_factories.data_models.cost.systems import Systems
class CapitalCost:
"""
Capital cost class
"""
def __init__(self, general_chapters, design_allowance, overhead_and_profit):
self._general_chapters = general_chapters
self._design_allowance = design_allowance
self._overhead_and_profit = overhead_and_profit
def __init__(self, structural, sub_structural, envelope, systems, surface_finish, engineer):
self._structural = structural
self._sub_structural = sub_structural
self._envelope = envelope
self._systems = systems
self._surface_finish = surface_finish
self._engineer = engineer
@property
def general_chapters(self) -> List[Chapter]:
def structural(self):
"""
Get general chapters in capital costs
:return: [Chapter]
"""
return self._general_chapters
@property
def design_allowance(self):
"""
Get design allowance in percentage (-)
Get structural cost per building volume in currency/m3
:return: float
"""
return self._design_allowance
return self._structural
@property
def overhead_and_profit(self):
def sub_structural(self):
"""
Get overhead profit in percentage (-)
Get sub structural cost per building foot-print in currency/m2
:return: float
"""
return self._overhead_and_profit
return self._sub_structural
def chapter(self, name) -> Chapter:
@property
def envelope(self) -> Envelope:
"""
Get specific chapter by name
:return: Chapter
Get envelope cost
:return: Envelope
"""
for chapter in self.general_chapters:
if chapter.chapter_type == name:
return chapter
raise KeyError(f'Chapter name {name} not found')
return self._envelope
def to_dictionary(self):
"""Class content to dictionary"""
_chapters = []
for _chapter in self.general_chapters:
_chapters.append(_chapter.to_dictionary())
content = {'Capital cost': {'design allowance': self.design_allowance,
'overhead and profit': self.overhead_and_profit,
'chapters': _chapters
}
}
@property
def systems(self) -> Systems:
"""
Get systems cost
:return: Systems
"""
return self._systems
return content
@property
def surface_finish(self):
"""
Get surface finish cost per external surfaces areas in currency/m2
:return: float
"""
return self._surface_finish
@property
def engineer(self):
"""
Get engineer cost in %
:return: float
"""
return self._engineer

View File

@ -1,57 +0,0 @@
"""
Cost chapter description
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 typing import List
from hub.catalog_factories.data_models.cost.item_description import ItemDescription
class Chapter:
"""
Chapter class
"""
def __init__(self, chapter_type, items):
self._chapter_type = chapter_type
self._items = items
@property
def chapter_type(self):
"""
Get chapter type
:return: str
"""
return self._chapter_type
@property
def items(self) -> List[ItemDescription]:
"""
Get list of items contained in the chapter
:return: [str]
"""
return self._items
def item(self, name) -> ItemDescription:
"""
Get specific item by name
:return: ItemDescription
"""
for item in self.items:
if item.type == name:
return item
raise KeyError(f'Item name {name} not found')
def to_dictionary(self):
"""Class content to dictionary"""
_items = []
for _item in self.items:
_items.append(_item.to_dictionary())
content = {'Chapter': {'chapter type': self.chapter_type,
'items': _items
}
}
return content

View File

@ -8,9 +8,6 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
class Content:
"""
Content class
"""
def __init__(self, archetypes):
self._archetypes = archetypes
@ -20,21 +17,3 @@ class Content:
All archetypes in the catalog
"""
return self._archetypes
def to_dictionary(self):
"""Class content to dictionary"""
_archetypes = []
for _archetype in self.archetypes:
_archetypes.append(_archetype.to_dictionary())
content = {'Archetypes': _archetypes}
return content
def __str__(self):
"""Print content"""
_archetypes = []
for _archetype in self.archetypes:
_archetypes.append(_archetype.to_dictionary())
content = {'Archetypes': _archetypes}
return str(content)

View File

@ -0,0 +1,66 @@
"""
Envelope costs from Cost catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class Envelope:
def __init__(self, opaque_reposition, opaque_initial_investment, opaque_lifetime,
transparent_reposition, transparent_initial_investment, transparent_lifetime):
self._opaque_reposition = opaque_reposition
self._opaque_initial_investment = opaque_initial_investment
self._opaque_lifetime = opaque_lifetime
self._transparent_reposition = transparent_reposition
self._transparent_initial_investment = transparent_initial_investment
self._transparent_lifetime = transparent_lifetime
@property
def opaque_reposition(self):
"""
Get reposition costs for opaque envelope per area of external opaque surfaces in currency/m2
:return: float
"""
return self._opaque_reposition
@property
def opaque_initial_investment(self):
"""
Get initial investment for opaque envelope per area of external opaque surfaces in currency/m2
:return: float
"""
return self._opaque_initial_investment
@property
def opaque_lifetime(self):
"""
Get lifetime of opaque envelope in years
:return: float
"""
return self._opaque_lifetime
@property
def transparent_reposition(self):
"""
Get reposition costs for transparent envelope per area of windows in currency/m2
:return: float
"""
return self._transparent_reposition
@property
def transparent_initial_investment(self):
"""
Get initial investment for transparent envelope per area of windows in currency/m2
:return: float
"""
return self._transparent_initial_investment
@property
def transparent_lifetime(self):
"""
Get lifetime of transparent envelope in years
:return: float
"""
return self._transparent_lifetime

View File

@ -1,71 +0,0 @@
"""
Cost fuel
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 typing import Union
class Fuel:
"""
Fuel class
"""
def __init__(self, fuel_type,
fixed_monthly=None,
fixed_power=None,
variable=None,
variable_units=None):
self._fuel_type = fuel_type
self._fixed_monthly = fixed_monthly
self._fixed_power = fixed_power
self._variable = variable
self._variable_units = variable_units
@property
def type(self):
"""
Get fuel type
:return: str
"""
return self._fuel_type
@property
def fixed_monthly(self) -> Union[None, float]:
"""
Get fixed operational costs in currency per month
:return: None or float
"""
return self._fixed_monthly
@property
def fixed_power(self) -> Union[None, float]:
"""
Get fixed operational costs depending on the peak power consumed in currency per month per W
:return: None or float
"""
if self._fixed_power is not None:
return self._fixed_power/1000
return None
@property
def variable(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get variable costs in given units
:return: None, None or float, str
"""
return self._variable, self._variable_units
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Fuel': {'fuel type': self.type,
'fixed operational costs [currency/month]': self.fixed_monthly,
'fixed operational costs depending on the peak power consumed [currency/month W]': self.fixed_power,
'variable operational costs': self.variable[0],
'units': self.variable[1]
}
}
return content

View File

@ -0,0 +1,96 @@
"""
Hvac costs
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class Hvac:
def __init__(self, heating_equipment_reposition, heating_equipment_initial_investment,
heating_equipment_lifetime, cooling_equipment_reposition,
cooling_equipment_initial_investment, cooling_equipment_lifetime,
general_hvac_equipment_reposition, general_hvac_equipment_initial_investment,
general_hvac_equipment_lifetime):
self._heating_equipment_reposition = heating_equipment_reposition
self._heating_equipment_initial_investment = heating_equipment_initial_investment
self._heating_equipment_lifetime = heating_equipment_lifetime
self._cooling_equipment_reposition = cooling_equipment_reposition
self._cooling_equipment_initial_investment = cooling_equipment_initial_investment
self._cooling_equipment_lifetime = cooling_equipment_lifetime
self._general_hvac_equipment_reposition = general_hvac_equipment_reposition
self._general_hvac_equipment_initial_investment = general_hvac_equipment_initial_investment
self._general_hvac_equipment_lifetime = general_hvac_equipment_lifetime
@property
def heating_equipment_reposition(self):
"""
Get reposition costs of heating equipment per peak-load in currency/W
:return: float
"""
return self._heating_equipment_reposition
@property
def heating_equipment_initial_investment(self):
"""
Get initial investment costs of heating equipment per peak-load in currency/W
:return: float
"""
return self._heating_equipment_initial_investment
@property
def heating_equipment_lifetime(self):
"""
Get lifetime of heating equipment in years
:return: float
"""
return self._heating_equipment_lifetime
@property
def cooling_equipment_reposition(self):
"""
Get reposition costs of cooling equipment per peak-load in currency/W
:return: float
"""
return self._cooling_equipment_reposition
@property
def cooling_equipment_initial_investment(self):
"""
Get initial investment costs of cooling equipment per peak-load in currency/W
:return: float
"""
return self._cooling_equipment_initial_investment
@property
def cooling_equipment_lifetime(self):
"""
Get lifetime of cooling equipment in years
:return: float
"""
return self._cooling_equipment_lifetime
@property
def general_hvac_equipment_reposition(self):
"""
Get reposition costs of general hvac equipment per peak-air-flow in currency/(m3/s)
:return: float
"""
return self._general_hvac_equipment_reposition
@property
def general_hvac_equipment_initial_investment(self):
"""
Get initial investment costs of cooling equipment per peak-air-flow in currency/(m3/s)
:return: float
"""
return self._general_hvac_equipment_initial_investment
@property
def general_hvac_equipment_lifetime(self):
"""
Get lifetime of cooling equipment in years
:return: float
"""
return self._general_hvac_equipment_lifetime

View File

@ -1,77 +1,64 @@
"""
Incomes included in the costs catalog
Income from costs catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union
class Income:
"""
Income class
"""
def __init__(self, construction_subsidy=None,
hvac_subsidy=None,
photovoltaic_subsidy=None,
electricity_export=None,
reductions_tax=None):
self._construction_subsidy = construction_subsidy
self._hvac_subsidy = hvac_subsidy
self._photovoltaic_subsidy = photovoltaic_subsidy
self._electricity_export = electricity_export
self._reductions_tax = reductions_tax
def __init__(self, construction, hvac, photovoltaic_system, electricity_exports, heat_exports, co2):
self._construction = construction
self._hvac = hvac
self._photovoltaic_system = photovoltaic_system
self._electricity_exports = electricity_exports
self._heat_exports = heat_exports
self._co2 = co2
@property
def construction_subsidy(self) -> Union[None, float]:
def construction(self):
"""
Get subsidy for construction in percentage %
:return: None or float
Get construction subsidy in % of total investment construction cost
:return: float
"""
return self._construction_subsidy
return self._construction
@property
def hvac_subsidy(self) -> Union[None, float]:
def hvac(self):
"""
Get subsidy for HVAC system in percentage %
:return: None or float
Get hvac subsidy in % of total investment HVAC cost
:return: float
"""
return self._hvac_subsidy
return self._hvac
@property
def photovoltaic_subsidy(self) -> Union[None, float]:
def photovoltaic_system(self):
"""
Get subsidy PV systems in percentage
:return: None or float
Get photovoltaic system subsidy in % of total investment photovoltaic cost
:return: float
"""
return self._photovoltaic_subsidy
return self._photovoltaic_system
@property
def electricity_export(self) -> Union[None, float]:
def electricity_exports(self):
"""
Get electricity export incomes in currency per J
:return: None or float
Get electricity exports gains in currency/J
:return: float
"""
return self._electricity_export
return self._construction
@property
def reductions_tax(self) -> Union[None, float]:
def heat_exports(self):
"""
Get reduction in taxes in percentage (-)
:return: None or float
Get heat exports gains in currency/J
:return: float
"""
return self._reductions_tax
return self._heat_exports
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Income': {'construction subsidy [%]': self.construction_subsidy,
'hvac subsidy [%]': self.hvac_subsidy,
'photovoltaic subsidy [%]': self.photovoltaic_subsidy,
'electricity export [currency/J]': self.electricity_export,
'reductions tax': self.reductions_tax
}
}
return content
@property
def co2(self):
"""
Get co2 income in currency/kg
:return: float
"""
return self._co2

View File

@ -1,86 +0,0 @@
"""
Cost item properties
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 typing import Union
class ItemDescription:
"""
Item description class
"""
def __init__(self, item_type,
initial_investment=None,
initial_investment_unit=None,
refurbishment=None,
refurbishment_unit=None,
reposition=None,
reposition_unit=None,
lifetime=None):
self._item_type = item_type
self._initial_investment = initial_investment
self._initial_investment_unit = initial_investment_unit
self._refurbishment = refurbishment
self._refurbishment_unit = refurbishment_unit
self._reposition = reposition
self._reposition_unit = reposition_unit
self._lifetime = lifetime
@property
def type(self):
"""
Get item type
:return: str
"""
return self._item_type
@property
def initial_investment(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get initial investment of the specific item in given units
:return: None, None or float, str
"""
return self._initial_investment, self._initial_investment_unit
@property
def refurbishment(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get refurbishment costs of the specific item in given units
:return: None, None or float, str
"""
return self._refurbishment, self._refurbishment_unit
@property
def reposition(self) -> Union[tuple[None, None], tuple[float, str]]:
"""
Get reposition costs of the specific item in given units
:return: None, None or float, str
"""
return self._reposition, self._reposition_unit
@property
def lifetime(self) -> Union[None, float]:
"""
Get lifetime in years
:return: None or float
"""
return self._lifetime
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Item': {'type': self.type,
'initial investment': self.initial_investment[0],
'initial investment units': self.initial_investment[1],
'refurbishment': self.refurbishment[0],
'refurbishment units': self.refurbishment[1],
'reposition': self.reposition[0],
'reposition units': self.reposition[1],
'life time [years]': self.lifetime
}
}
return content

View File

@ -1,76 +1,104 @@
"""
Operational costs included in the catalog
Cost catalog OperationalCost
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import List
from hub.catalog_factories.data_models.cost.fuel import Fuel
class OperationalCost:
"""
Operational cost class
"""
def __init__(self, fuels, maintenance_heating, maintenance_cooling, maintenance_pv, co2):
self._fuels = fuels
self._maintenance_heating = maintenance_heating
self._maintenance_cooling = maintenance_cooling
self._maintenance_pv = maintenance_pv
self._co2 = co2
def __init__(self, fuel_type, fuel_fixed_operational_monthly, fuel_fixed_operational_peak,
fuel_variable_operational, heating_equipment_maintenance, cooling_equipment_maintenance,
general_hvac_equipment_maintenance, photovoltaic_system_maintenance, other_systems_maintenance,
co2_emissions):
self._fuel_type = fuel_type
self._fuel_fixed_operational_monthly = fuel_fixed_operational_monthly
self._fuel_fixed_operational_peak = fuel_fixed_operational_peak
self._fuel_variable_operational = fuel_variable_operational
self._heating_equipment_maintenance = heating_equipment_maintenance
self._cooling_equipment_maintenance = cooling_equipment_maintenance
self._general_hvac_equipment_maintenance = general_hvac_equipment_maintenance
self._photovoltaic_system_maintenance = photovoltaic_system_maintenance
self._other_systems_maintenance = other_systems_maintenance
self._co2_emissions = co2_emissions
@property
def fuels(self) -> List[Fuel]:
def fuel_type(self):
"""
Get fuels listed in capital costs
:return: [Fuel]
Get fuel type
:return: string
"""
return self._fuels
return self._fuel_type
@property
def maintenance_heating(self):
def fuel_fixed_operational_monthly(self):
"""
Get cost of maintaining the heating system in currency/W
Get fuel fixed operational cost in currency/month
:return: float
"""
return self._maintenance_heating
return self._fuel_fixed_operational_monthly
@property
def maintenance_cooling(self):
def fuel_fixed_operational_peak(self):
"""
Get cost of maintaining the cooling system in currency/W
Get fuel fixed operational cost per peak power in currency/W
:return: float
"""
return self._maintenance_cooling
return self._fuel_fixed_operational_peak
@property
def maintenance_pv(self):
def fuel_variable_operational(self):
"""
Get cost of maintaining the PV system in currency/m2
Get fuel variable operational cost in currency/J
:return: float
"""
return self._maintenance_pv
return self._fuel_variable_operational
@property
def co2(self):
def heating_equipment_maintenance(self):
"""
Get cost of CO2 emissions in currency/kgCO2
Get heating equipment maintenance cost per peak power in currency/W
:return: float
"""
return self._co2
return self._heating_equipment_maintenance
def to_dictionary(self):
"""Class content to dictionary"""
_fuels = []
for _fuel in self.fuels:
_fuels.append(_fuel.to_dictionary())
content = {'Maintenance': {'fuels': _fuels,
'cost of maintaining the heating system [currency/W]': self.maintenance_heating,
'cost of maintaining the cooling system [currency/W]': self.maintenance_cooling,
'cost of maintaining the PV system [currency/W]': self.maintenance_pv,
'cost of CO2 emissions [currency/kgCO2]': self.co2
}
}
@property
def cooling_equipment_maintenance(self):
"""
Get cooling equipment maintenance cost per peak power in currency/W
:return: float
"""
return self._cooling_equipment_maintenance
return content
@property
def general_hvac_equipment_maintenance(self):
"""
Get general hvac equipment maintenance cost per peak-air-flow in currency/(m3/s)
:return: float
"""
return self._general_hvac_equipment_maintenance
@property
def photovoltaic_system_maintenance(self):
"""
Get photovoltaic system maintenance cost per panels area in currency/m2
:return: float
"""
return self._photovoltaic_system_maintenance
@property
def other_systems_maintenance(self):
"""
Get other systems' maintenance cost per building's foot-print area in currency/m2
:return: float
"""
return self._other_systems_maintenance
@property
def co2_emissions(self):
"""
Get CO2 emissions cost in currency/kg
:return: float
"""
return self._co2_emissions

View File

@ -0,0 +1,106 @@
"""
Systems cost catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Atiya atiya.atiya@mail.concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.catalog_factories.data_models.cost.hvac import Hvac
class Systems:
def __init__(self, hvac, photovoltaic_system_reposition, photovoltaic_system_initial_investment,
photovoltaic_system_lifetime, other_conditioning_systems_reposition,
other_conditioning_systems_initial_investment, other_conditioning_systems_lifetime,
lighting_reposition, lighting_initial_investment, lighting_lifetime):
self._hvac = hvac
self._photovoltaic_system_reposition = photovoltaic_system_reposition
self._photovoltaic_system_initial_investment = photovoltaic_system_initial_investment
self._photovoltaic_system_lifetime = photovoltaic_system_lifetime
self._other_conditioning_systems_reposition = other_conditioning_systems_reposition
self._other_conditioning_systems_initial_investment = other_conditioning_systems_initial_investment
self._other_conditioning_systems_lifetime = other_conditioning_systems_lifetime
self._lighting_reposition = lighting_reposition
self._lighting_initial_investment = lighting_initial_investment
self._lighting_lifetime = lighting_lifetime
@property
def hvac(self) -> Hvac:
"""
Get hvac capital cost
:return: Hvac
"""
return self._hvac
@property
def photovoltaic_system_reposition(self):
"""
Get photovoltaic system reposition cost per area of panels in currency/m2
:return: float
"""
return self._photovoltaic_system_reposition
@property
def photovoltaic_system_initial_investment(self):
"""
Get photovoltaic system initial investment per area of panels in currency/m2
:return: float
"""
return self._photovoltaic_system_initial_investment
@property
def photovoltaic_system_lifetime(self):
"""
Get photovoltaic system lifetime in years
:return: float
"""
return self._photovoltaic_system_lifetime
@property
def other_conditioning_systems_reposition(self):
"""
Get other conditioning systems reposition cost per building's foot-print area in currency/m2
:return: float
"""
return self._other_conditioning_systems_reposition
@property
def other_conditioning_systems_initial_investment(self):
"""
Get other conditioning systems initial investment per building's foot-print area in currency/m2
:return: float
"""
return self._other_conditioning_systems_initial_investment
@property
def other_conditioning_systems_lifetime(self):
"""
Get other conditioning systems lifetime in years
:return: float
"""
return self._other_conditioning_systems_lifetime
@property
def lighting_reposition(self):
"""
Get lighting reposition cost per building's foot-print area in currency/m2
:return: float
"""
return self._lighting_reposition
@property
def lighting_initial_investment(self):
"""
Get lighting initial investment per building's foot-print area in currency/m2
:return: float
"""
return self._lighting_initial_investment
@property
def lighting_lifetime(self):
"""
Get lighting lifetime in years
:return: float
"""
return self._lighting_lifetime

View File

@ -1,50 +0,0 @@
"""
Energy System catalog archetype, understood as a cluster of energy systems
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
from typing import List
from hub.catalog_factories.data_models.energy_systems.system import System
class Archetype:
"""
Archetype class
"""
def __init__(self, name, systems):
self._name = name
self._systems = systems
@property
def name(self):
"""
Get name
:return: string
"""
return self._name
@property
def systems(self) -> List[System]:
"""
Get list of equipments that compose the total energy system
:return: [Equipment]
"""
return self._systems
def to_dictionary(self):
"""Class content to dictionary"""
_systems = []
for _system in self.systems:
_systems.append(_system.to_dictionary())
content = {
'Archetype': {
'name': self.name,
'systems': _systems
}
}
return content

View File

@ -1,63 +0,0 @@
"""
Energy System catalog content
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class Content:
"""
Content class
"""
def __init__(self, archetypes, systems, generations=None, distributions=None):
self._archetypes = archetypes
self._systems = systems
self._generations = generations
self._distributions = distributions
@property
def archetypes(self):
"""
All archetype system clusters in the catalog
"""
return self._archetypes
@property
def systems(self):
"""
All systems in the catalog
"""
return self._systems
@property
def generation_equipments(self):
"""
All generation equipments in the catalog
"""
return self._generations
@property
def distribution_equipments(self):
"""
All distribution equipments in the catalog
"""
return self._distributions
def to_dictionary(self):
"""Class content to dictionary"""
_archetypes = []
for _archetype in self.archetypes:
_archetypes.append(_archetype.to_dictionary())
content = {'Archetypes': _archetypes}
return content
def __str__(self):
"""Print content"""
_archetypes = []
for _archetype in self.archetypes:
_archetypes.append(_archetype.to_dictionary())
content = {'Archetypes': _archetypes}
return str(content)

View File

@ -1,140 +0,0 @@
"""
Energy System catalog distribution system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
from typing import Union, List, TypeVar
from hub.catalog_factories.data_models.energy_systems.energy_storage_system import EnergyStorageSystem
from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem
GenerationSystem = TypeVar('GenerationSystem')
class DistributionSystem:
"""
Distribution system class
"""
def __init__(self, system_id, 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):
self._system_id = system_id
self._model_name = model_name
self._type = system_type
self._supply_temperature = supply_temperature
self._distribution_consumption_fix_flow = distribution_consumption_fix_flow
self._distribution_consumption_variable_flow = distribution_consumption_variable_flow
self._heat_losses = heat_losses
self._generation_systems = generation_systems
self._energy_storage_systems = energy_storage_systems
self._emission_systems = emission_systems
@property
def id(self):
"""
Get system id
:return: float
"""
return self._system_id
@property
def model_name(self):
"""
Get model name
:return: string
"""
return self._model_name
@property
def type(self):
"""
Get type from [air, water, refrigerant]
:return: string
"""
return self._type
@property
def supply_temperature(self):
"""
Get supply_temperature in degree Celsius
:return: float
"""
return self._supply_temperature
@property
def distribution_consumption_fix_flow(self):
"""
Get distribution_consumption if the pump or fan work at fix mass or volume flow in ratio over peak power (W/W)
:return: float
"""
return self._distribution_consumption_fix_flow
@property
def distribution_consumption_variable_flow(self):
"""
Get distribution_consumption if the pump or fan work at variable mass or volume flow in ratio
over energy produced (J/J)
:return: float
"""
return self._distribution_consumption_variable_flow
@property
def heat_losses(self):
"""
Get heat_losses in ratio over energy produced in J/J
:return: float
"""
return self._heat_losses
@property
def generation_systems(self) -> Union[None, List[GenerationSystem]]:
"""
Get generation systems connected to the distribution system
:return: [GenerationSystem]
"""
return self._generation_systems
@property
def energy_storage_systems(self) -> Union[None, List[EnergyStorageSystem]]:
"""
Get energy storage systems connected to this distribution system
:return: [EnergyStorageSystem]
"""
return self._energy_storage_systems
@property
def emission_systems(self) -> Union[None, List[EmissionSystem]]:
"""
Get energy emission systems connected to this distribution system
:return: [EmissionSystem]
"""
return self._emission_systems
def to_dictionary(self):
"""Class content to dictionary"""
_generation_systems = [_generation_system.to_dictionary() for _generation_system in
self.generation_systems] if self.generation_systems is not None else None
_energy_storage_systems = [_energy_storage_system.to_dictionary() for _energy_storage_system in
self.energy_storage_systems] if self.energy_storage_systems is not None else None
_emission_systems = [_emission_system.to_dictionary() for _emission_system in
self.emission_systems] if self.emission_systems is not None else None
content = {
'Layer': {
'id': self.id,
'model name': self.model_name,
'type': self.type,
'supply temperature [Celsius]': self.supply_temperature,
'distribution consumption if fix flow over peak power [W/W]': self.distribution_consumption_fix_flow,
'distribution consumption if variable flow over peak power [J/J]': self.distribution_consumption_variable_flow,
'heat losses per energy produced [J/J]': self.heat_losses,
'generation systems connected': _generation_systems,
'energy storage systems connected': _energy_storage_systems,
'emission systems connected': _emission_systems
}
}
return content

View File

@ -1,103 +0,0 @@
"""
Energy System catalog electrical storage system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
from hub.catalog_factories.data_models.energy_systems.energy_storage_system import EnergyStorageSystem
class ElectricalStorageSystem(EnergyStorageSystem):
""""
Energy Storage System Class
"""
def __init__(self, storage_id, type_energy_stored=None, model_name=None, manufacturer=None, storage_type=None,
nominal_capacity=None, losses_ratio=None, rated_output_power=None, nominal_efficiency=None,
battery_voltage=None, depth_of_discharge=None, self_discharge_rate=None):
super().__init__(storage_id, model_name, manufacturer, nominal_capacity, losses_ratio)
self._type_energy_stored = type_energy_stored
self._storage_type = storage_type
self._rated_output_power = rated_output_power
self._nominal_efficiency = nominal_efficiency
self._battery_voltage = battery_voltage
self._depth_of_discharge = depth_of_discharge
self._self_discharge_rate = self_discharge_rate
@property
def type_energy_stored(self):
"""
Get type of energy stored from ['electrical', 'thermal']
:return: string
"""
return self._type_energy_stored
@property
def storage_type(self):
"""
Get storage type from ['lithium_ion', 'lead_acid', 'NiCd']
:return: string
"""
return self._storage_type
@property
def rated_output_power(self):
"""
Get the rated output power of storage system in Watts
:return: float
"""
return self._rated_output_power
@property
def nominal_efficiency(self):
"""
Get the nominal efficiency of the storage system
:return: float
"""
return self._nominal_efficiency
@property
def battery_voltage(self):
"""
Get the battery voltage in Volts
:return: float
"""
return self._battery_voltage
@property
def depth_of_discharge(self):
"""
Get the depth of discharge as a percentage
:return: float
"""
return self._depth_of_discharge
@property
def self_discharge_rate(self):
"""
Get the self discharge rate of battery as a percentage
:return: float
"""
return self._self_discharge_rate
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Storage component': {
'storage id': self.id,
'type of energy stored': self.type_energy_stored,
'model name': self.model_name,
'manufacturer': self.manufacturer,
'storage type': self.storage_type,
'nominal capacity [J]': self.nominal_capacity,
'losses-ratio [J/J]': self.losses_ratio,
'rated power [W]': self.rated_output_power,
'nominal efficiency': self.nominal_efficiency,
'battery voltage [V]': self.battery_voltage,
'depth of discharge [%]': self.depth_of_discharge,
'self discharge rate': self.self_discharge_rate
}
}
return content

View File

@ -1,60 +0,0 @@
"""
Energy System catalog emission system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
class EmissionSystem:
"""
Emission system class
"""
def __init__(self, system_id, model_name=None, system_type=None, parasitic_energy_consumption=0):
self._system_id = system_id
self._model_name = model_name
self._type = system_type
self._parasitic_energy_consumption = parasitic_energy_consumption
@property
def id(self):
"""
Get system id
:return: float
"""
return self._system_id
@property
def model_name(self):
"""
Get model name
:return: string
"""
return self._model_name
@property
def type(self):
"""
Get type
:return: string
"""
return self._type
@property
def parasitic_energy_consumption(self):
"""
Get parasitic_energy_consumption in ratio (J/J)
:return: float
"""
return self._parasitic_energy_consumption
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Layer': {'id': self.id,
'model name': self.model_name,
'type': self.type,
'parasitic energy consumption per energy produced [J/J]': self.parasitic_energy_consumption
}
}
return content

View File

@ -1,75 +0,0 @@
"""
Energy System catalog heat generation system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from abc import ABC
class EnergyStorageSystem(ABC):
""""
Energy Storage System Abstract Class
"""
def __init__(self, storage_id, model_name=None, manufacturer=None,
nominal_capacity=None, losses_ratio=None):
self._storage_id = storage_id
self._model_name = model_name
self._manufacturer = manufacturer
self._nominal_capacity = nominal_capacity
self._losses_ratio = losses_ratio
@property
def id(self):
"""
Get storage id
:return: string
"""
return self._storage_id
@property
def type_energy_stored(self):
"""
Get type of energy stored from ['electrical', 'thermal']
:return: string
"""
raise NotImplementedError
@property
def model_name(self):
"""
Get system model
:return: string
"""
return self._model_name
@property
def manufacturer(self):
"""
Get name of manufacturer
:return: string
"""
return self._manufacturer
@property
def nominal_capacity(self):
"""
Get the nominal capacity of the storage system in Jules
:return: float
"""
return self._nominal_capacity
@property
def losses_ratio(self):
"""
Get the losses-ratio of storage system in Jules lost / Jules stored
:return: float
"""
return self._losses_ratio
def to_dictionary(self):
"""Class content to dictionary"""
raise NotImplementedError

View File

@ -1,98 +0,0 @@
"""
Energy System catalog heat generation system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
from __future__ import annotations
from abc import ABC
from typing import List, Union
from hub.catalog_factories.data_models.energy_systems.energy_storage_system import EnergyStorageSystem
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
class GenerationSystem(ABC):
"""
Heat Generation system class
"""
def __init__(self, system_id, name, model_name=None, manufacturer=None, fuel_type=None,
distribution_systems=None, energy_storage_systems=None):
self._system_id = system_id
self._name = name
self._model_name = model_name
self._manufacturer = manufacturer
self._fuel_type = fuel_type
self._distribution_systems = distribution_systems
self._energy_storage_systems = energy_storage_systems
@property
def id(self):
"""
Get system id
:return: float
"""
return self._system_id
@property
def name(self):
"""
Get system name
:return: string
"""
return self._name
@property
def system_type(self):
"""
Get type
:return: string
"""
raise NotImplementedError
@property
def model_name(self):
"""
Get system id
:return: float
"""
return self._model_name
@property
def manufacturer(self):
"""
Get name
:return: string
"""
return self._manufacturer
@property
def fuel_type(self):
"""
Get fuel_type from [renewable, gas, diesel, electricity, wood, coal, biogas]
:return: string
"""
return self._fuel_type
@property
def distribution_systems(self) -> Union[None, List[DistributionSystem]]:
"""
Get distributions systems connected to this generation system
:return: [DistributionSystem]
"""
return self._distribution_systems
@property
def energy_storage_systems(self) -> Union[None, List[EnergyStorageSystem]]:
"""
Get energy storage systems connected to this generation system
:return: [EnergyStorageSystem]
"""
return self._energy_storage_systems
def to_dictionary(self):
"""Class content to dictionary"""
raise NotImplementedError

View File

@ -1,344 +0,0 @@
"""
Energy System catalog non PV generation system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
from typing import Union
from hub.catalog_factories.data_models.energy_systems.performance_curves import PerformanceCurves
from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem
class NonPvGenerationSystem(GenerationSystem):
"""
Non PV Generation system class
"""
def __init__(self, system_id, name, system_type, model_name=None, manufacturer=None, fuel_type=None,
nominal_heat_output=None, maximum_heat_output=None, minimum_heat_output=None, source_medium=None,
supply_medium=None, heat_efficiency=None, nominal_cooling_output=None, maximum_cooling_output=None,
minimum_cooling_output=None, cooling_efficiency=None, electricity_efficiency=None,
source_temperature=None, source_mass_flow=None, nominal_electricity_output=None,
maximum_heat_supply_temperature=None, minimum_heat_supply_temperature=None,
maximum_cooling_supply_temperature=None, minimum_cooling_supply_temperature=None, 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,
distribution_systems=None, energy_storage_systems=None, domestic_hot_water=False,
reversible=None, simultaneous_heat_cold=None):
super().__init__(system_id=system_id, name=name, model_name=model_name, manufacturer=manufacturer,
fuel_type=fuel_type, distribution_systems=distribution_systems,
energy_storage_systems=energy_storage_systems)
self._system_type = system_type
self._nominal_heat_output = nominal_heat_output
self._maximum_heat_output = maximum_heat_output
self._minimum_heat_output = minimum_heat_output
self._heat_efficiency = heat_efficiency
self._nominal_cooling_output = nominal_cooling_output
self._maximum_cooling_output = maximum_cooling_output
self._minimum_cooling_output = minimum_cooling_output
self._cooling_efficiency = cooling_efficiency
self._electricity_efficiency = electricity_efficiency
self._nominal_electricity_output = nominal_electricity_output
self._source_medium = source_medium
self._source_temperature = source_temperature
self._source_mass_flow = source_mass_flow
self._supply_medium = supply_medium
self._maximum_heat_supply_temperature = maximum_heat_supply_temperature
self._minimum_heat_supply_temperature = minimum_heat_supply_temperature
self._maximum_cooling_supply_temperature = maximum_cooling_supply_temperature
self._minimum_cooling_supply_temperature = minimum_cooling_supply_temperature
self._heat_output_curve = heat_output_curve
self._heat_fuel_consumption_curve = heat_fuel_consumption_curve
self._heat_efficiency_curve = heat_efficiency_curve
self._cooling_output_curve = cooling_output_curve
self._cooling_fuel_consumption_curve = cooling_fuel_consumption_curve
self._cooling_efficiency_curve = cooling_efficiency_curve
self._domestic_hot_water = domestic_hot_water
self._reversible = reversible
self._simultaneous_heat_cold = simultaneous_heat_cold
@property
def system_type(self):
"""
Get type
:return: string
"""
return self._system_type
@property
def nominal_heat_output(self):
"""
Get nominal heat output of heat generation devices in W
:return: float
"""
return self._nominal_heat_output
@property
def maximum_heat_output(self):
"""
Get maximum heat output of heat generation devices in W
:return: float
"""
return self._maximum_heat_output
@property
def minimum_heat_output(self):
"""
Get minimum heat output of heat generation devices in W
:return: float
"""
return self._minimum_heat_output
@property
def source_medium(self):
"""
Get source_type from [air, water, ground, district_heating, grid, on_site_electricity]
:return: string
"""
return self._source_medium
@property
def supply_medium(self):
"""
Get the supply medium from ['air', 'water']
:return: string
"""
return self._supply_medium
@property
def heat_efficiency(self):
"""
Get heat_efficiency
:return: float
"""
return self._heat_efficiency
@property
def nominal_cooling_output(self):
"""
Get nominal cooling output of heat generation devices in W
:return: float
"""
return self._nominal_cooling_output
@property
def maximum_cooling_output(self):
"""
Get maximum heat output of heat generation devices in W
:return: float
"""
return self._maximum_cooling_output
@property
def minimum_cooling_output(self):
"""
Get minimum heat output of heat generation devices in W
:return: float
"""
return self._minimum_cooling_output
@property
def cooling_efficiency(self):
"""
Get cooling_efficiency
:return: float
"""
return self._cooling_efficiency
@property
def electricity_efficiency(self):
"""
Get electricity_efficiency
:return: float
"""
return self._electricity_efficiency
@property
def source_temperature(self):
"""
Get source_temperature in degree Celsius
:return: float
"""
return self._source_temperature
@property
def source_mass_flow(self):
"""
Get source_mass_flow in kg/s
:return: float
"""
return self._source_mass_flow
@property
def nominal_electricity_output(self):
"""
Get nominal_power_output of electricity generation devices or inverters in W
:return: float
"""
return self._nominal_electricity_output
@property
def maximum_heat_supply_temperature(self):
"""
Get the maximum heat supply temperature in degree Celsius
:return: float
"""
return self._minimum_heat_supply_temperature
@property
def minimum_heat_supply_temperature(self):
"""
Get the minimum heat supply temperature in degree Celsius
:return: float
"""
return self._minimum_heat_supply_temperature
@property
def maximum_cooling_supply_temperature(self):
"""
Get the maximum cooling supply temperature in degree Celsius
:return: float
"""
return self._maximum_cooling_supply_temperature
@property
def minimum_cooling_supply_temperature(self):
"""
Get the minimum cooling supply temperature in degree Celsius
:return: float
"""
return self._minimum_cooling_supply_temperature
@property
def heat_output_curve(self) -> Union[None, PerformanceCurves]:
"""
Get the heat output curve of the heat generation device
:return: PerformanceCurve
"""
return self._heat_output_curve
@property
def heat_fuel_consumption_curve(self) -> Union[None, PerformanceCurves]:
"""
Get the heating fuel consumption curve of the heat generation device
:return: PerformanceCurve
"""
return self._heat_fuel_consumption_curve
@property
def heat_efficiency_curve(self) -> Union[None, PerformanceCurves]:
"""
Get the heating efficiency curve of the heat generation device
:return: PerformanceCurve
"""
return self._heat_efficiency_curve
@property
def cooling_output_curve(self) -> Union[None, PerformanceCurves]:
"""
Get the heat output curve of the heat generation device
:return: PerformanceCurve
"""
return self._cooling_output_curve
@property
def cooling_fuel_consumption_curve(self) -> Union[None, PerformanceCurves]:
"""
Get the heating fuel consumption curve of the heat generation device
:return: PerformanceCurve
"""
return self._cooling_fuel_consumption_curve
@property
def cooling_efficiency_curve(self) -> Union[None, PerformanceCurves]:
"""
Get the heating efficiency curve of the heat generation device
:return: PerformanceCurve
"""
return self._cooling_efficiency_curve
@property
def domestic_hot_water(self):
"""
Get the ability to produce domestic hot water
:return: bool
"""
return self._domestic_hot_water
@property
def reversibility(self):
"""
Get the ability to produce heating and cooling
:return: bool
"""
return self._reversible
@property
def simultaneous_heat_cold(self):
"""
Get the ability to produce heating and cooling at the same time
:return: bool
"""
return self._simultaneous_heat_cold
def to_dictionary(self):
"""Class content to dictionary"""
_distribution_systems = [_distribution_system.to_dictionary() for _distribution_system in
self.distribution_systems] if self.distribution_systems is not None else None
_energy_storage_systems = [_energy_storage_system.to_dictionary() for _energy_storage_system in
self.energy_storage_systems] if self.energy_storage_systems is not None else None
_heat_output_curve = self.heat_output_curve.to_dictionary() if (
self.heat_output_curve is not None) else None
_heat_fuel_consumption_curve = self.heat_fuel_consumption_curve.to_dictionary() if (
self.heat_fuel_consumption_curve is not None) else None
_heat_efficiency_curve = self.heat_efficiency_curve.to_dictionary() if (
self.heat_efficiency_curve is not None) else None
_cooling_output_curve = self.cooling_output_curve.to_dictionary() if (
self.cooling_output_curve is not None) else None
_cooling_fuel_consumption_curve = self.cooling_fuel_consumption_curve.to_dictionary() if (
self.cooling_fuel_consumption_curve is not None) else None
_cooling_efficiency_curve = self.cooling_efficiency_curve.to_dictionary() if (
self.cooling_efficiency_curve is not None) else None
content = {
'Energy Generation component':
{
'id': self.id,
'model name': self.model_name,
'manufacturer': self.manufacturer,
'type': self.system_type,
'fuel type': self.fuel_type,
'nominal heat output [W]': self.nominal_heat_output,
'maximum heat output [W]': self.maximum_heat_output,
'minimum heat output [W]': self.minimum_heat_output,
'source medium': self.source_medium,
'supply medium': self.supply_medium,
'source temperature [Celsius]': self.source_temperature,
'source mass flow [kg/s]': self.source_mass_flow,
'heat efficiency': self.heat_efficiency,
'nominal cooling output [W]': self.nominal_cooling_output,
'maximum cooling output [W]': self.maximum_cooling_output,
'minimum cooling output [W]': self.minimum_cooling_output,
'cooling efficiency': self.cooling_efficiency,
'electricity efficiency': self.electricity_efficiency,
'nominal power output [W]': self.nominal_electricity_output,
'maximum heating supply temperature [Celsius]': self.maximum_heat_supply_temperature,
'minimum heating supply temperature [Celsius]': self.minimum_heat_supply_temperature,
'maximum cooling supply temperature [Celsius]': self.maximum_cooling_supply_temperature,
'minimum cooling supply temperature [Celsius]': self.minimum_cooling_supply_temperature,
'heat output curve': self.heat_output_curve,
'heat fuel consumption curve': self.heat_fuel_consumption_curve,
'heat efficiency curve': _heat_efficiency_curve,
'cooling output curve': self.cooling_output_curve,
'cooling fuel consumption curve': self.cooling_fuel_consumption_curve,
'cooling efficiency curve': self.cooling_efficiency_curve,
'distribution systems connected': _distribution_systems,
'storage systems connected': _energy_storage_systems,
'domestic hot water production capability': self.domestic_hot_water,
'reversible cycle': self.reversibility,
'simultaneous heat and cooling production': self.simultaneous_heat_cold
}
}
return content

View File

@ -1,72 +0,0 @@
"""
Energy System catalog heat generation system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from __future__ import annotations
class PerformanceCurves:
"""
Parameter function class
"""
def __init__(self, curve_type, dependant_variable, parameters, coefficients):
self._curve_type = curve_type
self._dependant_variable = dependant_variable
self._parameters = parameters
self._coefficients = coefficients
@property
def curve_type(self):
"""
The type of the fit function from the following
Linear =>>> y = a + b*x
Exponential =>>> y = a*(b**x)
Second degree polynomial =>>> y = a + b*x + c*(x**2)
Power =>>> y = a*(x**b)
Bi-Quadratic =>>> y = a + b*x + c*(x**2) + d*z + e*(z**2) + f*x*z
Get the type of function from ['linear', 'exponential', 'second degree polynomial', 'power', 'bi-quadratic']
:return: string
"""
return self._curve_type
@property
def dependant_variable(self):
"""
y (e.g. COP in COP = a*source temperature**2 + b*source temperature + c*source temperature*supply temperature +
d*supply temperature + e*supply temperature**2 + f)
"""
return self._dependant_variable
@property
def parameters(self):
"""
Get the list of parameters involved in fitting process as ['x', 'z'] (e.g. [source temperature, supply temperature]
in COP=)
:return: string
"""
return self._parameters
@property
def coefficients(self):
"""
Get the coefficients of the functions as list of ['a', 'b', 'c', 'd', 'e', 'f']
:return: [coefficients]
"""
return self._coefficients
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Parameter Function': {
'curve type': self.curve_type,
'dependant variable': self.dependant_variable,
'parameter(s)': self.parameters,
'coefficients': self.coefficients,
}
}
return content

View File

@ -1,165 +0,0 @@
"""
Energy System catalog heat generation system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem
class PvGenerationSystem(GenerationSystem):
"""
Electricity Generation system class
"""
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_radiation=None, standard_test_condition_cell_temperature=None,
standard_test_condition_maximum_power=None, standard_test_condition_radiation=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,
manufacturer=manufacturer, fuel_type='renewable', distribution_systems=distribution_systems,
energy_storage_systems=energy_storage_systems)
self._system_type = system_type
self._electricity_efficiency = electricity_efficiency
self._nominal_electricity_output = nominal_electricity_output
self._nominal_ambient_temperature = nominal_ambient_temperature
self._nominal_cell_temperature = nominal_cell_temperature
self._nominal_radiation = nominal_radiation
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_radiation = standard_test_condition_radiation
self._cell_temperature_coefficient = cell_temperature_coefficient
self._width = width
self._height = height
@property
def system_type(self):
"""
Get type
:return: string
"""
return self._system_type
@property
def nominal_electricity_output(self):
"""
Get nominal_power_output of electricity generation devices or inverters in W
:return: float
"""
return self._nominal_electricity_output
@property
def electricity_efficiency(self):
"""
Get electricity_efficiency
:return: float
"""
return self._electricity_efficiency
@property
def nominal_ambient_temperature(self):
"""
Get nominal ambient temperature of PV panels in degree Celsius
:return: float
"""
return self._nominal_ambient_temperature
@property
def nominal_cell_temperature(self):
"""
Get nominal cell temperature of PV panels in degree Celsius
:return: float
"""
return self._nominal_cell_temperature
@property
def nominal_radiation(self):
"""
Get nominal radiation of PV panels
:return: float
"""
return self._nominal_radiation
@property
def standard_test_condition_cell_temperature(self):
"""
Get standard test condition cell temperature of PV panels in degree Celsius
:return: float
"""
return self._standard_test_condition_cell_temperature
@property
def standard_test_condition_maximum_power(self):
"""
Get standard test condition maximum power of PV panels in W
:return: float
"""
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
def cell_temperature_coefficient(self):
"""
Get cell temperature coefficient of PV module
:return: float
"""
return self._cell_temperature_coefficient
@property
def width(self):
"""
Get PV module width in m
:return: float
"""
return self._width
@property
def height(self):
"""
Get PV module height in m
:return: float
"""
return self._height
def to_dictionary(self):
"""Class content to dictionary"""
_distribution_systems = [_distribution_system.to_dictionary() for _distribution_system in
self.distribution_systems] if self.distribution_systems is not None else None
_energy_storage_systems = [_energy_storage_system.to_dictionary() for _energy_storage_system in
self.energy_storage_systems] if self.energy_storage_systems is not None else None
content = {
'Energy Generation component':
{
'id': self.id,
'model name': self.model_name,
'manufacturer': self.manufacturer,
'type': self.system_type,
'fuel type': self.fuel_type,
'electricity efficiency': self.electricity_efficiency,
'nominal power output [W]': self.nominal_electricity_output,
'nominal ambient temperature [Celsius]': self.nominal_ambient_temperature,
'nominal cell temperature [Celsius]': self.nominal_cell_temperature,
'nominal radiation [W/m2]': self.nominal_radiation,
'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 radiation [W/m2]': self.standard_test_condition_radiation,
'cell temperature coefficient': self.cell_temperature_coefficient,
'width': self.width,
'height': self.height,
'distribution systems connected': _distribution_systems,
'storage systems connected': _energy_storage_systems
}
}
return content

View File

@ -1,99 +0,0 @@
"""
Energy Systems catalog System
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
from typing import Union, List
from pathlib import Path
from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
class System:
"""
System class
"""
def __init__(self,
system_id,
demand_types,
name=None,
generation_systems=None,
distribution_systems=None,
configuration_schema=None):
self._system_id = system_id
self._name = name
self._demand_types = demand_types
self._generation_systems = generation_systems
self._distribution_systems = distribution_systems
self._configuration_schema = configuration_schema
@property
def id(self):
"""
Get equipment id
:return: string
"""
return self._system_id
@property
def name(self):
"""
Get the system name
:return: string
"""
return self._name
@property
def demand_types(self):
"""
Get demand able to cover from ['heating', 'cooling', 'domestic_hot_water', 'electricity']
:return: [string]
"""
return self._demand_types
@property
def generation_systems(self) -> Union[None, List[GenerationSystem]]:
"""
Get generation systems
:return: [GenerationSystem]
"""
return self._generation_systems
@property
def distribution_systems(self) -> Union[None, List[DistributionSystem]]:
"""
Get distribution systems
:return: [DistributionSystem]
"""
return self._distribution_systems
@property
def configuration_schema(self) -> Path:
"""
Get system configuration schema
:return: Path
"""
return self._configuration_schema
def to_dictionary(self):
"""Class content to dictionary"""
_generation_systems = []
for _generation in self.generation_systems:
_generation_systems.append(_generation.to_dictionary())
_distribution_systems = [_distribution.to_dictionary() for _distribution in
self.distribution_systems] if self.distribution_systems is not None else None
content = {'system': {'id': self.id,
'name': self.name,
'demand types': self.demand_types,
'generation system(s)': _generation_systems,
'distribution system(s)': _distribution_systems,
'configuration schema path': self.configuration_schema
}
}
return content

View File

@ -1,126 +0,0 @@
"""
Energy System catalog thermal storage system
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
"""
from hub.catalog_factories.data_models.energy_systems.energy_storage_system import EnergyStorageSystem
from hub.catalog_factories.data_models.construction.layer import Layer
from hub.catalog_factories.data_models.construction.material import Material
class ThermalStorageSystem(EnergyStorageSystem):
""""
Energy Storage System Class
"""
def __init__(self, storage_id, type_energy_stored=None, model_name=None, manufacturer=None, storage_type=None,
nominal_capacity=None, losses_ratio=None, volume=None, height=None, layers=None,
maximum_operating_temperature=None, storage_medium=None, heating_coil_capacity=None):
super().__init__(storage_id, model_name, manufacturer, nominal_capacity, losses_ratio)
self._type_energy_stored = type_energy_stored
self._storage_type = storage_type
self._volume = volume
self._height = height
self._layers = layers
self._maximum_operating_temperature = maximum_operating_temperature
self._storage_medium = storage_medium
self._heating_coil_capacity = heating_coil_capacity
@property
def type_energy_stored(self):
"""
Get type of energy stored from ['electrical', 'thermal']
:return: string
"""
return self._type_energy_stored
@property
def storage_type(self):
"""
Get storage type from ['thermal', 'sensible', 'latent']
:return: string
"""
return self._storage_type
@property
def volume(self):
"""
Get the physical volume of the storage system in cubic meters
:return: float
"""
return self._volume
@property
def height(self):
"""
Get the diameter of the storage system in meters
:return: float
"""
return self._height
@property
def layers(self) -> [Layer]:
"""
Get construction layers
:return: [layer]
"""
return self._layers
@property
def maximum_operating_temperature(self):
"""
Get maximum operating temperature of the storage system in degree Celsius
:return: float
"""
return self._maximum_operating_temperature
@property
def storage_medium(self) -> Material:
"""
Get thermodynamic characteristics of the storage medium
:return: [material
"""
return self._storage_medium
@property
def heating_coil_capacity(self):
"""
Get heating coil capacity in Watts
:return: [material
"""
return self._heating_coil_capacity
def to_dictionary(self):
"""Class content to dictionary"""
_layers = None
_medias = None
if self.layers is not None:
_layers = []
for _layer in self.layers:
_layers.append(_layer.to_dictionary())
if self.storage_medium is not None:
_medias = self.storage_medium.to_dictionary()
content = {
'Storage component':
{
'storage id': self.id,
'type of energy stored': self.type_energy_stored,
'model name': self.model_name,
'manufacturer': self.manufacturer,
'storage type': self.storage_type,
'nominal capacity [J]': self.nominal_capacity,
'losses-ratio [J/J]': self.losses_ratio,
'volume [m3]': self.volume,
'height [m]': self.height,
'layers': _layers,
'maximum operating temperature [Celsius]': self.maximum_operating_temperature,
'storage_medium': self.storage_medium.to_dictionary(),
'heating coil capacity [W]': self.heating_coil_capacity
}
}
return content

View File

@ -7,9 +7,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class Content:
"""
Content class
"""
def __init__(self, vegetations, plants, soils):
self._vegetations = vegetations
self._plants = plants
@ -36,20 +33,3 @@ class Content:
"""
return self._soils
def to_dictionary(self):
"""Class content to dictionary"""
_archetypes = []
for _archetype in self.vegetations:
_archetypes.append(_archetype.to_dictionary())
content = {'Archetypes': _archetypes}
return content
def __str__(self):
"""Print content"""
_archetypes = []
for _archetype in self.vegetations:
_archetypes.append(_archetype.to_dictionary())
content = {'Archetypes': _archetypes}
return str(content)

View File

@ -9,9 +9,6 @@ from hub.catalog_factories.data_models.greenery.soil import Soil as hub_soil
class Plant:
"""
Plant class
"""
def __init__(self, category, plant):
self._name = plant.name
self._category = category
@ -96,22 +93,3 @@ class Plant:
:return: [Soil]
"""
return self._grows_on
def to_dictionary(self):
"""Class content to dictionary"""
_soils = []
for _soil in self.grows_on:
_soils.append(_soil.to_dictionary())
content = {'Plant': {'name': self.name,
'category': self.category,
'height [m]': self.height,
'leaf area index': self.leaf_area_index,
'leaf reflectivity': self.leaf_reflectivity,
'leaf emissivity': self.leaf_emissivity,
'minimal stomatal resistance [s/m]': self.minimal_stomatal_resistance,
'co2 sequestration [kg????]': self.co2_sequestration,
'soils where it grows on': _soils
}
}
return content

View File

@ -5,13 +5,10 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from hub.catalog_factories.data_models.greenery.plant import Plant as HubPlant
from hub.catalog_factories.data_models.greenery.plant import Plant as libs_plant
class PlantPercentage(HubPlant):
"""
Plant percentage class
"""
class PlantPercentage(libs_plant):
def __init__(self, percentage, plant_category, plant):
super().__init__(plant_category, plant)
@ -24,23 +21,3 @@ class PlantPercentage(HubPlant):
:return: float
"""
return self._percentage
def to_dictionary(self):
"""Class content to dictionary"""
_soils = []
for _soil in self.grows_on:
_soils.append(_soil.to_dictionary())
content = {'Plant': {'name': self.name,
'percentage': self.percentage,
'category': self.category,
'height [m]': self.height,
'leaf area index': self.leaf_area_index,
'leaf reflectivity': self.leaf_reflectivity,
'leaf emissivity': self.leaf_emissivity,
'minimal stomatal resistance [s/m]': self.minimal_stomatal_resistance,
'co2 sequestration [kg????]': self.co2_sequestration,
'soils where it grows on': _soils
}
}
return content

View File

@ -7,9 +7,6 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
class Soil:
"""
Soil class
"""
def __init__(self, soil):
self._name = soil.name
self._roughness = soil.roughness
@ -110,20 +107,3 @@ class Soil:
:return: float
"""
return self._initial_volumetric_moisture_content
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Soil': {'name': self.name,
# 'roughness': self.roughness, # todo: this line prints value=2????
'dry conductivity [W/m2K]': self.dry_conductivity,
'dry density [kg/m3]': self.dry_density,
'dry specific heat [J/kgK]': self.dry_specific_heat,
'thermal absorptance': self.thermal_absorptance,
'solar absorptance': self.solar_absorptance,
'visible absorptance': self.visible_absorptance,
'saturation volumetric moisture content [units??]': self.saturation_volumetric_moisture_content,
'residual volumetric moisture content [units??]': self.residual_volumetric_moisture_content
}
}
return content

View File

@ -9,9 +9,6 @@ from hub.catalog_factories.data_models.greenery.plant_percentage import PlantPer
class Vegetation:
"""
Vegetation class
"""
def __init__(self, category, vegetation, plant_percentages):
self._name = vegetation.name
self._category = category
@ -171,28 +168,3 @@ class Vegetation:
:return: float
"""
return self._soil_initial_volumetric_moisture_content
def to_dictionary(self):
"""Class content to dictionary"""
_plants = []
for _plant in self.plant_percentages:
_plants.append(_plant.to_dictionary())
content = {'Archetype': {'name': self.name,
'category': self.category,
'air gap thickness [m]': self.air_gap,
'soil thickness [m]': self.soil_thickness,
'soil name': self.soil_name,
# 'soil roughness': self.soil_roughness, # todo: this line prints value=2????
'dry soil conductivity [W/m2K]': self.dry_soil_conductivity,
'dry soil density [kg/m3]': self.dry_soil_density,
'dry soil specific heat [J/kgK]': self.dry_soil_specific_heat,
'soil thermal absorptance': self.soil_thermal_absorptance,
'soil solar absorptance': self.soil_solar_absorptance,
'soil visible absorptance': self.soil_visible_absorptance,
'soil saturation volumetric moisture content [units??]': self.soil_saturation_volumetric_moisture_content,
'soil residual volumetric moisture content [units??]': self.soil_residual_volumetric_moisture_content,
'plants': _plants
}
}
return content

View File

@ -24,7 +24,7 @@ class Appliances:
@property
def density(self) -> Union[None, float]:
"""
Get appliances density in W/m2
Get appliances density in Watts per m2
:return: None or float
"""
return self._density
@ -61,16 +61,3 @@ class Appliances:
:return: None or [Schedule]
"""
return self._schedules
def to_dictionary(self):
"""Class content to dictionary"""
_schedules = []
for _schedule in self.schedules:
_schedules.append(_schedule.to_dictionary())
content = {'Appliances': {'density [W/m2]': self.density,
'convective fraction': self.convective_fraction,
'radiative fraction': self.radiative_fraction,
'latent fraction': self.latent_fraction,
'schedules': _schedules}
}
return content

View File

@ -8,9 +8,6 @@ from hub.catalog_factories.data_models.usages.usage import Usage
class Content:
"""
Content class
"""
def __init__(self, usages):
self._usages = usages
@ -21,20 +18,3 @@ class Content:
"""
return self._usages
def to_dictionary(self):
"""Class content to dictionary"""
_usages = []
for _usage in self.usages:
_usages.append(_usage.to_dictionary())
content = {'Usages': _usages}
return content
def __str__(self):
"""Print content"""
_usages = []
for _usage in self.usages:
_usages.append(_usage.to_dictionary())
content = {'Usages': _usages}
return str(content)

View File

@ -1,66 +0,0 @@
"""
Usage catalog domestic hot water
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 typing import Union, List
from hub.catalog_factories.data_models.usages.schedule import Schedule
class DomesticHotWater:
"""
DomesticHotWater class
"""
def __init__(self, density, peak_flow, service_temperature, schedules):
self._density = density
self._peak_flow = peak_flow
self._service_temperature = service_temperature
self._schedules = schedules
@property
def density(self) -> Union[None, float]:
"""
Get domestic hot water load density in Watts per m2
:return: None or float
"""
return self._density
@property
def peak_flow(self) -> Union[None, float]:
"""
Get domestic hot water peak_flow density in m3 per second and m2
:return: None or float
"""
return self._peak_flow
@property
def service_temperature(self) -> Union[None, float]:
"""
Get service temperature in degrees Celsius
:return: None or float
"""
return self._service_temperature
@property
def schedules(self) -> Union[None, List[Schedule]]:
"""
Get schedules
dataType = fraction of loads
:return: None or [Schedule]
"""
return self._schedules
def to_dictionary(self):
"""Class content to dictionary"""
_schedules = []
for _schedule in self.schedules:
_schedules.append(_schedule.to_dictionary())
content = {'Domestic hot water': {'density [W/m2]': self.density,
'peak flow [m3/sm2]': self.peak_flow,
'service temperature [Celsius]': self.service_temperature,
'schedules': _schedules}
}
return content

View File

@ -0,0 +1,22 @@
"""
Usage catalog internal gain
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class InternalGain:
"""
InternalGain class
"""
def __init__(self, internal_gain_type, average_internal_gain, convective_fraction, radiative_fraction, latent_fraction, schedules):
self._type = internal_gain_type
self._average_internal_gain = average_internal_gain
self._convective_fraction = convective_fraction
self._radiative_fraction = radiative_fraction
self._latent_fraction = latent_fraction
self._schedules = schedules

View File

@ -11,9 +11,6 @@ from hub.catalog_factories.data_models.usages.schedule import Schedule
class Lighting:
"""
Lighting class
"""
def __init__(self, density, convective_fraction, radiative_fraction, latent_fraction, schedules):
self._density = density
self._convective_fraction = convective_fraction
@ -61,16 +58,3 @@ class Lighting:
:return: None or [Schedule]
"""
return self._schedules
def to_dictionary(self):
"""Class content to dictionary"""
_schedules = []
for _schedule in self.schedules:
_schedules.append(_schedule.to_dictionary())
content = {'Lighting': {'density [W/m2]': self.density,
'convective fraction': self.convective_fraction,
'radiative fraction': self.radiative_fraction,
'latent fraction': self.latent_fraction,
'schedules': _schedules}
}
return content

View File

@ -2,7 +2,7 @@
Usage catalog occupancy
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
Project Coder Guille Gutierrez Morote Guillermo.GutierrezMorote@concordia.ca
"""
from typing import Union, List
@ -65,16 +65,3 @@ class Occupancy:
:return: None or [Schedule]
"""
return self._schedules
def to_dictionary(self):
"""Class content to dictionary"""
_schedules = []
for _schedule in self.schedules:
_schedules.append(_schedule.to_dictionary())
content = {'Occupancy': {'occupancy density [persons/m2]': self.occupancy_density,
'sensible convective internal gain [W/m2]': self.sensible_convective_internal_gain,
'sensible radiative internal gain [W/m2]': self.sensible_radiative_internal_gain,
'latent internal gain [W/m2]': self.latent_internal_gain,
'schedules': _schedules}
}
return content

View File

@ -74,13 +74,3 @@ class Schedule:
"""
return self._day_types
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Schedule': {'type': self.type,
'time range': self.time_range,
'time step': self.time_step,
'data type': self.data_type,
'day types': self.day_types,
'values': self.values}
}
return content

View File

@ -18,7 +18,6 @@ class ThermalControl:
hvac_availability_schedules,
heating_set_point_schedules,
cooling_set_point_schedules):
self._mean_heating_set_point = mean_heating_set_point
self._heating_set_back = heating_set_back
self._mean_cooling_set_point = mean_cooling_set_point
@ -76,23 +75,3 @@ class ThermalControl:
:return: None or [Schedule]
"""
return self._cooling_set_point_schedules
def to_dictionary(self):
"""Class content to dictionary"""
_hvac_schedules = []
for _schedule in self.hvac_availability_schedules:
_hvac_schedules.append(_schedule.to_dictionary())
_heating_set_point_schedules = []
for _schedule in self.heating_set_point_schedules:
_heating_set_point_schedules.append(_schedule.to_dictionary())
_cooling_set_point_schedules = []
for _schedule in self.cooling_set_point_schedules:
_cooling_set_point_schedules.append(_schedule.to_dictionary())
content = {'Thermal control': {'mean heating set point [Celsius]': self.mean_heating_set_point,
'heating set back [Celsius]': self.heating_set_back,
'mean cooling set point [Celsius]': self.mean_cooling_set_point,
'hvac availability schedules': _hvac_schedules,
'heating set point schedules': _heating_set_point_schedules,
'cooling set point schedules': _cooling_set_point_schedules}
}
return content

View File

@ -8,15 +8,11 @@ from typing import Union
from hub.catalog_factories.data_models.usages.appliances import Appliances
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.ocupancy import Occupancy
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
class Usage:
"""
Usage class
"""
def __init__(self, name,
hours_day,
days_year,
@ -25,18 +21,17 @@ class Usage:
occupancy,
lighting,
appliances,
thermal_control,
domestic_hot_water):
thermal_control):
self._name = name
self._hours_day = hours_day
self._days_year = days_year
self._mechanical_air_change = mechanical_air_change
self._ventilation_rate = ventilation_rate
# classes
self._occupancy = occupancy
self._lighting = lighting
self._appliances = appliances
self._thermal_control = thermal_control
self._domestic_hot_water = domestic_hot_water
@property
def name(self) -> Union[None, str]:
@ -65,7 +60,7 @@ class Usage:
@property
def mechanical_air_change(self) -> Union[None, float]:
"""
Get usage zone mechanical air change in air change per second (1/s)
Get usage zone mechanical air change in air change per hour (ACH)
:return: None or float
"""
return self._mechanical_air_change
@ -113,31 +108,7 @@ class Usage:
@property
def thermal_control(self) -> Union[None, ThermalControl]:
"""
Get thermal control information
Get thermal control of this thermal zone
:return: None or ThermalControl
"""
return self._thermal_control
@property
def domestic_hot_water(self) -> Union[None, DomesticHotWater]:
"""
Get domestic hot water information
:return: None or DomesticHotWater
"""
return self._domestic_hot_water
def to_dictionary(self):
"""Class content to dictionary"""
content = {'Usage': {'name': self.name,
'hours a day': self.hours_day,
'days a year': self.days_year,
'mechanical air change [ACH]': self.mechanical_air_change,
'ventilation rate [m3/sm2]': self.ventilation_rate,
'occupancy': self.occupancy.to_dictionary(),
'lighting': self.lighting.to_dictionary(),
'appliances': self.appliances.to_dictionary(),
'thermal control': self.thermal_control.to_dictionary(),
'domestic hot water': self.domestic_hot_water.to_dictionary()
}
}
return content

View File

@ -1,256 +0,0 @@
"""
Montreal custom energy systems catalog module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from ast import literal_eval
import xmltodict
from hub.catalog_factories.catalog import Catalog
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.distribution_system import DistributionSystem
from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem
from hub.catalog_factories.data_models.energy_systems.archetype import Archetype
from hub.catalog_factories.data_models.energy_systems.thermal_storage_system import ThermalStorageSystem
from hub.catalog_factories.data_models.energy_systems.electrical_storage_system import ElectricalStorageSystem
class MontrealCustomCatalog(Catalog):
"""
Montreal custom energy systems catalog class
"""
def __init__(self, path):
path = str(path / 'montreal_custom_systems.xml')
with open(path, 'r', encoding='utf-8') as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list=('system', 'system_cluster', 'equipment',
'demand', 'system_id'))
self._catalog_generation_equipments = self._load_generation_equipments()
self._catalog_emission_equipments = self._load_emission_equipments()
self._catalog_distribution_equipments = self._load_distribution_equipments()
self._catalog_systems = self._load_systems()
self._catalog_archetypes = self._load_archetypes()
# store the full catalog data model in self._content
self._content = Content(self._catalog_archetypes,
self._catalog_systems,
self._catalog_generation_equipments,
self._catalog_distribution_equipments)
def _load_generation_equipments(self):
_equipments = []
_storages = []
equipments = self._archetypes['catalog']['generation_equipments']['equipment']
for equipment in equipments:
equipment_id = float(equipment['@id'])
equipment_type = equipment['@type']
fuel_type = equipment['@fuel_type']
model_name = equipment['name']
heating_efficiency = None
if 'heating_efficiency' in equipment:
heating_efficiency = float(equipment['heating_efficiency'])
cooling_efficiency = None
if 'cooling_efficiency' in equipment:
cooling_efficiency = float(equipment['cooling_efficiency'])
electricity_efficiency = None
if 'electrical_efficiency' in equipment:
electricity_efficiency = float(equipment['electrical_efficiency'])
storage_systems = None
storage = literal_eval(equipment['storage'].capitalize())
if storage:
if equipment_type == 'electricity generator':
storage_system = ElectricalStorageSystem(equipment_id)
else:
storage_system = ThermalStorageSystem(equipment_id)
storage_systems = [storage_system]
if model_name == 'PV system':
system_type = 'Photovoltaic'
generation_system = PvGenerationSystem(equipment_id,
name=None,
system_type= system_type,
model_name=model_name,
electricity_efficiency=electricity_efficiency,
energy_storage_systems=storage_systems
)
else:
generation_system = NonPvGenerationSystem(equipment_id,
name=None,
model_name=model_name,
system_type=equipment_type,
fuel_type=fuel_type,
heat_efficiency=heating_efficiency,
cooling_efficiency=cooling_efficiency,
electricity_efficiency=electricity_efficiency,
energy_storage_systems=storage_systems,
domestic_hot_water=False
)
_equipments.append(generation_system)
return _equipments
def _load_distribution_equipments(self):
_equipments = []
equipments = self._archetypes['catalog']['distribution_equipments']['equipment']
for equipment in equipments:
equipment_id = float(equipment['@id'])
equipment_type = equipment['@type']
model_name = equipment['name']
distribution_heat_losses = None
if 'distribution_heat_losses' in equipment:
distribution_heat_losses = float(equipment['distribution_heat_losses']['#text']) / 100
distribution_consumption_fix_flow = None
if 'distribution_consumption_fix_flow' in equipment:
distribution_consumption_fix_flow = float(equipment['distribution_consumption_fix_flow']['#text']) / 100
distribution_consumption_variable_flow = None
if 'distribution_consumption_variable_flow' in equipment:
distribution_consumption_variable_flow = float(
equipment['distribution_consumption_variable_flow']['#text']) / 100
emission_equipment = equipment['dissipation_id']
_emission_equipments = None
for equipment_archetype in self._catalog_emission_equipments:
if int(equipment_archetype.id) == int(emission_equipment):
_emission_equipments = [equipment_archetype]
distribution_system = DistributionSystem(equipment_id,
model_name=model_name,
system_type=equipment_type,
distribution_consumption_fix_flow=distribution_consumption_fix_flow,
distribution_consumption_variable_flow=distribution_consumption_variable_flow,
heat_losses=distribution_heat_losses,
emission_systems=_emission_equipments)
_equipments.append(distribution_system)
return _equipments
def _load_emission_equipments(self):
_equipments = []
equipments = self._archetypes['catalog']['dissipation_equipments']['equipment']
for equipment in equipments:
equipment_id = float(equipment['@id'])
equipment_type = equipment['@type']
model_name = equipment['name']
parasitic_consumption = 0
if 'parasitic_consumption' in equipment:
parasitic_consumption = float(equipment['parasitic_consumption']['#text']) / 100
emission_system = EmissionSystem(equipment_id,
model_name=model_name,
system_type=equipment_type,
parasitic_energy_consumption=parasitic_consumption)
_equipments.append(emission_system)
return _equipments
def _load_systems(self):
_catalog_systems = []
systems = self._archetypes['catalog']['systems']['system']
for system in systems:
system_id = float(system['@id'])
name = system['name']
demands = system['demands']['demand']
generation_equipment = system['equipments']['generation_id']
_generation_equipments = None
for equipment_archetype in self._catalog_generation_equipments:
if int(equipment_archetype.id) == int(generation_equipment):
_generation_equipments = [equipment_archetype]
distribution_equipment = system['equipments']['distribution_id']
_distribution_equipments = None
for equipment_archetype in self._catalog_distribution_equipments:
if int(equipment_archetype.id) == int(distribution_equipment):
_distribution_equipments = [equipment_archetype]
_catalog_systems.append(System(system_id,
demands,
name=name,
generation_systems=_generation_equipments,
distribution_systems=_distribution_equipments))
return _catalog_systems
def _load_archetypes(self):
_catalog_archetypes = []
system_clusters = self._archetypes['catalog']['system_clusters']['system_cluster']
for system_cluster in system_clusters:
name = system_cluster['@name']
systems = system_cluster['systems']['system_id']
_systems = []
for system in systems:
for system_archetype in self._catalog_systems:
if int(system_archetype.id) == int(system):
_systems.append(system_archetype)
_catalog_archetypes.append(Archetype(name, _systems))
return _catalog_archetypes
def names(self, category=None):
"""
Get the catalog elements names
:parm: optional category filter
"""
if category is None:
_names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'distribution_equipments': [],
'emission_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.model_name)
for equipment in self._content.distribution_equipments:
_names['distribution_equipments'].append(equipment.model_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.model_name)
elif category.lower() == 'distribution_equipments':
for system in self._content.distribution_equipments:
_names[category].append(system.model_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
if category.lower() == 'distribution_equipments':
return self._content.distribution_equipments
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.model_name.lower() == name.lower():
return entry
for entry in self._content.distribution_equipments:
if entry.model_name.lower() == name.lower():
return entry
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -1,559 +0,0 @@
"""
Montreal future 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 MontrealFutureSystemCatalogue(Catalog):
"""
North america energy system catalog class
"""
def __init__(self, path):
path = str(path / 'montreal_future_systems.xml')
with open(path, 'r', encoding='utf-8') as xml:
self._archetypes = xmltodict.parse(xml.read(),
force_list=['pv_generation_component', 'templateStorages', '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']
template_storages = self._archetypes['EnergySystemCatalog']['energy_storage_components']['templateStorages']
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)
for template in template_storages:
storage_id = template['storage_id']
storage_type = template['storage_type']
type_energy_stored = template['type_energy_stored']
maximum_operating_temperature = template['maximum_operating_temperature']
height = float(template['physical_characteristics']['height'])
materials = self._load_materials()
insulation_material_id = template['insulation']['material_id']
insulation_material = self._search_material(materials, insulation_material_id)
material_id = template['physical_characteristics']['material_id']
tank_material = self._search_material(materials, material_id)
thickness = float(template['insulation']['insulationThickness']) / 100 # from cm to m
insulation_layer = Layer(None, 'insulation', insulation_material, thickness)
thickness = float(template['physical_characteristics']['tankThickness']) / 100 # from cm to m
tank_layer = Layer(None, 'tank', tank_material, thickness)
layers = [insulation_layer, tank_layer]
media = self._load_media()
media_id = template['storage_medium']['medium_id']
medium = self._search_media(media, media_id)
model_name = template['model_name']
manufacturer = template['manufacturer']
nominal_capacity = template['nominal_capacity']
losses_ratio = template['losses_ratio']
volume = template['physical_characteristics']['volume']
heating_coil_capacity = template['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 = 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

@ -1,520 +0,0 @@
"""
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

@ -1,57 +0,0 @@
"""
Energy Systems catalog factory, publish the energy systems information
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from pathlib import Path
from typing import TypeVar
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.palma_system_catalgue import PalmaSystemCatalogue
from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog')
class EnergySystemsCatalogFactory:
"""
Energy system catalog factory class
"""
def __init__(self, handler, base_path=None):
if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
self._handler = '_' + handler.lower()
validate_import_export_type(EnergySystemsCatalogFactory, handler)
self._path = base_path
@property
def _montreal_custom(self):
"""
Retrieve NRCAN catalog
"""
return MontrealCustomCatalog(self._path)
@property
def _montreal_future(self):
"""
Retrieve North American catalog
"""
return MontrealFutureSystemCatalogue(self._path)
@property
def _palma(self):
"""
Retrieve Palma catalog
"""
return PalmaSystemCatalogue(self._path)
@property
def catalog(self) -> Catalog:
"""
Enrich the city given to the class using the class given handler
:return: Catalog
"""
return getattr(self, self._handler, lambda: None)

View File

@ -5,36 +5,33 @@ Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pathlib import Path
from pyecore.resources import ResourceSet, URI
from hub.catalog_factories.greenery.ecore_greenery.greenerycatalog import GreeneryCatalog as Gc
from hub.catalog_factories.greenery.ecore_greenery.greenerycatalog import GreeneryCatalog as gc
from hub.catalog_factories.catalog import Catalog
from hub.catalog_factories.data_models.greenery.vegetation import Vegetation as HubVegetation
from hub.catalog_factories.data_models.greenery.plant import Plant as HubPlant
from hub.catalog_factories.data_models.greenery.soil import Soil as HubSoil
from hub.catalog_factories.data_models.greenery.plant_percentage import PlantPercentage as HubPlantPercentage
from pathlib import Path
from hub.catalog_factories.data_models.greenery.vegetation import Vegetation as libs_vegetation
from hub.catalog_factories.data_models.greenery.plant import Plant as libs_plant
from hub.catalog_factories.data_models.greenery.soil import Soil as libs_soil
from hub.catalog_factories.data_models.greenery.plant_percentage import PlantPercentage as libs_pp
from hub.catalog_factories.data_models.greenery.content import Content as GreeneryContent
class GreeneryCatalog(Catalog):
"""
Greenery catalog class
"""
def __init__(self, path):
base_path = Path(Path(__file__).parent / 'ecore_greenery/greenerycatalog_no_quantities.ecore').resolve()
base_path = Path(Path(__file__).parent / 'ecore_greenery' / 'greenerycatalog_no_quantities.ecore')
resource_set = ResourceSet()
data_model = resource_set.get_resource(URI(str(base_path)))
data_model_root = data_model.contents[0]
resource_set.metamodel_registry[data_model_root.nsURI] = data_model_root
resource = resource_set.get_resource(URI(str(path)))
catalog_data: Gc = resource.contents[0]
catalog_data: gc = resource.contents[0]
plants = []
for plant_category in catalog_data.plantCategories:
name = plant_category.name
for plant in plant_category.plants:
plants.append(HubPlant(name, plant))
plants.append(libs_plant(name, plant))
vegetations = []
for vegetation_category in catalog_data.vegetationCategories:
@ -48,19 +45,17 @@ class GreeneryCatalog(Catalog):
if plant.name == plant_percentage.plant.name:
plant_category = plant.category
break
plant_percentages.append(
HubPlantPercentage(plant_percentage.percentage, plant_category, plant_percentage.plant)
)
vegetations.append(HubVegetation(name, vegetation, plant_percentages))
plant_percentages.append(libs_pp(plant_percentage.percentage,plant_category, plant_percentage.plant))
vegetations.append(libs_vegetation(name, vegetation, plant_percentages))
plants = []
for plant_category in catalog_data.plantCategories:
name = plant_category.name
for plant in plant_category.plants:
plants.append(HubPlant(name, plant))
plants.append(libs_plant(name, plant))
soils = []
for soil in catalog_data.soils:
soils.append(HubSoil(soil))
soils.append(libs_soil(soil))
self._content = GreeneryContent(vegetations, plants, soils)
@ -108,15 +103,14 @@ class GreeneryCatalog(Catalog):
raise IndexError(f"{name} doesn't exists in the catalog")
def entries(self, category=None):
"""
Get all entries from the greenery catalog optionally filtered by category
"""
if category is None:
return self._content
else:
if category.lower() == 'vegetations':
return self._content.vegetations
if category.lower() == 'plants':
elif category.lower() == 'plants':
return self._content.plants
if category.lower() == 'soils':
elif category.lower() == 'soils':
return self._content.soils
else:
raise ValueError(f'Unknown category [{category}]')

View File

@ -7,9 +7,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
from pathlib import Path
from typing import TypeVar
from hub.catalog_factories.greenery.greenery_catalog import GreeneryCatalog
from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog')
@ -17,10 +17,15 @@ class GreeneryCatalogFactory:
"""
GreeneryCatalogFactory class
"""
def __init__(self, handler, base_path=None):
def __init__(self, file_type, base_path=None):
if base_path is None:
base_path = (Path(__file__).parent.parent / 'data/greenery').resolve()
self._handler = '_' + handler.lower()
base_path = Path(Path(__file__).parent.parent / 'data/greenery')
self._catalog_type = '_' + file_type.lower()
class_funcs = validate_import_export_type(GreeneryCatalogFactory)
if self._catalog_type not in class_funcs:
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._path = base_path
@property
@ -37,4 +42,4 @@ class GreeneryCatalogFactory:
Enrich the city given to the class using the class given handler
:return: Catalog
"""
return getattr(self, self._handler, lambda: None)
return getattr(self, self._catalog_type, lambda: None)

View File

@ -4,7 +4,6 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
import io
from typing import Dict
import pandas as pd
@ -14,8 +13,7 @@ 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.ocupancy import Occupancy
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
@ -24,15 +22,13 @@ from hub.helpers.configuration_helper import ConfigurationHelper as ch
class ComnetCatalog(Catalog):
"""
Comnet catalog class
"""
def __init__(self, path):
self._comnet_archetypes_path = str(path / 'comnet_archetypes.xlsx')
self._comnet_schedules_path = str(path / 'comnet_schedules_archetypes.xlsx')
self._archetypes = self._read_archetype_file()
self._schedules = self._read_schedules_file()
# todo: comment with @Guille, this hypotheses should go in the import factory?
sensible_convective = ch().comnet_occupancy_sensible_convective
sensible_radiative = ch().comnet_occupancy_sensible_radiant
lighting_convective = ch().comnet_lighting_convective
@ -55,7 +51,6 @@ class ComnetCatalog(Catalog):
ventilation_rate = self._archetypes['ventilation rate'][comnet_usage]
# convert cfm/ft2 to m3/m2.s
ventilation_rate = ventilation_rate / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
domestic_hot_water_archetype = self._archetypes['water heating'][comnet_usage]
# get occupancy
occupancy_density = occupancy_archetype[0] / pow(cte.METERS_TO_FEET, 2)
@ -101,16 +96,6 @@ class ComnetCatalog(Catalog):
self._schedules[schedule_name]['ClgSetPt']
)
# get domestic hot water
density = domestic_hot_water_archetype
# convert Btu/h/occ to W/m2
density = float(density) * cte.BTU_H_TO_WATTS * occupancy_density
domestic_hot_water_service_temperature = self._schedules[schedule_name]['WtrHtrSetPt'][0].values[0]
domestic_hot_water = DomesticHotWater(density,
None,
domestic_hot_water_service_temperature,
self._schedules[schedule_name]['Service Hot Water']
)
usages.append(Usage(comnet_usage,
hours_day,
days_year,
@ -119,8 +104,7 @@ class ComnetCatalog(Catalog):
occupancy,
lighting,
appliances,
thermal_control,
domestic_hot_water))
thermal_control))
self._content = Content(usages)
@ -132,12 +116,8 @@ class ComnetCatalog(Catalog):
for usage_name in comnet_usages:
if usage_name == 'C-13 Data Center':
continue
with open(self._comnet_schedules_path, 'rb') as xls:
_extracted_data = pd.read_excel(
io.BytesIO(xls.read()),
sheet_name=comnet_usages[usage_name],
skiprows=[0, 1, 2, 3], nrows=39, usecols="A:AA"
)
_extracted_data = pd.read_excel(self._comnet_schedules_path, sheet_name=comnet_usages[usage_name],
skiprows=[0, 1, 2, 3], nrows=39, usecols="A:AA")
_schedules = {}
for row in range(0, 39, 3):
_schedule_values = {}
@ -150,13 +130,13 @@ class ComnetCatalog(Catalog):
if day == cte.SATURDAY:
start = start + 1
end = end + 1
elif day in (cte.SUNDAY, cte.HOLIDAY):
elif day == cte.SUNDAY or day == cte.HOLIDAY:
start = start + 2
end = end + 2
_schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0]
_schedule = []
for day in _schedule_values:
if schedule_name in ('ClgSetPt', 'HtgSetPt', 'WtrHtrSetPt'):
if schedule_name == 'ClgSetPt' or schedule_name == 'HtgSetPt':
# to celsius
if 'n.a.' in _schedule_values[day]:
_schedule_values[day] = None
@ -173,13 +153,9 @@ class ComnetCatalog(Catalog):
:return : Dict
"""
number_usage_types = 33
with open(self._comnet_archetypes_path, 'rb') as xls:
_extracted_data = pd.read_excel(
io.BytesIO(xls.read()),
sheet_name="Modeling Data",
skiprows=[0, 1, 2, 24],
nrows=number_usage_types, usecols="A:AB"
)
xl_file = pd.ExcelFile(self._comnet_archetypes_path)
file_data = pd.read_excel(xl_file, sheet_name="Modeling Data", skiprows=[0, 1, 2, 24],
nrows=number_usage_types, usecols="A:AB")
lighting_data = {}
plug_loads_data = {}
@ -189,15 +165,15 @@ class ComnetCatalog(Catalog):
process_data = {}
schedules_key = {}
for j in range(0, number_usage_types-1):
usage_parameters = _extracted_data.iloc[j]
usage_type = usage_parameters.iloc[0]
lighting_data[usage_type] = usage_parameters.iloc[1:6].values.tolist()
plug_loads_data[usage_type] = usage_parameters.iloc[8:13].values.tolist()
occupancy_data[usage_type] = usage_parameters.iloc[17:20].values.tolist()
ventilation_rate[usage_type] = usage_parameters.iloc[20:21].item()
water_heating[usage_type] = usage_parameters.iloc[23:24].item()
process_data[usage_type] = usage_parameters.iloc[24:26].values.tolist()
schedules_key[usage_type] = usage_parameters.iloc[27:28].item()
usage_parameters = file_data.iloc[j]
usage_type = usage_parameters[0]
lighting_data[usage_type] = usage_parameters[1:6].values.tolist()
plug_loads_data[usage_type] = usage_parameters[8:13].values.tolist()
occupancy_data[usage_type] = usage_parameters[17:20].values.tolist()
ventilation_rate[usage_type] = usage_parameters[20:21].item()
water_heating[usage_type] = usage_parameters[23:24].item()
process_data[usage_type] = usage_parameters[24:26].values.tolist()
schedules_key[usage_type] = usage_parameters[27:28].item()
return {'lighting': lighting_data,
'plug loads': plug_loads_data,

View File

@ -1,234 +0,0 @@
"""
Eilat usage catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import io
from typing import Dict
import pandas as pd
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
from hub.helpers.configuration_helper import ConfigurationHelper as ch
class EilatCatalog(Catalog):
"""
Eilat catalog class
"""
def __init__(self, path):
self._eilat_archetypes_path = str(path / 'eilat_archetypes.xlsx')
self._eilat_schedules_path = str(path / 'eilat_schedules_archetypes.xlsx')
self._archetypes = self._read_archetype_file()
self._schedules = self._read_schedules_file()
sensible_convective = ch().comnet_occupancy_sensible_convective
sensible_radiative = ch().comnet_occupancy_sensible_radiant
lighting_convective = ch().comnet_lighting_convective
lighting_radiative = ch().comnet_lighting_radiant
lighting_latent = ch().comnet_lighting_latent
appliances_convective = ch().comnet_plugs_convective
appliances_radiative = ch().comnet_plugs_radiant
appliances_latent = ch().comnet_plugs_latent
usages = []
for schedule_key in self._archetypes['schedules_key']:
eilat_usage = schedule_key
schedule_name = self._archetypes['schedules_key'][schedule_key]
hours_day = None
days_year = None
occupancy_archetype = self._archetypes['occupancy'][eilat_usage]
lighting_archetype = self._archetypes['lighting'][eilat_usage]
appliances_archetype = self._archetypes['plug loads'][eilat_usage]
mechanical_air_change = None # eilat provides ventilation rate only
ventilation_rate = self._archetypes['ventilation rate'][eilat_usage]
# convert cfm/ft2 to m3/m2.s
ventilation_rate = ventilation_rate / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
domestic_hot_water_archetype = self._archetypes['water heating'][eilat_usage]
# get occupancy
occupancy_density = occupancy_archetype[0] / pow(cte.METERS_TO_FEET, 2)
sensible_heat_gain = occupancy_archetype[1] * cte.BTU_H_TO_WATTS
latent_heat_gain = occupancy_archetype[1] * cte.BTU_H_TO_WATTS
if occupancy_density != 0:
occupancy_density = 1 / occupancy_density
sensible_convective_internal_gain = occupancy_density * sensible_heat_gain * sensible_convective
sensible_radiative_internal_gain = occupancy_density * sensible_heat_gain * sensible_radiative
latent_internal_gain = occupancy_density * latent_heat_gain
occupancy = Occupancy(occupancy_density,
sensible_convective_internal_gain,
sensible_radiative_internal_gain,
latent_internal_gain,
self._schedules[schedule_name]['Occupancy'])
# get lighting
density = lighting_archetype[4] * pow(cte.METERS_TO_FEET, 2)
lighting = Lighting(density,
lighting_convective,
lighting_radiative,
lighting_latent,
self._schedules[schedule_name]['Lights'])
# get appliances
density = appliances_archetype[0]
if density == 'n.a.':
density = 0
# convert W/ft2 to W/m2
density = float(density) * pow(cte.METERS_TO_FEET, 2)
appliances = Appliances(density,
appliances_convective,
appliances_radiative,
appliances_latent,
self._schedules[schedule_name]['Receptacle'])
# get thermal control
thermal_control = ThermalControl(None,
None,
None,
self._schedules[schedule_name]['HVAC Avail'],
self._schedules[schedule_name]['HtgSetPt'],
self._schedules[schedule_name]['ClgSetPt']
)
# get domestic hot water
density = domestic_hot_water_archetype
# convert Btu/h/occ to W/m2
density = float(density) * cte.BTU_H_TO_WATTS * occupancy_density
domestic_hot_water_service_temperature = self._schedules[schedule_name]['WtrHtrSetPt'][0].values[0]
domestic_hot_water = DomesticHotWater(density,
None,
domestic_hot_water_service_temperature,
self._schedules[schedule_name]['Service Hot Water']
)
usages.append(Usage(eilat_usage,
hours_day,
days_year,
mechanical_air_change,
ventilation_rate,
occupancy,
lighting,
appliances,
thermal_control,
domestic_hot_water))
self._content = Content(usages)
def _read_schedules_file(self) -> Dict:
dictionary = {}
eilat_usages = UsageHelper().eilat_schedules_key_to_eilat_schedules
eilat_days = UsageHelper().comnet_days
eilat_data_types = UsageHelper().comnet_data_type_to_hub_data_type
for usage_name in eilat_usages:
with open(self._eilat_schedules_path, 'rb') as xls:
_extracted_data = pd.read_excel(
io.BytesIO(xls.read()),
sheet_name=eilat_usages[usage_name],
skiprows=[0, 1, 2, 3], nrows=39, usecols="A:AA"
)
_schedules = {}
for row in range(0, 39, 3):
_schedule_values = {}
schedule_name = _extracted_data.loc[row:row, 'Description'].item()
schedule_data_type = eilat_data_types[_extracted_data.loc[row:row, 'Type'].item()]
for day in eilat_days:
# Monday to Friday
start = row
end = row + 1
if day == cte.FRIDAY:
start = start + 1
end = end + 1
elif day in (cte.SATURDAY, cte.HOLIDAY):
start = start + 2
end = end + 2
_schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0]
_schedule = []
for day in _schedule_values:
if schedule_name in ('ClgSetPt', 'HtgSetPt', 'WtrHtrSetPt'):
# to celsius
if 'n.a.' in _schedule_values[day]:
_schedule_values[day] = None
else:
_schedule_values[day] = [(float(value)-32)*5/9 for value in _schedule_values[day]]
_schedule.append(Schedule(schedule_name, _schedule_values[day], schedule_data_type, cte.HOUR, cte.DAY, [day]))
_schedules[schedule_name] = _schedule
dictionary[usage_name] = _schedules
return dictionary
def _read_archetype_file(self) -> Dict:
"""
reads xlsx files containing usage information into a dictionary
:return : Dict
"""
number_usage_types = 3
with open(self._eilat_archetypes_path, 'rb') as xls:
_extracted_data = pd.read_excel(
io.BytesIO(xls.read()),
sheet_name="Modeling Data",
skiprows=[0, 1, 2],
nrows=number_usage_types + 1, usecols="A:AB"
)
lighting_data = {}
plug_loads_data = {}
occupancy_data = {}
ventilation_rate = {}
water_heating = {}
process_data = {}
schedules_key = {}
for j in range(0, number_usage_types):
usage_parameters = _extracted_data.iloc[j]
usage_type = usage_parameters.iloc[0]
lighting_data[usage_type] = usage_parameters[1:6].values.tolist()
plug_loads_data[usage_type] = usage_parameters[8:13].values.tolist()
occupancy_data[usage_type] = usage_parameters[17:20].values.tolist()
ventilation_rate[usage_type] = usage_parameters[20:21].item()
water_heating[usage_type] = usage_parameters[23:24].item()
process_data[usage_type] = usage_parameters[24:26].values.tolist()
schedules_key[usage_type] = usage_parameters[27:28].item()
return {'lighting': lighting_data,
'plug loads': plug_loads_data,
'occupancy': occupancy_data,
'ventilation rate': ventilation_rate,
'water heating': water_heating,
'process': process_data,
'schedules_key': schedules_key
}
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

@ -8,8 +8,6 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
import json
import urllib.request
from pathlib import Path
import xmltodict
import hub.helpers.constants as cte
@ -17,8 +15,7 @@ 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.ocupancy import Occupancy
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
@ -26,22 +23,20 @@ from hub.catalog_factories.usage.usage_helper import UsageHelper
class NrcanCatalog(Catalog):
"""
Nrcan catalog class
"""
def __init__(self, path):
self._schedules_path = Path(path / 'nrcan_schedules.json').resolve()
self._space_types_path = Path(path / 'nrcan_space_types.json').resolve()
self._space_compliance_path = Path(path / 'nrcan_space_compliance_2015.json').resolve()
path = str(path / 'nrcan.xml')
self._content = None
self._schedules = {}
with open(path) as xml:
self._metadata = xmltodict.parse(xml.read())
self._base_url = self._metadata['nrcan']['@base_url']
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']:
if 'Heating' in raw['name']:
nrcan_schedule_type = f'{nrcan_schedule_type} Heating'
elif 'Cooling' in raw['name']:
nrcan_schedule_type = f'{nrcan_schedule_type} Cooling'
@ -50,15 +45,17 @@ class NrcanCatalog(Catalog):
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
# nrcan only uses yearly range for the schedules
time_range = cte.YEAR
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):
usage = self._metadata['nrcan']
url = f'{self._base_url}{usage["schedules_location"]}'
_schedule_types = []
with open(self._schedules_path, 'r') as f:
schedules_type = json.load(f)
with urllib.request.urlopen(url) as json_file:
schedules_type = json.load(json_file)
for schedule_type in schedules_type['tables']['schedules']['table']:
schedule = NrcanCatalog._extract_schedule(schedule_type)
if schedule_type['name'] not in _schedule_types:
@ -72,47 +69,20 @@ class NrcanCatalog(Catalog):
self._schedules[schedule_type['name']] = _schedules
def _get_schedules(self, name):
schedule = None
if name in self._schedules:
schedule = self._schedules[name]
return schedule
return self._schedules[name]
def _load_archetypes(self):
usages = []
with open(self._space_types_path, 'r') as f:
space_types = json.load(f)['tables']['space_types']['table']
name = self._metadata['nrcan']
url = f'{self._base_url}{name["space_types_location"]}'
with urllib.request.urlopen(url) as json_file:
space_types = json.load(json_file)['tables']['space_types']['table']
# space_types = [st for st in space_types if st['building_type'] == 'Space Function']
space_types = [st for st in space_types if st['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['space_type']
usage_type = space_type['building_type']
space_type_compliance = space_types_dictionary[usage_type]
occupancy_density = space_type_compliance['occupancy_per_area']
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']
@ -121,37 +91,39 @@ class NrcanCatalog(Catalog):
hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan')
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
occupancy_density = space_type['occupancy_per_area']
# ACH
mechanical_air_change = space_type['ventilation_air_changes']
# cfm/ft2 to m3/m2.s
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
if ventilation_rate == 0:
# cfm/person to m3/m2.s
ventilation_rate += space_type['ventilation_per_person'] / (
pow(cte.METERS_TO_FEET, 3) * cte.MINUTES_TO_SECONDS
) * occupancy_density
ventilation_rate = space_type['ventilation_per_person'] / occupancy_density\
/ (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
# W/sqft to W/m2
lighting_density = space_type['lighting_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET
lighting_radiative_fraction = space_type['lighting_fraction_radiant']
lighting_convective_fraction = 0
if lighting_radiative_fraction is not None:
lighting_convective_fraction = 1 - lighting_radiative_fraction
lighting_latent_fraction = 0
# W/sqft to W/m2
appliances_density = space_type['electric_equipment_per_area'] * cte.METERS_TO_FEET * cte.METERS_TO_FEET
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
appliances_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,
None,
None,
@ -173,11 +145,6 @@ class NrcanCatalog(Catalog):
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,
@ -188,8 +155,7 @@ class NrcanCatalog(Catalog):
occupancy,
lighting,
appliances,
thermal_control,
domestic_hot_water))
thermal_control))
return usages
def names(self, category=None):

View File

@ -1,227 +0,0 @@
"""
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

@ -4,9 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Dict
import sys
import hub.helpers.constants as cte
from hub.hub_logger import logger
from typing import Dict
class UsageHelper:
@ -17,10 +18,9 @@ class UsageHelper:
'Lighting': cte.LIGHTING,
'Occupancy': cte.OCCUPANCY,
'Equipment': cte.APPLIANCES,
'Thermostat Setpoint Cooling': cte.COOLING_SET_POINT,
'Thermostat Setpoint Heating': cte.HEATING_SET_POINT,
'Fan': cte.HVAC_AVAILABILITY,
'Service Water Heating': cte.DOMESTIC_HOT_WATER
'Thermostat Setpoint Cooling': cte.COOLING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Cooling'
'Thermostat Setpoint Heating': cte.HEATING_SET_POINT, # Compose 'Thermostat Setpoint' + 'Heating'
'Fan': cte.HVAC_AVAILABILITY
}
_nrcan_data_type_to_hub_data_type = {
'FRACTION': cte.FRACTION,
@ -90,64 +90,45 @@ class UsageHelper:
'C-14 Gymnasium': 'C-14 Gymnasium'
}
_eilat_schedules_key_to_eilat_schedules = {
'C-12 Residential': 'C-12 Residential',
'C-15 Dormitory': 'C-15 Dormitory',
'C-16 Hotel employees': 'C-16 Hotel employees'
}
@property
def nrcan_day_type_to_hub_days(self):
"""
Get a dictionary to convert nrcan day types to hub day types
"""
return self._nrcan_day_type_to_hub_days
@property
def nrcan_schedule_type_to_hub_schedule_type(self):
"""
Get a dictionary to convert nrcan schedule types to hub schedule types
"""
return self._nrcan_schedule_type_to_hub_schedule_type
@property
def nrcan_data_type_to_hub_data_type(self):
"""
Get a dictionary to convert nrcan data types to hub data types
"""
return self._nrcan_data_type_to_hub_data_type
@property
def nrcan_time_to_hub_time(self):
"""
Get a dictionary to convert nrcan time to hub time
"""
return self._nrcan_time_to_hub_time
@property
def comnet_data_type_to_hub_data_type(self) -> Dict:
"""
Get a dictionary to convert comnet data types to hub data types
"""
def comnet_data_type_to_hub_data_type(self):
return self._comnet_data_type_to_hub_data_type
@property
def comnet_schedules_key_to_comnet_schedules(self) -> Dict:
"""
Get a dictionary to convert hub schedules to comnet schedules
"""
return self._comnet_schedules_key_to_comnet_schedules
@property
def comnet_days(self) -> [str]:
"""
Get the list of days used in comnet
"""
def comnet_days(self):
return self._comnet_days
@property
def eilat_schedules_key_to_eilat_schedules(self) -> [str]:
@staticmethod
def schedules_key(usage):
"""
Get a dictionary to convert hub schedules to eilat schedules
Get Comnet schedules key from the list found in the Comnet usage file
:param usage: str
:return: str
"""
return self._eilat_schedules_key_to_eilat_schedules
try:
return UsageHelper._comnet_schedules_key_to_comnet_schedules[usage]
except KeyError:
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
'done changing the keywords.\n')
logger.error('Error: Comnet keyword not found. An update of the Comnet files might have been '
'done changing the keywords.\n')

View File

@ -7,25 +7,23 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
from pathlib import Path
from typing import TypeVar
from hub.catalog_factories.usage.comnet_catalog import ComnetCatalog
from hub.catalog_factories.usage.nrcan_catalog import NrcanCatalog
from hub.catalog_factories.usage.eilat_catalog import EilatCatalog
from hub.catalog_factories.usage.palma_catalog import PalmaCatalog
from hub.hub_logger import logger
from hub.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog')
class UsageCatalogFactory:
"""
Usage catalog factory class
"""
def __init__(self, handler, base_path=None):
def __init__(self, file_type, base_path=None):
if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/usage')
self._catalog_type = '_' + handler.lower()
validate_import_export_type(UsageCatalogFactory, handler)
self._catalog_type = '_' + file_type.lower()
class_funcs = validate_import_export_type(UsageCatalogFactory)
if self._catalog_type not in class_funcs:
err_msg = f"Wrong import type. Valid functions include {class_funcs}"
logger.error(err_msg)
raise Exception(err_msg)
self._path = base_path
@property
@ -43,20 +41,6 @@ class UsageCatalogFactory:
# nrcan retrieves the data directly from github
return NrcanCatalog(self._path)
@property
def _palma(self):
"""
Retrieve Palma catalog
"""
return PalmaCatalog(self._path)
@property
def _eilat(self):
"""
Retrieve Eilat catalog
"""
return EilatCatalog(self._path)
@property
def catalog(self) -> Catalog:
"""

View File

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

View File

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

View File

@ -6,27 +6,28 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from __future__ import annotations
import logging
import math
import sys
from typing import List
from hub.hub_logger import logger
import numpy as np
from trimesh import Trimesh
import trimesh.intersections
import trimesh.creation
import trimesh.geometry
import trimesh.intersections
from shapely.geometry.polygon import Polygon as shapley_polygon
from trimesh import Trimesh
from hub.city_model_structure.attributes.plane import Plane
from hub.city_model_structure.attributes.point import Point
import hub.helpers.constants as cte
class Polygon:
"""
Polygon class
"""
# todo: review with @Guille: Points, Coordinates, Vertices, Faces
def __init__(self, coordinates):
self._area = None
self._points = None
@ -70,6 +71,44 @@ class Polygon:
"""
return self._coordinates
def contains_point(self, point):
"""
Determines if the given point is contained by the current polygon
:return: boolean
"""
# fixme: This method doesn't seems to work.
n = len(self.vertices)
angle_sum = 0
for i in range(0, n):
vector_0 = self.vertices[i]
vector_1 = self.vertices[(i+1) % n]
# set to origin
vector_0[0] = vector_0[0] - point.coordinates[0]
vector_0[1] = vector_0[1] - point.coordinates[1]
vector_0[2] = vector_0[2] - point.coordinates[2]
vector_1[0] = vector_1[0] - point.coordinates[0]
vector_1[1] = vector_1[1] - point.coordinates[1]
vector_1[2] = vector_1[2] - point.coordinates[2]
module = np.linalg.norm(vector_0) * np.linalg.norm(vector_1)
scalar_product = np.dot(vector_0, vector_1)
angle = np.pi/2
if module != 0:
angle = abs(np.arcsin(scalar_product / module))
angle_sum += angle
return abs(angle_sum - math.pi*2) < cte.EPSILON
def contains_polygon(self, polygon):
"""
Determines if the given polygon is contained by the current polygon
:return: boolean
"""
for point in polygon.points:
if not self.contains_point(point):
return False
return True
@property
def points_list(self) -> np.ndarray:
"""
@ -105,18 +144,14 @@ class Polygon:
if self._area is None:
self._area = 0
for triangle in self.triangles:
a_b = np.zeros(3)
a_c = np.zeros(3)
ab = np.zeros(3)
ac = np.zeros(3)
for i in range(0, 3):
a_b[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
a_c[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
self._area += np.linalg.norm(np.cross(a_b, a_c)) / 2
ab[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
ac[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
self._area += np.linalg.norm(np.cross(ab, ac)) / 2
return self._area
@area.setter
def area(self, value):
self._area = value
@property
def normal(self) -> np.ndarray:
"""
@ -180,11 +215,7 @@ class Polygon:
return -alpha
@staticmethod
def triangle_mesh(vertices, normal) -> Trimesh:
"""
Get the triangulated mesh for the polygon
:return: Trimesh
"""
def triangle_mesh(vertices, normal):
min_x = 1e16
min_y = 1e16
min_z = 1e16
@ -213,8 +244,7 @@ class Polygon:
polygon = shapley_polygon(coordinates)
try:
_, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
vertices_2d, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
mesh = Trimesh(vertices=vertices, faces=faces)
# check orientation
@ -230,20 +260,18 @@ class Polygon:
new_face.append(face[len(face)-i-1])
new_faces.append(new_face)
mesh = Trimesh(vertices=vertices, faces=new_faces)
return mesh
except ValueError:
logging.error('Not able to triangulate polygon\n')
sys.stderr.write(f'Not able to triangulate polygon\n')
logger.error(f'Not able to triangulate polygon\n')
_vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
_faces = [[0, 1, 2]]
return Trimesh(vertices=_vertices, faces=_faces)
@property
def triangles(self) -> List[Polygon]:
"""
Triangulate the polygon and return a list of triangular polygons
:return: [Polygon]
"""
if self._triangles is None:
self._triangles = []
_mesh = self.triangle_mesh(self.coordinates, self.normal)
@ -265,6 +293,7 @@ class Polygon:
"""
if np.linalg.norm(vec_1) == 0 or np.linalg.norm(vec_2) == 0:
sys.stderr.write("Warning: impossible to calculate angle between planes' normal. Return 0\n")
logger.error("Warning: impossible to calculate angle between planes' normal. Return 0\n")
return 0
cosine = np.dot(vec_1, vec_2) / np.linalg.norm(vec_1) / np.linalg.norm(vec_2)
if cosine > 1 and cosine - 1 < 1e-5:
@ -306,7 +335,7 @@ class Polygon:
def _reshape(self, triangles) -> Polygon:
edges_list = []
for i in enumerate(triangles):
for i in range(0, len(triangles)):
for edge in triangles[i].edges:
if not self._edge_in_edges_list(edge, edges_list):
edges_list.append(edge)
@ -391,8 +420,7 @@ class Polygon:
if len(points) != 3:
sub_polygons = polygon.triangles
# todo: I modified this! To be checked @Guille
if len(sub_polygons) < 1:
continue
if len(sub_polygons) >= 1:
for sub_polygon in sub_polygons:
face = []
points = sub_polygon.coordinates
@ -411,7 +439,7 @@ class Polygon:
:return: int
"""
vertices = self.vertices
for i in enumerate(vertices):
for i in range(len(vertices)):
# ensure not duplicated vertex
power = 0
vertex2 = vertices[i]

View File

@ -12,6 +12,7 @@ import math
import numpy as np
from trimesh import Trimesh
from hub.helpers.configuration_helper import ConfigurationHelper
from hub.hub_logger import logger
class Polyhedron:
@ -41,10 +42,10 @@ class Polyhedron:
:return: int
"""
vertices = self.vertices
for i, vertex in enumerate(vertices):
for i in range(len(vertices)):
# ensure not duplicated vertex
power = 0
vertex2 = vertex
vertex2 = vertices[i]
for dimension in range(0, 3):
power += math.pow(vertex2[dimension] - point[dimension], 2)
distance = math.sqrt(power)
@ -92,8 +93,8 @@ class Polyhedron:
points = polygon.coordinates
if len(points) != 3:
sub_polygons = polygon.triangles
if len(sub_polygons) < 1:
continue
# todo: I modified this! To be checked @Guille
if len(sub_polygons) >= 1:
for sub_polygon in sub_polygons:
face = []
points = sub_polygon.coordinates
@ -116,6 +117,7 @@ class Polyhedron:
for face in self.faces:
if len(face) != 3:
sys.stderr.write('Not able to generate trimesh\n')
logger.error('Not able to generate trimesh\n')
return None
self._trimesh = Trimesh(vertices=self.vertices, faces=self.faces)
return self._trimesh

View File

@ -6,30 +6,24 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import logging
from typing import List, Union, TypeVar
import sys
from typing import List, Union
import numpy as np
from hub.hub_logger import logger
import hub.helpers.constants as cte
from hub.city_model_structure.attributes.polyhedron import Polyhedron
from hub.city_model_structure.building_demand.household import Household
from hub.city_model_structure.building_demand.internal_zone import InternalZone
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
from hub.city_model_structure.building_demand.surface import Surface
from hub.city_model_structure.city_object import CityObject
from hub.city_model_structure.energy_systems.energy_system import EnergySystem
from hub.helpers.peak_loads import PeakLoads
City = TypeVar('City')
from hub.city_model_structure.building_demand.household import Household
from hub.city_model_structure.building_demand.internal_zone import InternalZone
from hub.city_model_structure.attributes.polyhedron import Polyhedron
class Building(CityObject):
"""
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, terrains=None):
super().__init__(name, surfaces)
self._city = city
self._households = None
self._basement_heated = None
self._attic_heated = None
@ -41,24 +35,15 @@ class Building(CityObject):
self._floor_area = None
self._roof_type = None
self._internal_zones = None
self._thermal_zones_from_internal_zones = None
self._shell = None
self._aliases = []
self._alias = None
self._type = 'building'
self._cold_water_temperature = {}
self._heating_demand = {}
self._cooling_demand = {}
self._lighting_electrical_demand = {}
self._appliances_electrical_demand = {}
self._domestic_hot_water_heat_demand = {}
self._heating_consumption = {}
self._cooling_consumption = {}
self._domestic_hot_water_consumption = {}
self._distribution_systems_electrical_consumption = {}
self._onsite_electrical_production = {}
self._heating = dict()
self._cooling = dict()
self._lighting_electrical_demand = dict()
self._appliances_electrical_demand = dict()
self._domestic_hot_water_heat_demand = dict()
self._eave_height = None
self._energy_systems = None
self._systems_archetype_name = None
self._grounds = []
self._roofs = []
self._walls = []
@ -70,9 +55,6 @@ class Building(CityObject):
self._min_x = min(self._min_x, surface.lower_corner[0])
self._min_y = min(self._min_y, surface.lower_corner[1])
self._min_z = min(self._min_z, surface.lower_corner[2])
self._max_x = max(self._max_x, surface.upper_corner[0])
self._max_y = max(self._max_y, surface.upper_corner[1])
self._max_z = max(self._max_z, surface.upper_corner[2])
surface.id = surface_id
if surface.type == cte.GROUND:
self._grounds.append(surface)
@ -89,10 +71,8 @@ class Building(CityObject):
elif surface.type == cte.INTERIOR_SLAB:
self._interior_slabs.append(surface)
else:
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._fuel_consumption_breakdown = {}
self._pv_generation = {}
sys.stderr.write(f'Building {self.name} [alias {self.alias}] has an unexpected surface type {surface.type}.\n')
logger.error(f'Building {self.name} [alias {self.alias}] has an unexpected surface type {surface.type}.\n')
@property
def shell(self) -> Polyhedron:
@ -120,24 +100,9 @@ class Building(CityObject):
:return: [InternalZone]
"""
if self._internal_zones is None:
self._internal_zones = [InternalZone(self.surfaces, self.floor_area, self.volume)]
self._internal_zones = [InternalZone(self.surfaces, self.floor_area)]
return self._internal_zones
@property
def thermal_zones_from_internal_zones(self) -> Union[None, List[ThermalZone]]:
"""
Get building thermal zones
:return: [ThermalZone]
"""
if self._thermal_zones_from_internal_zones is None:
self._thermal_zones_from_internal_zones = []
for internal_zone in self.internal_zones:
if internal_zone.thermal_zones_from_internal_zones is None:
self._thermal_zones_from_internal_zones = None
return self._thermal_zones_from_internal_zones
self._thermal_zones_from_internal_zones.append(internal_zone.thermal_zones_from_internal_zones[0])
return self._thermal_zones_from_internal_zones
@property
def grounds(self) -> List[Surface]:
"""
@ -224,6 +189,14 @@ class Building(CityObject):
if value is not None:
self._basement_heated = int(value)
@property
def heated_volume(self):
"""
Raises not implemented error
"""
# todo: this need to be calculated based on the basement and attic heated values
raise NotImplementedError
@property
def year_of_construction(self):
"""
@ -264,15 +237,6 @@ class Building(CityObject):
Get building average storey height in meters
:return: None or float
"""
if len(self.internal_zones) > 1:
self._average_storey_height = 0
for internal_zone in self.internal_zones:
self._average_storey_height += internal_zone.mean_height / len(self.internal_zones)
else:
if self.internal_zones[0].thermal_archetype is None:
self._average_storey_height = None
else:
self._average_storey_height = self.internal_zones[0].thermal_archetype.average_storey_height
return self._average_storey_height
@average_storey_height.setter
@ -290,12 +254,6 @@ class Building(CityObject):
Get building storeys number above ground
:return: None or int
"""
if self._storeys_above_ground is None:
if self.eave_height is not None and self.average_storey_height is not None:
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
@storeys_above_ground.setter
@ -308,189 +266,85 @@ class Building(CityObject):
self._storeys_above_ground = int(value)
@property
def cold_water_temperature(self) -> {float}:
def heating(self) -> dict:
"""
Get cold water temperature in degrees Celsius
:return: dict{[float]}
Get heating demand in Wh
:return: dict{DataFrame(float)}
"""
return self._cold_water_temperature
return self._heating
@cold_water_temperature.setter
def cold_water_temperature(self, value):
@heating.setter
def heating(self, value):
"""
Set cold water temperature in degrees Celsius
:param value: dict{[float]}
Set heating demand in Wh
:param value: dict{DataFrame(float)}
"""
self._cold_water_temperature = value
self._heating = value
@property
def heating_demand(self) -> dict:
def cooling(self) -> dict:
"""
Get heating demand in J
:return: dict{[float]}
Get cooling demand in Wh
:return: dict{DataFrame(float)}
"""
return self._heating_demand
return self._cooling
@heating_demand.setter
def heating_demand(self, value):
@cooling.setter
def cooling(self, value):
"""
Set heating demand in J
:param value: dict{[float]}
Set cooling demand in Wh
:param value: dict{DataFrame(float)}
"""
self._heating_demand = value
@property
def cooling_demand(self) -> dict:
"""
Get cooling demand in J
:return: dict{[float]}
"""
return self._cooling_demand
@cooling_demand.setter
def cooling_demand(self, value):
"""
Set cooling demand in J
:param value: dict{[float]}
"""
self._cooling_demand = value
self._cooling = value
@property
def lighting_electrical_demand(self) -> dict:
"""
Get lighting electrical demand in J
:return: dict{[float]}
Get lighting electrical demand in Wh
:return: dict{DataFrame(float)}
"""
return self._lighting_electrical_demand
@lighting_electrical_demand.setter
def lighting_electrical_demand(self, value):
"""
Set lighting electrical demand in J
:param value: dict{[float]}
Set lighting electrical demand in Wh
:param value: dict{DataFrame(float)}
"""
self._lighting_electrical_demand = value
@property
def appliances_electrical_demand(self) -> dict:
"""
Get appliances electrical demand in J
:return: dict{[float]}
Get appliances electrical demand in Wh
:return: dict{DataFrame(float)}
"""
return self._appliances_electrical_demand
@appliances_electrical_demand.setter
def appliances_electrical_demand(self, value):
"""
Set appliances electrical demand in J
:param value: dict{[float]}
Set appliances electrical demand in Wh
:param value: dict{DataFrame(float)}
"""
self._appliances_electrical_demand = value
@property
def domestic_hot_water_heat_demand(self) -> dict:
"""
Get domestic hot water heat demand in J
:return: dict{[float]}
Get domestic hot water heat demand in Wh
:return: dict{DataFrame(float)}
"""
return self._domestic_hot_water_heat_demand
@domestic_hot_water_heat_demand.setter
def domestic_hot_water_heat_demand(self, value):
"""
Set domestic hot water heat demand in J
:param value: dict{[float]}
Set domestic hot water heat demand in Wh
:param value: dict{DataFrame(float)}
"""
self._domestic_hot_water_heat_demand = value
@property
def lighting_peak_load(self) -> Union[None, dict]:
"""
Get lighting peak load in W
:return: dict{[float]}
"""
results = {}
peak_lighting = 0
peak = 0
for thermal_zone in self.thermal_zones_from_internal_zones:
lighting = thermal_zone.lighting
for schedule in lighting.schedules:
peak = max(schedule.values) * lighting.density * thermal_zone.total_floor_area
if peak > peak_lighting:
peak_lighting = peak
results[cte.MONTH] = [peak for _ in range(0, 12)]
results[cte.YEAR] = [peak]
return results
@property
def appliances_peak_load(self) -> Union[None, dict]:
"""
Get appliances peak load in W
:return: dict{[float]}
"""
results = {}
peak_appliances = 0
peak = 0
for thermal_zone in self.thermal_zones_from_internal_zones:
appliances = thermal_zone.appliances
for schedule in appliances.schedules:
peak = max(schedule.values) * appliances.density * thermal_zone.total_floor_area
if peak > peak_appliances:
peak_appliances = peak
results[cte.MONTH] = [peak for _ in range(0, 12)]
results[cte.YEAR] = [peak]
return results
@property
def heating_peak_load(self) -> Union[None, dict]:
"""
Get heating peak load in W
:return: dict{[float]}
"""
results = {}
if cte.HOUR in self.heating_demand:
monthly_values = PeakLoads().peak_loads_from_hourly(self.heating_demand[cte.HOUR])
else:
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
if monthly_values is None:
return None
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
return results
@property
def cooling_peak_load(self) -> Union[None, dict]:
"""
Get cooling peak load in W
:return: dict{[float]}
"""
results = {}
if cte.HOUR in self.cooling_demand:
monthly_values = PeakLoads().peak_loads_from_hourly(self.cooling_demand[cte.HOUR])
else:
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
if monthly_values is None:
return None
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
return results
@property
def domestic_hot_water_peak_load(self) -> Union[None, dict]:
"""
Get cooling peak load in W
:return: dict{[float]}
"""
results = {}
monthly_values = None
if cte.HOUR in self.domestic_hot_water_heat_demand:
monthly_values = PeakLoads().peak_loads_from_hourly(self.domestic_hot_water_heat_demand[cte.HOUR])
if monthly_values is None:
return None
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
return results
@property
def eave_height(self):
"""
@ -500,7 +354,7 @@ class Building(CityObject):
if self._eave_height is None:
self._eave_height = 0
for wall in self.walls:
self._eave_height = max(self._eave_height, wall.upper_corner[2]) - self.simplified_polyhedron.min_z
self._eave_height = max(self._eave_height, wall.upper_corner[2])
return self._eave_height
@property
@ -563,35 +417,19 @@ class Building(CityObject):
return False
@property
def aliases(self):
def alias(self):
"""
Get the alias name for the building
:return: str
"""
return self._aliases
return self._alias
def add_alias(self, value):
@alias.setter
def alias(self, value):
"""
Add a new alias for the building
Set the alias name for the building
"""
self._aliases.append(value)
if self.city is not None:
self.city.add_building_alias(self, value)
@property
def city(self) -> City:
"""
Get the city containing the building
:return: City
"""
return self._city
@city.setter
def city(self, value):
"""
Set the city containing the building
"""
self._city = value
self._alias = value
@property
def usages_percentage(self):
@ -600,320 +438,6 @@ class Building(CityObject):
"""
_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
def energy_systems(self) -> Union[None, List[EnergySystem]]:
"""
Get list of energy systems installed to cover the building demands
:return: [EnergySystem]
"""
return self._energy_systems
@energy_systems.setter
def energy_systems(self, value):
"""
Set list of energy systems installed to cover the building demands
:param value: [EnergySystem]
"""
self._energy_systems = value
@property
def energy_systems_archetype_name(self):
"""
Get energy systems archetype name
:return: str
"""
return self._systems_archetype_name
@energy_systems_archetype_name.setter
def energy_systems_archetype_name(self, value):
"""
Set energy systems archetype name
:param value: str
"""
self._systems_archetype_name = value
@property
def heating_consumption(self):
"""
Get energy consumption for heating according to the heating system installed in J
return: dict
"""
if len(self._heating_consumption) == 0:
for heating_demand_key in self.heating_demand:
demand = self.heating_demand[heating_demand_key]
consumption_type = cte.HEATING
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
if final_energy_consumed is None:
continue
self._heating_consumption[heating_demand_key] = final_energy_consumed
return self._heating_consumption
@property
def cooling_consumption(self):
"""
Get energy consumption for cooling according to the cooling system installed in J
return: dict
"""
if len(self._cooling_consumption) == 0:
for cooling_demand_key in self.cooling_demand:
demand = self.cooling_demand[cooling_demand_key]
consumption_type = cte.COOLING
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
if final_energy_consumed is None:
continue
self._cooling_consumption[cooling_demand_key] = final_energy_consumed
return self._cooling_consumption
@property
def domestic_hot_water_consumption(self):
"""
Get energy consumption for domestic according to the domestic hot water system installed in J
return: dict
"""
if len(self._domestic_hot_water_consumption) == 0:
for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand:
demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key]
consumption_type = cte.DOMESTIC_HOT_WATER
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
if final_energy_consumed is None:
continue
self._domestic_hot_water_consumption[domestic_hot_water_demand_key] = final_energy_consumed
return self._domestic_hot_water_consumption
def _calculate_working_hours(self):
_working_hours = {}
for internal_zone in self.internal_zones:
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
_working_hours_per_thermal_zone = {}
for schedule in thermal_zone.thermal_control.hvac_availability_schedules:
_working_hours_per_schedule = [0] * len(schedule.values)
for i, value in enumerate(schedule.values):
if value > 0:
_working_hours_per_schedule[i] = 1
for day_type in schedule.day_types:
_working_hours_per_thermal_zone[day_type] = _working_hours_per_schedule
if len(_working_hours) == 0:
_working_hours = _working_hours_per_thermal_zone
else:
for key, item in _working_hours.items():
saved_values = _working_hours_per_thermal_zone[key]
for i, value in enumerate(item):
_working_hours[key][i] = max(_working_hours[key][i], saved_values[i])
working_hours = {}
values_months = []
for month in cte.WEEK_DAYS_A_MONTH.keys():
_total_hours_month = 0
for key in _working_hours:
hours = sum(_working_hours[key])
_total_hours_month += hours * cte.WEEK_DAYS_A_MONTH[month][key]
values_months.append(_total_hours_month)
working_hours[cte.MONTH] = values_months
working_hours[cte.YEAR] = sum(working_hours[cte.MONTH])
return working_hours
@property
def distribution_systems_electrical_consumption(self):
"""
Get total electricity consumption for distribution and emission systems in J
return: dict
"""
_distribution_systems_electrical_consumption = {}
if len(self._distribution_systems_electrical_consumption) != 0:
return self._distribution_systems_electrical_consumption
_peak_load = self.heating_peak_load[cte.YEAR][0]
_peak_load_type = cte.HEATING
if _peak_load < self.cooling_peak_load[cte.YEAR][0]:
_peak_load = self.cooling_peak_load[cte.YEAR][0]
_peak_load_type = cte.COOLING
_working_hours = self._calculate_working_hours()
_consumption_fix_flow = 0
if self.energy_systems is None:
return self._distribution_systems_electrical_consumption
for energy_system in self.energy_systems:
distribution_systems = energy_system.distribution_systems
if distribution_systems is not None:
for distribution_system in distribution_systems:
emission_systems = distribution_system.emission_systems
parasitic_energy_consumption = 0
if emission_systems is not None:
for emission_system in emission_systems:
parasitic_energy_consumption += emission_system.parasitic_energy_consumption
consumption_variable_flow = distribution_system.distribution_consumption_variable_flow
for demand_type in energy_system.demand_types:
if demand_type.lower() == cte.HEATING.lower():
if _peak_load_type == cte.HEATING.lower():
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
for heating_demand_key in self.heating_demand:
_consumption = [0]*len(self.heating_demand[heating_demand_key])
_demand = self.heating_demand[heating_demand_key]
for i, _ in enumerate(_consumption):
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
if demand_type.lower() == cte.COOLING.lower():
if _peak_load_type == cte.COOLING.lower():
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
for demand_key in self.cooling_demand:
_consumption = self._distribution_systems_electrical_consumption[demand_key]
_demand = self.cooling_demand[demand_key]
for i, _ in enumerate(_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 i in range(0, len(item)):
_working_hours_value = _working_hours[key]
if len(item) == 12:
_working_hours_value = _working_hours[key][i]
self._distribution_systems_electrical_consumption[key][i] += (
_peak_load * _consumption_fix_flow * _working_hours_value * cte.WATTS_HOUR_TO_JULES
)
return self._distribution_systems_electrical_consumption
def _calculate_consumption(self, consumption_type, demand):
# todo: modify when COP depends on the hour
coefficient_of_performance = 0
if self.energy_systems is None:
return None
for energy_system in self.energy_systems:
generation_systems = energy_system.generation_systems
for demand_type in energy_system.demand_types:
if demand_type.lower() == consumption_type.lower():
if consumption_type in (cte.HEATING, cte.DOMESTIC_HOT_WATER):
for generation_system in generation_systems:
if generation_system.heat_efficiency is not None:
coefficient_of_performance = float(generation_system.heat_efficiency)
elif consumption_type == cte.COOLING:
for generation_system in generation_systems:
if generation_system.cooling_efficiency is not None:
coefficient_of_performance = float(generation_system.cooling_efficiency)
elif consumption_type == cte.ELECTRICITY:
for generation_system in generation_systems:
if generation_system.electricity_efficiency is not None:
coefficient_of_performance = float(generation_system.electricity_efficiency)
if coefficient_of_performance == 0:
values = [0]*len(demand)
final_energy_consumed = values
else:
final_energy_consumed = []
for demand_value in demand:
final_energy_consumed.append(demand_value / coefficient_of_performance)
return final_energy_consumed
@property
def onsite_electrical_production(self):
"""
Get total electricity produced onsite in J
return: dict
"""
orientation_losses_factor = {cte.MONTH: {'north': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'east': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
'south': [2.137931, 1.645503, 1.320946, 1.107817, 0.993213, 0.945175,
0.967949, 1.065534, 1.24183, 1.486486, 1.918033, 2.210526],
'west': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]},
cte.YEAR: {'north': [0],
'east': [0],
'south': [1.212544],
'west': [0]}
}
# Add other systems whenever new ones appear
if self.energy_systems is None:
return self._onsite_electrical_production
for energy_system in self.energy_systems:
for generation_system in energy_system.generation_systems:
if generation_system.system_type == cte.PHOTOVOLTAIC:
if generation_system.electricity_efficiency is not None:
_efficiency = float(generation_system.electricity_efficiency)
else:
_efficiency = 0
self._onsite_electrical_production = {}
for _key in self.roofs[0].global_irradiance.keys():
_results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key]))]
for surface in self.roofs:
if _key in orientation_losses_factor:
_results = [x + y * _efficiency * surface.perimeter_area
* surface.solar_collectors_area_reduction_factor * z
for x, y, z in zip(_results, surface.global_irradiance[_key],
orientation_losses_factor[_key]['south'])]
self._onsite_electrical_production[_key] = _results
return self._onsite_electrical_production
@property
def lower_corner(self):
"""
Get building lower corner.
"""
return [self._min_x, self._min_y, self._min_z]
@property
def upper_corner(self):
"""
Get building upper corner.
"""
return [self._max_x, self._max_y, self._max_z]
@property
def energy_consumption_breakdown(self) -> dict:
"""
Get energy consumption of different sectors
return: dict
"""
fuel_breakdown = {cte.ELECTRICITY: {cte.LIGHTING: self.lighting_electrical_demand[cte.YEAR][0],
cte.APPLIANCES: self.appliances_electrical_demand[cte.YEAR][0]}}
energy_systems = self.energy_systems
for energy_system in energy_systems:
demand_types = energy_system.demand_types
generation_systems = energy_system.generation_systems
for demand_type in demand_types:
for generation_system in generation_systems:
if generation_system.system_type != cte.PHOTOVOLTAIC:
if generation_system.fuel_type not in fuel_breakdown:
fuel_breakdown[generation_system.fuel_type] = {}
if demand_type in generation_system.energy_consumption:
fuel_breakdown[f'{generation_system.fuel_type}'][f'{demand_type}'] = (
generation_system.energy_consumption)[f'{demand_type}'][cte.YEAR][0]
storage_systems = generation_system.energy_storage_systems
if storage_systems:
for storage_system in storage_systems:
if storage_system.type_energy_stored == 'thermal' and storage_system.heating_coil_energy_consumption:
fuel_breakdown[cte.ELECTRICITY][f'{demand_type}'] += storage_system.heating_coil_energy_consumption[cte.YEAR][0]
#TODO: When simulation models of all energy system archetypes are created, this part can be removed
heating_fuels = []
dhw_fuels = []
for energy_system in self.energy_systems:
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
heating_fuels.append(generation_system.fuel_type)
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
dhw_fuels.append(generation_system.fuel_type)
for key in fuel_breakdown:
if key == cte.ELECTRICITY and cte.COOLING not in fuel_breakdown[key]:
for energy_system in energy_systems:
if cte.COOLING in energy_system.demand_types 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:
if cte.HEATING in energy_system.demand_types:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.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:
for generation_system in energy_system.generation_systems:
fuel_breakdown[generation_system.fuel_type][cte.DOMESTIC_HOT_WATER] = self.domestic_hot_water_consumption[cte.YEAR][0]
self._fuel_consumption_breakdown = fuel_breakdown
return self._fuel_consumption_breakdown

View File

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

View File

@ -1,87 +0,0 @@
"""
Domestic Hot Water module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
from typing import Union, List
from hub.city_model_structure.attributes.schedule import Schedule
class DomesticHotWater:
"""
DomesticHotWater class
"""
def __init__(self):
self._density = None
self._peak_flow = None
self._service_temperature = None
self._schedules = None
@property
def density(self) -> Union[None, float]:
"""
Get domestic hot water load density in Watts per m2
:return: None or float
"""
return self._density
@density.setter
def density(self, value):
"""
Set domestic hot water load density in Watts per m2
:param value: float
"""
if value is not None:
self._density = float(value)
@property
def peak_flow(self) -> Union[None, float]:
"""
Get domestic hot water peak_flow density in m3 per second and m2
:return: None or float
"""
return self._peak_flow
@peak_flow.setter
def peak_flow(self, value):
"""
Set domestic hot water peak_flow density in m3 per second and m2
:return: None or float
"""
self._peak_flow = value
@property
def service_temperature(self) -> Union[None, float]:
"""
Get service temperature in degrees Celsius
:return: None or float
"""
return self._service_temperature
@service_temperature.setter
def service_temperature(self, value):
"""
Set service temperature in degrees Celsius
:param value: float
"""
if value is not None:
self._service_temperature = float(value)
@property
def schedules(self) -> Union[None, List[Schedule]]:
"""
Get schedules
dataType = fraction
:return: None or [Schedule]
"""
return self._schedules
@schedules.setter
def schedules(self, value):
"""
Set schedules
dataType = fraction
:param value: [Schedule]
"""
self._schedules = value

View File

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

View File

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

View File

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

View File

@ -90,9 +90,7 @@ class Storey:
:return: ThermalZone
"""
if self._thermal_zone is None:
_number_of_storeys = 1
self._thermal_zone = ThermalZone(self.thermal_boundaries, self._internal_zone,
self.volume, self.floor_area, _number_of_storeys)
self._thermal_zone = ThermalZone(self.thermal_boundaries, self._internal_zone, self.volume, self.floor_area)
return self._thermal_zone
@property

View File

@ -7,18 +7,15 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
"""
from __future__ import annotations
import math
import uuid
from typing import List, Union
import numpy as np
from typing import List, Union
from hub.city_model_structure.attributes.polygon import Polygon
from hub.city_model_structure.attributes.plane import Plane
from hub.city_model_structure.attributes.point import Point
from hub.city_model_structure.greenery.vegetation import Vegetation
from hub.city_model_structure.building_demand.thermal_boundary import ThermalBoundary
import hub.helpers.constants as cte
from hub.helpers.configuration_helper import ConfigurationHelper
class Surface:
@ -35,19 +32,16 @@ class Surface:
self._area = None
self._lower_corner = None
self._upper_corner = None
self._global_irradiance = {}
self._global_irradiance = dict()
self._perimeter_polygon = perimeter_polygon
self._holes_polygons = holes_polygons
self._solid_polygon = solid_polygon
self._short_wave_reflectance = None
self._long_wave_emittance = None
self._inverse = None
self._associated_thermal_boundaries = None
self._associated_thermal_boundaries = []
self._vegetation = None
self._percentage_shared = None
self._solar_collectors_area_reduction_factor = None
self._global_irradiance_tilted = {}
self._installed_solar_collector_area = None
@property
def name(self):
@ -140,7 +134,7 @@ class Surface:
@property
def azimuth(self):
"""
Get surface azimuth in radians (north = 0)
Get surface azimuth in radians
:return: float
"""
if self._azimuth is None:
@ -151,12 +145,13 @@ class Surface:
@property
def inclination(self):
"""
Get surface inclination in radians (zenith = 0, horizon = pi/2)
Get surface inclination in radians
:return: float
"""
if self._inclination is None:
self._inclination = np.arccos(self.perimeter_polygon.normal[2])
return self._inclination
@property
def type(self):
"""
@ -166,12 +161,10 @@ class Surface:
:return: str
"""
if self._type is None:
inclination_cos = math.cos(self.inclination)
# 170 degrees
if inclination_cos <= -0.98:
grad = np.rad2deg(self.inclination)
if grad >= 170:
self._type = 'Ground'
# between 80 and 100 degrees
elif abs(inclination_cos) <= 0.17:
elif 80 <= grad <= 100:
self._type = 'Wall'
else:
self._type = 'Roof'
@ -180,16 +173,16 @@ class Surface:
@property
def global_irradiance(self) -> dict:
"""
Get global irradiance on surface in W/m2
:return: dict
Get global irradiance on surface in Wh/m2
:return: dict{DataFrame(float)}
"""
return self._global_irradiance
@global_irradiance.setter
def global_irradiance(self, value):
"""
Set global irradiance on surface in W/m2
:param value: dict
Set global irradiance on surface in Wh/m2
:param value: dict{DataFrame(float)}
"""
self._global_irradiance = value
@ -353,68 +346,3 @@ class Surface:
:param value: float
"""
self._percentage_shared = value
@property
def solar_collectors_area_reduction_factor(self):
"""
Get factor area collector per surface area if set or calculate using Romero Rodriguez, L. et al (2017) model if not
:return: float
"""
if self._solar_collectors_area_reduction_factor is None:
if self.type == cte.ROOF:
_protected_building_restriction = 1
# 10 degrees range
if abs(math.sin(self.inclination)) < 0.17:
# horizontal
_construction_restriction = 0.8
_separation_of_panels = 0.46
_shadow_between_panels = 0.7
else:
# tilted
_construction_restriction = 0.9
_separation_of_panels = 0.9
_shadow_between_panels = 1
self._solar_collectors_area_reduction_factor = (
_protected_building_restriction * _construction_restriction * _separation_of_panels * _shadow_between_panels
)
return self._solar_collectors_area_reduction_factor
@solar_collectors_area_reduction_factor.setter
def solar_collectors_area_reduction_factor(self, value):
"""
Set factor area collector per surface area
:param value: float
"""
self._solar_collectors_area_reduction_factor = value
@property
def global_irradiance_tilted(self) -> dict:
"""
Get global irradiance on a tilted surface in W/m2
:return: dict
"""
return self._global_irradiance_tilted
@global_irradiance_tilted.setter
def global_irradiance_tilted(self, value):
"""
Set global irradiance on a tilted surface in W/m2
:param value: dict
"""
self._global_irradiance_tilted = value
@property
def installed_solar_collector_area(self):
"""
Get installed solar collector area in m2
:return: dict
"""
return self._installed_solar_collector_area
@installed_solar_collector_area.setter
def installed_solar_collector_area(self, value):
"""
Set installed solar collector area in m2
:return: dict
"""
self._installed_solar_collector_area = value

View File

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

View File

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

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