zen-garden 1.7.5__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.
- zen_garden-1.7.5/LICENSE.txt +21 -0
- zen_garden-1.7.5/PKG-INFO +106 -0
- zen_garden-1.7.5/README.md +67 -0
- zen_garden-1.7.5/pyproject.toml +55 -0
- zen_garden-1.7.5/zen_garden/__init__.py +11 -0
- zen_garden-1.7.5/zen_garden/__main__.py +83 -0
- zen_garden-1.7.5/zen_garden/_internal.py +103 -0
- zen_garden-1.7.5/zen_garden/model/__init__.py +1 -0
- zen_garden-1.7.5/zen_garden/model/default_config.py +178 -0
- zen_garden-1.7.5/zen_garden/model/objects/__init__.py +2 -0
- zen_garden-1.7.5/zen_garden/model/objects/carrier/__init__.py +13 -0
- zen_garden-1.7.5/zen_garden/model/objects/carrier/carrier.py +486 -0
- zen_garden-1.7.5/zen_garden/model/objects/component.py +1331 -0
- zen_garden-1.7.5/zen_garden/model/objects/element.py +397 -0
- zen_garden-1.7.5/zen_garden/model/objects/energy_system.py +557 -0
- zen_garden-1.7.5/zen_garden/model/objects/technology/__init__.py +13 -0
- zen_garden-1.7.5/zen_garden/model/objects/technology/conversion_technology.py +572 -0
- zen_garden-1.7.5/zen_garden/model/objects/technology/retrofitting_technology.py +142 -0
- zen_garden-1.7.5/zen_garden/model/objects/technology/storage_technology.py +445 -0
- zen_garden-1.7.5/zen_garden/model/objects/technology/technology.py +1003 -0
- zen_garden-1.7.5/zen_garden/model/objects/technology/transport_technology.py +396 -0
- zen_garden-1.7.5/zen_garden/model/objects/time_steps.py +266 -0
- zen_garden-1.7.5/zen_garden/model/optimization_setup.py +709 -0
- zen_garden-1.7.5/zen_garden/postprocess/.gitkeep +1 -0
- zen_garden-1.7.5/zen_garden/postprocess/__init__.py +0 -0
- zen_garden-1.7.5/zen_garden/postprocess/comparisons.py +342 -0
- zen_garden-1.7.5/zen_garden/postprocess/postprocess.py +507 -0
- zen_garden-1.7.5/zen_garden/postprocess/results/__init__.py +3 -0
- zen_garden-1.7.5/zen_garden/postprocess/results/multi_hdf_loader.py +546 -0
- zen_garden-1.7.5/zen_garden/postprocess/results/results.py +681 -0
- zen_garden-1.7.5/zen_garden/postprocess/results/solution_loader.py +223 -0
- zen_garden-1.7.5/zen_garden/preprocess/__init__.py +0 -0
- zen_garden-1.7.5/zen_garden/preprocess/extract_input_data.py +847 -0
- zen_garden-1.7.5/zen_garden/preprocess/time_series_aggregation.py +425 -0
- zen_garden-1.7.5/zen_garden/preprocess/unit_handling.py +1026 -0
- zen_garden-1.7.5/zen_garden/utils.py +1474 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Reliability and Risk Engineering, ETH Zurich
|
|
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,106 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: zen_garden
|
|
3
|
+
Version: 1.7.5
|
|
4
|
+
Summary: ZEN-garden is an optimization model of energy systems and value chains.
|
|
5
|
+
Author-email: Jacob Mannhardt <jmannhardt@ethz.ch>, Alissa Ganter <aganter@ethz.ch>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: xarray
|
|
9
|
+
Requires-Dist: cython
|
|
10
|
+
Requires-Dist: numpy<=1.26.4
|
|
11
|
+
Requires-Dist: pandas>=2.2
|
|
12
|
+
Requires-Dist: scipy
|
|
13
|
+
Requires-Dist: pint
|
|
14
|
+
Requires-Dist: tables
|
|
15
|
+
Requires-Dist: pydantic
|
|
16
|
+
Requires-Dist: tsam
|
|
17
|
+
Requires-Dist: h5py
|
|
18
|
+
Requires-Dist: filelock
|
|
19
|
+
Requires-Dist: ordered-set
|
|
20
|
+
Requires-Dist: pyogrio
|
|
21
|
+
Requires-Dist: psutil
|
|
22
|
+
Requires-Dist: linopy<=0.3.10
|
|
23
|
+
Requires-Dist: pytest ; extra == "dev"
|
|
24
|
+
Requires-Dist: coverage ; extra == "dev"
|
|
25
|
+
Requires-Dist: sphinx==7.3.7 ; extra == "docs"
|
|
26
|
+
Requires-Dist: myst-parser==3.0.1 ; extra == "docs"
|
|
27
|
+
Requires-Dist: sphinx-book-theme==1.1.3 ; extra == "docs"
|
|
28
|
+
Requires-Dist: pydata-sphinx-theme==0.15.4 ; extra == "docs"
|
|
29
|
+
Requires-Dist: sphinx-reredirects==0.1.4 ; extra == "docs"
|
|
30
|
+
Requires-Dist: nbsphinx==0.9.4 ; extra == "docs"
|
|
31
|
+
Requires-Dist: nbsphinx-link==1.3.0 ; extra == "docs"
|
|
32
|
+
Requires-Dist: gurobipy ; extra == "gurobipy"
|
|
33
|
+
Project-URL: Documentation, https://zen-garden.readthedocs.io/en/latest/
|
|
34
|
+
Project-URL: Homepage, https://github.com/ZEN-universe/ZEN-garden
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Provides-Extra: docs
|
|
37
|
+
Provides-Extra: gurobipy
|
|
38
|
+
|
|
39
|
+
# ZEN-garden
|
|
40
|
+
|
|
41
|
+
[](https://github.com/ZEN-universe/ZEN-garden/releases)
|
|
42
|
+
[](https://github.com/ZEN-universe/ZEN-garden/tags)
|
|
43
|
+
[](https://github.com/ZEN-universe/ZEN-garden/forks)
|
|
44
|
+
|
|
45
|
+
[](https://github.com/ZEN-universe/ZEN-garden/actions)
|
|
46
|
+
[](https://github.com/ZEN-universe/ZEN-garden/actions)
|
|
47
|
+
|
|
48
|
+
[](https://zen-garden.readthedocs.io/en/latest/index.html)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
[//]: # (<table><tr><td valign="center"> )
|
|
52
|
+
|
|
53
|
+
[//]: # ( <img align="left" height="25px" src="https://github.com/RRE-ETH/ZEN-garden/actions/workflows/pytest_with_conda.yml/badge.svg?branch=development"> )
|
|
54
|
+
|
|
55
|
+
[//]: # ( <img align="left" height="25px" src="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/jafluri/5d0d79e86182cd9ccd785d824b1f9ac7/raw/zen_coverage.json">)
|
|
56
|
+
|
|
57
|
+
[//]: # ( <b> (Development Branch) </b>)
|
|
58
|
+
|
|
59
|
+
[//]: # (</td></tr></table>)
|
|
60
|
+
|
|
61
|
+
[//]: # (<hr style="height: 5px; background-color: black;">)
|
|
62
|
+
|
|
63
|
+
<img src="https://github.com/ZEN-universe/ZEN-garden/assets/114185605/d6a9aca9-74b0-4a82-8295-43e6a78b8450" alt="drawing" width="200"/>
|
|
64
|
+
|
|
65
|
+
Welcome to the ZEN-garden! ZEN-garden is an optimization model of energy systems and value chains.
|
|
66
|
+
It is currently used to model the electricity system, hydrogen value chains, and carbon capture, storage and utilization (CCUS) value chains.
|
|
67
|
+
However, it is designed to be modular and flexible, and can be extended to model other types of energy systems, value chains or other network-based systems.
|
|
68
|
+
|
|
69
|
+
ZEN-garden is developed by the [Reliability and Risk Engineering Laboratory](https://www.rre.ethz.ch/) at ETH Zurich.
|
|
70
|
+
<hr style="height: 5px; background-color: black;">
|
|
71
|
+
|
|
72
|
+
## Documentation
|
|
73
|
+
Please refer to the documentation of the ZEN-garden framework [on Read-the-Docs](https://zen-garden.readthedocs.io/en/latest/).
|
|
74
|
+
To get started with ZEN-garden, you can follow the instructions in the [installation guide](https://zen-garden.readthedocs.io/en/latest/files/installation.html).
|
|
75
|
+
|
|
76
|
+
In the file `documentation/how_to_ZEN-garden.md`, you can find additional information on how to use the framework.
|
|
77
|
+
The `documentation/dataset_creation_tutorial.md` file contains a tutorial on how to create a simple dataset for the framework.
|
|
78
|
+
Additionally, example datasets are available in the `dataset_examples` folder.
|
|
79
|
+
|
|
80
|
+
More in-depth manuals are available in the [discussions forum](https://github.com/ZEN-universe/ZEN-garden/discussions) of our repo.
|
|
81
|
+
|
|
82
|
+
## News
|
|
83
|
+
Review recent modifications outlined in the [changelog](https://github.com/ZEN-universe/ZEN-garden/blob/main/CHANGELOG.md).
|
|
84
|
+
|
|
85
|
+
## Citing ZEN-garden
|
|
86
|
+
If you use ZEN-garden for research please cite
|
|
87
|
+
|
|
88
|
+
Ganter Alissa, Gabrielli Paolo, Sansavini, Giovanni (2024).
|
|
89
|
+
Near-term infrastructure rollout and investment strategies for net-zero hydrogen supply chains
|
|
90
|
+
2024. https://doi.org/10.1016/j.rser.2024.114314
|
|
91
|
+
|
|
92
|
+
and use the following BibTeX:
|
|
93
|
+
```
|
|
94
|
+
@article{GANTER2024114314,
|
|
95
|
+
author = {Alissa Ganter and Paolo Gabrielli and Giovanni Sansavini}
|
|
96
|
+
title = {Near-term infrastructure rollout and investment strategies for net-zero hydrogen supply chains},
|
|
97
|
+
journal = {Renewable and Sustainable Energy Reviews},
|
|
98
|
+
volume = {194},
|
|
99
|
+
pages = {114314},
|
|
100
|
+
year = {2024},
|
|
101
|
+
issn = {1364-0321},
|
|
102
|
+
doi = {https://doi.org/10.1016/j.rser.2024.114314},
|
|
103
|
+
url = {https://www.sciencedirect.com/science/article/pii/S1364032124000376},
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# ZEN-garden
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ZEN-universe/ZEN-garden/releases)
|
|
4
|
+
[](https://github.com/ZEN-universe/ZEN-garden/tags)
|
|
5
|
+
[](https://github.com/ZEN-universe/ZEN-garden/forks)
|
|
6
|
+
|
|
7
|
+
[](https://github.com/ZEN-universe/ZEN-garden/actions)
|
|
8
|
+
[](https://github.com/ZEN-universe/ZEN-garden/actions)
|
|
9
|
+
|
|
10
|
+
[](https://zen-garden.readthedocs.io/en/latest/index.html)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
[//]: # (<table><tr><td valign="center"> )
|
|
14
|
+
|
|
15
|
+
[//]: # ( <img align="left" height="25px" src="https://github.com/RRE-ETH/ZEN-garden/actions/workflows/pytest_with_conda.yml/badge.svg?branch=development"> )
|
|
16
|
+
|
|
17
|
+
[//]: # ( <img align="left" height="25px" src="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/jafluri/5d0d79e86182cd9ccd785d824b1f9ac7/raw/zen_coverage.json">)
|
|
18
|
+
|
|
19
|
+
[//]: # ( <b> (Development Branch) </b>)
|
|
20
|
+
|
|
21
|
+
[//]: # (</td></tr></table>)
|
|
22
|
+
|
|
23
|
+
[//]: # (<hr style="height: 5px; background-color: black;">)
|
|
24
|
+
|
|
25
|
+
<img src="https://github.com/ZEN-universe/ZEN-garden/assets/114185605/d6a9aca9-74b0-4a82-8295-43e6a78b8450" alt="drawing" width="200"/>
|
|
26
|
+
|
|
27
|
+
Welcome to the ZEN-garden! ZEN-garden is an optimization model of energy systems and value chains.
|
|
28
|
+
It is currently used to model the electricity system, hydrogen value chains, and carbon capture, storage and utilization (CCUS) value chains.
|
|
29
|
+
However, it is designed to be modular and flexible, and can be extended to model other types of energy systems, value chains or other network-based systems.
|
|
30
|
+
|
|
31
|
+
ZEN-garden is developed by the [Reliability and Risk Engineering Laboratory](https://www.rre.ethz.ch/) at ETH Zurich.
|
|
32
|
+
<hr style="height: 5px; background-color: black;">
|
|
33
|
+
|
|
34
|
+
## Documentation
|
|
35
|
+
Please refer to the documentation of the ZEN-garden framework [on Read-the-Docs](https://zen-garden.readthedocs.io/en/latest/).
|
|
36
|
+
To get started with ZEN-garden, you can follow the instructions in the [installation guide](https://zen-garden.readthedocs.io/en/latest/files/installation.html).
|
|
37
|
+
|
|
38
|
+
In the file `documentation/how_to_ZEN-garden.md`, you can find additional information on how to use the framework.
|
|
39
|
+
The `documentation/dataset_creation_tutorial.md` file contains a tutorial on how to create a simple dataset for the framework.
|
|
40
|
+
Additionally, example datasets are available in the `dataset_examples` folder.
|
|
41
|
+
|
|
42
|
+
More in-depth manuals are available in the [discussions forum](https://github.com/ZEN-universe/ZEN-garden/discussions) of our repo.
|
|
43
|
+
|
|
44
|
+
## News
|
|
45
|
+
Review recent modifications outlined in the [changelog](https://github.com/ZEN-universe/ZEN-garden/blob/main/CHANGELOG.md).
|
|
46
|
+
|
|
47
|
+
## Citing ZEN-garden
|
|
48
|
+
If you use ZEN-garden for research please cite
|
|
49
|
+
|
|
50
|
+
Ganter Alissa, Gabrielli Paolo, Sansavini, Giovanni (2024).
|
|
51
|
+
Near-term infrastructure rollout and investment strategies for net-zero hydrogen supply chains
|
|
52
|
+
2024. https://doi.org/10.1016/j.rser.2024.114314
|
|
53
|
+
|
|
54
|
+
and use the following BibTeX:
|
|
55
|
+
```
|
|
56
|
+
@article{GANTER2024114314,
|
|
57
|
+
author = {Alissa Ganter and Paolo Gabrielli and Giovanni Sansavini}
|
|
58
|
+
title = {Near-term infrastructure rollout and investment strategies for net-zero hydrogen supply chains},
|
|
59
|
+
journal = {Renewable and Sustainable Energy Reviews},
|
|
60
|
+
volume = {194},
|
|
61
|
+
pages = {114314},
|
|
62
|
+
year = {2024},
|
|
63
|
+
issn = {1364-0321},
|
|
64
|
+
doi = {https://doi.org/10.1016/j.rser.2024.114314},
|
|
65
|
+
url = {https://www.sciencedirect.com/science/article/pii/S1364032124000376},
|
|
66
|
+
}
|
|
67
|
+
```
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["flit_core >=3.2,<4"]
|
|
3
|
+
build-backend = "flit_core.buildapi"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "zen_garden"
|
|
7
|
+
authors = [
|
|
8
|
+
{name = "Jacob Mannhardt", email = "jmannhardt@ethz.ch"},
|
|
9
|
+
{name = "Alissa Ganter", email = "aganter@ethz.ch"}
|
|
10
|
+
]
|
|
11
|
+
version = "1.7.5"
|
|
12
|
+
requires-python= ">=3.10"
|
|
13
|
+
description="ZEN-garden is an optimization model of energy systems and value chains."
|
|
14
|
+
readme = "README.md"
|
|
15
|
+
license = { file = "LICENSE.txt" }
|
|
16
|
+
|
|
17
|
+
dependencies = [
|
|
18
|
+
"xarray",
|
|
19
|
+
"cython",
|
|
20
|
+
"numpy<=1.26.4",
|
|
21
|
+
"pandas>=2.2",
|
|
22
|
+
"scipy",
|
|
23
|
+
"pint",
|
|
24
|
+
"tables",
|
|
25
|
+
"pydantic",
|
|
26
|
+
"tsam",
|
|
27
|
+
"h5py",
|
|
28
|
+
"filelock",
|
|
29
|
+
"ordered-set",
|
|
30
|
+
"pyogrio",
|
|
31
|
+
"psutil",
|
|
32
|
+
"linopy<=0.3.10",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
docs = [
|
|
37
|
+
"sphinx==7.3.7",
|
|
38
|
+
"myst-parser==3.0.1",
|
|
39
|
+
"sphinx-book-theme==1.1.3",
|
|
40
|
+
"pydata-sphinx-theme==0.15.4",
|
|
41
|
+
"sphinx-reredirects==0.1.4",
|
|
42
|
+
"nbsphinx==0.9.4",
|
|
43
|
+
"nbsphinx-link==1.3.0",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
dev = [
|
|
47
|
+
"pytest",
|
|
48
|
+
"coverage",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
gurobipy = ["gurobipy"]
|
|
52
|
+
|
|
53
|
+
[project.urls]
|
|
54
|
+
Homepage = "https://github.com/ZEN-universe/ZEN-garden"
|
|
55
|
+
Documentation = "https://zen-garden.readthedocs.io/en/latest/"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from . import model
|
|
2
|
+
from . import postprocess
|
|
3
|
+
from . import preprocess
|
|
4
|
+
from .utils import get_inheritors
|
|
5
|
+
|
|
6
|
+
from .model.objects.element import Element
|
|
7
|
+
from .model.optimization_setup import OptimizationSetup
|
|
8
|
+
|
|
9
|
+
# set the element classes of the EnergySystem class
|
|
10
|
+
inheritors = get_inheritors(Element)
|
|
11
|
+
OptimizationSetup.dict_element_classes.update({klass.__name__: klass for klass in inheritors})
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:Title: ZEN-GARDEN
|
|
3
|
+
:Created: September-2022
|
|
4
|
+
:Authors: Janis Fluri (janis.fluri@id.ethz.ch),
|
|
5
|
+
Alissa Ganter (aganter@ethz.ch),
|
|
6
|
+
Jacob Mannhardt (jmannhardt@ethz.ch)
|
|
7
|
+
:Organization: Laboratory of Reliability and Risk Engineering, ETH Zurich
|
|
8
|
+
|
|
9
|
+
Compilation of the optimization problem.
|
|
10
|
+
"""
|
|
11
|
+
from ._internal import main
|
|
12
|
+
import importlib.util
|
|
13
|
+
import argparse
|
|
14
|
+
import sys
|
|
15
|
+
import os
|
|
16
|
+
import zen_garden.model.default_config as default_config
|
|
17
|
+
import json
|
|
18
|
+
from zen_garden.utils import copy_dataset_example
|
|
19
|
+
|
|
20
|
+
def run_module(args=None):
|
|
21
|
+
"""
|
|
22
|
+
Runs the main function of ZEN-Garden
|
|
23
|
+
|
|
24
|
+
:param args: Arguments to parse
|
|
25
|
+
"""
|
|
26
|
+
if args is None:
|
|
27
|
+
args = sys.argv[1:]
|
|
28
|
+
|
|
29
|
+
# parse the args
|
|
30
|
+
description = "Run ZEN garden with a given config file. Per default, the config file will be read out from the " \
|
|
31
|
+
"current working directory. You can specify a config file with the --config argument. However, " \
|
|
32
|
+
"note that the output directory will always be the current working directory, independent of the " \
|
|
33
|
+
"dataset specified in the config file."
|
|
34
|
+
parser = argparse.ArgumentParser(description=description, add_help=True, usage="usage: python -m zen_garden [-h] [--config CONFIG] [--dataset DATASET] [--job_index JOB_INDEX] [--job_index_var JOB_INDEX_VAR] [--example EXAMPLE]")
|
|
35
|
+
# TODO make json config default
|
|
36
|
+
parser.add_argument("--config", required=False, type=str, default="./config.py", help="The config file used to run the pipeline, "
|
|
37
|
+
"defaults to config.py in the current directory.")
|
|
38
|
+
parser.add_argument("--dataset", required=False, type=str, default=None, help="Path to the dataset used for the run. IMPORTANT: This will overwrite the "
|
|
39
|
+
"config.analysis['dataset'] attribute of the config file!")
|
|
40
|
+
parser.add_argument("--job_index", required=False, type=str, default=None, help="A comma separated list (no spaces) of indices of the scenarios to run, if None, all scenarios are run in sequence")
|
|
41
|
+
parser.add_argument("--job_index_var", required=False, type=str, default="SLURM_ARRAY_TASK_ID", help="Try to read out the job index from the environment variable specified here. "
|
|
42
|
+
"If both --job_index and --job_index_var are specified, --job_index will be used.")
|
|
43
|
+
parser.add_argument("--example", required=False, type=str, default=None, help="Run an example scenario. The argument should be the name of a dataset example in documentation/dataset_examples. This command will copy the dataset and the config to the current folder and run the example.")
|
|
44
|
+
|
|
45
|
+
args = parser.parse_args(args)
|
|
46
|
+
|
|
47
|
+
# copy example dataset and run example #TODO so far doesn't work because dataset_examples are not part of the package but outside
|
|
48
|
+
if args.example is not None:
|
|
49
|
+
example_path_cwd,config_path_cwd = copy_dataset_example(args.example)
|
|
50
|
+
args.dataset = example_path_cwd
|
|
51
|
+
args.config = config_path_cwd
|
|
52
|
+
|
|
53
|
+
if not os.path.exists(args.config):
|
|
54
|
+
args.config = args.config.replace(".py", ".json")
|
|
55
|
+
|
|
56
|
+
# change working directory to the directory of the config file
|
|
57
|
+
config_path, config_file = os.path.split(args.config)
|
|
58
|
+
os.chdir(config_path)
|
|
59
|
+
### import the config
|
|
60
|
+
if config_file.endswith(".py"):
|
|
61
|
+
spec = importlib.util.spec_from_file_location("module", config_file)
|
|
62
|
+
module = importlib.util.module_from_spec(spec)
|
|
63
|
+
spec.loader.exec_module(module)
|
|
64
|
+
config = module.config
|
|
65
|
+
else:
|
|
66
|
+
with open(args.config, "r") as f:
|
|
67
|
+
config = default_config.Config(**json.load(f))
|
|
68
|
+
|
|
69
|
+
### get the job index
|
|
70
|
+
job_index = args.job_index
|
|
71
|
+
if job_index is None:
|
|
72
|
+
if (job_index := os.environ.get(args.job_index_var)) is not None:
|
|
73
|
+
job_index = int(job_index)
|
|
74
|
+
else:
|
|
75
|
+
job_index = [int(i) for i in job_index.split(",")]
|
|
76
|
+
|
|
77
|
+
### run
|
|
78
|
+
main(config=config, dataset_path=args.dataset, job_index=job_index)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
|
|
83
|
+
run_module()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:Title: ZEN-GARDEN
|
|
3
|
+
:Created: October-2021
|
|
4
|
+
:Authors: Alissa Ganter (aganter@ethz.ch),
|
|
5
|
+
Jacob Mannhardt (jmannhardt@ethz.ch)
|
|
6
|
+
:Organization: Laboratory of Reliability and Risk Engineering, ETH Zurich
|
|
7
|
+
|
|
8
|
+
Compilation of the optimization problem.
|
|
9
|
+
"""
|
|
10
|
+
import cProfile
|
|
11
|
+
import importlib.util
|
|
12
|
+
import logging
|
|
13
|
+
import os
|
|
14
|
+
from collections import defaultdict
|
|
15
|
+
import importlib
|
|
16
|
+
|
|
17
|
+
from .model.optimization_setup import OptimizationSetup
|
|
18
|
+
from .postprocess.postprocess import Postprocess
|
|
19
|
+
from .utils import setup_logger, InputDataChecks, StringUtils, ScenarioUtils, OptimizationError
|
|
20
|
+
from .preprocess.unit_handling import Scaling
|
|
21
|
+
|
|
22
|
+
# we setup the logger here
|
|
23
|
+
setup_logger()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main(config, dataset_path=None, job_index=None):
|
|
27
|
+
"""
|
|
28
|
+
This function runs ZEN garden,
|
|
29
|
+
it is executed in the __main__.py script
|
|
30
|
+
|
|
31
|
+
:param config: A config instance used for the run
|
|
32
|
+
:param dataset_path: If not None, used to overwrite the config.analysis["dataset"]
|
|
33
|
+
:param job_index: The index of the scenario to run or a list of indices, if None, all scenarios are run in sequence
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# print the version
|
|
37
|
+
version = importlib.metadata.version("zen-garden")
|
|
38
|
+
logging.info(f"Running ZEN-garden version: {version}")
|
|
39
|
+
|
|
40
|
+
# prevent double printing
|
|
41
|
+
logging.propagate = False
|
|
42
|
+
|
|
43
|
+
# overwrite the path if necessary
|
|
44
|
+
if dataset_path is not None:
|
|
45
|
+
# logging.info(f"Overwriting dataset to: {dataset_path}")
|
|
46
|
+
config.analysis["dataset"] = dataset_path
|
|
47
|
+
logging.info(f"Optimizing for dataset {config.analysis['dataset']}")
|
|
48
|
+
# get the abs path to avoid working dir stuff
|
|
49
|
+
config.analysis["dataset"] = os.path.abspath(config.analysis['dataset'])
|
|
50
|
+
config.analysis["folder_output"] = os.path.abspath(config.analysis['folder_output'])
|
|
51
|
+
|
|
52
|
+
### SYSTEM CONFIGURATION
|
|
53
|
+
input_data_checks = InputDataChecks(config=config, optimization_setup=None)
|
|
54
|
+
input_data_checks.check_dataset()
|
|
55
|
+
input_data_checks.read_system_file(config)
|
|
56
|
+
input_data_checks.check_technology_selections()
|
|
57
|
+
input_data_checks.check_year_definitions()
|
|
58
|
+
# overwrite default system and scenario dictionaries
|
|
59
|
+
scenarios,elements = ScenarioUtils.get_scenarios(config,job_index)
|
|
60
|
+
# get the name of the dataset
|
|
61
|
+
model_name, out_folder = StringUtils.setup_model_folder(config.analysis,config.system)
|
|
62
|
+
# clean sub-scenarios if necessary
|
|
63
|
+
ScenarioUtils.clean_scenario_folder(config,out_folder)
|
|
64
|
+
### ITERATE THROUGH SCENARIOS
|
|
65
|
+
for scenario, scenario_dict in zip(scenarios, elements):
|
|
66
|
+
# FORMULATE THE OPTIMIZATION PROBLEM
|
|
67
|
+
# add the scenario_dict and read input data
|
|
68
|
+
optimization_setup = OptimizationSetup(config, scenario_dict=scenario_dict, input_data_checks=input_data_checks)
|
|
69
|
+
# get rolling horizon years
|
|
70
|
+
steps_horizon = optimization_setup.get_optimization_horizon()
|
|
71
|
+
# iterate through horizon steps
|
|
72
|
+
for step in steps_horizon:
|
|
73
|
+
StringUtils.print_optimization_progress(scenario,steps_horizon,step,system=config.system)
|
|
74
|
+
# overwrite time indices
|
|
75
|
+
optimization_setup.overwrite_time_indices(step)
|
|
76
|
+
# create optimization problem
|
|
77
|
+
optimization_setup.construct_optimization_problem()
|
|
78
|
+
#TODO scaling algorithm
|
|
79
|
+
if config.solver["use_scaling"]:
|
|
80
|
+
optimization_setup.scaling.run_scaling()
|
|
81
|
+
else:
|
|
82
|
+
optimization_setup.scaling.analyze_numerics()
|
|
83
|
+
# SOLVE THE OPTIMIZATION PROBLEM
|
|
84
|
+
optimization_setup.solve()
|
|
85
|
+
# break if infeasible
|
|
86
|
+
if not optimization_setup.optimality:
|
|
87
|
+
# write IIS
|
|
88
|
+
optimization_setup.write_IIS()
|
|
89
|
+
raise OptimizationError(optimization_setup.model.termination_condition)
|
|
90
|
+
if config.solver["use_scaling"]:
|
|
91
|
+
optimization_setup.scaling.re_scale()
|
|
92
|
+
# save new capacity additions and cumulative carbon emissions for next time step
|
|
93
|
+
optimization_setup.add_results_of_optimization_step(step)
|
|
94
|
+
# EVALUATE RESULTS
|
|
95
|
+
# create scenario name, subfolder and param_map for postprocessing
|
|
96
|
+
scenario_name, subfolder, param_map = StringUtils.generate_folder_path(
|
|
97
|
+
config = config,scenario = scenario,scenario_dict=scenario_dict,steps_horizon=steps_horizon,step=step
|
|
98
|
+
)
|
|
99
|
+
# write results
|
|
100
|
+
Postprocess(optimization_setup, scenarios=config.scenarios, subfolder=subfolder,
|
|
101
|
+
model_name=model_name, scenario_name=scenario_name, param_map=param_map)
|
|
102
|
+
logging.info("--- Optimization finished ---")
|
|
103
|
+
return optimization_setup
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .default_config import Config
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""
|
|
2
|
+
:Title: ZEN-GARDEN
|
|
3
|
+
:Created: October-2021
|
|
4
|
+
:Authors: Alissa Ganter (aganter@ethz.ch)
|
|
5
|
+
:Organization: Laboratory of Reliability and Risk Engineering, ETH Zurich
|
|
6
|
+
|
|
7
|
+
Default configuration. Changes from the default values are specified in config.py (folders data/tests) and system.py (individual datasets)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, ConfigDict
|
|
11
|
+
from typing import Any, Optional, Union
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Subscriptable(BaseModel, extra="allow"):
|
|
15
|
+
def __getitem__(self, __name: str) -> Any:
|
|
16
|
+
return getattr(self, __name)
|
|
17
|
+
|
|
18
|
+
def __setitem__(self, __name: str, __value: Any) -> None:
|
|
19
|
+
setattr(self, __name, __value)
|
|
20
|
+
|
|
21
|
+
def keys(self) -> Any:
|
|
22
|
+
return self.model_dump().keys()
|
|
23
|
+
|
|
24
|
+
def update(self, new_values: dict[Any, Any]) -> None:
|
|
25
|
+
for key, val in new_values.items():
|
|
26
|
+
if isinstance(val, dict):
|
|
27
|
+
getattr(self, key).update(val)
|
|
28
|
+
else:
|
|
29
|
+
setattr(self, key, val)
|
|
30
|
+
|
|
31
|
+
def items(self) -> Any:
|
|
32
|
+
return self.model_dump().items()
|
|
33
|
+
|
|
34
|
+
def values(self) -> Any:
|
|
35
|
+
return self.model_dump().values()
|
|
36
|
+
|
|
37
|
+
def __iter__(self) -> Any:
|
|
38
|
+
self.fix_keys = list(self.model_dump().keys())
|
|
39
|
+
self.i = 0
|
|
40
|
+
return self
|
|
41
|
+
|
|
42
|
+
def __next__(self) -> Any:
|
|
43
|
+
if self.i < len(self.fix_keys):
|
|
44
|
+
ans = self.fix_keys[self.i]
|
|
45
|
+
self.i += 1
|
|
46
|
+
return ans
|
|
47
|
+
else:
|
|
48
|
+
del self.i
|
|
49
|
+
del self.fix_keys
|
|
50
|
+
raise StopIteration
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Subsets(Subscriptable):
|
|
54
|
+
set_carriers: list[str] = []
|
|
55
|
+
set_technologies: dict[str, list[str]] | list[str] = {
|
|
56
|
+
"set_conversion_technologies": ["set_retrofitting_technologies"],
|
|
57
|
+
"set_transport_technologies": [],
|
|
58
|
+
"set_storage_technologies": [],
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class HeaderDataInputs(Subscriptable):
|
|
63
|
+
set_nodes: str = "node"
|
|
64
|
+
set_edges: str = "edge"
|
|
65
|
+
set_location: str = "location"
|
|
66
|
+
set_time_steps: str = "time" # IMPORTANT: time must be unique
|
|
67
|
+
set_time_steps_operation: str = "time_operation"
|
|
68
|
+
set_time_steps_storage_level: str = "time_storage_level"
|
|
69
|
+
set_time_steps_yearly: str = "year" # IMPORTANT: year must be unique
|
|
70
|
+
set_time_steps_yearly_entire_horizon: str = "year_entire_horizon"
|
|
71
|
+
set_carriers: str = "carrier"
|
|
72
|
+
set_input_carriers: str = "carrier"
|
|
73
|
+
set_output_carriers: str = "carrier"
|
|
74
|
+
set_time_steps_storage: str = "time_storage_level"
|
|
75
|
+
set_dependent_carriers: str = "carrier"
|
|
76
|
+
set_elements: str = "element"
|
|
77
|
+
set_conversion_technologies: str = "technology"
|
|
78
|
+
set_transport_technologies: str = "technology"
|
|
79
|
+
set_transport_technologies_loss_exponential: str = "technology"
|
|
80
|
+
set_storage_technologies: str = "technology"
|
|
81
|
+
set_technologies: str = "technology"
|
|
82
|
+
set_technologies_existing: str = "technology_existing"
|
|
83
|
+
set_capacity_types: str = "capacity_type"
|
|
84
|
+
|
|
85
|
+
class System(Subscriptable):
|
|
86
|
+
model_config = ConfigDict(extra="allow")
|
|
87
|
+
set_carriers: list[str] = []
|
|
88
|
+
set_capacity_types: list[str] = ["power", "energy"]
|
|
89
|
+
set_conversion_technologies: list[str] = []
|
|
90
|
+
set_storage_technologies: list[str] = []
|
|
91
|
+
set_retrofitting_technologies: list[str] = []
|
|
92
|
+
storage_periodicity: bool = True
|
|
93
|
+
set_transport_technologies: list[str] = []
|
|
94
|
+
set_transport_technologies_loss_exponential: list[str] = []
|
|
95
|
+
double_capex_transport: bool = False
|
|
96
|
+
set_nodes: list[str] = []
|
|
97
|
+
exclude_parameters_from_TSA: bool = True
|
|
98
|
+
conduct_scenario_analysis: bool = False
|
|
99
|
+
run_default_scenario: bool = True
|
|
100
|
+
clean_sub_scenarios: bool = False
|
|
101
|
+
total_hours_per_year: int = 8760
|
|
102
|
+
knowledge_depreciation_rate: float = 0.1
|
|
103
|
+
enforce_selfish_behavior: bool = False
|
|
104
|
+
reference_year: int = 2023
|
|
105
|
+
unaggregated_time_steps_per_year: int = 8760
|
|
106
|
+
aggregated_time_steps_per_year: int = 10
|
|
107
|
+
conduct_time_series_aggregation: bool = True
|
|
108
|
+
optimized_years: int = 3
|
|
109
|
+
interval_between_years: int = 1
|
|
110
|
+
use_rolling_horizon: bool = False
|
|
111
|
+
years_in_rolling_horizon: int = 5
|
|
112
|
+
years_in_decision_horizon: int = 1
|
|
113
|
+
use_capacities_existing: bool = True
|
|
114
|
+
|
|
115
|
+
class SolverOptions(Subscriptable):
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
class Solver(Subscriptable):
|
|
119
|
+
name: str = "highs"
|
|
120
|
+
solver_options: SolverOptions = SolverOptions()
|
|
121
|
+
check_unit_consistency: bool = True
|
|
122
|
+
solver_dir: str = ".//outputs//solver_files"
|
|
123
|
+
keep_files: bool = False
|
|
124
|
+
io_api: str = "lp"
|
|
125
|
+
add_duals: bool = False
|
|
126
|
+
recommend_base_units: bool = False
|
|
127
|
+
immutable_unit: list[str] = []
|
|
128
|
+
range_unit_exponents: dict[str, int] = {"min": -1, "max": 1, "step_width": 1}
|
|
129
|
+
rounding_decimal_points: int = 5
|
|
130
|
+
rounding_decimal_points_ts: int = 4
|
|
131
|
+
linear_regression_check: dict[str, float] = {
|
|
132
|
+
"eps_intercept": 0.1,
|
|
133
|
+
"epsRvalue": 1 - (1e-5),
|
|
134
|
+
}
|
|
135
|
+
rounding_decimal_points_units: int = 6
|
|
136
|
+
round_parameters: bool = True
|
|
137
|
+
rounding_decimal_points_capacity: int = 4
|
|
138
|
+
analyze_numerics: bool = True
|
|
139
|
+
use_scaling: bool = True
|
|
140
|
+
scaling_include_rhs: bool = False
|
|
141
|
+
scaling_algorithm: Union[list[str],str] = ["geom","geom","geom"]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class TimeSeriesAggregation(Subscriptable):
|
|
146
|
+
slv: Solver = Solver()
|
|
147
|
+
clusterMethod: str = "hierarchical"
|
|
148
|
+
solver: str = slv.name
|
|
149
|
+
hoursPerPeriod: int = 1
|
|
150
|
+
extremePeriodMethod: Optional[str] = "None"
|
|
151
|
+
rescaleClusterPeriods: bool = False
|
|
152
|
+
representationMethod: str = "meanRepresentation"
|
|
153
|
+
resolution: int = 1
|
|
154
|
+
segmentation: bool = False
|
|
155
|
+
noSegments: int = 12
|
|
156
|
+
|
|
157
|
+
class Analysis(Subscriptable):
|
|
158
|
+
dataset: str = ""
|
|
159
|
+
objective: str = "total_cost"
|
|
160
|
+
sense: str = "minimize"
|
|
161
|
+
transport_distance: str = "Euclidean"
|
|
162
|
+
subsets: Subsets = Subsets()
|
|
163
|
+
header_data_inputs: HeaderDataInputs = HeaderDataInputs()
|
|
164
|
+
time_series_aggregation: TimeSeriesAggregation = TimeSeriesAggregation()
|
|
165
|
+
folder_output: str = "./outputs/"
|
|
166
|
+
overwrite_output: bool = True
|
|
167
|
+
output_format: str = "h5"
|
|
168
|
+
write_results_yml: bool = False
|
|
169
|
+
max_output_size_mb: int = 500
|
|
170
|
+
folder_name_system_specification: str = "system_specification"
|
|
171
|
+
earliest_year_of_data: int = 1900
|
|
172
|
+
|
|
173
|
+
class Config(Subscriptable):
|
|
174
|
+
analysis: Analysis = Analysis()
|
|
175
|
+
solver: Solver = Solver()
|
|
176
|
+
system: System = System()
|
|
177
|
+
|
|
178
|
+
scenarios: dict[str, Any] = {"": {}}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""==========
|
|
2
|
+
:Title: ZEN-GARDEN
|
|
3
|
+
:Created: March-2022
|
|
4
|
+
:Authors: Alissa Ganter (aganter@ethz.ch)
|
|
5
|
+
:Organization: Laboratory of Reliability and Risk Engineering, ETH Zurich
|
|
6
|
+
|
|
7
|
+
function that loads all classes and subclasses of carrier directory.
|
|
8
|
+
"""
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
# register the subclasses
|
|
12
|
+
modules = Path(__file__).parent.glob("*.py")
|
|
13
|
+
__all__ = [f.stem for f in modules if f.is_file()]
|