Merge branch 'hub_branch'

This commit is contained in:
Saeed Ranjbar 2024-03-29 10:49:27 -04:00
commit 918cd26a5c
596 changed files with 707661 additions and 0 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
!.gitignore
**/venv/
.idea/
/development_tests/
/data/energy_systems/heat_pumps/*.csv
/data/energy_systems/heat_pumps/*.insel
.DS_Store
**/.env
**/hub/logs/
**/__pycache__/
**/.idea/
cerc_hub.egg-info

60
hub/CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,60 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, rejecting any kind of discrimination.
We pledge to act and interact in ways that contribute to an open, welcoming,
and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people.
* Being respectful of differing opinions, viewpoints, and experiences.
* Giving and gracefully accepting constructive feedback.
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience.
* Focusing on what is best not just for us as individuals, but for the
overall community.
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind.
* Trolling, insulting or derogatory comments, and personal or political attacks.
* Public or private harassment.
* Publishing others' private information, such as a physical or email
address, without their explicit permission.
* Other conduct which could reasonably be considered inappropriate in a
professional setting.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, participating in a congress
or acting as an appointed representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior might be
reported to guillermo.gutierrezmorote@concordia.ca or ursula.eicker@concordia.ca.
All complaints will be reviewed and investigated promptly and fairly.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org

View File

