RunFeemsSim 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RunFeemsSim-0.2.2/CONTRIBUTING.md +33 -0
- RunFeemsSim-0.2.2/LICENSE +21 -0
- RunFeemsSim-0.2.2/MANIFEST.in +5 -0
- RunFeemsSim-0.2.2/PKG-INFO +73 -0
- RunFeemsSim-0.2.2/README.md +49 -0
- RunFeemsSim-0.2.2/RunFeemsSim/__init__.py +1 -0
- RunFeemsSim-0.2.2/RunFeemsSim/_modidx.py +117 -0
- RunFeemsSim-0.2.2/RunFeemsSim/_nbdev.py +26 -0
- RunFeemsSim-0.2.2/RunFeemsSim/machinery_calculation.py +341 -0
- RunFeemsSim-0.2.2/RunFeemsSim/pms_basic.py +205 -0
- RunFeemsSim-0.2.2/RunFeemsSim.egg-info/PKG-INFO +73 -0
- RunFeemsSim-0.2.2/RunFeemsSim.egg-info/SOURCES.txt +17 -0
- RunFeemsSim-0.2.2/RunFeemsSim.egg-info/dependency_links.txt +1 -0
- RunFeemsSim-0.2.2/RunFeemsSim.egg-info/not-zip-safe +1 -0
- RunFeemsSim-0.2.2/RunFeemsSim.egg-info/requires.txt +7 -0
- RunFeemsSim-0.2.2/RunFeemsSim.egg-info/top_level.txt +1 -0
- RunFeemsSim-0.2.2/settings.ini +27 -0
- RunFeemsSim-0.2.2/setup.cfg +4 -0
- RunFeemsSim-0.2.2/setup.py +113 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# How to contribute
|
|
2
|
+
|
|
3
|
+
## How to get started
|
|
4
|
+
|
|
5
|
+
Before anything else, please install the git hooks that run automatic scripts during each commit and merge to strip the notebooks of superfluous metadata (and avoid merge conflicts). After cloning the repository, run the following command inside it:
|
|
6
|
+
```
|
|
7
|
+
nbdev_install_git_hooks
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Did you find a bug?
|
|
11
|
+
|
|
12
|
+
* Ensure the bug was not already reported by searching on GitHub under Issues.
|
|
13
|
+
* If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
|
|
14
|
+
* Be sure to add the complete error messages.
|
|
15
|
+
|
|
16
|
+
#### Did you write a patch that fixes a bug?
|
|
17
|
+
|
|
18
|
+
* Open a new GitHub pull request with the patch.
|
|
19
|
+
* Ensure that your PR includes a test that fails without your patch, and pass with it.
|
|
20
|
+
* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
|
|
21
|
+
|
|
22
|
+
## PR submission guidelines
|
|
23
|
+
|
|
24
|
+
* Keep each PR focused. While it's more convenient, do not combine several unrelated fixes together. Create as many branches as needing to keep each PR focused.
|
|
25
|
+
* Do not mix style changes/fixes with "functional" changes. It's very difficult to review such PRs and it most likely get rejected.
|
|
26
|
+
* Do not add/remove vertical whitespace. Preserve the original style of the file you edit as much as you can.
|
|
27
|
+
* Do not turn an already submitted PR into your development playground. If after you submitted PR, you discovered that more work is needed - close the PR, do the required work and then submit a new PR. Otherwise each of your commits requires attention from maintainers of the project.
|
|
28
|
+
* If, however, you submitted a PR and received a request for changes, you should proceed with commits inside that PR, so that the maintainer can see the incremental fixes and won't need to review the whole PR again. In the exception case where you realize it'll take many many commits to complete the requests, then it's probably best to close the PR, do the work and then submit it again. Use common sense where you'd choose one way over another.
|
|
29
|
+
|
|
30
|
+
## Do you want to contribute to the documentation?
|
|
31
|
+
|
|
32
|
+
* Docs are automatically created from the notebooks in the nbs folder.
|
|
33
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 SINTEF
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: RunFeemsSim
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: A library for running feems simulation
|
|
5
|
+
Home-page: https://SintefOceanEnergySystem@dev.azure.com/SintefOceanEnergySystem/FEEMSService/_git/RunFEEMSSim
|
|
6
|
+
Author: Kevin Koosup Yum
|
|
7
|
+
Author-email: kevinkoosup.yum@sintef.no
|
|
8
|
+
License: Apache Software License 2.0
|
|
9
|
+
Keywords: FEEMS,machinery system,fuel,emissions
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: pip
|
|
19
|
+
Requires-Dist: packaging
|
|
20
|
+
Requires-Dist: pandas
|
|
21
|
+
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: MachSysS
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
|
|
25
|
+
# RunFeemsSim Package
|
|
26
|
+
|
|
27
|
+
> The RunFeemsSim package is a Python package for running FEEMS simulations. It provides a simple
|
|
28
|
+
> interface for running FEEMS simulations and for visualizing the results. It also provides a basic
|
|
29
|
+
> pms model to apply for an electric power system that has a functionality of load dependent
|
|
30
|
+
> start-stop of gensets.
|
|
31
|
+
|
|
32
|
+
## Installation of the package
|
|
33
|
+
The package is distributed by the Azure Artifacts package manager. To install the package,
|
|
34
|
+
you need to install artifacts-keyring package and should have a valid Azure DevOps account.
|
|
35
|
+
```sh
|
|
36
|
+
pip install artifacts-keyring
|
|
37
|
+
```
|
|
38
|
+
Then, you need to add the package source to your pip configuration. You can do this by copying
|
|
39
|
+
the pip configuration file (pip.conf for macOS and Linux or pip.ini for Windows) to your
|
|
40
|
+
virtual environment directory or base python directory. The file should contain the following lines:
|
|
41
|
+
```sh
|
|
42
|
+
[global]
|
|
43
|
+
extra-index-url=https://pkgs.dev.azure.com/SintefOceanEnergySystem/_packaging/SintefOceanEnergySystem/pypi/simple/
|
|
44
|
+
```
|
|
45
|
+
If you already have a pip configuration file, you can add the above lines to the file. Finally,
|
|
46
|
+
you can install the package by running the following command:
|
|
47
|
+
```sh
|
|
48
|
+
pip install RunFeemsSim
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Installation of the development environment
|
|
52
|
+
For the development, one should create a virtual environment and install the package using the
|
|
53
|
+
requirements.txt file. First, create a virtual environment and activate it.
|
|
54
|
+
```sh
|
|
55
|
+
python -m venv venv
|
|
56
|
+
source venv/bin/activate
|
|
57
|
+
```
|
|
58
|
+
Then, you need to add the package source to your pip configuration. You can do this by copying
|
|
59
|
+
the pip configuration file (pip.conf for macOS and Linux or pip.ini for Windows) to your venv
|
|
60
|
+
directory or base python directory. The file should contain the following lines:
|
|
61
|
+
```sh
|
|
62
|
+
[global]
|
|
63
|
+
extra-index-url=https://pkgs.dev.azure.com/SintefOceanEnergySystem/_packaging/SintefOceanEnergySystem/pypi/simple/
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Then, install the package using the requirements.txt file.
|
|
67
|
+
```sh
|
|
68
|
+
pip install -r requirements.txt
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# RunFeemsSim Package
|
|
2
|
+
|
|
3
|
+
> The RunFeemsSim package is a Python package for running FEEMS simulations. It provides a simple
|
|
4
|
+
> interface for running FEEMS simulations and for visualizing the results. It also provides a basic
|
|
5
|
+
> pms model to apply for an electric power system that has a functionality of load dependent
|
|
6
|
+
> start-stop of gensets.
|
|
7
|
+
|
|
8
|
+
## Installation of the package
|
|
9
|
+
The package is distributed by the Azure Artifacts package manager. To install the package,
|
|
10
|
+
you need to install artifacts-keyring package and should have a valid Azure DevOps account.
|
|
11
|
+
```sh
|
|
12
|
+
pip install artifacts-keyring
|
|
13
|
+
```
|
|
14
|
+
Then, you need to add the package source to your pip configuration. You can do this by copying
|
|
15
|
+
the pip configuration file (pip.conf for macOS and Linux or pip.ini for Windows) to your
|
|
16
|
+
virtual environment directory or base python directory. The file should contain the following lines:
|
|
17
|
+
```sh
|
|
18
|
+
[global]
|
|
19
|
+
extra-index-url=https://pkgs.dev.azure.com/SintefOceanEnergySystem/_packaging/SintefOceanEnergySystem/pypi/simple/
|
|
20
|
+
```
|
|
21
|
+
If you already have a pip configuration file, you can add the above lines to the file. Finally,
|
|
22
|
+
you can install the package by running the following command:
|
|
23
|
+
```sh
|
|
24
|
+
pip install RunFeemsSim
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Installation of the development environment
|
|
28
|
+
For the development, one should create a virtual environment and install the package using the
|
|
29
|
+
requirements.txt file. First, create a virtual environment and activate it.
|
|
30
|
+
```sh
|
|
31
|
+
python -m venv venv
|
|
32
|
+
source venv/bin/activate
|
|
33
|
+
```
|
|
34
|
+
Then, you need to add the package source to your pip configuration. You can do this by copying
|
|
35
|
+
the pip configuration file (pip.conf for macOS and Linux or pip.ini for Windows) to your venv
|
|
36
|
+
directory or base python directory. The file should contain the following lines:
|
|
37
|
+
```sh
|
|
38
|
+
[global]
|
|
39
|
+
extra-index-url=https://pkgs.dev.azure.com/SintefOceanEnergySystem/_packaging/SintefOceanEnergySystem/pypi/simple/
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then, install the package using the requirements.txt file.
|
|
43
|
+
```sh
|
|
44
|
+
pip install -r requirements.txt
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.2"
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Autogenerated by nbdev
|
|
2
|
+
|
|
3
|
+
d = {
|
|
4
|
+
"settings": {
|
|
5
|
+
"branch": "master",
|
|
6
|
+
"doc_baseurl": "/RunFeemsSim/",
|
|
7
|
+
"doc_host": "https://kevinkoosup.yum@sintef.no.github.io",
|
|
8
|
+
"git_url": "https://SintefOceanEnergySystem@dev.azure.com/SintefOceanEnergySystem/FEEMSService/_git/RunFEEMSSim",
|
|
9
|
+
"lib_path": "RunFeemsSim",
|
|
10
|
+
},
|
|
11
|
+
"syms": {
|
|
12
|
+
"RunFeemsSim.machinery_calculation": {
|
|
13
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation": (
|
|
14
|
+
"machinery_calculation.html#machinerycalculation",
|
|
15
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
16
|
+
),
|
|
17
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation.__init__": (
|
|
18
|
+
"machinery_calculation.html#machinerycalculation.__init__",
|
|
19
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
20
|
+
),
|
|
21
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation._run_simulation": (
|
|
22
|
+
"machinery_calculation.html#machinerycalculation._run_simulation",
|
|
23
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
24
|
+
),
|
|
25
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation._set_equal_load_sharing_on_power_sources": (
|
|
26
|
+
"machinery_calculation.html#machinerycalculation._set_equal_load_sharing_on_power_sources",
|
|
27
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
28
|
+
),
|
|
29
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation._set_input_load_from_gymir_result": (
|
|
30
|
+
"machinery_calculation.html#machinerycalculation._set_input_load_from_gymir_result",
|
|
31
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
32
|
+
),
|
|
33
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation._set_input_load_time_interval_from_propulsion_power_time_series": (
|
|
34
|
+
"machinery_calculation.html#machinerycalculation._set_input_load_time_interval_from_propulsion_power_time_series",
|
|
35
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
36
|
+
),
|
|
37
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation._set_status_for_mechanical_system": (
|
|
38
|
+
"machinery_calculation.html#machinerycalculation._set_status_for_mechanical_system",
|
|
39
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
40
|
+
),
|
|
41
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation.calculate_machinery_system_output_from_gymir_result": (
|
|
42
|
+
"machinery_calculation.html#machinerycalculation.calculate_machinery_system_output_from_gymir_result",
|
|
43
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
44
|
+
),
|
|
45
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation.calculate_machinery_system_output_from_propulsion_power_time_series": (
|
|
46
|
+
"machinery_calculation.html#machinerycalculation.calculate_machinery_system_output_from_propulsion_power_time_series",
|
|
47
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
48
|
+
),
|
|
49
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation.calculate_machinery_system_output_from_statistics": (
|
|
50
|
+
"machinery_calculation.html#machinerycalculation.calculate_machinery_system_output_from_statistics",
|
|
51
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
52
|
+
),
|
|
53
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation.calculate_machinery_system_output_from_time_series_result": (
|
|
54
|
+
"machinery_calculation.html#machinerycalculation.calculate_machinery_system_output_from_time_series_result",
|
|
55
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
56
|
+
),
|
|
57
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation.electric_system": (
|
|
58
|
+
"machinery_calculation.html#machinerycalculation.electric_system",
|
|
59
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
60
|
+
),
|
|
61
|
+
"RunFeemsSim.machinery_calculation.MachineryCalculation.system_is_not_electric": (
|
|
62
|
+
"machinery_calculation.html#machinerycalculation.system_is_not_electric",
|
|
63
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
64
|
+
),
|
|
65
|
+
"RunFeemsSim.machinery_calculation.convert_gymir_result_to_propulsion_power_series": (
|
|
66
|
+
"machinery_calculation.html#convert_gymir_result_to_propulsion_power_series",
|
|
67
|
+
"RunFeemsSim/machinery_calculation.py",
|
|
68
|
+
),
|
|
69
|
+
},
|
|
70
|
+
"RunFeemsSim.pms_basic": {
|
|
71
|
+
"RunFeemsSim.pms_basic.PmsLoadTable": (
|
|
72
|
+
"pms_basic.html#pmsloadtable",
|
|
73
|
+
"RunFeemsSim/pms_basic.py",
|
|
74
|
+
),
|
|
75
|
+
"RunFeemsSim.pms_basic.PmsLoadTable.__post_init__": (
|
|
76
|
+
"pms_basic.html#pmsloadtable.__post_init__",
|
|
77
|
+
"RunFeemsSim/pms_basic.py",
|
|
78
|
+
),
|
|
79
|
+
"RunFeemsSim.pms_basic.PmsLoadTable.on_pattern": (
|
|
80
|
+
"pms_basic.html#pmsloadtable.on_pattern",
|
|
81
|
+
"RunFeemsSim/pms_basic.py",
|
|
82
|
+
),
|
|
83
|
+
"RunFeemsSim.pms_basic.PmsLoadTable.sorted_load_table": (
|
|
84
|
+
"pms_basic.html#pmsloadtable.sorted_load_table",
|
|
85
|
+
"RunFeemsSim/pms_basic.py",
|
|
86
|
+
),
|
|
87
|
+
"RunFeemsSim.pms_basic.PmsLoadTableSimulationInterface": (
|
|
88
|
+
"pms_basic.html#pmsloadtablesimulationinterface",
|
|
89
|
+
"RunFeemsSim/pms_basic.py",
|
|
90
|
+
),
|
|
91
|
+
"RunFeemsSim.pms_basic.PmsLoadTableSimulationInterface.__init__": (
|
|
92
|
+
"pms_basic.html#pmsloadtablesimulationinterface.__init__",
|
|
93
|
+
"RunFeemsSim/pms_basic.py",
|
|
94
|
+
),
|
|
95
|
+
"RunFeemsSim.pms_basic.PmsLoadTableSimulationInterface.set_status": (
|
|
96
|
+
"pms_basic.html#pmsloadtablesimulationinterface.set_status",
|
|
97
|
+
"RunFeemsSim/pms_basic.py",
|
|
98
|
+
),
|
|
99
|
+
"RunFeemsSim.pms_basic.get_min_load_table_dict_from_feems_system": (
|
|
100
|
+
"pms_basic.html#get_min_load_table_dict_from_feems_system",
|
|
101
|
+
"RunFeemsSim/pms_basic.py",
|
|
102
|
+
),
|
|
103
|
+
"RunFeemsSim.pms_basic.get_min_load_table_dict_from_proto_system": (
|
|
104
|
+
"pms_basic.html#get_min_load_table_dict_from_proto_system",
|
|
105
|
+
"RunFeemsSim/pms_basic.py",
|
|
106
|
+
),
|
|
107
|
+
"RunFeemsSim.pms_basic.get_rated_power_from_power_source": (
|
|
108
|
+
"pms_basic.html#get_rated_power_from_power_source",
|
|
109
|
+
"RunFeemsSim/pms_basic.py",
|
|
110
|
+
),
|
|
111
|
+
"RunFeemsSim.pms_basic.min_load_table_dict": (
|
|
112
|
+
"pms_basic.html#min_load_table_dict",
|
|
113
|
+
"RunFeemsSim/pms_basic.py",
|
|
114
|
+
),
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# AUTOGENERATED BY NBDEV! DO NOT EDIT!
|
|
2
|
+
|
|
3
|
+
__all__ = ["index", "modules", "custom_doc_links", "git_url"]
|
|
4
|
+
|
|
5
|
+
index = {
|
|
6
|
+
"convert_gymir_result_to_propulsion_power_series": "00_machinery_calculation.ipynb",
|
|
7
|
+
"MachineryCalculation": "00_machinery_calculation.ipynb",
|
|
8
|
+
"PmsLoadTable": "01_pms_basic.ipynb",
|
|
9
|
+
"get_rated_power_from_power_source": "01_pms_basic.ipynb",
|
|
10
|
+
"get_min_load_table_dict_from_proto_system": "01_pms_basic.ipynb",
|
|
11
|
+
"get_min_load_table_dict_from_feems_system": "01_pms_basic.ipynb",
|
|
12
|
+
"min_load_table_dict": "01_pms_basic.ipynb",
|
|
13
|
+
"PmsLoadTableSimulationInterface": "01_pms_basic.ipynb",
|
|
14
|
+
"OnPattern": "01_pms_basic.ipynb",
|
|
15
|
+
"Load2OnPattern": "01_pms_basic.ipynb",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
modules = ["machinery_calculation.py", "pms_basic.py"]
|
|
19
|
+
|
|
20
|
+
doc_url = "https://kevinkoosup.yum@sintef.no.github.io/RunFeemsSim/"
|
|
21
|
+
|
|
22
|
+
git_url = "https://"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def custom_doc_links(name):
|
|
26
|
+
return None
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# AUTOGENERATED! DO NOT EDIT! File to edit: ../00_machinery_calculation.ipynb.
|
|
2
|
+
|
|
3
|
+
# %% auto 0
|
|
4
|
+
__all__ = [
|
|
5
|
+
"Numeric",
|
|
6
|
+
"convert_gymir_result_to_propulsion_power_series",
|
|
7
|
+
"MachineryCalculation",
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
# %% ../00_machinery_calculation.ipynb 3
|
|
11
|
+
from typing import List, Union, Type, TypeVar
|
|
12
|
+
|
|
13
|
+
import MachSysS.gymir_result_pb2 as proto_gymir
|
|
14
|
+
from MachSysS.convert_proto_timeseries import convert_proto_timeseries_to_pd_dataframe
|
|
15
|
+
import numpy as np
|
|
16
|
+
import pandas as pd
|
|
17
|
+
from feems.components_model.utility import IntegrationMethod
|
|
18
|
+
from feems.system_model import (
|
|
19
|
+
ElectricPowerSystem,
|
|
20
|
+
HybridPropulsionSystem,
|
|
21
|
+
MechanicalPropulsionSystemWithElectricPowerSystem,
|
|
22
|
+
FEEMSResultForMachinerySystem,
|
|
23
|
+
)
|
|
24
|
+
from feems.types_for_feems import FEEMSResult, TypePower
|
|
25
|
+
from feems.simulation_interface import SimulationInterface
|
|
26
|
+
from feems.fuel import FuelSpecifiedBy
|
|
27
|
+
|
|
28
|
+
from RunFeemsSim.pms_basic import (
|
|
29
|
+
PmsLoadTable,
|
|
30
|
+
get_min_load_table_dict_from_feems_system,
|
|
31
|
+
PmsLoadTableSimulationInterface,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
Numeric = TypeVar("Numeric", int, float, np.ndarray)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def convert_gymir_result_to_propulsion_power_series(
|
|
38
|
+
gymir_result: proto_gymir.GymirResult,
|
|
39
|
+
) -> pd.Series:
|
|
40
|
+
time = map(lambda each: each.epoch_s, gymir_result.result)
|
|
41
|
+
power = map(lambda each: each.power_kw, gymir_result.result)
|
|
42
|
+
return pd.Series(index=time, data=power)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class MachineryCalculation:
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
feems_system: Union[
|
|
49
|
+
ElectricPowerSystem,
|
|
50
|
+
MechanicalPropulsionSystemWithElectricPowerSystem,
|
|
51
|
+
HybridPropulsionSystem,
|
|
52
|
+
],
|
|
53
|
+
pms: SimulationInterface = None,
|
|
54
|
+
maximum_allowed_power_source_load_percentage: float = 80,
|
|
55
|
+
):
|
|
56
|
+
self.system_feems = feems_system
|
|
57
|
+
if pms is None:
|
|
58
|
+
load_table = PmsLoadTable(
|
|
59
|
+
min_load2on_pattern=get_min_load_table_dict_from_feems_system(
|
|
60
|
+
system=feems_system,
|
|
61
|
+
maximum_allowed_genset_load_percentage=maximum_allowed_power_source_load_percentage,
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
self.pms = PmsLoadTableSimulationInterface(
|
|
65
|
+
n_bus_ties=1, pms_load_table=load_table
|
|
66
|
+
)
|
|
67
|
+
else:
|
|
68
|
+
self.pms = pms
|
|
69
|
+
self._set_equal_load_sharing_on_power_sources(n_datapoints=1)
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def electric_system(self) -> ElectricPowerSystem:
|
|
73
|
+
if self.system_is_not_electric:
|
|
74
|
+
return self.system_feems.electric_system
|
|
75
|
+
else:
|
|
76
|
+
return self.system_feems
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def system_is_not_electric(self) -> bool:
|
|
80
|
+
return hasattr(self.system_feems, "electric_system")
|
|
81
|
+
|
|
82
|
+
def _set_input_load_from_gymir_result(
|
|
83
|
+
self,
|
|
84
|
+
*,
|
|
85
|
+
gymir_result: proto_gymir.GymirResult,
|
|
86
|
+
) -> None:
|
|
87
|
+
propulsion_power_timeseries = convert_gymir_result_to_propulsion_power_series(
|
|
88
|
+
gymir_result
|
|
89
|
+
)
|
|
90
|
+
self._set_input_load_time_interval_from_propulsion_power_time_series(
|
|
91
|
+
propulsion_power_time_series=propulsion_power_timeseries,
|
|
92
|
+
auxiliary_load_kw=gymir_result.auxiliary_load_kw,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def _set_input_load_time_interval_from_propulsion_power_time_series(
|
|
96
|
+
self,
|
|
97
|
+
*,
|
|
98
|
+
propulsion_power_time_series: pd.Series,
|
|
99
|
+
auxiliary_load_kw: Numeric,
|
|
100
|
+
time_is_given_as_interval: bool = False,
|
|
101
|
+
) -> None:
|
|
102
|
+
if time_is_given_as_interval:
|
|
103
|
+
propulsion_power = propulsion_power_time_series.values
|
|
104
|
+
time_interval_s = propulsion_power_time_series.index.to_numpy()
|
|
105
|
+
else:
|
|
106
|
+
propulsion_power = propulsion_power_time_series.values[:-1]
|
|
107
|
+
time_interval_s = np.diff(propulsion_power_time_series.index.to_numpy())
|
|
108
|
+
|
|
109
|
+
number_points = len(propulsion_power)
|
|
110
|
+
auxiliary_load_kw = np.atleast_1d(auxiliary_load_kw)
|
|
111
|
+
if len(auxiliary_load_kw) > 1:
|
|
112
|
+
auxiliary_load_kw = auxiliary_load_kw[:number_points]
|
|
113
|
+
else:
|
|
114
|
+
auxiliary_load_kw = np.repeat(auxiliary_load_kw, number_points)
|
|
115
|
+
# set power load
|
|
116
|
+
number_of_propulsors = len(self.electric_system.propulsion_drives)
|
|
117
|
+
if self.system_is_not_electric:
|
|
118
|
+
number_of_propulsors = (
|
|
119
|
+
self.system_feems.mechanical_system.no_mechanical_loads
|
|
120
|
+
)
|
|
121
|
+
number_of_other_loads = len(self.electric_system.other_load)
|
|
122
|
+
if number_of_other_loads == 0:
|
|
123
|
+
assert np.all(
|
|
124
|
+
np.atleast_1d(auxiliary_load_kw) == 0
|
|
125
|
+
), "Auxiliary load is not zero while other loads are not defined in the system."
|
|
126
|
+
for propulsor in self.electric_system.propulsion_drives:
|
|
127
|
+
propulsor.set_power_input_from_output(
|
|
128
|
+
propulsion_power / number_of_propulsors
|
|
129
|
+
)
|
|
130
|
+
if self.system_is_not_electric:
|
|
131
|
+
for propulsor in self.system_feems.mechanical_system.mechanical_loads:
|
|
132
|
+
propulsor.set_power_input_from_output(
|
|
133
|
+
propulsion_power / number_of_propulsors
|
|
134
|
+
)
|
|
135
|
+
for other_load in self.electric_system.other_load:
|
|
136
|
+
other_load.power_input = auxiliary_load_kw / number_of_other_loads
|
|
137
|
+
self.electric_system.set_time_interval(
|
|
138
|
+
time_interval_s=time_interval_s,
|
|
139
|
+
integration_method=IntegrationMethod.sum_with_time,
|
|
140
|
+
)
|
|
141
|
+
if self.system_is_not_electric:
|
|
142
|
+
self.system_feems.mechanical_system.set_time_interval(
|
|
143
|
+
time_interval_s=time_interval_s,
|
|
144
|
+
integration_method=IntegrationMethod.sum_with_time,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
def _set_equal_load_sharing_on_power_sources(self, n_datapoints: int) -> None:
|
|
148
|
+
for power_source in self.electric_system.power_sources:
|
|
149
|
+
power_source.load_sharing_mode = np.zeros(shape=[n_datapoints])
|
|
150
|
+
if self.system_is_not_electric:
|
|
151
|
+
for power_source in self.system_feems.mechanical_system.main_engines:
|
|
152
|
+
power_source.load_sharing_mode = np.zeros(shape=[n_datapoints])
|
|
153
|
+
|
|
154
|
+
def _set_status_for_mechanical_system(self) -> None:
|
|
155
|
+
"""Set the status of main engines for the mechanical system, turning all the gensets on.
|
|
156
|
+
The main engines that are not used for propulsion after the power balance calculation
|
|
157
|
+
will be turned off.
|
|
158
|
+
"""
|
|
159
|
+
if np.isscalar(self.system_feems.mechanical_system.time_interval_s):
|
|
160
|
+
n_data_points = 1
|
|
161
|
+
else:
|
|
162
|
+
n_data_points = len(self.system_feems.mechanical_system.time_interval_s)
|
|
163
|
+
for main_engine in self.system_feems.mechanical_system.main_engines:
|
|
164
|
+
main_engine.status = np.ones(n_data_points).astype(bool)
|
|
165
|
+
|
|
166
|
+
def _run_simulation(
|
|
167
|
+
self,
|
|
168
|
+
fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
|
|
169
|
+
ignore_power_balance: bool = False,
|
|
170
|
+
) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
|
|
171
|
+
"""Run the simulation and return the result.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
|
|
175
|
+
ignore_power_balance(bool): If True, the power balance calculation will be ignored.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
The result of the simulation. FEEMSResult or FEEMSResultForMachinery system.
|
|
179
|
+
"""
|
|
180
|
+
if ignore_power_balance:
|
|
181
|
+
if self.system_is_not_electric:
|
|
182
|
+
return self.system_feems.get_fuel_energy_consumption_running_time(
|
|
183
|
+
time_interval_s=self.system_feems.mechanical_system.time_interval_s,
|
|
184
|
+
integration_method=IntegrationMethod.sum_with_time,
|
|
185
|
+
fuel_specified_by=fuel_specified_by,
|
|
186
|
+
)
|
|
187
|
+
else:
|
|
188
|
+
return self.system_feems.get_fuel_energy_consumption_running_time(
|
|
189
|
+
fuel_specified_by=fuel_specified_by
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
power_kw_per_switchboard = (
|
|
193
|
+
self.electric_system.get_sum_consumption_kw_sources_switchboard()
|
|
194
|
+
)
|
|
195
|
+
self.pms.set_status(
|
|
196
|
+
power_kw_per_switchboard=power_kw_per_switchboard,
|
|
197
|
+
electric_power_system=self.electric_system,
|
|
198
|
+
time_interval_s=self.electric_system.time_interval_s,
|
|
199
|
+
power_source_priority=None,
|
|
200
|
+
)
|
|
201
|
+
if self.system_is_not_electric:
|
|
202
|
+
self._set_status_for_mechanical_system()
|
|
203
|
+
self.system_feems.do_power_balance_calculation()
|
|
204
|
+
return self.system_feems.get_fuel_energy_consumption_running_time(
|
|
205
|
+
time_interval_s=self.system_feems.mechanical_system.time_interval_s,
|
|
206
|
+
integration_method=IntegrationMethod.sum_with_time,
|
|
207
|
+
fuel_specified_by=fuel_specified_by,
|
|
208
|
+
)
|
|
209
|
+
else:
|
|
210
|
+
self.system_feems.do_power_balance_calculation()
|
|
211
|
+
return self.system_feems.get_fuel_energy_consumption_running_time(
|
|
212
|
+
fuel_specified_by=fuel_specified_by
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
def calculate_machinery_system_output_from_gymir_result(
|
|
216
|
+
self,
|
|
217
|
+
*,
|
|
218
|
+
gymir_result: proto_gymir.GymirResult,
|
|
219
|
+
fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
|
|
220
|
+
ignore_power_balance: bool = False,
|
|
221
|
+
) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
|
|
222
|
+
"""
|
|
223
|
+
Calculate the machinery system output from a Gymir result.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
gymir_result(GymirResult): Gymir result given as protobuf message.
|
|
227
|
+
fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
|
|
228
|
+
ignore_power_balance(bool): If True, the power balance calculation will be ignored.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
The result of the calculation. FEEMSResult or FEEMSResultForMachinerySystem.
|
|
232
|
+
"""
|
|
233
|
+
self._set_input_load_from_gymir_result(gymir_result=gymir_result)
|
|
234
|
+
return self._run_simulation(
|
|
235
|
+
fuel_specified_by=fuel_specified_by,
|
|
236
|
+
ignore_power_balance=ignore_power_balance,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
def calculate_machinery_system_output_from_propulsion_power_time_series(
|
|
240
|
+
self,
|
|
241
|
+
*,
|
|
242
|
+
propulsion_power: pd.Series,
|
|
243
|
+
auxiliary_power_kw: Numeric,
|
|
244
|
+
fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
|
|
245
|
+
ignore_power_balance: bool = False,
|
|
246
|
+
) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
|
|
247
|
+
"""
|
|
248
|
+
Calculate the machinery system output from a time series of the propulsion power and
|
|
249
|
+
auxiliary power.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
propulsion_power(pd.Series): The propulsion power time series.
|
|
253
|
+
auxiliary_power_kw(Numeric): The auxiliary power in kW. It can be a single value or
|
|
254
|
+
a numpy array with the same length as the propulsion power.
|
|
255
|
+
fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
|
|
256
|
+
ignore_power_balance(bool): If True, the power balance calculation will be ignored.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
The result of the calculation. FEEMSResult or FEEMSResultForMachinerySystem.
|
|
260
|
+
"""
|
|
261
|
+
if not np.isscalar(auxiliary_power_kw):
|
|
262
|
+
assert (
|
|
263
|
+
len(propulsion_power) == len(auxiliary_power_kw)
|
|
264
|
+
or len(auxiliary_power_kw) == 1
|
|
265
|
+
), "The length of the auxiliary power must be 1 or the same as the propulsion power"
|
|
266
|
+
self._set_input_load_time_interval_from_propulsion_power_time_series(
|
|
267
|
+
propulsion_power_time_series=propulsion_power,
|
|
268
|
+
auxiliary_load_kw=auxiliary_power_kw,
|
|
269
|
+
)
|
|
270
|
+
return self._run_simulation(
|
|
271
|
+
fuel_specified_by=fuel_specified_by,
|
|
272
|
+
ignore_power_balance=ignore_power_balance,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
def calculate_machinery_system_output_from_time_series_result(
|
|
276
|
+
self,
|
|
277
|
+
*,
|
|
278
|
+
time_series: proto_gymir.TimeSeriesResult,
|
|
279
|
+
fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
|
|
280
|
+
ignore_power_balance: bool = False,
|
|
281
|
+
) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
|
|
282
|
+
"""
|
|
283
|
+
Calculate the machinery system output from statistics of the propulsion power.
|
|
284
|
+
Args:
|
|
285
|
+
time_series(TimeSeriesResult): Time series result given as protobuf message.
|
|
286
|
+
fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
|
|
287
|
+
ignore_power_balance(bool): If True, the power balance calculation will be ignored.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
The result of the simulation. FEEMSResult or FEEMSResultForMachinery system.
|
|
291
|
+
"""
|
|
292
|
+
df = convert_proto_timeseries_to_pd_dataframe(time_series)
|
|
293
|
+
self._set_input_load_time_interval_from_propulsion_power_time_series(
|
|
294
|
+
propulsion_power_time_series=df["propulsion_power_kw"],
|
|
295
|
+
auxiliary_load_kw=df["auxiliary_power_kw"].values,
|
|
296
|
+
)
|
|
297
|
+
return self._run_simulation(
|
|
298
|
+
fuel_specified_by=fuel_specified_by,
|
|
299
|
+
ignore_power_balance=ignore_power_balance,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
def calculate_machinery_system_output_from_statistics(
|
|
303
|
+
self,
|
|
304
|
+
*,
|
|
305
|
+
propulsion_power: np.ndarray,
|
|
306
|
+
frequency: np.ndarray,
|
|
307
|
+
auxiliary_power_kw: Numeric,
|
|
308
|
+
fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
|
|
309
|
+
ignore_power_balance: bool = False,
|
|
310
|
+
) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
|
|
311
|
+
"""
|
|
312
|
+
Calculate the machinery system output from statistics of the propulsion power.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
propulsion_power(np.ndarray): The propulsion power for each mode in kW.
|
|
316
|
+
frequency(np.ndarray): The frequency of each mode in seconds. If the frequency is
|
|
317
|
+
given as normalized value, the output should be interpreted as per second value.
|
|
318
|
+
auxiliary_power_kw(Numeric): The auxiliary power for each mode in kW. It is also
|
|
319
|
+
possible to give a single value for all modes.
|
|
320
|
+
fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
|
|
321
|
+
ignore_power_balance(bool): If True, the power balance calculation will be ignored.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
The result of the simulation. FEEMSResult or FEEMSResultForMachinery system.
|
|
325
|
+
"""
|
|
326
|
+
if not np.isscalar(auxiliary_power_kw):
|
|
327
|
+
assert (
|
|
328
|
+
len(propulsion_power) == len(auxiliary_power_kw)
|
|
329
|
+
or len(auxiliary_power_kw) == 1
|
|
330
|
+
), "The length of the auxiliary power must be 1 or the same as the propulsion power"
|
|
331
|
+
self._set_input_load_time_interval_from_propulsion_power_time_series(
|
|
332
|
+
propulsion_power_time_series=pd.Series(
|
|
333
|
+
data=propulsion_power, index=frequency
|
|
334
|
+
),
|
|
335
|
+
auxiliary_load_kw=auxiliary_power_kw,
|
|
336
|
+
time_is_given_as_interval=True,
|
|
337
|
+
)
|
|
338
|
+
return self._run_simulation(
|
|
339
|
+
fuel_specified_by=fuel_specified_by,
|
|
340
|
+
ignore_power_balance=ignore_power_balance,
|
|
341
|
+
)
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# AUTOGENERATED! DO NOT EDIT! File to edit: ../01_pms_basic.ipynb.
|
|
2
|
+
|
|
3
|
+
# %% auto 0
|
|
4
|
+
__all__ = [
|
|
5
|
+
"OnPattern",
|
|
6
|
+
"Load2OnPattern",
|
|
7
|
+
"PmsLoadTable",
|
|
8
|
+
"get_rated_power_from_power_source",
|
|
9
|
+
"get_min_load_table_dict_from_proto_system",
|
|
10
|
+
"get_min_load_table_dict_from_feems_system",
|
|
11
|
+
"min_load_table_dict",
|
|
12
|
+
"PmsLoadTableSimulationInterface",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
# %% ../01_pms_basic.ipynb 3
|
|
16
|
+
import itertools
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from itertools import chain
|
|
19
|
+
from typing import Dict, List, Tuple, Union
|
|
20
|
+
|
|
21
|
+
import numpy as np
|
|
22
|
+
|
|
23
|
+
from feems.components_model import SwbId
|
|
24
|
+
from feems.simulation_interface import SimulationInterface, EnergySourceType
|
|
25
|
+
from feems.system_model import (
|
|
26
|
+
ElectricPowerSystem,
|
|
27
|
+
MechanicalPropulsionSystemWithElectricPowerSystem,
|
|
28
|
+
HybridPropulsionSystem,
|
|
29
|
+
)
|
|
30
|
+
from feems.types_for_feems import Power_kW, TypeComponent
|
|
31
|
+
|
|
32
|
+
import MachSysS.system_structure_pb2 as proto_system
|
|
33
|
+
import MachSysS.convert_to_feems as feems_converter
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
OnPattern = Tuple[
|
|
37
|
+
bool, ...
|
|
38
|
+
] # Tuple of on-status for each producer in a power management system.
|
|
39
|
+
Load2OnPattern = Dict[
|
|
40
|
+
Power_kW, OnPattern
|
|
41
|
+
] # Mapping from load power into PMS on-status.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class PmsLoadTable:
|
|
46
|
+
"""Table of producer OnPattern for each minimum load of a power management system."""
|
|
47
|
+
|
|
48
|
+
min_load2on_pattern: Load2OnPattern
|
|
49
|
+
|
|
50
|
+
def __post_init__(self) -> None:
|
|
51
|
+
# Sort belonging loads and patterns to obtain increasing loads with keys and values in separate tuples.
|
|
52
|
+
self._bins, self._i2on = zip(*sorted(self.min_load2on_pattern.items()))
|
|
53
|
+
|
|
54
|
+
def sorted_load_table(self) -> Tuple[Tuple[Power_kW, ...], Tuple[OnPattern, ...]]:
|
|
55
|
+
"""Return the sorted load table with loads and patterns separated."""
|
|
56
|
+
return self._bins, self._i2on
|
|
57
|
+
|
|
58
|
+
def on_pattern(
|
|
59
|
+
self, load: Union[List[float], List[Power_kW], np.ndarray]
|
|
60
|
+
) -> List[OnPattern]:
|
|
61
|
+
"""Return one OnPattern for each input value in load vector."""
|
|
62
|
+
return [self._i2on[i] for i in np.digitize(load, self._bins[1:])] # type: ignore[no-untyped-call]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_rated_power_from_power_source(subsystem: proto_system.Subsystem) -> float:
|
|
66
|
+
if subsystem.rated_power_kw > 0:
|
|
67
|
+
return subsystem.rated_power_kw
|
|
68
|
+
else:
|
|
69
|
+
component = feems_converter.collect_electric_components_from_sub_system(
|
|
70
|
+
subsystem
|
|
71
|
+
)[0].get("proto_component")
|
|
72
|
+
return component.rated_power_kw
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_min_load_table_dict_from_proto_system(
|
|
76
|
+
system: proto_system.MachinerySystem,
|
|
77
|
+
) -> Load2OnPattern:
|
|
78
|
+
"""Return a minimum load table dict generated from a protubuf message"""
|
|
79
|
+
gensets_rated_power_kw: List[Power_kW] = []
|
|
80
|
+
# Loop inspired by system_configuration_graphic.converter.converter.FeemsConverter.model()
|
|
81
|
+
for switchboard in system.electric_system.switchboards:
|
|
82
|
+
groups_rated_power = [
|
|
83
|
+
get_rated_power_from_power_source(subsystem)
|
|
84
|
+
for subsystem in switchboard.subsystems
|
|
85
|
+
if subsystem.power_type == proto_system.Subsystem.PowerType.POWER_SOURCE
|
|
86
|
+
]
|
|
87
|
+
gensets_rated_power_kw.extend(groups_rated_power)
|
|
88
|
+
|
|
89
|
+
return min_load_table_dict(
|
|
90
|
+
gensets_rated_power_kw, system.maximum_allowed_genset_load_percentage / 100
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_min_load_table_dict_from_feems_system(
|
|
95
|
+
system: Union[
|
|
96
|
+
ElectricPowerSystem,
|
|
97
|
+
MechanicalPropulsionSystemWithElectricPowerSystem,
|
|
98
|
+
HybridPropulsionSystem,
|
|
99
|
+
],
|
|
100
|
+
maximum_allowed_genset_load_percentage,
|
|
101
|
+
component_types: List[TypeComponent] = None,
|
|
102
|
+
) -> Load2OnPattern:
|
|
103
|
+
"""Return a minimum load table dict generated from a feems model"""
|
|
104
|
+
electric_system = (
|
|
105
|
+
system if not hasattr(system, "electric_system") else system.electric_system
|
|
106
|
+
)
|
|
107
|
+
power_sources = [component for component in electric_system.power_sources]
|
|
108
|
+
if component_types is not None:
|
|
109
|
+
power_sources = [
|
|
110
|
+
component
|
|
111
|
+
for component in power_sources
|
|
112
|
+
if component.type in component_types
|
|
113
|
+
]
|
|
114
|
+
rated_power_all = [power_source.rated_power for power_source in power_sources]
|
|
115
|
+
return min_load_table_dict(
|
|
116
|
+
rated_power_all, maximum_allowed_genset_load_percentage / 100
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def min_load_table_dict(
|
|
121
|
+
rated_power_kw: List[Power_kW], max_load_factor: float
|
|
122
|
+
) -> Load2OnPattern:
|
|
123
|
+
"""Return a minimum load table dict generated from a list of genset ratings."""
|
|
124
|
+
patterns = list(itertools.product([False, True], repeat=len(rated_power_kw)))
|
|
125
|
+
assert len(patterns) == 2 ** len(rated_power_kw)
|
|
126
|
+
loads = [
|
|
127
|
+
Power_kW(
|
|
128
|
+
max_load_factor * sum(pwr for pwr, on in zip(rated_power_kw, pat) if on)
|
|
129
|
+
)
|
|
130
|
+
for pat in patterns
|
|
131
|
+
]
|
|
132
|
+
assert len(loads) == len(patterns)
|
|
133
|
+
# Sort belonging loads and patterns to obtain increasing loads.
|
|
134
|
+
loads, patterns = zip(*sorted(zip(loads, patterns))) # type: ignore[assignment]
|
|
135
|
+
assert loads[0] == Power_kW(0)
|
|
136
|
+
assert patterns[0] == (False,) * len(rated_power_kw)
|
|
137
|
+
assert patterns[-1] == (True,) * len(rated_power_kw)
|
|
138
|
+
# Use all maximum loads except the highest, as minimum loads to activate the on patterns for the next higher
|
|
139
|
+
# load, i.e. ignoring the all-off-pattern.
|
|
140
|
+
return dict(zip(loads[:-1], patterns[1:]))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class PmsLoadTableSimulationInterface(SimulationInterface):
|
|
144
|
+
def __init__(
|
|
145
|
+
self,
|
|
146
|
+
*,
|
|
147
|
+
n_bus_ties: int,
|
|
148
|
+
pms_load_table: PmsLoadTable,
|
|
149
|
+
):
|
|
150
|
+
_, on_patterns = pms_load_table.sorted_load_table()
|
|
151
|
+
self._n_power_sources = len(on_patterns[0])
|
|
152
|
+
self._n_bus_ties = n_bus_ties
|
|
153
|
+
self._pms_load_table = pms_load_table
|
|
154
|
+
assert all(
|
|
155
|
+
self._n_power_sources == len(v)
|
|
156
|
+
for v in pms_load_table.min_load2on_pattern.values()
|
|
157
|
+
), f"All PMS on_pattern lengths must match the genset count = {self._n_power_sources}"
|
|
158
|
+
|
|
159
|
+
def set_status(
|
|
160
|
+
self,
|
|
161
|
+
*,
|
|
162
|
+
power_kw_per_switchboard: Dict[SwbId, np.ndarray],
|
|
163
|
+
electric_power_system: ElectricPowerSystem,
|
|
164
|
+
time_interval_s: np.ndarray,
|
|
165
|
+
power_source_priority: EnergySourceType = EnergySourceType.LNG_DIESEL,
|
|
166
|
+
) -> None:
|
|
167
|
+
# Check that all switchboards have the same number of datapoints. If not, check that
|
|
168
|
+
# the switchboard with different number points has only one datapoint with value 0
|
|
169
|
+
# where there is no load.
|
|
170
|
+
n_datapoints = set(len(v) for v in power_kw_per_switchboard.values())
|
|
171
|
+
n_datapoint_max = max(n_datapoints)
|
|
172
|
+
if len(n_datapoints) > 1:
|
|
173
|
+
for swb_id, power_kw in power_kw_per_switchboard.items():
|
|
174
|
+
if (
|
|
175
|
+
len(power_kw) < n_datapoint_max
|
|
176
|
+
and len(power_kw) != 1
|
|
177
|
+
and power_kw[0] != 0
|
|
178
|
+
):
|
|
179
|
+
raise ValueError(
|
|
180
|
+
f"Load vector for switchboard {swb_id} has length {len(power_kw)} "
|
|
181
|
+
f"but should have length {n_datapoint_max} or 1 with 0 value."
|
|
182
|
+
)
|
|
183
|
+
n_datapoints = n_datapoint_max
|
|
184
|
+
total_power_kw = sum(power_kw_per_switchboard.values(), np.zeros(n_datapoints))
|
|
185
|
+
off_vector = np.zeros(n_datapoints)
|
|
186
|
+
on_vector = np.ones(n_datapoints)
|
|
187
|
+
equal_load_sharing_vector = np.zeros(n_datapoints)
|
|
188
|
+
number_power_sources = len(electric_power_system.power_sources)
|
|
189
|
+
on_pattern_per_datapoint = np.array(
|
|
190
|
+
self._pms_load_table.on_pattern(total_power_kw)
|
|
191
|
+
)
|
|
192
|
+
assert on_pattern_per_datapoint.shape == (n_datapoints, self._n_power_sources)
|
|
193
|
+
if self._n_bus_ties > 0:
|
|
194
|
+
electric_power_system.set_bus_tie_status_all(
|
|
195
|
+
np.ones([n_datapoints, self._n_bus_ties])
|
|
196
|
+
)
|
|
197
|
+
assert (
|
|
198
|
+
self._n_power_sources == number_power_sources
|
|
199
|
+
), f"The electric_power_system.power_sources count is different from {self._n_power_sources}"
|
|
200
|
+
for i, source in enumerate(electric_power_system.power_sources):
|
|
201
|
+
source.status = on_pattern_per_datapoint[:, i]
|
|
202
|
+
source.load_sharing_mode = equal_load_sharing_vector
|
|
203
|
+
for component in chain(electric_power_system.energy_storage):
|
|
204
|
+
component.status = off_vector
|
|
205
|
+
component.load_sharing_mode = equal_load_sharing_vector
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: RunFeemsSim
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: A library for running feems simulation
|
|
5
|
+
Home-page: https://SintefOceanEnergySystem@dev.azure.com/SintefOceanEnergySystem/FEEMSService/_git/RunFEEMSSim
|
|
6
|
+
Author: Kevin Koosup Yum
|
|
7
|
+
Author-email: kevinkoosup.yum@sintef.no
|
|
8
|
+
License: Apache Software License 2.0
|
|
9
|
+
Keywords: FEEMS,machinery system,fuel,emissions
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: pip
|
|
19
|
+
Requires-Dist: packaging
|
|
20
|
+
Requires-Dist: pandas
|
|
21
|
+
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: MachSysS
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
|
|
25
|
+
# RunFeemsSim Package
|
|
26
|
+
|
|
27
|
+
> The RunFeemsSim package is a Python package for running FEEMS simulations. It provides a simple
|
|
28
|
+
> interface for running FEEMS simulations and for visualizing the results. It also provides a basic
|
|
29
|
+
> pms model to apply for an electric power system that has a functionality of load dependent
|
|
30
|
+
> start-stop of gensets.
|
|
31
|
+
|
|
32
|
+
## Installation of the package
|
|
33
|
+
The package is distributed by the Azure Artifacts package manager. To install the package,
|
|
34
|
+
you need to install artifacts-keyring package and should have a valid Azure DevOps account.
|
|
35
|
+
```sh
|
|
36
|
+
pip install artifacts-keyring
|
|
37
|
+
```
|
|
38
|
+
Then, you need to add the package source to your pip configuration. You can do this by copying
|
|
39
|
+
the pip configuration file (pip.conf for macOS and Linux or pip.ini for Windows) to your
|
|
40
|
+
virtual environment directory or base python directory. The file should contain the following lines:
|
|
41
|
+
```sh
|
|
42
|
+
[global]
|
|
43
|
+
extra-index-url=https://pkgs.dev.azure.com/SintefOceanEnergySystem/_packaging/SintefOceanEnergySystem/pypi/simple/
|
|
44
|
+
```
|
|
45
|
+
If you already have a pip configuration file, you can add the above lines to the file. Finally,
|
|
46
|
+
you can install the package by running the following command:
|
|
47
|
+
```sh
|
|
48
|
+
pip install RunFeemsSim
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Installation of the development environment
|
|
52
|
+
For the development, one should create a virtual environment and install the package using the
|
|
53
|
+
requirements.txt file. First, create a virtual environment and activate it.
|
|
54
|
+
```sh
|
|
55
|
+
python -m venv venv
|
|
56
|
+
source venv/bin/activate
|
|
57
|
+
```
|
|
58
|
+
Then, you need to add the package source to your pip configuration. You can do this by copying
|
|
59
|
+
the pip configuration file (pip.conf for macOS and Linux or pip.ini for Windows) to your venv
|
|
60
|
+
directory or base python directory. The file should contain the following lines:
|
|
61
|
+
```sh
|
|
62
|
+
[global]
|
|
63
|
+
extra-index-url=https://pkgs.dev.azure.com/SintefOceanEnergySystem/_packaging/SintefOceanEnergySystem/pypi/simple/
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Then, install the package using the requirements.txt file.
|
|
67
|
+
```sh
|
|
68
|
+
pip install -r requirements.txt
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
CONTRIBUTING.md
|
|
2
|
+
LICENSE
|
|
3
|
+
MANIFEST.in
|
|
4
|
+
README.md
|
|
5
|
+
settings.ini
|
|
6
|
+
setup.py
|
|
7
|
+
RunFeemsSim/__init__.py
|
|
8
|
+
RunFeemsSim/_modidx.py
|
|
9
|
+
RunFeemsSim/_nbdev.py
|
|
10
|
+
RunFeemsSim/machinery_calculation.py
|
|
11
|
+
RunFeemsSim/pms_basic.py
|
|
12
|
+
RunFeemsSim.egg-info/PKG-INFO
|
|
13
|
+
RunFeemsSim.egg-info/SOURCES.txt
|
|
14
|
+
RunFeemsSim.egg-info/dependency_links.txt
|
|
15
|
+
RunFeemsSim.egg-info/not-zip-safe
|
|
16
|
+
RunFeemsSim.egg-info/requires.txt
|
|
17
|
+
RunFeemsSim.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
RunFeemsSim
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[DEFAULT]
|
|
2
|
+
host = Azure
|
|
3
|
+
lib_name = RunFeemsSim
|
|
4
|
+
user = kevinkoosup.yum@sintef.no
|
|
5
|
+
description = A library for running feems simulation
|
|
6
|
+
keywords = FEEMS, machinery system, fuel, emissions
|
|
7
|
+
author = Kevin Koosup Yum
|
|
8
|
+
author_email = kevinkoosup.yum@sintef.no
|
|
9
|
+
copyright = SINTEF
|
|
10
|
+
branch = master
|
|
11
|
+
version = 0.2.2
|
|
12
|
+
min_python = 3.10
|
|
13
|
+
audience = Developers
|
|
14
|
+
language = English
|
|
15
|
+
custom_sidebar = False
|
|
16
|
+
license = apache2
|
|
17
|
+
status = 2
|
|
18
|
+
requirements = pandas numpy MachSysS
|
|
19
|
+
nbs_path = .
|
|
20
|
+
doc_path = docs
|
|
21
|
+
recursive = False
|
|
22
|
+
doc_baseurl = /RunFeemsSim/
|
|
23
|
+
git_url = https://SintefOceanEnergySystem@dev.azure.com/SintefOceanEnergySystem/FEEMSService/_git/RunFEEMSSim
|
|
24
|
+
lib_path = RunFeemsSim
|
|
25
|
+
title = RunFeemsSim
|
|
26
|
+
doc_host = https://kevinkoosup.yum@sintef.no.github.io
|
|
27
|
+
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from pkg_resources import parse_version
|
|
2
|
+
from configparser import ConfigParser
|
|
3
|
+
import setuptools, re, sys
|
|
4
|
+
|
|
5
|
+
assert parse_version(setuptools.__version__) >= parse_version("36.2")
|
|
6
|
+
|
|
7
|
+
# note: all settings are in settings.ini; edit there, not here
|
|
8
|
+
config = ConfigParser(delimiters=["="])
|
|
9
|
+
config.read("settings.ini")
|
|
10
|
+
cfg = config["DEFAULT"]
|
|
11
|
+
|
|
12
|
+
cfg_keys = "version description keywords author author_email".split()
|
|
13
|
+
expected = (
|
|
14
|
+
cfg_keys
|
|
15
|
+
+ "lib_name user branch license status min_python audience language".split()
|
|
16
|
+
)
|
|
17
|
+
for o in expected:
|
|
18
|
+
assert o in cfg, "missing expected setting: {}".format(o)
|
|
19
|
+
setup_cfg = {o: cfg[o] for o in cfg_keys}
|
|
20
|
+
|
|
21
|
+
if len(sys.argv) > 1 and sys.argv[1] == "version":
|
|
22
|
+
print(setup_cfg["version"])
|
|
23
|
+
exit()
|
|
24
|
+
|
|
25
|
+
licenses = {
|
|
26
|
+
"apache2": (
|
|
27
|
+
"Apache Software License 2.0",
|
|
28
|
+
"OSI Approved :: Apache Software License",
|
|
29
|
+
),
|
|
30
|
+
"mit": ("MIT License", "OSI Approved :: MIT License"),
|
|
31
|
+
"gpl2": (
|
|
32
|
+
"GNU General Public License v2",
|
|
33
|
+
"OSI Approved :: GNU General Public License v2 (GPLv2)",
|
|
34
|
+
),
|
|
35
|
+
"gpl3": (
|
|
36
|
+
"GNU General Public License v3",
|
|
37
|
+
"OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
38
|
+
),
|
|
39
|
+
"bsd3": ("BSD License", "OSI Approved :: BSD License"),
|
|
40
|
+
}
|
|
41
|
+
statuses = [
|
|
42
|
+
"1 - Planning",
|
|
43
|
+
"2 - Pre-Alpha",
|
|
44
|
+
"3 - Alpha",
|
|
45
|
+
"4 - Beta",
|
|
46
|
+
"5 - Production/Stable",
|
|
47
|
+
"6 - Mature",
|
|
48
|
+
"7 - Inactive",
|
|
49
|
+
]
|
|
50
|
+
py_versions = "2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10".split()
|
|
51
|
+
|
|
52
|
+
lic = licenses.get(cfg["license"].lower(), (cfg["license"], None))
|
|
53
|
+
min_python = cfg["min_python"]
|
|
54
|
+
|
|
55
|
+
requirements = ["pip", "packaging"]
|
|
56
|
+
if cfg.get("requirements"):
|
|
57
|
+
requirements += cfg.get("requirements", "").split()
|
|
58
|
+
if cfg.get("pip_requirements"):
|
|
59
|
+
requirements += cfg.get("pip_requirements", "").split()
|
|
60
|
+
dev_requirements = (cfg.get("dev_requirements") or "").split()
|
|
61
|
+
|
|
62
|
+
long_description = open("README.md").read()
|
|
63
|
+
# 
|
|
64
|
+
for ext in ["png", "svg"]:
|
|
65
|
+
long_description = re.sub(
|
|
66
|
+
r"!\[" + ext + "\]\((.*)\)",
|
|
67
|
+
"
|
|
71
|
+
+ "/"
|
|
72
|
+
+ cfg["branch"]
|
|
73
|
+
+ "/\\1)",
|
|
74
|
+
long_description,
|
|
75
|
+
)
|
|
76
|
+
long_description = re.sub(
|
|
77
|
+
r"src=\"(.*)\." + ext + '"',
|
|
78
|
+
'src="https://raw.githubusercontent.com/{}/{}'.format(
|
|
79
|
+
cfg["user"], cfg["lib_name"]
|
|
80
|
+
)
|
|
81
|
+
+ "/"
|
|
82
|
+
+ cfg["branch"]
|
|
83
|
+
+ "/\\1."
|
|
84
|
+
+ ext
|
|
85
|
+
+ '"',
|
|
86
|
+
long_description,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
setuptools.setup(
|
|
90
|
+
name=cfg["lib_name"],
|
|
91
|
+
license=lic[0],
|
|
92
|
+
classifiers=[
|
|
93
|
+
"Development Status :: " + statuses[int(cfg["status"])],
|
|
94
|
+
"Intended Audience :: " + cfg["audience"].title(),
|
|
95
|
+
"Natural Language :: " + cfg["language"].title(),
|
|
96
|
+
]
|
|
97
|
+
+ [
|
|
98
|
+
"Programming Language :: Python :: " + o
|
|
99
|
+
for o in py_versions[py_versions.index(min_python) :]
|
|
100
|
+
]
|
|
101
|
+
+ (["License :: " + lic[1]] if lic[1] else []),
|
|
102
|
+
url=cfg["git_url"],
|
|
103
|
+
packages=setuptools.find_packages(),
|
|
104
|
+
include_package_data=True,
|
|
105
|
+
install_requires=requirements,
|
|
106
|
+
extras_require={"dev": dev_requirements},
|
|
107
|
+
python_requires=">=" + cfg["min_python"],
|
|
108
|
+
long_description=long_description,
|
|
109
|
+
long_description_content_type="text/markdown",
|
|
110
|
+
zip_safe=False,
|
|
111
|
+
entry_points={"console_scripts": cfg.get("console_scripts", "").split()},
|
|
112
|
+
**setup_cfg
|
|
113
|
+
)
|