Compare commits
524 Commits
test_majid
...
main
Author | SHA1 | Date | |
---|---|---|---|
3db3acd3c6 | |||
15aaf2a337 | |||
7ad16ba640 | |||
f42bb64b85 | |||
3dd64143ab | |||
164ffbf9c8 | |||
bf4018a649 | |||
6c7f652390 | |||
4e46b6bc0d | |||
4ac9ccda81 | |||
df2d7a3054 | |||
47810737fa | |||
99535a979c | |||
9986552ec1 | |||
d1719b50ed | |||
5e01f4eb7f | |||
d38150ac2d | |||
5e5129ecd7 | |||
3905f228dc | |||
33049441f0 | |||
70dd9f7c6a | |||
0ce392ea06 | |||
|
4b6a942324 | ||
2495046c44 | |||
4738de0d8c | |||
e220bf2c0d | |||
a45cf02b28 | |||
ef62e2531f | |||
|
cd34435a9f | ||
|
15b96fe154 | ||
|
54a6e6b2db | ||
|
a7375f0b53 | ||
|
725746fbcb | ||
ec320a2e1c | |||
8a68118503 | |||
a3ec3c7e19 | |||
|
ace666553a | ||
c4636c2c3c | |||
4a01ac51d8 | |||
ee846a6225 | |||
a4f3b48617 | |||
abc3fc48dd | |||
db371aecf3 | |||
998df80b63 | |||
446c7fa4ce | |||
3c5f1b7357 | |||
6d2bb98470 | |||
26b2af1e2b | |||
dc3372ff5e | |||
a81c0cfee3 | |||
1279dffff8 | |||
1cc7b2cb8c | |||
2d11bf6640 | |||
9adacadc2a | |||
15e43a0f35 | |||
6dbff12ff9 | |||
982bcab045 | |||
83d308e03b | |||
915170e60f | |||
6afc076402 | |||
6e79541816 | |||
c36ce1b83a | |||
3de2e00a54 | |||
5fb31fc5ca | |||
7851968bdc | |||
6684e7ef1b | |||
64449aee1d | |||
a0f7ca0e17 | |||
58d84021cf | |||
84d80d5d2a | |||
6b3110d1c0 | |||
f095483b36 | |||
841098b615 | |||
73e6dcdaf7 | |||
8fe002a22c | |||
ffd0367d50 | |||
f15401c148 | |||
9a99f69bdf | |||
fe99059e5a | |||
d9d9a628b4 | |||
d9a941a97a | |||
b52e66c263 | |||
039a0f30ba | |||
ebeafddc74 | |||
355cc6ecdf | |||
cbe720f0de | |||
52382566d3 | |||
4056a2ab8a | |||
1f7b4924fe | |||
20200f0efe | |||
919ab60bd5 | |||
aa85473a81 | |||
aac006f63a | |||
199d7dc4f9 | |||
3a6a712cad | |||
27291ad1b8 | |||
5fdfee9265 | |||
0f0a923329 | |||
bf23730281 | |||
11d493ba0e | |||
1266f50e29 | |||
674393970c | |||
8d75fe1f3a | |||
57a9d24f4c | |||
087fead489 | |||
ebaec9bb7c | |||
3e193f04a6 | |||
ac4742d2c4 | |||
f976040f45 | |||
54b62ec2d0 | |||
9357cef641 | |||
002d5a659d | |||
f9815dfa49 | |||
eeda66f410 | |||
aa0f790d8e | |||
e0e7daf64b | |||
5181ddcabb | |||
68457b9d26 | |||
673cbac77a | |||
11f78ccb89 | |||
3891c866cf | |||
5230da861c | |||
87b2319fda | |||
1916d21c4e | |||
57388a9dc4 | |||
89d0d0eae8 | |||
e025510c93 | |||
d592de6759 | |||
eeac9a24a8 | |||
7328118861 | |||
9444de6bae | |||
27ceed01fe | |||
57c7a76529 | |||
020190829f | |||
c3f2cfb02a | |||
e3f1d52a21 | |||
716465f1eb | |||
81702e0008 | |||
953b6796e9 | |||
898f364e28 | |||
03da727d29 | |||
b51d49d598 | |||
802641b4a3 | |||
914375171a | |||
72b6cddea4 | |||
7f16449edb | |||
c8545835d9 | |||
4bc8df8e9d | |||
fca74eeb08 | |||
227685695a | |||
ac6b023080 | |||
383a480f65 | |||
67525e50fa | |||
601058fc5e | |||
cfd2586f80 | |||
a3c5219ccd | |||
5fa55ea79f | |||
68bb9223e3 | |||
a1ca764057 | |||
8c27e69a79 | |||
557d77661e | |||
38d8013356 | |||
43fa1e0d92 | |||
812c9541f4 | |||
c1e392d828 | |||
fe315bc6bb | |||
087379b010 | |||
452bfdf780 | |||
63803efccb | |||
0f0368c074 | |||
08e701a972 | |||
914d521e81 | |||
7f8e0d48ee | |||
26c0ef7864 | |||
5ce3a24e55 | |||
0894c5dac6 | |||
ee06d45ba9 | |||
3dd928574a | |||
9591db3bf8 | |||
69f3b7f814 | |||
6e6c78b6f4 | |||
75bb316848 | |||
ed7d6d13f6 | |||
42de9cea97 | |||
255f9f861a | |||
4449d0b92d | |||
89452dcf31 | |||
6aafda7f42 | |||
6da8fde949 | |||
6332519e12 | |||
9ce97edc13 | |||
98676e81e0 | |||
5cba38cf65 | |||
3512d4b1e4 | |||
b0fabf3b7f | |||
6d987f43f7 | |||
f62ab95cf0 | |||
b711bceb7b | |||
6ee1466b8e | |||
a31281cae7 | |||
8d5010218b | |||
a102a201e6 | |||
2afce4acce | |||
9c1e05939a | |||
978cc9d1ea | |||
0240e89170 | |||
c6d4feec89 | |||
3f649fd020 | |||
d94bce4174 | |||
f865490ff9 | |||
31a4893ed8 | |||
1a7ad20135 | |||
fe76d2fe3d | |||
57ee3e734b | |||
7cb4600c15 | |||
3578d2faae | |||
d6bfe730eb | |||
84f5ebe4a0 | |||
6b24a59178 | |||
11dc02d0e8 | |||
d29161b05e | |||
a331dce966 | |||
3f91da9f45 | |||
f13d7fd860 | |||
ef89da8552 | |||
9654bee978 | |||
dae117fb44 | |||
91fa9d5ca1 | |||
8e145eefa1 | |||
6f40a15609 | |||
4a14deece1 | |||
ca48d6448b | |||
f2bfc297b3 | |||
d5c443a57b | |||
568317ebf1 | |||
af32decf96 | |||
bb05b01312 | |||
cbda6ce13d | |||
2b696f9251 | |||
a97c068513 | |||
f0ad1462d0 | |||
23a8fbe86d | |||
087384475f | |||
fac6844da1 | |||
b914c9e7bf | |||
cf783d8998 | |||
8bd75c790f | |||
eaa3064a3f | |||
207058a16f | |||
8dbbfb9460 | |||
3809cf2885 | |||
8b66e20e9a | |||
6d34e41e90 | |||
f495c1d27a | |||
a43c971bbb | |||
4ce9f99e4d | |||
e3c9c64e9f | |||
8099037225 | |||
|
12d20f2d7a | ||
|
bf004f9e18 | ||
|
482c06e4c2 | ||
cb3e100fd4 | |||
41cf280aab | |||
ee875859e8 | |||
989d89df80 | |||
73dffdc367 | |||
b24a616d00 | |||
aa6b3c9e74 | |||
707b42f2a9 | |||
cd7104206a | |||
29ba43f1d9 | |||
70cc659c14 | |||
f0ffc26348 | |||
cde3bfb4ae | |||
8f8a6dbf71 | |||
1392c05489 | |||
a0d2f7e5bc | |||
2a5c552f17 | |||
86b7378a54 | |||
cf6542cb0c | |||
4004ff3c84 | |||
4ae09915b1 | |||
9624be2cf9 | |||
c072527dc6 | |||
56c84ad399 | |||
a5f70f4720 | |||
b7c2bbae96 | |||
8763523d3b | |||
7810f8f91d | |||
d4b424357d | |||
8dbeeaafa1 | |||
c77b2254f1 | |||
b1d42ee00b | |||
6ac63adaaf | |||
644b1c9346 | |||
8f1f344769 | |||
6551eb6402 | |||
24a670755a | |||
cfb76a9ebd | |||
5d4813f2f6 | |||
2f62ce3fdb | |||
58e7ce7574 | |||
43e5bb7310 | |||
fe0a2d3003 | |||
3deb63b14a | |||
9b0bdf2b7e | |||
ade5ef94bb | |||
40bc0154dd | |||
ff1bb80a6c | |||
76d3ba8495 | |||
491b976fd9 | |||
072d2a6d9d | |||
72b5ff1040 | |||
e20a700deb | |||
0528aa0718 | |||
923b1fe267 | |||
32a40f17a6 | |||
e91e61741e | |||
16618fb54a | |||
21ca1e1e28 | |||
ccdc7a454d | |||
3feecac15d | |||
acd7ad2266 | |||
6ce82c52de | |||
d6ee3d6e6b | |||
231e4a17f2 | |||
012076492f | |||
61d4c012dc | |||
fa518126a5 | |||
e0037e788f | |||
e08080c601 | |||
1b3a128f33 | |||
a3028221e3 | |||
19d05940fa | |||
fde6f0f751 | |||
fdead81f26 | |||
db0e400343 | |||
ec288f8db1 | |||
b746387133 | |||
480acc6552 | |||
7c29405f21 | |||
|
e1ca39950f | ||
|
02a03b8239 | ||
d564218531 | |||
ebb712ebaf | |||
|
9094c286c4 | ||
9034c3375e | |||
e2c8ef0c56 | |||
30908eda6d | |||
deb04cbe2d | |||
2b95173dfc | |||
7f5cde8175 | |||
bb76d05f17 | |||
ca81ce3020 | |||
3f4038286e | |||
c4930b940f | |||
527bf4448b | |||
1b3053b37f | |||
cf3f85c7f4 | |||
db7caad218 | |||
7fb39171f4 | |||
b7d7c9aadb | |||
4012408e2f | |||
8502efc710 | |||
19011d3fc1 | |||
bdf0deb3b3 | |||
ab81edc33d | |||
a3bf594071 | |||
04ef636423 | |||
d7e041b686 | |||
90a196465a | |||
7cf926bc5b | |||
83fc351fc7 | |||
8a41c4f656 | |||
589f3e7f11 | |||
67cd435fd5 | |||
1e9afa28a8 | |||
212b4b0621 | |||
fe8c79d7c2 | |||
e138a24555 | |||
86845dd05f | |||
1691ada01c | |||
4bbd65bb41 | |||
9365b47dc2 | |||
7143913144 | |||
75848ef250 | |||
9f24ed8fae | |||
4b5c037ffa | |||
6b89008698 | |||
0f982df32e | |||
c38b025c2e | |||
4d0f247a83 | |||
a147afe76f | |||
e44abc2f3a | |||
421c69e97e | |||
2292bff1b8 | |||
1abf76125f | |||
ce995c375d | |||
2cc938e416 | |||
eb246a18e6 | |||
57322e1b19 | |||
24324988b6 | |||
ee419b0849 | |||
f95c45660e | |||
4add8b2cff | |||
5afb60e7c4 | |||
35e50cf551 | |||
066a25bfee | |||
0d63a6c4e9 | |||
e82d20bfd7 | |||
a3d4390a19 | |||
f3208f1735 | |||
c5c298d708 | |||
1ae07cc14f | |||
37c09df932 | |||
92f0c81109 | |||
a8c961f7bc | |||
2c7fc66423 | |||
1a8dbe7f87 | |||
89bfa33d1e | |||
6dd9fc8328 | |||
d27134677d | |||
f8ccdf7eeb | |||
883db8840c | |||
06ddbd0f98 | |||
34d2f5e8ab | |||
285c819d31 | |||
2744f86c66 | |||
91f77ee477 | |||
caaa51774c | |||
dede8d4929 | |||
df2e7a9370 | |||
048f79e1ae | |||
2af993630a | |||
24620d485e | |||
6ab3ee3dc3 | |||
639e5a952d | |||
c69f071958 | |||
8434bdef04 | |||
8be6e3b3e8 | |||
ae157a9243 | |||
5247eda305 | |||
f146cf3281 | |||
f2201c9575 | |||
7da26947d7 | |||
3818bf5595 | |||
8839cf07c2 | |||
af93dbb3a1 | |||
46ed69ef6e | |||
e646f97890 | |||
778aa5e187 | |||
06de614588 | |||
408a32f781 | |||
461d8d4ca0 | |||
66739bc306 | |||
bca68f33ff | |||
68ca47d644 | |||
f39c1deff4 | |||
c8379eeb38 | |||
1acdebd6e7 | |||
1ee5fd9dc5 | |||
dfd41250e5 | |||
db2687f75f | |||
2612d63414 | |||
722b41aa10 | |||
93c867558a | |||
0d05960102 | |||
1d3293a55f | |||
fbdd4e369e | |||
d11c67615c | |||
99ba0d430b | |||
5dcead4e5d | |||
e07156ac30 | |||
db1d2362c8 | |||
0989aadbf4 | |||
23cb327e1b | |||
7eafd33b33 | |||
0c7d428aa6 | |||
08df06dc2e | |||
65f9e3e43e | |||
e14bc5c2bd | |||
4e22bfec4a | |||
745c8f9080 | |||
650966c195 | |||
4e382f0633 | |||
e0f11b7c02 | |||
38bda1920d | |||
56fae48277 | |||
357e9f4a7e | |||
ea00266626 | |||
8e20e747a5 | |||
d67c5c438b | |||
00a1313235 | |||
5cc62ccabd | |||
c6852e5af6 | |||
502e1e8279 | |||
4d8e41b4a3 | |||
eae26f6388 | |||
bd23185ca3 | |||
4ccf16411c | |||
d6e6d06d39 | |||
ff642a2c0c | |||
8d3d1ac427 | |||
1819541a21 | |||
5e969986fb | |||
c0a2a8a2f9 | |||
c6b986ad1b | |||
1e68e3d40a | |||
21b1eef3d3 | |||
dab931cadb | |||
1d8a1dc275 | |||
665bf8159b | |||
03a1744f87 | |||
11b38eaa4c | |||
22c4f362fe | |||
0956f40e42 | |||
3e9060c6a7 | |||
909b453036 | |||
11ba482e73 | |||
6809a4fca3 | |||
eeb75c101f | |||
891b660824 | |||
b60be9c39e | |||
ac96b0467b |
2
hub/.gitignore → .gitignore
vendored
2
hub/.gitignore → .gitignore
vendored
|
@ -9,4 +9,4 @@
|
||||||
**/hub/logs/
|
**/hub/logs/
|
||||||
**/__pycache__/
|
**/__pycache__/
|
||||||
**/.idea/
|
**/.idea/
|
||||||
|
cerc_hub.egg-info
|
50
hub/LINUX_INSTALL.md
Normal file
50
hub/LINUX_INSTALL.md
Normal 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.
|
|
@ -1,20 +1,16 @@
|
||||||
# Functions and usages internally recognized within the hub
|
# Functions and usages internally recognized within the hub
|
||||||
|
|
||||||
The hub uses a list of building functions a building usages that are the only ones recognized. All new categories should be added to the dictionaries that translate from the input formats to the libs functions. From the libs functions to the libs usages and from the libs usages and libs functions to the output formats.
|
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.
|
||||||
|
|
||||||
Input formats accepted:
|
|
||||||
* Function:
|
|
||||||
* pluto
|
|
||||||
* hft
|
|
||||||
|
|
||||||
Output formats accepted:
|
Output formats accepted:
|
||||||
* Function:
|
* Function:
|
||||||
* nrel
|
* nrel
|
||||||
* nrcan
|
* nrcan
|
||||||
|
* eilat
|
||||||
* Usage:
|
* Usage:
|
||||||
* ca
|
* nrcan
|
||||||
* hft
|
|
||||||
* comnet
|
* comnet
|
||||||
|
* eilat
|
||||||
|
|
||||||
Libs_functions:
|
Libs_functions:
|
||||||
* single family house
|
* single family house
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
This is an installation guide for Windows, covering all the steps needed to begin developing code for the Urban
|
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,
|
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.
|
set up your own project on CERC's Gitea and created your first python file.
|
||||||
|
|
||||||
## Prepare your environment
|
## Prepare your environment
|
||||||
g
|
|
||||||
To develop any new code for the Urban Simulation Platform you must have the right software applications installed and configured.
|
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:
|
The Platform is written in python and so the applications you need are:
|
||||||
* Miniconda
|
* Miniconda
|
||||||
|
* SRA Files
|
||||||
* Python Editor
|
* Python Editor
|
||||||
|
|
||||||
You also need to register a user account with the CERC's code repository on Gitlab and have the necessary permissions for
|
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
|
creating new code. For that purpose, please, contact Guillermo (guillermo.gutierrezmorote@concordia.ca) or
|
||||||
Koa (kekoa.wells@concordia.ca) as soon as possible.
|
Koa (kekoa.wells@concordia.ca) as soon as possible.
|
||||||
|
|
||||||
|
@ -47,6 +47,29 @@ _The term '...' is not recognized as the name of a cmdlet, function,..._
|
||||||
|
|
||||||
To solve it, type 'Set-ExecutionPolicy Unrestricted' as shown in the image.
|
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
|
### 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.
|
1. You will need a python editor in order to import the existing Hub source code and to write your own python code.
|
||||||
|
@ -55,7 +78,7 @@ an excellent open-source python editor.
|
||||||
2. Run the installer, and follow the installation instructions for PyCharm, you may change a few options,
|
2. Run the installer, and follow the installation instructions for PyCharm, you may change a few options,
|
||||||
but the default ones should be fine.
|
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.
|
**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)
|
![creating_virtual_environment](docs/img_windows_install/img_31.png)
|
||||||
|
|
||||||
|
@ -70,14 +93,12 @@ You can find it also at **Git->Clone...**
|
||||||
|
|
||||||
![pycharm get from version control](docs/img_windows_install/img_6.png)
|
![pycharm get from version control](docs/img_windows_install/img_6.png)
|
||||||
|
|
||||||
3. Select **Git** as the **Version control**. For the URL use the link to the Hub repository, as seen below.
|
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)
|
![pycharm get from version control screen](docs/img_windows_install/img_1.png)
|
||||||
|
|
||||||
(You can also copy this URL by going to the Hub repository in [Gitlab](https://rs-loy-gitlab.concordia.ca/Guille/hub.git)
|
![gitea get https](docs/img_windows_install/img_39.png)
|
||||||
and clicking on the **Copy URL** button, next to **Clone with HTTPS**)
|
|
||||||
|
|
||||||
![gitlab get https](docs/img_windows_install/img_17.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.
|
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.
|
||||||
|
|
||||||
|
@ -152,7 +173,7 @@ _lca_classes_,... And, click on the **Create** button.
|
||||||
3. Click on the **Git** button in the bottom-left corner to pop-up the window showing the Git information.
|
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_.
|
See your new branch has been created under _Local_.
|
||||||
|
|
||||||
4. Now we need to let the CERC Gitlab repository know about this new branch. You do this by right-clicking on
|
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.
|
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.
|
5. Then click on the **Push** button at the bottom-right of the **Push Commits** window.
|
||||||
|
@ -180,33 +201,35 @@ See the picture below.
|
||||||
|
|
||||||
![pycharm configuration screen](docs/img_windows_install/img_5.png)
|
![pycharm configuration screen](docs/img_windows_install/img_5.png)
|
||||||
|
|
||||||
## Set up a new project on Gitlab
|
## 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 to the [CERC Git](https://rs-loy-gitlab.concordia.ca/). Click on the blue **New project** button.
|
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_14.png)
|
![git new project screen](docs/img_windows_install/img_37.png)
|
||||||
|
|
||||||
2. Choose the **Create blank project** option from the three options seen below.
|
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_...
|
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)).
|
(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**.
|
Ideally, uncheck the option **Make Repository Private**, and check the **Initialize Repository**
|
||||||
Then click on the **Create project** button.
|
Then click on the **Create project** button.
|
||||||
|
|
||||||
![git give a name](docs/img_windows_install/img_15.png)
|
![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.
|
You should then see a confirmation screen with all the information about your new project.
|
||||||
|
|
||||||
## Get your project into Pycharm
|
## 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
|
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.
|
||||||
and then click on the **Copy URL** button, next to the **Clone with HTTPS** link.
|
|
||||||
|
|
||||||
2. Switch back to PyCharm and close the Hub project by choosing **File->Close Project**. You will then see the
|
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.
|
**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_
|
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.
|
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
|
4. Select **File->Settings** to open the **Settings** window. From the panel on the left click on
|
||||||
**Project:<project name> -> Project Structure**.
|
**Project:<project name> -> Project Structure**.
|
||||||
|
@ -242,5 +265,5 @@ 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!
|
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.
|
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).
|
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.
|
Once the conflicts are solved and the merge in local is done, push the changes by clicking on the green arrow.
|
||||||
|
|
0
hub/catalog_factories/__init__.py
Normal file
0
hub/catalog_factories/__init__.py
Normal file
|
@ -8,7 +8,7 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
|
||||||
class Catalog:
|
class Catalog:
|
||||||
"""
|
"""
|
||||||
Catalogs base class not implemented instance of the Catalog base class,
|
Catalogs base class
|
||||||
catalog_factories will inherit from this class.
|
catalog_factories will inherit from this class.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
0
hub/catalog_factories/construction/__init__.py
Normal file
0
hub/catalog_factories/construction/__init__.py
Normal file
|
@ -1,3 +1,9 @@
|
||||||
|
"""
|
||||||
|
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
|
from hub.helpers import constants as cte
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,12 +40,24 @@ class ConstructionHelper:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reference_standard_to_construction_period(self):
|
def reference_standard_to_construction_period(self):
|
||||||
|
"""
|
||||||
|
Get reference standard to construction period dictionary
|
||||||
|
:return: {}
|
||||||
|
"""
|
||||||
return self._reference_standard_to_construction_period
|
return self._reference_standard_to_construction_period
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nrel_surfaces_types_to_hub_types(self):
|
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
|
return self._nrel_surfaces_types_to_hub_types
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nrcan_surfaces_types_to_hub_types(self):
|
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
|
return self._nrcan_surfaces_types_to_hub_types
|
||||||
|
|
238
hub/catalog_factories/construction/eilat_catalog.py
Normal file
238
hub/catalog_factories/construction/eilat_catalog.py
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
"""
|
||||||
|
Eilat construction catalog
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2023 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
from hub.catalog_factories.catalog import Catalog
|
||||||
|
from hub.catalog_factories.data_models.construction.content import Content
|
||||||
|
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
|
||||||
|
from hub.catalog_factories.data_models.construction.construction import Construction
|
||||||
|
from hub.catalog_factories.data_models.construction.archetype import Archetype
|
||||||
|
from hub.catalog_factories.data_models.construction.window import Window
|
||||||
|
from hub.catalog_factories.data_models.construction.material import Material
|
||||||
|
from hub.catalog_factories.data_models.construction.layer import Layer
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
|
class EilatCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Eilat catalog class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
_path_archetypes = Path(path / 'eilat_archetypes.json').resolve()
|
||||||
|
_path_constructions = (path / 'eilat_constructions.json').resolve()
|
||||||
|
with open(_path_archetypes, 'r', encoding='utf-8') as file:
|
||||||
|
self._archetypes = json.load(file)
|
||||||
|
with open(_path_constructions, 'r', encoding='utf-8') as file:
|
||||||
|
self._constructions = json.load(file)
|
||||||
|
|
||||||
|
self._catalog_windows = self._load_windows()
|
||||||
|
self._catalog_materials = self._load_materials()
|
||||||
|
self._catalog_constructions = self._load_constructions()
|
||||||
|
self._catalog_archetypes = self._load_archetypes()
|
||||||
|
|
||||||
|
# store the full catalog data model in self._content
|
||||||
|
self._content = Content(self._catalog_archetypes,
|
||||||
|
self._catalog_constructions,
|
||||||
|
self._catalog_materials,
|
||||||
|
self._catalog_windows)
|
||||||
|
|
||||||
|
def _load_windows(self):
|
||||||
|
_catalog_windows = []
|
||||||
|
windows = self._constructions['transparent_surfaces']
|
||||||
|
for window in windows:
|
||||||
|
name = list(window.keys())[0]
|
||||||
|
window_id = name
|
||||||
|
g_value = window[name]['shgc']
|
||||||
|
window_type = window[name]['type']
|
||||||
|
frame_ratio = window[name]['frame_ratio']
|
||||||
|
overall_u_value = window[name]['u_value']
|
||||||
|
_catalog_windows.append(Window(window_id, frame_ratio, g_value, overall_u_value, name, window_type))
|
||||||
|
return _catalog_windows
|
||||||
|
|
||||||
|
def _load_materials(self):
|
||||||
|
_catalog_materials = []
|
||||||
|
materials = self._constructions['materials']
|
||||||
|
for material in materials:
|
||||||
|
name = list(material.keys())[0]
|
||||||
|
material_id = name
|
||||||
|
no_mass = material[name]['no_mass']
|
||||||
|
thermal_resistance = None
|
||||||
|
conductivity = None
|
||||||
|
density = None
|
||||||
|
specific_heat = None
|
||||||
|
solar_absorptance = None
|
||||||
|
thermal_absorptance = None
|
||||||
|
visible_absorptance = None
|
||||||
|
if no_mass:
|
||||||
|
thermal_resistance = material[name]['thermal_resistance']
|
||||||
|
else:
|
||||||
|
solar_absorptance = material[name]['solar_absorptance']
|
||||||
|
thermal_absorptance = str(1 - float(material[name]['thermal_emittance']))
|
||||||
|
visible_absorptance = material[name]['visible_absorptance']
|
||||||
|
conductivity = material[name]['conductivity']
|
||||||
|
density = material[name]['density']
|
||||||
|
specific_heat = material[name]['specific_heat']
|
||||||
|
_material = Material(material_id,
|
||||||
|
name,
|
||||||
|
solar_absorptance,
|
||||||
|
thermal_absorptance,
|
||||||
|
visible_absorptance,
|
||||||
|
no_mass,
|
||||||
|
thermal_resistance,
|
||||||
|
conductivity,
|
||||||
|
density,
|
||||||
|
specific_heat)
|
||||||
|
_catalog_materials.append(_material)
|
||||||
|
return _catalog_materials
|
||||||
|
|
||||||
|
def _load_constructions(self):
|
||||||
|
_catalog_constructions = []
|
||||||
|
constructions = self._constructions['opaque_surfaces']
|
||||||
|
for construction in constructions:
|
||||||
|
name = list(construction.keys())[0]
|
||||||
|
construction_id = name
|
||||||
|
construction_type = ConstructionHelper().nrcan_surfaces_types_to_hub_types[construction[name]['type']]
|
||||||
|
layers = []
|
||||||
|
for layer in construction[name]['layers']:
|
||||||
|
layer_id = layer
|
||||||
|
layer_name = layer
|
||||||
|
material_id = layer
|
||||||
|
thickness = construction[name]['layers'][layer]
|
||||||
|
for material in self._catalog_materials:
|
||||||
|
if str(material_id) == str(material.id):
|
||||||
|
layers.append(Layer(layer_id, layer_name, material, thickness))
|
||||||
|
break
|
||||||
|
_catalog_constructions.append(Construction(construction_id, construction_type, name, layers))
|
||||||
|
return _catalog_constructions
|
||||||
|
|
||||||
|
def _load_archetypes(self):
|
||||||
|
_catalog_archetypes = []
|
||||||
|
archetypes = self._archetypes['archetypes']
|
||||||
|
for archetype in archetypes:
|
||||||
|
archetype_id = f'{archetype["function"]}_{archetype["period_of_construction"]}_{archetype["climate_zone"]}'
|
||||||
|
function = archetype['function']
|
||||||
|
name = archetype_id
|
||||||
|
climate_zone = archetype['climate_zone']
|
||||||
|
construction_period = archetype['period_of_construction']
|
||||||
|
average_storey_height = archetype['average_storey_height']
|
||||||
|
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges']
|
||||||
|
infiltration_rate_for_ventilation_system_off = archetype[
|
||||||
|
'infiltration_rate_for_ventilation_system_off'] / cte.HOUR_TO_SECONDS
|
||||||
|
infiltration_rate_for_ventilation_system_on = archetype[
|
||||||
|
'infiltration_rate_for_ventilation_system_on'] / cte.HOUR_TO_SECONDS
|
||||||
|
|
||||||
|
archetype_constructions = []
|
||||||
|
for archetype_construction in archetype['constructions']:
|
||||||
|
archetype_construction_type = ConstructionHelper().nrcan_surfaces_types_to_hub_types[archetype_construction]
|
||||||
|
archetype_construction_name = archetype['constructions'][archetype_construction]['opaque_surface_name']
|
||||||
|
for construction in self._catalog_constructions:
|
||||||
|
if archetype_construction_type == construction.type and construction.name == archetype_construction_name:
|
||||||
|
_construction = None
|
||||||
|
_window = None
|
||||||
|
_window_ratio = None
|
||||||
|
if 'transparent_surface_name' in archetype['constructions'][archetype_construction].keys():
|
||||||
|
_window_ratio = archetype['constructions'][archetype_construction]['transparent_ratio']
|
||||||
|
_window_id = archetype['constructions'][archetype_construction]['transparent_surface_name']
|
||||||
|
for window in self._catalog_windows:
|
||||||
|
if _window_id == window.id:
|
||||||
|
_window = window
|
||||||
|
break
|
||||||
|
_construction = Construction(construction.id,
|
||||||
|
construction.type,
|
||||||
|
construction.name,
|
||||||
|
construction.layers,
|
||||||
|
_window_ratio,
|
||||||
|
_window)
|
||||||
|
archetype_constructions.append(_construction)
|
||||||
|
break
|
||||||
|
|
||||||
|
_catalog_archetypes.append(Archetype(archetype_id,
|
||||||
|
name,
|
||||||
|
function,
|
||||||
|
climate_zone,
|
||||||
|
construction_period,
|
||||||
|
archetype_constructions,
|
||||||
|
average_storey_height,
|
||||||
|
None,
|
||||||
|
extra_loses_due_to_thermal_bridges,
|
||||||
|
None,
|
||||||
|
infiltration_rate_for_ventilation_system_off,
|
||||||
|
infiltration_rate_for_ventilation_system_on,
|
||||||
|
0,
|
||||||
|
0))
|
||||||
|
return _catalog_archetypes
|
||||||
|
|
||||||
|
def names(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements names
|
||||||
|
:parm: optional category filter
|
||||||
|
"""
|
||||||
|
if category is None:
|
||||||
|
_names = {'archetypes': [], 'constructions': [], 'materials': [], 'windows': []}
|
||||||
|
for archetype in self._content.archetypes:
|
||||||
|
_names['archetypes'].append(archetype.name)
|
||||||
|
for construction in self._content.constructions:
|
||||||
|
_names['constructions'].append(construction.name)
|
||||||
|
for material in self._content.materials:
|
||||||
|
_names['materials'].append(material.name)
|
||||||
|
for window in self._content.windows:
|
||||||
|
_names['windows'].append(window.name)
|
||||||
|
else:
|
||||||
|
_names = {category: []}
|
||||||
|
if category.lower() == 'archetypes':
|
||||||
|
for archetype in self._content.archetypes:
|
||||||
|
_names[category].append(archetype.name)
|
||||||
|
elif category.lower() == 'constructions':
|
||||||
|
for construction in self._content.constructions:
|
||||||
|
_names[category].append(construction.name)
|
||||||
|
elif category.lower() == 'materials':
|
||||||
|
for material in self._content.materials:
|
||||||
|
_names[category].append(material.name)
|
||||||
|
elif category.lower() == 'windows':
|
||||||
|
for window in self._content.windows:
|
||||||
|
_names[category].append(window.name)
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
|
return _names
|
||||||
|
|
||||||
|
def entries(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements
|
||||||
|
:parm: optional category filter
|
||||||
|
"""
|
||||||
|
if category is None:
|
||||||
|
return self._content
|
||||||
|
if category.lower() == 'archetypes':
|
||||||
|
return self._content.archetypes
|
||||||
|
if category.lower() == 'constructions':
|
||||||
|
return self._content.constructions
|
||||||
|
if category.lower() == 'materials':
|
||||||
|
return self._content.materials
|
||||||
|
if category.lower() == 'windows':
|
||||||
|
return self._content.windows
|
||||||
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
|
|
||||||
|
def get_entry(self, name):
|
||||||
|
"""
|
||||||
|
Get one catalog element by names
|
||||||
|
:parm: entry name
|
||||||
|
"""
|
||||||
|
for entry in self._content.archetypes:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.constructions:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.materials:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.windows:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -15,15 +15,19 @@ from hub.catalog_factories.data_models.construction.archetype import Archetype
|
||||||
from hub.catalog_factories.data_models.construction.window import Window
|
from hub.catalog_factories.data_models.construction.window import Window
|
||||||
from hub.catalog_factories.data_models.construction.material import Material
|
from hub.catalog_factories.data_models.construction.material import Material
|
||||||
from hub.catalog_factories.data_models.construction.layer import Layer
|
from hub.catalog_factories.data_models.construction.layer import Layer
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class NrcanCatalog(Catalog):
|
class NrcanCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Nrcan catalog class
|
||||||
|
"""
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
_path_archetypes = Path(path / 'nrcan_archetypes.json').resolve()
|
_path_archetypes = Path(path / 'nrcan_archetypes.json').resolve()
|
||||||
_path_constructions = (path / 'nrcan_constructions.json')
|
_path_constructions = (path / 'nrcan_constructions.json').resolve()
|
||||||
with open(_path_archetypes, 'r') as file:
|
with open(_path_archetypes, 'r', encoding='utf-8') as file:
|
||||||
self._archetypes = json.load(file)
|
self._archetypes = json.load(file)
|
||||||
with open(_path_constructions, 'r') as file:
|
with open(_path_constructions, 'r', encoding='utf-8') as file:
|
||||||
self._constructions = json.load(file)
|
self._constructions = json.load(file)
|
||||||
|
|
||||||
self._catalog_windows = self._load_windows()
|
self._catalog_windows = self._load_windows()
|
||||||
|
@ -118,8 +122,18 @@ class NrcanCatalog(Catalog):
|
||||||
average_storey_height = archetype['average_storey_height']
|
average_storey_height = archetype['average_storey_height']
|
||||||
thermal_capacity = float(archetype['thermal_capacity']) * 1000
|
thermal_capacity = float(archetype['thermal_capacity']) * 1000
|
||||||
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges']
|
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges']
|
||||||
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off']
|
infiltration_rate_for_ventilation_system_off = (
|
||||||
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on']
|
archetype['infiltration_rate_for_ventilation_system_off'] / cte.HOUR_TO_SECONDS
|
||||||
|
)
|
||||||
|
infiltration_rate_for_ventilation_system_on = (
|
||||||
|
archetype['infiltration_rate_for_ventilation_system_on'] / cte.HOUR_TO_SECONDS
|
||||||
|
)
|
||||||
|
infiltration_rate_area_for_ventilation_system_off = (
|
||||||
|
archetype['infiltration_rate_area_for_ventilation_system_off'] * 1
|
||||||
|
)
|
||||||
|
infiltration_rate_area_for_ventilation_system_on = (
|
||||||
|
archetype['infiltration_rate_area_for_ventilation_system_on'] * 1
|
||||||
|
)
|
||||||
|
|
||||||
archetype_constructions = []
|
archetype_constructions = []
|
||||||
for archetype_construction in archetype['constructions']:
|
for archetype_construction in archetype['constructions']:
|
||||||
|
@ -145,7 +159,6 @@ class NrcanCatalog(Catalog):
|
||||||
_window)
|
_window)
|
||||||
archetype_constructions.append(_construction)
|
archetype_constructions.append(_construction)
|
||||||
break
|
break
|
||||||
|
|
||||||
_catalog_archetypes.append(Archetype(archetype_id,
|
_catalog_archetypes.append(Archetype(archetype_id,
|
||||||
name,
|
name,
|
||||||
function,
|
function,
|
||||||
|
@ -157,7 +170,10 @@ class NrcanCatalog(Catalog):
|
||||||
extra_loses_due_to_thermal_bridges,
|
extra_loses_due_to_thermal_bridges,
|
||||||
None,
|
None,
|
||||||
infiltration_rate_for_ventilation_system_off,
|
infiltration_rate_for_ventilation_system_off,
|
||||||
infiltration_rate_for_ventilation_system_on))
|
infiltration_rate_for_ventilation_system_on,
|
||||||
|
infiltration_rate_area_for_ventilation_system_off,
|
||||||
|
infiltration_rate_area_for_ventilation_system_on
|
||||||
|
))
|
||||||
return _catalog_archetypes
|
return _catalog_archetypes
|
||||||
|
|
||||||
def names(self, category=None):
|
def names(self, category=None):
|
||||||
|
@ -200,17 +216,15 @@ class NrcanCatalog(Catalog):
|
||||||
"""
|
"""
|
||||||
if category is None:
|
if category is None:
|
||||||
return self._content
|
return self._content
|
||||||
else:
|
if category.lower() == 'archetypes':
|
||||||
if category.lower() == 'archetypes':
|
return self._content.archetypes
|
||||||
return self._content.archetypes
|
if category.lower() == 'constructions':
|
||||||
elif category.lower() == 'constructions':
|
return self._content.constructions
|
||||||
return self._content.constructions
|
if category.lower() == 'materials':
|
||||||
elif category.lower() == 'materials':
|
return self._content.materials
|
||||||
return self._content.materials
|
if category.lower() == 'windows':
|
||||||
elif category.lower() == 'windows':
|
return self._content.windows
|
||||||
return self._content.windows
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
else:
|
|
||||||
raise ValueError(f'Unknown category [{category}]')
|
|
||||||
|
|
||||||
def get_entry(self, name):
|
def get_entry(self, name):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,8 +5,8 @@ Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import xmltodict
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import xmltodict
|
||||||
from hub.catalog_factories.catalog import Catalog
|
from hub.catalog_factories.catalog import Catalog
|
||||||
from hub.catalog_factories.data_models.construction.window import Window
|
from hub.catalog_factories.data_models.construction.window import Window
|
||||||
from hub.catalog_factories.data_models.construction.material import Material
|
from hub.catalog_factories.data_models.construction.material import Material
|
||||||
|
@ -15,15 +15,19 @@ from hub.catalog_factories.data_models.construction.construction import Construc
|
||||||
from hub.catalog_factories.data_models.construction.content import Content
|
from hub.catalog_factories.data_models.construction.content import Content
|
||||||
from hub.catalog_factories.data_models.construction.archetype import Archetype
|
from hub.catalog_factories.data_models.construction.archetype import Archetype
|
||||||
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
|
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class NrelCatalog(Catalog):
|
class NrelCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Nrel catalog class
|
||||||
|
"""
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
archetypes_path = str(Path(path / 'us_archetypes.xml').resolve())
|
archetypes_path = str(Path(path / 'us_archetypes.xml').resolve())
|
||||||
constructions_path = str(Path(path / 'us_constructions.xml').resolve())
|
constructions_path = str(Path(path / 'us_constructions.xml').resolve())
|
||||||
with open(constructions_path) as xml:
|
with open(constructions_path, 'r', encoding='utf-8') as xml:
|
||||||
self._constructions = xmltodict.parse(xml.read(), force_list=('material', 'window', 'construction', 'layer'))
|
self._constructions = xmltodict.parse(xml.read(), force_list=('material', 'window', 'construction', 'layer'))
|
||||||
with open(archetypes_path) as xml:
|
with open(archetypes_path, 'r', encoding='utf-8') as xml:
|
||||||
self._archetypes = xmltodict.parse(xml.read(), force_list=('archetype', 'construction'))
|
self._archetypes = xmltodict.parse(xml.read(), force_list=('archetype', 'construction'))
|
||||||
self._catalog_windows = self._load_windows()
|
self._catalog_windows = self._load_windows()
|
||||||
self._catalog_materials = self._load_materials()
|
self._catalog_materials = self._load_materials()
|
||||||
|
@ -58,9 +62,9 @@ class NrelCatalog(Catalog):
|
||||||
thermal_absorptance = float(material['thermal_absorptance']['#text'])
|
thermal_absorptance = float(material['thermal_absorptance']['#text'])
|
||||||
visible_absorptance = float(material['visible_absorptance']['#text'])
|
visible_absorptance = float(material['visible_absorptance']['#text'])
|
||||||
no_mass = False
|
no_mass = False
|
||||||
thermal_resistance = None,
|
thermal_resistance = None
|
||||||
conductivity = None,
|
conductivity = None
|
||||||
density = None,
|
density = None
|
||||||
specific_heat = None
|
specific_heat = None
|
||||||
if 'no_mass' in material and material['no_mass'] == 'true':
|
if 'no_mass' in material and material['no_mass'] == 'true':
|
||||||
no_mass = True
|
no_mass = True
|
||||||
|
@ -121,10 +125,10 @@ class NrelCatalog(Catalog):
|
||||||
indirect_heated_ratio = float(archetype['indirect_heated_ratio']['#text'])
|
indirect_heated_ratio = float(archetype['indirect_heated_ratio']['#text'])
|
||||||
infiltration_rate_for_ventilation_system_off = float(
|
infiltration_rate_for_ventilation_system_off = float(
|
||||||
archetype['infiltration_rate_for_ventilation_system_off']['#text']
|
archetype['infiltration_rate_for_ventilation_system_off']['#text']
|
||||||
)
|
) / cte.HOUR_TO_SECONDS
|
||||||
infiltration_rate_for_ventilation_system_on = float(
|
infiltration_rate_for_ventilation_system_on = float(
|
||||||
archetype['infiltration_rate_for_ventilation_system_on']['#text']
|
archetype['infiltration_rate_for_ventilation_system_on']['#text']
|
||||||
)
|
) / cte.HOUR_TO_SECONDS
|
||||||
|
|
||||||
archetype_constructions = []
|
archetype_constructions = []
|
||||||
for archetype_construction in archetype['constructions']['construction']:
|
for archetype_construction in archetype['constructions']['construction']:
|
||||||
|
@ -158,7 +162,9 @@ class NrelCatalog(Catalog):
|
||||||
extra_loses_due_to_thermal_bridges,
|
extra_loses_due_to_thermal_bridges,
|
||||||
indirect_heated_ratio,
|
indirect_heated_ratio,
|
||||||
infiltration_rate_for_ventilation_system_off,
|
infiltration_rate_for_ventilation_system_off,
|
||||||
infiltration_rate_for_ventilation_system_on))
|
infiltration_rate_for_ventilation_system_on,
|
||||||
|
0,
|
||||||
|
0))
|
||||||
return _catalog_archetypes
|
return _catalog_archetypes
|
||||||
|
|
||||||
def names(self, category=None):
|
def names(self, category=None):
|
||||||
|
@ -201,17 +207,15 @@ class NrelCatalog(Catalog):
|
||||||
"""
|
"""
|
||||||
if category is None:
|
if category is None:
|
||||||
return self._content
|
return self._content
|
||||||
else:
|
if category.lower() == 'archetypes':
|
||||||
if category.lower() == 'archetypes':
|
return self._content.archetypes
|
||||||
return self._content.archetypes
|
if category.lower() == 'constructions':
|
||||||
elif category.lower() == 'constructions':
|
return self._content.constructions
|
||||||
return self._content.constructions
|
if category.lower() == 'materials':
|
||||||
elif category.lower() == 'materials':
|
return self._content.materials
|
||||||
return self._content.materials
|
if category.lower() == 'windows':
|
||||||
elif category.lower() == 'windows':
|
return self._content.windows
|
||||||
return self._content.windows
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
else:
|
|
||||||
raise ValueError(f'Unknown category [{category}]')
|
|
||||||
|
|
||||||
def get_entry(self, name):
|
def get_entry(self, name):
|
||||||
"""
|
"""
|
||||||
|
|
242
hub/catalog_factories/construction/palma_catalog.py
Normal file
242
hub/catalog_factories/construction/palma_catalog.py
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
"""
|
||||||
|
Palma construction catalog
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2023 Concordia CERC group
|
||||||
|
Project Coder Cecilia Pérez Pérez cperez@irec.cat
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
from hub.catalog_factories.catalog import Catalog
|
||||||
|
from hub.catalog_factories.data_models.construction.content import Content
|
||||||
|
from hub.catalog_factories.construction.construction_helper import ConstructionHelper
|
||||||
|
from hub.catalog_factories.data_models.construction.construction import Construction
|
||||||
|
from hub.catalog_factories.data_models.construction.archetype import Archetype
|
||||||
|
from hub.catalog_factories.data_models.construction.window import Window
|
||||||
|
from hub.catalog_factories.data_models.construction.material import Material
|
||||||
|
from hub.catalog_factories.data_models.construction.layer import Layer
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
|
class PalmaCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Palma catalog class
|
||||||
|
"""
|
||||||
|
def __init__(self, path):
|
||||||
|
_path_archetypes = Path(path / 'palma_archetypes.json').resolve()
|
||||||
|
_path_constructions = (path / 'palma_constructions.json').resolve()
|
||||||
|
with open(_path_archetypes, 'r', encoding='utf-8') as file:
|
||||||
|
self._archetypes = json.load(file)
|
||||||
|
with open(_path_constructions, 'r', encoding='utf-8') as file:
|
||||||
|
self._constructions = json.load(file)
|
||||||
|
|
||||||
|
self._catalog_windows = self._load_windows()
|
||||||
|
self._catalog_materials = self._load_materials()
|
||||||
|
self._catalog_constructions = self._load_constructions()
|
||||||
|
self._catalog_archetypes = self._load_archetypes()
|
||||||
|
|
||||||
|
# store the full catalog data model in self._content
|
||||||
|
self._content = Content(self._catalog_archetypes,
|
||||||
|
self._catalog_constructions,
|
||||||
|
self._catalog_materials,
|
||||||
|
self._catalog_windows)
|
||||||
|
|
||||||
|
def _load_windows(self):
|
||||||
|
_catalog_windows = []
|
||||||
|
windows = self._constructions['transparent_surfaces']
|
||||||
|
for window in windows:
|
||||||
|
name = list(window.keys())[0]
|
||||||
|
window_id = name
|
||||||
|
g_value = window[name]['shgc']
|
||||||
|
window_type = window[name]['type']
|
||||||
|
frame_ratio = window[name]['frame_ratio']
|
||||||
|
overall_u_value = window[name]['u_value']
|
||||||
|
_catalog_windows.append(Window(window_id, frame_ratio, g_value, overall_u_value, name, window_type))
|
||||||
|
return _catalog_windows
|
||||||
|
|
||||||
|
def _load_materials(self):
|
||||||
|
_catalog_materials = []
|
||||||
|
materials = self._constructions['materials']
|
||||||
|
for material in materials:
|
||||||
|
name = list(material.keys())[0]
|
||||||
|
material_id = name
|
||||||
|
no_mass = material[name]['no_mass']
|
||||||
|
thermal_resistance = None
|
||||||
|
conductivity = None
|
||||||
|
density = None
|
||||||
|
specific_heat = None
|
||||||
|
solar_absorptance = None
|
||||||
|
thermal_absorptance = None
|
||||||
|
visible_absorptance = None
|
||||||
|
if no_mass:
|
||||||
|
thermal_resistance = material[name]['thermal_resistance']
|
||||||
|
else:
|
||||||
|
solar_absorptance = material[name]['solar_absorptance']
|
||||||
|
thermal_absorptance = str(1 - float(material[name]['thermal_emittance']))
|
||||||
|
visible_absorptance = material[name]['visible_absorptance']
|
||||||
|
conductivity = material[name]['conductivity']
|
||||||
|
density = material[name]['density']
|
||||||
|
specific_heat = material[name]['specific_heat']
|
||||||
|
_material = Material(material_id,
|
||||||
|
name,
|
||||||
|
solar_absorptance,
|
||||||
|
thermal_absorptance,
|
||||||
|
visible_absorptance,
|
||||||
|
no_mass,
|
||||||
|
thermal_resistance,
|
||||||
|
conductivity,
|
||||||
|
density,
|
||||||
|
specific_heat)
|
||||||
|
_catalog_materials.append(_material)
|
||||||
|
return _catalog_materials
|
||||||
|
|
||||||
|
def _load_constructions(self):
|
||||||
|
_catalog_constructions = []
|
||||||
|
constructions = self._constructions['opaque_surfaces']
|
||||||
|
for construction in constructions:
|
||||||
|
name = list(construction.keys())[0]
|
||||||
|
construction_id = name
|
||||||
|
construction_type = ConstructionHelper().nrcan_surfaces_types_to_hub_types[construction[name]['type']]
|
||||||
|
layers = []
|
||||||
|
for layer in construction[name]['layers']:
|
||||||
|
layer_id = layer
|
||||||
|
layer_name = layer
|
||||||
|
material_id = layer
|
||||||
|
thickness = construction[name]['layers'][layer]
|
||||||
|
for material in self._catalog_materials:
|
||||||
|
if str(material_id) == str(material.id):
|
||||||
|
layers.append(Layer(layer_id, layer_name, material, thickness))
|
||||||
|
break
|
||||||
|
_catalog_constructions.append(Construction(construction_id, construction_type, name, layers))
|
||||||
|
return _catalog_constructions
|
||||||
|
|
||||||
|
def _load_archetypes(self):
|
||||||
|
_catalog_archetypes = []
|
||||||
|
archetypes = self._archetypes['archetypes']
|
||||||
|
for archetype in archetypes:
|
||||||
|
archetype_id = f'{archetype["function"]}_{archetype["period_of_construction"]}_{archetype["climate_zone"]}'
|
||||||
|
function = archetype['function']
|
||||||
|
name = archetype_id
|
||||||
|
climate_zone = archetype['climate_zone']
|
||||||
|
construction_period = archetype['period_of_construction']
|
||||||
|
average_storey_height = archetype['average_storey_height']
|
||||||
|
thermal_capacity = float(archetype['thermal_capacity']) * 1000
|
||||||
|
extra_loses_due_to_thermal_bridges = archetype['extra_loses_due_thermal_bridges']
|
||||||
|
infiltration_rate_for_ventilation_system_off = archetype['infiltration_rate_for_ventilation_system_off'] / cte.HOUR_TO_SECONDS
|
||||||
|
infiltration_rate_for_ventilation_system_on = archetype['infiltration_rate_for_ventilation_system_on'] / cte.HOUR_TO_SECONDS
|
||||||
|
infiltration_rate_area_for_ventilation_system_off = (
|
||||||
|
archetype['infiltration_rate_area_for_ventilation_system_off'] * 1
|
||||||
|
)
|
||||||
|
infiltration_rate_area_for_ventilation_system_on = (
|
||||||
|
archetype['infiltration_rate_area_for_ventilation_system_on'] * 1
|
||||||
|
)
|
||||||
|
|
||||||
|
archetype_constructions = []
|
||||||
|
for archetype_construction in archetype['constructions']:
|
||||||
|
archetype_construction_type = ConstructionHelper().nrcan_surfaces_types_to_hub_types[archetype_construction]
|
||||||
|
archetype_construction_name = archetype['constructions'][archetype_construction]['opaque_surface_name']
|
||||||
|
for construction in self._catalog_constructions:
|
||||||
|
if archetype_construction_type == construction.type and construction.name == archetype_construction_name:
|
||||||
|
_construction = None
|
||||||
|
_window = None
|
||||||
|
_window_ratio = None
|
||||||
|
if 'transparent_surface_name' in archetype['constructions'][archetype_construction].keys():
|
||||||
|
_window_ratio = archetype['constructions'][archetype_construction]['transparent_ratio']
|
||||||
|
_window_id = archetype['constructions'][archetype_construction]['transparent_surface_name']
|
||||||
|
for window in self._catalog_windows:
|
||||||
|
if _window_id == window.id:
|
||||||
|
_window = window
|
||||||
|
break
|
||||||
|
_construction = Construction(construction.id,
|
||||||
|
construction.type,
|
||||||
|
construction.name,
|
||||||
|
construction.layers,
|
||||||
|
_window_ratio,
|
||||||
|
_window)
|
||||||
|
archetype_constructions.append(_construction)
|
||||||
|
break
|
||||||
|
|
||||||
|
_catalog_archetypes.append(Archetype(archetype_id,
|
||||||
|
name,
|
||||||
|
function,
|
||||||
|
climate_zone,
|
||||||
|
construction_period,
|
||||||
|
archetype_constructions,
|
||||||
|
average_storey_height,
|
||||||
|
thermal_capacity,
|
||||||
|
extra_loses_due_to_thermal_bridges,
|
||||||
|
None,
|
||||||
|
infiltration_rate_for_ventilation_system_off,
|
||||||
|
infiltration_rate_for_ventilation_system_on,
|
||||||
|
infiltration_rate_area_for_ventilation_system_off,
|
||||||
|
infiltration_rate_area_for_ventilation_system_on))
|
||||||
|
return _catalog_archetypes
|
||||||
|
|
||||||
|
def names(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements names
|
||||||
|
:parm: optional category filter
|
||||||
|
"""
|
||||||
|
if category is None:
|
||||||
|
_names = {'archetypes': [], 'constructions': [], 'materials': [], 'windows': []}
|
||||||
|
for archetype in self._content.archetypes:
|
||||||
|
_names['archetypes'].append(archetype.name)
|
||||||
|
for construction in self._content.constructions:
|
||||||
|
_names['constructions'].append(construction.name)
|
||||||
|
for material in self._content.materials:
|
||||||
|
_names['materials'].append(material.name)
|
||||||
|
for window in self._content.windows:
|
||||||
|
_names['windows'].append(window.name)
|
||||||
|
else:
|
||||||
|
_names = {category: []}
|
||||||
|
if category.lower() == 'archetypes':
|
||||||
|
for archetype in self._content.archetypes:
|
||||||
|
_names[category].append(archetype.name)
|
||||||
|
elif category.lower() == 'constructions':
|
||||||
|
for construction in self._content.constructions:
|
||||||
|
_names[category].append(construction.name)
|
||||||
|
elif category.lower() == 'materials':
|
||||||
|
for material in self._content.materials:
|
||||||
|
_names[category].append(material.name)
|
||||||
|
elif category.lower() == 'windows':
|
||||||
|
for window in self._content.windows:
|
||||||
|
_names[category].append(window.name)
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
|
return _names
|
||||||
|
|
||||||
|
def entries(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements
|
||||||
|
:parm: optional category filter
|
||||||
|
"""
|
||||||
|
if category is None:
|
||||||
|
return self._content
|
||||||
|
if category.lower() == 'archetypes':
|
||||||
|
return self._content.archetypes
|
||||||
|
if category.lower() == 'constructions':
|
||||||
|
return self._content.constructions
|
||||||
|
if category.lower() == 'materials':
|
||||||
|
return self._content.materials
|
||||||
|
if category.lower() == 'windows':
|
||||||
|
return self._content.windows
|
||||||
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
|
|
||||||
|
def get_entry(self, name):
|
||||||
|
"""
|
||||||
|
Get one catalog element by names
|
||||||
|
:parm: entry name
|
||||||
|
"""
|
||||||
|
for entry in self._content.archetypes:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.constructions:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.materials:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.windows:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -4,17 +4,23 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
import logging
|
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
from hub.catalog_factories.construction.nrel_catalog import NrelCatalog
|
|
||||||
from hub.helpers.utils import validate_import_export_type
|
|
||||||
from hub.catalog_factories.construction.nrcan_catalog import NrcanCatalog
|
from hub.catalog_factories.construction.nrcan_catalog import NrcanCatalog
|
||||||
|
from hub.catalog_factories.construction.nrel_catalog import NrelCatalog
|
||||||
|
from hub.catalog_factories.construction.eilat_catalog import EilatCatalog
|
||||||
|
from hub.catalog_factories.construction.palma_catalog import PalmaCatalog
|
||||||
|
from hub.helpers.utils import validate_import_export_type
|
||||||
|
|
||||||
Catalog = TypeVar('Catalog')
|
Catalog = TypeVar('Catalog')
|
||||||
|
|
||||||
|
|
||||||
class ConstructionCatalogFactory:
|
class ConstructionCatalogFactory:
|
||||||
|
"""
|
||||||
|
Construction catalog factory class
|
||||||
|
"""
|
||||||
def __init__(self, handler, base_path=None):
|
def __init__(self, handler, base_path=None):
|
||||||
if base_path is None:
|
if base_path is None:
|
||||||
base_path = Path(Path(__file__).parent.parent / 'data/construction')
|
base_path = Path(Path(__file__).parent.parent / 'data/construction')
|
||||||
|
@ -32,10 +38,24 @@ class ConstructionCatalogFactory:
|
||||||
@property
|
@property
|
||||||
def _nrcan(self):
|
def _nrcan(self):
|
||||||
"""
|
"""
|
||||||
Retrieve NREL catalog
|
Retrieve NRCAN catalog
|
||||||
"""
|
"""
|
||||||
return NrcanCatalog(self._path)
|
return NrcanCatalog(self._path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _eilat(self):
|
||||||
|
"""
|
||||||
|
Retrieve Eilat catalog
|
||||||
|
"""
|
||||||
|
return EilatCatalog(self._path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _palma(self):
|
||||||
|
"""
|
||||||
|
Retrieve Palma catalog
|
||||||
|
"""
|
||||||
|
return PalmaCatalog(self._path)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def catalog(self) -> Catalog:
|
def catalog(self) -> Catalog:
|
||||||
"""
|
"""
|
||||||
|
|
0
hub/catalog_factories/cost/__init__.py
Normal file
0
hub/catalog_factories/cost/__init__.py
Normal file
|
@ -18,9 +18,12 @@ from hub.catalog_factories.data_models.cost.income import Income
|
||||||
|
|
||||||
|
|
||||||
class MontrealCustomCatalog(Catalog):
|
class MontrealCustomCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Montreal custom catalog class
|
||||||
|
"""
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
path = (path / 'montreal_costs.xml')
|
path = (path / 'montreal_costs.xml').resolve()
|
||||||
with open(path) as xml:
|
with open(path, 'r', encoding='utf-8') as xml:
|
||||||
self._archetypes = xmltodict.parse(xml.read(), force_list='archetype')
|
self._archetypes = xmltodict.parse(xml.read(), force_list='archetype')
|
||||||
|
|
||||||
# store the full catalog data model in self._content
|
# store the full catalog data model in self._content
|
||||||
|
|
|
@ -13,7 +13,7 @@ from hub.catalog_factories.cost.montreal_custom_catalog import MontrealCustomCat
|
||||||
Catalog = TypeVar('Catalog')
|
Catalog = TypeVar('Catalog')
|
||||||
|
|
||||||
|
|
||||||
class CostCatalogFactory:
|
class CostsCatalogFactory:
|
||||||
"""
|
"""
|
||||||
CostsCatalogFactory class
|
CostsCatalogFactory class
|
||||||
"""
|
"""
|
||||||
|
|
0
hub/catalog_factories/data_models/__init__.py
Normal file
0
hub/catalog_factories/data_models/__init__.py
Normal file
|
@ -9,6 +9,9 @@ from hub.catalog_factories.data_models.construction.construction import Construc
|
||||||
|
|
||||||
|
|
||||||
class Archetype:
|
class Archetype:
|
||||||
|
"""
|
||||||
|
Archetype class
|
||||||
|
"""
|
||||||
def __init__(self, archetype_id,
|
def __init__(self, archetype_id,
|
||||||
name,
|
name,
|
||||||
function,
|
function,
|
||||||
|
@ -20,7 +23,10 @@ class Archetype:
|
||||||
extra_loses_due_to_thermal_bridges,
|
extra_loses_due_to_thermal_bridges,
|
||||||
indirect_heated_ratio,
|
indirect_heated_ratio,
|
||||||
infiltration_rate_for_ventilation_system_off,
|
infiltration_rate_for_ventilation_system_off,
|
||||||
infiltration_rate_for_ventilation_system_on):
|
infiltration_rate_for_ventilation_system_on,
|
||||||
|
infiltration_rate_area_for_ventilation_system_off,
|
||||||
|
infiltration_rate_area_for_ventilation_system_on
|
||||||
|
):
|
||||||
self._id = archetype_id
|
self._id = archetype_id
|
||||||
self._name = name
|
self._name = name
|
||||||
self._function = function
|
self._function = function
|
||||||
|
@ -33,6 +39,8 @@ class Archetype:
|
||||||
self._indirect_heated_ratio = indirect_heated_ratio
|
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_off = infiltration_rate_for_ventilation_system_off
|
||||||
self._infiltration_rate_for_ventilation_system_on = infiltration_rate_for_ventilation_system_on
|
self._infiltration_rate_for_ventilation_system_on = infiltration_rate_for_ventilation_system_on
|
||||||
|
self._infiltration_rate_area_for_ventilation_system_off = infiltration_rate_area_for_ventilation_system_off
|
||||||
|
self._infiltration_rate_area_for_ventilation_system_on = infiltration_rate_area_for_ventilation_system_on
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
@ -117,7 +125,7 @@ class Archetype:
|
||||||
@property
|
@property
|
||||||
def infiltration_rate_for_ventilation_system_off(self):
|
def infiltration_rate_for_ventilation_system_off(self):
|
||||||
"""
|
"""
|
||||||
Get archetype infiltration rate for ventilation system off in ACH
|
Get archetype infiltration rate for ventilation system off in 1/s
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._infiltration_rate_for_ventilation_system_off
|
return self._infiltration_rate_for_ventilation_system_off
|
||||||
|
@ -125,7 +133,46 @@ class Archetype:
|
||||||
@property
|
@property
|
||||||
def infiltration_rate_for_ventilation_system_on(self):
|
def infiltration_rate_for_ventilation_system_on(self):
|
||||||
"""
|
"""
|
||||||
Get archetype infiltration rate for ventilation system on in ACH
|
Get archetype infiltration rate for ventilation system on in 1/s
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._infiltration_rate_for_ventilation_system_on
|
return self._infiltration_rate_for_ventilation_system_on
|
||||||
|
|
||||||
|
@property
|
||||||
|
def infiltration_rate_area_for_ventilation_system_off(self):
|
||||||
|
"""
|
||||||
|
Get archetype infiltration rate for ventilation system off in m3/sm2
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._infiltration_rate_area_for_ventilation_system_off
|
||||||
|
|
||||||
|
@property
|
||||||
|
def infiltration_rate_area_for_ventilation_system_on(self):
|
||||||
|
"""
|
||||||
|
Get archetype infiltration rate for ventilation system on in m3/sm2
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._infiltration_rate_for_ventilation_system_on
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
_constructions = []
|
||||||
|
for _construction in self.constructions:
|
||||||
|
_constructions.append(_construction.to_dictionary())
|
||||||
|
content = {'Archetype': {'id': self.id,
|
||||||
|
'name': self.name,
|
||||||
|
'function': self.function,
|
||||||
|
'climate zone': self.climate_zone,
|
||||||
|
'period of construction': self.construction_period,
|
||||||
|
'average storey height [m]': self.average_storey_height,
|
||||||
|
'thermal capacity [J/m3K]': self.thermal_capacity,
|
||||||
|
'extra loses due to thermal bridges [W/m2K]': self.extra_loses_due_to_thermal_bridges,
|
||||||
|
'indirect heated ratio': self.indirect_heated_ratio,
|
||||||
|
'infiltration rate for ventilation off [1/s]': self.infiltration_rate_for_ventilation_system_off,
|
||||||
|
'infiltration rate for ventilation on [1/s]': self.infiltration_rate_for_ventilation_system_on,
|
||||||
|
'infiltration rate area for ventilation off [m3/sm2]': self.infiltration_rate_area_for_ventilation_system_off,
|
||||||
|
'infiltration rate area for ventilation on [m3/sm2]': self.infiltration_rate_area_for_ventilation_system_on,
|
||||||
|
'constructions': _constructions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
|
|
@ -4,11 +4,15 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from hub.catalog_factories.data_models.construction.layer import Layer
|
from hub.catalog_factories.data_models.construction.layer import Layer
|
||||||
from hub.catalog_factories.data_models.construction.window import Window
|
from hub.catalog_factories.data_models.construction.window import Window
|
||||||
|
|
||||||
|
|
||||||
class Construction:
|
class Construction:
|
||||||
|
"""
|
||||||
|
Construction class
|
||||||
|
"""
|
||||||
def __init__(self, construction_id, construction_type, name, layers, window_ratio=None, window=None):
|
def __init__(self, construction_id, construction_type, name, layers, window_ratio=None, window=None):
|
||||||
self._id = construction_id
|
self._id = construction_id
|
||||||
self._type = construction_type
|
self._type = construction_type
|
||||||
|
@ -64,3 +68,21 @@ class Construction:
|
||||||
:return: Window
|
:return: Window
|
||||||
"""
|
"""
|
||||||
return self._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
|
||||||
|
|
|
@ -7,6 +7,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
|
||||||
|
|
||||||
class Content:
|
class Content:
|
||||||
|
"""
|
||||||
|
Content class
|
||||||
|
"""
|
||||||
def __init__(self, archetypes, constructions, materials, windows):
|
def __init__(self, archetypes, constructions, materials, windows):
|
||||||
self._archetypes = archetypes
|
self._archetypes = archetypes
|
||||||
self._constructions = constructions
|
self._constructions = constructions
|
||||||
|
@ -40,3 +43,21 @@ class Content:
|
||||||
All windows in the catalog
|
All windows in the catalog
|
||||||
"""
|
"""
|
||||||
return self._windows
|
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)
|
||||||
|
|
|
@ -5,8 +5,13 @@ Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from hub.catalog_factories.data_models.construction.material import Material
|
||||||
|
|
||||||
|
|
||||||
class Layer:
|
class Layer:
|
||||||
|
"""
|
||||||
|
Layer class
|
||||||
|
"""
|
||||||
def __init__(self, layer_id, name, material, thickness):
|
def __init__(self, layer_id, name, material, thickness):
|
||||||
self._id = layer_id
|
self._id = layer_id
|
||||||
self._name = name
|
self._name = name
|
||||||
|
@ -30,7 +35,7 @@ class Layer:
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def material(self):
|
def material(self) -> Material:
|
||||||
"""
|
"""
|
||||||
Get layer material
|
Get layer material
|
||||||
:return: Material
|
:return: Material
|
||||||
|
@ -44,3 +49,13 @@ class Layer:
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._thickness
|
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
|
||||||
|
|
|
@ -7,6 +7,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
|
||||||
|
|
||||||
class Material:
|
class Material:
|
||||||
|
"""
|
||||||
|
Material class
|
||||||
|
"""
|
||||||
def __init__(self, material_id,
|
def __init__(self, material_id,
|
||||||
name,
|
name,
|
||||||
solar_absorptance,
|
solar_absorptance,
|
||||||
|
@ -107,3 +110,19 @@ class Material:
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._thermal_resistance
|
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
|
||||||
|
|
|
@ -7,6 +7,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
|
||||||
|
|
||||||
class Window:
|
class Window:
|
||||||
|
"""
|
||||||
|
Window class
|
||||||
|
"""
|
||||||
def __init__(self, window_id, frame_ratio, g_value, overall_u_value, name, window_type=None):
|
def __init__(self, window_id, frame_ratio, g_value, overall_u_value, name, window_type=None):
|
||||||
self._id = window_id
|
self._id = window_id
|
||||||
self._frame_ratio = frame_ratio
|
self._frame_ratio = frame_ratio
|
||||||
|
@ -61,4 +64,16 @@ class Window:
|
||||||
Get transparent surface type, 'window' or 'skylight'
|
Get transparent surface type, 'window' or 'skylight'
|
||||||
:return: str
|
:return: str
|
||||||
"""
|
"""
|
||||||
return self.type
|
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
|
||||||
|
|
0
hub/catalog_factories/data_models/cost/__init__.py
Normal file
0
hub/catalog_factories/data_models/cost/__init__.py
Normal file
|
@ -11,6 +11,9 @@ from hub.catalog_factories.data_models.cost.income import Income
|
||||||
|
|
||||||
|
|
||||||
class Archetype:
|
class Archetype:
|
||||||
|
"""
|
||||||
|
Archetype class
|
||||||
|
"""
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
lod,
|
lod,
|
||||||
function,
|
function,
|
||||||
|
@ -99,7 +102,7 @@ class Archetype:
|
||||||
@property
|
@property
|
||||||
def end_of_life_cost(self):
|
def end_of_life_cost(self):
|
||||||
"""
|
"""
|
||||||
Get end of life cost in given currency
|
Get end of life cost in given currency per m2
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._end_of_life_cost
|
return self._end_of_life_cost
|
||||||
|
@ -111,3 +114,19 @@ class Archetype:
|
||||||
:return: Income
|
:return: Income
|
||||||
"""
|
"""
|
||||||
return self._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
|
||||||
|
|
|
@ -10,6 +10,9 @@ from hub.catalog_factories.data_models.cost.chapter import Chapter
|
||||||
|
|
||||||
|
|
||||||
class CapitalCost:
|
class CapitalCost:
|
||||||
|
"""
|
||||||
|
Capital cost class
|
||||||
|
"""
|
||||||
def __init__(self, general_chapters, design_allowance, overhead_and_profit):
|
def __init__(self, general_chapters, design_allowance, overhead_and_profit):
|
||||||
self._general_chapters = general_chapters
|
self._general_chapters = general_chapters
|
||||||
self._design_allowance = design_allowance
|
self._design_allowance = design_allowance
|
||||||
|
@ -48,3 +51,16 @@ class CapitalCost:
|
||||||
if chapter.chapter_type == name:
|
if chapter.chapter_type == name:
|
||||||
return chapter
|
return chapter
|
||||||
raise KeyError(f'Chapter name {name} not found')
|
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
|
||||||
|
|
|
@ -10,6 +10,9 @@ from hub.catalog_factories.data_models.cost.item_description import ItemDescript
|
||||||
|
|
||||||
|
|
||||||
class Chapter:
|
class Chapter:
|
||||||
|
"""
|
||||||
|
Chapter class
|
||||||
|
"""
|
||||||
def __init__(self, chapter_type, items):
|
def __init__(self, chapter_type, items):
|
||||||
|
|
||||||
self._chapter_type = chapter_type
|
self._chapter_type = chapter_type
|
||||||
|
@ -40,3 +43,15 @@ class Chapter:
|
||||||
if item.type == name:
|
if item.type == name:
|
||||||
return item
|
return item
|
||||||
raise KeyError(f'Item name {name} not found')
|
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
|
||||||
|
|
|
@ -8,6 +8,9 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
||||||
|
|
||||||
|
|
||||||
class Content:
|
class Content:
|
||||||
|
"""
|
||||||
|
Content class
|
||||||
|
"""
|
||||||
def __init__(self, archetypes):
|
def __init__(self, archetypes):
|
||||||
self._archetypes = archetypes
|
self._archetypes = archetypes
|
||||||
|
|
||||||
|
@ -17,3 +20,21 @@ class Content:
|
||||||
All archetypes in the catalog
|
All archetypes in the catalog
|
||||||
"""
|
"""
|
||||||
return self._archetypes
|
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)
|
||||||
|
|
|
@ -9,6 +9,9 @@ from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class Fuel:
|
class Fuel:
|
||||||
|
"""
|
||||||
|
Fuel class
|
||||||
|
"""
|
||||||
def __init__(self, fuel_type,
|
def __init__(self, fuel_type,
|
||||||
fixed_monthly=None,
|
fixed_monthly=None,
|
||||||
fixed_power=None,
|
fixed_power=None,
|
||||||
|
@ -40,10 +43,12 @@ class Fuel:
|
||||||
@property
|
@property
|
||||||
def fixed_power(self) -> Union[None, float]:
|
def fixed_power(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get fixed operational costs depending on the peak power consumed in currency per month per kW
|
Get fixed operational costs depending on the peak power consumed in currency per month per W
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._fixed_power
|
if self._fixed_power is not None:
|
||||||
|
return self._fixed_power/1000
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def variable(self) -> Union[tuple[None, None], tuple[float, str]]:
|
def variable(self) -> Union[tuple[None, None], tuple[float, str]]:
|
||||||
|
@ -52,3 +57,15 @@ class Fuel:
|
||||||
:return: None, None or float, str
|
:return: None, None or float, str
|
||||||
"""
|
"""
|
||||||
return self._variable, self._variable_units
|
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
|
||||||
|
|
|
@ -9,6 +9,9 @@ from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class Income:
|
class Income:
|
||||||
|
"""
|
||||||
|
Income class
|
||||||
|
"""
|
||||||
def __init__(self, construction_subsidy=None,
|
def __init__(self, construction_subsidy=None,
|
||||||
hvac_subsidy=None,
|
hvac_subsidy=None,
|
||||||
photovoltaic_subsidy=None,
|
photovoltaic_subsidy=None,
|
||||||
|
@ -24,7 +27,7 @@ class Income:
|
||||||
@property
|
@property
|
||||||
def construction_subsidy(self) -> Union[None, float]:
|
def construction_subsidy(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get subsidy for construction in percentage
|
Get subsidy for construction in percentage %
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._construction_subsidy
|
return self._construction_subsidy
|
||||||
|
@ -32,7 +35,7 @@ class Income:
|
||||||
@property
|
@property
|
||||||
def hvac_subsidy(self) -> Union[None, float]:
|
def hvac_subsidy(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get subsidy for HVAC system in percentage
|
Get subsidy for HVAC system in percentage %
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._hvac_subsidy
|
return self._hvac_subsidy
|
||||||
|
@ -51,7 +54,7 @@ class Income:
|
||||||
Get electricity export incomes in currency per J
|
Get electricity export incomes in currency per J
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._construction_subsidy
|
return self._electricity_export
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reductions_tax(self) -> Union[None, float]:
|
def reductions_tax(self) -> Union[None, float]:
|
||||||
|
@ -60,3 +63,15 @@ class Income:
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._reductions_tax
|
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
|
||||||
|
|
|
@ -9,6 +9,9 @@ from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class ItemDescription:
|
class ItemDescription:
|
||||||
|
"""
|
||||||
|
Item description class
|
||||||
|
"""
|
||||||
def __init__(self, item_type,
|
def __init__(self, item_type,
|
||||||
initial_investment=None,
|
initial_investment=None,
|
||||||
initial_investment_unit=None,
|
initial_investment_unit=None,
|
||||||
|
@ -66,3 +69,18 @@ class ItemDescription:
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._lifetime
|
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
|
||||||
|
|
|
@ -10,6 +10,9 @@ from hub.catalog_factories.data_models.cost.fuel import Fuel
|
||||||
|
|
||||||
|
|
||||||
class OperationalCost:
|
class OperationalCost:
|
||||||
|
"""
|
||||||
|
Operational cost class
|
||||||
|
"""
|
||||||
def __init__(self, fuels, maintenance_heating, maintenance_cooling, maintenance_pv, co2):
|
def __init__(self, fuels, maintenance_heating, maintenance_cooling, maintenance_pv, co2):
|
||||||
self._fuels = fuels
|
self._fuels = fuels
|
||||||
self._maintenance_heating = maintenance_heating
|
self._maintenance_heating = maintenance_heating
|
||||||
|
@ -21,7 +24,7 @@ class OperationalCost:
|
||||||
def fuels(self) -> List[Fuel]:
|
def fuels(self) -> List[Fuel]:
|
||||||
"""
|
"""
|
||||||
Get fuels listed in capital costs
|
Get fuels listed in capital costs
|
||||||
:return: [FUEL]
|
:return: [Fuel]
|
||||||
"""
|
"""
|
||||||
return self._fuels
|
return self._fuels
|
||||||
|
|
||||||
|
@ -56,3 +59,18 @@ class OperationalCost:
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._co2
|
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
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
"""
|
"""
|
||||||
Energy System catalog archetype
|
Energy System catalog archetype, understood as a cluster of energy systems
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2023 Concordia CERC group
|
Copyright © 2023 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
@ -11,27 +12,21 @@ from hub.catalog_factories.data_models.energy_systems.system import System
|
||||||
|
|
||||||
|
|
||||||
class Archetype:
|
class Archetype:
|
||||||
def __init__(self, lod, name, systems):
|
"""
|
||||||
|
Archetype class
|
||||||
|
"""
|
||||||
|
def __init__(self, name, systems):
|
||||||
|
|
||||||
self._lod = lod
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._systems = systems
|
self._systems = systems
|
||||||
|
|
||||||
@property
|
|
||||||
def lod(self):
|
|
||||||
"""
|
|
||||||
Get level of detail of the catalog
|
|
||||||
:return: string
|
|
||||||
"""
|
|
||||||
return self._lod
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""
|
"""
|
||||||
Get name
|
Get name
|
||||||
:return: string
|
:return: string
|
||||||
"""
|
"""
|
||||||
return f'{self._name}_lod{self._lod}'
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def systems(self) -> List[System]:
|
def systems(self) -> List[System]:
|
||||||
|
@ -40,3 +35,16 @@ class Archetype:
|
||||||
:return: [Equipment]
|
:return: [Equipment]
|
||||||
"""
|
"""
|
||||||
return self._systems
|
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
|
||||||
|
|
|
@ -7,12 +7,14 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
|
||||||
|
|
||||||
class Content:
|
class Content:
|
||||||
def __init__(self, archetypes, systems, generations, distributions, emissions):
|
"""
|
||||||
|
Content class
|
||||||
|
"""
|
||||||
|
def __init__(self, archetypes, systems, generations=None, distributions=None):
|
||||||
self._archetypes = archetypes
|
self._archetypes = archetypes
|
||||||
self._systems = systems
|
self._systems = systems
|
||||||
self._generations = generations
|
self._generations = generations
|
||||||
self._distributions = distributions
|
self._distributions = distributions
|
||||||
self._emissions = emissions
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def archetypes(self):
|
def archetypes(self):
|
||||||
|
@ -42,9 +44,20 @@ class Content:
|
||||||
"""
|
"""
|
||||||
return self._distributions
|
return self._distributions
|
||||||
|
|
||||||
@property
|
def to_dictionary(self):
|
||||||
def emission_equipments(self):
|
"""Class content to dictionary"""
|
||||||
"""
|
_archetypes = []
|
||||||
All emission equipments in the catalog
|
for _archetype in self.archetypes:
|
||||||
"""
|
_archetypes.append(_archetype.to_dictionary())
|
||||||
return self._emissions
|
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)
|
||||||
|
|
|
@ -3,20 +3,35 @@ Energy System catalog distribution system
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2023 Concordia CERC group
|
Copyright © 2023 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
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:
|
class DistributionSystem:
|
||||||
def __init__(self, system_id, name, system_type, supply_temperature, distribution_consumption_fix_flow,
|
"""
|
||||||
distribution_consumption_variable_flow, heat_losses):
|
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._system_id = system_id
|
||||||
self._name = name
|
self._model_name = model_name
|
||||||
self._type = system_type
|
self._type = system_type
|
||||||
self._supply_temperature = supply_temperature
|
self._supply_temperature = supply_temperature
|
||||||
self._distribution_consumption_fix_flow = distribution_consumption_fix_flow
|
self._distribution_consumption_fix_flow = distribution_consumption_fix_flow
|
||||||
self._distribution_consumption_variable_flow = distribution_consumption_variable_flow
|
self._distribution_consumption_variable_flow = distribution_consumption_variable_flow
|
||||||
self._heat_losses = heat_losses
|
self._heat_losses = heat_losses
|
||||||
|
self._generation_systems = generation_systems
|
||||||
|
self._energy_storage_systems = energy_storage_systems
|
||||||
|
self._emission_systems = emission_systems
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
@ -26,29 +41,13 @@ class DistributionSystem:
|
||||||
"""
|
"""
|
||||||
return self._system_id
|
return self._system_id
|
||||||
|
|
||||||
@id.setter
|
|
||||||
def id(self, value):
|
|
||||||
"""
|
|
||||||
Set system id
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
self._system_id = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def model_name(self):
|
||||||
"""
|
"""
|
||||||
Get name
|
Get model name
|
||||||
:return: string
|
:return: string
|
||||||
"""
|
"""
|
||||||
return self._name
|
return self._model_name
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, value):
|
|
||||||
"""
|
|
||||||
Set name
|
|
||||||
:param value: string
|
|
||||||
"""
|
|
||||||
self._name = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
|
@ -78,7 +77,7 @@ class DistributionSystem:
|
||||||
def distribution_consumption_variable_flow(self):
|
def distribution_consumption_variable_flow(self):
|
||||||
"""
|
"""
|
||||||
Get distribution_consumption if the pump or fan work at variable mass or volume flow in ratio
|
Get distribution_consumption if the pump or fan work at variable mass or volume flow in ratio
|
||||||
over energy produced (Wh/Wh)
|
over energy produced (J/J)
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._distribution_consumption_variable_flow
|
return self._distribution_consumption_variable_flow
|
||||||
|
@ -86,7 +85,56 @@ class DistributionSystem:
|
||||||
@property
|
@property
|
||||||
def heat_losses(self):
|
def heat_losses(self):
|
||||||
"""
|
"""
|
||||||
Get heat_losses in ratio over energy produced
|
Get heat_losses in ratio over energy produced in J/J
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._heat_losses
|
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
|
||||||
|
|
|
@ -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
|
|
@ -7,10 +7,13 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
|
||||||
|
|
||||||
class EmissionSystem:
|
class EmissionSystem:
|
||||||
def __init__(self, system_id, name, system_type, parasitic_energy_consumption):
|
"""
|
||||||
|
Emission system class
|
||||||
|
"""
|
||||||
|
def __init__(self, system_id, model_name=None, system_type=None, parasitic_energy_consumption=0):
|
||||||
|
|
||||||
self._system_id = system_id
|
self._system_id = system_id
|
||||||
self._name = name
|
self._model_name = model_name
|
||||||
self._type = system_type
|
self._type = system_type
|
||||||
self._parasitic_energy_consumption = parasitic_energy_consumption
|
self._parasitic_energy_consumption = parasitic_energy_consumption
|
||||||
|
|
||||||
|
@ -22,29 +25,13 @@ class EmissionSystem:
|
||||||
"""
|
"""
|
||||||
return self._system_id
|
return self._system_id
|
||||||
|
|
||||||
@id.setter
|
|
||||||
def id(self, value):
|
|
||||||
"""
|
|
||||||
Set system id
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
self._system_id = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def model_name(self):
|
||||||
"""
|
"""
|
||||||
Get name
|
Get model name
|
||||||
:return: string
|
:return: string
|
||||||
"""
|
"""
|
||||||
return self._name
|
return self._model_name
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, value):
|
|
||||||
"""
|
|
||||||
Set name
|
|
||||||
:param value: string
|
|
||||||
"""
|
|
||||||
self._name = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
|
@ -57,7 +44,17 @@ class EmissionSystem:
|
||||||
@property
|
@property
|
||||||
def parasitic_energy_consumption(self):
|
def parasitic_energy_consumption(self):
|
||||||
"""
|
"""
|
||||||
Get parasitic_energy_consumption in ratio (Wh/Wh)
|
Get parasitic_energy_consumption in ratio (J/J)
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._parasitic_energy_consumption
|
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
|
||||||
|
|
|
@ -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
|
|
@ -1,30 +1,33 @@
|
||||||
"""
|
"""
|
||||||
Energy System catalog generation system
|
Energy System catalog heat generation system
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2023 Concordia CERC group
|
Copyright © 2023 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Union
|
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:
|
class GenerationSystem(ABC):
|
||||||
def __init__(self, system_id, name, system_type, fuel_type, source_types, heat_efficiency, cooling_efficiency,
|
"""
|
||||||
electricity_efficiency, source_temperature, source_mass_flow, storage, auxiliary_equipment):
|
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._system_id = system_id
|
||||||
self._name = name
|
self._name = name
|
||||||
self._type = system_type
|
self._model_name = model_name
|
||||||
|
self._manufacturer = manufacturer
|
||||||
self._fuel_type = fuel_type
|
self._fuel_type = fuel_type
|
||||||
self._source_types = source_types
|
self._distribution_systems = distribution_systems
|
||||||
self._heat_efficiency = heat_efficiency
|
self._energy_storage_systems = energy_storage_systems
|
||||||
self._cooling_efficiency = cooling_efficiency
|
|
||||||
self._electricity_efficiency = electricity_efficiency
|
|
||||||
self._source_temperature = source_temperature
|
|
||||||
self._source_mass_flow = source_mass_flow
|
|
||||||
self._storage = storage
|
|
||||||
self._auxiliary_equipment = auxiliary_equipment
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
@ -34,106 +37,62 @@ class GenerationSystem:
|
||||||
"""
|
"""
|
||||||
return self._system_id
|
return self._system_id
|
||||||
|
|
||||||
@id.setter
|
|
||||||
def id(self, value):
|
|
||||||
"""
|
|
||||||
Set system id
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
self._system_id = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""
|
"""
|
||||||
Get name
|
Get system name
|
||||||
:return: string
|
:return: string
|
||||||
"""
|
"""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, value):
|
|
||||||
"""
|
|
||||||
Set name
|
|
||||||
:param value: string
|
|
||||||
"""
|
|
||||||
self._name = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def system_type(self):
|
||||||
"""
|
"""
|
||||||
Get type
|
Get type
|
||||||
:return: string
|
:return: string
|
||||||
"""
|
"""
|
||||||
return self._type
|
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
|
@property
|
||||||
def fuel_type(self):
|
def fuel_type(self):
|
||||||
"""
|
"""
|
||||||
Get fuel_type from [renewable, gas, diesel, electricity, wood, coal]
|
Get fuel_type from [renewable, gas, diesel, electricity, wood, coal, biogas]
|
||||||
:return: string
|
:return: string
|
||||||
"""
|
"""
|
||||||
return self._fuel_type
|
return self._fuel_type
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def source_types(self):
|
def distribution_systems(self) -> Union[None, List[DistributionSystem]]:
|
||||||
"""
|
"""
|
||||||
Get source_type from [air, water, geothermal, district_heating, grid, on_site_electricity]
|
Get distributions systems connected to this generation system
|
||||||
:return: [string]
|
:return: [DistributionSystem]
|
||||||
"""
|
"""
|
||||||
return self._source_types
|
return self._distribution_systems
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def heat_efficiency(self):
|
def energy_storage_systems(self) -> Union[None, List[EnergyStorageSystem]]:
|
||||||
"""
|
"""
|
||||||
Get heat_efficiency
|
Get energy storage systems connected to this generation system
|
||||||
:return: float
|
:return: [EnergyStorageSystem]
|
||||||
"""
|
"""
|
||||||
return self._heat_efficiency
|
return self._energy_storage_systems
|
||||||
|
|
||||||
@property
|
def to_dictionary(self):
|
||||||
def cooling_efficiency(self):
|
"""Class content to dictionary"""
|
||||||
"""
|
raise NotImplementedError
|
||||||
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 storage(self):
|
|
||||||
"""
|
|
||||||
Get boolean storage exists
|
|
||||||
:return: bool
|
|
||||||
"""
|
|
||||||
return self._storage
|
|
||||||
|
|
||||||
@property
|
|
||||||
def auxiliary_equipment(self) -> Union[None, GenerationSystem]:
|
|
||||||
"""
|
|
||||||
Get auxiliary_equipment
|
|
||||||
:return: GenerationSystem
|
|
||||||
"""
|
|
||||||
return self._auxiliary_equipment
|
|
||||||
|
|
|
@ -0,0 +1,344 @@
|
||||||
|
"""
|
||||||
|
Energy System catalog non PV generation system
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2023 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Union
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.performance_curves import PerformanceCurves
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem
|
||||||
|
|
||||||
|
|
||||||
|
class NonPvGenerationSystem(GenerationSystem):
|
||||||
|
"""
|
||||||
|
Non PV Generation system class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, system_id, name, system_type, model_name=None, manufacturer=None, fuel_type=None,
|
||||||
|
nominal_heat_output=None, maximum_heat_output=None, minimum_heat_output=None, source_medium=None,
|
||||||
|
supply_medium=None, heat_efficiency=None, nominal_cooling_output=None, maximum_cooling_output=None,
|
||||||
|
minimum_cooling_output=None, cooling_efficiency=None, electricity_efficiency=None,
|
||||||
|
source_temperature=None, source_mass_flow=None, nominal_electricity_output=None,
|
||||||
|
maximum_heat_supply_temperature=None, minimum_heat_supply_temperature=None,
|
||||||
|
maximum_cooling_supply_temperature=None, minimum_cooling_supply_temperature=None, heat_output_curve=None,
|
||||||
|
heat_fuel_consumption_curve=None, heat_efficiency_curve=None, cooling_output_curve=None,
|
||||||
|
cooling_fuel_consumption_curve=None, cooling_efficiency_curve=None,
|
||||||
|
distribution_systems=None, energy_storage_systems=None, domestic_hot_water=False,
|
||||||
|
reversible=None, simultaneous_heat_cold=None):
|
||||||
|
super().__init__(system_id=system_id, name=name, model_name=model_name, manufacturer=manufacturer,
|
||||||
|
fuel_type=fuel_type, distribution_systems=distribution_systems,
|
||||||
|
energy_storage_systems=energy_storage_systems)
|
||||||
|
self._system_type = system_type
|
||||||
|
self._nominal_heat_output = nominal_heat_output
|
||||||
|
self._maximum_heat_output = maximum_heat_output
|
||||||
|
self._minimum_heat_output = minimum_heat_output
|
||||||
|
self._heat_efficiency = heat_efficiency
|
||||||
|
self._nominal_cooling_output = nominal_cooling_output
|
||||||
|
self._maximum_cooling_output = maximum_cooling_output
|
||||||
|
self._minimum_cooling_output = minimum_cooling_output
|
||||||
|
self._cooling_efficiency = cooling_efficiency
|
||||||
|
self._electricity_efficiency = electricity_efficiency
|
||||||
|
self._nominal_electricity_output = nominal_electricity_output
|
||||||
|
self._source_medium = source_medium
|
||||||
|
self._source_temperature = source_temperature
|
||||||
|
self._source_mass_flow = source_mass_flow
|
||||||
|
self._supply_medium = supply_medium
|
||||||
|
self._maximum_heat_supply_temperature = maximum_heat_supply_temperature
|
||||||
|
self._minimum_heat_supply_temperature = minimum_heat_supply_temperature
|
||||||
|
self._maximum_cooling_supply_temperature = maximum_cooling_supply_temperature
|
||||||
|
self._minimum_cooling_supply_temperature = minimum_cooling_supply_temperature
|
||||||
|
self._heat_output_curve = heat_output_curve
|
||||||
|
self._heat_fuel_consumption_curve = heat_fuel_consumption_curve
|
||||||
|
self._heat_efficiency_curve = heat_efficiency_curve
|
||||||
|
self._cooling_output_curve = cooling_output_curve
|
||||||
|
self._cooling_fuel_consumption_curve = cooling_fuel_consumption_curve
|
||||||
|
self._cooling_efficiency_curve = cooling_efficiency_curve
|
||||||
|
self._domestic_hot_water = domestic_hot_water
|
||||||
|
self._reversible = reversible
|
||||||
|
self._simultaneous_heat_cold = simultaneous_heat_cold
|
||||||
|
|
||||||
|
@property
|
||||||
|
def system_type(self):
|
||||||
|
"""
|
||||||
|
Get type
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
return self._system_type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nominal_heat_output(self):
|
||||||
|
"""
|
||||||
|
Get nominal heat output of heat generation devices in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._nominal_heat_output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def maximum_heat_output(self):
|
||||||
|
"""
|
||||||
|
Get maximum heat output of heat generation devices in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._maximum_heat_output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def minimum_heat_output(self):
|
||||||
|
"""
|
||||||
|
Get minimum heat output of heat generation devices in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._minimum_heat_output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_medium(self):
|
||||||
|
"""
|
||||||
|
Get source_type from [air, water, ground, district_heating, grid, on_site_electricity]
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
return self._source_medium
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supply_medium(self):
|
||||||
|
"""
|
||||||
|
Get the supply medium from ['air', 'water']
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
return self._supply_medium
|
||||||
|
|
||||||
|
@property
|
||||||
|
def heat_efficiency(self):
|
||||||
|
"""
|
||||||
|
Get heat_efficiency
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._heat_efficiency
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nominal_cooling_output(self):
|
||||||
|
"""
|
||||||
|
Get nominal cooling output of heat generation devices in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._nominal_cooling_output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def maximum_cooling_output(self):
|
||||||
|
"""
|
||||||
|
Get maximum heat output of heat generation devices in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._maximum_cooling_output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def minimum_cooling_output(self):
|
||||||
|
"""
|
||||||
|
Get minimum heat output of heat generation devices in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._minimum_cooling_output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cooling_efficiency(self):
|
||||||
|
"""
|
||||||
|
Get cooling_efficiency
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._cooling_efficiency
|
||||||
|
|
||||||
|
@property
|
||||||
|
def electricity_efficiency(self):
|
||||||
|
"""
|
||||||
|
Get electricity_efficiency
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._electricity_efficiency
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_temperature(self):
|
||||||
|
"""
|
||||||
|
Get source_temperature in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._source_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_mass_flow(self):
|
||||||
|
"""
|
||||||
|
Get source_mass_flow in kg/s
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._source_mass_flow
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nominal_electricity_output(self):
|
||||||
|
"""
|
||||||
|
Get nominal_power_output of electricity generation devices or inverters in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._nominal_electricity_output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def maximum_heat_supply_temperature(self):
|
||||||
|
"""
|
||||||
|
Get the maximum heat supply temperature in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._minimum_heat_supply_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def minimum_heat_supply_temperature(self):
|
||||||
|
"""
|
||||||
|
Get the minimum heat supply temperature in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._minimum_heat_supply_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def maximum_cooling_supply_temperature(self):
|
||||||
|
"""
|
||||||
|
Get the maximum cooling supply temperature in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._maximum_cooling_supply_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def minimum_cooling_supply_temperature(self):
|
||||||
|
"""
|
||||||
|
Get the minimum cooling supply temperature in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._minimum_cooling_supply_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def heat_output_curve(self) -> Union[None, PerformanceCurves]:
|
||||||
|
"""
|
||||||
|
Get the heat output curve of the heat generation device
|
||||||
|
:return: PerformanceCurve
|
||||||
|
"""
|
||||||
|
return self._heat_output_curve
|
||||||
|
|
||||||
|
@property
|
||||||
|
def heat_fuel_consumption_curve(self) -> Union[None, PerformanceCurves]:
|
||||||
|
"""
|
||||||
|
Get the heating fuel consumption curve of the heat generation device
|
||||||
|
:return: PerformanceCurve
|
||||||
|
"""
|
||||||
|
return self._heat_fuel_consumption_curve
|
||||||
|
|
||||||
|
@property
|
||||||
|
def heat_efficiency_curve(self) -> Union[None, PerformanceCurves]:
|
||||||
|
"""
|
||||||
|
Get the heating efficiency curve of the heat generation device
|
||||||
|
:return: PerformanceCurve
|
||||||
|
"""
|
||||||
|
return self._heat_efficiency_curve
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cooling_output_curve(self) -> Union[None, PerformanceCurves]:
|
||||||
|
"""
|
||||||
|
Get the heat output curve of the heat generation device
|
||||||
|
:return: PerformanceCurve
|
||||||
|
"""
|
||||||
|
return self._cooling_output_curve
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cooling_fuel_consumption_curve(self) -> Union[None, PerformanceCurves]:
|
||||||
|
"""
|
||||||
|
Get the heating fuel consumption curve of the heat generation device
|
||||||
|
:return: PerformanceCurve
|
||||||
|
"""
|
||||||
|
return self._cooling_fuel_consumption_curve
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cooling_efficiency_curve(self) -> Union[None, PerformanceCurves]:
|
||||||
|
"""
|
||||||
|
Get the heating efficiency curve of the heat generation device
|
||||||
|
:return: PerformanceCurve
|
||||||
|
"""
|
||||||
|
return self._cooling_efficiency_curve
|
||||||
|
|
||||||
|
@property
|
||||||
|
def domestic_hot_water(self):
|
||||||
|
"""
|
||||||
|
Get the ability to produce domestic hot water
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
return self._domestic_hot_water
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reversibility(self):
|
||||||
|
"""
|
||||||
|
Get the ability to produce heating and cooling
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
return self._reversible
|
||||||
|
|
||||||
|
@property
|
||||||
|
def simultaneous_heat_cold(self):
|
||||||
|
"""
|
||||||
|
Get the ability to produce heating and cooling at the same time
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
return self._simultaneous_heat_cold
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
_distribution_systems = [_distribution_system.to_dictionary() for _distribution_system in
|
||||||
|
self.distribution_systems] if self.distribution_systems is not None else None
|
||||||
|
_energy_storage_systems = [_energy_storage_system.to_dictionary() for _energy_storage_system in
|
||||||
|
self.energy_storage_systems] if self.energy_storage_systems is not None else None
|
||||||
|
_heat_output_curve = self.heat_output_curve.to_dictionary() if (
|
||||||
|
self.heat_output_curve is not None) else None
|
||||||
|
_heat_fuel_consumption_curve = self.heat_fuel_consumption_curve.to_dictionary() if (
|
||||||
|
self.heat_fuel_consumption_curve is not None) else None
|
||||||
|
_heat_efficiency_curve = self.heat_efficiency_curve.to_dictionary() if (
|
||||||
|
self.heat_efficiency_curve is not None) else None
|
||||||
|
_cooling_output_curve = self.cooling_output_curve.to_dictionary() if (
|
||||||
|
self.cooling_output_curve is not None) else None
|
||||||
|
_cooling_fuel_consumption_curve = self.cooling_fuel_consumption_curve.to_dictionary() if (
|
||||||
|
self.cooling_fuel_consumption_curve is not None) else None
|
||||||
|
_cooling_efficiency_curve = self.cooling_efficiency_curve.to_dictionary() if (
|
||||||
|
self.cooling_efficiency_curve is not None) else None
|
||||||
|
|
||||||
|
content = {
|
||||||
|
'Energy Generation component':
|
||||||
|
{
|
||||||
|
'id': self.id,
|
||||||
|
'model name': self.model_name,
|
||||||
|
'manufacturer': self.manufacturer,
|
||||||
|
'type': self.system_type,
|
||||||
|
'fuel type': self.fuel_type,
|
||||||
|
'nominal heat output [W]': self.nominal_heat_output,
|
||||||
|
'maximum heat output [W]': self.maximum_heat_output,
|
||||||
|
'minimum heat output [W]': self.minimum_heat_output,
|
||||||
|
'source medium': self.source_medium,
|
||||||
|
'supply medium': self.supply_medium,
|
||||||
|
'source temperature [Celsius]': self.source_temperature,
|
||||||
|
'source mass flow [kg/s]': self.source_mass_flow,
|
||||||
|
'heat efficiency': self.heat_efficiency,
|
||||||
|
'nominal cooling output [W]': self.nominal_cooling_output,
|
||||||
|
'maximum cooling output [W]': self.maximum_cooling_output,
|
||||||
|
'minimum cooling output [W]': self.minimum_cooling_output,
|
||||||
|
'cooling efficiency': self.cooling_efficiency,
|
||||||
|
'electricity efficiency': self.electricity_efficiency,
|
||||||
|
'nominal power output [W]': self.nominal_electricity_output,
|
||||||
|
'maximum heating supply temperature [Celsius]': self.maximum_heat_supply_temperature,
|
||||||
|
'minimum heating supply temperature [Celsius]': self.minimum_heat_supply_temperature,
|
||||||
|
'maximum cooling supply temperature [Celsius]': self.maximum_cooling_supply_temperature,
|
||||||
|
'minimum cooling supply temperature [Celsius]': self.minimum_cooling_supply_temperature,
|
||||||
|
'heat output curve': self.heat_output_curve,
|
||||||
|
'heat fuel consumption curve': self.heat_fuel_consumption_curve,
|
||||||
|
'heat efficiency curve': _heat_efficiency_curve,
|
||||||
|
'cooling output curve': self.cooling_output_curve,
|
||||||
|
'cooling fuel consumption curve': self.cooling_fuel_consumption_curve,
|
||||||
|
'cooling efficiency curve': self.cooling_efficiency_curve,
|
||||||
|
'distribution systems connected': _distribution_systems,
|
||||||
|
'storage systems connected': _energy_storage_systems,
|
||||||
|
'domestic hot water production capability': self.domestic_hot_water,
|
||||||
|
'reversible cycle': self.reversibility,
|
||||||
|
'simultaneous heat and cooling production': self.simultaneous_heat_cold
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content
|
|
@ -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 + b*x
|
||||||
|
Exponential =>>> y = a*(b**x)
|
||||||
|
Second degree polynomial =>>> y = a + b*x + c*(x**2)
|
||||||
|
Power =>>> y = a*(x**b)
|
||||||
|
Bi-Quadratic =>>> y = a + b*x + c*(x**2) + d*z + e*(z**2) + f*x*z
|
||||||
|
|
||||||
|
Get the type of function from ['linear', 'exponential', 'second degree polynomial', 'power', 'bi-quadratic']
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
return self._curve_type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dependant_variable(self):
|
||||||
|
"""
|
||||||
|
y (e.g. COP in COP = a*source temperature**2 + b*source temperature + c*source temperature*supply temperature +
|
||||||
|
d*supply temperature + e*supply temperature**2 + f)
|
||||||
|
"""
|
||||||
|
return self._dependant_variable
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parameters(self):
|
||||||
|
"""
|
||||||
|
Get the list of parameters involved in fitting process as ['x', 'z'] (e.g. [source temperature, supply temperature]
|
||||||
|
in COP=)
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
return self._parameters
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coefficients(self):
|
||||||
|
"""
|
||||||
|
Get the coefficients of the functions as list of ['a', 'b', 'c', 'd', 'e', 'f']
|
||||||
|
:return: [coefficients]
|
||||||
|
"""
|
||||||
|
return self._coefficients
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
content = {'Parameter Function': {
|
||||||
|
'curve type': self.curve_type,
|
||||||
|
'dependant variable': self.dependant_variable,
|
||||||
|
'parameter(s)': self.parameters,
|
||||||
|
'coefficients': self.coefficients,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content
|
|
@ -0,0 +1,165 @@
|
||||||
|
"""
|
||||||
|
Energy System catalog heat generation system
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2023 Concordia CERC group
|
||||||
|
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
|
Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem
|
||||||
|
|
||||||
|
|
||||||
|
class PvGenerationSystem(GenerationSystem):
|
||||||
|
"""
|
||||||
|
Electricity Generation system class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, system_id, name, system_type, model_name=None, manufacturer=None, electricity_efficiency=None,
|
||||||
|
nominal_electricity_output=None, nominal_ambient_temperature=None, nominal_cell_temperature=None,
|
||||||
|
nominal_radiation=None, standard_test_condition_cell_temperature=None,
|
||||||
|
standard_test_condition_maximum_power=None, standard_test_condition_radiation=None,
|
||||||
|
cell_temperature_coefficient=None, width=None, height=None, distribution_systems=None,
|
||||||
|
energy_storage_systems=None):
|
||||||
|
super().__init__(system_id=system_id, name=name, model_name=model_name,
|
||||||
|
manufacturer=manufacturer, fuel_type='renewable', distribution_systems=distribution_systems,
|
||||||
|
energy_storage_systems=energy_storage_systems)
|
||||||
|
self._system_type = system_type
|
||||||
|
self._electricity_efficiency = electricity_efficiency
|
||||||
|
self._nominal_electricity_output = nominal_electricity_output
|
||||||
|
self._nominal_ambient_temperature = nominal_ambient_temperature
|
||||||
|
self._nominal_cell_temperature = nominal_cell_temperature
|
||||||
|
self._nominal_radiation = nominal_radiation
|
||||||
|
self._standard_test_condition_cell_temperature = standard_test_condition_cell_temperature
|
||||||
|
self._standard_test_condition_maximum_power = standard_test_condition_maximum_power
|
||||||
|
self._standard_test_condition_radiation = standard_test_condition_radiation
|
||||||
|
self._cell_temperature_coefficient = cell_temperature_coefficient
|
||||||
|
self._width = width
|
||||||
|
self._height = height
|
||||||
|
|
||||||
|
@property
|
||||||
|
def system_type(self):
|
||||||
|
"""
|
||||||
|
Get type
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
return self._system_type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nominal_electricity_output(self):
|
||||||
|
"""
|
||||||
|
Get nominal_power_output of electricity generation devices or inverters in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._nominal_electricity_output
|
||||||
|
|
||||||
|
@property
|
||||||
|
def electricity_efficiency(self):
|
||||||
|
"""
|
||||||
|
Get electricity_efficiency
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._electricity_efficiency
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nominal_ambient_temperature(self):
|
||||||
|
"""
|
||||||
|
Get nominal ambient temperature of PV panels in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._nominal_ambient_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nominal_cell_temperature(self):
|
||||||
|
"""
|
||||||
|
Get nominal cell temperature of PV panels in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._nominal_cell_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nominal_radiation(self):
|
||||||
|
"""
|
||||||
|
Get nominal radiation of PV panels
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._nominal_radiation
|
||||||
|
|
||||||
|
@property
|
||||||
|
def standard_test_condition_cell_temperature(self):
|
||||||
|
"""
|
||||||
|
Get standard test condition cell temperature of PV panels in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._standard_test_condition_cell_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def standard_test_condition_maximum_power(self):
|
||||||
|
"""
|
||||||
|
Get standard test condition maximum power of PV panels in W
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._standard_test_condition_maximum_power
|
||||||
|
|
||||||
|
@property
|
||||||
|
def standard_test_condition_radiation(self):
|
||||||
|
"""
|
||||||
|
Get standard test condition cell temperature of PV panels in W/m2
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._standard_test_condition_radiation
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cell_temperature_coefficient(self):
|
||||||
|
"""
|
||||||
|
Get cell temperature coefficient of PV module
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._cell_temperature_coefficient
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self):
|
||||||
|
"""
|
||||||
|
Get PV module width in m
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._width
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
"""
|
||||||
|
Get PV module height in m
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._height
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
_distribution_systems = [_distribution_system.to_dictionary() for _distribution_system in
|
||||||
|
self.distribution_systems] if self.distribution_systems is not None else None
|
||||||
|
_energy_storage_systems = [_energy_storage_system.to_dictionary() for _energy_storage_system in
|
||||||
|
self.energy_storage_systems] if self.energy_storage_systems is not None else None
|
||||||
|
content = {
|
||||||
|
'Energy Generation component':
|
||||||
|
{
|
||||||
|
'id': self.id,
|
||||||
|
'model name': self.model_name,
|
||||||
|
'manufacturer': self.manufacturer,
|
||||||
|
'type': self.system_type,
|
||||||
|
'fuel type': self.fuel_type,
|
||||||
|
'electricity efficiency': self.electricity_efficiency,
|
||||||
|
'nominal power output [W]': self.nominal_electricity_output,
|
||||||
|
'nominal ambient temperature [Celsius]': self.nominal_ambient_temperature,
|
||||||
|
'nominal cell temperature [Celsius]': self.nominal_cell_temperature,
|
||||||
|
'nominal radiation [W/m2]': self.nominal_radiation,
|
||||||
|
'standard test condition cell temperature [Celsius]': self.standard_test_condition_cell_temperature,
|
||||||
|
'standard test condition maximum power [W]': self.standard_test_condition_maximum_power,
|
||||||
|
'standard test condition radiation [W/m2]': self.standard_test_condition_radiation,
|
||||||
|
'cell temperature coefficient': self.cell_temperature_coefficient,
|
||||||
|
'width': self.width,
|
||||||
|
'height': self.height,
|
||||||
|
'distribution systems connected': _distribution_systems,
|
||||||
|
'storage systems connected': _energy_storage_systems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content
|
|
@ -1,42 +1,36 @@
|
||||||
"""
|
"""
|
||||||
Energy System catalog equipment
|
Energy Systems catalog System
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2023 Concordia CERC group
|
Copyright © 2023 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Union
|
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.generation_system import GenerationSystem
|
||||||
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
|
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
|
||||||
from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem
|
|
||||||
|
|
||||||
|
|
||||||
class System:
|
class System:
|
||||||
def __init__(self,
|
"""
|
||||||
lod,
|
System class
|
||||||
system_id,
|
"""
|
||||||
name,
|
|
||||||
demand_types,
|
|
||||||
generation_system,
|
|
||||||
distribution_system,
|
|
||||||
emission_system):
|
|
||||||
|
|
||||||
self._lod = lod
|
def __init__(self,
|
||||||
|
system_id,
|
||||||
|
demand_types,
|
||||||
|
name=None,
|
||||||
|
generation_systems=None,
|
||||||
|
distribution_systems=None,
|
||||||
|
configuration_schema=None):
|
||||||
self._system_id = system_id
|
self._system_id = system_id
|
||||||
self._name = name
|
self._name = name
|
||||||
self._demand_types = demand_types
|
self._demand_types = demand_types
|
||||||
self._generation_system = generation_system
|
self._generation_systems = generation_systems
|
||||||
self._distribution_system = distribution_system
|
self._distribution_systems = distribution_systems
|
||||||
self._emission_system = emission_system
|
self._configuration_schema = configuration_schema
|
||||||
|
|
||||||
@property
|
|
||||||
def lod(self):
|
|
||||||
"""
|
|
||||||
Get level of detail of the catalog
|
|
||||||
:return: string
|
|
||||||
"""
|
|
||||||
return self._lod
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
@ -49,39 +43,57 @@ class System:
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""
|
"""
|
||||||
Get name
|
Get the system name
|
||||||
:return: string
|
:return: string
|
||||||
"""
|
"""
|
||||||
return f'{self._name}_lod{self._lod}'
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def demand_types(self):
|
def demand_types(self):
|
||||||
"""
|
"""
|
||||||
Get demand able to cover from [heating, cooling, domestic_hot_water, electricity]
|
Get demand able to cover from ['heating', 'cooling', 'domestic_hot_water', 'electricity']
|
||||||
:return: [string]
|
:return: [string]
|
||||||
"""
|
"""
|
||||||
return self._demand_types
|
return self._demand_types
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def generation_system(self) -> GenerationSystem:
|
def generation_systems(self) -> Union[None, List[GenerationSystem]]:
|
||||||
"""
|
"""
|
||||||
Get generation system
|
Get generation systems
|
||||||
:return: GenerationSystem
|
:return: [GenerationSystem]
|
||||||
"""
|
"""
|
||||||
return self._generation_system
|
return self._generation_systems
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def distribution_system(self) -> Union[None, DistributionSystem]:
|
def distribution_systems(self) -> Union[None, List[DistributionSystem]]:
|
||||||
"""
|
"""
|
||||||
Get distribution system
|
Get distribution systems
|
||||||
:return: DistributionSystem
|
:return: [DistributionSystem]
|
||||||
"""
|
"""
|
||||||
return self._distribution_system
|
return self._distribution_systems
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def emission_system(self) -> Union[None, EmissionSystem]:
|
def configuration_schema(self) -> Path:
|
||||||
"""
|
"""
|
||||||
Get emission system
|
Get system configuration schema
|
||||||
:return: EmissionSystem
|
:return: Path
|
||||||
"""
|
"""
|
||||||
return self._emission_system
|
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
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
"""
|
||||||
|
Energy System catalog thermal storage system
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2023 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
Code contributors: Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.energy_storage_system import EnergyStorageSystem
|
||||||
|
from hub.catalog_factories.data_models.construction.layer import Layer
|
||||||
|
from hub.catalog_factories.data_models.construction.material import Material
|
||||||
|
|
||||||
|
class ThermalStorageSystem(EnergyStorageSystem):
|
||||||
|
""""
|
||||||
|
Energy Storage System Class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, storage_id, type_energy_stored=None, model_name=None, manufacturer=None, storage_type=None,
|
||||||
|
nominal_capacity=None, losses_ratio=None, volume=None, height=None, layers=None,
|
||||||
|
maximum_operating_temperature=None, storage_medium=None, heating_coil_capacity=None):
|
||||||
|
|
||||||
|
super().__init__(storage_id, model_name, manufacturer, nominal_capacity, losses_ratio)
|
||||||
|
self._type_energy_stored = type_energy_stored
|
||||||
|
self._storage_type = storage_type
|
||||||
|
self._volume = volume
|
||||||
|
self._height = height
|
||||||
|
self._layers = layers
|
||||||
|
self._maximum_operating_temperature = maximum_operating_temperature
|
||||||
|
self._storage_medium = storage_medium
|
||||||
|
self._heating_coil_capacity = heating_coil_capacity
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type_energy_stored(self):
|
||||||
|
"""
|
||||||
|
Get type of energy stored from ['electrical', 'thermal']
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
return self._type_energy_stored
|
||||||
|
|
||||||
|
@property
|
||||||
|
def storage_type(self):
|
||||||
|
"""
|
||||||
|
Get storage type from ['thermal', 'sensible', 'latent']
|
||||||
|
:return: string
|
||||||
|
"""
|
||||||
|
return self._storage_type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def volume(self):
|
||||||
|
"""
|
||||||
|
Get the physical volume of the storage system in cubic meters
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._volume
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
"""
|
||||||
|
Get the diameter of the storage system in meters
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._height
|
||||||
|
|
||||||
|
@property
|
||||||
|
def layers(self) -> [Layer]:
|
||||||
|
"""
|
||||||
|
Get construction layers
|
||||||
|
:return: [layer]
|
||||||
|
"""
|
||||||
|
return self._layers
|
||||||
|
|
||||||
|
@property
|
||||||
|
def maximum_operating_temperature(self):
|
||||||
|
"""
|
||||||
|
Get maximum operating temperature of the storage system in degree Celsius
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._maximum_operating_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def storage_medium(self) -> Material:
|
||||||
|
"""
|
||||||
|
Get thermodynamic characteristics of the storage medium
|
||||||
|
:return: [material
|
||||||
|
"""
|
||||||
|
return self._storage_medium
|
||||||
|
|
||||||
|
@property
|
||||||
|
def heating_coil_capacity(self):
|
||||||
|
"""
|
||||||
|
Get heating coil capacity in Watts
|
||||||
|
:return: [material
|
||||||
|
"""
|
||||||
|
return self._heating_coil_capacity
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
_layers = None
|
||||||
|
_medias = None
|
||||||
|
if self.layers is not None:
|
||||||
|
_layers = []
|
||||||
|
for _layer in self.layers:
|
||||||
|
_layers.append(_layer.to_dictionary())
|
||||||
|
|
||||||
|
if self.storage_medium is not None:
|
||||||
|
_medias = self.storage_medium.to_dictionary()
|
||||||
|
|
||||||
|
content = {
|
||||||
|
'Storage component':
|
||||||
|
{
|
||||||
|
'storage id': self.id,
|
||||||
|
'type of energy stored': self.type_energy_stored,
|
||||||
|
'model name': self.model_name,
|
||||||
|
'manufacturer': self.manufacturer,
|
||||||
|
'storage type': self.storage_type,
|
||||||
|
'nominal capacity [J]': self.nominal_capacity,
|
||||||
|
'losses-ratio [J/J]': self.losses_ratio,
|
||||||
|
'volume [m3]': self.volume,
|
||||||
|
'height [m]': self.height,
|
||||||
|
'layers': _layers,
|
||||||
|
'maximum operating temperature [Celsius]': self.maximum_operating_temperature,
|
||||||
|
'storage_medium': self.storage_medium.to_dictionary(),
|
||||||
|
'heating coil capacity [W]': self.heating_coil_capacity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content
|
|
@ -7,6 +7,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
|
||||||
|
|
||||||
class Content:
|
class Content:
|
||||||
|
"""
|
||||||
|
Content class
|
||||||
|
"""
|
||||||
def __init__(self, vegetations, plants, soils):
|
def __init__(self, vegetations, plants, soils):
|
||||||
self._vegetations = vegetations
|
self._vegetations = vegetations
|
||||||
self._plants = plants
|
self._plants = plants
|
||||||
|
@ -32,3 +35,21 @@ class Content:
|
||||||
All soils in the catalog
|
All soils in the catalog
|
||||||
"""
|
"""
|
||||||
return self._soils
|
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)
|
||||||
|
|
|
@ -9,6 +9,9 @@ from hub.catalog_factories.data_models.greenery.soil import Soil as hub_soil
|
||||||
|
|
||||||
|
|
||||||
class Plant:
|
class Plant:
|
||||||
|
"""
|
||||||
|
Plant class
|
||||||
|
"""
|
||||||
def __init__(self, category, plant):
|
def __init__(self, category, plant):
|
||||||
self._name = plant.name
|
self._name = plant.name
|
||||||
self._category = category
|
self._category = category
|
||||||
|
@ -93,3 +96,22 @@ class Plant:
|
||||||
:return: [Soil]
|
:return: [Soil]
|
||||||
"""
|
"""
|
||||||
return self._grows_on
|
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
|
||||||
|
|
|
@ -5,10 +5,13 @@ Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from hub.catalog_factories.data_models.greenery.plant import Plant as hub_plant
|
from hub.catalog_factories.data_models.greenery.plant import Plant as HubPlant
|
||||||
|
|
||||||
|
|
||||||
class PlantPercentage(hub_plant):
|
class PlantPercentage(HubPlant):
|
||||||
|
"""
|
||||||
|
Plant percentage class
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, percentage, plant_category, plant):
|
def __init__(self, percentage, plant_category, plant):
|
||||||
super().__init__(plant_category, plant)
|
super().__init__(plant_category, plant)
|
||||||
|
@ -21,3 +24,23 @@ class PlantPercentage(hub_plant):
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._percentage
|
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
|
||||||
|
|
|
@ -7,6 +7,9 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
|
||||||
|
|
||||||
class Soil:
|
class Soil:
|
||||||
|
"""
|
||||||
|
Soil class
|
||||||
|
"""
|
||||||
def __init__(self, soil):
|
def __init__(self, soil):
|
||||||
self._name = soil.name
|
self._name = soil.name
|
||||||
self._roughness = soil.roughness
|
self._roughness = soil.roughness
|
||||||
|
@ -19,7 +22,7 @@ class Soil:
|
||||||
self._saturation_volumetric_moisture_content = soil.saturationVolumetricMoistureContent
|
self._saturation_volumetric_moisture_content = soil.saturationVolumetricMoistureContent
|
||||||
self._residual_volumetric_moisture_content = soil.residualVolumetricMoistureContent
|
self._residual_volumetric_moisture_content = soil.residualVolumetricMoistureContent
|
||||||
self._initial_volumetric_moisture_content = soil.initialVolumetricMoistureContent
|
self._initial_volumetric_moisture_content = soil.initialVolumetricMoistureContent
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""
|
"""
|
||||||
|
@ -107,3 +110,20 @@ class Soil:
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._initial_volumetric_moisture_content
|
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
|
||||||
|
|
|
@ -9,6 +9,9 @@ from hub.catalog_factories.data_models.greenery.plant_percentage import PlantPer
|
||||||
|
|
||||||
|
|
||||||
class Vegetation:
|
class Vegetation:
|
||||||
|
"""
|
||||||
|
Vegetation class
|
||||||
|
"""
|
||||||
def __init__(self, category, vegetation, plant_percentages):
|
def __init__(self, category, vegetation, plant_percentages):
|
||||||
self._name = vegetation.name
|
self._name = vegetation.name
|
||||||
self._category = category
|
self._category = category
|
||||||
|
@ -168,3 +171,28 @@ class Vegetation:
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self._soil_initial_volumetric_moisture_content
|
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
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Appliances:
|
||||||
@property
|
@property
|
||||||
def density(self) -> Union[None, float]:
|
def density(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get appliances density in Watts per m2
|
Get appliances density in W/m2
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._density
|
return self._density
|
||||||
|
@ -61,3 +61,16 @@ class Appliances:
|
||||||
:return: None or [Schedule]
|
:return: None or [Schedule]
|
||||||
"""
|
"""
|
||||||
return self._schedules
|
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
|
||||||
|
|
|
@ -8,6 +8,9 @@ from hub.catalog_factories.data_models.usages.usage import Usage
|
||||||
|
|
||||||
|
|
||||||
class Content:
|
class Content:
|
||||||
|
"""
|
||||||
|
Content class
|
||||||
|
"""
|
||||||
def __init__(self, usages):
|
def __init__(self, usages):
|
||||||
self._usages = usages
|
self._usages = usages
|
||||||
|
|
||||||
|
@ -18,3 +21,20 @@ class Content:
|
||||||
"""
|
"""
|
||||||
return self._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)
|
||||||
|
|
|
@ -52,3 +52,15 @@ class DomesticHotWater:
|
||||||
:return: None or [Schedule]
|
:return: None or [Schedule]
|
||||||
"""
|
"""
|
||||||
return self._schedules
|
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
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
"""
|
|
||||||
Usage catalog internal gain
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class InternalGain:
|
|
||||||
"""
|
|
||||||
InternalGain class
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, internal_gain_type, average_internal_gain, convective_fraction, radiative_fraction, latent_fraction, schedules):
|
|
||||||
self._type = internal_gain_type
|
|
||||||
self._average_internal_gain = average_internal_gain
|
|
||||||
self._convective_fraction = convective_fraction
|
|
||||||
self._radiative_fraction = radiative_fraction
|
|
||||||
self._latent_fraction = latent_fraction
|
|
||||||
self._schedules = schedules
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@ from hub.catalog_factories.data_models.usages.schedule import Schedule
|
||||||
|
|
||||||
|
|
||||||
class Lighting:
|
class Lighting:
|
||||||
|
"""
|
||||||
|
Lighting class
|
||||||
|
"""
|
||||||
def __init__(self, density, convective_fraction, radiative_fraction, latent_fraction, schedules):
|
def __init__(self, density, convective_fraction, radiative_fraction, latent_fraction, schedules):
|
||||||
self._density = density
|
self._density = density
|
||||||
self._convective_fraction = convective_fraction
|
self._convective_fraction = convective_fraction
|
||||||
|
@ -58,3 +61,16 @@ class Lighting:
|
||||||
:return: None or [Schedule]
|
:return: None or [Schedule]
|
||||||
"""
|
"""
|
||||||
return self._schedules
|
return self._schedules
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
_schedules = []
|
||||||
|
for _schedule in self.schedules:
|
||||||
|
_schedules.append(_schedule.to_dictionary())
|
||||||
|
content = {'Lighting': {'density [W/m2]': self.density,
|
||||||
|
'convective fraction': self.convective_fraction,
|
||||||
|
'radiative fraction': self.radiative_fraction,
|
||||||
|
'latent fraction': self.latent_fraction,
|
||||||
|
'schedules': _schedules}
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
|
|
@ -65,3 +65,16 @@ class Occupancy:
|
||||||
:return: None or [Schedule]
|
:return: None or [Schedule]
|
||||||
"""
|
"""
|
||||||
return self._schedules
|
return self._schedules
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
_schedules = []
|
||||||
|
for _schedule in self.schedules:
|
||||||
|
_schedules.append(_schedule.to_dictionary())
|
||||||
|
content = {'Occupancy': {'occupancy density [persons/m2]': self.occupancy_density,
|
||||||
|
'sensible convective internal gain [W/m2]': self.sensible_convective_internal_gain,
|
||||||
|
'sensible radiative internal gain [W/m2]': self.sensible_radiative_internal_gain,
|
||||||
|
'latent internal gain [W/m2]': self.latent_internal_gain,
|
||||||
|
'schedules': _schedules}
|
||||||
|
}
|
||||||
|
return content
|
|
@ -73,3 +73,14 @@ class Schedule:
|
||||||
:return: None or [str]
|
:return: None or [str]
|
||||||
"""
|
"""
|
||||||
return self._day_types
|
return self._day_types
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
content = {'Schedule': {'type': self.type,
|
||||||
|
'time range': self.time_range,
|
||||||
|
'time step': self.time_step,
|
||||||
|
'data type': self.data_type,
|
||||||
|
'day types': self.day_types,
|
||||||
|
'values': self.values}
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
|
|
@ -76,3 +76,23 @@ class ThermalControl:
|
||||||
:return: None or [Schedule]
|
:return: None or [Schedule]
|
||||||
"""
|
"""
|
||||||
return self._cooling_set_point_schedules
|
return self._cooling_set_point_schedules
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
_hvac_schedules = []
|
||||||
|
for _schedule in self.hvac_availability_schedules:
|
||||||
|
_hvac_schedules.append(_schedule.to_dictionary())
|
||||||
|
_heating_set_point_schedules = []
|
||||||
|
for _schedule in self.heating_set_point_schedules:
|
||||||
|
_heating_set_point_schedules.append(_schedule.to_dictionary())
|
||||||
|
_cooling_set_point_schedules = []
|
||||||
|
for _schedule in self.cooling_set_point_schedules:
|
||||||
|
_cooling_set_point_schedules.append(_schedule.to_dictionary())
|
||||||
|
content = {'Thermal control': {'mean heating set point [Celsius]': self.mean_heating_set_point,
|
||||||
|
'heating set back [Celsius]': self.heating_set_back,
|
||||||
|
'mean cooling set point [Celsius]': self.mean_cooling_set_point,
|
||||||
|
'hvac availability schedules': _hvac_schedules,
|
||||||
|
'heating set point schedules': _heating_set_point_schedules,
|
||||||
|
'cooling set point schedules': _cooling_set_point_schedules}
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
|
|
@ -8,12 +8,15 @@ from typing import Union
|
||||||
|
|
||||||
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
||||||
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
||||||
from hub.catalog_factories.data_models.usages.ocupancy import Occupancy
|
from hub.catalog_factories.data_models.usages.occupancy import Occupancy
|
||||||
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
||||||
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
|
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
|
||||||
|
|
||||||
|
|
||||||
class Usage:
|
class Usage:
|
||||||
|
"""
|
||||||
|
Usage class
|
||||||
|
"""
|
||||||
def __init__(self, name,
|
def __init__(self, name,
|
||||||
hours_day,
|
hours_day,
|
||||||
days_year,
|
days_year,
|
||||||
|
@ -62,7 +65,7 @@ class Usage:
|
||||||
@property
|
@property
|
||||||
def mechanical_air_change(self) -> Union[None, float]:
|
def mechanical_air_change(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get usage zone mechanical air change in air change per hour (ACH)
|
Get usage zone mechanical air change in air change per second (1/s)
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._mechanical_air_change
|
return self._mechanical_air_change
|
||||||
|
@ -122,3 +125,19 @@ class Usage:
|
||||||
:return: None or DomesticHotWater
|
:return: None or DomesticHotWater
|
||||||
"""
|
"""
|
||||||
return self._domestic_hot_water
|
return self._domestic_hot_water
|
||||||
|
|
||||||
|
def to_dictionary(self):
|
||||||
|
"""Class content to dictionary"""
|
||||||
|
content = {'Usage': {'name': self.name,
|
||||||
|
'hours a day': self.hours_day,
|
||||||
|
'days a year': self.days_year,
|
||||||
|
'mechanical air change [ACH]': self.mechanical_air_change,
|
||||||
|
'ventilation rate [m3/sm2]': self.ventilation_rate,
|
||||||
|
'occupancy': self.occupancy.to_dictionary(),
|
||||||
|
'lighting': self.lighting.to_dictionary(),
|
||||||
|
'appliances': self.appliances.to_dictionary(),
|
||||||
|
'thermal control': self.thermal_control.to_dictionary(),
|
||||||
|
'domestic hot water': self.domestic_hot_water.to_dictionary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
|
0
hub/catalog_factories/energy_systems/__init__.py
Normal file
0
hub/catalog_factories/energy_systems/__init__.py
Normal file
|
@ -1,51 +1,55 @@
|
||||||
"""
|
"""
|
||||||
Montreal custom energy systems catalog
|
Montreal custom energy systems catalog module
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from ast import literal_eval
|
||||||
import xmltodict
|
import xmltodict
|
||||||
|
|
||||||
from hub.catalog_factories.catalog import Catalog
|
from hub.catalog_factories.catalog import Catalog
|
||||||
from hub.catalog_factories.data_models.energy_systems.system import System
|
from hub.catalog_factories.data_models.energy_systems.system import System
|
||||||
from hub.catalog_factories.data_models.energy_systems.content import Content
|
from hub.catalog_factories.data_models.energy_systems.content import Content
|
||||||
from hub.catalog_factories.data_models.energy_systems.generation_system import GenerationSystem
|
from hub.catalog_factories.data_models.energy_systems.non_pv_generation_system import NonPvGenerationSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.pv_generation_system import PvGenerationSystem
|
||||||
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
|
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
|
||||||
from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem
|
from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem
|
||||||
from hub.catalog_factories.data_models.energy_systems.archetype import Archetype
|
from hub.catalog_factories.data_models.energy_systems.archetype import Archetype
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.thermal_storage_system import ThermalStorageSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.electrical_storage_system import ElectricalStorageSystem
|
||||||
|
|
||||||
|
|
||||||
class MontrealCustomCatalog(Catalog):
|
class MontrealCustomCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Montreal custom energy systems catalog class
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
path = str(path / 'montreal_custom_systems.xml')
|
path = str(path / 'montreal_custom_systems.xml')
|
||||||
with open(path) as xml:
|
with open(path, 'r', encoding='utf-8') as xml:
|
||||||
self._archetypes = xmltodict.parse(xml.read(), force_list=('system', 'system_cluster', 'equipment',
|
self._archetypes = xmltodict.parse(xml.read(), force_list=('system', 'system_cluster', 'equipment',
|
||||||
'demand', 'system_id'))
|
'demand', 'system_id'))
|
||||||
|
|
||||||
self._lod = float(self._archetypes['catalog']['@lod'])
|
|
||||||
|
|
||||||
self._catalog_generation_equipments = self._load_generation_equipments()
|
self._catalog_generation_equipments = self._load_generation_equipments()
|
||||||
self._catalog_distribution_equipments = self._load_distribution_equipments()
|
|
||||||
self._catalog_emission_equipments = self._load_emission_equipments()
|
self._catalog_emission_equipments = self._load_emission_equipments()
|
||||||
|
self._catalog_distribution_equipments = self._load_distribution_equipments()
|
||||||
self._catalog_systems = self._load_systems()
|
self._catalog_systems = self._load_systems()
|
||||||
self._catalog_archetypes = self._load_archetypes()
|
self._catalog_archetypes = self._load_archetypes()
|
||||||
|
|
||||||
# store the full catalog data model in self._content
|
# store the full catalog data model in self._content
|
||||||
self._content = Content(self._catalog_archetypes,
|
self._content = Content(self._catalog_archetypes,
|
||||||
self._catalog_systems,
|
self._catalog_systems,
|
||||||
self._catalog_generation_equipments,
|
self._catalog_generation_equipments,
|
||||||
self._catalog_distribution_equipments,
|
self._catalog_distribution_equipments)
|
||||||
self._catalog_emission_equipments)
|
|
||||||
|
|
||||||
def _load_generation_equipments(self):
|
def _load_generation_equipments(self):
|
||||||
_equipments = []
|
_equipments = []
|
||||||
|
_storages = []
|
||||||
equipments = self._archetypes['catalog']['generation_equipments']['equipment']
|
equipments = self._archetypes['catalog']['generation_equipments']['equipment']
|
||||||
for equipment in equipments:
|
for equipment in equipments:
|
||||||
equipment_id = float(equipment['@id'])
|
equipment_id = float(equipment['@id'])
|
||||||
equipment_type = equipment['@type']
|
equipment_type = equipment['@type']
|
||||||
fuel_type = equipment['@fuel_type']
|
fuel_type = equipment['@fuel_type']
|
||||||
name = equipment['name']
|
model_name = equipment['name']
|
||||||
heating_efficiency = None
|
heating_efficiency = None
|
||||||
if 'heating_efficiency' in equipment:
|
if 'heating_efficiency' in equipment:
|
||||||
heating_efficiency = float(equipment['heating_efficiency'])
|
heating_efficiency = float(equipment['heating_efficiency'])
|
||||||
|
@ -55,21 +59,38 @@ class MontrealCustomCatalog(Catalog):
|
||||||
electricity_efficiency = None
|
electricity_efficiency = None
|
||||||
if 'electrical_efficiency' in equipment:
|
if 'electrical_efficiency' in equipment:
|
||||||
electricity_efficiency = float(equipment['electrical_efficiency'])
|
electricity_efficiency = float(equipment['electrical_efficiency'])
|
||||||
storage = eval(equipment['storage'].capitalize())
|
|
||||||
generation_system = GenerationSystem(equipment_id,
|
|
||||||
name,
|
|
||||||
equipment_type,
|
|
||||||
fuel_type,
|
|
||||||
None,
|
|
||||||
heating_efficiency,
|
|
||||||
cooling_efficiency,
|
|
||||||
electricity_efficiency,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
storage,
|
|
||||||
None)
|
|
||||||
|
|
||||||
|
storage_systems = None
|
||||||
|
storage = literal_eval(equipment['storage'].capitalize())
|
||||||
|
if storage:
|
||||||
|
if equipment_type == 'electricity generator':
|
||||||
|
storage_system = ElectricalStorageSystem(equipment_id)
|
||||||
|
else:
|
||||||
|
storage_system = ThermalStorageSystem(equipment_id)
|
||||||
|
storage_systems = [storage_system]
|
||||||
|
if model_name == 'PV system':
|
||||||
|
system_type = 'Photovoltaic'
|
||||||
|
generation_system = PvGenerationSystem(equipment_id,
|
||||||
|
name=None,
|
||||||
|
system_type= system_type,
|
||||||
|
model_name=model_name,
|
||||||
|
electricity_efficiency=electricity_efficiency,
|
||||||
|
energy_storage_systems=storage_systems
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
generation_system = NonPvGenerationSystem(equipment_id,
|
||||||
|
name=None,
|
||||||
|
model_name=model_name,
|
||||||
|
system_type=equipment_type,
|
||||||
|
fuel_type=fuel_type,
|
||||||
|
heat_efficiency=heating_efficiency,
|
||||||
|
cooling_efficiency=cooling_efficiency,
|
||||||
|
electricity_efficiency=electricity_efficiency,
|
||||||
|
energy_storage_systems=storage_systems,
|
||||||
|
domestic_hot_water=False
|
||||||
|
)
|
||||||
_equipments.append(generation_system)
|
_equipments.append(generation_system)
|
||||||
|
|
||||||
return _equipments
|
return _equipments
|
||||||
|
|
||||||
def _load_distribution_equipments(self):
|
def _load_distribution_equipments(self):
|
||||||
|
@ -78,7 +99,7 @@ class MontrealCustomCatalog(Catalog):
|
||||||
for equipment in equipments:
|
for equipment in equipments:
|
||||||
equipment_id = float(equipment['@id'])
|
equipment_id = float(equipment['@id'])
|
||||||
equipment_type = equipment['@type']
|
equipment_type = equipment['@type']
|
||||||
name = equipment['name']
|
model_name = equipment['name']
|
||||||
distribution_heat_losses = None
|
distribution_heat_losses = None
|
||||||
if 'distribution_heat_losses' in equipment:
|
if 'distribution_heat_losses' in equipment:
|
||||||
distribution_heat_losses = float(equipment['distribution_heat_losses']['#text']) / 100
|
distribution_heat_losses = float(equipment['distribution_heat_losses']['#text']) / 100
|
||||||
|
@ -87,15 +108,22 @@ class MontrealCustomCatalog(Catalog):
|
||||||
distribution_consumption_fix_flow = float(equipment['distribution_consumption_fix_flow']['#text']) / 100
|
distribution_consumption_fix_flow = float(equipment['distribution_consumption_fix_flow']['#text']) / 100
|
||||||
distribution_consumption_variable_flow = None
|
distribution_consumption_variable_flow = None
|
||||||
if 'distribution_consumption_variable_flow' in equipment:
|
if 'distribution_consumption_variable_flow' in equipment:
|
||||||
distribution_consumption_variable_flow = float(equipment['distribution_consumption_variable_flow']['#text']) / 100
|
distribution_consumption_variable_flow = float(
|
||||||
|
equipment['distribution_consumption_variable_flow']['#text']) / 100
|
||||||
|
|
||||||
|
emission_equipment = equipment['dissipation_id']
|
||||||
|
_emission_equipments = None
|
||||||
|
for equipment_archetype in self._catalog_emission_equipments:
|
||||||
|
if int(equipment_archetype.id) == int(emission_equipment):
|
||||||
|
_emission_equipments = [equipment_archetype]
|
||||||
|
|
||||||
distribution_system = DistributionSystem(equipment_id,
|
distribution_system = DistributionSystem(equipment_id,
|
||||||
name,
|
model_name=model_name,
|
||||||
equipment_type,
|
system_type=equipment_type,
|
||||||
None,
|
distribution_consumption_fix_flow=distribution_consumption_fix_flow,
|
||||||
distribution_consumption_fix_flow,
|
distribution_consumption_variable_flow=distribution_consumption_variable_flow,
|
||||||
distribution_consumption_variable_flow,
|
heat_losses=distribution_heat_losses,
|
||||||
distribution_heat_losses)
|
emission_systems=_emission_equipments)
|
||||||
|
|
||||||
_equipments.append(distribution_system)
|
_equipments.append(distribution_system)
|
||||||
return _equipments
|
return _equipments
|
||||||
|
@ -106,15 +134,15 @@ class MontrealCustomCatalog(Catalog):
|
||||||
for equipment in equipments:
|
for equipment in equipments:
|
||||||
equipment_id = float(equipment['@id'])
|
equipment_id = float(equipment['@id'])
|
||||||
equipment_type = equipment['@type']
|
equipment_type = equipment['@type']
|
||||||
name = equipment['name']
|
model_name = equipment['name']
|
||||||
parasitic_consumption = None
|
parasitic_consumption = 0
|
||||||
if 'parasitic_consumption' in equipment:
|
if 'parasitic_consumption' in equipment:
|
||||||
parasitic_consumption = float(equipment['parasitic_consumption']['#text']) / 100
|
parasitic_consumption = float(equipment['parasitic_consumption']['#text']) / 100
|
||||||
|
|
||||||
emission_system = EmissionSystem(equipment_id,
|
emission_system = EmissionSystem(equipment_id,
|
||||||
name,
|
model_name=model_name,
|
||||||
equipment_type,
|
system_type=equipment_type,
|
||||||
parasitic_consumption)
|
parasitic_energy_consumption=parasitic_consumption)
|
||||||
|
|
||||||
_equipments.append(emission_system)
|
_equipments.append(emission_system)
|
||||||
return _equipments
|
return _equipments
|
||||||
|
@ -127,28 +155,21 @@ class MontrealCustomCatalog(Catalog):
|
||||||
name = system['name']
|
name = system['name']
|
||||||
demands = system['demands']['demand']
|
demands = system['demands']['demand']
|
||||||
generation_equipment = system['equipments']['generation_id']
|
generation_equipment = system['equipments']['generation_id']
|
||||||
_generation_equipment = None
|
_generation_equipments = None
|
||||||
for equipment_archetype in self._catalog_generation_equipments:
|
for equipment_archetype in self._catalog_generation_equipments:
|
||||||
if int(equipment_archetype.id) == int(generation_equipment):
|
if int(equipment_archetype.id) == int(generation_equipment):
|
||||||
_generation_equipment = equipment_archetype
|
_generation_equipments = [equipment_archetype]
|
||||||
distribution_equipment = system['equipments']['distribution_id']
|
distribution_equipment = system['equipments']['distribution_id']
|
||||||
_distribution_equipment = None
|
_distribution_equipments = None
|
||||||
for equipment_archetype in self._catalog_distribution_equipments:
|
for equipment_archetype in self._catalog_distribution_equipments:
|
||||||
if int(equipment_archetype.id) == int(distribution_equipment):
|
if int(equipment_archetype.id) == int(distribution_equipment):
|
||||||
_distribution_equipment = equipment_archetype
|
_distribution_equipments = [equipment_archetype]
|
||||||
emission_equipment = system['equipments']['dissipation_id']
|
|
||||||
_emission_equipment = None
|
|
||||||
for equipment_archetype in self._catalog_emission_equipments:
|
|
||||||
if int(equipment_archetype.id) == int(emission_equipment):
|
|
||||||
_emission_equipment = equipment_archetype
|
|
||||||
|
|
||||||
_catalog_systems.append(System(self._lod,
|
_catalog_systems.append(System(system_id,
|
||||||
system_id,
|
|
||||||
name,
|
|
||||||
demands,
|
demands,
|
||||||
_generation_equipment,
|
name=name,
|
||||||
_distribution_equipment,
|
generation_systems=_generation_equipments,
|
||||||
_emission_equipment))
|
distribution_systems=_distribution_equipments))
|
||||||
return _catalog_systems
|
return _catalog_systems
|
||||||
|
|
||||||
def _load_archetypes(self):
|
def _load_archetypes(self):
|
||||||
|
@ -162,7 +183,7 @@ class MontrealCustomCatalog(Catalog):
|
||||||
for system_archetype in self._catalog_systems:
|
for system_archetype in self._catalog_systems:
|
||||||
if int(system_archetype.id) == int(system):
|
if int(system_archetype.id) == int(system):
|
||||||
_systems.append(system_archetype)
|
_systems.append(system_archetype)
|
||||||
_catalog_archetypes.append(Archetype(self._lod, name, _systems))
|
_catalog_archetypes.append(Archetype(name, _systems))
|
||||||
return _catalog_archetypes
|
return _catalog_archetypes
|
||||||
|
|
||||||
def names(self, category=None):
|
def names(self, category=None):
|
||||||
|
@ -172,17 +193,15 @@ class MontrealCustomCatalog(Catalog):
|
||||||
"""
|
"""
|
||||||
if category is None:
|
if category is None:
|
||||||
_names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'distribution_equipments': [],
|
_names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'distribution_equipments': [],
|
||||||
'emission_equipments':[]}
|
'emission_equipments': []}
|
||||||
for archetype in self._content.archetypes:
|
for archetype in self._content.archetypes:
|
||||||
_names['archetypes'].append(archetype.name)
|
_names['archetypes'].append(archetype.name)
|
||||||
for system in self._content.systems:
|
for system in self._content.systems:
|
||||||
_names['systems'].append(system.name)
|
_names['systems'].append(system.name)
|
||||||
for equipment in self._content.generation_equipments:
|
for equipment in self._content.generation_equipments:
|
||||||
_names['generation_equipments'].append(equipment.name)
|
_names['generation_equipments'].append(equipment.model_name)
|
||||||
for equipment in self._content.distribution_equipments:
|
for equipment in self._content.distribution_equipments:
|
||||||
_names['distribution_equipments'].append(equipment.name)
|
_names['distribution_equipments'].append(equipment.model_name)
|
||||||
for equipment in self._content.emission_equipments:
|
|
||||||
_names['emission_equipments'].append(equipment.name)
|
|
||||||
else:
|
else:
|
||||||
_names = {category: []}
|
_names = {category: []}
|
||||||
if category.lower() == 'archetypes':
|
if category.lower() == 'archetypes':
|
||||||
|
@ -193,13 +212,10 @@ class MontrealCustomCatalog(Catalog):
|
||||||
_names[category].append(system.name)
|
_names[category].append(system.name)
|
||||||
elif category.lower() == 'generation_equipments':
|
elif category.lower() == 'generation_equipments':
|
||||||
for system in self._content.generation_equipments:
|
for system in self._content.generation_equipments:
|
||||||
_names[category].append(system.name)
|
_names[category].append(system.model_name)
|
||||||
elif category.lower() == 'distribution_equipments':
|
elif category.lower() == 'distribution_equipments':
|
||||||
for system in self._content.distribution_equipments:
|
for system in self._content.distribution_equipments:
|
||||||
_names[category].append(system.name)
|
_names[category].append(system.model_name)
|
||||||
elif category.lower() == 'emission_equipments':
|
|
||||||
for system in self._content.emission_equipments:
|
|
||||||
_names[category].append(system.name)
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(f'Unknown category [{category}]')
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
return _names
|
return _names
|
||||||
|
@ -211,19 +227,14 @@ class MontrealCustomCatalog(Catalog):
|
||||||
"""
|
"""
|
||||||
if category is None:
|
if category is None:
|
||||||
return self._content
|
return self._content
|
||||||
else:
|
if category.lower() == 'archetypes':
|
||||||
if category.lower() == 'archetypes':
|
return self._content.archetypes
|
||||||
return self._content.archetypes
|
if category.lower() == 'systems':
|
||||||
elif category.lower() == 'systems':
|
return self._content.systems
|
||||||
return self._content.systems
|
if category.lower() == 'generation_equipments':
|
||||||
elif category.lower() == 'generation_equipments':
|
return self._content.generation_equipments
|
||||||
return self._content.generation_equipments
|
if category.lower() == 'distribution_equipments':
|
||||||
elif category.lower() == 'distribution_equipments':
|
return self._content.distribution_equipments
|
||||||
return self._content.distribution_equipments
|
|
||||||
elif category.lower() == 'emission_equipments':
|
|
||||||
return self._content.emission_equipments
|
|
||||||
else:
|
|
||||||
raise ValueError(f'Unknown category [{category}]')
|
|
||||||
|
|
||||||
def get_entry(self, name):
|
def get_entry(self, name):
|
||||||
"""
|
"""
|
||||||
|
@ -237,12 +248,9 @@ class MontrealCustomCatalog(Catalog):
|
||||||
if entry.name.lower() == name.lower():
|
if entry.name.lower() == name.lower():
|
||||||
return entry
|
return entry
|
||||||
for entry in self._content.generation_equipments:
|
for entry in self._content.generation_equipments:
|
||||||
if entry.name.lower() == name.lower():
|
if entry.model_name.lower() == name.lower():
|
||||||
return entry
|
return entry
|
||||||
for entry in self._content.distribution_equipments:
|
for entry in self._content.distribution_equipments:
|
||||||
if entry.name.lower() == name.lower():
|
if entry.model_name.lower() == name.lower():
|
||||||
return entry
|
|
||||||
for entry in self._content.emission_equipments:
|
|
||||||
if entry.name.lower() == name.lower():
|
|
||||||
return entry
|
return entry
|
||||||
raise IndexError(f"{name} doesn't exists in the catalog")
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
||||||
|
|
|
@ -0,0 +1,559 @@
|
||||||
|
"""
|
||||||
|
Montreal future energy system catalog
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
import xmltodict
|
||||||
|
from pathlib import Path
|
||||||
|
from hub.catalog_factories.catalog import Catalog
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.system import System
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.content import Content
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.non_pv_generation_system import NonPvGenerationSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.pv_generation_system import PvGenerationSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.thermal_storage_system import ThermalStorageSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.performance_curves import PerformanceCurves
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.archetype import Archetype
|
||||||
|
from hub.catalog_factories.data_models.construction.material import Material
|
||||||
|
from hub.catalog_factories.data_models.construction.layer import Layer
|
||||||
|
|
||||||
|
|
||||||
|
class MontrealFutureSystemCatalogue(Catalog):
|
||||||
|
"""
|
||||||
|
North america energy system catalog class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
path = str(path / 'montreal_future_systems.xml')
|
||||||
|
with open(path, 'r', encoding='utf-8') as xml:
|
||||||
|
self._archetypes = xmltodict.parse(xml.read(),
|
||||||
|
force_list=['pv_generation_component', 'templateStorages', 'demand'])
|
||||||
|
|
||||||
|
self._storage_components = self._load_storage_components()
|
||||||
|
self._generation_components = self._load_generation_components()
|
||||||
|
self._energy_emission_components = self._load_emission_equipments()
|
||||||
|
self._distribution_components = self._load_distribution_equipments()
|
||||||
|
self._systems = self._load_systems()
|
||||||
|
self._system_archetypes = self._load_archetypes()
|
||||||
|
self._content = Content(self._system_archetypes,
|
||||||
|
self._systems,
|
||||||
|
generations=self._generation_components,
|
||||||
|
distributions=self._distribution_components)
|
||||||
|
|
||||||
|
def _load_generation_components(self):
|
||||||
|
generation_components = []
|
||||||
|
non_pv_generation_components = self._archetypes['EnergySystemCatalog']['energy_generation_components'][
|
||||||
|
'non_pv_generation_component']
|
||||||
|
if non_pv_generation_components is not None:
|
||||||
|
for non_pv in non_pv_generation_components:
|
||||||
|
system_id = non_pv['system_id']
|
||||||
|
name = non_pv['name']
|
||||||
|
system_type = non_pv['system_type']
|
||||||
|
model_name = non_pv['model_name']
|
||||||
|
manufacturer = non_pv['manufacturer']
|
||||||
|
fuel_type = non_pv['fuel_type']
|
||||||
|
distribution_systems = non_pv['distribution_systems']
|
||||||
|
energy_storage_systems = None
|
||||||
|
if non_pv['energy_storage_systems'] is not None:
|
||||||
|
storage_component = non_pv['energy_storage_systems']['storage_id']
|
||||||
|
storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_component)
|
||||||
|
energy_storage_systems = storage_systems
|
||||||
|
nominal_heat_output = non_pv['nominal_heat_output']
|
||||||
|
maximum_heat_output = non_pv['maximum_heat_output']
|
||||||
|
minimum_heat_output = non_pv['minimum_heat_output']
|
||||||
|
source_medium = non_pv['source_medium']
|
||||||
|
supply_medium = non_pv['supply_medium']
|
||||||
|
heat_efficiency = non_pv['heat_efficiency']
|
||||||
|
nominal_cooling_output = non_pv['nominal_cooling_output']
|
||||||
|
maximum_cooling_output = non_pv['maximum_cooling_output']
|
||||||
|
minimum_cooling_output = non_pv['minimum_cooling_output']
|
||||||
|
cooling_efficiency = non_pv['cooling_efficiency']
|
||||||
|
electricity_efficiency = non_pv['electricity_efficiency']
|
||||||
|
source_temperature = non_pv['source_temperature']
|
||||||
|
source_mass_flow = non_pv['source_mass_flow']
|
||||||
|
nominal_electricity_output = non_pv['nominal_electricity_output']
|
||||||
|
maximum_heat_supply_temperature = non_pv['maximum_heat_supply_temperature']
|
||||||
|
minimum_heat_supply_temperature = non_pv['minimum_heat_supply_temperature']
|
||||||
|
maximum_cooling_supply_temperature = non_pv['maximum_cooling_supply_temperature']
|
||||||
|
minimum_cooling_supply_temperature = non_pv['minimum_cooling_supply_temperature']
|
||||||
|
heat_output_curve = None
|
||||||
|
heat_fuel_consumption_curve = None
|
||||||
|
heat_efficiency_curve = None
|
||||||
|
cooling_output_curve = None
|
||||||
|
cooling_fuel_consumption_curve = None
|
||||||
|
cooling_efficiency_curve = None
|
||||||
|
if non_pv['heat_output_curve'] is not None:
|
||||||
|
curve_type = non_pv['heat_output_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['heat_output_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['heat_output_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['heat_output_curve']['coefficients'].values())
|
||||||
|
heat_output_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['heat_fuel_consumption_curve'] is not None:
|
||||||
|
curve_type = non_pv['heat_fuel_consumption_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['heat_fuel_consumption_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['heat_fuel_consumption_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['heat_fuel_consumption_curve']['coefficients'].values())
|
||||||
|
heat_fuel_consumption_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['heat_efficiency_curve'] is not None:
|
||||||
|
curve_type = non_pv['heat_efficiency_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['heat_efficiency_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['heat_efficiency_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['heat_efficiency_curve']['coefficients'].values())
|
||||||
|
heat_efficiency_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['cooling_output_curve'] is not None:
|
||||||
|
curve_type = non_pv['cooling_output_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['cooling_output_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['cooling_output_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['cooling_output_curve']['coefficients'].values())
|
||||||
|
cooling_output_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['cooling_fuel_consumption_curve'] is not None:
|
||||||
|
curve_type = non_pv['cooling_fuel_consumption_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['cooling_fuel_consumption_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['cooling_fuel_consumption_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['cooling_fuel_consumption_curve']['coefficients'].values())
|
||||||
|
cooling_fuel_consumption_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['cooling_efficiency_curve'] is not None:
|
||||||
|
curve_type = non_pv['cooling_efficiency_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['cooling_efficiency_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['cooling_efficiency_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['cooling_efficiency_curve']['coefficients'].values())
|
||||||
|
cooling_efficiency_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
dhw = None
|
||||||
|
if non_pv['domestic_hot_water'] is not None:
|
||||||
|
if non_pv['domestic_hot_water'] == 'True':
|
||||||
|
dhw = True
|
||||||
|
else:
|
||||||
|
dhw = False
|
||||||
|
|
||||||
|
reversible = None
|
||||||
|
if non_pv['reversible'] is not None:
|
||||||
|
if non_pv['reversible'] == 'True':
|
||||||
|
reversible = True
|
||||||
|
else:
|
||||||
|
reversible = False
|
||||||
|
|
||||||
|
dual_supply = None
|
||||||
|
if non_pv['simultaneous_heat_cold'] is not None:
|
||||||
|
if non_pv['simultaneous_heat_cold'] == 'True':
|
||||||
|
dual_supply = True
|
||||||
|
else:
|
||||||
|
dual_supply = False
|
||||||
|
non_pv_component = NonPvGenerationSystem(system_id=system_id,
|
||||||
|
name=name,
|
||||||
|
system_type=system_type,
|
||||||
|
model_name=model_name,
|
||||||
|
manufacturer=manufacturer,
|
||||||
|
fuel_type=fuel_type,
|
||||||
|
nominal_heat_output=nominal_heat_output,
|
||||||
|
maximum_heat_output=maximum_heat_output,
|
||||||
|
minimum_heat_output=minimum_heat_output,
|
||||||
|
source_medium=source_medium,
|
||||||
|
supply_medium=supply_medium,
|
||||||
|
heat_efficiency=heat_efficiency,
|
||||||
|
nominal_cooling_output=nominal_cooling_output,
|
||||||
|
maximum_cooling_output=maximum_cooling_output,
|
||||||
|
minimum_cooling_output=minimum_cooling_output,
|
||||||
|
cooling_efficiency=cooling_efficiency,
|
||||||
|
electricity_efficiency=electricity_efficiency,
|
||||||
|
source_temperature=source_temperature,
|
||||||
|
source_mass_flow=source_mass_flow,
|
||||||
|
nominal_electricity_output=nominal_electricity_output,
|
||||||
|
maximum_heat_supply_temperature=maximum_heat_supply_temperature,
|
||||||
|
minimum_heat_supply_temperature=minimum_heat_supply_temperature,
|
||||||
|
maximum_cooling_supply_temperature=maximum_cooling_supply_temperature,
|
||||||
|
minimum_cooling_supply_temperature=minimum_cooling_supply_temperature,
|
||||||
|
heat_output_curve=heat_output_curve,
|
||||||
|
heat_fuel_consumption_curve=heat_fuel_consumption_curve,
|
||||||
|
heat_efficiency_curve=heat_efficiency_curve,
|
||||||
|
cooling_output_curve=cooling_output_curve,
|
||||||
|
cooling_fuel_consumption_curve=cooling_fuel_consumption_curve,
|
||||||
|
cooling_efficiency_curve=cooling_efficiency_curve,
|
||||||
|
distribution_systems=distribution_systems,
|
||||||
|
energy_storage_systems=energy_storage_systems,
|
||||||
|
domestic_hot_water=dhw,
|
||||||
|
reversible=reversible,
|
||||||
|
simultaneous_heat_cold=dual_supply)
|
||||||
|
generation_components.append(non_pv_component)
|
||||||
|
pv_generation_components = self._archetypes['EnergySystemCatalog']['energy_generation_components'][
|
||||||
|
'pv_generation_component']
|
||||||
|
if pv_generation_components is not None:
|
||||||
|
for pv in pv_generation_components:
|
||||||
|
system_id = pv['system_id']
|
||||||
|
name = pv['name']
|
||||||
|
system_type = pv['system_type']
|
||||||
|
model_name = pv['model_name']
|
||||||
|
manufacturer = pv['manufacturer']
|
||||||
|
electricity_efficiency = pv['electricity_efficiency']
|
||||||
|
nominal_electricity_output = pv['nominal_electricity_output']
|
||||||
|
nominal_ambient_temperature = pv['nominal_ambient_temperature']
|
||||||
|
nominal_cell_temperature = pv['nominal_cell_temperature']
|
||||||
|
nominal_radiation = pv['nominal_radiation']
|
||||||
|
standard_test_condition_cell_temperature = pv['standard_test_condition_cell_temperature']
|
||||||
|
standard_test_condition_maximum_power = pv['standard_test_condition_maximum_power']
|
||||||
|
standard_test_condition_radiation = pv['standard_test_condition_radiation']
|
||||||
|
cell_temperature_coefficient = pv['cell_temperature_coefficient']
|
||||||
|
width = pv['width']
|
||||||
|
height = pv['height']
|
||||||
|
distribution_systems = pv['distribution_systems']
|
||||||
|
energy_storage_systems = None
|
||||||
|
if pv['energy_storage_systems'] is not None:
|
||||||
|
storage_component = pv['energy_storage_systems']['storage_id']
|
||||||
|
storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_component)
|
||||||
|
energy_storage_systems = storage_systems
|
||||||
|
pv_component = PvGenerationSystem(system_id=system_id,
|
||||||
|
name=name,
|
||||||
|
system_type=system_type,
|
||||||
|
model_name=model_name,
|
||||||
|
manufacturer=manufacturer,
|
||||||
|
electricity_efficiency=electricity_efficiency,
|
||||||
|
nominal_electricity_output=nominal_electricity_output,
|
||||||
|
nominal_ambient_temperature=nominal_ambient_temperature,
|
||||||
|
nominal_cell_temperature=nominal_cell_temperature,
|
||||||
|
nominal_radiation=nominal_radiation,
|
||||||
|
standard_test_condition_cell_temperature=
|
||||||
|
standard_test_condition_cell_temperature,
|
||||||
|
standard_test_condition_maximum_power=standard_test_condition_maximum_power,
|
||||||
|
standard_test_condition_radiation=standard_test_condition_radiation,
|
||||||
|
cell_temperature_coefficient=cell_temperature_coefficient,
|
||||||
|
width=width,
|
||||||
|
height=height,
|
||||||
|
distribution_systems=distribution_systems,
|
||||||
|
energy_storage_systems=energy_storage_systems)
|
||||||
|
generation_components.append(pv_component)
|
||||||
|
|
||||||
|
return generation_components
|
||||||
|
|
||||||
|
def _load_distribution_equipments(self):
|
||||||
|
_equipments = []
|
||||||
|
distribution_systems = self._archetypes['EnergySystemCatalog']['distribution_systems']['distribution_system']
|
||||||
|
if distribution_systems is not None:
|
||||||
|
for distribution_system in distribution_systems:
|
||||||
|
system_id = None
|
||||||
|
model_name = None
|
||||||
|
system_type = None
|
||||||
|
supply_temperature = None
|
||||||
|
distribution_consumption_fix_flow = None
|
||||||
|
distribution_consumption_variable_flow = None
|
||||||
|
heat_losses = None
|
||||||
|
generation_systems = None
|
||||||
|
energy_storage_systems = None
|
||||||
|
emission_systems = None
|
||||||
|
distribution_equipment = DistributionSystem(system_id=system_id,
|
||||||
|
model_name=model_name,
|
||||||
|
system_type=system_type,
|
||||||
|
supply_temperature=supply_temperature,
|
||||||
|
distribution_consumption_fix_flow=distribution_consumption_fix_flow,
|
||||||
|
distribution_consumption_variable_flow=
|
||||||
|
distribution_consumption_variable_flow,
|
||||||
|
heat_losses=heat_losses,
|
||||||
|
generation_systems=generation_systems,
|
||||||
|
energy_storage_systems=energy_storage_systems,
|
||||||
|
emission_systems=emission_systems
|
||||||
|
)
|
||||||
|
_equipments.append(distribution_equipment)
|
||||||
|
return _equipments
|
||||||
|
|
||||||
|
def _load_emission_equipments(self):
|
||||||
|
_equipments = []
|
||||||
|
dissipation_systems = self._archetypes['EnergySystemCatalog']['dissipation_systems']['dissipation_system']
|
||||||
|
if dissipation_systems is not None:
|
||||||
|
for dissipation_system in dissipation_systems:
|
||||||
|
system_id = None
|
||||||
|
model_name = None
|
||||||
|
system_type = None
|
||||||
|
parasitic_energy_consumption = 0
|
||||||
|
emission_system = EmissionSystem(system_id=system_id,
|
||||||
|
model_name=model_name,
|
||||||
|
system_type=system_type,
|
||||||
|
parasitic_energy_consumption=parasitic_energy_consumption)
|
||||||
|
_equipments.append(emission_system)
|
||||||
|
return _equipments
|
||||||
|
|
||||||
|
def _load_storage_components(self):
|
||||||
|
storage_components = []
|
||||||
|
thermal_storages = self._archetypes['EnergySystemCatalog']['energy_storage_components']['thermalStorages']
|
||||||
|
template_storages = self._archetypes['EnergySystemCatalog']['energy_storage_components']['templateStorages']
|
||||||
|
for tes in thermal_storages:
|
||||||
|
storage_id = tes['storage_id']
|
||||||
|
type_energy_stored = tes['type_energy_stored']
|
||||||
|
model_name = tes['model_name']
|
||||||
|
manufacturer = tes['manufacturer']
|
||||||
|
storage_type = tes['storage_type']
|
||||||
|
volume = tes['physical_characteristics']['volume']
|
||||||
|
height = tes['physical_characteristics']['height']
|
||||||
|
maximum_operating_temperature = tes['maximum_operating_temperature']
|
||||||
|
materials = self._load_materials()
|
||||||
|
insulation_material_id = tes['insulation']['material_id']
|
||||||
|
insulation_material = self._search_material(materials, insulation_material_id)
|
||||||
|
material_id = tes['physical_characteristics']['material_id']
|
||||||
|
tank_material = self._search_material(materials, material_id)
|
||||||
|
thickness = float(tes['insulation']['insulationThickness']) / 100 # from cm to m
|
||||||
|
insulation_layer = Layer(None, 'insulation', insulation_material, thickness)
|
||||||
|
thickness = float(tes['physical_characteristics']['tankThickness']) / 100 # from cm to m
|
||||||
|
tank_layer = Layer(None, 'tank', tank_material, thickness)
|
||||||
|
media = self._load_media()
|
||||||
|
media_id = tes['storage_medium']['medium_id']
|
||||||
|
medium = self._search_media(media, media_id)
|
||||||
|
layers = [insulation_layer, tank_layer]
|
||||||
|
nominal_capacity = tes['nominal_capacity']
|
||||||
|
losses_ratio = tes['losses_ratio']
|
||||||
|
heating_coil_capacity = tes['heating_coil_capacity']
|
||||||
|
storage_component = ThermalStorageSystem(storage_id=storage_id,
|
||||||
|
model_name=model_name,
|
||||||
|
type_energy_stored=type_energy_stored,
|
||||||
|
manufacturer=manufacturer,
|
||||||
|
storage_type=storage_type,
|
||||||
|
nominal_capacity=nominal_capacity,
|
||||||
|
losses_ratio=losses_ratio,
|
||||||
|
volume=volume,
|
||||||
|
height=height,
|
||||||
|
layers=layers,
|
||||||
|
maximum_operating_temperature=maximum_operating_temperature,
|
||||||
|
storage_medium=medium,
|
||||||
|
heating_coil_capacity=heating_coil_capacity)
|
||||||
|
storage_components.append(storage_component)
|
||||||
|
|
||||||
|
for template in template_storages:
|
||||||
|
storage_id = template['storage_id']
|
||||||
|
storage_type = template['storage_type']
|
||||||
|
type_energy_stored = template['type_energy_stored']
|
||||||
|
maximum_operating_temperature = template['maximum_operating_temperature']
|
||||||
|
height = float(template['physical_characteristics']['height'])
|
||||||
|
materials = self._load_materials()
|
||||||
|
insulation_material_id = template['insulation']['material_id']
|
||||||
|
insulation_material = self._search_material(materials, insulation_material_id)
|
||||||
|
material_id = template['physical_characteristics']['material_id']
|
||||||
|
tank_material = self._search_material(materials, material_id)
|
||||||
|
thickness = float(template['insulation']['insulationThickness']) / 100 # from cm to m
|
||||||
|
insulation_layer = Layer(None, 'insulation', insulation_material, thickness)
|
||||||
|
thickness = float(template['physical_characteristics']['tankThickness']) / 100 # from cm to m
|
||||||
|
tank_layer = Layer(None, 'tank', tank_material, thickness)
|
||||||
|
layers = [insulation_layer, tank_layer]
|
||||||
|
media = self._load_media()
|
||||||
|
media_id = template['storage_medium']['medium_id']
|
||||||
|
medium = self._search_media(media, media_id)
|
||||||
|
model_name = template['model_name']
|
||||||
|
manufacturer = template['manufacturer']
|
||||||
|
nominal_capacity = template['nominal_capacity']
|
||||||
|
losses_ratio = template['losses_ratio']
|
||||||
|
volume = template['physical_characteristics']['volume']
|
||||||
|
heating_coil_capacity = template['heating_coil_capacity']
|
||||||
|
storage_component = ThermalStorageSystem(storage_id=storage_id,
|
||||||
|
model_name=model_name,
|
||||||
|
type_energy_stored=type_energy_stored,
|
||||||
|
manufacturer=manufacturer,
|
||||||
|
storage_type=storage_type,
|
||||||
|
nominal_capacity=nominal_capacity,
|
||||||
|
losses_ratio=losses_ratio,
|
||||||
|
volume=volume,
|
||||||
|
height=height,
|
||||||
|
layers=layers,
|
||||||
|
maximum_operating_temperature=maximum_operating_temperature,
|
||||||
|
storage_medium=medium,
|
||||||
|
heating_coil_capacity=heating_coil_capacity)
|
||||||
|
storage_components.append(storage_component)
|
||||||
|
return storage_components
|
||||||
|
|
||||||
|
def _load_systems(self):
|
||||||
|
base_path = Path(Path(__file__).parent.parent.parent / 'data/energy_systems')
|
||||||
|
_catalog_systems = []
|
||||||
|
systems = self._archetypes['EnergySystemCatalog']['systems']['system']
|
||||||
|
for system in systems:
|
||||||
|
system_id = system['id']
|
||||||
|
name = system['name']
|
||||||
|
demands = system['demands']['demand']
|
||||||
|
generation_components = system['components']['generation_id']
|
||||||
|
generation_systems = self._search_generation_equipment(self._load_generation_components(), generation_components)
|
||||||
|
configuration_schema = Path(base_path / system['schema'])
|
||||||
|
energy_system = System(system_id=system_id,
|
||||||
|
name=name,
|
||||||
|
demand_types=demands,
|
||||||
|
generation_systems=generation_systems,
|
||||||
|
distribution_systems=None,
|
||||||
|
configuration_schema=configuration_schema)
|
||||||
|
_catalog_systems.append(energy_system)
|
||||||
|
return _catalog_systems
|
||||||
|
|
||||||
|
def _load_archetypes(self):
|
||||||
|
_system_archetypes = []
|
||||||
|
system_clusters = self._archetypes['EnergySystemCatalog']['system_archetypes']['system_archetype']
|
||||||
|
for system_cluster in system_clusters:
|
||||||
|
name = system_cluster['name']
|
||||||
|
systems = system_cluster['systems']['system_id']
|
||||||
|
integer_system_ids = [int(item) for item in systems]
|
||||||
|
_systems = []
|
||||||
|
for system_archetype in self._systems:
|
||||||
|
if int(system_archetype.id) in integer_system_ids:
|
||||||
|
_systems.append(system_archetype)
|
||||||
|
_system_archetypes.append(Archetype(name=name, systems=_systems))
|
||||||
|
return _system_archetypes
|
||||||
|
|
||||||
|
def _load_materials(self):
|
||||||
|
materials = []
|
||||||
|
_materials = self._archetypes['EnergySystemCatalog']['materials']['material']
|
||||||
|
for _material in _materials:
|
||||||
|
material_id = _material['material_id']
|
||||||
|
name = _material['name']
|
||||||
|
conductivity = _material['conductivity']
|
||||||
|
solar_absorptance = _material['solar_absorptance']
|
||||||
|
thermal_absorptance = _material['thermal_absorptance']
|
||||||
|
density = _material['density']
|
||||||
|
specific_heat = _material['specific_heat']
|
||||||
|
no_mass = _material['no_mass']
|
||||||
|
visible_absorptance = _material['visible_absorptance']
|
||||||
|
thermal_resistance = _material['thermal_resistance']
|
||||||
|
|
||||||
|
material = Material(material_id,
|
||||||
|
name,
|
||||||
|
solar_absorptance=solar_absorptance,
|
||||||
|
thermal_absorptance=thermal_absorptance,
|
||||||
|
density=density,
|
||||||
|
conductivity=conductivity,
|
||||||
|
thermal_resistance=thermal_resistance,
|
||||||
|
visible_absorptance=visible_absorptance,
|
||||||
|
no_mass=no_mass,
|
||||||
|
specific_heat=specific_heat)
|
||||||
|
materials.append(material)
|
||||||
|
return materials
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_material(materials, material_id):
|
||||||
|
_material = None
|
||||||
|
for material in materials:
|
||||||
|
if int(material.id) == int(material_id):
|
||||||
|
_material = material
|
||||||
|
break
|
||||||
|
if _material is None:
|
||||||
|
raise ValueError(f'Material with the id = [{material_id}] not found in catalog ')
|
||||||
|
return _material
|
||||||
|
|
||||||
|
def _load_media(self):
|
||||||
|
media = []
|
||||||
|
_media = [self._archetypes['EnergySystemCatalog']['media']['medium']]
|
||||||
|
for _medium in _media:
|
||||||
|
medium_id = _medium['medium_id']
|
||||||
|
density = _medium['density']
|
||||||
|
name = _medium['name']
|
||||||
|
conductivity = _medium['conductivity']
|
||||||
|
solar_absorptance = _medium['solar_absorptance']
|
||||||
|
thermal_absorptance = _medium['thermal_absorptance']
|
||||||
|
specific_heat = _medium['specific_heat']
|
||||||
|
no_mass = _medium['no_mass']
|
||||||
|
visible_absorptance = _medium['visible_absorptance']
|
||||||
|
thermal_resistance = _medium['thermal_resistance']
|
||||||
|
medium = Material(material_id=medium_id,
|
||||||
|
name=name,
|
||||||
|
solar_absorptance=solar_absorptance,
|
||||||
|
thermal_absorptance=thermal_absorptance,
|
||||||
|
visible_absorptance=visible_absorptance,
|
||||||
|
no_mass=no_mass,
|
||||||
|
thermal_resistance=thermal_resistance,
|
||||||
|
conductivity=conductivity,
|
||||||
|
density=density,
|
||||||
|
specific_heat=specific_heat)
|
||||||
|
media.append(medium)
|
||||||
|
return media
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_media(media, medium_id):
|
||||||
|
_medium = None
|
||||||
|
for medium in media:
|
||||||
|
if int(medium.id) == int(medium_id):
|
||||||
|
_medium = medium
|
||||||
|
break
|
||||||
|
if _medium is None:
|
||||||
|
raise ValueError(f'media with the id = [{medium_id}] not found in catalog ')
|
||||||
|
return _medium
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_generation_equipment(generation_systems, generation_id):
|
||||||
|
_generation_systems = []
|
||||||
|
|
||||||
|
if isinstance(generation_id, list):
|
||||||
|
integer_ids = [int(item) for item in generation_id]
|
||||||
|
for generation in generation_systems:
|
||||||
|
if int(generation.id) in integer_ids:
|
||||||
|
_generation_systems.append(generation)
|
||||||
|
else:
|
||||||
|
integer_id = int(generation_id)
|
||||||
|
for generation in generation_systems:
|
||||||
|
if int(generation.id) == integer_id:
|
||||||
|
_generation_systems.append(generation)
|
||||||
|
|
||||||
|
if len(_generation_systems) == 0:
|
||||||
|
_generation_systems = None
|
||||||
|
raise ValueError(f'The system with the following id is not found in catalog [{generation_id}]')
|
||||||
|
return _generation_systems
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_storage_equipment(storage_systems, storage_id):
|
||||||
|
_storage_systems = []
|
||||||
|
for storage in storage_systems:
|
||||||
|
if storage.id in storage_id:
|
||||||
|
_storage_systems.append(storage)
|
||||||
|
if len(_storage_systems) == 0:
|
||||||
|
_storage_systems = None
|
||||||
|
raise ValueError(f'The system with the following id is not found in catalog [{storage_id}]')
|
||||||
|
return _storage_systems
|
||||||
|
|
||||||
|
def names(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements names
|
||||||
|
:parm: optional category filter
|
||||||
|
"""
|
||||||
|
if category is None:
|
||||||
|
_names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'storage_equipments': []}
|
||||||
|
for archetype in self._content.archetypes:
|
||||||
|
_names['archetypes'].append(archetype.name)
|
||||||
|
for system in self._content.systems:
|
||||||
|
_names['systems'].append(system.name)
|
||||||
|
for equipment in self._content.generation_equipments:
|
||||||
|
_names['generation_equipments'].append(equipment.name)
|
||||||
|
else:
|
||||||
|
_names = {category: []}
|
||||||
|
if category.lower() == 'archetypes':
|
||||||
|
for archetype in self._content.archetypes:
|
||||||
|
_names[category].append(archetype.name)
|
||||||
|
elif category.lower() == 'systems':
|
||||||
|
for system in self._content.systems:
|
||||||
|
_names[category].append(system.name)
|
||||||
|
elif category.lower() == 'generation_equipments':
|
||||||
|
for system in self._content.generation_equipments:
|
||||||
|
_names[category].append(system.name)
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
|
return _names
|
||||||
|
|
||||||
|
def entries(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements
|
||||||
|
:parm: optional category filter
|
||||||
|
"""
|
||||||
|
if category is None:
|
||||||
|
return self._content
|
||||||
|
if category.lower() == 'archetypes':
|
||||||
|
return self._content.archetypes
|
||||||
|
if category.lower() == 'systems':
|
||||||
|
return self._content.systems
|
||||||
|
if category.lower() == 'generation_equipments':
|
||||||
|
return self._content.generation_equipments
|
||||||
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
|
|
||||||
|
def get_entry(self, name):
|
||||||
|
"""
|
||||||
|
Get one catalog element by names
|
||||||
|
:parm: entry name
|
||||||
|
"""
|
||||||
|
for entry in self._content.archetypes:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.systems:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.generation_equipments:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
520
hub/catalog_factories/energy_systems/palma_system_catalgue.py
Normal file
520
hub/catalog_factories/energy_systems/palma_system_catalgue.py
Normal file
|
@ -0,0 +1,520 @@
|
||||||
|
"""
|
||||||
|
Palma energy system catalog
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Saeed Ranjbar saeed.ranjbar@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
import xmltodict
|
||||||
|
from pathlib import Path
|
||||||
|
from hub.catalog_factories.catalog import Catalog
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.distribution_system import DistributionSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.emission_system import EmissionSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.system import System
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.content import Content
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.non_pv_generation_system import NonPvGenerationSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.pv_generation_system import PvGenerationSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.thermal_storage_system import ThermalStorageSystem
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.performance_curves import PerformanceCurves
|
||||||
|
from hub.catalog_factories.data_models.energy_systems.archetype import Archetype
|
||||||
|
from hub.catalog_factories.data_models.construction.material import Material
|
||||||
|
from hub.catalog_factories.data_models.construction.layer import Layer
|
||||||
|
|
||||||
|
|
||||||
|
class PalmaSystemCatalogue(Catalog):
|
||||||
|
"""
|
||||||
|
North america energy system catalog class
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
path = str(path / 'palma_systems.xml')
|
||||||
|
with open(path, 'r', encoding='utf-8') as xml:
|
||||||
|
self._archetypes = xmltodict.parse(xml.read(),
|
||||||
|
force_list=['pv_generation_component', 'demand'])
|
||||||
|
|
||||||
|
self._storage_components = self._load_storage_components()
|
||||||
|
self._generation_components = self._load_generation_components()
|
||||||
|
self._energy_emission_components = self._load_emission_equipments()
|
||||||
|
self._distribution_components = self._load_distribution_equipments()
|
||||||
|
self._systems = self._load_systems()
|
||||||
|
self._system_archetypes = self._load_archetypes()
|
||||||
|
self._content = Content(self._system_archetypes,
|
||||||
|
self._systems,
|
||||||
|
generations=self._generation_components,
|
||||||
|
distributions=self._distribution_components)
|
||||||
|
|
||||||
|
def _load_generation_components(self):
|
||||||
|
generation_components = []
|
||||||
|
non_pv_generation_components = self._archetypes['EnergySystemCatalog']['energy_generation_components'][
|
||||||
|
'non_pv_generation_component']
|
||||||
|
if non_pv_generation_components is not None:
|
||||||
|
for non_pv in non_pv_generation_components:
|
||||||
|
system_id = non_pv['system_id']
|
||||||
|
name = non_pv['name']
|
||||||
|
system_type = non_pv['system_type']
|
||||||
|
model_name = non_pv['model_name']
|
||||||
|
manufacturer = non_pv['manufacturer']
|
||||||
|
fuel_type = non_pv['fuel_type']
|
||||||
|
distribution_systems = non_pv['distribution_systems']
|
||||||
|
energy_storage_systems = None
|
||||||
|
if non_pv['energy_storage_systems'] is not None:
|
||||||
|
storage_component = non_pv['energy_storage_systems']['storage_id']
|
||||||
|
storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_component)
|
||||||
|
energy_storage_systems = storage_systems
|
||||||
|
nominal_heat_output = non_pv['nominal_heat_output']
|
||||||
|
maximum_heat_output = non_pv['maximum_heat_output']
|
||||||
|
minimum_heat_output = non_pv['minimum_heat_output']
|
||||||
|
source_medium = non_pv['source_medium']
|
||||||
|
supply_medium = non_pv['supply_medium']
|
||||||
|
heat_efficiency = non_pv['heat_efficiency']
|
||||||
|
nominal_cooling_output = non_pv['nominal_cooling_output']
|
||||||
|
maximum_cooling_output = non_pv['maximum_cooling_output']
|
||||||
|
minimum_cooling_output = non_pv['minimum_cooling_output']
|
||||||
|
cooling_efficiency = non_pv['cooling_efficiency']
|
||||||
|
electricity_efficiency = non_pv['electricity_efficiency']
|
||||||
|
source_temperature = non_pv['source_temperature']
|
||||||
|
source_mass_flow = non_pv['source_mass_flow']
|
||||||
|
nominal_electricity_output = non_pv['nominal_electricity_output']
|
||||||
|
maximum_heat_supply_temperature = non_pv['maximum_heat_supply_temperature']
|
||||||
|
minimum_heat_supply_temperature = non_pv['minimum_heat_supply_temperature']
|
||||||
|
maximum_cooling_supply_temperature = non_pv['maximum_cooling_supply_temperature']
|
||||||
|
minimum_cooling_supply_temperature = non_pv['minimum_cooling_supply_temperature']
|
||||||
|
heat_output_curve = None
|
||||||
|
heat_fuel_consumption_curve = None
|
||||||
|
heat_efficiency_curve = None
|
||||||
|
cooling_output_curve = None
|
||||||
|
cooling_fuel_consumption_curve = None
|
||||||
|
cooling_efficiency_curve = None
|
||||||
|
if non_pv['heat_output_curve'] is not None:
|
||||||
|
curve_type = non_pv['heat_output_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['heat_output_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['heat_output_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['heat_output_curve']['coefficients'].values())
|
||||||
|
heat_output_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['heat_fuel_consumption_curve'] is not None:
|
||||||
|
curve_type = non_pv['heat_fuel_consumption_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['heat_fuel_consumption_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['heat_fuel_consumption_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['heat_fuel_consumption_curve']['coefficients'].values())
|
||||||
|
heat_fuel_consumption_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['heat_efficiency_curve'] is not None:
|
||||||
|
curve_type = non_pv['heat_efficiency_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['heat_efficiency_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['heat_efficiency_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['heat_efficiency_curve']['coefficients'].values())
|
||||||
|
heat_efficiency_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['cooling_output_curve'] is not None:
|
||||||
|
curve_type = non_pv['cooling_output_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['cooling_output_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['cooling_output_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['cooling_output_curve']['coefficients'].values())
|
||||||
|
cooling_output_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['cooling_fuel_consumption_curve'] is not None:
|
||||||
|
curve_type = non_pv['cooling_fuel_consumption_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['cooling_fuel_consumption_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['cooling_fuel_consumption_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['cooling_fuel_consumption_curve']['coefficients'].values())
|
||||||
|
cooling_fuel_consumption_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
if non_pv['cooling_efficiency_curve'] is not None:
|
||||||
|
curve_type = non_pv['cooling_efficiency_curve']['curve_type']
|
||||||
|
dependant_variable = non_pv['cooling_efficiency_curve']['dependant_variable']
|
||||||
|
parameters = non_pv['cooling_efficiency_curve']['parameters']
|
||||||
|
coefficients = list(non_pv['cooling_efficiency_curve']['coefficients'].values())
|
||||||
|
cooling_efficiency_curve = PerformanceCurves(curve_type, dependant_variable, parameters, coefficients)
|
||||||
|
dhw = None
|
||||||
|
if non_pv['domestic_hot_water'] is not None:
|
||||||
|
if non_pv['domestic_hot_water'] == 'True':
|
||||||
|
dhw = True
|
||||||
|
else:
|
||||||
|
dhw = False
|
||||||
|
|
||||||
|
reversible = None
|
||||||
|
if non_pv['reversible'] is not None:
|
||||||
|
if non_pv['reversible'] == 'True':
|
||||||
|
reversible = True
|
||||||
|
else:
|
||||||
|
reversible = False
|
||||||
|
|
||||||
|
dual_supply = None
|
||||||
|
if non_pv['simultaneous_heat_cold'] is not None:
|
||||||
|
if non_pv['simultaneous_heat_cold'] == 'True':
|
||||||
|
dual_supply = True
|
||||||
|
else:
|
||||||
|
dual_supply = False
|
||||||
|
non_pv_component = NonPvGenerationSystem(system_id=system_id,
|
||||||
|
name=name,
|
||||||
|
system_type=system_type,
|
||||||
|
model_name=model_name,
|
||||||
|
manufacturer=manufacturer,
|
||||||
|
fuel_type=fuel_type,
|
||||||
|
nominal_heat_output=nominal_heat_output,
|
||||||
|
maximum_heat_output=maximum_heat_output,
|
||||||
|
minimum_heat_output=minimum_heat_output,
|
||||||
|
source_medium=source_medium,
|
||||||
|
supply_medium=supply_medium,
|
||||||
|
heat_efficiency=heat_efficiency,
|
||||||
|
nominal_cooling_output=nominal_cooling_output,
|
||||||
|
maximum_cooling_output=maximum_cooling_output,
|
||||||
|
minimum_cooling_output=minimum_cooling_output,
|
||||||
|
cooling_efficiency=cooling_efficiency,
|
||||||
|
electricity_efficiency=electricity_efficiency,
|
||||||
|
source_temperature=source_temperature,
|
||||||
|
source_mass_flow=source_mass_flow,
|
||||||
|
nominal_electricity_output=nominal_electricity_output,
|
||||||
|
maximum_heat_supply_temperature=maximum_heat_supply_temperature,
|
||||||
|
minimum_heat_supply_temperature=minimum_heat_supply_temperature,
|
||||||
|
maximum_cooling_supply_temperature=maximum_cooling_supply_temperature,
|
||||||
|
minimum_cooling_supply_temperature=minimum_cooling_supply_temperature,
|
||||||
|
heat_output_curve=heat_output_curve,
|
||||||
|
heat_fuel_consumption_curve=heat_fuel_consumption_curve,
|
||||||
|
heat_efficiency_curve=heat_efficiency_curve,
|
||||||
|
cooling_output_curve=cooling_output_curve,
|
||||||
|
cooling_fuel_consumption_curve=cooling_fuel_consumption_curve,
|
||||||
|
cooling_efficiency_curve=cooling_efficiency_curve,
|
||||||
|
distribution_systems=distribution_systems,
|
||||||
|
energy_storage_systems=energy_storage_systems,
|
||||||
|
domestic_hot_water=dhw,
|
||||||
|
reversible=reversible,
|
||||||
|
simultaneous_heat_cold=dual_supply)
|
||||||
|
generation_components.append(non_pv_component)
|
||||||
|
pv_generation_components = self._archetypes['EnergySystemCatalog']['energy_generation_components'][
|
||||||
|
'pv_generation_component']
|
||||||
|
if pv_generation_components is not None:
|
||||||
|
for pv in pv_generation_components:
|
||||||
|
system_id = pv['system_id']
|
||||||
|
name = pv['name']
|
||||||
|
system_type = pv['system_type']
|
||||||
|
model_name = pv['model_name']
|
||||||
|
manufacturer = pv['manufacturer']
|
||||||
|
electricity_efficiency = pv['electricity_efficiency']
|
||||||
|
nominal_electricity_output = pv['nominal_electricity_output']
|
||||||
|
nominal_ambient_temperature = pv['nominal_ambient_temperature']
|
||||||
|
nominal_cell_temperature = pv['nominal_cell_temperature']
|
||||||
|
nominal_radiation = pv['nominal_radiation']
|
||||||
|
standard_test_condition_cell_temperature = pv['standard_test_condition_cell_temperature']
|
||||||
|
standard_test_condition_maximum_power = pv['standard_test_condition_maximum_power']
|
||||||
|
standard_test_condition_radiation = pv['standard_test_condition_radiation']
|
||||||
|
cell_temperature_coefficient = pv['cell_temperature_coefficient']
|
||||||
|
width = pv['width']
|
||||||
|
height = pv['height']
|
||||||
|
distribution_systems = pv['distribution_systems']
|
||||||
|
energy_storage_systems = None
|
||||||
|
if pv['energy_storage_systems'] is not None:
|
||||||
|
storage_component = pv['energy_storage_systems']['storage_id']
|
||||||
|
storage_systems = self._search_storage_equipment(self._load_storage_components(), storage_component)
|
||||||
|
energy_storage_systems = storage_systems
|
||||||
|
pv_component = PvGenerationSystem(system_id=system_id,
|
||||||
|
name=name,
|
||||||
|
system_type=system_type,
|
||||||
|
model_name=model_name,
|
||||||
|
manufacturer=manufacturer,
|
||||||
|
electricity_efficiency=electricity_efficiency,
|
||||||
|
nominal_electricity_output=nominal_electricity_output,
|
||||||
|
nominal_ambient_temperature=nominal_ambient_temperature,
|
||||||
|
nominal_cell_temperature=nominal_cell_temperature,
|
||||||
|
nominal_radiation=nominal_radiation,
|
||||||
|
standard_test_condition_cell_temperature=
|
||||||
|
standard_test_condition_cell_temperature,
|
||||||
|
standard_test_condition_maximum_power=standard_test_condition_maximum_power,
|
||||||
|
standard_test_condition_radiation=standard_test_condition_radiation,
|
||||||
|
cell_temperature_coefficient=cell_temperature_coefficient,
|
||||||
|
width=width,
|
||||||
|
height=height,
|
||||||
|
distribution_systems=distribution_systems,
|
||||||
|
energy_storage_systems=energy_storage_systems)
|
||||||
|
generation_components.append(pv_component)
|
||||||
|
|
||||||
|
return generation_components
|
||||||
|
|
||||||
|
def _load_distribution_equipments(self):
|
||||||
|
_equipments = []
|
||||||
|
distribution_systems = self._archetypes['EnergySystemCatalog']['distribution_systems']['distribution_system']
|
||||||
|
if distribution_systems is not None:
|
||||||
|
for distribution_system in distribution_systems:
|
||||||
|
system_id = None
|
||||||
|
model_name = None
|
||||||
|
system_type = None
|
||||||
|
supply_temperature = None
|
||||||
|
distribution_consumption_fix_flow = None
|
||||||
|
distribution_consumption_variable_flow = None
|
||||||
|
heat_losses = None
|
||||||
|
generation_systems = None
|
||||||
|
energy_storage_systems = None
|
||||||
|
emission_systems = None
|
||||||
|
distribution_equipment = DistributionSystem(system_id=system_id,
|
||||||
|
model_name=model_name,
|
||||||
|
system_type=system_type,
|
||||||
|
supply_temperature=supply_temperature,
|
||||||
|
distribution_consumption_fix_flow=distribution_consumption_fix_flow,
|
||||||
|
distribution_consumption_variable_flow=
|
||||||
|
distribution_consumption_variable_flow,
|
||||||
|
heat_losses=heat_losses,
|
||||||
|
generation_systems=generation_systems,
|
||||||
|
energy_storage_systems=energy_storage_systems,
|
||||||
|
emission_systems=emission_systems
|
||||||
|
)
|
||||||
|
_equipments.append(distribution_equipment)
|
||||||
|
return _equipments
|
||||||
|
|
||||||
|
def _load_emission_equipments(self):
|
||||||
|
_equipments = []
|
||||||
|
dissipation_systems = self._archetypes['EnergySystemCatalog']['dissipation_systems']['dissipation_system']
|
||||||
|
if dissipation_systems is not None:
|
||||||
|
for dissipation_system in dissipation_systems:
|
||||||
|
system_id = None
|
||||||
|
model_name = None
|
||||||
|
system_type = None
|
||||||
|
parasitic_energy_consumption = 0
|
||||||
|
emission_system = EmissionSystem(system_id=system_id,
|
||||||
|
model_name=model_name,
|
||||||
|
system_type=system_type,
|
||||||
|
parasitic_energy_consumption=parasitic_energy_consumption)
|
||||||
|
_equipments.append(emission_system)
|
||||||
|
return _equipments
|
||||||
|
|
||||||
|
def _load_storage_components(self):
|
||||||
|
storage_components = []
|
||||||
|
thermal_storages = self._archetypes['EnergySystemCatalog']['energy_storage_components']['thermalStorages']
|
||||||
|
for tes in thermal_storages:
|
||||||
|
storage_id = tes['storage_id']
|
||||||
|
type_energy_stored = tes['type_energy_stored']
|
||||||
|
model_name = tes['model_name']
|
||||||
|
manufacturer = tes['manufacturer']
|
||||||
|
storage_type = tes['storage_type']
|
||||||
|
volume = tes['physical_characteristics']['volume']
|
||||||
|
height = tes['physical_characteristics']['height']
|
||||||
|
maximum_operating_temperature = tes['maximum_operating_temperature']
|
||||||
|
materials = self._load_materials()
|
||||||
|
insulation_material_id = tes['insulation']['material_id']
|
||||||
|
insulation_material = self._search_material(materials, insulation_material_id)
|
||||||
|
material_id = tes['physical_characteristics']['material_id']
|
||||||
|
tank_material = self._search_material(materials, material_id)
|
||||||
|
thickness = float(tes['insulation']['insulationThickness']) / 100 # from cm to m
|
||||||
|
insulation_layer = Layer(None, 'insulation', insulation_material, thickness)
|
||||||
|
thickness = float(tes['physical_characteristics']['tankThickness']) / 100 # from cm to m
|
||||||
|
tank_layer = Layer(None, 'tank', tank_material, thickness)
|
||||||
|
media = self._load_media()
|
||||||
|
media_id = tes['storage_medium']['medium_id']
|
||||||
|
medium = self._search_media(media, media_id)
|
||||||
|
layers = [insulation_layer, tank_layer]
|
||||||
|
nominal_capacity = tes['nominal_capacity']
|
||||||
|
losses_ratio = tes['losses_ratio']
|
||||||
|
heating_coil_capacity = tes['heating_coil_capacity']
|
||||||
|
storage_component = ThermalStorageSystem(storage_id=storage_id,
|
||||||
|
model_name=model_name,
|
||||||
|
type_energy_stored=type_energy_stored,
|
||||||
|
manufacturer=manufacturer,
|
||||||
|
storage_type=storage_type,
|
||||||
|
nominal_capacity=nominal_capacity,
|
||||||
|
losses_ratio=losses_ratio,
|
||||||
|
volume=volume,
|
||||||
|
height=height,
|
||||||
|
layers=layers,
|
||||||
|
maximum_operating_temperature=maximum_operating_temperature,
|
||||||
|
storage_medium=medium,
|
||||||
|
heating_coil_capacity=heating_coil_capacity)
|
||||||
|
storage_components.append(storage_component)
|
||||||
|
return storage_components
|
||||||
|
|
||||||
|
def _load_systems(self):
|
||||||
|
base_path = Path(Path(__file__).parent.parent.parent / 'data/energy_systems')
|
||||||
|
_catalog_systems = []
|
||||||
|
systems = self._archetypes['EnergySystemCatalog']['systems']['system']
|
||||||
|
for system in systems:
|
||||||
|
system_id = system['id']
|
||||||
|
name = system['name']
|
||||||
|
demands = system['demands']['demand']
|
||||||
|
generation_components = system['components']['generation_id']
|
||||||
|
generation_systems = self._search_generation_equipment(self._load_generation_components(), generation_components)
|
||||||
|
configuration_schema = None
|
||||||
|
if system['schema'] is not None:
|
||||||
|
configuration_schema = Path(base_path / system['schema'])
|
||||||
|
energy_system = System(system_id=system_id,
|
||||||
|
name=name,
|
||||||
|
demand_types=demands,
|
||||||
|
generation_systems=generation_systems,
|
||||||
|
distribution_systems=None,
|
||||||
|
configuration_schema=configuration_schema)
|
||||||
|
_catalog_systems.append(energy_system)
|
||||||
|
return _catalog_systems
|
||||||
|
|
||||||
|
def _load_archetypes(self):
|
||||||
|
_system_archetypes = []
|
||||||
|
system_clusters = self._archetypes['EnergySystemCatalog']['system_archetypes']['system_archetype']
|
||||||
|
for system_cluster in system_clusters:
|
||||||
|
name = system_cluster['name']
|
||||||
|
systems = system_cluster['systems']['system_id']
|
||||||
|
integer_system_ids = [int(item) for item in systems]
|
||||||
|
_systems = []
|
||||||
|
for system_archetype in self._systems:
|
||||||
|
if int(system_archetype.id) in integer_system_ids:
|
||||||
|
_systems.append(system_archetype)
|
||||||
|
_system_archetypes.append(Archetype(name=name, systems=_systems))
|
||||||
|
return _system_archetypes
|
||||||
|
|
||||||
|
def _load_materials(self):
|
||||||
|
materials = []
|
||||||
|
_materials = self._archetypes['EnergySystemCatalog']['materials']['material']
|
||||||
|
for _material in _materials:
|
||||||
|
material_id = _material['material_id']
|
||||||
|
name = _material['name']
|
||||||
|
conductivity = _material['conductivity']
|
||||||
|
solar_absorptance = _material['solar_absorptance']
|
||||||
|
thermal_absorptance = _material['thermal_absorptance']
|
||||||
|
density = _material['density']
|
||||||
|
specific_heat = _material['specific_heat']
|
||||||
|
no_mass = _material['no_mass']
|
||||||
|
visible_absorptance = _material['visible_absorptance']
|
||||||
|
thermal_resistance = _material['thermal_resistance']
|
||||||
|
|
||||||
|
material = Material(material_id,
|
||||||
|
name,
|
||||||
|
solar_absorptance=solar_absorptance,
|
||||||
|
thermal_absorptance=thermal_absorptance,
|
||||||
|
density=density,
|
||||||
|
conductivity=conductivity,
|
||||||
|
thermal_resistance=thermal_resistance,
|
||||||
|
visible_absorptance=visible_absorptance,
|
||||||
|
no_mass=no_mass,
|
||||||
|
specific_heat=specific_heat)
|
||||||
|
materials.append(material)
|
||||||
|
return materials
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_material(materials, material_id):
|
||||||
|
_material = None
|
||||||
|
for material in materials:
|
||||||
|
if int(material.id) == int(material_id):
|
||||||
|
_material = material
|
||||||
|
break
|
||||||
|
if _material is None:
|
||||||
|
raise ValueError(f'Material with the id = [{material_id}] not found in catalog ')
|
||||||
|
return _material
|
||||||
|
|
||||||
|
def _load_media(self):
|
||||||
|
media = []
|
||||||
|
_media = [self._archetypes['EnergySystemCatalog']['media']['medium']]
|
||||||
|
for _medium in _media:
|
||||||
|
medium_id = _medium['medium_id']
|
||||||
|
density = _medium['density']
|
||||||
|
name = _medium['name']
|
||||||
|
conductivity = _medium['conductivity']
|
||||||
|
solar_absorptance = _medium['solar_absorptance']
|
||||||
|
thermal_absorptance = _medium['thermal_absorptance']
|
||||||
|
specific_heat = _medium['specific_heat']
|
||||||
|
no_mass = _medium['no_mass']
|
||||||
|
visible_absorptance = _medium['visible_absorptance']
|
||||||
|
thermal_resistance = _medium['thermal_resistance']
|
||||||
|
medium = Material(material_id=medium_id,
|
||||||
|
name=name,
|
||||||
|
solar_absorptance=solar_absorptance,
|
||||||
|
thermal_absorptance=thermal_absorptance,
|
||||||
|
visible_absorptance=visible_absorptance,
|
||||||
|
no_mass=no_mass,
|
||||||
|
thermal_resistance=thermal_resistance,
|
||||||
|
conductivity=conductivity,
|
||||||
|
density=density,
|
||||||
|
specific_heat=specific_heat)
|
||||||
|
media.append(medium)
|
||||||
|
return media
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_media(media, medium_id):
|
||||||
|
_medium = None
|
||||||
|
for medium in media:
|
||||||
|
if int(medium.id) == int(medium_id):
|
||||||
|
_medium = medium
|
||||||
|
break
|
||||||
|
if _medium is None:
|
||||||
|
raise ValueError(f'media with the id = [{medium_id}] not found in catalog ')
|
||||||
|
return _medium
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_generation_equipment(generation_systems, generation_id):
|
||||||
|
_generation_systems = []
|
||||||
|
|
||||||
|
if isinstance(generation_id, list):
|
||||||
|
integer_ids = [int(item) for item in generation_id]
|
||||||
|
for generation in generation_systems:
|
||||||
|
if int(generation.id) in integer_ids:
|
||||||
|
_generation_systems.append(generation)
|
||||||
|
else:
|
||||||
|
integer_id = int(generation_id)
|
||||||
|
for generation in generation_systems:
|
||||||
|
if int(generation.id) == integer_id:
|
||||||
|
_generation_systems.append(generation)
|
||||||
|
|
||||||
|
if len(_generation_systems) == 0:
|
||||||
|
_generation_systems = None
|
||||||
|
raise ValueError(f'The system with the following id is not found in catalog [{generation_id}]')
|
||||||
|
return _generation_systems
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _search_storage_equipment(storage_systems, storage_id):
|
||||||
|
_storage_systems = []
|
||||||
|
for storage in storage_systems:
|
||||||
|
if storage.id in storage_id:
|
||||||
|
_storage_systems.append(storage)
|
||||||
|
if len(_storage_systems) == 0:
|
||||||
|
_storage_systems = None
|
||||||
|
raise ValueError(f'The system with the following id is not found in catalog [{storage_id}]')
|
||||||
|
return _storage_systems
|
||||||
|
|
||||||
|
def names(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements names
|
||||||
|
:parm: optional category filter
|
||||||
|
"""
|
||||||
|
if category is None:
|
||||||
|
_names = {'archetypes': [], 'systems': [], 'generation_equipments': [], 'storage_equipments': []}
|
||||||
|
for archetype in self._content.archetypes:
|
||||||
|
_names['archetypes'].append(archetype.name)
|
||||||
|
for system in self._content.systems:
|
||||||
|
_names['systems'].append(system.name)
|
||||||
|
for equipment in self._content.generation_equipments:
|
||||||
|
_names['generation_equipments'].append(equipment.name)
|
||||||
|
else:
|
||||||
|
_names = {category: []}
|
||||||
|
if category.lower() == 'archetypes':
|
||||||
|
for archetype in self._content.archetypes:
|
||||||
|
_names[category].append(archetype.name)
|
||||||
|
elif category.lower() == 'systems':
|
||||||
|
for system in self._content.systems:
|
||||||
|
_names[category].append(system.name)
|
||||||
|
elif category.lower() == 'generation_equipments':
|
||||||
|
for system in self._content.generation_equipments:
|
||||||
|
_names[category].append(system.name)
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
|
return _names
|
||||||
|
|
||||||
|
def entries(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements
|
||||||
|
:parm: optional category filter
|
||||||
|
"""
|
||||||
|
if category is None:
|
||||||
|
return self._content
|
||||||
|
if category.lower() == 'archetypes':
|
||||||
|
return self._content.archetypes
|
||||||
|
if category.lower() == 'systems':
|
||||||
|
return self._content.systems
|
||||||
|
if category.lower() == 'generation_equipments':
|
||||||
|
return self._content.generation_equipments
|
||||||
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
|
|
||||||
|
def get_entry(self, name):
|
||||||
|
"""
|
||||||
|
Get one catalog element by names
|
||||||
|
:parm: entry name
|
||||||
|
"""
|
||||||
|
for entry in self._content.archetypes:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.systems:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
for entry in self._content.generation_equipments:
|
||||||
|
if entry.name.lower() == name.lower():
|
||||||
|
return entry
|
||||||
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -4,16 +4,22 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
import logging
|
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
from hub.catalog_factories.energy_systems.montreal_custom_catalog import MontrealCustomCatalog
|
from hub.catalog_factories.energy_systems.montreal_custom_catalog import MontrealCustomCatalog
|
||||||
|
from hub.catalog_factories.energy_systems.montreal_future_system_catalogue import MontrealFutureSystemCatalogue
|
||||||
|
from hub.catalog_factories.energy_systems.palma_system_catalgue import PalmaSystemCatalogue
|
||||||
from hub.helpers.utils import validate_import_export_type
|
from hub.helpers.utils import validate_import_export_type
|
||||||
|
|
||||||
Catalog = TypeVar('Catalog')
|
Catalog = TypeVar('Catalog')
|
||||||
|
|
||||||
|
|
||||||
class EnergySystemsCatalogFactory:
|
class EnergySystemsCatalogFactory:
|
||||||
|
"""
|
||||||
|
Energy system catalog factory class
|
||||||
|
"""
|
||||||
def __init__(self, handler, base_path=None):
|
def __init__(self, handler, base_path=None):
|
||||||
if base_path is None:
|
if base_path is None:
|
||||||
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
|
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
|
||||||
|
@ -28,6 +34,20 @@ class EnergySystemsCatalogFactory:
|
||||||
"""
|
"""
|
||||||
return MontrealCustomCatalog(self._path)
|
return MontrealCustomCatalog(self._path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _montreal_future(self):
|
||||||
|
"""
|
||||||
|
Retrieve North American catalog
|
||||||
|
"""
|
||||||
|
return MontrealFutureSystemCatalogue(self._path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _palma(self):
|
||||||
|
"""
|
||||||
|
Retrieve Palma catalog
|
||||||
|
"""
|
||||||
|
return PalmaSystemCatalogue(self._path)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def catalog(self) -> Catalog:
|
def catalog(self) -> Catalog:
|
||||||
"""
|
"""
|
||||||
|
|
0
hub/catalog_factories/greenery/__init__.py
Normal file
0
hub/catalog_factories/greenery/__init__.py
Normal file
|
@ -15,304 +15,304 @@ getEClassifier = partial(Ecore.getEClassifier, searchspace=eClassifiers)
|
||||||
Management = EEnum('Management', literals=['Intensive', 'Extensive', 'SemiIntensive', 'NA'])
|
Management = EEnum('Management', literals=['Intensive', 'Extensive', 'SemiIntensive', 'NA'])
|
||||||
|
|
||||||
Roughness = EEnum('Roughness', literals=['VeryRough', 'Rough',
|
Roughness = EEnum('Roughness', literals=['VeryRough', 'Rough',
|
||||||
'MediumRough', 'MediumSmooth', 'Smooth', 'VerySmooth'])
|
'MediumRough', 'MediumSmooth', 'Smooth', 'VerySmooth'])
|
||||||
|
|
||||||
|
|
||||||
class Soil(EObject, metaclass=MetaEClass):
|
class Soil(EObject, metaclass=MetaEClass):
|
||||||
|
|
||||||
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
roughness = EAttribute(eType=Roughness, unique=True, derived=False,
|
roughness = EAttribute(eType=Roughness, unique=True, derived=False,
|
||||||
changeable=True, default_value=Roughness.MediumRough)
|
changeable=True, default_value=Roughness.MediumRough)
|
||||||
conductivityOfDrySoil = EAttribute(
|
conductivityOfDrySoil = EAttribute(
|
||||||
eType=EString, unique=True, derived=False, changeable=True, default_value='1.0 W/(m*K)')
|
eType=EString, unique=True, derived=False, changeable=True, default_value='1.0 W/(m*K)')
|
||||||
densityOfDrySoil = EAttribute(eType=EString, unique=True, derived=False,
|
densityOfDrySoil = EAttribute(eType=EString, unique=True, derived=False,
|
||||||
changeable=True, default_value='1100 kg/m³')
|
changeable=True, default_value='1100 kg/m³')
|
||||||
specificHeatOfDrySoil = EAttribute(
|
specificHeatOfDrySoil = EAttribute(
|
||||||
eType=EString, unique=True, derived=False, changeable=True, default_value='1200 J/(kg*K)')
|
eType=EString, unique=True, derived=False, changeable=True, default_value='1200 J/(kg*K)')
|
||||||
thermalAbsorptance = EAttribute(eType=EString, unique=True,
|
thermalAbsorptance = EAttribute(eType=EString, unique=True,
|
||||||
derived=False, changeable=True, default_value='0.9')
|
derived=False, changeable=True, default_value='0.9')
|
||||||
solarAbsorptance = EAttribute(eType=EString, unique=True,
|
solarAbsorptance = EAttribute(eType=EString, unique=True,
|
||||||
derived=False, changeable=True, default_value='0.7')
|
derived=False, changeable=True, default_value='0.7')
|
||||||
visibleAbsorptance = EAttribute(eType=EString, unique=True,
|
visibleAbsorptance = EAttribute(eType=EString, unique=True,
|
||||||
derived=False, changeable=True, default_value='0.75')
|
derived=False, changeable=True, default_value='0.75')
|
||||||
saturationVolumetricMoistureContent = EAttribute(
|
saturationVolumetricMoistureContent = EAttribute(
|
||||||
eType=EString, unique=True, derived=False, changeable=True, default_value='0.0')
|
eType=EString, unique=True, derived=False, changeable=True, default_value='0.0')
|
||||||
residualVolumetricMoistureContent = EAttribute(
|
residualVolumetricMoistureContent = EAttribute(
|
||||||
eType=EString, unique=True, derived=False, changeable=True, default_value='0.05')
|
eType=EString, unique=True, derived=False, changeable=True, default_value='0.05')
|
||||||
initialVolumetricMoistureContent = EAttribute(
|
initialVolumetricMoistureContent = EAttribute(
|
||||||
eType=EString, unique=True, derived=False, changeable=True, default_value='0.1')
|
eType=EString, unique=True, derived=False, changeable=True, default_value='0.1')
|
||||||
|
|
||||||
def __init__(self, *, name=None, roughness=None, conductivityOfDrySoil=None, densityOfDrySoil=None, specificHeatOfDrySoil=None, thermalAbsorptance=None, solarAbsorptance=None, visibleAbsorptance=None, saturationVolumetricMoistureContent=None, residualVolumetricMoistureContent=None, initialVolumetricMoistureContent=None):
|
def __init__(self, *, name=None, roughness=None, conductivityOfDrySoil=None, densityOfDrySoil=None, specificHeatOfDrySoil=None, thermalAbsorptance=None, solarAbsorptance=None, visibleAbsorptance=None, saturationVolumetricMoistureContent=None, residualVolumetricMoistureContent=None, initialVolumetricMoistureContent=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
if roughness is not None:
|
if roughness is not None:
|
||||||
self.roughness = roughness
|
self.roughness = roughness
|
||||||
|
|
||||||
if conductivityOfDrySoil is not None:
|
if conductivityOfDrySoil is not None:
|
||||||
self.conductivityOfDrySoil = conductivityOfDrySoil
|
self.conductivityOfDrySoil = conductivityOfDrySoil
|
||||||
|
|
||||||
if densityOfDrySoil is not None:
|
if densityOfDrySoil is not None:
|
||||||
self.densityOfDrySoil = densityOfDrySoil
|
self.densityOfDrySoil = densityOfDrySoil
|
||||||
|
|
||||||
if specificHeatOfDrySoil is not None:
|
if specificHeatOfDrySoil is not None:
|
||||||
self.specificHeatOfDrySoil = specificHeatOfDrySoil
|
self.specificHeatOfDrySoil = specificHeatOfDrySoil
|
||||||
|
|
||||||
if thermalAbsorptance is not None:
|
if thermalAbsorptance is not None:
|
||||||
self.thermalAbsorptance = thermalAbsorptance
|
self.thermalAbsorptance = thermalAbsorptance
|
||||||
|
|
||||||
if solarAbsorptance is not None:
|
if solarAbsorptance is not None:
|
||||||
self.solarAbsorptance = solarAbsorptance
|
self.solarAbsorptance = solarAbsorptance
|
||||||
|
|
||||||
if visibleAbsorptance is not None:
|
if visibleAbsorptance is not None:
|
||||||
self.visibleAbsorptance = visibleAbsorptance
|
self.visibleAbsorptance = visibleAbsorptance
|
||||||
|
|
||||||
if saturationVolumetricMoistureContent is not None:
|
if saturationVolumetricMoistureContent is not None:
|
||||||
self.saturationVolumetricMoistureContent = saturationVolumetricMoistureContent
|
self.saturationVolumetricMoistureContent = saturationVolumetricMoistureContent
|
||||||
|
|
||||||
if residualVolumetricMoistureContent is not None:
|
if residualVolumetricMoistureContent is not None:
|
||||||
self.residualVolumetricMoistureContent = residualVolumetricMoistureContent
|
self.residualVolumetricMoistureContent = residualVolumetricMoistureContent
|
||||||
|
|
||||||
if initialVolumetricMoistureContent is not None:
|
if initialVolumetricMoistureContent is not None:
|
||||||
self.initialVolumetricMoistureContent = initialVolumetricMoistureContent
|
self.initialVolumetricMoistureContent = initialVolumetricMoistureContent
|
||||||
|
|
||||||
|
|
||||||
class Plant(EObject, metaclass=MetaEClass):
|
class Plant(EObject, metaclass=MetaEClass):
|
||||||
|
|
||||||
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
height = EAttribute(eType=EString, unique=True, derived=False,
|
height = EAttribute(eType=EString, unique=True, derived=False,
|
||||||
changeable=True, default_value='0.1 m')
|
changeable=True, default_value='0.1 m')
|
||||||
leafAreaIndex = EAttribute(eType=EString, unique=True, derived=False,
|
leafAreaIndex = EAttribute(eType=EString, unique=True, derived=False,
|
||||||
changeable=True, default_value='2.5')
|
changeable=True, default_value='2.5')
|
||||||
leafReflectivity = EAttribute(eType=EString, unique=True,
|
leafReflectivity = EAttribute(eType=EString, unique=True,
|
||||||
derived=False, changeable=True, default_value='0.1')
|
derived=False, changeable=True, default_value='0.1')
|
||||||
leafEmissivity = EAttribute(eType=EString, unique=True, derived=False,
|
leafEmissivity = EAttribute(eType=EString, unique=True, derived=False,
|
||||||
changeable=True, default_value='0.9')
|
changeable=True, default_value='0.9')
|
||||||
minimalStomatalResistance = EAttribute(
|
minimalStomatalResistance = EAttribute(
|
||||||
eType=EString, unique=True, derived=False, changeable=True, default_value='100.0 s/m')
|
eType=EString, unique=True, derived=False, changeable=True, default_value='100.0 s/m')
|
||||||
co2Sequestration = EAttribute(eType=EString, unique=True, derived=False,
|
co2Sequestration = EAttribute(eType=EString, unique=True, derived=False,
|
||||||
changeable=True, default_value='kgCO₂eq')
|
changeable=True, default_value='kgCO₂eq')
|
||||||
growsOn = EReference(ordered=True, unique=True, containment=False, derived=False, upper=-1)
|
growsOn = EReference(ordered=True, unique=True, containment=False, derived=False, upper=-1)
|
||||||
|
|
||||||
def __init__(self, *, name=None, height=None, leafAreaIndex=None, leafReflectivity=None, leafEmissivity=None, minimalStomatalResistance=None, growsOn=None, co2Sequestration=None):
|
def __init__(self, *, name=None, height=None, leafAreaIndex=None, leafReflectivity=None, leafEmissivity=None, minimalStomatalResistance=None, growsOn=None, co2Sequestration=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
if height is not None:
|
if height is not None:
|
||||||
self.height = height
|
self.height = height
|
||||||
|
|
||||||
if leafAreaIndex is not None:
|
if leafAreaIndex is not None:
|
||||||
self.leafAreaIndex = leafAreaIndex
|
self.leafAreaIndex = leafAreaIndex
|
||||||
|
|
||||||
if leafReflectivity is not None:
|
if leafReflectivity is not None:
|
||||||
self.leafReflectivity = leafReflectivity
|
self.leafReflectivity = leafReflectivity
|
||||||
|
|
||||||
if leafEmissivity is not None:
|
if leafEmissivity is not None:
|
||||||
self.leafEmissivity = leafEmissivity
|
self.leafEmissivity = leafEmissivity
|
||||||
|
|
||||||
if minimalStomatalResistance is not None:
|
if minimalStomatalResistance is not None:
|
||||||
self.minimalStomatalResistance = minimalStomatalResistance
|
self.minimalStomatalResistance = minimalStomatalResistance
|
||||||
|
|
||||||
if co2Sequestration is not None:
|
if co2Sequestration is not None:
|
||||||
self.co2Sequestration = co2Sequestration
|
self.co2Sequestration = co2Sequestration
|
||||||
|
|
||||||
if growsOn:
|
if growsOn:
|
||||||
self.growsOn.extend(growsOn)
|
self.growsOn.extend(growsOn)
|
||||||
|
|
||||||
|
|
||||||
class SupportEnvelope(EObject, metaclass=MetaEClass):
|
class SupportEnvelope(EObject, metaclass=MetaEClass):
|
||||||
|
|
||||||
roughness = EAttribute(eType=Roughness, unique=True, derived=False,
|
roughness = EAttribute(eType=Roughness, unique=True, derived=False,
|
||||||
changeable=True, default_value=Roughness.MediumRough)
|
changeable=True, default_value=Roughness.MediumRough)
|
||||||
solarAbsorptance = EAttribute(eType=EDouble, unique=True,
|
solarAbsorptance = EAttribute(eType=EDouble, unique=True,
|
||||||
|
derived=False, changeable=True, default_value=0.0)
|
||||||
|
conductivity = EAttribute(eType=EDouble, unique=True, derived=False,
|
||||||
|
changeable=True, default_value=0.0)
|
||||||
|
visibleAbsorptance = EAttribute(eType=EDouble, unique=True,
|
||||||
|
derived=False, changeable=True, default_value=0.0)
|
||||||
|
specificHeat = EAttribute(eType=EDouble, unique=True, derived=False,
|
||||||
|
changeable=True, default_value=0.0)
|
||||||
|
density = EAttribute(eType=EDouble, unique=True, derived=False,
|
||||||
|
changeable=True, default_value=0.0)
|
||||||
|
thermalAbsorptance = EAttribute(eType=EDouble, unique=True,
|
||||||
derived=False, changeable=True, default_value=0.0)
|
derived=False, changeable=True, default_value=0.0)
|
||||||
conductivity = EAttribute(eType=EDouble, unique=True, derived=False,
|
|
||||||
changeable=True, default_value=0.0)
|
|
||||||
visibleAbsorptance = EAttribute(eType=EDouble, unique=True,
|
|
||||||
derived=False, changeable=True, default_value=0.0)
|
|
||||||
specificHeat = EAttribute(eType=EDouble, unique=True, derived=False,
|
|
||||||
changeable=True, default_value=0.0)
|
|
||||||
density = EAttribute(eType=EDouble, unique=True, derived=False,
|
|
||||||
changeable=True, default_value=0.0)
|
|
||||||
thermalAbsorptance = EAttribute(eType=EDouble, unique=True,
|
|
||||||
derived=False, changeable=True, default_value=0.0)
|
|
||||||
|
|
||||||
def __init__(self, *, roughness=None, solarAbsorptance=None, conductivity=None, visibleAbsorptance=None, specificHeat=None, density=None, thermalAbsorptance=None):
|
def __init__(self, *, roughness=None, solarAbsorptance=None, conductivity=None, visibleAbsorptance=None, specificHeat=None, density=None, thermalAbsorptance=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if roughness is not None:
|
if roughness is not None:
|
||||||
self.roughness = roughness
|
self.roughness = roughness
|
||||||
|
|
||||||
if solarAbsorptance is not None:
|
if solarAbsorptance is not None:
|
||||||
self.solarAbsorptance = solarAbsorptance
|
self.solarAbsorptance = solarAbsorptance
|
||||||
|
|
||||||
if conductivity is not None:
|
if conductivity is not None:
|
||||||
self.conductivity = conductivity
|
self.conductivity = conductivity
|
||||||
|
|
||||||
if visibleAbsorptance is not None:
|
if visibleAbsorptance is not None:
|
||||||
self.visibleAbsorptance = visibleAbsorptance
|
self.visibleAbsorptance = visibleAbsorptance
|
||||||
|
|
||||||
if specificHeat is not None:
|
if specificHeat is not None:
|
||||||
self.specificHeat = specificHeat
|
self.specificHeat = specificHeat
|
||||||
|
|
||||||
if density is not None:
|
if density is not None:
|
||||||
self.density = density
|
self.density = density
|
||||||
|
|
||||||
if thermalAbsorptance is not None:
|
if thermalAbsorptance is not None:
|
||||||
self.thermalAbsorptance = thermalAbsorptance
|
self.thermalAbsorptance = thermalAbsorptance
|
||||||
|
|
||||||
|
|
||||||
class GreeneryCatalog(EObject, metaclass=MetaEClass):
|
class GreeneryCatalog(EObject, metaclass=MetaEClass):
|
||||||
|
|
||||||
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
description = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
description = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
source = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
source = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
plantCategories = EReference(ordered=True, unique=True,
|
plantCategories = EReference(ordered=True, unique=True,
|
||||||
containment=True, derived=False, upper=-1)
|
containment=True, derived=False, upper=-1)
|
||||||
vegetationCategories = EReference(ordered=True, unique=True,
|
vegetationCategories = EReference(ordered=True, unique=True,
|
||||||
containment=True, derived=False, upper=-1)
|
containment=True, derived=False, upper=-1)
|
||||||
soils = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
|
soils = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
|
||||||
|
|
||||||
def __init__(self, *, name=None, description=None, source=None, plantCategories=None, vegetationCategories=None, soils=None):
|
def __init__(self, *, name=None, description=None, source=None, plantCategories=None, vegetationCategories=None, soils=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
if description is not None:
|
if description is not None:
|
||||||
self.description = description
|
self.description = description
|
||||||
|
|
||||||
if source is not None:
|
if source is not None:
|
||||||
self.source = source
|
self.source = source
|
||||||
|
|
||||||
if plantCategories:
|
if plantCategories:
|
||||||
self.plantCategories.extend(plantCategories)
|
self.plantCategories.extend(plantCategories)
|
||||||
|
|
||||||
if vegetationCategories:
|
if vegetationCategories:
|
||||||
self.vegetationCategories.extend(vegetationCategories)
|
self.vegetationCategories.extend(vegetationCategories)
|
||||||
|
|
||||||
if soils:
|
if soils:
|
||||||
self.soils.extend(soils)
|
self.soils.extend(soils)
|
||||||
|
|
||||||
|
|
||||||
class PlantCategory(EObject, metaclass=MetaEClass):
|
class PlantCategory(EObject, metaclass=MetaEClass):
|
||||||
"""Excluding (that is non-overlapping) categories like Trees, Hedeges, Grasses that help users finding a specific biol. plant species."""
|
"""Excluding (that is non-overlapping) categories like Trees, Hedeges, Grasses that help users finding a specific biol. plant species."""
|
||||||
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
|
plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
|
||||||
|
|
||||||
def __init__(self, *, name=None, plants=None):
|
def __init__(self, *, name=None, plants=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
if plants:
|
if plants:
|
||||||
self.plants.extend(plants)
|
self.plants.extend(plants)
|
||||||
|
|
||||||
|
|
||||||
class IrrigationSchedule(EObject, metaclass=MetaEClass):
|
class IrrigationSchedule(EObject, metaclass=MetaEClass):
|
||||||
|
|
||||||
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
|
|
||||||
def __init__(self, *, name=None):
|
def __init__(self, *, name=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
class Vegetation(EObject, metaclass=MetaEClass):
|
class Vegetation(EObject, metaclass=MetaEClass):
|
||||||
"""Plant life or total plant cover (as of an area)"""
|
"""Plant life or total plant cover (as of an area)"""
|
||||||
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
thicknessOfSoil = EAttribute(eType=EString, unique=True, derived=False,
|
thicknessOfSoil = EAttribute(eType=EString, unique=True, derived=False,
|
||||||
changeable=True, default_value='20 cm')
|
changeable=True, default_value='20 cm')
|
||||||
management = EAttribute(eType=Management, unique=True, derived=False,
|
management = EAttribute(eType=Management, unique=True, derived=False,
|
||||||
changeable=True, default_value=Management.NA)
|
changeable=True, default_value=Management.NA)
|
||||||
airGap = EAttribute(eType=EString, unique=True, derived=False,
|
airGap = EAttribute(eType=EString, unique=True, derived=False,
|
||||||
changeable=True, default_value='0.0 cm')
|
changeable=True, default_value='0.0 cm')
|
||||||
soil = EReference(ordered=True, unique=True, containment=False, derived=False)
|
soil = EReference(ordered=True, unique=True, containment=False, derived=False)
|
||||||
plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
|
plants = EReference(ordered=True, unique=True, containment=True, derived=False, upper=-1)
|
||||||
|
|
||||||
def __init__(self, *, name=None, thicknessOfSoil=None, soil=None, plants=None, management=None, airGap=None):
|
def __init__(self, *, name=None, thicknessOfSoil=None, soil=None, plants=None, management=None, airGap=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
if thicknessOfSoil is not None:
|
if thicknessOfSoil is not None:
|
||||||
self.thicknessOfSoil = thicknessOfSoil
|
self.thicknessOfSoil = thicknessOfSoil
|
||||||
|
|
||||||
if management is not None:
|
if management is not None:
|
||||||
self.management = management
|
self.management = management
|
||||||
|
|
||||||
if airGap is not None:
|
if airGap is not None:
|
||||||
self.airGap = airGap
|
self.airGap = airGap
|
||||||
|
|
||||||
if soil is not None:
|
if soil is not None:
|
||||||
self.soil = soil
|
self.soil = soil
|
||||||
|
|
||||||
if plants:
|
if plants:
|
||||||
self.plants.extend(plants)
|
self.plants.extend(plants)
|
||||||
|
|
||||||
|
|
||||||
class VegetationCategory(EObject, metaclass=MetaEClass):
|
class VegetationCategory(EObject, metaclass=MetaEClass):
|
||||||
"""Excluding (that is non-overlapping) categories to help users finding a specific vegetation template."""
|
"""Excluding (that is non-overlapping) categories to help users finding a specific vegetation template."""
|
||||||
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
name = EAttribute(eType=EString, unique=True, derived=False, changeable=True)
|
||||||
vegetationTemplates = EReference(ordered=True, unique=True,
|
vegetationTemplates = EReference(ordered=True, unique=True,
|
||||||
containment=True, derived=False, upper=-1)
|
containment=True, derived=False, upper=-1)
|
||||||
|
|
||||||
def __init__(self, *, vegetationTemplates=None, name=None):
|
def __init__(self, *, vegetationTemplates=None, name=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
if vegetationTemplates:
|
if vegetationTemplates:
|
||||||
self.vegetationTemplates.extend(vegetationTemplates)
|
self.vegetationTemplates.extend(vegetationTemplates)
|
||||||
|
|
||||||
|
|
||||||
class PlantPercentage(EObject, metaclass=MetaEClass):
|
class PlantPercentage(EObject, metaclass=MetaEClass):
|
||||||
|
|
||||||
percentage = EAttribute(eType=EString, unique=True, derived=False,
|
percentage = EAttribute(eType=EString, unique=True, derived=False,
|
||||||
changeable=True, default_value='100')
|
changeable=True, default_value='100')
|
||||||
plant = EReference(ordered=True, unique=True, containment=False, derived=False)
|
plant = EReference(ordered=True, unique=True, containment=False, derived=False)
|
||||||
|
|
||||||
def __init__(self, *, percentage=None, plant=None):
|
def __init__(self, *, percentage=None, plant=None):
|
||||||
# if kwargs:
|
# if kwargs:
|
||||||
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
# raise AttributeError('unexpected arguments: {}'.format(kwargs))
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if percentage is not None:
|
if percentage is not None:
|
||||||
self.percentage = percentage
|
self.percentage = percentage
|
||||||
|
|
||||||
if plant is not None:
|
if plant is not None:
|
||||||
self.plant = plant
|
self.plant = plant
|
||||||
|
|
|
@ -5,33 +5,36 @@ Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pyecore.resources import ResourceSet, URI
|
|
||||||
from hub.catalog_factories.greenery.ecore_greenery.greenerycatalog import GreeneryCatalog as gc
|
|
||||||
from hub.catalog_factories.catalog import Catalog
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from hub.catalog_factories.data_models.greenery.vegetation import Vegetation as libs_vegetation
|
from pyecore.resources import ResourceSet, URI
|
||||||
from hub.catalog_factories.data_models.greenery.plant import Plant as libs_plant
|
from hub.catalog_factories.greenery.ecore_greenery.greenerycatalog import GreeneryCatalog as Gc
|
||||||
from hub.catalog_factories.data_models.greenery.soil import Soil as libs_soil
|
from hub.catalog_factories.catalog import Catalog
|
||||||
from hub.catalog_factories.data_models.greenery.plant_percentage import PlantPercentage as libs_pp
|
from hub.catalog_factories.data_models.greenery.vegetation import Vegetation as HubVegetation
|
||||||
|
from hub.catalog_factories.data_models.greenery.plant import Plant as HubPlant
|
||||||
|
from hub.catalog_factories.data_models.greenery.soil import Soil as HubSoil
|
||||||
|
from hub.catalog_factories.data_models.greenery.plant_percentage import PlantPercentage as HubPlantPercentage
|
||||||
from hub.catalog_factories.data_models.greenery.content import Content as GreeneryContent
|
from hub.catalog_factories.data_models.greenery.content import Content as GreeneryContent
|
||||||
|
|
||||||
|
|
||||||
class GreeneryCatalog(Catalog):
|
class GreeneryCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Greenery catalog class
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
base_path = Path(Path(__file__).parent / 'ecore_greenery' / 'greenerycatalog_no_quantities.ecore')
|
base_path = Path(Path(__file__).parent / 'ecore_greenery/greenerycatalog_no_quantities.ecore').resolve()
|
||||||
resource_set = ResourceSet()
|
resource_set = ResourceSet()
|
||||||
data_model = resource_set.get_resource(URI(str(base_path)))
|
data_model = resource_set.get_resource(URI(str(base_path)))
|
||||||
data_model_root = data_model.contents[0]
|
data_model_root = data_model.contents[0]
|
||||||
resource_set.metamodel_registry[data_model_root.nsURI] = data_model_root
|
resource_set.metamodel_registry[data_model_root.nsURI] = data_model_root
|
||||||
resource = resource_set.get_resource(URI(str(path)))
|
resource = resource_set.get_resource(URI(str(path)))
|
||||||
catalog_data: gc = resource.contents[0]
|
catalog_data: Gc = resource.contents[0]
|
||||||
|
|
||||||
plants = []
|
plants = []
|
||||||
for plant_category in catalog_data.plantCategories:
|
for plant_category in catalog_data.plantCategories:
|
||||||
name = plant_category.name
|
name = plant_category.name
|
||||||
for plant in plant_category.plants:
|
for plant in plant_category.plants:
|
||||||
plants.append(libs_plant(name, plant))
|
plants.append(HubPlant(name, plant))
|
||||||
|
|
||||||
vegetations = []
|
vegetations = []
|
||||||
for vegetation_category in catalog_data.vegetationCategories:
|
for vegetation_category in catalog_data.vegetationCategories:
|
||||||
|
@ -45,17 +48,19 @@ class GreeneryCatalog(Catalog):
|
||||||
if plant.name == plant_percentage.plant.name:
|
if plant.name == plant_percentage.plant.name:
|
||||||
plant_category = plant.category
|
plant_category = plant.category
|
||||||
break
|
break
|
||||||
plant_percentages.append(libs_pp(plant_percentage.percentage, plant_category, plant_percentage.plant))
|
plant_percentages.append(
|
||||||
vegetations.append(libs_vegetation(name, vegetation, plant_percentages))
|
HubPlantPercentage(plant_percentage.percentage, plant_category, plant_percentage.plant)
|
||||||
|
)
|
||||||
|
vegetations.append(HubVegetation(name, vegetation, plant_percentages))
|
||||||
plants = []
|
plants = []
|
||||||
for plant_category in catalog_data.plantCategories:
|
for plant_category in catalog_data.plantCategories:
|
||||||
name = plant_category.name
|
name = plant_category.name
|
||||||
for plant in plant_category.plants:
|
for plant in plant_category.plants:
|
||||||
plants.append(libs_plant(name, plant))
|
plants.append(HubPlant(name, plant))
|
||||||
|
|
||||||
soils = []
|
soils = []
|
||||||
for soil in catalog_data.soils:
|
for soil in catalog_data.soils:
|
||||||
soils.append(libs_soil(soil))
|
soils.append(HubSoil(soil))
|
||||||
|
|
||||||
self._content = GreeneryContent(vegetations, plants, soils)
|
self._content = GreeneryContent(vegetations, plants, soils)
|
||||||
|
|
||||||
|
@ -103,14 +108,15 @@ class GreeneryCatalog(Catalog):
|
||||||
raise IndexError(f"{name} doesn't exists in the catalog")
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
||||||
|
|
||||||
def entries(self, category=None):
|
def entries(self, category=None):
|
||||||
|
"""
|
||||||
|
Get all entries from the greenery catalog optionally filtered by category
|
||||||
|
"""
|
||||||
if category is None:
|
if category is None:
|
||||||
return self._content
|
return self._content
|
||||||
else:
|
if category.lower() == 'vegetations':
|
||||||
if category.lower() == 'vegetations':
|
return self._content.vegetations
|
||||||
return self._content.vegetations
|
if category.lower() == 'plants':
|
||||||
elif category.lower() == 'plants':
|
return self._content.plants
|
||||||
return self._content.plants
|
if category.lower() == 'soils':
|
||||||
elif category.lower() == 'soils':
|
return self._content.soils
|
||||||
return self._content.soils
|
raise ValueError(f'Unknown category [{category}]')
|
||||||
else:
|
|
||||||
raise ValueError(f'Unknown category [{category}]')
|
|
||||||
|
|
|
@ -4,12 +4,12 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
import logging
|
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
from hub.catalog_factories.greenery.greenery_catalog import GreeneryCatalog
|
from hub.catalog_factories.greenery.greenery_catalog import GreeneryCatalog
|
||||||
from hub.helpers.utils import validate_import_export_type
|
|
||||||
Catalog = TypeVar('Catalog')
|
Catalog = TypeVar('Catalog')
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,9 +19,8 @@ class GreeneryCatalogFactory:
|
||||||
"""
|
"""
|
||||||
def __init__(self, handler, base_path=None):
|
def __init__(self, handler, base_path=None):
|
||||||
if base_path is None:
|
if base_path is None:
|
||||||
base_path = Path(Path(__file__).parent.parent / 'data/greenery')
|
base_path = (Path(__file__).parent.parent / 'data/greenery').resolve()
|
||||||
self._handler = '_' + handler.lower()
|
self._handler = '_' + handler.lower()
|
||||||
class_funcs = validate_import_export_type(GreeneryCatalogFactory, handler)
|
|
||||||
self._path = base_path
|
self._path = base_path
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
0
hub/catalog_factories/usage/__init__.py
Normal file
0
hub/catalog_factories/usage/__init__.py
Normal file
|
@ -14,7 +14,7 @@ from hub.catalog_factories.catalog import Catalog
|
||||||
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
||||||
from hub.catalog_factories.data_models.usages.content import Content
|
from hub.catalog_factories.data_models.usages.content import Content
|
||||||
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
||||||
from hub.catalog_factories.data_models.usages.ocupancy import Occupancy
|
from hub.catalog_factories.data_models.usages.occupancy import Occupancy
|
||||||
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
|
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
|
||||||
from hub.catalog_factories.data_models.usages.schedule import Schedule
|
from hub.catalog_factories.data_models.usages.schedule import Schedule
|
||||||
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
||||||
|
@ -24,13 +24,15 @@ from hub.helpers.configuration_helper import ConfigurationHelper as ch
|
||||||
|
|
||||||
|
|
||||||
class ComnetCatalog(Catalog):
|
class ComnetCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Comnet catalog class
|
||||||
|
"""
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
self._comnet_archetypes_path = str(path / 'comnet_archetypes.xlsx')
|
self._comnet_archetypes_path = str(path / 'comnet_archetypes.xlsx')
|
||||||
self._comnet_schedules_path = str(path / 'comnet_schedules_archetypes.xlsx')
|
self._comnet_schedules_path = str(path / 'comnet_schedules_archetypes.xlsx')
|
||||||
self._archetypes = self._read_archetype_file()
|
self._archetypes = self._read_archetype_file()
|
||||||
self._schedules = self._read_schedules_file()
|
self._schedules = self._read_schedules_file()
|
||||||
|
|
||||||
# todo: comment with @Guille, this hypotheses should go in the import factory?
|
|
||||||
sensible_convective = ch().comnet_occupancy_sensible_convective
|
sensible_convective = ch().comnet_occupancy_sensible_convective
|
||||||
sensible_radiative = ch().comnet_occupancy_sensible_radiant
|
sensible_radiative = ch().comnet_occupancy_sensible_radiant
|
||||||
lighting_convective = ch().comnet_lighting_convective
|
lighting_convective = ch().comnet_lighting_convective
|
||||||
|
@ -148,13 +150,13 @@ class ComnetCatalog(Catalog):
|
||||||
if day == cte.SATURDAY:
|
if day == cte.SATURDAY:
|
||||||
start = start + 1
|
start = start + 1
|
||||||
end = end + 1
|
end = end + 1
|
||||||
elif day == cte.SUNDAY or day == cte.HOLIDAY:
|
elif day in (cte.SUNDAY, cte.HOLIDAY):
|
||||||
start = start + 2
|
start = start + 2
|
||||||
end = end + 2
|
end = end + 2
|
||||||
_schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0]
|
_schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0]
|
||||||
_schedule = []
|
_schedule = []
|
||||||
for day in _schedule_values:
|
for day in _schedule_values:
|
||||||
if schedule_name == 'ClgSetPt' or schedule_name == 'HtgSetPt' or schedule_name == 'WtrHtrSetPt':
|
if schedule_name in ('ClgSetPt', 'HtgSetPt', 'WtrHtrSetPt'):
|
||||||
# to celsius
|
# to celsius
|
||||||
if 'n.a.' in _schedule_values[day]:
|
if 'n.a.' in _schedule_values[day]:
|
||||||
_schedule_values[day] = None
|
_schedule_values[day] = None
|
||||||
|
@ -188,14 +190,14 @@ class ComnetCatalog(Catalog):
|
||||||
schedules_key = {}
|
schedules_key = {}
|
||||||
for j in range(0, number_usage_types-1):
|
for j in range(0, number_usage_types-1):
|
||||||
usage_parameters = _extracted_data.iloc[j]
|
usage_parameters = _extracted_data.iloc[j]
|
||||||
usage_type = usage_parameters[0]
|
usage_type = usage_parameters.iloc[0]
|
||||||
lighting_data[usage_type] = usage_parameters[1:6].values.tolist()
|
lighting_data[usage_type] = usage_parameters.iloc[1:6].values.tolist()
|
||||||
plug_loads_data[usage_type] = usage_parameters[8:13].values.tolist()
|
plug_loads_data[usage_type] = usage_parameters.iloc[8:13].values.tolist()
|
||||||
occupancy_data[usage_type] = usage_parameters[17:20].values.tolist()
|
occupancy_data[usage_type] = usage_parameters.iloc[17:20].values.tolist()
|
||||||
ventilation_rate[usage_type] = usage_parameters[20:21].item()
|
ventilation_rate[usage_type] = usage_parameters.iloc[20:21].item()
|
||||||
water_heating[usage_type] = usage_parameters[23:24].item()
|
water_heating[usage_type] = usage_parameters.iloc[23:24].item()
|
||||||
process_data[usage_type] = usage_parameters[24:26].values.tolist()
|
process_data[usage_type] = usage_parameters.iloc[24:26].values.tolist()
|
||||||
schedules_key[usage_type] = usage_parameters[27:28].item()
|
schedules_key[usage_type] = usage_parameters.iloc[27:28].item()
|
||||||
|
|
||||||
return {'lighting': lighting_data,
|
return {'lighting': lighting_data,
|
||||||
'plug loads': plug_loads_data,
|
'plug loads': plug_loads_data,
|
||||||
|
|
234
hub/catalog_factories/usage/eilat_catalog.py
Normal file
234
hub/catalog_factories/usage/eilat_catalog.py
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
"""
|
||||||
|
Eilat usage catalog
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
import io
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
from hub.catalog_factories.catalog import Catalog
|
||||||
|
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
||||||
|
from hub.catalog_factories.data_models.usages.content import Content
|
||||||
|
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
||||||
|
from hub.catalog_factories.data_models.usages.occupancy import Occupancy
|
||||||
|
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
|
||||||
|
from hub.catalog_factories.data_models.usages.schedule import Schedule
|
||||||
|
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
||||||
|
from hub.catalog_factories.data_models.usages.usage import Usage
|
||||||
|
from hub.catalog_factories.usage.usage_helper import UsageHelper
|
||||||
|
from hub.helpers.configuration_helper import ConfigurationHelper as ch
|
||||||
|
|
||||||
|
|
||||||
|
class EilatCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Eilat catalog class
|
||||||
|
"""
|
||||||
|
def __init__(self, path):
|
||||||
|
self._eilat_archetypes_path = str(path / 'eilat_archetypes.xlsx')
|
||||||
|
self._eilat_schedules_path = str(path / 'eilat_schedules_archetypes.xlsx')
|
||||||
|
self._archetypes = self._read_archetype_file()
|
||||||
|
self._schedules = self._read_schedules_file()
|
||||||
|
|
||||||
|
sensible_convective = ch().comnet_occupancy_sensible_convective
|
||||||
|
sensible_radiative = ch().comnet_occupancy_sensible_radiant
|
||||||
|
lighting_convective = ch().comnet_lighting_convective
|
||||||
|
lighting_radiative = ch().comnet_lighting_radiant
|
||||||
|
lighting_latent = ch().comnet_lighting_latent
|
||||||
|
appliances_convective = ch().comnet_plugs_convective
|
||||||
|
appliances_radiative = ch().comnet_plugs_radiant
|
||||||
|
appliances_latent = ch().comnet_plugs_latent
|
||||||
|
|
||||||
|
usages = []
|
||||||
|
for schedule_key in self._archetypes['schedules_key']:
|
||||||
|
eilat_usage = schedule_key
|
||||||
|
schedule_name = self._archetypes['schedules_key'][schedule_key]
|
||||||
|
hours_day = None
|
||||||
|
days_year = None
|
||||||
|
occupancy_archetype = self._archetypes['occupancy'][eilat_usage]
|
||||||
|
lighting_archetype = self._archetypes['lighting'][eilat_usage]
|
||||||
|
appliances_archetype = self._archetypes['plug loads'][eilat_usage]
|
||||||
|
mechanical_air_change = None # eilat provides ventilation rate only
|
||||||
|
ventilation_rate = self._archetypes['ventilation rate'][eilat_usage]
|
||||||
|
# convert cfm/ft2 to m3/m2.s
|
||||||
|
ventilation_rate = ventilation_rate / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
|
||||||
|
domestic_hot_water_archetype = self._archetypes['water heating'][eilat_usage]
|
||||||
|
|
||||||
|
# get occupancy
|
||||||
|
occupancy_density = occupancy_archetype[0] / pow(cte.METERS_TO_FEET, 2)
|
||||||
|
sensible_heat_gain = occupancy_archetype[1] * cte.BTU_H_TO_WATTS
|
||||||
|
latent_heat_gain = occupancy_archetype[1] * cte.BTU_H_TO_WATTS
|
||||||
|
if occupancy_density != 0:
|
||||||
|
occupancy_density = 1 / occupancy_density
|
||||||
|
sensible_convective_internal_gain = occupancy_density * sensible_heat_gain * sensible_convective
|
||||||
|
sensible_radiative_internal_gain = occupancy_density * sensible_heat_gain * sensible_radiative
|
||||||
|
latent_internal_gain = occupancy_density * latent_heat_gain
|
||||||
|
occupancy = Occupancy(occupancy_density,
|
||||||
|
sensible_convective_internal_gain,
|
||||||
|
sensible_radiative_internal_gain,
|
||||||
|
latent_internal_gain,
|
||||||
|
self._schedules[schedule_name]['Occupancy'])
|
||||||
|
|
||||||
|
# get lighting
|
||||||
|
density = lighting_archetype[4] * pow(cte.METERS_TO_FEET, 2)
|
||||||
|
lighting = Lighting(density,
|
||||||
|
lighting_convective,
|
||||||
|
lighting_radiative,
|
||||||
|
lighting_latent,
|
||||||
|
self._schedules[schedule_name]['Lights'])
|
||||||
|
|
||||||
|
# get appliances
|
||||||
|
density = appliances_archetype[0]
|
||||||
|
if density == 'n.a.':
|
||||||
|
density = 0
|
||||||
|
# convert W/ft2 to W/m2
|
||||||
|
density = float(density) * pow(cte.METERS_TO_FEET, 2)
|
||||||
|
appliances = Appliances(density,
|
||||||
|
appliances_convective,
|
||||||
|
appliances_radiative,
|
||||||
|
appliances_latent,
|
||||||
|
self._schedules[schedule_name]['Receptacle'])
|
||||||
|
|
||||||
|
# get thermal control
|
||||||
|
thermal_control = ThermalControl(None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
self._schedules[schedule_name]['HVAC Avail'],
|
||||||
|
self._schedules[schedule_name]['HtgSetPt'],
|
||||||
|
self._schedules[schedule_name]['ClgSetPt']
|
||||||
|
)
|
||||||
|
|
||||||
|
# get domestic hot water
|
||||||
|
density = domestic_hot_water_archetype
|
||||||
|
# convert Btu/h/occ to W/m2
|
||||||
|
density = float(density) * cte.BTU_H_TO_WATTS * occupancy_density
|
||||||
|
domestic_hot_water_service_temperature = self._schedules[schedule_name]['WtrHtrSetPt'][0].values[0]
|
||||||
|
domestic_hot_water = DomesticHotWater(density,
|
||||||
|
None,
|
||||||
|
domestic_hot_water_service_temperature,
|
||||||
|
self._schedules[schedule_name]['Service Hot Water']
|
||||||
|
)
|
||||||
|
usages.append(Usage(eilat_usage,
|
||||||
|
hours_day,
|
||||||
|
days_year,
|
||||||
|
mechanical_air_change,
|
||||||
|
ventilation_rate,
|
||||||
|
occupancy,
|
||||||
|
lighting,
|
||||||
|
appliances,
|
||||||
|
thermal_control,
|
||||||
|
domestic_hot_water))
|
||||||
|
|
||||||
|
self._content = Content(usages)
|
||||||
|
|
||||||
|
def _read_schedules_file(self) -> Dict:
|
||||||
|
dictionary = {}
|
||||||
|
eilat_usages = UsageHelper().eilat_schedules_key_to_eilat_schedules
|
||||||
|
eilat_days = UsageHelper().comnet_days
|
||||||
|
eilat_data_types = UsageHelper().comnet_data_type_to_hub_data_type
|
||||||
|
for usage_name in eilat_usages:
|
||||||
|
with open(self._eilat_schedules_path, 'rb') as xls:
|
||||||
|
_extracted_data = pd.read_excel(
|
||||||
|
io.BytesIO(xls.read()),
|
||||||
|
sheet_name=eilat_usages[usage_name],
|
||||||
|
skiprows=[0, 1, 2, 3], nrows=39, usecols="A:AA"
|
||||||
|
)
|
||||||
|
_schedules = {}
|
||||||
|
for row in range(0, 39, 3):
|
||||||
|
_schedule_values = {}
|
||||||
|
schedule_name = _extracted_data.loc[row:row, 'Description'].item()
|
||||||
|
schedule_data_type = eilat_data_types[_extracted_data.loc[row:row, 'Type'].item()]
|
||||||
|
for day in eilat_days:
|
||||||
|
# Monday to Friday
|
||||||
|
start = row
|
||||||
|
end = row + 1
|
||||||
|
if day == cte.FRIDAY:
|
||||||
|
start = start + 1
|
||||||
|
end = end + 1
|
||||||
|
elif day in (cte.SATURDAY, cte.HOLIDAY):
|
||||||
|
start = start + 2
|
||||||
|
end = end + 2
|
||||||
|
_schedule_values[day] = _extracted_data.iloc[start:end, 3:27].to_numpy().tolist()[0]
|
||||||
|
_schedule = []
|
||||||
|
for day in _schedule_values:
|
||||||
|
if schedule_name in ('ClgSetPt', 'HtgSetPt', 'WtrHtrSetPt'):
|
||||||
|
# to celsius
|
||||||
|
if 'n.a.' in _schedule_values[day]:
|
||||||
|
_schedule_values[day] = None
|
||||||
|
else:
|
||||||
|
_schedule_values[day] = [(float(value)-32)*5/9 for value in _schedule_values[day]]
|
||||||
|
_schedule.append(Schedule(schedule_name, _schedule_values[day], schedule_data_type, cte.HOUR, cte.DAY, [day]))
|
||||||
|
_schedules[schedule_name] = _schedule
|
||||||
|
dictionary[usage_name] = _schedules
|
||||||
|
return dictionary
|
||||||
|
|
||||||
|
def _read_archetype_file(self) -> Dict:
|
||||||
|
"""
|
||||||
|
reads xlsx files containing usage information into a dictionary
|
||||||
|
:return : Dict
|
||||||
|
"""
|
||||||
|
number_usage_types = 3
|
||||||
|
with open(self._eilat_archetypes_path, 'rb') as xls:
|
||||||
|
_extracted_data = pd.read_excel(
|
||||||
|
io.BytesIO(xls.read()),
|
||||||
|
sheet_name="Modeling Data",
|
||||||
|
skiprows=[0, 1, 2],
|
||||||
|
nrows=number_usage_types + 1, usecols="A:AB"
|
||||||
|
)
|
||||||
|
|
||||||
|
lighting_data = {}
|
||||||
|
plug_loads_data = {}
|
||||||
|
occupancy_data = {}
|
||||||
|
ventilation_rate = {}
|
||||||
|
water_heating = {}
|
||||||
|
process_data = {}
|
||||||
|
schedules_key = {}
|
||||||
|
for j in range(0, number_usage_types):
|
||||||
|
usage_parameters = _extracted_data.iloc[j]
|
||||||
|
usage_type = usage_parameters.iloc[0]
|
||||||
|
lighting_data[usage_type] = usage_parameters[1:6].values.tolist()
|
||||||
|
plug_loads_data[usage_type] = usage_parameters[8:13].values.tolist()
|
||||||
|
occupancy_data[usage_type] = usage_parameters[17:20].values.tolist()
|
||||||
|
ventilation_rate[usage_type] = usage_parameters[20:21].item()
|
||||||
|
water_heating[usage_type] = usage_parameters[23:24].item()
|
||||||
|
process_data[usage_type] = usage_parameters[24:26].values.tolist()
|
||||||
|
schedules_key[usage_type] = usage_parameters[27:28].item()
|
||||||
|
|
||||||
|
return {'lighting': lighting_data,
|
||||||
|
'plug loads': plug_loads_data,
|
||||||
|
'occupancy': occupancy_data,
|
||||||
|
'ventilation rate': ventilation_rate,
|
||||||
|
'water heating': water_heating,
|
||||||
|
'process': process_data,
|
||||||
|
'schedules_key': schedules_key
|
||||||
|
}
|
||||||
|
|
||||||
|
def names(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements names
|
||||||
|
:parm: for usage catalog category filter does nothing as there is only one category (usages)
|
||||||
|
"""
|
||||||
|
_names = {'usages': []}
|
||||||
|
for usage in self._content.usages:
|
||||||
|
_names['usages'].append(usage.name)
|
||||||
|
return _names
|
||||||
|
|
||||||
|
def entries(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements
|
||||||
|
:parm: for usage catalog category filter does nothing as there is only one category (usages)
|
||||||
|
"""
|
||||||
|
return self._content
|
||||||
|
|
||||||
|
def get_entry(self, name):
|
||||||
|
"""
|
||||||
|
Get one catalog element by names
|
||||||
|
:parm: entry name
|
||||||
|
"""
|
||||||
|
for usage in self._content.usages:
|
||||||
|
if usage.name.lower() == name.lower():
|
||||||
|
return usage
|
||||||
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -8,6 +8,8 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import xmltodict
|
import xmltodict
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
|
@ -15,7 +17,7 @@ from hub.catalog_factories.catalog import Catalog
|
||||||
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
||||||
from hub.catalog_factories.data_models.usages.content import Content
|
from hub.catalog_factories.data_models.usages.content import Content
|
||||||
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
||||||
from hub.catalog_factories.data_models.usages.ocupancy import Occupancy
|
from hub.catalog_factories.data_models.usages.occupancy import Occupancy
|
||||||
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
|
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
|
||||||
from hub.catalog_factories.data_models.usages.schedule import Schedule
|
from hub.catalog_factories.data_models.usages.schedule import Schedule
|
||||||
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
||||||
|
@ -24,13 +26,15 @@ from hub.catalog_factories.usage.usage_helper import UsageHelper
|
||||||
|
|
||||||
|
|
||||||
class NrcanCatalog(Catalog):
|
class NrcanCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Nrcan catalog class
|
||||||
|
"""
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
path = str(path / 'nrcan.xml')
|
self._schedules_path = Path(path / 'nrcan_schedules.json').resolve()
|
||||||
|
self._space_types_path = Path(path / 'nrcan_space_types.json').resolve()
|
||||||
|
self._space_compliance_path = Path(path / 'nrcan_space_compliance_2015.json').resolve()
|
||||||
self._content = None
|
self._content = None
|
||||||
self._schedules = {}
|
self._schedules = {}
|
||||||
with open(path) as xml:
|
|
||||||
self._metadata = xmltodict.parse(xml.read())
|
|
||||||
self._base_url = self._metadata['nrcan']['@base_url']
|
|
||||||
self._load_schedules()
|
self._load_schedules()
|
||||||
self._content = Content(self._load_archetypes())
|
self._content = Content(self._load_archetypes())
|
||||||
|
|
||||||
|
@ -52,11 +56,9 @@ class NrcanCatalog(Catalog):
|
||||||
return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types)
|
return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types)
|
||||||
|
|
||||||
def _load_schedules(self):
|
def _load_schedules(self):
|
||||||
usage = self._metadata['nrcan']
|
|
||||||
url = f'{self._base_url}{usage["schedules"]}'
|
|
||||||
_schedule_types = []
|
_schedule_types = []
|
||||||
with urllib.request.urlopen(url) as json_file:
|
with open(self._schedules_path, 'r') as f:
|
||||||
schedules_type = json.load(json_file)
|
schedules_type = json.load(f)
|
||||||
for schedule_type in schedules_type['tables']['schedules']['table']:
|
for schedule_type in schedules_type['tables']['schedules']['table']:
|
||||||
schedule = NrcanCatalog._extract_schedule(schedule_type)
|
schedule = NrcanCatalog._extract_schedule(schedule_type)
|
||||||
if schedule_type['name'] not in _schedule_types:
|
if schedule_type['name'] not in _schedule_types:
|
||||||
|
@ -70,19 +72,18 @@ class NrcanCatalog(Catalog):
|
||||||
self._schedules[schedule_type['name']] = _schedules
|
self._schedules[schedule_type['name']] = _schedules
|
||||||
|
|
||||||
def _get_schedules(self, name):
|
def _get_schedules(self, name):
|
||||||
|
schedule = None
|
||||||
if name in self._schedules:
|
if name in self._schedules:
|
||||||
return self._schedules[name]
|
schedule = self._schedules[name]
|
||||||
|
return schedule
|
||||||
|
|
||||||
def _load_archetypes(self):
|
def _load_archetypes(self):
|
||||||
usages = []
|
usages = []
|
||||||
name = self._metadata['nrcan']
|
with open(self._space_types_path, 'r') as f:
|
||||||
url_1 = f'{self._base_url}{name["space_types"]}'
|
space_types = json.load(f)['tables']['space_types']['table']
|
||||||
url_2 = f'{self._base_url}{name["space_types_compliance"]}'
|
|
||||||
with urllib.request.urlopen(url_1) as json_file:
|
|
||||||
space_types = json.load(json_file)['tables']['space_types']['table']
|
|
||||||
space_types = [st for st in space_types if st['space_type'] == 'WholeBuilding']
|
space_types = [st for st in space_types if st['space_type'] == 'WholeBuilding']
|
||||||
with urllib.request.urlopen(url_2) as json_file:
|
with open(self._space_compliance_path, 'r') as f:
|
||||||
space_types_compliance = json.load(json_file)['tables']['space_compliance']['table']
|
space_types_compliance = json.load(f)['tables']['space_compliance']['table']
|
||||||
space_types_compliance = [st for st in space_types_compliance if st['space_type'] == 'WholeBuilding']
|
space_types_compliance = [st for st in space_types_compliance if st['space_type'] == 'WholeBuilding']
|
||||||
space_types_dictionary = {}
|
space_types_dictionary = {}
|
||||||
for space_type in space_types_compliance:
|
for space_type in space_types_compliance:
|
||||||
|
@ -94,7 +95,10 @@ class NrcanCatalog(Catalog):
|
||||||
# W/m2
|
# W/m2
|
||||||
appliances_density = space_type['electric_equipment_per_area_w_per_m2']
|
appliances_density = space_type['electric_equipment_per_area_w_per_m2']
|
||||||
# peak flow in gallons/h/m2
|
# peak flow in gallons/h/m2
|
||||||
domestic_hot_water_peak_flow = space_type['service_water_heating_peak_flow_per_area'] * cte.GALLONS_TO_QUBIC_METERS / cte.HOUR_TO_SECONDS
|
domestic_hot_water_peak_flow = (
|
||||||
|
space_type['service_water_heating_peak_flow_per_area'] *
|
||||||
|
cte.GALLONS_TO_QUBIC_METERS / cte.HOUR_TO_SECONDS
|
||||||
|
)
|
||||||
space_types_dictionary[usage_type] = {'occupancy_per_area': occupancy_density,
|
space_types_dictionary[usage_type] = {'occupancy_per_area': occupancy_density,
|
||||||
'lighting_per_area': lighting_density,
|
'lighting_per_area': lighting_density,
|
||||||
'electric_equipment_per_area': appliances_density,
|
'electric_equipment_per_area': appliances_density,
|
||||||
|
@ -126,8 +130,8 @@ class NrcanCatalog(Catalog):
|
||||||
hvac_availability = self._get_schedules(hvac_schedule_name)
|
hvac_availability = self._get_schedules(hvac_schedule_name)
|
||||||
domestic_hot_water_load_schedule = self._get_schedules(domestic_hot_water_schedule_name)
|
domestic_hot_water_load_schedule = self._get_schedules(domestic_hot_water_schedule_name)
|
||||||
|
|
||||||
# ACH
|
# ACH -> 1/s
|
||||||
mechanical_air_change = space_type['ventilation_air_changes']
|
mechanical_air_change = space_type['ventilation_air_changes'] / cte.HOUR_TO_SECONDS
|
||||||
# cfm/ft2 to m3/m2.s
|
# cfm/ft2 to m3/m2.s
|
||||||
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
|
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
|
||||||
# cfm/person to m3/m2.s
|
# cfm/person to m3/m2.s
|
||||||
|
|
227
hub/catalog_factories/usage/palma_catalog.py
Normal file
227
hub/catalog_factories/usage/palma_catalog.py
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
"""
|
||||||
|
Palma usage catalog
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Cecilia Pérez cperez@irec.cat
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import xmltodict
|
||||||
|
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
from hub.catalog_factories.catalog import Catalog
|
||||||
|
from hub.catalog_factories.data_models.usages.appliances import Appliances
|
||||||
|
from hub.catalog_factories.data_models.usages.content import Content
|
||||||
|
from hub.catalog_factories.data_models.usages.lighting import Lighting
|
||||||
|
from hub.catalog_factories.data_models.usages.occupancy import Occupancy
|
||||||
|
from hub.catalog_factories.data_models.usages.domestic_hot_water import DomesticHotWater
|
||||||
|
from hub.catalog_factories.data_models.usages.schedule import Schedule
|
||||||
|
from hub.catalog_factories.data_models.usages.thermal_control import ThermalControl
|
||||||
|
from hub.catalog_factories.data_models.usages.usage import Usage
|
||||||
|
from hub.catalog_factories.usage.usage_helper import UsageHelper
|
||||||
|
|
||||||
|
|
||||||
|
class PalmaCatalog(Catalog):
|
||||||
|
"""
|
||||||
|
Palma catalog class
|
||||||
|
"""
|
||||||
|
def __init__(self, path):
|
||||||
|
self._schedules_path = Path(path / 'palma_schedules.json').resolve()
|
||||||
|
self._space_types_path = Path(path / 'palma_space_types.json').resolve()
|
||||||
|
self._space_compliance_path = Path(path / 'palma_space_compliance.json').resolve()
|
||||||
|
self._content = None
|
||||||
|
self._schedules = {}
|
||||||
|
self._load_schedules()
|
||||||
|
self._content = Content(self._load_archetypes())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _extract_schedule(raw):
|
||||||
|
nrcan_schedule_type = raw['category']
|
||||||
|
if 'Heating' in raw['name'] and 'Water' not in raw['name']:
|
||||||
|
nrcan_schedule_type = f'{nrcan_schedule_type} Heating'
|
||||||
|
elif 'Cooling' in raw['name']:
|
||||||
|
nrcan_schedule_type = f'{nrcan_schedule_type} Cooling'
|
||||||
|
if nrcan_schedule_type not in UsageHelper().nrcan_schedule_type_to_hub_schedule_type:
|
||||||
|
return None
|
||||||
|
hub_type = UsageHelper().nrcan_schedule_type_to_hub_schedule_type[nrcan_schedule_type]
|
||||||
|
data_type = UsageHelper().nrcan_data_type_to_hub_data_type[raw['units']]
|
||||||
|
time_step = UsageHelper().nrcan_time_to_hub_time[raw['type']]
|
||||||
|
# nrcan only uses daily range for the schedules
|
||||||
|
time_range = cte.DAY
|
||||||
|
day_types = UsageHelper().nrcan_day_type_to_hub_days[raw['day_types']]
|
||||||
|
return Schedule(hub_type, raw['values'], data_type, time_step, time_range, day_types)
|
||||||
|
|
||||||
|
def _load_schedules(self):
|
||||||
|
_schedule_types = []
|
||||||
|
with open(self._schedules_path, 'r') as f:
|
||||||
|
schedules_type = json.load(f)
|
||||||
|
for schedule_type in schedules_type['tables']['schedules']['table']:
|
||||||
|
schedule = PalmaCatalog._extract_schedule(schedule_type)
|
||||||
|
if schedule_type['name'] not in _schedule_types:
|
||||||
|
_schedule_types.append(schedule_type['name'])
|
||||||
|
if schedule is not None:
|
||||||
|
self._schedules[schedule_type['name']] = [schedule]
|
||||||
|
else:
|
||||||
|
if schedule is not None:
|
||||||
|
_schedules = self._schedules[schedule_type['name']]
|
||||||
|
_schedules.append(schedule)
|
||||||
|
self._schedules[schedule_type['name']] = _schedules
|
||||||
|
|
||||||
|
def _get_schedules(self, name):
|
||||||
|
schedule = None
|
||||||
|
if name in self._schedules:
|
||||||
|
schedule = self._schedules[name]
|
||||||
|
return schedule
|
||||||
|
|
||||||
|
def _load_archetypes(self):
|
||||||
|
usages = []
|
||||||
|
with open(self._space_types_path, 'r') as f:
|
||||||
|
space_types = json.load(f)['tables']['space_types']['table']
|
||||||
|
space_types = [st for st in space_types if st['space_type'] == 'WholeBuilding']
|
||||||
|
with open(self._space_compliance_path, 'r') as f:
|
||||||
|
space_types_compliance = json.load(f)['tables']['space_compliance']['table']
|
||||||
|
space_types_compliance = [st for st in space_types_compliance if st['space_type'] == 'WholeBuilding']
|
||||||
|
space_types_dictionary = {}
|
||||||
|
for space_type in space_types_compliance:
|
||||||
|
usage_type = space_type['building_type']
|
||||||
|
# people/m2
|
||||||
|
occupancy_density = space_type['occupancy_per_area_people_per_m2']
|
||||||
|
# W/m2
|
||||||
|
lighting_density = space_type['lighting_per_area_w_per_m2']
|
||||||
|
# W/m2
|
||||||
|
appliances_density = space_type['electric_equipment_per_area_w_per_m2']
|
||||||
|
# peak flow in gallons/h/m2
|
||||||
|
domestic_hot_water_peak_flow = (
|
||||||
|
space_type['service_water_heating_peak_flow_per_area'] *
|
||||||
|
cte.GALLONS_TO_QUBIC_METERS / cte.HOUR_TO_SECONDS
|
||||||
|
)
|
||||||
|
space_types_dictionary[usage_type] = {'occupancy_per_area': occupancy_density,
|
||||||
|
'lighting_per_area': lighting_density,
|
||||||
|
'electric_equipment_per_area': appliances_density,
|
||||||
|
'service_water_heating_peak_flow_per_area': domestic_hot_water_peak_flow
|
||||||
|
}
|
||||||
|
|
||||||
|
for space_type in space_types:
|
||||||
|
usage_type = space_type['building_type']
|
||||||
|
space_type_compliance = space_types_dictionary[usage_type]
|
||||||
|
occupancy_density = space_type_compliance['occupancy_per_area']
|
||||||
|
sensible_convective_internal_gain = space_type['sensible_convective_internal_gain']
|
||||||
|
sensible_radiative_internal_gain = space_type['sensible_radiative_internal_gain']
|
||||||
|
latent_internal_gain = space_type['latent_internal_gain']
|
||||||
|
lighting_density = space_type_compliance['lighting_per_area']
|
||||||
|
appliances_density = space_type_compliance['electric_equipment_per_area']
|
||||||
|
domestic_hot_water_peak_flow = space_type_compliance['service_water_heating_peak_flow_per_area']
|
||||||
|
|
||||||
|
occupancy_schedule_name = space_type['occupancy_schedule']
|
||||||
|
lighting_schedule_name = space_type['lighting_schedule']
|
||||||
|
appliance_schedule_name = space_type['electric_equipment_schedule']
|
||||||
|
hvac_schedule_name = space_type['exhaust_schedule']
|
||||||
|
if hvac_schedule_name and 'FAN' in hvac_schedule_name:
|
||||||
|
hvac_schedule_name = hvac_schedule_name.replace('FAN', 'Fan')
|
||||||
|
if not hvac_schedule_name:
|
||||||
|
hvac_schedule_name = 'default_HVAC_schedule'
|
||||||
|
heating_setpoint_schedule_name = space_type['heating_setpoint_schedule']
|
||||||
|
cooling_setpoint_schedule_name = space_type['cooling_setpoint_schedule']
|
||||||
|
domestic_hot_water_schedule_name = space_type['service_water_heating_schedule']
|
||||||
|
occupancy_schedule = self._get_schedules(occupancy_schedule_name)
|
||||||
|
lighting_schedule = self._get_schedules(lighting_schedule_name)
|
||||||
|
appliance_schedule = self._get_schedules(appliance_schedule_name)
|
||||||
|
heating_schedule = self._get_schedules(heating_setpoint_schedule_name)
|
||||||
|
cooling_schedule = self._get_schedules(cooling_setpoint_schedule_name)
|
||||||
|
hvac_availability = self._get_schedules(hvac_schedule_name)
|
||||||
|
domestic_hot_water_load_schedule = self._get_schedules(domestic_hot_water_schedule_name)
|
||||||
|
|
||||||
|
# ACH -> 1/s
|
||||||
|
mechanical_air_change = space_type['ventilation_air_changes'] / cte.HOUR_TO_SECONDS
|
||||||
|
# cfm/ft2 to m3/m2.s
|
||||||
|
ventilation_rate = space_type['ventilation_per_area'] / (cte.METERS_TO_FEET * cte.MINUTES_TO_SECONDS)
|
||||||
|
# cfm/person to m3/m2.s
|
||||||
|
ventilation_rate += space_type['ventilation_per_person'] / (
|
||||||
|
pow(cte.METERS_TO_FEET, 3) * cte.MINUTES_TO_SECONDS
|
||||||
|
) * occupancy_density
|
||||||
|
|
||||||
|
lighting_radiative_fraction = space_type['lighting_fraction_radiant']
|
||||||
|
lighting_convective_fraction = 0
|
||||||
|
if lighting_radiative_fraction is not None:
|
||||||
|
lighting_convective_fraction = 1 - lighting_radiative_fraction
|
||||||
|
lighting_latent_fraction = 0
|
||||||
|
appliances_radiative_fraction = space_type['electric_equipment_fraction_radiant']
|
||||||
|
appliances_latent_fraction = space_type['electric_equipment_fraction_latent']
|
||||||
|
appliances_convective_fraction = 0
|
||||||
|
if appliances_radiative_fraction is not None and appliances_latent_fraction is not None:
|
||||||
|
appliances_convective_fraction = 1 - appliances_radiative_fraction - appliances_latent_fraction
|
||||||
|
|
||||||
|
domestic_hot_water_service_temperature = space_type['service_water_heating_target_temperature']
|
||||||
|
|
||||||
|
occupancy = Occupancy(occupancy_density,
|
||||||
|
sensible_convective_internal_gain,
|
||||||
|
sensible_radiative_internal_gain,
|
||||||
|
latent_internal_gain,
|
||||||
|
occupancy_schedule)
|
||||||
|
lighting = Lighting(lighting_density,
|
||||||
|
lighting_convective_fraction,
|
||||||
|
lighting_radiative_fraction,
|
||||||
|
lighting_latent_fraction,
|
||||||
|
lighting_schedule)
|
||||||
|
appliances = Appliances(appliances_density,
|
||||||
|
appliances_convective_fraction,
|
||||||
|
appliances_radiative_fraction,
|
||||||
|
appliances_latent_fraction,
|
||||||
|
appliance_schedule)
|
||||||
|
thermal_control = ThermalControl(None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
hvac_availability,
|
||||||
|
heating_schedule,
|
||||||
|
cooling_schedule)
|
||||||
|
domestic_hot_water = DomesticHotWater(None,
|
||||||
|
domestic_hot_water_peak_flow,
|
||||||
|
domestic_hot_water_service_temperature,
|
||||||
|
domestic_hot_water_load_schedule)
|
||||||
|
|
||||||
|
hours_day = None
|
||||||
|
days_year = None
|
||||||
|
|
||||||
|
usages.append(Usage(usage_type,
|
||||||
|
hours_day,
|
||||||
|
days_year,
|
||||||
|
mechanical_air_change,
|
||||||
|
ventilation_rate,
|
||||||
|
occupancy,
|
||||||
|
lighting,
|
||||||
|
appliances,
|
||||||
|
thermal_control,
|
||||||
|
domestic_hot_water))
|
||||||
|
|
||||||
|
|
||||||
|
return usages
|
||||||
|
|
||||||
|
def names(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements names
|
||||||
|
:parm: for usage catalog category filter does nothing as there is only one category (usages)
|
||||||
|
"""
|
||||||
|
_names = {'usages': []}
|
||||||
|
for usage in self._content.usages:
|
||||||
|
_names['usages'].append(usage.name)
|
||||||
|
return _names
|
||||||
|
|
||||||
|
def entries(self, category=None):
|
||||||
|
"""
|
||||||
|
Get the catalog elements
|
||||||
|
:parm: for usage catalog category filter does nothing as there is only one category (usages)
|
||||||
|
"""
|
||||||
|
return self._content
|
||||||
|
|
||||||
|
def get_entry(self, name):
|
||||||
|
"""
|
||||||
|
Get one catalog element by names
|
||||||
|
:parm: entry name
|
||||||
|
"""
|
||||||
|
for usage in self._content.usages:
|
||||||
|
if usage.name.lower() == name.lower():
|
||||||
|
return usage
|
||||||
|
raise IndexError(f"{name} doesn't exists in the catalog")
|
|
@ -4,10 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
import hub.helpers.constants as cte
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
|
import hub.helpers.constants as cte
|
||||||
|
|
||||||
|
|
||||||
class UsageHelper:
|
class UsageHelper:
|
||||||
"""
|
"""
|
||||||
|
@ -90,43 +90,64 @@ class UsageHelper:
|
||||||
'C-14 Gymnasium': 'C-14 Gymnasium'
|
'C-14 Gymnasium': 'C-14 Gymnasium'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_eilat_schedules_key_to_eilat_schedules = {
|
||||||
|
'C-12 Residential': 'C-12 Residential',
|
||||||
|
'C-15 Dormitory': 'C-15 Dormitory',
|
||||||
|
'C-16 Hotel employees': 'C-16 Hotel employees'
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nrcan_day_type_to_hub_days(self):
|
def nrcan_day_type_to_hub_days(self):
|
||||||
|
"""
|
||||||
|
Get a dictionary to convert nrcan day types to hub day types
|
||||||
|
"""
|
||||||
return self._nrcan_day_type_to_hub_days
|
return self._nrcan_day_type_to_hub_days
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nrcan_schedule_type_to_hub_schedule_type(self):
|
def nrcan_schedule_type_to_hub_schedule_type(self):
|
||||||
|
"""
|
||||||
|
Get a dictionary to convert nrcan schedule types to hub schedule types
|
||||||
|
"""
|
||||||
return self._nrcan_schedule_type_to_hub_schedule_type
|
return self._nrcan_schedule_type_to_hub_schedule_type
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nrcan_data_type_to_hub_data_type(self):
|
def nrcan_data_type_to_hub_data_type(self):
|
||||||
|
"""
|
||||||
|
Get a dictionary to convert nrcan data types to hub data types
|
||||||
|
"""
|
||||||
return self._nrcan_data_type_to_hub_data_type
|
return self._nrcan_data_type_to_hub_data_type
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nrcan_time_to_hub_time(self):
|
def nrcan_time_to_hub_time(self):
|
||||||
|
"""
|
||||||
|
Get a dictionary to convert nrcan time to hub time
|
||||||
|
"""
|
||||||
return self._nrcan_time_to_hub_time
|
return self._nrcan_time_to_hub_time
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def comnet_data_type_to_hub_data_type(self):
|
def comnet_data_type_to_hub_data_type(self) -> Dict:
|
||||||
|
"""
|
||||||
|
Get a dictionary to convert comnet data types to hub data types
|
||||||
|
"""
|
||||||
return self._comnet_data_type_to_hub_data_type
|
return self._comnet_data_type_to_hub_data_type
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def comnet_schedules_key_to_comnet_schedules(self) -> Dict:
|
def comnet_schedules_key_to_comnet_schedules(self) -> Dict:
|
||||||
|
"""
|
||||||
|
Get a dictionary to convert hub schedules to comnet schedules
|
||||||
|
"""
|
||||||
return self._comnet_schedules_key_to_comnet_schedules
|
return self._comnet_schedules_key_to_comnet_schedules
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def comnet_days(self):
|
def comnet_days(self) -> [str]:
|
||||||
|
"""
|
||||||
|
Get the list of days used in comnet
|
||||||
|
"""
|
||||||
return self._comnet_days
|
return self._comnet_days
|
||||||
|
|
||||||
@staticmethod
|
@property
|
||||||
def schedules_key(usage):
|
def eilat_schedules_key_to_eilat_schedules(self) -> [str]:
|
||||||
"""
|
"""
|
||||||
Get Comnet schedules key from the list found in the Comnet usage file
|
Get a dictionary to convert hub schedules to eilat schedules
|
||||||
:param usage: str
|
|
||||||
:return: str
|
|
||||||
"""
|
"""
|
||||||
try:
|
return self._eilat_schedules_key_to_eilat_schedules
|
||||||
return UsageHelper._comnet_schedules_key_to_comnet_schedules[usage]
|
|
||||||
except KeyError:
|
|
||||||
sys.stderr.write('Error: Comnet keyword not found. An update of the Comnet files might have been '
|
|
||||||
'done changing the keywords.\n')
|
|
||||||
|
|
|
@ -4,17 +4,23 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
import logging
|
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TypeVar
|
from typing import TypeVar
|
||||||
|
|
||||||
from hub.catalog_factories.usage.comnet_catalog import ComnetCatalog
|
from hub.catalog_factories.usage.comnet_catalog import ComnetCatalog
|
||||||
from hub.catalog_factories.usage.nrcan_catalog import NrcanCatalog
|
from hub.catalog_factories.usage.nrcan_catalog import NrcanCatalog
|
||||||
|
from hub.catalog_factories.usage.eilat_catalog import EilatCatalog
|
||||||
|
from hub.catalog_factories.usage.palma_catalog import PalmaCatalog
|
||||||
from hub.helpers.utils import validate_import_export_type
|
from hub.helpers.utils import validate_import_export_type
|
||||||
|
|
||||||
Catalog = TypeVar('Catalog')
|
Catalog = TypeVar('Catalog')
|
||||||
|
|
||||||
|
|
||||||
class UsageCatalogFactory:
|
class UsageCatalogFactory:
|
||||||
|
"""
|
||||||
|
Usage catalog factory class
|
||||||
|
"""
|
||||||
def __init__(self, handler, base_path=None):
|
def __init__(self, handler, base_path=None):
|
||||||
if base_path is None:
|
if base_path is None:
|
||||||
base_path = Path(Path(__file__).parent.parent / 'data/usage')
|
base_path = Path(Path(__file__).parent.parent / 'data/usage')
|
||||||
|
@ -37,6 +43,20 @@ class UsageCatalogFactory:
|
||||||
# nrcan retrieves the data directly from github
|
# nrcan retrieves the data directly from github
|
||||||
return NrcanCatalog(self._path)
|
return NrcanCatalog(self._path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _palma(self):
|
||||||
|
"""
|
||||||
|
Retrieve Palma catalog
|
||||||
|
"""
|
||||||
|
return PalmaCatalog(self._path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _eilat(self):
|
||||||
|
"""
|
||||||
|
Retrieve Eilat catalog
|
||||||
|
"""
|
||||||
|
return EilatCatalog(self._path)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def catalog(self) -> Catalog:
|
def catalog(self) -> Catalog:
|
||||||
"""
|
"""
|
||||||
|
|
0
hub/city_model_structure/__init__.py
Normal file
0
hub/city_model_structure/__init__.py
Normal file
0
hub/city_model_structure/attributes/__init__.py
Normal file
0
hub/city_model_structure/attributes/__init__.py
Normal file
|
@ -45,14 +45,13 @@ class Plane:
|
||||||
:return: (A, B, C, D)
|
:return: (A, B, C, D)
|
||||||
"""
|
"""
|
||||||
if self._equation is None:
|
if self._equation is None:
|
||||||
|
|
||||||
a = self.normal[0]
|
a = self.normal[0]
|
||||||
b = self.normal[1]
|
b = self.normal[1]
|
||||||
c = self.normal[2]
|
c = self.normal[2]
|
||||||
d = ((-1 * self.origin.coordinates[0]) * self.normal[0])
|
d = -1 * self.origin.coordinates[0] * self.normal[0]
|
||||||
d += ((-1 * self.origin.coordinates[1]) * self.normal[1])
|
d += -1 * self.origin.coordinates[1] * self.normal[1]
|
||||||
d += ((-1 * self.origin.coordinates[2]) * self.normal[2])
|
d += -1 * self.origin.coordinates[2] * self.normal[2]
|
||||||
self._equation = (a, b, c, d)
|
self._equation = a, b, c, d
|
||||||
return self._equation
|
return self._equation
|
||||||
|
|
||||||
def distance_to_point(self, point):
|
def distance_to_point(self, point):
|
||||||
|
|
|
@ -31,7 +31,7 @@ class Point:
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
power = 0
|
power = 0
|
||||||
for dimension in range(0, len(self.coordinates)):
|
for dimension in enumerate(self.coordinates):
|
||||||
power += math.pow(other_point.coordinates[dimension]-self.coordinates[dimension], 2)
|
power += math.pow(other_point.coordinates[dimension]-self.coordinates[dimension], 2)
|
||||||
distance = math.sqrt(power)
|
distance = math.sqrt(power)
|
||||||
return distance
|
return distance
|
||||||
|
|
|
@ -6,20 +6,21 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import sys
|
import sys
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from trimesh import Trimesh
|
|
||||||
import trimesh.intersections
|
|
||||||
import trimesh.creation
|
import trimesh.creation
|
||||||
import trimesh.geometry
|
import trimesh.geometry
|
||||||
|
import trimesh.intersections
|
||||||
from shapely.geometry.polygon import Polygon as shapley_polygon
|
from shapely.geometry.polygon import Polygon as shapley_polygon
|
||||||
|
from trimesh import Trimesh
|
||||||
|
|
||||||
from hub.city_model_structure.attributes.plane import Plane
|
from hub.city_model_structure.attributes.plane import Plane
|
||||||
from hub.city_model_structure.attributes.point import Point
|
from hub.city_model_structure.attributes.point import Point
|
||||||
import hub.helpers.constants as cte
|
|
||||||
|
|
||||||
|
|
||||||
class Polygon:
|
class Polygon:
|
||||||
|
@ -69,44 +70,6 @@ class Polygon:
|
||||||
"""
|
"""
|
||||||
return self._coordinates
|
return self._coordinates
|
||||||
|
|
||||||
def contains_point(self, point):
|
|
||||||
"""
|
|
||||||
Determines if the given point is contained by the current polygon
|
|
||||||
:return: boolean
|
|
||||||
"""
|
|
||||||
# fixme: This method doesn't seems to work.
|
|
||||||
n = len(self.vertices)
|
|
||||||
angle_sum = 0
|
|
||||||
for i in range(0, n):
|
|
||||||
vector_0 = self.vertices[i]
|
|
||||||
vector_1 = self.vertices[(i+1) % n]
|
|
||||||
# set to origin
|
|
||||||
vector_0[0] = vector_0[0] - point.coordinates[0]
|
|
||||||
vector_0[1] = vector_0[1] - point.coordinates[1]
|
|
||||||
vector_0[2] = vector_0[2] - point.coordinates[2]
|
|
||||||
vector_1[0] = vector_1[0] - point.coordinates[0]
|
|
||||||
vector_1[1] = vector_1[1] - point.coordinates[1]
|
|
||||||
vector_1[2] = vector_1[2] - point.coordinates[2]
|
|
||||||
module = np.linalg.norm(vector_0) * np.linalg.norm(vector_1)
|
|
||||||
|
|
||||||
scalar_product = np.dot(vector_0, vector_1)
|
|
||||||
angle = np.pi/2
|
|
||||||
if module != 0:
|
|
||||||
angle = abs(np.arcsin(scalar_product / module))
|
|
||||||
angle_sum += angle
|
|
||||||
return abs(angle_sum - math.pi*2) < cte.EPSILON
|
|
||||||
|
|
||||||
def contains_polygon(self, polygon):
|
|
||||||
"""
|
|
||||||
Determines if the given polygon is contained by the current polygon
|
|
||||||
:return: boolean
|
|
||||||
"""
|
|
||||||
|
|
||||||
for point in polygon.points:
|
|
||||||
if not self.contains_point(point):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def points_list(self) -> np.ndarray:
|
def points_list(self) -> np.ndarray:
|
||||||
"""
|
"""
|
||||||
|
@ -142,12 +105,12 @@ class Polygon:
|
||||||
if self._area is None:
|
if self._area is None:
|
||||||
self._area = 0
|
self._area = 0
|
||||||
for triangle in self.triangles:
|
for triangle in self.triangles:
|
||||||
ab = np.zeros(3)
|
a_b = np.zeros(3)
|
||||||
ac = np.zeros(3)
|
a_c = np.zeros(3)
|
||||||
for i in range(0, 3):
|
for i in range(0, 3):
|
||||||
ab[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
|
a_b[i] = triangle.coordinates[1][i] - triangle.coordinates[0][i]
|
||||||
ac[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
|
a_c[i] = triangle.coordinates[2][i] - triangle.coordinates[0][i]
|
||||||
self._area += np.linalg.norm(np.cross(ab, ac)) / 2
|
self._area += np.linalg.norm(np.cross(a_b, a_c)) / 2
|
||||||
return self._area
|
return self._area
|
||||||
|
|
||||||
@area.setter
|
@area.setter
|
||||||
|
@ -217,7 +180,11 @@ class Polygon:
|
||||||
return -alpha
|
return -alpha
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def triangle_mesh(vertices, normal):
|
def triangle_mesh(vertices, normal) -> Trimesh:
|
||||||
|
"""
|
||||||
|
Get the triangulated mesh for the polygon
|
||||||
|
:return: Trimesh
|
||||||
|
"""
|
||||||
min_x = 1e16
|
min_x = 1e16
|
||||||
min_y = 1e16
|
min_y = 1e16
|
||||||
min_z = 1e16
|
min_z = 1e16
|
||||||
|
@ -246,8 +213,7 @@ class Polygon:
|
||||||
polygon = shapley_polygon(coordinates)
|
polygon = shapley_polygon(coordinates)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
_, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
|
||||||
vertices_2d, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
|
|
||||||
|
|
||||||
mesh = Trimesh(vertices=vertices, faces=faces)
|
mesh = Trimesh(vertices=vertices, faces=faces)
|
||||||
|
|
||||||
|
@ -267,13 +233,17 @@ class Polygon:
|
||||||
return mesh
|
return mesh
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logging.error(f'Not able to triangulate polygon\n')
|
logging.error('Not able to triangulate polygon\n')
|
||||||
_vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
|
_vertices = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
|
||||||
_faces = [[0, 1, 2]]
|
_faces = [[0, 1, 2]]
|
||||||
return Trimesh(vertices=_vertices, faces=_faces)
|
return Trimesh(vertices=_vertices, faces=_faces)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def triangles(self) -> List[Polygon]:
|
def triangles(self) -> List[Polygon]:
|
||||||
|
"""
|
||||||
|
Triangulate the polygon and return a list of triangular polygons
|
||||||
|
:return: [Polygon]
|
||||||
|
"""
|
||||||
if self._triangles is None:
|
if self._triangles is None:
|
||||||
self._triangles = []
|
self._triangles = []
|
||||||
_mesh = self.triangle_mesh(self.coordinates, self.normal)
|
_mesh = self.triangle_mesh(self.coordinates, self.normal)
|
||||||
|
@ -336,7 +306,7 @@ class Polygon:
|
||||||
|
|
||||||
def _reshape(self, triangles) -> Polygon:
|
def _reshape(self, triangles) -> Polygon:
|
||||||
edges_list = []
|
edges_list = []
|
||||||
for i in range(0, len(triangles)):
|
for i in enumerate(triangles):
|
||||||
for edge in triangles[i].edges:
|
for edge in triangles[i].edges:
|
||||||
if not self._edge_in_edges_list(edge, edges_list):
|
if not self._edge_in_edges_list(edge, edges_list):
|
||||||
edges_list.append(edge)
|
edges_list.append(edge)
|
||||||
|
@ -421,13 +391,14 @@ class Polygon:
|
||||||
if len(points) != 3:
|
if len(points) != 3:
|
||||||
sub_polygons = polygon.triangles
|
sub_polygons = polygon.triangles
|
||||||
# todo: I modified this! To be checked @Guille
|
# todo: I modified this! To be checked @Guille
|
||||||
if len(sub_polygons) >= 1:
|
if len(sub_polygons) < 1:
|
||||||
for sub_polygon in sub_polygons:
|
continue
|
||||||
face = []
|
for sub_polygon in sub_polygons:
|
||||||
points = sub_polygon.coordinates
|
face = []
|
||||||
for point in points:
|
points = sub_polygon.coordinates
|
||||||
face.append(self._position_of(point, face))
|
for point in points:
|
||||||
self._faces.append(face)
|
face.append(self._position_of(point, face))
|
||||||
|
self._faces.append(face)
|
||||||
else:
|
else:
|
||||||
for point in points:
|
for point in points:
|
||||||
face.append(self._position_of(point, face))
|
face.append(self._position_of(point, face))
|
||||||
|
@ -440,7 +411,7 @@ class Polygon:
|
||||||
:return: int
|
:return: int
|
||||||
"""
|
"""
|
||||||
vertices = self.vertices
|
vertices = self.vertices
|
||||||
for i in range(len(vertices)):
|
for i in enumerate(vertices):
|
||||||
# ensure not duplicated vertex
|
# ensure not duplicated vertex
|
||||||
power = 0
|
power = 0
|
||||||
vertex2 = vertices[i]
|
vertex2 = vertices[i]
|
||||||
|
|
|
@ -41,10 +41,10 @@ class Polyhedron:
|
||||||
:return: int
|
:return: int
|
||||||
"""
|
"""
|
||||||
vertices = self.vertices
|
vertices = self.vertices
|
||||||
for i in range(len(vertices)):
|
for i, vertex in enumerate(vertices):
|
||||||
# ensure not duplicated vertex
|
# ensure not duplicated vertex
|
||||||
power = 0
|
power = 0
|
||||||
vertex2 = vertices[i]
|
vertex2 = vertex
|
||||||
for dimension in range(0, 3):
|
for dimension in range(0, 3):
|
||||||
power += math.pow(vertex2[dimension] - point[dimension], 2)
|
power += math.pow(vertex2[dimension] - point[dimension], 2)
|
||||||
distance = math.sqrt(power)
|
distance = math.sqrt(power)
|
||||||
|
@ -92,13 +92,14 @@ class Polyhedron:
|
||||||
points = polygon.coordinates
|
points = polygon.coordinates
|
||||||
if len(points) != 3:
|
if len(points) != 3:
|
||||||
sub_polygons = polygon.triangles
|
sub_polygons = polygon.triangles
|
||||||
if len(sub_polygons) >= 1:
|
if len(sub_polygons) < 1:
|
||||||
for sub_polygon in sub_polygons:
|
continue
|
||||||
face = []
|
for sub_polygon in sub_polygons:
|
||||||
points = sub_polygon.coordinates
|
face = []
|
||||||
for point in points:
|
points = sub_polygon.coordinates
|
||||||
face.append(self._position_of(point, face))
|
for point in points:
|
||||||
self._faces.append(face)
|
face.append(self._position_of(point, face))
|
||||||
|
self._faces.append(face)
|
||||||
else:
|
else:
|
||||||
for point in points:
|
for point in points:
|
||||||
face.append(self._position_of(point, face))
|
face.append(self._position_of(point, face))
|
||||||
|
|
|
@ -10,12 +10,11 @@ import logging
|
||||||
from typing import List, Union, TypeVar
|
from typing import List, Union, TypeVar
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
||||||
from hub.city_model_structure.building_demand.household import Household
|
from hub.city_model_structure.building_demand.household import Household
|
||||||
from hub.city_model_structure.building_demand.internal_zone import InternalZone
|
from hub.city_model_structure.building_demand.internal_zone import InternalZone
|
||||||
|
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
|
||||||
from hub.city_model_structure.building_demand.surface import Surface
|
from hub.city_model_structure.building_demand.surface import Surface
|
||||||
from hub.city_model_structure.city_object import CityObject
|
from hub.city_model_structure.city_object import CityObject
|
||||||
from hub.city_model_structure.energy_systems.energy_system import EnergySystem
|
from hub.city_model_structure.energy_systems.energy_system import EnergySystem
|
||||||
|
@ -42,20 +41,21 @@ class Building(CityObject):
|
||||||
self._floor_area = None
|
self._floor_area = None
|
||||||
self._roof_type = None
|
self._roof_type = None
|
||||||
self._internal_zones = None
|
self._internal_zones = None
|
||||||
|
self._thermal_zones_from_internal_zones = None
|
||||||
self._shell = None
|
self._shell = None
|
||||||
self._aliases = None
|
self._aliases = []
|
||||||
self._type = 'building'
|
self._type = 'building'
|
||||||
self._cold_water_temperature = dict()
|
self._cold_water_temperature = {}
|
||||||
self._heating = dict()
|
self._heating_demand = {}
|
||||||
self._cooling = dict()
|
self._cooling_demand = {}
|
||||||
self._lighting_electrical_demand = dict()
|
self._lighting_electrical_demand = {}
|
||||||
self._appliances_electrical_demand = dict()
|
self._appliances_electrical_demand = {}
|
||||||
self._domestic_hot_water_heat_demand = dict()
|
self._domestic_hot_water_heat_demand = {}
|
||||||
self._heating_consumption = dict()
|
self._heating_consumption = {}
|
||||||
self._cooling_consumption = dict()
|
self._cooling_consumption = {}
|
||||||
self._domestic_hot_water_consumption = dict()
|
self._domestic_hot_water_consumption = {}
|
||||||
self._distribution_systems_electrical_consumption = dict()
|
self._distribution_systems_electrical_consumption = {}
|
||||||
self._onsite_electrical_production = dict()
|
self._onsite_electrical_production = {}
|
||||||
self._eave_height = None
|
self._eave_height = None
|
||||||
self._energy_systems = None
|
self._energy_systems = None
|
||||||
self._systems_archetype_name = None
|
self._systems_archetype_name = None
|
||||||
|
@ -70,6 +70,9 @@ class Building(CityObject):
|
||||||
self._min_x = min(self._min_x, surface.lower_corner[0])
|
self._min_x = min(self._min_x, surface.lower_corner[0])
|
||||||
self._min_y = min(self._min_y, surface.lower_corner[1])
|
self._min_y = min(self._min_y, surface.lower_corner[1])
|
||||||
self._min_z = min(self._min_z, surface.lower_corner[2])
|
self._min_z = min(self._min_z, surface.lower_corner[2])
|
||||||
|
self._max_x = max(self._max_x, surface.upper_corner[0])
|
||||||
|
self._max_y = max(self._max_y, surface.upper_corner[1])
|
||||||
|
self._max_z = max(self._max_z, surface.upper_corner[2])
|
||||||
surface.id = surface_id
|
surface.id = surface_id
|
||||||
if surface.type == cte.GROUND:
|
if surface.type == cte.GROUND:
|
||||||
self._grounds.append(surface)
|
self._grounds.append(surface)
|
||||||
|
@ -86,7 +89,10 @@ class Building(CityObject):
|
||||||
elif surface.type == cte.INTERIOR_SLAB:
|
elif surface.type == cte.INTERIOR_SLAB:
|
||||||
self._interior_slabs.append(surface)
|
self._interior_slabs.append(surface)
|
||||||
else:
|
else:
|
||||||
logging.error(f'Building {self.name} [{self.aliases}] has an unexpected surface type {surface.type}.\n')
|
logging.error('Building %s [%s] has an unexpected surface type %s.', self.name, self.aliases, surface.type)
|
||||||
|
self._domestic_hot_water_peak_load = None
|
||||||
|
self._fuel_consumption_breakdown = {}
|
||||||
|
self._pv_generation = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def shell(self) -> Polyhedron:
|
def shell(self) -> Polyhedron:
|
||||||
|
@ -114,9 +120,24 @@ class Building(CityObject):
|
||||||
:return: [InternalZone]
|
:return: [InternalZone]
|
||||||
"""
|
"""
|
||||||
if self._internal_zones is None:
|
if self._internal_zones is None:
|
||||||
self._internal_zones = [InternalZone(self.surfaces, self.floor_area)]
|
self._internal_zones = [InternalZone(self.surfaces, self.floor_area, self.volume)]
|
||||||
return self._internal_zones
|
return self._internal_zones
|
||||||
|
|
||||||
|
@property
|
||||||
|
def thermal_zones_from_internal_zones(self) -> Union[None, List[ThermalZone]]:
|
||||||
|
"""
|
||||||
|
Get building thermal zones
|
||||||
|
:return: [ThermalZone]
|
||||||
|
"""
|
||||||
|
if self._thermal_zones_from_internal_zones is None:
|
||||||
|
self._thermal_zones_from_internal_zones = []
|
||||||
|
for internal_zone in self.internal_zones:
|
||||||
|
if internal_zone.thermal_zones_from_internal_zones is None:
|
||||||
|
self._thermal_zones_from_internal_zones = None
|
||||||
|
return self._thermal_zones_from_internal_zones
|
||||||
|
self._thermal_zones_from_internal_zones.append(internal_zone.thermal_zones_from_internal_zones[0])
|
||||||
|
return self._thermal_zones_from_internal_zones
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def grounds(self) -> List[Surface]:
|
def grounds(self) -> List[Surface]:
|
||||||
"""
|
"""
|
||||||
|
@ -243,6 +264,15 @@ class Building(CityObject):
|
||||||
Get building average storey height in meters
|
Get building average storey height in meters
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
|
if len(self.internal_zones) > 1:
|
||||||
|
self._average_storey_height = 0
|
||||||
|
for internal_zone in self.internal_zones:
|
||||||
|
self._average_storey_height += internal_zone.mean_height / len(self.internal_zones)
|
||||||
|
else:
|
||||||
|
if self.internal_zones[0].thermal_archetype is None:
|
||||||
|
self._average_storey_height = None
|
||||||
|
else:
|
||||||
|
self._average_storey_height = self.internal_zones[0].thermal_archetype.average_storey_height
|
||||||
return self._average_storey_height
|
return self._average_storey_height
|
||||||
|
|
||||||
@average_storey_height.setter
|
@average_storey_height.setter
|
||||||
|
@ -262,7 +292,10 @@ class Building(CityObject):
|
||||||
"""
|
"""
|
||||||
if self._storeys_above_ground is None:
|
if self._storeys_above_ground is None:
|
||||||
if self.eave_height is not None and self.average_storey_height is not None:
|
if self.eave_height is not None and self.average_storey_height is not None:
|
||||||
self._storeys_above_ground = int(self.eave_height / self.average_storey_height)
|
storeys_above_ground = int(self.eave_height / self.average_storey_height)
|
||||||
|
if storeys_above_ground == 0:
|
||||||
|
storeys_above_ground += 1
|
||||||
|
self._storeys_above_ground = storeys_above_ground
|
||||||
return self._storeys_above_ground
|
return self._storeys_above_ground
|
||||||
|
|
||||||
@storeys_above_ground.setter
|
@storeys_above_ground.setter
|
||||||
|
@ -278,7 +311,7 @@ class Building(CityObject):
|
||||||
def cold_water_temperature(self) -> {float}:
|
def cold_water_temperature(self) -> {float}:
|
||||||
"""
|
"""
|
||||||
Get cold water temperature in degrees Celsius
|
Get cold water temperature in degrees Celsius
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._cold_water_temperature
|
return self._cold_water_temperature
|
||||||
|
|
||||||
|
@ -286,123 +319,176 @@ class Building(CityObject):
|
||||||
def cold_water_temperature(self, value):
|
def cold_water_temperature(self, value):
|
||||||
"""
|
"""
|
||||||
Set cold water temperature in degrees Celsius
|
Set cold water temperature in degrees Celsius
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._cold_water_temperature = value
|
self._cold_water_temperature = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def heating(self) -> dict:
|
def heating_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get heating demand in Wh
|
Get heating demand in J
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._heating
|
return self._heating_demand
|
||||||
|
|
||||||
@heating.setter
|
@heating_demand.setter
|
||||||
def heating(self, value):
|
def heating_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set heating demand in Wh
|
Set heating demand in J
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._heating = value
|
self._heating_demand = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cooling(self) -> dict:
|
def cooling_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get cooling demand in Wh
|
Get cooling demand in J
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._cooling
|
return self._cooling_demand
|
||||||
|
|
||||||
@cooling.setter
|
@cooling_demand.setter
|
||||||
def cooling(self, value):
|
def cooling_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set cooling demand in Wh
|
Set cooling demand in J
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._cooling = value
|
self._cooling_demand = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lighting_electrical_demand(self) -> dict:
|
def lighting_electrical_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get lighting electrical demand in Wh
|
Get lighting electrical demand in J
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._lighting_electrical_demand
|
return self._lighting_electrical_demand
|
||||||
|
|
||||||
@lighting_electrical_demand.setter
|
@lighting_electrical_demand.setter
|
||||||
def lighting_electrical_demand(self, value):
|
def lighting_electrical_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set lighting electrical demand in Wh
|
Set lighting electrical demand in J
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._lighting_electrical_demand = value
|
self._lighting_electrical_demand = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def appliances_electrical_demand(self) -> dict:
|
def appliances_electrical_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get appliances electrical demand in Wh
|
Get appliances electrical demand in J
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._appliances_electrical_demand
|
return self._appliances_electrical_demand
|
||||||
|
|
||||||
@appliances_electrical_demand.setter
|
@appliances_electrical_demand.setter
|
||||||
def appliances_electrical_demand(self, value):
|
def appliances_electrical_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set appliances electrical demand in Wh
|
Set appliances electrical demand in J
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._appliances_electrical_demand = value
|
self._appliances_electrical_demand = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def domestic_hot_water_heat_demand(self) -> dict:
|
def domestic_hot_water_heat_demand(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get domestic hot water heat demand in Wh
|
Get domestic hot water heat demand in J
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
return self._domestic_hot_water_heat_demand
|
return self._domestic_hot_water_heat_demand
|
||||||
|
|
||||||
@domestic_hot_water_heat_demand.setter
|
@domestic_hot_water_heat_demand.setter
|
||||||
def domestic_hot_water_heat_demand(self, value):
|
def domestic_hot_water_heat_demand(self, value):
|
||||||
"""
|
"""
|
||||||
Set domestic hot water heat demand in Wh
|
Set domestic hot water heat demand in J
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{[float]}
|
||||||
"""
|
"""
|
||||||
self._domestic_hot_water_heat_demand = value
|
self._domestic_hot_water_heat_demand = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lighting_peak_load(self) -> Union[None, dict]:
|
||||||
|
"""
|
||||||
|
Get lighting peak load in W
|
||||||
|
:return: dict{[float]}
|
||||||
|
"""
|
||||||
|
results = {}
|
||||||
|
peak_lighting = 0
|
||||||
|
peak = 0
|
||||||
|
for thermal_zone in self.thermal_zones_from_internal_zones:
|
||||||
|
lighting = thermal_zone.lighting
|
||||||
|
for schedule in lighting.schedules:
|
||||||
|
peak = max(schedule.values) * lighting.density * thermal_zone.total_floor_area
|
||||||
|
if peak > peak_lighting:
|
||||||
|
peak_lighting = peak
|
||||||
|
results[cte.MONTH] = [peak for _ in range(0, 12)]
|
||||||
|
results[cte.YEAR] = [peak]
|
||||||
|
return results
|
||||||
|
|
||||||
|
@property
|
||||||
|
def appliances_peak_load(self) -> Union[None, dict]:
|
||||||
|
"""
|
||||||
|
Get appliances peak load in W
|
||||||
|
:return: dict{[float]}
|
||||||
|
"""
|
||||||
|
results = {}
|
||||||
|
peak_appliances = 0
|
||||||
|
peak = 0
|
||||||
|
for thermal_zone in self.thermal_zones_from_internal_zones:
|
||||||
|
appliances = thermal_zone.appliances
|
||||||
|
for schedule in appliances.schedules:
|
||||||
|
peak = max(schedule.values) * appliances.density * thermal_zone.total_floor_area
|
||||||
|
if peak > peak_appliances:
|
||||||
|
peak_appliances = peak
|
||||||
|
results[cte.MONTH] = [peak for _ in range(0, 12)]
|
||||||
|
results[cte.YEAR] = [peak]
|
||||||
|
return results
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def heating_peak_load(self) -> Union[None, dict]:
|
def heating_peak_load(self) -> Union[None, dict]:
|
||||||
"""
|
"""
|
||||||
Get heating peak load in W
|
Get heating peak load in W
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
results = {}
|
results = {}
|
||||||
if cte.HOUR in self.heating:
|
if cte.HOUR in self.heating_demand:
|
||||||
monthly_values = PeakLoads().\
|
monthly_values = PeakLoads().peak_loads_from_hourly(self.heating_demand[cte.HOUR])
|
||||||
peak_loads_from_hourly(self.heating[cte.HOUR][next(iter(self.heating[cte.HOUR]))])
|
|
||||||
else:
|
else:
|
||||||
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
|
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
|
||||||
if monthly_values is None:
|
if monthly_values is None:
|
||||||
return None
|
return None
|
||||||
results[cte.MONTH] = pd.DataFrame(monthly_values, columns=[cte.HEATING_PEAK_LOAD])
|
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
|
||||||
results[cte.YEAR] = pd.DataFrame([max(monthly_values)], columns=[cte.HEATING_PEAK_LOAD])
|
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cooling_peak_load(self) -> Union[None, dict]:
|
def cooling_peak_load(self) -> Union[None, dict]:
|
||||||
"""
|
"""
|
||||||
Get cooling peak load in W
|
Get cooling peak load in W
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{[float]}
|
||||||
"""
|
"""
|
||||||
results = {}
|
results = {}
|
||||||
if cte.HOUR in self.cooling:
|
if cte.HOUR in self.cooling_demand:
|
||||||
monthly_values = PeakLoads().peak_loads_from_hourly(self.cooling[cte.HOUR][next(iter(self.cooling[cte.HOUR]))])
|
monthly_values = PeakLoads().peak_loads_from_hourly(self.cooling_demand[cte.HOUR])
|
||||||
else:
|
else:
|
||||||
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
|
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
|
||||||
if monthly_values is None:
|
if monthly_values is None:
|
||||||
return None
|
return None
|
||||||
results[cte.MONTH] = pd.DataFrame(monthly_values, columns=[cte.COOLING_PEAK_LOAD])
|
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
|
||||||
results[cte.YEAR] = pd.DataFrame([max(monthly_values)], columns=[cte.COOLING_PEAK_LOAD])
|
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
|
||||||
|
return results
|
||||||
|
|
||||||
|
@property
|
||||||
|
def domestic_hot_water_peak_load(self) -> Union[None, dict]:
|
||||||
|
"""
|
||||||
|
Get cooling peak load in W
|
||||||
|
:return: dict{[float]}
|
||||||
|
"""
|
||||||
|
results = {}
|
||||||
|
monthly_values = None
|
||||||
|
if cte.HOUR in self.domestic_hot_water_heat_demand:
|
||||||
|
monthly_values = PeakLoads().peak_loads_from_hourly(self.domestic_hot_water_heat_demand[cte.HOUR])
|
||||||
|
if monthly_values is None:
|
||||||
|
return None
|
||||||
|
results[cte.MONTH] = [x / cte.WATTS_HOUR_TO_JULES for x in monthly_values]
|
||||||
|
results[cte.YEAR] = [max(monthly_values) / cte.WATTS_HOUR_TO_JULES]
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -414,7 +500,7 @@ class Building(CityObject):
|
||||||
if self._eave_height is None:
|
if self._eave_height is None:
|
||||||
self._eave_height = 0
|
self._eave_height = 0
|
||||||
for wall in self.walls:
|
for wall in self.walls:
|
||||||
self._eave_height = max(self._eave_height, wall.upper_corner[2])
|
self._eave_height = max(self._eave_height, wall.upper_corner[2]) - self.simplified_polyhedron.min_z
|
||||||
return self._eave_height
|
return self._eave_height
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -488,10 +574,7 @@ class Building(CityObject):
|
||||||
"""
|
"""
|
||||||
Add a new alias for the building
|
Add a new alias for the building
|
||||||
"""
|
"""
|
||||||
if self._aliases is None:
|
self._aliases.append(value)
|
||||||
self._aliases = [value]
|
|
||||||
else:
|
|
||||||
self._aliases.append(value)
|
|
||||||
if self.city is not None:
|
if self.city is not None:
|
||||||
self.city.add_building_alias(self, value)
|
self.city.add_building_alias(self, value)
|
||||||
|
|
||||||
|
@ -558,12 +641,12 @@ class Building(CityObject):
|
||||||
@property
|
@property
|
||||||
def heating_consumption(self):
|
def heating_consumption(self):
|
||||||
"""
|
"""
|
||||||
Get energy consumption for heating according to the heating system installed in Wh
|
Get energy consumption for heating according to the heating system installed in J
|
||||||
return: dict
|
return: dict
|
||||||
"""
|
"""
|
||||||
if len(self._heating_consumption) == 0:
|
if len(self._heating_consumption) == 0:
|
||||||
for heating_demand_key in self.heating:
|
for heating_demand_key in self.heating_demand:
|
||||||
demand = self.heating[heating_demand_key][cte.INSEL_MEB]
|
demand = self.heating_demand[heating_demand_key]
|
||||||
consumption_type = cte.HEATING
|
consumption_type = cte.HEATING
|
||||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||||
if final_energy_consumed is None:
|
if final_energy_consumed is None:
|
||||||
|
@ -574,12 +657,12 @@ class Building(CityObject):
|
||||||
@property
|
@property
|
||||||
def cooling_consumption(self):
|
def cooling_consumption(self):
|
||||||
"""
|
"""
|
||||||
Get energy consumption for cooling according to the cooling system installed in Wh
|
Get energy consumption for cooling according to the cooling system installed in J
|
||||||
return: dict
|
return: dict
|
||||||
"""
|
"""
|
||||||
if len(self._cooling_consumption) == 0:
|
if len(self._cooling_consumption) == 0:
|
||||||
for cooling_demand_key in self.cooling:
|
for cooling_demand_key in self.cooling_demand:
|
||||||
demand = self.cooling[cooling_demand_key][cte.INSEL_MEB]
|
demand = self.cooling_demand[cooling_demand_key]
|
||||||
consumption_type = cte.COOLING
|
consumption_type = cte.COOLING
|
||||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||||
if final_energy_consumed is None:
|
if final_energy_consumed is None:
|
||||||
|
@ -590,12 +673,12 @@ class Building(CityObject):
|
||||||
@property
|
@property
|
||||||
def domestic_hot_water_consumption(self):
|
def domestic_hot_water_consumption(self):
|
||||||
"""
|
"""
|
||||||
Get energy consumption for domestic according to the domestic hot water system installed in Wh
|
Get energy consumption for domestic according to the domestic hot water system installed in J
|
||||||
return: dict
|
return: dict
|
||||||
"""
|
"""
|
||||||
if len(self._domestic_hot_water_consumption) == 0:
|
if len(self._domestic_hot_water_consumption) == 0:
|
||||||
for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand:
|
for domestic_hot_water_demand_key in self.domestic_hot_water_heat_demand:
|
||||||
demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key][cte.INSEL_MEB]
|
demand = self.domestic_hot_water_heat_demand[domestic_hot_water_demand_key]
|
||||||
consumption_type = cte.DOMESTIC_HOT_WATER
|
consumption_type = cte.DOMESTIC_HOT_WATER
|
||||||
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
final_energy_consumed = self._calculate_consumption(consumption_type, demand)
|
||||||
if final_energy_consumed is None:
|
if final_energy_consumed is None:
|
||||||
|
@ -606,75 +689,93 @@ class Building(CityObject):
|
||||||
def _calculate_working_hours(self):
|
def _calculate_working_hours(self):
|
||||||
_working_hours = {}
|
_working_hours = {}
|
||||||
for internal_zone in self.internal_zones:
|
for internal_zone in self.internal_zones:
|
||||||
for thermal_zone in internal_zone.thermal_zones:
|
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
|
||||||
_working_hours_per_thermal_zone = {}
|
_working_hours_per_thermal_zone = {}
|
||||||
for schedule in thermal_zone.thermal_control.hvac_availability_schedules:
|
for schedule in thermal_zone.thermal_control.hvac_availability_schedules:
|
||||||
_working_hours_per_schedule = [0] * len(schedule.values)
|
_working_hours_per_schedule = [0] * len(schedule.values)
|
||||||
for i, value in enumerate(schedule.values):
|
for i, value in enumerate(schedule.values):
|
||||||
if value > 0:
|
if value > 0:
|
||||||
_working_hours_per_schedule[i] = 1
|
_working_hours_per_schedule[i] = 1
|
||||||
for day_type in schedule.day_types:
|
for day_type in schedule.day_types:
|
||||||
_working_hours_per_thermal_zone[day_type] = _working_hours_per_schedule
|
_working_hours_per_thermal_zone[day_type] = _working_hours_per_schedule
|
||||||
if len(_working_hours) == 0:
|
if len(_working_hours) == 0:
|
||||||
_working_hours = _working_hours_per_thermal_zone
|
_working_hours = _working_hours_per_thermal_zone
|
||||||
else:
|
else:
|
||||||
for key in _working_hours.keys():
|
for key, item in _working_hours.items():
|
||||||
saved_values = _working_hours_per_thermal_zone[key]
|
saved_values = _working_hours_per_thermal_zone[key]
|
||||||
for i, value in enumerate(_working_hours[key]):
|
for i, value in enumerate(item):
|
||||||
if saved_values[i] == 1:
|
_working_hours[key][i] = max(_working_hours[key][i], saved_values[i])
|
||||||
_working_hours[key][i] = 1
|
|
||||||
_total_hours = 0
|
working_hours = {}
|
||||||
for key in _working_hours:
|
values_months = []
|
||||||
_total_hours += _working_hours[key] * cte.DAYS_A_YEAR[key]
|
for month in cte.WEEK_DAYS_A_MONTH.keys():
|
||||||
return _total_hours
|
_total_hours_month = 0
|
||||||
|
for key in _working_hours:
|
||||||
|
hours = sum(_working_hours[key])
|
||||||
|
_total_hours_month += hours * cte.WEEK_DAYS_A_MONTH[month][key]
|
||||||
|
values_months.append(_total_hours_month)
|
||||||
|
working_hours[cte.MONTH] = values_months
|
||||||
|
working_hours[cte.YEAR] = sum(working_hours[cte.MONTH])
|
||||||
|
return working_hours
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def distribution_systems_electrical_consumption(self):
|
def distribution_systems_electrical_consumption(self):
|
||||||
"""
|
"""
|
||||||
Get total electricity consumption for distribution and emission systems in Wh
|
Get total electricity consumption for distribution and emission systems in J
|
||||||
return: dict
|
return: dict
|
||||||
"""
|
"""
|
||||||
if len(self._distribution_systems_electrical_consumption) == 0:
|
_distribution_systems_electrical_consumption = {}
|
||||||
_peak_load = self.heating_peak_load[cte.YEAR][cte.HEATING_PEAK_LOAD][0]
|
if len(self._distribution_systems_electrical_consumption) != 0:
|
||||||
_peak_load_type = cte.HEATING
|
return self._distribution_systems_electrical_consumption
|
||||||
if _peak_load < self.cooling_peak_load[cte.YEAR][cte.COOLING_PEAK_LOAD][0]:
|
_peak_load = self.heating_peak_load[cte.YEAR][0]
|
||||||
_peak_load = self.cooling_peak_load[cte.YEAR][cte.COOLING_PEAK_LOAD][0]
|
_peak_load_type = cte.HEATING
|
||||||
_peak_load_type = cte.COOLING
|
if _peak_load < self.cooling_peak_load[cte.YEAR][0]:
|
||||||
|
_peak_load = self.cooling_peak_load[cte.YEAR][0]
|
||||||
|
_peak_load_type = cte.COOLING
|
||||||
|
|
||||||
_consumption_fix_flow = 0
|
_working_hours = self._calculate_working_hours()
|
||||||
if self.energy_systems is None:
|
_consumption_fix_flow = 0
|
||||||
return self._distribution_systems_electrical_consumption
|
if self.energy_systems is None:
|
||||||
for energy_system in self.energy_systems:
|
return self._distribution_systems_electrical_consumption
|
||||||
emission_system = energy_system.emission_system.generic_emission_system
|
for energy_system in self.energy_systems:
|
||||||
parasitic_energy_consumption = 0
|
distribution_systems = energy_system.distribution_systems
|
||||||
if emission_system is not None:
|
if distribution_systems is not None:
|
||||||
parasitic_energy_consumption = emission_system.parasitic_energy_consumption
|
for distribution_system in distribution_systems:
|
||||||
distribution_system = energy_system.distribution_system.generic_distribution_system
|
emission_systems = distribution_system.emission_systems
|
||||||
consumption_variable_flow = distribution_system.distribution_consumption_variable_flow
|
parasitic_energy_consumption = 0
|
||||||
for demand_type in energy_system.demand_types:
|
if emission_systems is not None:
|
||||||
if demand_type.lower() == cte.HEATING:
|
for emission_system in emission_systems:
|
||||||
if _peak_load_type == cte.HEATING:
|
parasitic_energy_consumption += emission_system.parasitic_energy_consumption
|
||||||
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
|
consumption_variable_flow = distribution_system.distribution_consumption_variable_flow
|
||||||
for heating_demand_key in self.heating:
|
for demand_type in energy_system.demand_types:
|
||||||
_consumption = [0]*len(self.heating)
|
if demand_type.lower() == cte.HEATING.lower():
|
||||||
_demand = self.heating[heating_demand_key][cte.INSEL_MEB]
|
if _peak_load_type == cte.HEATING.lower():
|
||||||
for i in range(0, len(_consumption)):
|
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
|
||||||
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
for heating_demand_key in self.heating_demand:
|
||||||
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
|
_consumption = [0]*len(self.heating_demand[heating_demand_key])
|
||||||
if demand_type.lower() == cte.COOLING:
|
_demand = self.heating_demand[heating_demand_key]
|
||||||
if _peak_load_type == cte.COOLING:
|
for i, _ in enumerate(_consumption):
|
||||||
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
|
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
||||||
for demand_key in self.cooling:
|
self._distribution_systems_electrical_consumption[heating_demand_key] = _consumption
|
||||||
_consumption = self._distribution_systems_electrical_consumption[demand_key]
|
if demand_type.lower() == cte.COOLING.lower():
|
||||||
_demand = self.cooling[demand_key][cte.INSEL_MEB]
|
if _peak_load_type == cte.COOLING.lower():
|
||||||
for i in range(0, len(_consumption)):
|
_consumption_fix_flow = distribution_system.distribution_consumption_fix_flow
|
||||||
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
for demand_key in self.cooling_demand:
|
||||||
self._distribution_systems_electrical_consumption[demand_key] = _consumption
|
_consumption = self._distribution_systems_electrical_consumption[demand_key]
|
||||||
|
_demand = self.cooling_demand[demand_key]
|
||||||
|
for i, _ in enumerate(_consumption):
|
||||||
|
_consumption[i] += (parasitic_energy_consumption + consumption_variable_flow) * _demand[i]
|
||||||
|
self._distribution_systems_electrical_consumption[demand_key] = _consumption
|
||||||
|
|
||||||
|
for key, item in self._distribution_systems_electrical_consumption.items():
|
||||||
|
for i in range(0, len(item)):
|
||||||
|
_working_hours_value = _working_hours[key]
|
||||||
|
if len(item) == 12:
|
||||||
|
_working_hours_value = _working_hours[key][i]
|
||||||
|
self._distribution_systems_electrical_consumption[key][i] += (
|
||||||
|
_peak_load * _consumption_fix_flow * _working_hours_value * cte.WATTS_HOUR_TO_JULES
|
||||||
|
)
|
||||||
|
|
||||||
for key in self._distribution_systems_electrical_consumption:
|
|
||||||
for i in range(0, len(self._distribution_systems_electrical_consumption[key])):
|
|
||||||
self._distribution_systems_electrical_consumption[key][i] += _peak_load * _consumption_fix_flow \
|
|
||||||
* self._calculate_working_hours()
|
|
||||||
return self._distribution_systems_electrical_consumption
|
return self._distribution_systems_electrical_consumption
|
||||||
|
|
||||||
def _calculate_consumption(self, consumption_type, demand):
|
def _calculate_consumption(self, consumption_type, demand):
|
||||||
|
@ -683,15 +784,21 @@ class Building(CityObject):
|
||||||
if self.energy_systems is None:
|
if self.energy_systems is None:
|
||||||
return None
|
return None
|
||||||
for energy_system in self.energy_systems:
|
for energy_system in self.energy_systems:
|
||||||
|
generation_systems = energy_system.generation_systems
|
||||||
for demand_type in energy_system.demand_types:
|
for demand_type in energy_system.demand_types:
|
||||||
if demand_type.lower() == consumption_type.lower():
|
if demand_type.lower() == consumption_type.lower():
|
||||||
if consumption_type == cte.HEATING or consumption_type == cte.DOMESTIC_HOT_WATER:
|
if consumption_type in (cte.HEATING, cte.DOMESTIC_HOT_WATER):
|
||||||
coefficient_of_performance = energy_system.generation_system.generic_generation_system.heat_efficiency
|
for generation_system in generation_systems:
|
||||||
|
if generation_system.heat_efficiency is not None:
|
||||||
|
coefficient_of_performance = float(generation_system.heat_efficiency)
|
||||||
elif consumption_type == cte.COOLING:
|
elif consumption_type == cte.COOLING:
|
||||||
coefficient_of_performance = energy_system.generation_system.generic_generation_system.cooling_efficiency
|
for generation_system in generation_systems:
|
||||||
|
if generation_system.cooling_efficiency is not None:
|
||||||
|
coefficient_of_performance = float(generation_system.cooling_efficiency)
|
||||||
elif consumption_type == cte.ELECTRICITY:
|
elif consumption_type == cte.ELECTRICITY:
|
||||||
coefficient_of_performance = \
|
for generation_system in generation_systems:
|
||||||
energy_system.generation_system.generic_generation_system.electricity_efficiency
|
if generation_system.electricity_efficiency is not None:
|
||||||
|
coefficient_of_performance = float(generation_system.electricity_efficiency)
|
||||||
if coefficient_of_performance == 0:
|
if coefficient_of_performance == 0:
|
||||||
values = [0]*len(demand)
|
values = [0]*len(demand)
|
||||||
final_energy_consumed = values
|
final_energy_consumed = values
|
||||||
|
@ -704,11 +811,9 @@ class Building(CityObject):
|
||||||
@property
|
@property
|
||||||
def onsite_electrical_production(self):
|
def onsite_electrical_production(self):
|
||||||
"""
|
"""
|
||||||
Get total electricity produced onsite in Wh
|
Get total electricity produced onsite in J
|
||||||
return: dict
|
return: dict
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Add other systems whenever new ones appear
|
|
||||||
orientation_losses_factor = {cte.MONTH: {'north': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
orientation_losses_factor = {cte.MONTH: {'north': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
'east': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
'east': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
'south': [2.137931, 1.645503, 1.320946, 1.107817, 0.993213, 0.945175,
|
'south': [2.137931, 1.645503, 1.320946, 1.107817, 0.993213, 0.945175,
|
||||||
|
@ -719,18 +824,96 @@ class Building(CityObject):
|
||||||
'south': [1.212544],
|
'south': [1.212544],
|
||||||
'west': [0]}
|
'west': [0]}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add other systems whenever new ones appear
|
||||||
if self.energy_systems is None:
|
if self.energy_systems is None:
|
||||||
return self._onsite_electrical_production
|
return self._onsite_electrical_production
|
||||||
for energy_system in self.energy_systems:
|
for energy_system in self.energy_systems:
|
||||||
if energy_system.generation_system.generic_generation_system.type == cte.PHOTOVOLTAIC:
|
for generation_system in energy_system.generation_systems:
|
||||||
_efficiency = energy_system.generation_system.generic_generation_system.electricity_efficiency
|
if generation_system.system_type == cte.PHOTOVOLTAIC:
|
||||||
self._onsite_electrical_production = {}
|
if generation_system.electricity_efficiency is not None:
|
||||||
for _key in self.roofs[0].global_irradiance.keys():
|
_efficiency = float(generation_system.electricity_efficiency)
|
||||||
_results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key][cte.SRA]))]
|
else:
|
||||||
for surface in self.roofs:
|
_efficiency = 0
|
||||||
_results = [x + y * _efficiency * surface.perimeter_area
|
self._onsite_electrical_production = {}
|
||||||
* surface.solar_collectors_area_reduction_factor * z
|
for _key in self.roofs[0].global_irradiance.keys():
|
||||||
for x, y, z in zip(_results, surface.global_irradiance[_key][cte.SRA],
|
_results = [0 for _ in range(0, len(self.roofs[0].global_irradiance[_key]))]
|
||||||
orientation_losses_factor[cte.MONTH]['south'])]
|
for surface in self.roofs:
|
||||||
self._onsite_electrical_production[_key] = _results
|
if _key in orientation_losses_factor:
|
||||||
|
_results = [x + y * _efficiency * surface.perimeter_area
|
||||||
|
* surface.solar_collectors_area_reduction_factor * z
|
||||||
|
for x, y, z in zip(_results, surface.global_irradiance[_key],
|
||||||
|
orientation_losses_factor[_key]['south'])]
|
||||||
|
self._onsite_electrical_production[_key] = _results
|
||||||
return self._onsite_electrical_production
|
return self._onsite_electrical_production
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lower_corner(self):
|
||||||
|
"""
|
||||||
|
Get building lower corner.
|
||||||
|
"""
|
||||||
|
return [self._min_x, self._min_y, self._min_z]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def upper_corner(self):
|
||||||
|
"""
|
||||||
|
Get building upper corner.
|
||||||
|
"""
|
||||||
|
return [self._max_x, self._max_y, self._max_z]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def energy_consumption_breakdown(self) -> dict:
|
||||||
|
"""
|
||||||
|
Get energy consumption of different sectors
|
||||||
|
return: dict
|
||||||
|
"""
|
||||||
|
fuel_breakdown = {cte.ELECTRICITY: {cte.LIGHTING: self.lighting_electrical_demand[cte.YEAR][0],
|
||||||
|
cte.APPLIANCES: self.appliances_electrical_demand[cte.YEAR][0]}}
|
||||||
|
energy_systems = self.energy_systems
|
||||||
|
for energy_system in energy_systems:
|
||||||
|
demand_types = energy_system.demand_types
|
||||||
|
generation_systems = energy_system.generation_systems
|
||||||
|
for demand_type in demand_types:
|
||||||
|
for generation_system in generation_systems:
|
||||||
|
if generation_system.system_type != cte.PHOTOVOLTAIC:
|
||||||
|
if generation_system.fuel_type not in fuel_breakdown:
|
||||||
|
fuel_breakdown[generation_system.fuel_type] = {}
|
||||||
|
if demand_type in generation_system.energy_consumption:
|
||||||
|
fuel_breakdown[f'{generation_system.fuel_type}'][f'{demand_type}'] = (
|
||||||
|
generation_system.energy_consumption)[f'{demand_type}'][cte.YEAR][0]
|
||||||
|
storage_systems = generation_system.energy_storage_systems
|
||||||
|
if storage_systems:
|
||||||
|
for storage_system in storage_systems:
|
||||||
|
if storage_system.type_energy_stored == 'thermal' and storage_system.heating_coil_energy_consumption:
|
||||||
|
fuel_breakdown[cte.ELECTRICITY][f'{demand_type}'] += storage_system.heating_coil_energy_consumption[cte.YEAR][0]
|
||||||
|
#TODO: When simulation models of all energy system archetypes are created, this part can be removed
|
||||||
|
heating_fuels = []
|
||||||
|
dhw_fuels = []
|
||||||
|
for energy_system in self.energy_systems:
|
||||||
|
if cte.HEATING in energy_system.demand_types:
|
||||||
|
for generation_system in energy_system.generation_systems:
|
||||||
|
heating_fuels.append(generation_system.fuel_type)
|
||||||
|
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
|
||||||
|
for generation_system in energy_system.generation_systems:
|
||||||
|
dhw_fuels.append(generation_system.fuel_type)
|
||||||
|
for key in fuel_breakdown:
|
||||||
|
if key == cte.ELECTRICITY and cte.COOLING not in fuel_breakdown[key]:
|
||||||
|
for energy_system in energy_systems:
|
||||||
|
if cte.COOLING in energy_system.demand_types and cte.COOLING not in fuel_breakdown[key]:
|
||||||
|
for generation_system in energy_system.generation_systems:
|
||||||
|
fuel_breakdown[generation_system.fuel_type][cte.COOLING] = self.cooling_consumption[cte.YEAR][0]
|
||||||
|
for fuel in heating_fuels:
|
||||||
|
if cte.HEATING not in fuel_breakdown[fuel]:
|
||||||
|
for energy_system in energy_systems:
|
||||||
|
if cte.HEATING in energy_system.demand_types:
|
||||||
|
for generation_system in energy_system.generation_systems:
|
||||||
|
fuel_breakdown[generation_system.fuel_type][cte.HEATING] = self.heating_consumption[cte.YEAR][0]
|
||||||
|
for fuel in dhw_fuels:
|
||||||
|
if cte.DOMESTIC_HOT_WATER not in fuel_breakdown[fuel]:
|
||||||
|
for energy_system in energy_systems:
|
||||||
|
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types:
|
||||||
|
for generation_system in energy_system.generation_systems:
|
||||||
|
fuel_breakdown[generation_system.fuel_type][cte.DOMESTIC_HOT_WATER] = self.domestic_hot_water_consumption[cte.YEAR][0]
|
||||||
|
self._fuel_consumption_breakdown = fuel_breakdown
|
||||||
|
return self._fuel_consumption_breakdown
|
||||||
|
|
||||||
|
|
151
hub/city_model_structure/building_demand/construction.py
Normal file
151
hub/city_model_structure/building_demand/construction.py
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
"""
|
||||||
|
Construction thermal parameters
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2023 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
from hub.city_model_structure.building_demand.layer import Layer
|
||||||
|
|
||||||
|
|
||||||
|
class Construction:
|
||||||
|
"""
|
||||||
|
Construction class
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self._type = None
|
||||||
|
self._name = None
|
||||||
|
self._layers = None
|
||||||
|
self._window_ratio = None
|
||||||
|
self._window_frame_ratio = None
|
||||||
|
self._window_g_value = None
|
||||||
|
self._window_overall_u_value = None
|
||||||
|
self._window_type = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
"""
|
||||||
|
Get construction type
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
return self._type
|
||||||
|
|
||||||
|
@type.setter
|
||||||
|
def type(self, value):
|
||||||
|
"""
|
||||||
|
Set construction type
|
||||||
|
:param value: str
|
||||||
|
"""
|
||||||
|
self._type = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""
|
||||||
|
Get construction name
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value):
|
||||||
|
"""
|
||||||
|
Set construction name
|
||||||
|
:param value: str
|
||||||
|
"""
|
||||||
|
self._name = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def layers(self) -> [Layer]:
|
||||||
|
"""
|
||||||
|
Get layers
|
||||||
|
:return: [layer]
|
||||||
|
"""
|
||||||
|
return self._layers
|
||||||
|
|
||||||
|
@layers.setter
|
||||||
|
def layers(self, value):
|
||||||
|
"""
|
||||||
|
Set layers
|
||||||
|
:param value: [layer]
|
||||||
|
"""
|
||||||
|
self._layers = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def window_ratio(self):
|
||||||
|
"""
|
||||||
|
Get window ratio
|
||||||
|
:return: dict
|
||||||
|
"""
|
||||||
|
return self._window_ratio
|
||||||
|
|
||||||
|
@window_ratio.setter
|
||||||
|
def window_ratio(self, value):
|
||||||
|
"""
|
||||||
|
Set window ratio
|
||||||
|
:param value: dict
|
||||||
|
"""
|
||||||
|
self._window_ratio = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def window_frame_ratio(self):
|
||||||
|
"""
|
||||||
|
Get window frame ratio
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._window_frame_ratio
|
||||||
|
|
||||||
|
@window_frame_ratio.setter
|
||||||
|
def window_frame_ratio(self, value):
|
||||||
|
"""
|
||||||
|
Set window frame ratio
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._window_frame_ratio = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def window_g_value(self):
|
||||||
|
"""
|
||||||
|
Get transparent surface g-value
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._window_g_value
|
||||||
|
|
||||||
|
@window_g_value.setter
|
||||||
|
def window_g_value(self, value):
|
||||||
|
"""
|
||||||
|
Set transparent surface g-value
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._window_g_value = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def window_overall_u_value(self):
|
||||||
|
"""
|
||||||
|
Get transparent surface overall U-value in W/m2K
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._window_overall_u_value
|
||||||
|
|
||||||
|
@window_overall_u_value.setter
|
||||||
|
def window_overall_u_value(self, value):
|
||||||
|
"""
|
||||||
|
Set transparent surface overall U-value in W/m2K
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._window_overall_u_value = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def window_type(self):
|
||||||
|
"""
|
||||||
|
Get transparent surface type, 'window' or 'skylight'
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
return self._window_type
|
||||||
|
|
||||||
|
@window_type.setter
|
||||||
|
def window_type(self, value):
|
||||||
|
"""
|
||||||
|
Set transparent surface type, 'window' or 'skylight'
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
self._window_type = value
|
|
@ -8,24 +8,25 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Union, List
|
from typing import Union, List
|
||||||
from hub.city_model_structure.building_demand.usage import Usage
|
from hub.city_model_structure.building_demand.usage import Usage
|
||||||
|
from hub.city_model_structure.building_demand.thermal_archetype import ThermalArchetype
|
||||||
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
|
from hub.city_model_structure.building_demand.thermal_zone import ThermalZone
|
||||||
|
from hub.city_model_structure.building_demand.thermal_boundary import ThermalBoundary
|
||||||
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
||||||
from hub.city_model_structure.energy_systems.hvac_system import HvacSystem
|
|
||||||
|
|
||||||
|
|
||||||
class InternalZone:
|
class InternalZone:
|
||||||
"""
|
"""
|
||||||
InternalZone class
|
InternalZone class
|
||||||
"""
|
"""
|
||||||
def __init__(self, surfaces, area):
|
def __init__(self, surfaces, area, volume):
|
||||||
self._surfaces = surfaces
|
self._surfaces = surfaces
|
||||||
self._id = None
|
self._id = None
|
||||||
self._geometry = None
|
self._geometry = None
|
||||||
self._volume = None
|
self._volume = volume
|
||||||
self._area = area
|
self._area = area
|
||||||
self._thermal_zones = None
|
self._thermal_zones_from_internal_zones = None
|
||||||
self._usages = None
|
self._usages = None
|
||||||
self._hvac_system = None
|
self._thermal_archetype = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
@ -64,7 +65,7 @@ class InternalZone:
|
||||||
Get internal zone volume in cubic meters
|
Get internal zone volume in cubic meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
return self.geometry.volume
|
return self._volume
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def area(self):
|
def area(self):
|
||||||
|
@ -74,10 +75,18 @@ class InternalZone:
|
||||||
"""
|
"""
|
||||||
return self._area
|
return self._area
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mean_height(self):
|
||||||
|
"""
|
||||||
|
Get internal zone mean height in meters
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self.volume / self.area
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usages(self) -> [Usage]:
|
def usages(self) -> [Usage]:
|
||||||
"""
|
"""
|
||||||
Get internal zone usage zones
|
Get usage archetypes
|
||||||
:return: [Usage]
|
:return: [Usage]
|
||||||
"""
|
"""
|
||||||
return self._usages
|
return self._usages
|
||||||
|
@ -85,39 +94,59 @@ class InternalZone:
|
||||||
@usages.setter
|
@usages.setter
|
||||||
def usages(self, value):
|
def usages(self, value):
|
||||||
"""
|
"""
|
||||||
Set internal zone usage zones
|
Set usage archetypes
|
||||||
:param value: [Usage]
|
:param value: [Usage]
|
||||||
"""
|
"""
|
||||||
self._usages = value
|
self._usages = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_system(self) -> Union[None, HvacSystem]:
|
def thermal_archetype(self) -> ThermalArchetype:
|
||||||
"""
|
"""
|
||||||
Get HVAC system installed for this thermal zone
|
Get thermal archetype parameters
|
||||||
:return: None or HvacSystem
|
:return: ThermalArchetype
|
||||||
"""
|
"""
|
||||||
return self._hvac_system
|
return self._thermal_archetype
|
||||||
|
|
||||||
@hvac_system.setter
|
@thermal_archetype.setter
|
||||||
def hvac_system(self, value):
|
def thermal_archetype(self, value):
|
||||||
"""
|
"""
|
||||||
Set HVAC system installed for this thermal zone
|
Set thermal archetype parameters
|
||||||
:param value: HvacSystem
|
:param value: ThermalArchetype
|
||||||
"""
|
"""
|
||||||
self._hvac_system = value
|
self._thermal_archetype = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def thermal_zones(self) -> Union[None, List[ThermalZone]]:
|
def thermal_zones_from_internal_zones(self) -> Union[None, List[ThermalZone]]:
|
||||||
"""
|
"""
|
||||||
Get building thermal zones
|
Get building thermal zones as one per internal zone
|
||||||
:return: [ThermalZone]
|
:return: [ThermalZone]
|
||||||
"""
|
"""
|
||||||
return self._thermal_zones
|
_thermal_boundaries = []
|
||||||
|
for surface in self.surfaces:
|
||||||
|
if surface.holes_polygons is None:
|
||||||
|
windows_areas = None
|
||||||
|
else:
|
||||||
|
windows_areas = []
|
||||||
|
for hole in surface.holes_polygons:
|
||||||
|
windows_areas.append(hole.area)
|
||||||
|
_thermal_boundary = ThermalBoundary(surface, surface.solid_polygon.area, windows_areas)
|
||||||
|
surface.associated_thermal_boundaries = [_thermal_boundary]
|
||||||
|
_thermal_boundaries.append(_thermal_boundary)
|
||||||
|
if self.thermal_archetype is None:
|
||||||
|
return None # there are no archetype
|
||||||
|
_number_of_storeys = int(self.volume / self.area / self.thermal_archetype.average_storey_height)
|
||||||
|
if _number_of_storeys == 0:
|
||||||
|
_number_of_storeys = 1
|
||||||
|
_thermal_zone = ThermalZone(_thermal_boundaries, self, self.volume, self.area, _number_of_storeys)
|
||||||
|
for thermal_boundary in _thermal_zone.thermal_boundaries:
|
||||||
|
thermal_boundary.thermal_zones = [_thermal_zone]
|
||||||
|
self._thermal_zones_from_internal_zones = [_thermal_zone]
|
||||||
|
return self._thermal_zones_from_internal_zones
|
||||||
|
|
||||||
@thermal_zones.setter
|
@thermal_zones_from_internal_zones.setter
|
||||||
def thermal_zones(self, value):
|
def thermal_zones_from_internal_zones(self, value):
|
||||||
"""
|
"""
|
||||||
Set city object thermal zones
|
Set city object thermal zones as one per internal zone
|
||||||
:param value: [ThermalZone]
|
:param value: [ThermalZone]
|
||||||
"""
|
"""
|
||||||
self._thermal_zones = value
|
self._thermal_zones_from_internal_zones = value
|
||||||
|
|
|
@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Union
|
from typing import Union
|
||||||
from hub.city_model_structure.building_demand.material import Material
|
|
||||||
|
|
||||||
|
|
||||||
class Layer:
|
class Layer:
|
||||||
|
@ -14,9 +14,17 @@ class Layer:
|
||||||
Layer class
|
Layer class
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._material = None
|
|
||||||
self._thickness = None
|
self._thickness = None
|
||||||
self._id = None
|
self._id = None
|
||||||
|
self._material_name = None
|
||||||
|
self._conductivity = None
|
||||||
|
self._specific_heat = None
|
||||||
|
self._density = None
|
||||||
|
self._solar_absorptance = None
|
||||||
|
self._thermal_absorptance = None
|
||||||
|
self._visible_absorptance = None
|
||||||
|
self._no_mass = False
|
||||||
|
self._thermal_resistance = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
@ -28,22 +36,6 @@ class Layer:
|
||||||
self._id = uuid.uuid4()
|
self._id = uuid.uuid4()
|
||||||
return self._id
|
return self._id
|
||||||
|
|
||||||
@property
|
|
||||||
def material(self) -> Material:
|
|
||||||
"""
|
|
||||||
Get layer material
|
|
||||||
:return: Material
|
|
||||||
"""
|
|
||||||
return self._material
|
|
||||||
|
|
||||||
@material.setter
|
|
||||||
def material(self, value):
|
|
||||||
"""
|
|
||||||
Set layer material
|
|
||||||
:param value: Material
|
|
||||||
"""
|
|
||||||
self._material = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def thickness(self) -> Union[None, float]:
|
def thickness(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
|
@ -60,3 +52,155 @@ class Layer:
|
||||||
"""
|
"""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self._thickness = float(value)
|
self._thickness = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def material_name(self):
|
||||||
|
"""
|
||||||
|
Get material name
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
return self._material_name
|
||||||
|
|
||||||
|
@material_name.setter
|
||||||
|
def material_name(self, value):
|
||||||
|
"""
|
||||||
|
Set material name
|
||||||
|
:param value: string
|
||||||
|
"""
|
||||||
|
self._material_name = str(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def conductivity(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get material conductivity in W/mK
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._conductivity
|
||||||
|
|
||||||
|
@conductivity.setter
|
||||||
|
def conductivity(self, value):
|
||||||
|
"""
|
||||||
|
Set material conductivity in W/mK
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._conductivity = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def specific_heat(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get material conductivity in J/kgK
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._specific_heat
|
||||||
|
|
||||||
|
@specific_heat.setter
|
||||||
|
def specific_heat(self, value):
|
||||||
|
"""
|
||||||
|
Get material conductivity in J/kgK
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._specific_heat = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def density(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get material density in kg/m3
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._density
|
||||||
|
|
||||||
|
@density.setter
|
||||||
|
def density(self, value):
|
||||||
|
"""
|
||||||
|
Set material density
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._density = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def solar_absorptance(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get material solar absorptance
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._solar_absorptance
|
||||||
|
|
||||||
|
@solar_absorptance.setter
|
||||||
|
def solar_absorptance(self, value):
|
||||||
|
"""
|
||||||
|
Set material solar absorptance
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._solar_absorptance = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def thermal_absorptance(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get material thermal absorptance
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._thermal_absorptance
|
||||||
|
|
||||||
|
@thermal_absorptance.setter
|
||||||
|
def thermal_absorptance(self, value):
|
||||||
|
"""
|
||||||
|
Set material thermal absorptance
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._thermal_absorptance = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def visible_absorptance(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get material visible absorptance
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._visible_absorptance
|
||||||
|
|
||||||
|
@visible_absorptance.setter
|
||||||
|
def visible_absorptance(self, value):
|
||||||
|
"""
|
||||||
|
Set material visible absorptance
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._visible_absorptance = float(value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def no_mass(self) -> Union[None, bool]:
|
||||||
|
"""
|
||||||
|
Get material no mass flag
|
||||||
|
:return: None or Boolean
|
||||||
|
"""
|
||||||
|
return self._no_mass
|
||||||
|
|
||||||
|
@no_mass.setter
|
||||||
|
def no_mass(self, value):
|
||||||
|
"""
|
||||||
|
Set material no mass flag
|
||||||
|
:param value: Boolean
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._no_mass = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def thermal_resistance(self) -> Union[None, float]:
|
||||||
|
"""
|
||||||
|
Get material thermal resistance in m2K/W
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
return self._thermal_resistance
|
||||||
|
|
||||||
|
@thermal_resistance.setter
|
||||||
|
def thermal_resistance(self, value):
|
||||||
|
"""
|
||||||
|
Set material thermal resistance in m2K/W
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._thermal_resistance = float(value)
|
||||||
|
|
|
@ -1,193 +0,0 @@
|
||||||
"""
|
|
||||||
Material module
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
|
|
||||||
class Material:
|
|
||||||
"""
|
|
||||||
Material class
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self._id = None
|
|
||||||
self._name = None
|
|
||||||
self._conductivity = None
|
|
||||||
self._specific_heat = None
|
|
||||||
self._density = None
|
|
||||||
self._solar_absorptance = None
|
|
||||||
self._thermal_absorptance = None
|
|
||||||
self._visible_absorptance = None
|
|
||||||
self._no_mass = False
|
|
||||||
self._thermal_resistance = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self):
|
|
||||||
"""
|
|
||||||
Get material id
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
return self._id
|
|
||||||
|
|
||||||
@id.setter
|
|
||||||
def id(self, value):
|
|
||||||
"""
|
|
||||||
Set material id
|
|
||||||
:param value: str
|
|
||||||
"""
|
|
||||||
self._id = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""
|
|
||||||
Get material name
|
|
||||||
:return: str
|
|
||||||
"""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, value):
|
|
||||||
"""
|
|
||||||
Set material name
|
|
||||||
:param value: string
|
|
||||||
"""
|
|
||||||
self._name = str(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def conductivity(self) -> Union[None, float]:
|
|
||||||
"""
|
|
||||||
Get material conductivity in W/mK
|
|
||||||
:return: None or float
|
|
||||||
"""
|
|
||||||
return self._conductivity
|
|
||||||
|
|
||||||
@conductivity.setter
|
|
||||||
def conductivity(self, value):
|
|
||||||
"""
|
|
||||||
Set material conductivity in W/mK
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._conductivity = float(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def specific_heat(self) -> Union[None, float]:
|
|
||||||
"""
|
|
||||||
Get material conductivity in J/kgK
|
|
||||||
:return: None or float
|
|
||||||
"""
|
|
||||||
return self._specific_heat
|
|
||||||
|
|
||||||
@specific_heat.setter
|
|
||||||
def specific_heat(self, value):
|
|
||||||
"""
|
|
||||||
Get material conductivity in J/kgK
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._specific_heat = float(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def density(self) -> Union[None, float]:
|
|
||||||
"""
|
|
||||||
Get material density in kg/m3
|
|
||||||
:return: None or float
|
|
||||||
"""
|
|
||||||
return self._density
|
|
||||||
|
|
||||||
@density.setter
|
|
||||||
def density(self, value):
|
|
||||||
"""
|
|
||||||
Set material density
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._density = float(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def solar_absorptance(self) -> Union[None, float]:
|
|
||||||
"""
|
|
||||||
Get material solar absorptance
|
|
||||||
:return: None or float
|
|
||||||
"""
|
|
||||||
return self._solar_absorptance
|
|
||||||
|
|
||||||
@solar_absorptance.setter
|
|
||||||
def solar_absorptance(self, value):
|
|
||||||
"""
|
|
||||||
Set material solar absorptance
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._solar_absorptance = float(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def thermal_absorptance(self) -> Union[None, float]:
|
|
||||||
"""
|
|
||||||
Get material thermal absorptance
|
|
||||||
:return: None or float
|
|
||||||
"""
|
|
||||||
return self._thermal_absorptance
|
|
||||||
|
|
||||||
@thermal_absorptance.setter
|
|
||||||
def thermal_absorptance(self, value):
|
|
||||||
"""
|
|
||||||
Set material thermal absorptance
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._thermal_absorptance = float(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def visible_absorptance(self) -> Union[None, float]:
|
|
||||||
"""
|
|
||||||
Get material visible absorptance
|
|
||||||
:return: None or float
|
|
||||||
"""
|
|
||||||
return self._visible_absorptance
|
|
||||||
|
|
||||||
@visible_absorptance.setter
|
|
||||||
def visible_absorptance(self, value):
|
|
||||||
"""
|
|
||||||
Set material visible absorptance
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._visible_absorptance = float(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def no_mass(self) -> Union[None, bool]:
|
|
||||||
"""
|
|
||||||
Get material no mass flag
|
|
||||||
:return: None or Boolean
|
|
||||||
"""
|
|
||||||
return self._no_mass
|
|
||||||
|
|
||||||
@no_mass.setter
|
|
||||||
def no_mass(self, value):
|
|
||||||
"""
|
|
||||||
Set material no mass flag
|
|
||||||
:param value: Boolean
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._no_mass = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def thermal_resistance(self) -> Union[None, float]:
|
|
||||||
"""
|
|
||||||
Get material thermal resistance in m2K/W
|
|
||||||
:return: None or float
|
|
||||||
"""
|
|
||||||
return self._thermal_resistance
|
|
||||||
|
|
||||||
@thermal_resistance.setter
|
|
||||||
def thermal_resistance(self, value):
|
|
||||||
"""
|
|
||||||
Set material thermal resistance in m2K/W
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._thermal_resistance = float(value)
|
|
|
@ -90,7 +90,9 @@ class Storey:
|
||||||
:return: ThermalZone
|
:return: ThermalZone
|
||||||
"""
|
"""
|
||||||
if self._thermal_zone is None:
|
if self._thermal_zone is None:
|
||||||
self._thermal_zone = ThermalZone(self.thermal_boundaries, self._internal_zone, self.volume, self.floor_area)
|
_number_of_storeys = 1
|
||||||
|
self._thermal_zone = ThermalZone(self.thermal_boundaries, self._internal_zone,
|
||||||
|
self.volume, self.floor_area, _number_of_storeys)
|
||||||
return self._thermal_zone
|
return self._thermal_zone
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -10,14 +10,15 @@ from __future__ import annotations
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import uuid
|
import uuid
|
||||||
import numpy as np
|
|
||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
|
import numpy as np
|
||||||
from hub.city_model_structure.attributes.polygon import Polygon
|
from hub.city_model_structure.attributes.polygon import Polygon
|
||||||
from hub.city_model_structure.attributes.plane import Plane
|
from hub.city_model_structure.attributes.plane import Plane
|
||||||
from hub.city_model_structure.attributes.point import Point
|
from hub.city_model_structure.attributes.point import Point
|
||||||
from hub.city_model_structure.greenery.vegetation import Vegetation
|
from hub.city_model_structure.greenery.vegetation import Vegetation
|
||||||
from hub.city_model_structure.building_demand.thermal_boundary import ThermalBoundary
|
from hub.city_model_structure.building_demand.thermal_boundary import ThermalBoundary
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
|
from hub.helpers.configuration_helper import ConfigurationHelper
|
||||||
|
|
||||||
|
|
||||||
class Surface:
|
class Surface:
|
||||||
|
@ -34,17 +35,19 @@ class Surface:
|
||||||
self._area = None
|
self._area = None
|
||||||
self._lower_corner = None
|
self._lower_corner = None
|
||||||
self._upper_corner = None
|
self._upper_corner = None
|
||||||
self._global_irradiance = dict()
|
self._global_irradiance = {}
|
||||||
self._perimeter_polygon = perimeter_polygon
|
self._perimeter_polygon = perimeter_polygon
|
||||||
self._holes_polygons = holes_polygons
|
self._holes_polygons = holes_polygons
|
||||||
self._solid_polygon = solid_polygon
|
self._solid_polygon = solid_polygon
|
||||||
self._short_wave_reflectance = None
|
self._short_wave_reflectance = None
|
||||||
self._long_wave_emittance = None
|
self._long_wave_emittance = None
|
||||||
self._inverse = None
|
self._inverse = None
|
||||||
self._associated_thermal_boundaries = []
|
self._associated_thermal_boundaries = None
|
||||||
self._vegetation = None
|
self._vegetation = None
|
||||||
self._percentage_shared = None
|
self._percentage_shared = None
|
||||||
self._solar_collectors_area_reduction_factor = None
|
self._solar_collectors_area_reduction_factor = None
|
||||||
|
self._global_irradiance_tilted = {}
|
||||||
|
self._installed_solar_collector_area = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -154,7 +157,6 @@ class Surface:
|
||||||
if self._inclination is None:
|
if self._inclination is None:
|
||||||
self._inclination = np.arccos(self.perimeter_polygon.normal[2])
|
self._inclination = np.arccos(self.perimeter_polygon.normal[2])
|
||||||
return self._inclination
|
return self._inclination
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
"""
|
"""
|
||||||
|
@ -178,16 +180,16 @@ class Surface:
|
||||||
@property
|
@property
|
||||||
def global_irradiance(self) -> dict:
|
def global_irradiance(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get global irradiance on surface in Wh/m2
|
Get global irradiance on surface in W/m2
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict
|
||||||
"""
|
"""
|
||||||
return self._global_irradiance
|
return self._global_irradiance
|
||||||
|
|
||||||
@global_irradiance.setter
|
@global_irradiance.setter
|
||||||
def global_irradiance(self, value):
|
def global_irradiance(self, value):
|
||||||
"""
|
"""
|
||||||
Set global irradiance on surface in Wh/m2
|
Set global irradiance on surface in W/m2
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict
|
||||||
"""
|
"""
|
||||||
self._global_irradiance = value
|
self._global_irradiance = value
|
||||||
|
|
||||||
|
@ -384,3 +386,35 @@ class Surface:
|
||||||
:param value: float
|
:param value: float
|
||||||
"""
|
"""
|
||||||
self._solar_collectors_area_reduction_factor = value
|
self._solar_collectors_area_reduction_factor = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def global_irradiance_tilted(self) -> dict:
|
||||||
|
"""
|
||||||
|
Get global irradiance on a tilted surface in W/m2
|
||||||
|
:return: dict
|
||||||
|
"""
|
||||||
|
return self._global_irradiance_tilted
|
||||||
|
|
||||||
|
@global_irradiance_tilted.setter
|
||||||
|
def global_irradiance_tilted(self, value):
|
||||||
|
"""
|
||||||
|
Set global irradiance on a tilted surface in W/m2
|
||||||
|
:param value: dict
|
||||||
|
"""
|
||||||
|
self._global_irradiance_tilted = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def installed_solar_collector_area(self):
|
||||||
|
"""
|
||||||
|
Get installed solar collector area in m2
|
||||||
|
:return: dict
|
||||||
|
"""
|
||||||
|
return self._installed_solar_collector_area
|
||||||
|
|
||||||
|
@installed_solar_collector_area.setter
|
||||||
|
def installed_solar_collector_area(self, value):
|
||||||
|
"""
|
||||||
|
Set installed solar collector area in m2
|
||||||
|
:return: dict
|
||||||
|
"""
|
||||||
|
self._installed_solar_collector_area = value
|
168
hub/city_model_structure/building_demand/thermal_archetype.py
Normal file
168
hub/city_model_structure/building_demand/thermal_archetype.py
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
"""
|
||||||
|
Thermal archetype module
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2022 Concordia CERC group
|
||||||
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
|
"""
|
||||||
|
|
||||||
|
from hub.city_model_structure.building_demand.construction import Construction
|
||||||
|
|
||||||
|
|
||||||
|
class ThermalArchetype:
|
||||||
|
"""
|
||||||
|
ThermalArchetype class
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self._constructions = None
|
||||||
|
self._average_storey_height = None
|
||||||
|
self._thermal_capacity = None
|
||||||
|
self._extra_loses_due_to_thermal_bridges = None
|
||||||
|
self._indirect_heated_ratio = None
|
||||||
|
self._infiltration_rate_for_ventilation_system_off = None
|
||||||
|
self._infiltration_rate_for_ventilation_system_on = None
|
||||||
|
self._infiltration_rate_area_for_ventilation_system_off=None
|
||||||
|
self._infiltration_rate_area_for_ventilation_system_on=None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def constructions(self) -> [Construction]:
|
||||||
|
"""
|
||||||
|
Get archetype constructions
|
||||||
|
:return: [Construction]
|
||||||
|
"""
|
||||||
|
return self._constructions
|
||||||
|
|
||||||
|
@constructions.setter
|
||||||
|
def constructions(self, value):
|
||||||
|
"""
|
||||||
|
Set archetype constructions
|
||||||
|
:param value: [Construction]
|
||||||
|
"""
|
||||||
|
self._constructions = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def average_storey_height(self):
|
||||||
|
"""
|
||||||
|
Get average storey height in m
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._average_storey_height
|
||||||
|
|
||||||
|
@average_storey_height.setter
|
||||||
|
def average_storey_height(self, value):
|
||||||
|
"""
|
||||||
|
Set average storey height in m
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._average_storey_height = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def thermal_capacity(self):
|
||||||
|
"""
|
||||||
|
Get thermal capacity in J/m3K
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._thermal_capacity
|
||||||
|
|
||||||
|
@thermal_capacity.setter
|
||||||
|
def thermal_capacity(self, value):
|
||||||
|
"""
|
||||||
|
Set thermal capacity in J/m3K
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._thermal_capacity = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extra_loses_due_to_thermal_bridges(self):
|
||||||
|
"""
|
||||||
|
Get extra loses due to thermal bridges in W/m2K
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._extra_loses_due_to_thermal_bridges
|
||||||
|
|
||||||
|
@extra_loses_due_to_thermal_bridges.setter
|
||||||
|
def extra_loses_due_to_thermal_bridges(self, value):
|
||||||
|
"""
|
||||||
|
Set extra loses due to thermal bridges in W/m2K
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._extra_loses_due_to_thermal_bridges = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def indirect_heated_ratio(self):
|
||||||
|
"""
|
||||||
|
Get indirect heated area ratio
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._indirect_heated_ratio
|
||||||
|
|
||||||
|
@indirect_heated_ratio.setter
|
||||||
|
def indirect_heated_ratio(self, value):
|
||||||
|
"""
|
||||||
|
Set indirect heated area ratio
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._indirect_heated_ratio = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def infiltration_rate_for_ventilation_system_off(self):
|
||||||
|
"""
|
||||||
|
Get infiltration rate for ventilation system off in ACH
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._infiltration_rate_for_ventilation_system_off
|
||||||
|
|
||||||
|
@infiltration_rate_for_ventilation_system_off.setter
|
||||||
|
def infiltration_rate_for_ventilation_system_off(self, value):
|
||||||
|
"""
|
||||||
|
Set infiltration rate for ventilation system off in ACH
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._infiltration_rate_for_ventilation_system_off = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def infiltration_rate_for_ventilation_system_on(self):
|
||||||
|
"""
|
||||||
|
Get infiltration rate for ventilation system on in ACH
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._infiltration_rate_for_ventilation_system_on
|
||||||
|
|
||||||
|
@infiltration_rate_for_ventilation_system_on.setter
|
||||||
|
def infiltration_rate_for_ventilation_system_on(self, value):
|
||||||
|
"""
|
||||||
|
Set infiltration rate for ventilation system on in ACH
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._infiltration_rate_for_ventilation_system_on = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def infiltration_rate_area_for_ventilation_system_off(self):
|
||||||
|
"""
|
||||||
|
Get infiltration rate for ventilation system off in l/s/m2
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._infiltration_rate_for_ventilation_system_off
|
||||||
|
|
||||||
|
@infiltration_rate_area_for_ventilation_system_off.setter
|
||||||
|
def infiltration_rate_area_for_ventilation_system_off(self, value):
|
||||||
|
"""
|
||||||
|
Set infiltration rate for ventilation system off in l/s/m2
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._infiltration_rate_for_ventilation_system_off = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def infiltration_rate_area_for_ventilation_system_on(self):
|
||||||
|
"""
|
||||||
|
Get infiltration rate for ventilation system on in l/s/m2
|
||||||
|
:return: float
|
||||||
|
"""
|
||||||
|
return self._infiltration_rate_for_ventilation_system_on
|
||||||
|
|
||||||
|
@infiltration_rate_area_for_ventilation_system_on.setter
|
||||||
|
def infiltration_rate_area_for_ventilation_system_on(self, value):
|
||||||
|
"""
|
||||||
|
Set infiltration rate for ventilation system on in l/s/m2
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
|
self._infiltration_rate_for_ventilation_system_on = value
|
|
@ -7,7 +7,9 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
import math
|
||||||
from typing import List, Union, TypeVar
|
from typing import List, Union, TypeVar
|
||||||
|
import logging
|
||||||
from hub.helpers.configuration_helper import ConfigurationHelper as ch
|
from hub.helpers.configuration_helper import ConfigurationHelper as ch
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
from hub.city_model_structure.building_demand.layer import Layer
|
from hub.city_model_structure.building_demand.layer import Layer
|
||||||
|
@ -35,8 +37,11 @@ class ThermalBoundary:
|
||||||
self._construction_name = None
|
self._construction_name = None
|
||||||
self._thickness = None
|
self._thickness = None
|
||||||
self._internal_surface = None
|
self._internal_surface = None
|
||||||
self._window_ratio = None
|
self._external_surface = None
|
||||||
self._window_ratio_is_calculated = False
|
self._window_ratio = 0
|
||||||
|
self._window_ratio_to_be_calculated = False
|
||||||
|
if self._windows_areas is not None:
|
||||||
|
self._window_ratio_to_be_calculated = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
@ -51,7 +56,7 @@ class ThermalBoundary:
|
||||||
@property
|
@property
|
||||||
def parent_surface(self) -> Surface:
|
def parent_surface(self) -> Surface:
|
||||||
"""
|
"""
|
||||||
Get the surface that belongs to the thermal boundary
|
Get the surface that belongs to the thermal boundary, considered the external surface of that boundary
|
||||||
:return: Surface
|
:return: Surface
|
||||||
"""
|
"""
|
||||||
return self._parent_surface
|
return self._parent_surface
|
||||||
|
@ -90,7 +95,7 @@ class ThermalBoundary:
|
||||||
self._thickness = 0.0
|
self._thickness = 0.0
|
||||||
if self.layers is not None:
|
if self.layers is not None:
|
||||||
for layer in self.layers:
|
for layer in self.layers:
|
||||||
if not layer.material.no_mass:
|
if not layer.no_mass:
|
||||||
self._thickness += layer.thickness
|
self._thickness += layer.thickness
|
||||||
return self._thickness
|
return self._thickness
|
||||||
|
|
||||||
|
@ -101,18 +106,7 @@ class ThermalBoundary:
|
||||||
:return: None or [ThermalOpening]
|
:return: None or [ThermalOpening]
|
||||||
"""
|
"""
|
||||||
if self._thermal_openings is None:
|
if self._thermal_openings is None:
|
||||||
if self.window_ratio is not None:
|
if self.windows_areas is not None:
|
||||||
if self.window_ratio == 0:
|
|
||||||
self._thermal_openings = []
|
|
||||||
else:
|
|
||||||
thermal_opening = ThermalOpening()
|
|
||||||
if self.window_ratio == 1:
|
|
||||||
_area = self.opaque_area
|
|
||||||
else:
|
|
||||||
_area = self.opaque_area * self.window_ratio / (1-self.window_ratio)
|
|
||||||
thermal_opening.area = _area
|
|
||||||
self._thermal_openings = [thermal_opening]
|
|
||||||
else:
|
|
||||||
if len(self.windows_areas) > 0:
|
if len(self.windows_areas) > 0:
|
||||||
self._thermal_openings = []
|
self._thermal_openings = []
|
||||||
for window_area in self.windows_areas:
|
for window_area in self.windows_areas:
|
||||||
|
@ -121,24 +115,57 @@ class ThermalBoundary:
|
||||||
self._thermal_openings.append(thermal_opening)
|
self._thermal_openings.append(thermal_opening)
|
||||||
else:
|
else:
|
||||||
self._thermal_openings = []
|
self._thermal_openings = []
|
||||||
|
else:
|
||||||
|
if self.window_ratio is not None:
|
||||||
|
if self.window_ratio == 0:
|
||||||
|
self._thermal_openings = []
|
||||||
|
else:
|
||||||
|
thermal_opening = ThermalOpening()
|
||||||
|
if self.window_ratio == 1:
|
||||||
|
_area = self.opaque_area
|
||||||
|
else:
|
||||||
|
_area = self.opaque_area * self.window_ratio / (1-self.window_ratio)
|
||||||
|
thermal_opening.area = _area
|
||||||
|
self._thermal_openings = [thermal_opening]
|
||||||
|
else:
|
||||||
|
self._thermal_openings = []
|
||||||
|
else:
|
||||||
|
if self.windows_areas is not None:
|
||||||
|
return self._thermal_openings
|
||||||
|
if self.window_ratio is not None:
|
||||||
|
if self.window_ratio == 0:
|
||||||
|
self._thermal_openings = []
|
||||||
|
else:
|
||||||
|
if len(self._thermal_openings) == 0:
|
||||||
|
thermal_opening = ThermalOpening()
|
||||||
|
if self.window_ratio == 1:
|
||||||
|
_area = self.opaque_area
|
||||||
|
else:
|
||||||
|
_area = self.opaque_area * self.window_ratio / (1-self.window_ratio)
|
||||||
|
thermal_opening.area = _area
|
||||||
|
self._thermal_openings = [thermal_opening]
|
||||||
|
else:
|
||||||
|
for _thermal_opening in self._thermal_openings:
|
||||||
|
if self.window_ratio == 1:
|
||||||
|
_area = self.opaque_area
|
||||||
|
else:
|
||||||
|
_area = self.opaque_area * self.window_ratio / (1-self.window_ratio)
|
||||||
|
_thermal_opening.area = _area
|
||||||
|
self._thermal_openings = [_thermal_opening]
|
||||||
|
for thermal_opening in self._thermal_openings:
|
||||||
|
thermal_opening.g_value = self._construction_archetype.window_g_value
|
||||||
|
thermal_opening.overall_u_value = self._construction_archetype.window_overall_u_value
|
||||||
|
thermal_opening.frame_ratio = self._construction_archetype.window_frame_ratio
|
||||||
|
thermal_opening.construction_name = self._construction_archetype.window_type
|
||||||
return self._thermal_openings
|
return self._thermal_openings
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def construction_name(self) -> Union[None, str]:
|
def _construction_archetype(self):
|
||||||
"""
|
construction_archetypes = self.thermal_zones[0].parent_internal_zone.thermal_archetype.constructions
|
||||||
Get construction name
|
for construction_archetype in construction_archetypes:
|
||||||
:return: None or str
|
if str(self.type) == str(construction_archetype.type):
|
||||||
"""
|
return construction_archetype
|
||||||
return self._construction_name
|
return None
|
||||||
|
|
||||||
@construction_name.setter
|
|
||||||
def construction_name(self, value):
|
|
||||||
"""
|
|
||||||
Set construction name
|
|
||||||
:param value: str
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._construction_name = str(value)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def layers(self) -> List[Layer]:
|
def layers(self) -> List[Layer]:
|
||||||
|
@ -146,16 +173,13 @@ class ThermalBoundary:
|
||||||
Get thermal boundary layers
|
Get thermal boundary layers
|
||||||
:return: [Layers]
|
:return: [Layers]
|
||||||
"""
|
"""
|
||||||
|
if self._construction_archetype is not None:
|
||||||
|
self._layers = self._construction_archetype.layers
|
||||||
|
else:
|
||||||
|
logging.error('Layers not defined\n')
|
||||||
|
raise ValueError('Layers not defined')
|
||||||
return self._layers
|
return self._layers
|
||||||
|
|
||||||
@layers.setter
|
|
||||||
def layers(self, value):
|
|
||||||
"""
|
|
||||||
Set thermal boundary layers
|
|
||||||
:param value: [Layer]
|
|
||||||
"""
|
|
||||||
self._layers = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
"""
|
"""
|
||||||
|
@ -174,28 +198,31 @@ class ThermalBoundary:
|
||||||
If none of those sources are available, it returns None.
|
If none of those sources are available, it returns None.
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self.windows_areas is not None:
|
if self._window_ratio_to_be_calculated:
|
||||||
if not self._window_ratio_is_calculated:
|
if len(self.windows_areas) == 0:
|
||||||
_calculated = True
|
self._window_ratio = 0
|
||||||
if len(self.windows_areas) == 0:
|
else:
|
||||||
self._window_ratio = 0
|
total_window_area = 0
|
||||||
|
for window_area in self.windows_areas:
|
||||||
|
total_window_area += window_area
|
||||||
|
self._window_ratio = total_window_area / (self.opaque_area + total_window_area)
|
||||||
|
else:
|
||||||
|
if self.type in (cte.WALL, cte.ROOF):
|
||||||
|
if -math.sqrt(2) / 2 < math.sin(self.parent_surface.azimuth) < math.sqrt(2) / 2:
|
||||||
|
if 0 < math.cos(self.parent_surface.azimuth):
|
||||||
|
self._window_ratio = \
|
||||||
|
float(self._construction_archetype.window_ratio['north']) / 100
|
||||||
|
else:
|
||||||
|
self._window_ratio = \
|
||||||
|
float(self._construction_archetype.window_ratio['south']) / 100
|
||||||
|
elif math.sqrt(2) / 2 <= math.sin(self._parent_surface.azimuth):
|
||||||
|
self._window_ratio = \
|
||||||
|
float(self._construction_archetype.window_ratio['east']) / 100
|
||||||
else:
|
else:
|
||||||
total_window_area = 0
|
self._window_ratio = \
|
||||||
for window_area in self.windows_areas:
|
float(self._construction_archetype.window_ratio['west']) / 100
|
||||||
total_window_area += window_area
|
|
||||||
self._window_ratio = total_window_area / (self.opaque_area + total_window_area)
|
|
||||||
return self._window_ratio
|
return self._window_ratio
|
||||||
|
|
||||||
@window_ratio.setter
|
|
||||||
def window_ratio(self, value):
|
|
||||||
"""
|
|
||||||
Set thermal boundary window ratio
|
|
||||||
:param value: str
|
|
||||||
"""
|
|
||||||
if self._window_ratio_is_calculated:
|
|
||||||
raise ValueError('Window ratio cannot be assigned when the windows are defined in the geometry.')
|
|
||||||
self._window_ratio = float(value)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def windows_areas(self) -> [float]:
|
def windows_areas(self) -> [float]:
|
||||||
"""
|
"""
|
||||||
|
@ -220,15 +247,28 @@ class ThermalBoundary:
|
||||||
r_value = 1.0/h_i + 1.0/h_e
|
r_value = 1.0/h_i + 1.0/h_e
|
||||||
try:
|
try:
|
||||||
for layer in self.layers:
|
for layer in self.layers:
|
||||||
if layer.material.no_mass:
|
if layer.no_mass:
|
||||||
r_value += float(layer.material.thermal_resistance)
|
r_value += float(layer.thermal_resistance)
|
||||||
else:
|
else:
|
||||||
r_value += float(layer.thickness) / float(layer.material.conductivity)
|
r_value += float(layer.thickness) / float(layer.conductivity)
|
||||||
self._u_value = 1.0/r_value
|
self._u_value = 1.0/r_value
|
||||||
except TypeError:
|
except TypeError:
|
||||||
raise Exception('Constructions layers are not initialized') from TypeError
|
raise TypeError('Constructions layers are not initialized') from TypeError
|
||||||
return self._u_value
|
return self._u_value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def construction_name(self):
|
||||||
|
"""
|
||||||
|
Get construction name
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
if self._construction_archetype is not None:
|
||||||
|
self._construction_name = self._construction_archetype.name
|
||||||
|
else:
|
||||||
|
logging.error('Construction name not defined\n')
|
||||||
|
raise ValueError('Construction name not defined')
|
||||||
|
return self._construction_name
|
||||||
|
|
||||||
@u_value.setter
|
@u_value.setter
|
||||||
def u_value(self, value):
|
def u_value(self, value):
|
||||||
"""
|
"""
|
||||||
|
@ -280,4 +320,18 @@ class ThermalBoundary:
|
||||||
"""
|
"""
|
||||||
if self._internal_surface is None:
|
if self._internal_surface is None:
|
||||||
self._internal_surface = self.parent_surface.inverse
|
self._internal_surface = self.parent_surface.inverse
|
||||||
|
# The agreement is that the layers are defined from outside to inside
|
||||||
|
internal_layer = self.layers[len(self.layers) - 1]
|
||||||
|
self._internal_surface.short_wave_reflectance = 1 - internal_layer.solar_absorptance
|
||||||
|
self._internal_surface.long_wave_emittance = 1 - internal_layer.solar_absorptance
|
||||||
|
|
||||||
return self._internal_surface
|
return self._internal_surface
|
||||||
|
|
||||||
|
@property
|
||||||
|
def external_surface(self) -> Surface:
|
||||||
|
if self._external_surface is None:
|
||||||
|
# The agreement is that the layers are defined from outside to inside
|
||||||
|
self._external_surface = self.parent_surface
|
||||||
|
self._external_surface.short_wave_reflectance = 1 - self.layers[0].solar_absorptance
|
||||||
|
self._external_surface.long_wave_emittance = 1 - self.layers[0].solar_absorptance
|
||||||
|
return self._external_surface
|
||||||
|
|
|
@ -4,6 +4,7 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2022 Concordia CERC group
|
Copyright © 2022 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
from math import inf
|
||||||
from typing import Union, List
|
from typing import Union, List
|
||||||
from hub.city_model_structure.attributes.schedule import Schedule
|
from hub.city_model_structure.attributes.schedule import Schedule
|
||||||
|
|
||||||
|
@ -22,20 +23,16 @@ class ThermalControl:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _maximum_value(schedules):
|
def _maximum_value(schedules):
|
||||||
maximum = -1000
|
maximum = -inf
|
||||||
for schedule in schedules:
|
for schedule in schedules:
|
||||||
for value in schedule.values:
|
maximum = max(maximum, max(schedule.values))
|
||||||
if value > maximum:
|
|
||||||
maximum = value
|
|
||||||
return maximum
|
return maximum
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _minimum_value(schedules):
|
def _minimum_value(schedules):
|
||||||
minimum = 1000
|
minimum = inf
|
||||||
for schedule in schedules:
|
for schedule in schedules:
|
||||||
for value in schedule.values:
|
minimum = min(minimum, min(schedule.values))
|
||||||
if value < minimum:
|
|
||||||
minimum = value
|
|
||||||
return minimum
|
return minimum
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -8,8 +8,9 @@ Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concord
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
import copy
|
import copy
|
||||||
import numpy
|
|
||||||
from typing import List, Union, TypeVar
|
from typing import List, Union, TypeVar
|
||||||
|
import numpy
|
||||||
|
|
||||||
from hub.city_model_structure.building_demand.occupancy import Occupancy
|
from hub.city_model_structure.building_demand.occupancy import Occupancy
|
||||||
from hub.city_model_structure.building_demand.appliances import Appliances
|
from hub.city_model_structure.building_demand.appliances import Appliances
|
||||||
from hub.city_model_structure.building_demand.lighting import Lighting
|
from hub.city_model_structure.building_demand.lighting import Lighting
|
||||||
|
@ -28,7 +29,12 @@ class ThermalZone:
|
||||||
ThermalZone class
|
ThermalZone class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, thermal_boundaries, parent_internal_zone, volume, footprint_area, usage_name=None):
|
def __init__(self, thermal_boundaries,
|
||||||
|
parent_internal_zone,
|
||||||
|
volume,
|
||||||
|
footprint_area,
|
||||||
|
number_of_storeys,
|
||||||
|
usage_name=None):
|
||||||
self._id = None
|
self._id = None
|
||||||
self._parent_internal_zone = parent_internal_zone
|
self._parent_internal_zone = parent_internal_zone
|
||||||
self._footprint_area = footprint_area
|
self._footprint_area = footprint_area
|
||||||
|
@ -38,10 +44,13 @@ class ThermalZone:
|
||||||
self._indirectly_heated_area_ratio = None
|
self._indirectly_heated_area_ratio = None
|
||||||
self._infiltration_rate_system_on = None
|
self._infiltration_rate_system_on = None
|
||||||
self._infiltration_rate_system_off = None
|
self._infiltration_rate_system_off = None
|
||||||
|
self._infiltration_rate_area_system_on = None
|
||||||
|
self._infiltration_rate_area_system_off = None
|
||||||
self._volume = volume
|
self._volume = volume
|
||||||
self._ordinate_number = None
|
self._ordinate_number = None
|
||||||
self._view_factors_matrix = None
|
self._view_factors_matrix = None
|
||||||
self._total_floor_area = None
|
self._total_floor_area = None
|
||||||
|
self._number_of_storeys = number_of_storeys
|
||||||
self._usage_name = usage_name
|
self._usage_name = usage_name
|
||||||
self._usage_from_parent = False
|
self._usage_from_parent = False
|
||||||
if usage_name is None:
|
if usage_name is None:
|
||||||
|
@ -57,9 +66,21 @@ class ThermalZone:
|
||||||
self._domestic_hot_water = None
|
self._domestic_hot_water = None
|
||||||
self._usages = None
|
self._usages = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parent_internal_zone(self) -> InternalZone:
|
||||||
|
"""
|
||||||
|
Get the internal zone to which this thermal zone belongs
|
||||||
|
:return: InternalZone
|
||||||
|
"""
|
||||||
|
return self._parent_internal_zone
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usages(self):
|
def usages(self):
|
||||||
# example 70-office_30-residential
|
"""
|
||||||
|
Get the thermal zone usages including percentage with the format [percentage]-usage_[percentage]-usage...
|
||||||
|
Eg: 70-office_30-residential
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
if self._usage_from_parent:
|
if self._usage_from_parent:
|
||||||
self._usages = copy.deepcopy(self._parent_internal_zone.usages)
|
self._usages = copy.deepcopy(self._parent_internal_zone.usages)
|
||||||
else:
|
else:
|
||||||
|
@ -108,82 +129,62 @@ class ThermalZone:
|
||||||
Get thermal zone additional thermal bridge u value per footprint area W/m2K
|
Get thermal zone additional thermal bridge u value per footprint area W/m2K
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
|
self._additional_thermal_bridge_u_value = self.parent_internal_zone.thermal_archetype.extra_loses_due_to_thermal_bridges
|
||||||
return self._additional_thermal_bridge_u_value
|
return self._additional_thermal_bridge_u_value
|
||||||
|
|
||||||
@additional_thermal_bridge_u_value.setter
|
|
||||||
def additional_thermal_bridge_u_value(self, value):
|
|
||||||
"""
|
|
||||||
Set thermal zone additional thermal bridge u value per footprint area W/m2K
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._additional_thermal_bridge_u_value = float(value)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def effective_thermal_capacity(self) -> Union[None, float]:
|
def effective_thermal_capacity(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get thermal zone effective thermal capacity in J/m3K
|
Get thermal zone effective thermal capacity in J/m3K
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
|
self._effective_thermal_capacity = self._parent_internal_zone.thermal_archetype.thermal_capacity
|
||||||
return self._effective_thermal_capacity
|
return self._effective_thermal_capacity
|
||||||
|
|
||||||
@effective_thermal_capacity.setter
|
|
||||||
def effective_thermal_capacity(self, value):
|
|
||||||
"""
|
|
||||||
Set thermal zone effective thermal capacity in J/m3K
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._effective_thermal_capacity = float(value)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def indirectly_heated_area_ratio(self) -> Union[None, float]:
|
def indirectly_heated_area_ratio(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get thermal zone indirectly heated area ratio
|
Get thermal zone indirectly heated area ratio
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
|
self._indirectly_heated_area_ratio = self._parent_internal_zone.thermal_archetype.indirect_heated_ratio
|
||||||
return self._indirectly_heated_area_ratio
|
return self._indirectly_heated_area_ratio
|
||||||
|
|
||||||
@indirectly_heated_area_ratio.setter
|
|
||||||
def indirectly_heated_area_ratio(self, value):
|
|
||||||
"""
|
|
||||||
Set thermal zone indirectly heated area ratio
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._indirectly_heated_area_ratio = float(value)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def infiltration_rate_system_on(self):
|
def infiltration_rate_system_on(self):
|
||||||
"""
|
"""
|
||||||
Get thermal zone infiltration rate system on in air changes per hour (ACH)
|
Get thermal zone infiltration rate system on in air changes per second (1/s)
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
|
self._infiltration_rate_system_on = self._parent_internal_zone.thermal_archetype.infiltration_rate_for_ventilation_system_on
|
||||||
return self._infiltration_rate_system_on
|
return self._infiltration_rate_system_on
|
||||||
|
|
||||||
@infiltration_rate_system_on.setter
|
|
||||||
def infiltration_rate_system_on(self, value):
|
|
||||||
"""
|
|
||||||
Set thermal zone infiltration rate system on in air changes per hour (ACH)
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
self._infiltration_rate_system_on = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def infiltration_rate_system_off(self):
|
def infiltration_rate_system_off(self):
|
||||||
"""
|
"""
|
||||||
Get thermal zone infiltration rate system off in air changes per hour (ACH)
|
Get thermal zone infiltration rate system off in air changes per second (1/s)
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
|
self._infiltration_rate_system_off = self._parent_internal_zone.thermal_archetype.infiltration_rate_for_ventilation_system_off
|
||||||
return self._infiltration_rate_system_off
|
return self._infiltration_rate_system_off
|
||||||
|
|
||||||
@infiltration_rate_system_off.setter
|
@property
|
||||||
def infiltration_rate_system_off(self, value):
|
def infiltration_rate_area_system_on(self):
|
||||||
"""
|
"""
|
||||||
Set thermal zone infiltration rate system on in air changes per hour (ACH)
|
Get thermal zone infiltration rate system on in air changes per second (1/s)
|
||||||
:param value: float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
self._infiltration_rate_system_off = value
|
self._infiltration_rate_area_system_on = self._parent_internal_zone.thermal_archetype.infiltration_rate_area_for_ventilation_system_on
|
||||||
|
return self._infiltration_rate_area_system_on
|
||||||
|
|
||||||
|
@property
|
||||||
|
def infiltration_rate_area_system_off(self):
|
||||||
|
"""
|
||||||
|
Get thermal zone infiltration rate system off in air changes per second (1/s)
|
||||||
|
:return: None or float
|
||||||
|
"""
|
||||||
|
self._infiltration_rate_area_system_off = self._parent_internal_zone.thermal_archetype.infiltration_rate_area_for_ventilation_system_off
|
||||||
|
return self._infiltration_rate_area_system_off
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume(self):
|
def volume(self):
|
||||||
|
@ -216,15 +217,43 @@ class ThermalZone:
|
||||||
Get thermal zone view factors matrix
|
Get thermal zone view factors matrix
|
||||||
:return: [[float]]
|
:return: [[float]]
|
||||||
"""
|
"""
|
||||||
return self._view_factors_matrix
|
# todo: review method if windows not in window_ratio but in geometry
|
||||||
|
if self._view_factors_matrix is None:
|
||||||
|
total_area = 0
|
||||||
|
for thermal_boundary in self.thermal_boundaries:
|
||||||
|
total_area += thermal_boundary.opaque_area
|
||||||
|
for thermal_opening in thermal_boundary.thermal_openings:
|
||||||
|
total_area += thermal_opening.area
|
||||||
|
|
||||||
@view_factors_matrix.setter
|
view_factors_matrix = []
|
||||||
def view_factors_matrix(self, value):
|
for thermal_boundary_1 in self.thermal_boundaries:
|
||||||
"""
|
values = []
|
||||||
Set thermal zone view factors matrix
|
for thermal_boundary_2 in self.thermal_boundaries:
|
||||||
:param value: [[float]]
|
value = 0
|
||||||
"""
|
if thermal_boundary_1.id != thermal_boundary_2.id:
|
||||||
self._view_factors_matrix = value
|
value = thermal_boundary_2.opaque_area / (total_area - thermal_boundary_1.opaque_area)
|
||||||
|
values.append(value)
|
||||||
|
for thermal_boundary in self.thermal_boundaries:
|
||||||
|
for thermal_opening in thermal_boundary.thermal_openings:
|
||||||
|
value = thermal_opening.area / (total_area - thermal_boundary_1.opaque_area)
|
||||||
|
values.append(value)
|
||||||
|
view_factors_matrix.append(values)
|
||||||
|
|
||||||
|
for thermal_boundary_1 in self.thermal_boundaries:
|
||||||
|
values = []
|
||||||
|
for thermal_opening_1 in thermal_boundary_1.thermal_openings:
|
||||||
|
for thermal_boundary_2 in self.thermal_boundaries:
|
||||||
|
value = thermal_boundary_2.opaque_area / (total_area - thermal_opening_1.area)
|
||||||
|
values.append(value)
|
||||||
|
for thermal_boundary in self.thermal_boundaries:
|
||||||
|
for thermal_opening_2 in thermal_boundary.thermal_openings:
|
||||||
|
value = 0
|
||||||
|
if thermal_opening_1.id != thermal_opening_2.id:
|
||||||
|
value = thermal_opening_2.area / (total_area - thermal_opening_1.area)
|
||||||
|
values.append(value)
|
||||||
|
view_factors_matrix.append(values)
|
||||||
|
self._view_factors_matrix = view_factors_matrix
|
||||||
|
return self._view_factors_matrix
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage_name(self) -> Union[None, str]:
|
def usage_name(self) -> Union[None, str]:
|
||||||
|
@ -280,7 +309,7 @@ class ThermalZone:
|
||||||
@property
|
@property
|
||||||
def mechanical_air_change(self) -> Union[None, float]:
|
def mechanical_air_change(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get thermal zone mechanical air change in air change per hour (ACH)
|
Get thermal zone mechanical air change in air change per second (1/s)
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
if self.usages is None:
|
if self.usages is None:
|
||||||
|
@ -324,19 +353,19 @@ class ThermalZone:
|
||||||
_occupancy_reference = self.usages[0].occupancy
|
_occupancy_reference = self.usages[0].occupancy
|
||||||
if _occupancy_reference.occupancy_schedules is not None:
|
if _occupancy_reference.occupancy_schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_occupancy_reference.occupancy_schedules)):
|
for schedule_index, schedule_value in enumerate(_occupancy_reference.occupancy_schedules):
|
||||||
schedule = Schedule()
|
schedule = Schedule()
|
||||||
schedule.type = _occupancy_reference.occupancy_schedules[i_schedule].type
|
schedule.type = schedule_value.type
|
||||||
schedule.day_types = _occupancy_reference.occupancy_schedules[i_schedule].day_types
|
schedule.day_types = schedule_value.day_types
|
||||||
schedule.data_type = _occupancy_reference.occupancy_schedules[i_schedule].data_type
|
schedule.data_type = schedule_value.data_type
|
||||||
schedule.time_step = _occupancy_reference.occupancy_schedules[i_schedule].time_step
|
schedule.time_step = schedule_value.time_step
|
||||||
schedule.time_range = _occupancy_reference.occupancy_schedules[i_schedule].time_range
|
schedule.time_range = schedule_value.time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_occupancy_reference.occupancy_schedules[i_schedule].values)):
|
for i_value, _ in enumerate(schedule_value.values):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
for usage in self.usages:
|
for usage in self.usages:
|
||||||
_new_value += usage.percentage * usage.occupancy.occupancy_schedules[i_schedule].values[i_value]
|
_new_value += usage.percentage * usage.occupancy.occupancy_schedules[schedule_index].values[i_value]
|
||||||
new_values.append(_new_value)
|
new_values.append(_new_value)
|
||||||
schedule.values = new_values
|
schedule.values = new_values
|
||||||
_schedules.append(schedule)
|
_schedules.append(schedule)
|
||||||
|
@ -385,19 +414,19 @@ class ThermalZone:
|
||||||
_lighting_reference = self.usages[0].lighting
|
_lighting_reference = self.usages[0].lighting
|
||||||
if _lighting_reference.schedules is not None:
|
if _lighting_reference.schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_lighting_reference.schedules)):
|
for schedule_index, schedule_value in enumerate(_lighting_reference.schedules):
|
||||||
schedule = Schedule()
|
schedule = Schedule()
|
||||||
schedule.type = _lighting_reference.schedules[i_schedule].type
|
schedule.type = schedule_value.type
|
||||||
schedule.day_types = _lighting_reference.schedules[i_schedule].day_types
|
schedule.day_types = schedule_value.day_types
|
||||||
schedule.data_type = _lighting_reference.schedules[i_schedule].data_type
|
schedule.data_type = schedule_value.data_type
|
||||||
schedule.time_step = _lighting_reference.schedules[i_schedule].time_step
|
schedule.time_step = schedule_value.time_step
|
||||||
schedule.time_range = _lighting_reference.schedules[i_schedule].time_range
|
schedule.time_range = schedule_value.time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_lighting_reference.schedules[i_schedule].values)):
|
for i_value, _ in enumerate(schedule_value.values):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
for usage in self.usages:
|
for usage in self.usages:
|
||||||
_new_value += usage.percentage * usage.lighting.schedules[i_schedule].values[i_value]
|
_new_value += usage.percentage * usage.lighting.schedules[schedule_index].values[i_value]
|
||||||
new_values.append(_new_value)
|
new_values.append(_new_value)
|
||||||
schedule.values = new_values
|
schedule.values = new_values
|
||||||
_schedules.append(schedule)
|
_schedules.append(schedule)
|
||||||
|
@ -446,19 +475,19 @@ class ThermalZone:
|
||||||
_appliances_reference = self.usages[0].appliances
|
_appliances_reference = self.usages[0].appliances
|
||||||
if _appliances_reference.schedules is not None:
|
if _appliances_reference.schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_appliances_reference.schedules)):
|
for schedule_index, schedule_value in enumerate(_appliances_reference.schedules):
|
||||||
schedule = Schedule()
|
schedule = Schedule()
|
||||||
schedule.type = _appliances_reference.schedules[i_schedule].type
|
schedule.type = schedule_value.type
|
||||||
schedule.day_types = _appliances_reference.schedules[i_schedule].day_types
|
schedule.day_types = schedule_value.day_types
|
||||||
schedule.data_type = _appliances_reference.schedules[i_schedule].data_type
|
schedule.data_type = schedule_value.data_type
|
||||||
schedule.time_step = _appliances_reference.schedules[i_schedule].time_step
|
schedule.time_step = schedule_value.time_step
|
||||||
schedule.time_range = _appliances_reference.schedules[i_schedule].time_range
|
schedule.time_range = schedule_value.time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_appliances_reference.schedules[i_schedule].values)):
|
for i_value, _ in enumerate(schedule_value.values):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
for usage in self.usages:
|
for usage in self.usages:
|
||||||
_new_value += usage.percentage * usage.appliances.schedules[i_schedule].values[i_value]
|
_new_value += usage.percentage * usage.appliances.schedules[schedule_index].values[i_value]
|
||||||
new_values.append(_new_value)
|
new_values.append(_new_value)
|
||||||
schedule.values = new_values
|
schedule.values = new_values
|
||||||
_schedules.append(schedule)
|
_schedules.append(schedule)
|
||||||
|
@ -510,15 +539,15 @@ class ThermalZone:
|
||||||
_schedules_defined = False
|
_schedules_defined = False
|
||||||
break
|
break
|
||||||
for day, _schedule in enumerate(internal_gain.schedules):
|
for day, _schedule in enumerate(internal_gain.schedules):
|
||||||
for v, value in enumerate(_schedule.values):
|
for v_index, value in enumerate(_schedule.values):
|
||||||
values[v, day] += value * usage.percentage
|
values[v_index, day] += value * usage.percentage
|
||||||
|
|
||||||
if _schedules_defined:
|
if _schedules_defined:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for day in range(0, len(_days)):
|
for day_index, day in enumerate(_days):
|
||||||
_schedule = copy.deepcopy(_base_schedule)
|
_schedule = copy.deepcopy(_base_schedule)
|
||||||
_schedule.day_types = [_days[day]]
|
_schedule.day_types = [day]
|
||||||
_schedule.values = values[:day]
|
_schedule.values = values[:day_index]
|
||||||
_schedules.append(_schedule)
|
_schedules.append(_schedule)
|
||||||
|
|
||||||
_internal_gain.average_internal_gain = _average_internal_gain
|
_internal_gain.average_internal_gain = _average_internal_gain
|
||||||
|
@ -543,62 +572,62 @@ class ThermalZone:
|
||||||
if self.usages is None:
|
if self.usages is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if self._thermal_control is None:
|
if self._thermal_control is not None:
|
||||||
self._thermal_control = ThermalControl()
|
return self._thermal_control
|
||||||
_mean_heating_set_point = 0
|
self._thermal_control = ThermalControl()
|
||||||
_heating_set_back = 0
|
_mean_heating_set_point = 0
|
||||||
_mean_cooling_set_point = 0
|
_heating_set_back = 0
|
||||||
for usage in self.usages:
|
_mean_cooling_set_point = 0
|
||||||
_mean_heating_set_point += usage.percentage * usage.thermal_control.mean_heating_set_point
|
for usage in self.usages:
|
||||||
_heating_set_back += usage.percentage * usage.thermal_control.heating_set_back
|
_mean_heating_set_point += usage.percentage * usage.thermal_control.mean_heating_set_point
|
||||||
_mean_cooling_set_point += usage.percentage * usage.thermal_control.mean_cooling_set_point
|
_heating_set_back += usage.percentage * usage.thermal_control.heating_set_back
|
||||||
self._thermal_control.mean_heating_set_point = _mean_heating_set_point
|
_mean_cooling_set_point += usage.percentage * usage.thermal_control.mean_cooling_set_point
|
||||||
self._thermal_control.heating_set_back = _heating_set_back
|
self._thermal_control.mean_heating_set_point = _mean_heating_set_point
|
||||||
self._thermal_control.mean_cooling_set_point = _mean_cooling_set_point
|
self._thermal_control.heating_set_back = _heating_set_back
|
||||||
|
self._thermal_control.mean_cooling_set_point = _mean_cooling_set_point
|
||||||
|
|
||||||
_thermal_control_reference = self.usages[0].thermal_control
|
_thermal_control_reference = self.usages[0].thermal_control
|
||||||
_types_reference = []
|
_types_reference = []
|
||||||
if _thermal_control_reference.hvac_availability_schedules is not None:
|
if _thermal_control_reference.hvac_availability_schedules is not None:
|
||||||
_types_reference.append([cte.HVAC_AVAILABILITY, _thermal_control_reference.hvac_availability_schedules])
|
_types_reference.append([cte.HVAC_AVAILABILITY, _thermal_control_reference.hvac_availability_schedules])
|
||||||
if _thermal_control_reference.heating_set_point_schedules is not None:
|
if _thermal_control_reference.heating_set_point_schedules is not None:
|
||||||
_types_reference.append([cte.HEATING_SET_POINT, _thermal_control_reference.heating_set_point_schedules])
|
_types_reference.append([cte.HEATING_SET_POINT, _thermal_control_reference.heating_set_point_schedules])
|
||||||
if _thermal_control_reference.cooling_set_point_schedules is not None:
|
if _thermal_control_reference.cooling_set_point_schedules is not None:
|
||||||
_types_reference.append([cte.COOLING_SET_POINT, _thermal_control_reference.cooling_set_point_schedules])
|
_types_reference.append([cte.COOLING_SET_POINT, _thermal_control_reference.cooling_set_point_schedules])
|
||||||
|
|
||||||
for i_type in range(0, len(_types_reference)):
|
for i_type, _ in enumerate(_types_reference):
|
||||||
_schedules = []
|
_schedules = []
|
||||||
_schedule_type = _types_reference[i_type][1]
|
_schedule_type = _types_reference[i_type][1]
|
||||||
for i_schedule in range(0, len(_schedule_type)):
|
for i_schedule, schedule_value in enumerate(_schedule_type):
|
||||||
schedule = Schedule()
|
schedule = Schedule()
|
||||||
schedule.type = _schedule_type[i_schedule].type
|
schedule.type = schedule_value.type
|
||||||
schedule.day_types = _schedule_type[i_schedule].day_types
|
schedule.day_types = schedule_value.day_types
|
||||||
schedule.data_type = _schedule_type[i_schedule].data_type
|
schedule.data_type = schedule_value.data_type
|
||||||
schedule.time_step = _schedule_type[i_schedule].time_step
|
schedule.time_step = schedule_value.time_step
|
||||||
schedule.time_range = _schedule_type[i_schedule].time_range
|
schedule.time_range = schedule_value.time_range
|
||||||
|
|
||||||
new_values = []
|
|
||||||
for i_value in range(0, len(_schedule_type[i_schedule].values)):
|
|
||||||
_new_value = 0
|
|
||||||
for usage in self.usages:
|
|
||||||
if _types_reference[i_type][0] == cte.HVAC_AVAILABILITY:
|
|
||||||
_new_value += usage.percentage * \
|
|
||||||
usage.thermal_control.hvac_availability_schedules[i_schedule].values[i_value]
|
|
||||||
elif _types_reference[i_type][0] == cte.HEATING_SET_POINT:
|
|
||||||
_new_value += usage.percentage * \
|
|
||||||
usage.thermal_control.heating_set_point_schedules[i_schedule].values[i_value]
|
|
||||||
elif _types_reference[i_type][0] == cte.COOLING_SET_POINT:
|
|
||||||
_new_value += usage.percentage * \
|
|
||||||
usage.thermal_control.cooling_set_point_schedules[i_schedule].values[i_value]
|
|
||||||
new_values.append(_new_value)
|
|
||||||
schedule.values = new_values
|
|
||||||
_schedules.append(schedule)
|
|
||||||
if i_type == 0:
|
|
||||||
self._thermal_control.hvac_availability_schedules = _schedules
|
|
||||||
elif i_type == 1:
|
|
||||||
self._thermal_control.heating_set_point_schedules = _schedules
|
|
||||||
elif i_type == 2:
|
|
||||||
self._thermal_control.cooling_set_point_schedules = _schedules
|
|
||||||
|
|
||||||
|
new_values = []
|
||||||
|
for i_value, _ in enumerate(schedule_value.values):
|
||||||
|
_new_value = 0
|
||||||
|
for usage in self.usages:
|
||||||
|
if _types_reference[i_type][0] == cte.HVAC_AVAILABILITY:
|
||||||
|
_new_value += usage.percentage * \
|
||||||
|
usage.thermal_control.hvac_availability_schedules[i_schedule].values[i_value]
|
||||||
|
elif _types_reference[i_type][0] == cte.HEATING_SET_POINT:
|
||||||
|
_new_value += usage.percentage * \
|
||||||
|
usage.thermal_control.heating_set_point_schedules[i_schedule].values[i_value]
|
||||||
|
elif _types_reference[i_type][0] == cte.COOLING_SET_POINT:
|
||||||
|
_new_value += usage.percentage * \
|
||||||
|
usage.thermal_control.cooling_set_point_schedules[i_schedule].values[i_value]
|
||||||
|
new_values.append(_new_value)
|
||||||
|
schedule.values = new_values
|
||||||
|
_schedules.append(schedule)
|
||||||
|
if i_type == 0:
|
||||||
|
self._thermal_control.hvac_availability_schedules = _schedules
|
||||||
|
elif i_type == 1:
|
||||||
|
self._thermal_control.heating_set_point_schedules = _schedules
|
||||||
|
elif i_type == 2:
|
||||||
|
self._thermal_control.cooling_set_point_schedules = _schedules
|
||||||
return self._thermal_control
|
return self._thermal_control
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -612,9 +641,12 @@ class ThermalZone:
|
||||||
_mean_peak_flow = 0
|
_mean_peak_flow = 0
|
||||||
_mean_service_temperature = 0
|
_mean_service_temperature = 0
|
||||||
for usage in self.usages:
|
for usage in self.usages:
|
||||||
_mean_peak_density_load += usage.percentage * usage.domestic_hot_water.density
|
if usage.domestic_hot_water.density is not None:
|
||||||
_mean_peak_flow += usage.percentage * usage.domestic_hot_water.peak_flow
|
_mean_peak_density_load += usage.percentage * usage.domestic_hot_water.density
|
||||||
_mean_service_temperature += usage.percentage * usage.domestic_hot_water.service_temperature
|
if usage.domestic_hot_water.peak_flow is not None:
|
||||||
|
_mean_peak_flow += usage.percentage * usage.domestic_hot_water.peak_flow
|
||||||
|
if usage.domestic_hot_water.service_temperature is not None:
|
||||||
|
_mean_service_temperature += usage.percentage * usage.domestic_hot_water.service_temperature
|
||||||
self._domestic_hot_water.density = _mean_peak_density_load
|
self._domestic_hot_water.density = _mean_peak_density_load
|
||||||
self._domestic_hot_water.peak_flow = _mean_peak_flow
|
self._domestic_hot_water.peak_flow = _mean_peak_flow
|
||||||
self._domestic_hot_water.service_temperature = _mean_service_temperature
|
self._domestic_hot_water.service_temperature = _mean_service_temperature
|
||||||
|
@ -622,19 +654,19 @@ class ThermalZone:
|
||||||
_domestic_hot_water_reference = self.usages[0].domestic_hot_water
|
_domestic_hot_water_reference = self.usages[0].domestic_hot_water
|
||||||
if _domestic_hot_water_reference.schedules is not None:
|
if _domestic_hot_water_reference.schedules is not None:
|
||||||
_schedules = []
|
_schedules = []
|
||||||
for i_schedule in range(0, len(_domestic_hot_water_reference.schedules)):
|
for schedule_index, schedule_value in enumerate(_domestic_hot_water_reference.schedules):
|
||||||
schedule = Schedule()
|
schedule = Schedule()
|
||||||
schedule.type = _domestic_hot_water_reference.schedules[i_schedule].type
|
schedule.type = schedule_value.type
|
||||||
schedule.day_types = _domestic_hot_water_reference.schedules[i_schedule].day_types
|
schedule.day_types = schedule_value.day_types
|
||||||
schedule.data_type = _domestic_hot_water_reference.schedules[i_schedule].data_type
|
schedule.data_type = schedule_value.data_type
|
||||||
schedule.time_step = _domestic_hot_water_reference.schedules[i_schedule].time_step
|
schedule.time_step = schedule_value.time_step
|
||||||
schedule.time_range = _domestic_hot_water_reference.schedules[i_schedule].time_range
|
schedule.time_range = schedule_value.time_range
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
for i_value in range(0, len(_domestic_hot_water_reference.schedules[i_schedule].values)):
|
for i_value, _ in enumerate(schedule_value.values):
|
||||||
_new_value = 0
|
_new_value = 0
|
||||||
for usage in self.usages:
|
for usage in self.usages:
|
||||||
_new_value += usage.percentage * usage.domestic_hot_water.schedules[i_schedule].values[i_value]
|
_new_value += usage.percentage * usage.domestic_hot_water.schedules[schedule_index].values[i_value]
|
||||||
new_values.append(_new_value)
|
new_values.append(_new_value)
|
||||||
schedule.values = new_values
|
schedule.values = new_values
|
||||||
_schedules.append(schedule)
|
_schedules.append(schedule)
|
||||||
|
@ -645,15 +677,8 @@ class ThermalZone:
|
||||||
@property
|
@property
|
||||||
def total_floor_area(self):
|
def total_floor_area(self):
|
||||||
"""
|
"""
|
||||||
Get the total floor area of this thermal zone
|
Get the total floor area of this thermal zone in m2
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
|
self._total_floor_area = self.footprint_area * self._number_of_storeys
|
||||||
return self._total_floor_area
|
return self._total_floor_area
|
||||||
|
|
||||||
@total_floor_area.setter
|
|
||||||
def total_floor_area(self, value):
|
|
||||||
"""
|
|
||||||
Set the total floor area of this thermal zone
|
|
||||||
:param value: float
|
|
||||||
"""
|
|
||||||
self._total_floor_area = value
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ class Usage:
|
||||||
@property
|
@property
|
||||||
def mechanical_air_change(self) -> Union[None, float]:
|
def mechanical_air_change(self) -> Union[None, float]:
|
||||||
"""
|
"""
|
||||||
Get usage zone mechanical air change in air change per hour (ACH)
|
Get usage zone mechanical air change in air change per second (1/s)
|
||||||
:return: None or float
|
:return: None or float
|
||||||
"""
|
"""
|
||||||
return self._mechanical_air_change
|
return self._mechanical_air_change
|
||||||
|
@ -181,7 +181,7 @@ class Usage:
|
||||||
@mechanical_air_change.setter
|
@mechanical_air_change.setter
|
||||||
def mechanical_air_change(self, value):
|
def mechanical_air_change(self, value):
|
||||||
"""
|
"""
|
||||||
Set usage zone mechanical air change in air change per hour (ACH)
|
Set usage zone mechanical air change in air change per second (1/s)
|
||||||
:param value: float
|
:param value: float
|
||||||
"""
|
"""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
"""
|
|
||||||
Bus system module
|
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
||||||
Copyright © 2022 Concordia CERC group
|
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import List
|
|
||||||
from hub.city_model_structure.city_object import CityObject
|
|
||||||
from hub.city_model_structure.attributes.polygon import Polygon
|
|
||||||
from hub.city_model_structure.transport.bus_network import BusNetwork
|
|
||||||
from hub.city_model_structure.transport.bus_node import BusNode
|
|
||||||
from hub.city_model_structure.transport.bus import Bus
|
|
||||||
|
|
||||||
|
|
||||||
class BusSystem(CityObject):
|
|
||||||
"""
|
|
||||||
BusSystem(CityObject) class
|
|
||||||
"""
|
|
||||||
def __init__(self, name, surfaces):
|
|
||||||
super().__init__(name, surfaces)
|
|
||||||
self._bus_routes = None
|
|
||||||
self._bus_network = None
|
|
||||||
self._buses = None
|
|
||||||
self._restricted_polygons = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bus_routes(self) -> List[BusNode]:
|
|
||||||
"""
|
|
||||||
Add explanation here
|
|
||||||
:return: [BusNode]
|
|
||||||
"""
|
|
||||||
return self._bus_routes
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bus_network(self) -> BusNetwork:
|
|
||||||
"""
|
|
||||||
Add explanation here
|
|
||||||
:return: BusNetwork
|
|
||||||
"""
|
|
||||||
return self._bus_network
|
|
||||||
|
|
||||||
@property
|
|
||||||
def buses(self) -> List[Bus]:
|
|
||||||
"""
|
|
||||||
Add explanation here
|
|
||||||
:return: [Bus]
|
|
||||||
"""
|
|
||||||
return self._buses
|
|
||||||
|
|
||||||
@property
|
|
||||||
def restricted_polygons(self) -> List[Polygon]:
|
|
||||||
"""
|
|
||||||
Add explanation here
|
|
||||||
:return: [Polygon]
|
|
||||||
"""
|
|
||||||
return self._restricted_polygons
|
|
|
@ -8,29 +8,30 @@ Code contributors: Peter Yefi peteryefi@gmail.com
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import bz2
|
import bz2
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
import pickle
|
|
||||||
import math
|
|
||||||
import copy
|
import copy
|
||||||
import pyproj
|
import logging
|
||||||
from typing import List, Union
|
import math
|
||||||
from pyproj import Transformer
|
import pickle
|
||||||
|
import sys
|
||||||
|
import pathlib
|
||||||
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import List, Union
|
||||||
|
|
||||||
|
import pyproj
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
from pyproj import Transformer
|
||||||
|
|
||||||
from hub.city_model_structure.building import Building
|
from hub.city_model_structure.building import Building
|
||||||
|
from hub.city_model_structure.buildings_cluster import BuildingsCluster
|
||||||
from hub.city_model_structure.city_object import CityObject
|
from hub.city_model_structure.city_object import CityObject
|
||||||
from hub.city_model_structure.city_objects_cluster import CityObjectsCluster
|
from hub.city_model_structure.city_objects_cluster import CityObjectsCluster
|
||||||
from hub.city_model_structure.buildings_cluster import BuildingsCluster
|
|
||||||
|
|
||||||
from hub.city_model_structure.iot.station import Station
|
from hub.city_model_structure.iot.station import Station
|
||||||
from hub.city_model_structure.level_of_detail import LevelOfDetail
|
from hub.city_model_structure.level_of_detail import LevelOfDetail
|
||||||
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
from hub.city_model_structure.parts_consisting_building import PartsConsistingBuilding
|
||||||
from hub.helpers.geometry_helper import GeometryHelper
|
from hub.helpers.geometry_helper import GeometryHelper
|
||||||
from hub.helpers.location import Location
|
from hub.helpers.location import Location
|
||||||
import hub.helpers.constants as cte
|
import hub.helpers.constants as cte
|
||||||
from hub.city_model_structure.energy_system import EnergySystem
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
|
|
||||||
class City:
|
class City:
|
||||||
|
@ -57,24 +58,21 @@ class City:
|
||||||
self._city_objects = None
|
self._city_objects = None
|
||||||
self._energy_systems = None
|
self._energy_systems = None
|
||||||
self._fuels = None
|
self._fuels = None
|
||||||
self._machines = None
|
|
||||||
self._stations = []
|
self._stations = []
|
||||||
self._lca_materials = None
|
|
||||||
self._level_of_detail = LevelOfDetail()
|
self._level_of_detail = LevelOfDetail()
|
||||||
self._city_objects_dictionary = {}
|
self._city_objects_dictionary = {}
|
||||||
self._city_objects_alias_dictionary = {}
|
self._city_objects_alias_dictionary = {}
|
||||||
self._energy_systems_connection_table = None
|
|
||||||
self._generic_energy_systems = None
|
self._generic_energy_systems = None
|
||||||
|
|
||||||
def _get_location(self) -> Location:
|
def _get_location(self) -> Location:
|
||||||
if self._location is None:
|
if self._location is None:
|
||||||
gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
|
gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
|
||||||
try:
|
try:
|
||||||
if self._srs_name in GeometryHelper.srs_transformations.keys():
|
if self._srs_name in GeometryHelper.srs_transformations:
|
||||||
self._srs_name = GeometryHelper.srs_transformations[self._srs_name]
|
self._srs_name = GeometryHelper.srs_transformations[self._srs_name]
|
||||||
input_reference = pyproj.CRS(self.srs_name) # Projected coordinate system from input data
|
input_reference = pyproj.CRS(self.srs_name) # Projected coordinate system from input data
|
||||||
except pyproj.exceptions.CRSError as err:
|
except pyproj.exceptions.CRSError as err:
|
||||||
logging.error('Invalid projection reference system, please check the input data. (e.g. in CityGML files: srs_name)')
|
logging.error('Invalid projection reference system, please check the input data.')
|
||||||
raise pyproj.exceptions.CRSError from err
|
raise pyproj.exceptions.CRSError from err
|
||||||
transformer = Transformer.from_crs(input_reference, gps)
|
transformer = Transformer.from_crs(input_reference, gps)
|
||||||
coordinates = transformer.transform(self.lower_corner[0], self.lower_corner[1])
|
coordinates = transformer.transform(self.lower_corner[0], self.lower_corner[1])
|
||||||
|
@ -84,14 +82,26 @@ class City:
|
||||||
@property
|
@property
|
||||||
def country_code(self):
|
def country_code(self):
|
||||||
"""
|
"""
|
||||||
Get models country code
|
Get city country code
|
||||||
:return: str
|
:return: str
|
||||||
"""
|
"""
|
||||||
return self._get_location().country
|
return self._get_location().country
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def location(self):
|
def region_code(self):
|
||||||
return self._get_location().city
|
"""
|
||||||
|
Get city region name
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
return self._get_location().region_code
|
||||||
|
|
||||||
|
@property
|
||||||
|
def location(self) -> Location:
|
||||||
|
"""
|
||||||
|
Get city location
|
||||||
|
:return: Location
|
||||||
|
"""
|
||||||
|
return self._get_location()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -103,6 +113,15 @@ class City:
|
||||||
return self._get_location().city
|
return self._get_location().city
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value):
|
||||||
|
"""
|
||||||
|
Set city name
|
||||||
|
:param value:str
|
||||||
|
"""
|
||||||
|
if value is not None:
|
||||||
|
self._name = str(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def climate_reference_city(self) -> Union[None, str]:
|
def climate_reference_city(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
|
@ -152,9 +171,6 @@ class City:
|
||||||
if self.buildings is not None:
|
if self.buildings is not None:
|
||||||
for building in self.buildings:
|
for building in self.buildings:
|
||||||
self._city_objects.append(building)
|
self._city_objects.append(building)
|
||||||
if self.energy_systems is not None:
|
|
||||||
for energy_system in self.energy_systems:
|
|
||||||
self._city_objects.append(energy_system)
|
|
||||||
return self._city_objects
|
return self._city_objects
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -203,8 +219,11 @@ class City:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def add_building_alias(self, building, alias):
|
def add_building_alias(self, building, alias):
|
||||||
|
"""
|
||||||
|
Add an alias to the building
|
||||||
|
"""
|
||||||
building_index = self._city_objects_dictionary[building.name]
|
building_index = self._city_objects_dictionary[building.name]
|
||||||
if alias in self._city_objects_alias_dictionary.keys():
|
if alias in self._city_objects_alias_dictionary:
|
||||||
self._city_objects_alias_dictionary[alias].append(building_index)
|
self._city_objects_alias_dictionary[alias].append(building_index)
|
||||||
else:
|
else:
|
||||||
self._city_objects_alias_dictionary[alias] = [building_index]
|
self._city_objects_alias_dictionary[alias] = [building_index]
|
||||||
|
@ -218,7 +237,6 @@ class City:
|
||||||
if new_city_object.type == 'building':
|
if new_city_object.type == 'building':
|
||||||
if self._buildings is None:
|
if self._buildings is None:
|
||||||
self._buildings = []
|
self._buildings = []
|
||||||
new_city_object._alias_dictionary = self._city_objects_alias_dictionary
|
|
||||||
self._buildings.append(new_city_object)
|
self._buildings.append(new_city_object)
|
||||||
self._city_objects_dictionary[new_city_object.name] = len(self._buildings) - 1
|
self._city_objects_dictionary[new_city_object.name] = len(self._buildings) - 1
|
||||||
if new_city_object.aliases is not None:
|
if new_city_object.aliases is not None:
|
||||||
|
@ -242,17 +260,17 @@ class City:
|
||||||
"""
|
"""
|
||||||
if city_object.type != 'building':
|
if city_object.type != 'building':
|
||||||
raise NotImplementedError(city_object.type)
|
raise NotImplementedError(city_object.type)
|
||||||
if self._buildings is None or self._buildings == []:
|
if not self._buildings:
|
||||||
sys.stderr.write('Warning: impossible to remove city_object, the city is empty\n')
|
logging.warning('impossible to remove city_object, the city is empty\n')
|
||||||
else:
|
else:
|
||||||
if city_object in self._buildings:
|
if city_object in self._buildings:
|
||||||
self._buildings.remove(city_object)
|
self._buildings.remove(city_object)
|
||||||
# regenerate hash map
|
# regenerate hash map
|
||||||
self._city_objects_dictionary.clear()
|
self._city_objects_dictionary = {}
|
||||||
self._city_objects_alias_dictionary.clear()
|
self._city_objects_alias_dictionary = {}
|
||||||
for i, city_object in enumerate(self._buildings):
|
for i, _building in enumerate(self._buildings):
|
||||||
self._city_objects_dictionary[city_object.name] = i
|
self._city_objects_dictionary[_building.name] = i
|
||||||
for alias in city_object.aliases:
|
for alias in _building.aliases:
|
||||||
if alias in self._city_objects_alias_dictionary:
|
if alias in self._city_objects_alias_dictionary:
|
||||||
self._city_objects_alias_dictionary[alias].append(i)
|
self._city_objects_alias_dictionary[alias].append(i)
|
||||||
else:
|
else:
|
||||||
|
@ -266,15 +284,6 @@ class City:
|
||||||
"""
|
"""
|
||||||
return self._srs_name
|
return self._srs_name
|
||||||
|
|
||||||
@name.setter
|
|
||||||
def name(self, value):
|
|
||||||
"""
|
|
||||||
Set city name
|
|
||||||
:param value:str
|
|
||||||
"""
|
|
||||||
if value is not None:
|
|
||||||
self._name = str(value)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(city_filename) -> City:
|
def load(city_filename) -> City:
|
||||||
"""
|
"""
|
||||||
|
@ -282,9 +291,28 @@ class City:
|
||||||
:param city_filename: city filename
|
:param city_filename: city filename
|
||||||
:return: City
|
:return: City
|
||||||
"""
|
"""
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
pathlib.PosixPath = pathlib.WindowsPath
|
||||||
|
elif sys.platform == 'linux':
|
||||||
|
pathlib.WindowsPath = pathlib.PosixPath
|
||||||
|
|
||||||
with open(city_filename, 'rb') as file:
|
with open(city_filename, 'rb') as file:
|
||||||
return pickle.load(file)
|
return pickle.load(file)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load_compressed(compressed_city_filename, destination_filename) -> City:
|
||||||
|
"""
|
||||||
|
Load a city from compressed_city_filename
|
||||||
|
:param compressed_city_filename: Compressed pickle as source
|
||||||
|
:param destination_filename: Pickle file as destination
|
||||||
|
:return: City
|
||||||
|
"""
|
||||||
|
with open(str(compressed_city_filename), 'rb') as source, open(str(destination_filename), 'wb') as destination:
|
||||||
|
destination.write(bz2.decompress(source.read()))
|
||||||
|
loaded_city = City.load(destination_filename)
|
||||||
|
os.unlink(destination_filename)
|
||||||
|
return loaded_city
|
||||||
|
|
||||||
def save(self, city_filename):
|
def save(self, city_filename):
|
||||||
"""
|
"""
|
||||||
Save a city into the given filename
|
Save a city into the given filename
|
||||||
|
@ -300,8 +328,8 @@ class City:
|
||||||
:param city_filename: destination city filename
|
:param city_filename: destination city filename
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
with bz2.BZ2File(city_filename, 'wb') as f:
|
with bz2.BZ2File(city_filename, 'wb') as file:
|
||||||
pickle.dump(self, f)
|
pickle.dump(self, file)
|
||||||
|
|
||||||
def region(self, center, radius) -> City:
|
def region(self, center, radius) -> City:
|
||||||
"""
|
"""
|
||||||
|
@ -391,14 +419,6 @@ class City:
|
||||||
"""
|
"""
|
||||||
return self._parts_consisting_buildings
|
return self._parts_consisting_buildings
|
||||||
|
|
||||||
@property
|
|
||||||
def energy_systems(self) -> Union[List[EnergySystem], None]:
|
|
||||||
"""
|
|
||||||
Get energy systems belonging to the city
|
|
||||||
:return: None or [EnergySystem]
|
|
||||||
"""
|
|
||||||
return self._energy_systems
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stations(self) -> [Station]:
|
def stations(self) -> [Station]:
|
||||||
"""
|
"""
|
||||||
|
@ -446,7 +466,35 @@ class City:
|
||||||
return copy.deepcopy(self)
|
return copy.deepcopy(self)
|
||||||
|
|
||||||
def merge(self, city) -> City:
|
def merge(self, city) -> City:
|
||||||
raise NotImplementedError('This method needs to be reimplemented')
|
"""
|
||||||
|
Return a merged city combining the current city and the given one
|
||||||
|
:return: City
|
||||||
|
"""
|
||||||
|
merged_city = self.copy
|
||||||
|
for building in city.buildings:
|
||||||
|
if merged_city.city_object(building.name) is None:
|
||||||
|
# building is new so added to the city
|
||||||
|
merged_city.add_city_object(copy.deepcopy(building))
|
||||||
|
else:
|
||||||
|
# keep the one with less radiation
|
||||||
|
parameter_city_building_total_radiation = 0
|
||||||
|
for surface in building.surfaces:
|
||||||
|
if surface.global_irradiance:
|
||||||
|
parameter_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
|
|
||||||
|
merged_city_building_total_radiation = 0
|
||||||
|
for surface in merged_city.city_object(building.name).surfaces:
|
||||||
|
if surface.global_irradiance:
|
||||||
|
merged_city_building_total_radiation += surface.global_irradiance[cte.YEAR][0]
|
||||||
|
|
||||||
|
if merged_city_building_total_radiation == 0:
|
||||||
|
merged_city.remove_city_object(merged_city.city_object(building.name))
|
||||||
|
merged_city.add_city_object(building)
|
||||||
|
elif merged_city_building_total_radiation > parameter_city_building_total_radiation > 0:
|
||||||
|
merged_city.remove_city_object(merged_city.city_object(building.name))
|
||||||
|
merged_city.add_city_object(building)
|
||||||
|
|
||||||
|
return merged_city
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def level_of_detail(self) -> LevelOfDetail:
|
def level_of_detail(self) -> LevelOfDetail:
|
||||||
|
@ -456,24 +504,6 @@ class City:
|
||||||
"""
|
"""
|
||||||
return self._level_of_detail
|
return self._level_of_detail
|
||||||
|
|
||||||
@property
|
|
||||||
def energy_systems_connection_table(self) -> Union[None, DataFrame]:
|
|
||||||
"""
|
|
||||||
Get energy systems connection table which includes at least two columns: energy_system_type and associated_building
|
|
||||||
and may also include dimensioned_energy_system and connection_building_to_dimensioned_energy_system
|
|
||||||
:return: DataFrame
|
|
||||||
"""
|
|
||||||
return self._energy_systems_connection_table
|
|
||||||
|
|
||||||
@energy_systems_connection_table.setter
|
|
||||||
def energy_systems_connection_table(self, value):
|
|
||||||
"""
|
|
||||||
Set energy systems connection table which includes at least two columns: energy_system_type and associated_building
|
|
||||||
and may also include dimensioned_energy_system and connection_building_to_dimensioned_energy_system
|
|
||||||
:param value: DataFrame
|
|
||||||
"""
|
|
||||||
self._energy_systems_connection_table = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def generic_energy_systems(self) -> dict:
|
def generic_energy_systems(self) -> dict:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -37,13 +37,14 @@ class CityObject:
|
||||||
self._max_z = ConfigurationHelper().min_coordinate
|
self._max_z = ConfigurationHelper().min_coordinate
|
||||||
self._centroid = None
|
self._centroid = None
|
||||||
self._volume = None
|
self._volume = None
|
||||||
self._external_temperature = dict()
|
self._external_temperature = {}
|
||||||
self._ground_temperature = dict()
|
self._ground_temperature = {}
|
||||||
self._global_horizontal = dict()
|
self._global_horizontal = {}
|
||||||
self._diffuse = dict()
|
self._diffuse = {}
|
||||||
self._beam = dict()
|
self._direct_normal = {}
|
||||||
self._sensors = []
|
self._sensors = []
|
||||||
self._neighbours = None
|
self._neighbours = None
|
||||||
|
self._beam = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def level_of_detail(self) -> LevelOfDetail:
|
def level_of_detail(self) -> LevelOfDetail:
|
||||||
|
@ -81,6 +82,10 @@ class CityObject:
|
||||||
|
|
||||||
@volume.setter
|
@volume.setter
|
||||||
def volume(self, value):
|
def volume(self, value):
|
||||||
|
"""
|
||||||
|
Set city object volume in cubic meters
|
||||||
|
:param value: float
|
||||||
|
"""
|
||||||
self._volume = value
|
self._volume = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -172,7 +177,7 @@ class CityObject:
|
||||||
def external_temperature(self) -> {float}:
|
def external_temperature(self) -> {float}:
|
||||||
"""
|
"""
|
||||||
Get external temperature surrounding the city object in Celsius
|
Get external temperature surrounding the city object in Celsius
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
return self._external_temperature
|
return self._external_temperature
|
||||||
|
|
||||||
|
@ -180,11 +185,10 @@ class CityObject:
|
||||||
def external_temperature(self, value):
|
def external_temperature(self, value):
|
||||||
"""
|
"""
|
||||||
Set external temperature surrounding the city object in Celsius
|
Set external temperature surrounding the city object in Celsius
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
self._external_temperature = value
|
self._external_temperature = value
|
||||||
|
|
||||||
# todo: this is the new format we will use to get rid of the data frames
|
|
||||||
@property
|
@property
|
||||||
def ground_temperature(self) -> dict:
|
def ground_temperature(self) -> dict:
|
||||||
"""
|
"""
|
||||||
|
@ -205,50 +209,50 @@ class CityObject:
|
||||||
@property
|
@property
|
||||||
def global_horizontal(self) -> dict:
|
def global_horizontal(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get global horizontal radiation surrounding the city object in W/m2
|
Get global horizontal radiation surrounding the city object in J/m2
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
return self._global_horizontal
|
return self._global_horizontal
|
||||||
|
|
||||||
@global_horizontal.setter
|
@global_horizontal.setter
|
||||||
def global_horizontal(self, value):
|
def global_horizontal(self, value):
|
||||||
"""
|
"""
|
||||||
Set global horizontal radiation surrounding the city object in W/m2
|
Set global horizontal radiation surrounding the city object in J/m2
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
self._global_horizontal = value
|
self._global_horizontal = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def diffuse(self) -> dict:
|
def diffuse(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get diffuse radiation surrounding the city object in W/m2
|
Get diffuse radiation surrounding the city object in J/m2
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
return self._diffuse
|
return self._diffuse
|
||||||
|
|
||||||
@diffuse.setter
|
@diffuse.setter
|
||||||
def diffuse(self, value):
|
def diffuse(self, value):
|
||||||
"""
|
"""
|
||||||
Set diffuse radiation surrounding the city object in W/m2
|
Set diffuse radiation surrounding the city object in J/m2
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
self._diffuse = value
|
self._diffuse = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def beam(self) -> dict:
|
def direct_normal(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get beam radiation surrounding the city object in W/m2
|
Get beam radiation surrounding the city object in J/m2
|
||||||
:return: dict{DataFrame(float)}
|
:return: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
return self._beam
|
return self._direct_normal
|
||||||
|
|
||||||
@beam.setter
|
@direct_normal.setter
|
||||||
def beam(self, value):
|
def direct_normal(self, value):
|
||||||
"""
|
"""
|
||||||
Set beam radiation surrounding the city object in W/m2
|
Set beam radiation surrounding the city object in J/m2
|
||||||
:param value: dict{DataFrame(float)}
|
:param value: dict{dict{[float]}}
|
||||||
"""
|
"""
|
||||||
self._beam = value
|
self._direct_normal = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lower_corner(self):
|
def lower_corner(self):
|
||||||
|
@ -299,3 +303,19 @@ class CityObject:
|
||||||
Set the list of neighbour_objects and their properties associated to the current city_object
|
Set the list of neighbour_objects and their properties associated to the current city_object
|
||||||
"""
|
"""
|
||||||
self._neighbours = value
|
self._neighbours = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def beam(self) -> dict:
|
||||||
|
"""
|
||||||
|
Get beam radiation surrounding the city object in J/m2
|
||||||
|
:return: dict{dict{[float]}}
|
||||||
|
"""
|
||||||
|
return self._beam
|
||||||
|
|
||||||
|
@beam.setter
|
||||||
|
def beam(self, value):
|
||||||
|
"""
|
||||||
|
Set beam radiation surrounding the city object in J/m2
|
||||||
|
:param value: dict{dict{[float]}}
|
||||||
|
"""
|
||||||
|
self._beam = value
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user