@ -0,0 +1,164 @@
# How to create a class for the Central Data Model
This document explains the steps to follow if you want to contribute to the city data model by adding new classes or new attributes.
Use this document after having a clear idea of how your data model should look like already integrated in the Central Data Model.
Please, refer to the [cerclibs.pdf](https://liveconcordia.sharepoint.com/:b:/s/CERC-Next-GenCities-Platform/EfPNAGXexCFOju2sKBr6pNMBcwnvLin1Wio1Ahpfu4cxag?e=rhkdca)
to integrate your data model with the Central Data Model.
## Starting with the basics
- Install all requirements and download the hub project. [Here](WINDOWS_INSTALL.md) how to do it for windows.
In order to maintain a good quality code, we will work in branches. New codes will need to pass quality standards before being accepted in the main branch.
- Check and follow our [coding style](PYGUIDE.md).
- Dont forget to create unit tests and ensure that the old ones pass normally after your changes.
- Imperative! Document your work using comments in the code and, if needed, adding text files with extended explanations.
If the code doesn't pass the quality review, it will be rejected.
## Adding new parameters to existing classes
Adding a new parameter is an easy task. Open the desired class, for example, CityObject:
![city object](docs/img_contributing/img_5.png)
Add the name of your new parameter to the list at the constructor and initialize it as desired:
![new parameter](docs/img_contributing/img_6.png)
At the end of the class, add the corresponding getter and setter. It is very important that they are documented!
![getter and setter](docs/img_contributing/img_7.png)
You will see that the name of the file (city_object.py) changes from white to blue. That means that your version is different
from that one in the git. Once you finish doing your changes, you should commit and push them to your branch. The name of the file will turn back white.
## Creating a new class
Create a new class in the corresponding folder (if it does not exist, create a new folder ad hoc).
![new folder](docs/img_contributing/img_0.png)
![new file](docs/img_contributing/img_1.png)
![add to git](docs/img_contributing/img_2.png)
And add it to git (the name of the file will turn from red to green).
Every new class must have:
- A header with the following information:
```python
"""
My New Data Class module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Name of Project Coder name.project.coder@concordia.ca
"""
```
- A brief explanation of what it is, what it does, what it can be used for, etc. under its name:
```python
"""
MyNewDataClass class
This class models this and does that
"""
```
- All imported libraries together at the beginning.
![new class](docs/img_contributing/img_3.png)
A data class contains properties that describe the data model. Therefore, it should be mainly composed by getters and setters.
We would like to avoid having methods in the data classes. All those methods that could be done in the factories must be written there.
The properties can be divided into two groups, those that can be modified during the use of the model, and those that
are set only once and stay unchangeable. The line that divides these to groups is sometimes difficult to draw.
An example to get a taste of this difference could be the following. A building is formed by surfaces, the list of surfaces
is something that defines the building and, for our purposes, is unchangeable. On the other hand, if one of our studies is
to show the effect of the construction on the building demand, we may want to modify this during the run, so the construction
becomes changeable. This is important because those parameters that are static (unchangeable), must be provided for the
initialization and dont have setter, while the others are initialized at None and do have setter:
It is important to highlight that all setters and getters (@property) must have comments to describe the parameters, as shown in the previous image.
![new class getters and setters](docs/img_contributing/img_4.png)
Once you finish doing your changes, you should commit and push them to your branch. The name of the new files will change from green to white.
## Requesting a merge to the main branch
### Add a plugin
First, it is required to install a plugin for such purpose. We recommend [GitLab Merge Requests](https://plugins.jetbrains.com/plugin/18689-gitlab-merge-requests),
but you are free to choose the one you prefer. In order to install the plug, be sure that you have the latest pycharm version.
Go to Help -> Check for Updates... It will ask you to Update the new version, click on Update and Restart and follow the instructions.
![update pycharm](docs/img_contributing/img_9.png)
Don't forget to look in the bottom-right corner, there you always find the instructions, warnings, errors, announcements...
![pycharm announcement](docs/img_contributing/img_10.png)
Once you updated pycharm, go to File -> Settings... -> Plugins and search for _GitLab Merge Request_ and press Install.
![pycharm plugins](docs/img_contributing/img_11.png)
### Select the project
This step needs to be done only the first time.
Once the plugin is installed, it will appear a new tab at the bottom list called Gitlab Merge Requests as in the image:
![new tab](docs/img_contributing/img_12.png)
Click on _Clik to discover servers_ and select the gitlab.concordia.ca.
![new server](docs/img_contributing/img_13.png)
Observe that in the top-right corner of the tab, the message has changed from _No Repository_ to _Repo: /Guille/libs_.
![new repo](docs/img_contributing/img_14.png)
If you now click on Refresh Merge Request (see previous image), you will get a message asking for a token. As you don't have one yet, click on Create token.
![create token](docs/img_contributing/img_15.png)
You will be sent to the gitlab repository to create a new token. Give a name to it and check all options.
You are creating a token that has the same permits as your gitlab account has.
![create token in gitlab](docs/img_contributing/img_16.png)
A new personal access token will be created. Copy and paste it in the Access Token box.
A token is a personal and no-transferable key. Don't show it to anyone!
![copy token](docs/img_contributing/img_17.png)
![paste token](docs/img_contributing/img_18.png)
### Create merge request
Every time you want to send some changes to the main branch (merge your branch to the main one)
you will need to follow these steps.
Right clic on the blanc area and select + Create Merge Request.
![new merge request](docs/img_contributing/img_19.png)
A window will appear with the information of the request:
![request info](docs/img_contributing/img_20.png)
Clic on Assignees + and look for the project owner, in this case, Guillermo Gutierrez Morote.
Select him as assignee and clic OK.
This action will send a request for the merge. Now wait until this is accepted or rejected. You will receive an email to
the email account you use for gitlab with the answer.
Once the changes are accepted, go back to the main branch by selecting the Git tab (bottom-left). Right clic on Master and select Checkout.
![checkout master](docs/img_contributing/img_24.png)
Now pull (blue arrow), and delete the branch.
![erase branch](docs/img_contributing/img_26.png)
Now you have again the same version as in gitlab. For new changes, create a new branch and repeat the process.
## Documentation and authoring
There are two types of authors, that one who created the model and that one who coded it. If they are not the same person,
in the headers of the classes must appear just the name of the coder, who is the reference person to ask anything about the code,
and the one in charge of maintaining it, and interacting with the git.
The author of the data model will appear in the official documentation of the Insel4Cities platform. In those documents,
a larger explanation of the data model should be also added. This official documentation is under development and will be
linked here as soon as it is available.

View File

@ -0,0 +1,99 @@
# Contributing guidelines
## Push Request Checklist
Before sending your pull requests, make sure you completed this checklist:
- Read to the end [this document](CONTRIBUTING_EXTERNALS.md).
- Read [Code of Conduct](CODE_OF_CONDUCT.md).
- Check if your changes are consistent with the [Guidelines](CONTRIBUTING_EXTERNALS.md#user-content-general-guidelines-and-philosophy-for-contribution).
- Check if your changes are consistent with the [Coding Style](CONTRIBUTING_EXTERNALS.md#user-content-coding-style).
- Manually test your code and add [Unit Tests](CONTRIBUTING_EXTERNALS.md#user-content-testing-best-practices).
- Be sure that you didn't brake anything by running all unit tests in folder unittests (right click on the folder and click on the green play).
- [Document your work](CONTRIBUTING_EXTERNALS.md#user-content-documentation).
## How to become a contributor and submit your own code
### Contributor License Agreements
CERC Hub is an [LGPL licensed](LICENSE.md) software, so even if we'd love to accept your patches, before we can take them,
please be sure that you are the intellectual property owner of your code and that do you fully understand and respect our software license.
***NOTE***: Only source code that you own will go into the main repository.
### Contributing code
If you made any changes in your own project, just push them to git. You are the owner, you are the manager.
To do so, first, commit your changes by clicking on the green check at the top-right corner of Pycharm. Add a comment that explains briefly your changes.
Then, pull by clicking on the blue arrow to be sure that there are no conflicts between your version (local) and the one in gitlab (remote).
Once the conflicts are solved and the merge in local is done, push the changes by clicking on the green arrow.
If you have improvements to CERC Hub or want to extend the functionality, please send us your pull request as seen at [git pull request documentation](https://git-scm.com/docs/git-request-pull).
Or ASK GUILLE!!!!
Once the pull requests are approved and pass continuous integration checks, a team member will merge your changes on CERC Hub, and your code will become an integral part of Insel4D platform.
If you prefer to contribute, instead of adding new functionality, you can also take a look at our ticket system and try to fix any of the listed issues.
??????????? SURE WE WANT THIS?
### Contribution guidelines and standards
Before sending your pull request for review, make sure your changes are consistent with the guidelines, and follow the CERC Hub coding style.
#### General guidelines and philosophy for contribution
* Include unit tests when you contribute new features, as they help to:
* Prove that your code works correctly.
* Guard against future breaking changes to lower the maintenance cost.
* Bug fixes also generally require unit tests, because the presence of bugs usually indicates insufficient test coverage.
* Keep backward compatibility in mind when you change code in CERC Hub, and if you need to brake the backward compatibility, please ensure that you:
* Clearly indicate which features are affected by your changes.
* Technical reasons for the changes.
??????????? SURE WE WANT THIS?
* Tests should follow the
[testing best practices](CONTRIBUTING_EXTERNALS.md#user-content-testing-best-practices)
guide.
* [Document your contribution](CONTRIBUTING_EXTERNALS.md#user-content-documentation)
#### License
Include a small header with contact information and the code license at the top of any new file like in the following example.
"""
Name module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder name mail@concordia.ca
"""
#### Coding style
Changes to CERC Hub python code should conform to our coding style [Cerc Python Style Guide](PYGUIDE.md)
As a general basis, all contributions need to be focused on the concept of code clarity and use pylint to check your Python changes.
To install pylint and check your files against Cerc custom style definition:
To install `pylint` and check a file
with `pylint` against Cerc custom style definition:
```bash
pip install pylint
pylint --rcfile=pylintrc myfile.py
```
#### Testing best practices
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.
* 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.
#### Documentation
In case of new functionality, a general overview, configuration, installation, and user manuals need to be provided by the developer; this will provide an excellent starting point for all the future users and help you detect any inconsistencies in your design.

83
hub/DEPLOYMENT.md Normal file
View File

@ -0,0 +1,83 @@
## Installing PostgreSQL Database Server on Linux (Ubuntu) ##
In the terminal, add the key to the keyring
`
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
`
Update your repositories with
`sudo apt-get update`
Install postgresql
sudo apt-get install postgresql
`
*NB: PostgreSQL DB Server runs on a default port of 5432.*
## Installing PostgreSQL Database Server on Windows ##
1. Download a Windows installer from [this link](https://www.enterprisedb.com/downloads/postgres-postgresql-downloads).
2. Double click on the installer file and follow the prompts of the installation wizard
3. On the component selection page of the installation wizard make sure to select *PostgreSQL Server and Commandline tools*
4. You can optionally select pgAdmin 4 to install a graphical UI to access your database
5. On the password page when prompted, enter the default password (postgres) and confirm it
6. You can change the default password of 5432 on the port page. You should ensure that whatever port number you
provide is not used by another service.
7. Follow the installation wizard prompt to complete your installation. You can verify your installation by
searching for the *psql* tool from your start menu
## Installing PostgreSQL Database Server on Mac OS X ##
1. Download the Mac OS X installer from [this link](https://www.enterprisedb.com/downloads/postgres-postgresql-downloads).
2. Launch the installation wizard by double-clicking it and follow the rest of steps as described above on
Installing PostgreSQL Database Server on Windows.
NB: Hub has been tested with version 15 of PostgreSQL
## Create Database and Database User ##
1. Connect to the PostgreSQL database server via psql by executing `sudo -u postgres psql`. You will be
be prompted for a password, the default password of *postgres* user is *postgres*. The above command may not work on
a Windows system using the default command line tool. You can access the psql tool from Windows start menu and follow
the rest of the instructions from step 2 below
2. Execute `create user <username> with encrypted password '<password>';` in the psql console to create a user.
3. Execute `create database <database-name>;` in the psql console to create a database.
4. Execute `grant all privileges on database <database-name> to <username>;` to grant the all privileges on the database
to the user created in step 2 above.
5. The created database by default, has on schema named public which you can use. However, if you wish to create
another schema, you can do so by following [this link](https://www.postgresqltutorial.com/postgresql-administration/postgresql-create-schema/).
**NB: You can grant selected privileges to the user on the database using commands [on this page](https://tableplus.com/blog/2018/04/postgresql-how-to-grant-access-to-users.html).*
The user should however have read and write permission to all tables in the database. You can as well create a database and user using the PgAdmin UI tool*
## Setting Up Database Connection Parameters
1. Create a .env file that contains the configuration parameters as explained in the *Database Configuration Parameters*
section in persistence/README.md file.
2. The .env file should contain the following credentials: database user, database password, database host an,d database port
3. Provide the *absolute path* to the .env file to the persistence importers and exporters whenever using them in your code
as shown below:
```python
from hub.persistence.db_control import DBFactory
from pathlib import Path
dotenv_path = (Path(__file__).parent / '.env').resolve()
factory = DBFactory(db_name='hub_db', app_env='PROD', dotenv_path=dotenv_path)
```
## Create Database Tables ##
Use the *DBSetup* class in the persistence package to create the required database tables as described below
```python
from hub.persistence import DBSetup
from pathlib import Path
dotenv_path = (Path(__file__).parent / '.env').resolve()
DBSetup(db_name='hub_db', app_env='PROD', dotenv_path=dotenv_path, admin_password="your password here", application_uuid="your admin application uuid")
```
The *DBSetUp* class also creates a default admin user with default credentials that can be changed.
with the import UserFactory class. The admin user (name, email, password and role) is logged into the console after it is created by the
*constructor of DBSetup*. Use can also manage users (create, read, update and delete) with user import and export factories.
**NB: Make sure to change the default admin user credentials**

163
hub/LICENSE.md Normal file
View File

@ -0,0 +1,163 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license
document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates the terms
and conditions of version 3 of the GNU General Public License, supplemented
by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser General
Public License, and the "GNU GPL" refers to version 3 of the GNU General Public
License.
"The Library" refers to a covered work governed by this License, other than
an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided by the
Library, but which is not otherwise based on the Library. Defining a subclass
of a class defined by the Library is deemed a mode of using an interface provided
by the Library.
A "Combined Work" is a work produced by combining or linking an Application
with the Library. The particular version of the Library with which the Combined
Work was made is also called the "Linked Version".
The "Minimal Corresponding Source" for a Combined Work means the Corresponding
Source for the Combined Work, excluding any source code for portions of the
Combined Work that, considered in isolation, are based on the Application,
and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the object
code and/or source code for the Application, including any data and utility
programs needed for reproducing the Combined Work from the Application, but
excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License without
being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a facility
refers to a function or data to be supplied by an Application that uses the
facility (other than as an argument passed when the facility is invoked),
then you may convey a copy of the modified version:
a) under this License, provided that you make a good faith effort to ensure
that, in the event an Application does not supply the function or data, the
facility still operates, and performs whatever part of its purpose remains
meaningful, or
b) under the GNU GPL, with none of the additional permissions of this License
applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from a header
file that is part of the Library. You may convey such object code under terms
of your choice, provided that, if the incorporated material is not limited
to numerical parameters, data structure layouts and accessors, or small macros,
inline functions and templates (ten or fewer lines in length), you do both
of the following:
a) Give prominent notice with each copy of the object code that the Library
is used in it and that the Library and its use are covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that, taken together,
effectively do not restrict modification of the portions of the Library contained
in the Combined Work and reverse engineering for debugging such modifications,
if you also do each of the following:
a) Give prominent notice with each copy of the Combined Work that the Library
is used in it and that the Library and its use are covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during execution, include
the copyright notice for the Library among these notices, as well as a reference
directing the user to the copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this License,
and the Corresponding Application Code in a form suitable for, and under terms
that permit, the user to recombine or relink the Application with a modified
version of the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying Corresponding Source.
1) Use a suitable shared library mechanism for linking with the Library. A
suitable mechanism is one that (a) uses at run time a copy of the Library
already present on the user's computer system, and (b) will operate properly
with a modified version of the Library that is interface-compatible with the
Linked Version.
e) Provide Installation Information, but only if you would otherwise be required
to provide such information under section 6 of the GNU GPL, and only to the
extent that such information is necessary to install and execute a modified
version of the Combined Work produced by recombining or relinking the Application
with a modified version of the Linked Version. (If you use option 4d0, the
Installation Information must accompany the Minimal Corresponding Source and
Corresponding Application Code. If you use option 4d1, you must provide the
Installation Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the Library side
by side in a single library together with other library facilities that are
not Applications and are not covered by this License, and convey such a combined
library under terms of your choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based on the
Library, uncombined with any other library facilities, conveyed under the
terms of this License.
b) Give prominent notice with the combined library that part of it is a work
based on the Library, and explaining where to find the accompanying uncombined
form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions of the
GNU Lesser General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to address
new problems or concerns.
Each version is given a distinguishing version number. If the Library as you
received it specifies that a certain numbered version of the GNU Lesser General
Public License "or any later version" applies to it, you have the option of
following the terms and conditions either of that published version or of
any later version published by the Free Software Foundation. If the Library
as you received it does not specify a version number of the GNU Lesser General
Public License, you may choose any version of the GNU Lesser General Public
License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide whether
future versions of the GNU Lesser General Public License shall apply, that
proxy's public statement of acceptance of any version is permanent authorization
for you to choose that version for the Library.

50
hub/LINUX_INSTALL.md Normal file
View File

@ -0,0 +1,50 @@
# 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.

173
hub/MACOS_INSTALL.md Normal file
View File

@ -0,0 +1,173 @@
# MACOS_INSTALL
This is an installation guide for macOS, covering all the steps needed to begin developing code for the Urban Simulation
Platform 'Hub'. At the end of this process you will have installed and configured all the necessary applications,
set up your own project on CERC's Gitlab and created your first python file.
## Prepare your environment
To develop any new code for the Urban Simulation Platform you must have the right software applications installed and configured.
The Platform is written in python and so the applications you need are:
* Python Interpreter
* Python Editor
* @Chris: Miniconda??
You also need to register a user account with the CERC's code repository on Gitlab and have the necessary permissions for
creating new code. For that purpose, please, contact Guillermo (guillermo.gutierrezmorote@concordia.ca) or
Koa (kekoa.wells@concordia.ca) as soon as possible.
### Get a Python interpreter
1. Download the latest version of python for macOS: [Python environment](https://www.python.org/downloads/)
2. Open the downloaded .pkg file and follow the instructions to install.
### 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.
Whilst this is a personal choice we would like to recommend [PyCharm Community Edition](https://www.jetbrains.com/pycharm/download/#section=mac),
an excellent open-source python editor.
2. Open the downloaded .dmg file and then drag the PyCharm CE app into your Applications folder.
![pycharm ce](docs/img_macos_install/img_0.png)
## Get the CERC Hub source code
1. Run PyCharmCE
2. Click on the **Get from VCS** button in the top right of the window.
![get_vc_1](docs/img_macos_install/img_1.png)
3. Select **Git** as the **Version control**. For the URL use the link to the Hub repository, as seen below.
![get_vc_2](docs/img_macos_install/img_2.png)
(You can also copy this URL by going to the Hub repository in [Gitlab](https://rs-loy-gitlab.concordia.ca/Guille/hub.git)
and clicking on the Copy URL button next to **Clone with HTTPS**)
![git_lab](docs/img_macos_install/img_3.png)
The Directory to store the Hub source code locally is automatically created for you. Edit this if you prefer it to be stored somewhere else.
Note: If you see a message saying Git is not installed, click on the **Download and install** and follow instructions.
4. Click the **Clone** button to download CERC Hub source code.
(If the macOS security asks if you trust executing this source code, you can click **Trust Project**.)
![trust_project](docs/img_macos_install/img_4.png)
You will then see the project directories and files below, with the hub readme document displayed.
You have successfully cloned a copy of the CERC hub onto your computer.
![hub_readme](docs/img_macos_install/img_5.png)
## Create Your Own Branch of the Hub
You now need to create a new **Branch** of the Hub source code. This is like your own special version of the Hub,
where you can safely integrate your model, without affecting the smooth running of the Main Branch Hub and the Platform.
To create your working branch you need rights to edit the project. Please, contact Guillermo (guillermo.gutierrezmorote@concordia.ca)
or Koa (kekoa.wells@concordia.ca) to get those rights and then follow the instructions.
1. Create your working branch by right-clicking on the project folder (hub) and then selecting **Git->New Branch...**
![new_branch](docs/img_macos_install/img_6.png)
2. Give a name to your branch that has some sense of what will be done with it, _updating_documentation_,
_lca_classes_,... And, click on the **Create** button.
![name_branch](docs/img_macos_install/img_7.png)
3. Click on the **Git** button in the bottom-left corner to pop-up the window showing the Git information.
See your new branch has been created under _Local_.
![branch_in_local](docs/img_macos_install/img_8.png)
4. Now we need to let the CERC Gitlab repository know about this new branch. You do this by right-clicking on
your branch and selecting **Push...** from the drop-down menu.
![push_branch_1](docs/img_macos_install/img_9.png)
5. Then click on the **Push** button at the bottom-right of the **Push Commits** window.
![push_branch_2](docs/img_macos_install/img_10.png)
Note - at this point you may need to login to Gitlab using you Concordia credentials.
![gitlab_credentials](docs/img_macos_install/img_11.png)
Check that your branch now appears in the _Remote_ branch hierarchy, in the bottom-left corner. If it does not appear,
contact Guille (guillermo.gutierrezmorote@concordia.ca) or Koa (kekoa.wells@concordia.ca), to find the reason of the error.
![branch_pushed](docs/img_macos_install/img_12.png)
## Configure Pycharm
When integrating your model with the Platform, it is important that you follow [CERCs coding style guidelines](PYGUIDE.md).
One of the rules is that we use two spaces as a tab instead of the standard [pep8](https://www.python.org/dev/peps/pep-0008/)
four spaces indentation. This option can be configured in PyCharm at the settings screen.
To access the settings screen, click on the gear icon in the top right corner, and select **Preferences** from
the drop-down menu. The Preferences window will appear. From the panel on the left, select
**Editor->Code Style->Python** and you will see where tab size can be changed. Change it to 2.
See the picture below.
![configure_pycharm](docs/img_macos_install/img_13.png)
## Set up a new project on Gitlab
1. Open a browser and to the [CERC Git](https://rs-loy-gitlab.concordia.ca/). Click on the blue **New project** button.
![git_new_project](docs/img_macos_install/img_14.png)
2. Choose the **Create blank project** option from the three options seen below.
![blank_project](docs/img_macos_install/img_15.png)
3. Type in a name (remember to follow the CERC naming conventions described in the ![Coding Style](PYGUIDE.md)).
Check the option **Initialize repository with a README**, and ideally, check the **Visibility Level** to be **Public**.
Then click on the **Create project** button.
![project_created](docs/img_macos_install/img_16.png)
You should then see a confirmation screen with all the information about your new project.
![confirmation_project](docs/img_macos_install/img_17.png)
## Get your project into Pycharm
1. Now you can make a clone of this project, within PyCharm. First, copy the URL by clicking on the blue **Clone** button
and then click on the **Copy URL** button next to the **Clone with HTTPS** link.
![copy_https](docs/img_macos_install/img_18.png)
2. Switch back to PyCharm and close the Hub project by choosing **File->Close Project**. You will then see the
**Welcome To PyCharm** window again.
3. Clone a copy of your Project into PyCharm, following the steps 2-6 of the _GET THE CERC HUB SOURCE CODE_
section above, but using the URL link that you just copied for your gitlab project.
4. Select **Pycharm->Preferences** to open the **Preferences** window. From the panel on the left click on
**Project:<project name> -> Project Structure**.
![new_project_in_pychaem](docs/img_macos_install/img_19.png)
5. Add the Hub project to your own, by clicking on Add Content Root: (Pilar, this is where it all went wrong for me :-) )
## Create your first Python file
Add your first file to your project and click on install requirements to automatically download all the dependencies
(in blue at top-right corner).
When all the dependencies are satisfied, you are all set to start importing your first city model.
Add the following code to your main.py
from imports.geometry_factory import GeometryFactory
city = GeometryFactory('citygml', path='myfile.gml').city
Always remember to push your own project changes as the last thing you do before ending your working day!
First, commit your changes by clicking on the green check in the top-right corner of Pycharm. Add a comment
that explains briefly your changes. Then, pull by clicking on the blue arrow to be sure that there are no
conflicts between your version (local) and the remote one (gitlab). Once the conflicts are solved and the merge in
local is done, push the changes by clicking on the green arrow.

175
hub/PYGUIDE.md Normal file
View File

@ -0,0 +1,175 @@
# Cerc Python Style Guide
## What's coding style and why it matters.
Coding style is just how the code looks, it's incredibly personal, and everyone has their style.
Your preferred architectures, variable and function naming style all of then impacts in your code style and how the others read and understand it, so it could become a significant burden if everyone is coding on his or her own.
At CERC, we are following the [PEP8](https://www.python.org/dev/peps/pep-0008/) with two spaces indentation instead of four.
## Tools.
We use [PyCharm](https://www.jetbrains.com/pycharm/) as an integrated development environment and follow the tool's overall advice but the space indentation, which we set to two spaces instead of default four spaces.
For code analysis, we enforce the usage of [pylint](https://www.pylint.org/) with our own [custom style definition](pylintrc). This file will be downloaded with the project the first time you clone it.
## Naming convention.
* Name your folders and files in lowercase and use _ (underscore) to separate words.
* Your class names must start in capital letters and follow the python CapWords pattern.
* Methods and properties that return lists must end in "s". Therefore, those that return single values, must be singular.
* Methods and variables should be lowercase and use _ (underscore) as a word separator.
* Constant names must be all capitals.
* Avoid the usage of "get_" and "set_" methods whenever it is possible, use @property and @variable.setter decorators instead.
* "Private" methods, variables and properties start with _ (underscore).
## Imports.
Place your imports at the top of the file, after the license and contact information
comment.
```python
"""
MyClass module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder name name@concordia.ca
"""
import sys
```
Ensure that your imports are used and remove any unused.
## Object attributes and methods.
Use properties whenever it is possible. Encapsulate the access to all the calculated object attributes to avoid recalculating each time the property is called.
```python
@property
def object_attribute(cls):
if cls._object_attribute is None:
cls._object_attribute = ...
...
return cls._object_attribute
```
And like in the following example for read and write properties:
```python
@property
def object_changeable_attribute(cls):
return cls._object_changeable_attribute
@object_changeable_attribute.setter
def object_changeable_attribute(cls, value):
cls._object_changeable_attribute = value
```
If your method or attribute returns a complex object, use type hints as in this example:
```python
@property
def complex_object(cls) -> ComplexObject:
return cls._object_changeable_attribute
def new_complex_object(cls, first_param, second_param) -> ComplexObject:
other_needed_property = cls.other_needed_property
return ComplexObject(first_param, second_param, other_needed_property)
```
Always access your variable through the method and avoid to access directly.
```python
@property
def object_attribute(cls):
return cls._object_attribute
def operation(cls, first_param, second_param):
return cls.object_attribute * 2
```
### Comments.
#### Code documentation.
All public classes, properties, and methods must have code comments. Code comments start with capital letters and end without period:
```python
class MyClass
"""
MyClass class perform models class operations
"""
def __init__(cls):
@property
def object_attribute(cls):
"""
Get my class object attribute
:return: int
"""
return cls._object_attribute
def operation(cls, first_param, second_param):
"""
Multiplies object_attribute by two
:return: int
"""
return cls.object_attribute * 2
```
Comments at getters and setters always start with Get and Set, and identity the type of variable at return (at getter) or the value (at setter):
```python
@property
def object_attribute(cls):
"""
Get object attribute
:return: int
"""
return cls._object_attribute
@object_attribute.setter
def object_attribute(cls, value):
"""
Set object attribute
:param value: int
"""
cls._object_attribute = value
```
Attributes with known units should be explicit in method's comment.
```python
@property
def distance(cls):
"""
My class distance in meters
:return: float
"""
return cls._distance
```
#### To do's.
Pending to implement operations should be indicated with todo comments to highlight the missing functionality.
```python
# todo: right now extracted at the city level, in the future should be extracted also at building level if exist
```

20
hub/README.md Normal file
View File

@ -0,0 +1,20 @@
# Hub
Hub is part of Insel4Cities architecture for urban simulations, created by the CERC group at Concordia University.
Hub repository contains:
* city_model_structure: a central data model specifically design to model urban environments. An instance of this is called City.
* catalog_factories: a set of classes to describe catalog structures used by the import and export factories.
* imports: factories to import data from different formats to feed the city model structure (and create a City) or the catalog structures depending on the purpose.
* exports: factories to export desired parts of the City to different formats depending on the purpose, or to export catalogs in a common format.
* data: contains offered data, either for geometry, weather or different types of catalogs.
* other folders to support manipulating data.
Released under [LGPL license](LICENSE.md), will provide an object-oriented, modular approach to urban simulations.
Our aims are:
* involve as many scientists and contributors as possible.
* provide a complete set of classes that help scientists and students to model urban environments.
Please check the [contributing information](CONTRIBUTING_EXTERNALS.md) and [code of conduct](CODE_OF_CONDUCT.md) if you want to contribute, and let us know any new feature you may be of interest for you or your team.

View File

@ -0,0 +1,60 @@
# 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.
Output formats accepted:
* Function:
* nrel
* nrcan
* eilat
* Usage:
* nrcan
* comnet
* eilat
Libs_functions:
* single family house
* multi family house
* row hose
* mid rise apartment
* high rise apartment
* residential
* small office
* medium office
* large office
* primary school
* secondary school
* stand alone retail
* hospital
* out-patient health care
* strip mall
* supermarket
* ware house
* quick service restaurant
* full service restaurant
* small hotel
* large hotel
Libs_usage:
* residential
* single family house
* multi family house
* education
* school without shower
* school with shower
* retail shop without refrigerated food
* retail shop with refrigerated food
* hotel
* hotel medium class
* dormitory
* industry
* restaurant
* health care
* retirement home or orphanage
* office and administration
* event location
* hall
* sports location
* labor
* green-house
* non-heated

269
hub/WINDOWS_INSTALL.md Normal file
View File

@ -0,0 +1,269 @@
# WINDOWS_INSTALL
This is an installation guide for Windows, covering all the steps needed to begin developing code for the Urban
Simulation Platform 'Hub'. At the end of this process you will have installed and configured all the necessary applications,
set up your own project on CERC's Gitea and created your first python file.
## Prepare your environment
To develop any new code for the Urban Simulation Platform you must have the right software applications installed and configured.
The Platform is written in python and so the applications you need are:
* Miniconda
* SRA Files
* Python Editor
You also need to register a user account with the CERC's code repository on Gitea and have the necessary permissions for
creating new code. For that purpose, please, contact Guillermo (guillermo.gutierrezmorote@concordia.ca) or
Koa (kekoa.wells@concordia.ca) as soon as possible.
### Get Miniconda
1. Download [Miniconda for Windows](https://docs.conda.io/en/latest/miniconda.html) for Python version 3.9.
2. Run the installer and select in the corresponding window _Register Miniconda3 as my default Python 3.9_.
![conda](docs/img_windows_install/img_20.png)
If you already installed a Python interpreter, the following message will warn you:
![conda_2](docs/img_windows_install/img_21.png)
Click **OK** and then, click **Install**.
Once you are done, add Miniconda to the Path by clicking on **New** and writing the path where _conda.exe_ was installed.:
![path_1](docs/img_windows_install/img_27.png)
![path_2](docs/img_windows_install/img_28.png)
Now, restart the computer to update the Path.
Finally, open a terminal and type 'conda init powershell'.
![terminal_conda](docs/img_windows_install/img_30.png)
**NOTE:** This final step could produce the following error:
_The term '...' is not recognized as the name of a cmdlet, function,..._
![error_conda](docs/img_windows_install/img_32.png)
To solve it, type 'Set-ExecutionPolicy Unrestricted' as shown in the image.
### Setup SRA
1. Get the SRA executable and dll files from Guille or Koa
2. Create a folder in "C:\Program Files\" called "sra"
![create_sra](docs/img_windows_install/img_34.png)
3. Copy shortwave_integer.exe and pthreadGC2.dll into the sra folder.
![create_sra](docs/img_windows_install/img_35.png)
4. Add the newly created sra folder to the Path, similar to step 2 from the Miniconda setup above.
![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.
Whilst this is a personal choice we would like to recommend [PyCharm Community Edition](https://www.jetbrains.com/pycharm/download/#section=windows),
an excellent open-source python editor.
2. Run the installer, and follow the installation instructions for PyCharm, you may change a few options,
but the default ones should be fine.
**NOTE:** If PyCharm asks you to create a Virtual Environment, click **Cancel**. You will do it later using Conda instead.
![creating_virtual_environment](docs/img_windows_install/img_31.png)
## Get the CERC Hub source code
1. Run PyCharmCE
2. Click on the **Get from VCS** button in the top right of the window.
![pycharm welcome screen](docs/img_windows_install/img_0.png)
You can find it also at **Git->Clone...**
![pycharm get from version control](docs/img_windows_install/img_6.png)
3. Select **Git** as the **Version control**. Open the [hub repository](https://nextgenerations-cities.encs.concordia.ca/gitea/CERC/hub)
on Gitea and copy the URL from your browser to use as the URL inside PyCharm.
![pycharm get from version control screen](docs/img_windows_install/img_1.png)
![gitea get https](docs/img_windows_install/img_39.png)
The Directory to store the Hub source code locally is automatically created for you. Edit this if you prefer it to be stored somewhere else.
Note: If you see a message saying Git is not installed, click on the **Download and install** and follow instructions.
4. Click the **Clone** button to download CERC hub source code. You will then see the project directories and files below,
with the hub readme document displayed. You have successfully cloned a copy of the CERC hub onto your computer.
![pycharm_project_screen](docs/img_windows_install/img_2.png)
## Configure Python Interpreter
1. Click on **File**, and select **Settings...** from the drop-down menu. The Settings window will appear.
From the panel on the left, select **Project: hub->Python Interpreter** and you will see the following window:
![configure_interpreter_1](docs/img_windows_install/img_22.png)
2. Click on the little gear on the right and click **Add...**. In the new window, click on **Conda Environment**,
select **New environment** and the Python version 3.9.
![configure_interpreter_2](docs/img_windows_install/img_25.png)
You should end with the following window:
![configure_interpreter_3](docs/img_windows_install/img_26.png)
Click **OK** to close it.
**NOTE:** This final step could produce the following error:
![conda_environment_error](docs/img_windows_install/img_33.png)
To solve it, add to the Path (as explained in [previous chapter Get Miniconda](WINDOWS_INSTALL.md#Get Miniconda))
the following paths:
* C:\Users\User\miniconda3\Library\bin
* C:\Users\User\miniconda3
* C:\Users\User\miniconda3\Scripts
Restart the computer and come back to step 1 of this section.
5. Go to the Terminal (a tab in the bottom) to finish this process. You should see
_PS C:\Users\Pilar\PycharmProjects\hub>_ preceded either by _(base)_ or _(hub)_. If non of those are there,
be sure that you have Miniconda installed and included in the path as explained in
[previous chapter Get Miniconda](WINDOWS_INSTALL.md#Get Miniconda). If not, do it, restart Pycharm, and come back to this point.
If the environment you are working in is _(base)_, type 'conda activate ' and the project's name, in this case 'conda activate hub'.
Click enter, and the environment should change to _(hub)_. If this didn't work, contact Guillermo
(guillermo.gutierrezmorote@concordia.ca) or Koa (kekoa.wells@concordia.ca) for some help.
![configure interpreter 4](docs/img_windows_install/img_29.png)
6. Once you are in _(hub)_, type 'pip install -r .\requirements.txt' and wait until all requirements are installed. In the
bottom-right corner you should be able to see a bar showing the progress.
## Create Your Own Branch of the Hub
You now need to create a new **Branch** of the Hub source code. This is like your own special version of the Hub,
where you can safely integrate your model, without affecting the smooth running of the Main Branch Hub and the Platform.
To create your working branch you need rights to edit the project. Please, contact Guillermo (guillermo.gutierrezmorote@concordia.ca)
or Koa (kekoa.wells@concordia.ca) to get those rights and then follow the instructions.
1. Create your working branch by right-clicking on the project folder (hub) and then selecting **Git->New Branch...**
![create new branch 1](docs/img_windows_install/img_9.png)
2. Give a name to your branch that has some sense of what will be done with it, _updating_documentation_,
_lca_classes_,... And, click on the **Create** button.
![push new branch 1](docs/img_windows_install/img_11.png)
3. Click on the **Git** button in the bottom-left corner to pop-up the window showing the Git information.
See your new branch has been created under _Local_.
4. Now we need to let the CERC Gitea repository know about this new branch. You do this by right-clicking on
your branch and selecting **Push...** from the drop-down menu.
5. Then click on the **Push** button at the bottom-right of the **Push Commits** window.
![push new branch 2](docs/img_windows_install/img_12.png)
Check that your branch now appears in the _Remote_ branch hierarchy, in the bottom-left corner. If it does not appear,
contact Guillermo (guillermo.gutierrezmorote@concordia.ca) or Koa (kekoa.wells@concordia.ca), to find the reason of the error.
![check all set](docs/img_windows_install/img_13.png)
If your branch is there, you are done with this part.
Now you are all set to contribute to Hub or to use it for your own projects!
## Configure Pycharm
When integrating your model with the Platform, it is important that you follow [CERCs coding style guidelines](PYGUIDE.md).
One of the rules is that we use two spaces as a tab instead of the standard [pep8](https://www.python.org/dev/peps/pep-0008/)
four spaces indentation. This option can be configured in PyCharm at the settings screen.
To access the settings screen, click on **File**, and select **Settings...** from
the drop-down menu. The Settings window will appear. From the panel on the left, select
**Editor->Code Style->Python** and you will see where tab size can be changed. Change it to 2.
See the picture below.
![pycharm configuration screen](docs/img_windows_install/img_5.png)
## Set up a new project on Gitea
You will need an account before you can access the Gitea. Please contact Guillermo (guillermo.gutierrezmorote@concordia.ca) or
Koa (kekoa.wells@concordia.ca) to request an account.
1. Open a browser and go to the [CERC Gitea](https://nextgenerations-cities.encs.concordia.ca/). Click on the **+** in the top right
and select "New Repository" or press the **+** below the Organization tab.
![git new project screen](docs/img_windows_install/img_37.png)
2. Choose the **Create blank project** option from the three options seen below.
3. Type in a name that describes your project: _hp_workflow_, _bus_system_optimization_...
(remember to follow the CERC naming conventions described in the [Coding Style](PYGUIDE.md)).
Ideally, uncheck the option **Make Repository Private**, and check the **Initialize Repository**
Then click on the **Create project** button.
![git give a name](docs/img_windows_install/img_38.png)
You should then see a confirmation screen with all the information about your new project.
## Get your project into Pycharm
1. Now you can make a clone of this project, within PyCharm. First, go to the page of your repository on the Gitea and copy the URL.
2. Switch back to PyCharm and close the Hub project by choosing **File->Close Project**. You will then see the
**Welcome To PyCharm** window again.
3. Clone a copy of your Project into PyCharm, following the steps 2-6 of the _GET THE CERC HUB SOURCE CODE_
section above, but using the URL link that you just copied for your Gitea project.
4. Select **File->Settings** to open the **Settings** window. From the panel on the left click on
**Project:<project name> -> Project Structure**.
5. Add the Hub project to your own, by clicking on Add Content Root:
![pycharm new project screen](docs/img_windows_install/img_4.png)
![pycharm add hub](docs/img_windows_install/img_7.png)
6. Still in the **Settings** window, configure your Python interpreter (yes, again, you have to do this step for each new project)
by following steps 1 to 5 explained in [chapter Configure Python Interpreter](WINDOWS_INSTALL.md#Configure Python Interpreter).
Then, to install the requirements, type 'cd..' and enter. Then 'pip install -r .\hub\requirements.txt' and wait until all requirements are installed. In the
bottom-right corner you should be able to see a bar showing the progress. Finally, type 'cd ' and your project's name.
7. Now, add your first file to your project and click on install requirements to automatically download all the dependencies (in blue at top-right corner).
![pycharm add dependencies](docs/img_windows_install/img_8.png)
If the blue message doesn't appear, click on the **Terminal** tab (bottom-left), type _pip install -r .\requirements.txt_
and press enter.
8. When all the dependencies are satisfied, you are all set to start importing your first city model.
Add the following code to your main.py
```python
from hub.imports import GeometryFactory
city = GeometryFactory('citygml', path='myfile.gml').city
```
9. Always remember to push your own project changes as the last thing you do before ending your working day!
First, commit your changes by clicking on the green check in the top-right corner of Pycharm. Add a comment that explains briefly your changes.
Then, pull by clicking on the blue arrow to be sure that there are no conflicts between your version (local) and the remote one (Gitea).
Once the conflicts are solved and the merge in local is done, push the changes by clicking on the green arrow.

0
hub/__init__.py Normal file
View File

View File

View File

@ -0,0 +1,34 @@
"""
Catalog base class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class Catalog:
"""
Catalogs base class
catalog_factories will inherit from this class.
"""
def names(self, category=None):
"""
Base property to return the catalog entries names.
:return: Catalog names filter by category if provided
"""
raise NotImplementedError
def entries(self, category=None):
"""
Base property to return the catalog entries
:return: Catalog content filter by category if provided
"""
raise NotImplementedError
def get_entry(self, name):
"""
Base property to return the catalog entry matching the given name
:return: Catalog entry with the matching name
"""
raise NotImplementedError

View File

@ -0,0 +1,63 @@
"""
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
class ConstructionHelper:
"""
Construction helper class
"""
_reference_standard_to_construction_period = {
'non_standard_dompark': '1900 - 2004',
'ASHRAE 90.1_2004': '2004 - 2009',
'ASHRAE 189.1_2009': '2009 - PRESENT'
}
_nrel_surfaces_types_to_hub_types = {
'exterior wall': cte.WALL,
'interior wall': cte.INTERIOR_WALL,
'ground wall': cte.GROUND_WALL,
'exterior slab': cte.GROUND,
'attic floor': cte.ATTIC_FLOOR,
'interior slab': cte.INTERIOR_SLAB,
'roof': cte.ROOF
}
_nrcan_surfaces_types_to_hub_types = {
'OutdoorsWall': cte.WALL,
'OutdoorsRoofCeiling': cte.ROOF,
'OutdoorsFloor': cte.ATTIC_FLOOR,
'Window': cte.WINDOW,
'Skylight': cte.SKYLIGHT,
'GroundWall': cte.GROUND_WALL,
'GroundRoofCeiling': cte.GROUND_WALL,
'GroundFloor': cte.GROUND
}
@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

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

@ -0,0 +1,238 @@
"""
NRCAN construction catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
"""
import json
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 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:
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
)
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))
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

@ -0,0 +1,235 @@
"""
Nrel construction catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
from pathlib import Path
import xmltodict
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
from hub.catalog_factories.data_models.construction.layer import Layer
from hub.catalog_factories.data_models.construction.construction import Construction
from hub.catalog_factories.data_models.construction.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:
self._constructions = xmltodict.parse(xml.read(), force_list=('material', 'window', 'construction', 'layer'))
with open(archetypes_path, 'r', encoding='utf-8') as xml:
self._archetypes = xmltodict.parse(xml.read(), force_list=('archetype', 'construction'))
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['library']['windows']['window']
for window in windows:
frame_ratio = float(window['frame_ratio']['#text'])
g_value = window['shgc']
overall_u_value = float(window['conductivity']['#text']) / float(window['thickness']['#text'])
name = window['@name']
window_id = window['@id']
_catalog_windows.append(Window(window_id, frame_ratio, g_value, overall_u_value, name))
return _catalog_windows
def _load_materials(self):
_catalog_materials = []
materials = self._constructions['library']['materials']['material']
for material in materials:
material_id = material['@id']
name = material['@name']
solar_absorptance = float(material['solar_absorptance']['#text'])
thermal_absorptance = float(material['thermal_absorptance']['#text'])
visible_absorptance = float(material['visible_absorptance']['#text'])
no_mass = False
thermal_resistance = None
conductivity = None
density = None
specific_heat = None
if 'no_mass' in material and material['no_mass'] == 'true':
no_mass = True
thermal_resistance = float(material['thermal_resistance']['#text'])
else:
conductivity = float(material['conductivity']['#text'])
density = float(material['density']['#text'])
specific_heat = float(material['specific_heat']['#text'])
_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['library']['constructions']['construction']
for construction in constructions:
construction_id = construction['@id']
construction_type = ConstructionHelper().nrel_surfaces_types_to_hub_types[construction['@type']]
name = construction['@name']
layers = []
for layer in construction['layers']['layer']:
layer_id = layer['@id']
layer_name = layer['@name']
material_id = layer['material'][0]
thickness = 0
if 'thickness' in layer:
thickness = float(layer['thickness']['#text'])
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']['archetype']
for archetype in archetypes:
archetype_id = archetype['@id']
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']
]
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
archetype_constructions = []
for archetype_construction in archetype['constructions']['construction']:
for construction in self._catalog_constructions:
if construction.id == archetype_construction['@id']:
window_ratio = float(archetype_construction['window_ratio']['#text'])
window_id = archetype_construction['window']
_construction = None
_window = None
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,
indirect_heated_ratio,
infiltration_rate_for_ventilation_system_off,
infiltration_rate_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

@ -0,0 +1,57 @@
"""
Construction catalog factory, publish the construction information
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
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.helpers.utils import validate_import_export_type
Catalog = TypeVar('Catalog')
class ConstructionCatalogFactory:
"""
Construction catalog factory class
"""
def __init__(self, handler, 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._path = base_path
@property
def _nrel(self):
"""
Retrieve NREL catalog
"""
return NrelCatalog(self._path)
@property
def _nrcan(self):
"""
Retrieve NRCAN catalog
"""
return NrcanCatalog(self._path)
@property
def _eilat(self):
"""
Retrieve Eilat catalog
"""
return EilatCatalog(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

View File

@ -0,0 +1,196 @@
"""
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
"""
import xmltodict
from hub.catalog_factories.catalog import Catalog
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 MontrealNewCatalog(Catalog):
"""
Montreal custom catalog class
"""
def __init__(self, path):
path = (path / 'montreal_costs_completed.xml').resolve()
with open(path, 'r', encoding='utf-8') 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())
def _load_archetypes(self):
_catalog_archetypes = []
archetypes = self._archetypes['archetypes']['archetype']
for archetype in archetypes:
lod = float(archetype['@lod'])
function = archetype['@function']
municipality = archetype['@municipality']
country = archetype['@country']
currency = archetype['currency']
capital_cost = self.load_capital_costs(archetype)
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,
municipality,
country,
currency,
capital_cost,
operational_cost,
end_of_life_cost,
income))
return _catalog_archetypes
@staticmethod
def item_description(item_type, item):
if 'refurbishment_cost' in item.keys():
_refurbishment = float(item['refurbishment_cost']['#text'])
_refurbishment_unit = item['refurbishment_cost']['@cost_unit']
_item_description = ItemDescription(item_type,
initial_investment=None,
initial_investment_unit=None,
refurbishment=_refurbishment,
refurbishment_unit=_refurbishment_unit,
reposition=None,
reposition_unit=None,
lifetime=None)
else:
_reposition = float(item['reposition']['#text'])
_reposition_unit = item['reposition']['@cost_unit']
_investment = float(item['investment_cost']['#text'])
_investment_unit = item['investment_cost']['@cost_unit']
_lifetime = float(item['lifetime_equipment']['#text'])
_item_description = ItemDescription(item_type,
initial_investment=_investment,
initial_investment_unit=_investment_unit,
refurbishment=None,
refurbishment_unit=None,
reposition=_reposition,
reposition_unit=_reposition_unit,
lifetime=_lifetime)
return _item_description
def load_capital_costs(self, archetype):
archetype_capital_costs = archetype['capital_cost']
design_allowance = float(
archetype_capital_costs['Z_allowances_overhead_profit']['Z10_design_allowance']['#text']) / 100
overhead_and_profit = float(
archetype_capital_costs['Z_allowances_overhead_profit']['Z20_overhead_profit']['#text']) / 100
general_chapters = []
shell_items = []
service_items = []
for category in archetype_capital_costs:
if category == 'B_shell':
items = archetype_capital_costs[category]
for item in items:
components = items[item]
for component in components:
building_item = components[component]
shell_items.append(self.item_description(component, building_item))
general_chapters.append(Chapter(chapter_type=category, items=shell_items))
elif category == 'D_services':
services = archetype_capital_costs[category]
for service in services:
components = services[service]
if len(components.keys()) == 1:
for component in components:
service_item = components[component]
service_items.append(self.item_description(component, service_item))
else:
for component in components:
items = components[component]
if 'investment_cost' in items.keys():
service_item = components[component]
service_items.append(self.item_description(component, service_item))
else:
for item in items:
service_item = items[item]
service_items.append(self.item_description(item, service_item))
general_chapters.append(Chapter(chapter_type=category, items=service_items))
capital_costs = CapitalCost(general_chapters=general_chapters,
design_allowance=design_allowance,
overhead_and_profit=overhead_and_profit)
return capital_costs
@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)
heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text']) / 1000
cooling_equipment_maintenance = float(entry['maintenance']['cooling_equipment']['#text']) / 1000
photovoltaic_system_maintenance = float(entry['maintenance']['photovoltaic_system']['#text'])
co2_emissions = float(entry['co2_cost']['#text'])
_operational_cost = OperationalCost(fuels,
heating_equipment_maintenance,
cooling_equipment_maintenance,
photovoltaic_system_maintenance,
co2_emissions)
return _operational_cost
def names(self, category=None):
"""
Get the catalog elements names
:parm: for costs catalog category filter does nothing as there is only one category (archetypes)
"""
_names = {'archetypes': []}
for archetype in self._content.archetypes:
_names['archetypes'].append(archetype.name)
return _names
def entries(self, category=None):
"""
Get the catalog elements
:parm: for costs catalog category filter does nothing as there is only one category (archetypes)
"""
return self._content
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
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -0,0 +1,181 @@
"""
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
"""
import xmltodict
from hub.catalog_factories.catalog import Catalog
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:
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_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)
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)
heating_equipment_maintenance = float(entry['maintenance']['heating_equipment']['#text']) / 1000
cooling_equipment_maintenance = float(entry['maintenance']['cooling_equipment']['#text']) / 1000
photovoltaic_system_maintenance = float(entry['maintenance']['photovoltaic_system']['#text'])
co2_emissions = float(entry['co2_cost']['#text'])
_operational_cost = OperationalCost(fuels,
heating_equipment_maintenance,
cooling_equipment_maintenance,
photovoltaic_system_maintenance,
co2_emissions)
return _operational_cost
def _load_archetypes(self):
_catalog_archetypes = []
archetypes = self._archetypes['archetypes']['archetype']
for archetype in archetypes:
function = archetype['@function']
municipality = archetype['@municipality']
country = archetype['@country']
lod = float(archetype['@lod'])
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,
municipality,
country,
currency,
capital_cost,
operational_cost,
end_of_life_cost,
income))
return _catalog_archetypes
def names(self, category=None):
"""
Get the catalog elements names
:parm: for costs catalog category filter does nothing as there is only one category (archetypes)
"""
_names = {'archetypes': []}
for archetype in self._content.archetypes:
_names['archetypes'].append(archetype.name)
return _names
def entries(self, category=None):
"""
Get the catalog elements
:parm: for costs catalog category filter does nothing as there is only one category (archetypes)
"""
return self._content
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
raise IndexError(f"{name} doesn't exists in the catalog")

View File

@ -0,0 +1,51 @@
"""
Cost catalog publish the life cycle cost
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 pathlib import Path
from typing import TypeVar
from hub.catalog_factories.cost.montreal_custom_catalog import MontrealCustomCatalog
from hub.catalog_factories.cost.montreal_complete_cost_catalog import MontrealNewCatalog
Catalog = TypeVar('Catalog')
class CostsCatalogFactory:
"""
CostsCatalogFactory class
"""
def __init__(self, file_type, base_path=None):
if base_path is None:
base_path = Path(Path(__file__).parent.parent / 'data/costs')
self._catalog_type = '_' + file_type.lower()
self._path = base_path
@property
def _montreal_custom(self):
"""
Retrieve Montreal Custom catalog
"""
return MontrealCustomCatalog(self._path)
@property
def _montreal_new(self):
"""
Retrieve Montreal Custom catalog
"""
return MontrealNewCatalog(self._path)
@property
def catalog(self) -> Catalog:
"""
Return a cost catalog
:return: CostCatalog
"""
return getattr(self, self._catalog_type, lambda: None)
@property
def catalog_debug(self):
return MontrealNewCatalog(self._path)

View File

@ -0,0 +1,155 @@
"""
Construction catalog Archetype
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.construction import Construction
class Archetype:
"""
Archetype class
"""
def __init__(self, archetype_id,
name,
function,
climate_zone,
construction_period,
constructions,
average_storey_height,
thermal_capacity,
extra_loses_due_to_thermal_bridges,
indirect_heated_ratio,
infiltration_rate_for_ventilation_system_off,
infiltration_rate_for_ventilation_system_on):
self._id = archetype_id
self._name = name
self._function = function
self._climate_zone = climate_zone
self._construction_period = construction_period
self._constructions = constructions
self._average_storey_height = average_storey_height
self._thermal_capacity = thermal_capacity
self._extra_loses_due_to_thermal_bridges = extra_loses_due_to_thermal_bridges
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
@property
def id(self):
"""
Get archetype id
:return: str
"""
return self._id
@property
def name(self):
"""
Get archetype name
:return: str
"""
return self._name
@property
def function(self):
"""
Get archetype function
:return: str
"""
return self._function
@property
def climate_zone(self):
"""
Get archetype climate zone
:return: str
"""
return self._climate_zone
@property
def constructions(self) -> [Construction]:
"""
Get archetype constructions
:return: [Construction]
"""
return self._constructions
@property
def construction_period(self):
"""
Get archetype construction period
:return: str
"""
return self._construction_period
@property
def average_storey_height(self):
"""
Get archetype average storey height in m
:return: float
"""
return self._average_storey_height
@property
def thermal_capacity(self):
"""
Get archetype thermal capacity in J/m3K
:return: float
"""
return self._thermal_capacity
@property
def extra_loses_due_to_thermal_bridges(self):
"""
Get archetype extra loses due to thermal bridges in W/m2K
:return: float
"""
return self._extra_loses_due_to_thermal_bridges
@property
def indirect_heated_ratio(self):
"""
Get archetype indirect heated area ratio
:return: float
"""
return self._indirect_heated_ratio
@property
def infiltration_rate_for_ventilation_system_off(self):
"""
Get archetype infiltration rate for ventilation system off in 1/s
:return: float
"""
return self._infiltration_rate_for_ventilation_system_off
@property
def infiltration_rate_for_ventilation_system_on(self):
"""
Get archetype infiltration rate for ventilation system on in 1/s
: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,
'constructions': _constructions
}
}
return content

View File

@ -0,0 +1,88 @@
"""
Construction catalog construction
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
self._name = name
self._layers = layers
self._window_ratio = window_ratio
self._window = window
@property
def id(self):
"""
Get construction id
:return: str
"""
return self._id
@property
def type(self):
"""
Get construction type
:return: str
"""
return self._type
@property
def name(self):
"""
Get construction name
:return: str
"""
return self._name
@property
def layers(self) -> [Layer]:
"""
Get construction layers
:return: [layer]
"""
return self._layers
@property
def window_ratio(self):
"""
Get construction window ratio
:return: dict
"""
return self._window_ratio
@property
def window(self) -> Window:
"""
Get construction window
:return: Window
"""
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

@ -0,0 +1,63 @@
"""
Construction catalog content
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
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
self._materials = materials
self._windows = windows
@property
def archetypes(self):
"""
All archetypes in the catalog
"""
return self._archetypes
@property
def constructions(self):
"""
All constructions in the catalog
"""
return self._constructions
@property
def materials(self):
"""
All materials in the catalog
"""
return self._materials
@property
def windows(self):
"""
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

@ -0,0 +1,61 @@
"""
Construction catalog layer
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.material import Material
class Layer:
"""
Layer class
"""
def __init__(self, layer_id, name, material, thickness):
self._id = layer_id
self._name = name
self._material = material
self._thickness = thickness
@property
def id(self):
"""
Get layer id
:return: str
"""
return self._id
@property
def name(self):
"""
Get layer name
:return: str
"""
return self._name
@property
def material(self) -> Material:
"""
Get layer material
:return: Material
"""
return self._material
@property
def thickness(self):
"""
Get layer thickness in meters
: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

@ -0,0 +1,128 @@
"""
Construction catalog material
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class Material:
"""
Material class
"""
def __init__(self, material_id,
name,
solar_absorptance,
thermal_absorptance,
visible_absorptance,
no_mass=False,
thermal_resistance=None,
conductivity=None,
density=None,
specific_heat=None):
self._id = material_id
self._name = name
self._solar_absorptance = solar_absorptance
self._thermal_absorptance = thermal_absorptance
self._visible_absorptance = visible_absorptance
self._no_mass = no_mass
self._thermal_resistance = thermal_resistance
self._conductivity = conductivity
self._density = density
self._specific_heat = specific_heat
@property
def id(self):
"""
Get material id
:return: str
"""
return self._id
@property
def name(self):
"""
Get material name
:return: str
"""
return self._name
@property
def conductivity(self):
"""
Get material conductivity in W/mK
:return: None or float
"""
return self._conductivity
@property
def specific_heat(self):
"""
Get material conductivity in J/kgK
:return: None or float
"""
return self._specific_heat
@property
def density(self):
"""
Get material density in kg/m3
:return: None or float
"""
return self._density
@property
def solar_absorptance(self):
"""
Get material solar absorptance
:return: None or float
"""
return self._solar_absorptance
@property
def thermal_absorptance(self):
"""
Get material thermal absorptance
:return: None or float
"""
return self._thermal_absorptance
@property
def visible_absorptance(self):
"""
Get material visible absorptance
:return: None or float
"""
return self._visible_absorptance
@property
def no_mass(self):
"""
Get material no mass flag
:return: None or Boolean
"""
return self._no_mass
@property
def thermal_resistance(self):
"""
Get material thermal resistance in m2K/W
: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

@ -0,0 +1,79 @@
"""
Construction catalog window
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
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
self._g_value = g_value
self._overall_u_value = overall_u_value
self._name = name
self._type = window_type
@property
def id(self):
"""
Get window id
:return: str
"""
return self._id
@property
def name(self):
"""
Get window name
:return: str
"""
return self._name
@property
def frame_ratio(self):
"""
Get window frame ratio
:return: float
"""
return self._frame_ratio
@property
def g_value(self):
"""
Get thermal opening g-value
:return: float
"""
return self._g_value
@property
def overall_u_value(self):
"""
Get thermal opening overall U-value in W/m2K
:return: float
"""
return self._overall_u_value
@property
def type(self):
"""
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

View File

@ -0,0 +1,132 @@
"""
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
"""
from hub.catalog_factories.data_models.cost.capital_cost import CapitalCost
from hub.catalog_factories.data_models.cost.operational_cost import OperationalCost
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
self._function = function
self._municipality = municipality
self._country = country
self._currency = currency
self._capital_cost = capital_cost
self._operational_cost = operational_cost
self._end_of_life_cost = end_of_life_cost
self._income = income
@property
def name(self):
"""
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
@property
def function(self):
"""
Get function
:return: string
"""
return self._function
@property
def municipality(self):
"""
Get municipality
:return: string
"""
return self._municipality
@property
def country(self):
"""
Get country
:return: string
"""
return self._country
@property
def currency(self):
"""
Get currency
:return: string
"""
return self._currency
@property
def capital_cost(self) -> CapitalCost:
"""
Get capital cost
:return: CapitalCost
"""
return self._capital_cost
@property
def operational_cost(self) -> OperationalCost:
"""
Get operational cost
:return: OperationalCost
"""
return self._operational_cost
@property
def end_of_life_cost(self):
"""
Get end of life cost in given currency per m2
:return: float
"""
return self._end_of_life_cost
@property
def income(self) -> Income:
"""
Get income
: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

@ -0,0 +1,66 @@
"""
Capital costs included in the 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
"""
from typing import List
from hub.catalog_factories.data_models.cost.chapter import Chapter
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
@property
def general_chapters(self) -> List[Chapter]:
"""
Get general chapters in capital costs
:return: [Chapter]
"""
return self._general_chapters
@property
def design_allowance(self):
"""
Get design allowance in percentage (-)
:return: float
"""
return self._design_allowance
@property
def overhead_and_profit(self):
"""
Get overhead profit in percentage (-)
:return: float
"""
return self._overhead_and_profit
def chapter(self, name) -> Chapter:
"""
Get specific chapter by name
:return: Chapter
"""
for chapter in self.general_chapters:
if chapter.chapter_type == name:
return chapter
raise KeyError(f'Chapter name {name} not found')
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
}
}
return content

View File

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

@ -0,0 +1,40 @@
"""
Cost catalog content
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 Content:
"""
Content class
"""
def __init__(self, archetypes):
self._archetypes = archetypes
@property
def archetypes(self):
"""
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,71 @@
"""
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,77 @@
"""
Incomes included in the 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
"""
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
@property
def construction_subsidy(self) -> Union[None, float]:
"""
Get subsidy for construction in percentage %
:return: None or float
"""
return self._construction_subsidy
@property
def hvac_subsidy(self) -> Union[None, float]:
"""
Get subsidy for HVAC system in percentage %
:return: None or float
"""
return self._hvac_subsidy
@property
def photovoltaic_subsidy(self) -> Union[None, float]:
"""
Get subsidy PV systems in percentage
:return: None or float
"""
return self._photovoltaic_subsidy
@property
def electricity_export(self) -> Union[None, float]:
"""
Get electricity export incomes in currency per J
:return: None or float
"""
return self._electricity_export
@property
def reductions_tax(self) -> Union[None, float]:
"""
Get reduction in taxes in percentage (-)
:return: None or float
"""
return self._reductions_tax
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

View File

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

@ -0,0 +1,77 @@
"""
Operational costs included in the 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
"""
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
@property
def fuels(self) -> List[Fuel]:
"""
Get fuels listed in capital costs
:return: [Fuel]
"""
return self._fuels
@property
def maintenance_heating(self):
"""
Get cost of maintaining the heating system in currency/W
:return: float
"""
return self._maintenance_heating
@property
def maintenance_cooling(self):
"""
Get cost of maintaining the cooling system in currency/W
:return: float
"""
return self._maintenance_cooling
@property
def maintenance_pv(self):
"""
Get cost of maintaining the PV system in currency/m2
:return: float
"""
return self._maintenance_pv
@property
def co2(self):
"""
Get cost of CO2 emissions in currency/kgCO2
:return: float
"""
return self._co2
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
}
}
return content

View File

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

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

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

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

@ -0,0 +1,60 @@
"""
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=None):
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

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

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

@ -0,0 +1,310 @@
"""
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, dual_supply_capability=False):
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._dual_supply_capability = dual_supply_capability
@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 dual_supply_capability(self):
"""
Get dual supply capability
:return: bool
"""
return self._dual_supply_capability
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,
'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': self.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,
'dual supply capability': self.dual_supply_capability
}
}
return content

View File

@ -0,0 +1,72 @@
"""
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*x + b
Exponential =>>> y = a*(b**x)
Polynomial =>>> y = a*(x**2) + b*x + c
Power =>>> y = a*(x**b)
Second degree multivariable =>>> y = a*(x**2) + b*x + c*x*z + d*z + e*(z**2) + f
Get the type of function from ['linear', 'exponential', 'polynomial', 'power', 'second degree multivariable']
: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

@ -0,0 +1,153 @@
"""
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, 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._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 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,
'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

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

@ -0,0 +1,116 @@
"""
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):
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
@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
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()
}
}
return content

View File

@ -0,0 +1,55 @@
"""
Greenery catalog content
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class Content:
"""
Content class
"""
def __init__(self, vegetations, plants, soils):
self._vegetations = vegetations
self._plants = plants
self._soils = soils
@property
def vegetations(self):
"""
All vegetation in the catalog
"""
return self._vegetations
@property
def plants(self):
"""
All plants in the catalog
"""
return self._plants
@property
def soils(self):
"""
All soils in the catalog
"""
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

@ -0,0 +1,117 @@
"""
Greenery catalog data model Plant class
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.greenery.soil import Soil as hub_soil
class Plant:
"""
Plant class
"""
def __init__(self, category, plant):
self._name = plant.name
self._category = category
self._height = plant.height
self._leaf_area_index = plant.leafAreaIndex
self._leaf_reflectivity = plant.leafReflectivity
self._leaf_emissivity = plant.leafEmissivity
self._minimal_stomatal_resistance = plant.minimalStomatalResistance
self._co2_sequestration = plant.co2Sequestration
self._grows_on = []
for soil in plant.growsOn:
self._grows_on.append(hub_soil(soil))
@property
def name(self):
"""
Get plant name
:return: string
"""
return self._name
@property
def category(self):
"""
Get plant category name
:return: string
"""
return self._category
@property
def height(self):
"""
Get plant height in m
:return: float
"""
return self._height
@property
def leaf_area_index(self):
"""
Get plant leaf area index
:return: float
"""
return self._leaf_area_index
@property
def leaf_reflectivity(self):
"""
Get plant leaf area index
:return: float
"""
return self._leaf_reflectivity
@property
def leaf_emissivity(self):
"""
Get plant leaf emissivity
:return: float
"""
return self._leaf_emissivity
@property
def minimal_stomatal_resistance(self):
"""
Get plant minimal stomatal resistance in s/m
:return: float
"""
return self._minimal_stomatal_resistance
@property
def co2_sequestration(self):
"""
Get plant co2 sequestration capacity in kg CO2 equivalent
:return: float
"""
return self._co2_sequestration
@property
def grows_on(self) -> [hub_soil]:
"""
Get plant compatible soils
: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

@ -0,0 +1,46 @@
"""
Greenery catalog data model Plant percentage class
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.greenery.plant import Plant as HubPlant
class PlantPercentage(HubPlant):
"""
Plant percentage class
"""
def __init__(self, percentage, plant_category, plant):
super().__init__(plant_category, plant)
self._percentage = percentage
@property
def percentage(self):
"""
Get plant percentage
: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

@ -0,0 +1,129 @@
"""
Greenery catalog data model Soil class
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
"""
class Soil:
"""
Soil class
"""
def __init__(self, soil):
self._name = soil.name
self._roughness = soil.roughness
self._dry_conductivity = soil.conductivityOfDrySoil
self._dry_density = soil.densityOfDrySoil
self._dry_specific_heat = soil.specificHeatOfDrySoil
self._thermal_absorptance = soil.thermalAbsorptance
self._solar_absorptance = soil.solarAbsorptance
self._visible_absorptance = soil.visibleAbsorptance
self._saturation_volumetric_moisture_content = soil.saturationVolumetricMoistureContent
self._residual_volumetric_moisture_content = soil.residualVolumetricMoistureContent
self._initial_volumetric_moisture_content = soil.initialVolumetricMoistureContent
@property
def name(self):
"""
Get soil name
:return: string
"""
return self._name
@property
def roughness(self):
"""
Get soil roughness
:return: string
"""
return self._roughness
@property
def dry_conductivity(self):
"""
Get soil dry conductivity in W/mK
:return: float
"""
return self._dry_conductivity
@property
def dry_density(self):
"""
Get soil dry density in kg/m3
:return: float
"""
return self._dry_density
@property
def dry_specific_heat(self):
"""
Get soil dry specific heat in J/kgK
:return: float
"""
return self._dry_specific_heat
@property
def thermal_absorptance(self):
"""
Get soil thermal absortance
:return: float
"""
return self._thermal_absorptance
@property
def solar_absorptance(self):
"""
Get soil solar absortance
:return: float
"""
return self._solar_absorptance
@property
def visible_absorptance(self):
"""
Get soil visible absortance
:return: float
"""
return self._visible_absorptance
@property
def saturation_volumetric_moisture_content(self):
"""
Get soil saturation volumetric moisture content
:return: float
"""
return self._saturation_volumetric_moisture_content
@property
def residual_volumetric_moisture_content(self):
"""
Get soil residual volumetric moisture content
:return: float
"""
return self._residual_volumetric_moisture_content
@property
def initial_volumetric_moisture_content(self):
"""
Get soil initial volumetric moisture content
: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

@ -0,0 +1,198 @@
"""
Greenery catalog data model Vegetation class
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.greenery.plant_percentage import PlantPercentage
class Vegetation:
"""
Vegetation class
"""
def __init__(self, category, vegetation, plant_percentages):
self._name = vegetation.name
self._category = category
self._soil_thickness = vegetation.thicknessOfSoil
self._management = vegetation.management
self._air_gap = vegetation.airGap
self._soil_name = vegetation.soil.name
self._soil_roughness = vegetation.soil.roughness
self._dry_soil_conductivity = vegetation.soil.conductivityOfDrySoil
self._dry_soil_density = vegetation.soil.densityOfDrySoil
self._dry_soil_specific_heat = vegetation.soil.specificHeatOfDrySoil
self._soil_thermal_absorptance = vegetation.soil.thermalAbsorptance
self._soil_solar_absorptance = vegetation.soil.solarAbsorptance
self._soil_visible_absorptance = vegetation.soil.visibleAbsorptance
self._soil_saturation_volumetric_moisture_content = vegetation.soil.saturationVolumetricMoistureContent
self._soil_residual_volumetric_moisture_content = vegetation.soil.residualVolumetricMoistureContent
self._soil_initial_volumetric_moisture_content = vegetation.soil.initialVolumetricMoistureContent
self._plant_percentages = plant_percentages
@property
def name(self):
"""
Get vegetation name
:return: string
"""
return self._name
@property
def category(self):
"""
Get vegetation category
:return: string
"""
return self._category
@property
def soil_thickness(self):
"""
Get soil thickness in m
:return: float
"""
return self._soil_thickness
@property
def management(self):
"""
Get management
:return: string
"""
return self._management
@property
def air_gap(self):
"""
Get air gap in m
:return: float
"""
return self._air_gap
@property
def plant_percentages(self) -> [PlantPercentage]:
"""
Get plant percentages
:return: [PlantPercentage]
"""
percentage = 0.0
for plant_percentage in self._plant_percentages:
percentage += float(plant_percentage.percentage)
if percentage > 100:
raise ValueError('the plant percentage in this vegetation is over 100%')
return self._plant_percentages
@property
def soil_name(self):
"""
Get soil name
:return: string
"""
return self._soil_name
@property
def soil_roughness(self):
"""
Get soil roughness
:return: float
"""
return self._soil_roughness
@property
def dry_soil_conductivity(self):
"""
Get soil dry conductivity in W/mK
:return: float
"""
return self._dry_soil_conductivity
@property
def dry_soil_density(self):
"""
Get soil dry density in kg/m3
:return: float
"""
return self._dry_soil_density
@property
def dry_soil_specific_heat(self):
"""
Get soil dry specific heat in J/kgK
:return: float
"""
return self._dry_soil_specific_heat
@property
def soil_thermal_absorptance(self):
"""
Get soil thermal absortance
:return: float
"""
return self._soil_thermal_absorptance
@property
def soil_solar_absorptance(self):
"""
Get soil solar absortance
:return: float
"""
return self._soil_solar_absorptance
@property
def soil_visible_absorptance(self):
"""
Get soil visible absortance
:return: float
"""
return self._soil_visible_absorptance
@property
def soil_saturation_volumetric_moisture_content(self):
"""
Get soil saturation volumetric moisture content
:return: float
"""
return self._soil_saturation_volumetric_moisture_content
@property
def soil_residual_volumetric_moisture_content(self):
"""
Get soil residual volumetric moisture content
:return: float
"""
return self._soil_residual_volumetric_moisture_content
@property
def soil_initial_volumetric_moisture_content(self):
"""
Get soil initial volumetric moisture content
: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

@ -0,0 +1,76 @@
"""
Usage catalog appliances
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, List
from hub.catalog_factories.data_models.usages.schedule import Schedule
class Appliances:
"""
Appliances class
"""
def __init__(self, density, convective_fraction, radiative_fraction, latent_fraction, schedules):
self._density = density
self._convective_fraction = convective_fraction
self._radiative_fraction = radiative_fraction
self._latent_fraction = latent_fraction
self._schedules = schedules
@property
def density(self) -> Union[None, float]:
"""
Get appliances density in W/m2
:return: None or float
"""
return self._density
@property
def convective_fraction(self) -> Union[None, float]:
"""
Get convective fraction
:return: None or float
"""
return self._convective_fraction
@property
def radiative_fraction(self) -> Union[None, float]:
"""
Get radiant fraction
:return: None or float
"""
return self._radiative_fraction
@property
def latent_fraction(self) -> Union[None, float]:
"""
Get latent fraction
:return: None or float
"""
return self._latent_fraction
@property
def schedules(self) -> Union[None, List[Schedule]]:
"""
Get schedules
dataType = fraction
: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

@ -0,0 +1,40 @@
"""
Usage catalog usage
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.usages.usage import Usage
class Content:
"""
Content class
"""
def __init__(self, usages):
self._usages = usages
@property
def usages(self) -> [Usage]:
"""
Get catalog usages
"""
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

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

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