├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── docs-check.yml │ └── tests-coverage.yml ├── .gitignore ├── .isort.cfg ├── .pre-commit-config.yaml ├── .readthedocs.yml ├── LICENSE ├── README.md ├── doc ├── Makefile ├── conf.py ├── configs.rst ├── definitions_and_units.rst ├── dev_notes.rst ├── eDisGo_UML.graphml ├── equipment.rst ├── features_in_detail.rst ├── genindex.rst ├── images │ ├── cosphi-sign-convention_generation.png │ ├── cosphi-sign-convention_load.png │ ├── edisgo_logo.png │ └── grid_expansion_measures.png ├── index.rst ├── make.bat ├── quickstart.rst ├── units_table.csv ├── usage_details.rst ├── whatsnew.rst └── whatsnew │ ├── v0-0-10.rst │ ├── v0-0-2.rst │ ├── v0-0-3.rst │ ├── v0-0-5.rst │ ├── v0-0-6.rst │ ├── v0-0-7.rst │ ├── v0-0-8.rst │ ├── v0-0-9.rst │ ├── v0-1-0.rst │ ├── v0-1-1.rst │ ├── v0-2-0.rst │ ├── v0-2-1.rst │ └── v0-3-0.rst ├── eDisGo_env.yml ├── eDisGo_env_dev.yml ├── edisgo ├── __init__.py ├── config │ ├── config_db_tables_default.cfg │ ├── config_grid_default.cfg │ ├── config_grid_expansion_default.cfg │ ├── config_opf_julia_default.cfg │ ├── config_system.cfg │ └── config_timeseries_default.cfg ├── edisgo.py ├── equipment │ ├── equipment-parameters_LV_cables.csv │ ├── equipment-parameters_LV_transformers.csv │ ├── equipment-parameters_MV_cables.csv │ ├── equipment-parameters_MV_overhead_lines.csv │ ├── equipment-parameters_MV_transformers.csv │ └── equipment_data.meta ├── flex_opt │ ├── __init__.py │ ├── battery_storage_operation.py │ ├── charging_strategies.py │ ├── check_tech_constraints.py │ ├── costs.py │ ├── exceptions.py │ ├── heat_pump_operation.py │ ├── q_control.py │ ├── reinforce_grid.py │ └── reinforce_measures.py ├── io │ ├── __init__.py │ ├── db.py │ ├── ding0_import.py │ ├── dsm_import.py │ ├── electromobility_import.py │ ├── generators_import.py │ ├── heat_pump_import.py │ ├── powermodels_io.py │ ├── pypsa_io.py │ ├── storage_import.py │ └── timeseries_import.py ├── network │ ├── __init__.py │ ├── components.py │ ├── dsm.py │ ├── electromobility.py │ ├── grids.py │ ├── heat.py │ ├── overlying_grid.py │ ├── results.py │ ├── timeseries.py │ └── topology.py ├── opf │ ├── __init__.py │ ├── eDisGo_OPF.jl │ │ ├── Main.jl │ │ ├── Manifest.toml │ │ ├── Project.toml │ │ └── src │ │ │ ├── core │ │ │ ├── base.jl │ │ │ ├── constraint.jl │ │ │ ├── constraint_template.jl │ │ │ ├── data.jl │ │ │ ├── objective.jl │ │ │ ├── solution.jl │ │ │ ├── types.jl │ │ │ └── variables.jl │ │ │ ├── eDisGo_OPF.jl │ │ │ ├── form │ │ │ └── bf.jl │ │ │ ├── io │ │ │ ├── common.jl │ │ │ └── json.jl │ │ │ └── prob │ │ │ └── opf_bf.jl │ ├── opf_solutions │ │ └── __init__.py │ ├── powermodels_opf.py │ ├── results │ │ ├── __init__.py │ │ └── opf_result_class.py │ └── timeseries_reduction.py └── tools │ ├── __init__.py │ ├── config.py │ ├── geo.py │ ├── geopandas_helper.py │ ├── logger.py │ ├── networkx_helper.py │ ├── plots.py │ ├── powermodels_io.py │ ├── preprocess_pypsa_opf_structure.py │ ├── pseudo_coordinates.py │ ├── spatial_complexity_reduction.py │ ├── temporal_complexity_reduction.py │ └── tools.py ├── examples ├── data │ ├── vg250.cpg │ ├── vg250.dbf │ ├── vg250.prj │ ├── vg250.shp │ └── vg250.shx ├── edisgo_simple_example.ipynb ├── electromobility_example.ipynb └── plot_example.ipynb ├── rtd_requirements.txt ├── setup.py └── tests ├── conftest.py ├── data ├── ding0_test_network_1 │ ├── buses.csv │ ├── ding0_test_network_1.md │ ├── generators.csv │ ├── lines.csv │ ├── loads.csv │ ├── network.csv │ ├── storage_units.csv │ ├── switches.csv │ ├── transformers.csv │ └── transformers_hvmv.csv ├── ding0_test_network_2 │ ├── Ding0_20210416184606.meta │ ├── buses.csv │ ├── generators.csv │ ├── lines.csv │ ├── loads.csv │ ├── network.csv │ ├── switches.csv │ ├── transformers.csv │ └── transformers_hvmv.csv ├── ding0_test_network_3 │ ├── buses.csv │ ├── generators.csv │ ├── lines.csv │ ├── loads.csv │ ├── network.csv │ ├── switches.csv │ ├── transformers.csv │ └── transformers_hvmv.csv ├── simbev_example_scenario │ ├── 5334032 │ │ ├── bev_luxury_00000_110kWh_SR_Mitte_events.csv │ │ ├── bev_luxury_00001_110kWh_SR_Mitte_events.csv │ │ ├── bev_luxury_00002_110kWh_SR_Mitte_events.csv │ │ ├── bev_medium_00000_90kWh_SR_Mitte_events.csv │ │ ├── bev_medium_00001_90kWh_SR_Mitte_events.csv │ │ ├── bev_medium_00002_90kWh_SR_Mitte_events.csv │ │ ├── bev_mini_00000_60kWh_SR_Mitte_events.csv │ │ ├── bev_mini_00001_60kWh_SR_Mitte_events.csv │ │ ├── bev_mini_00002_60kWh_SR_Mitte_events.csv │ │ ├── phev_luxury_00000_30kWh_SR_Mitte_events.csv │ │ ├── phev_medium_00000_20kWh_SR_Mitte_events.csv │ │ └── phev_mini_00003_14kWh_SR_Mitte_events.csv │ └── metadata_simbev_run.json └── tracbev_example_scenario │ ├── output_home_05334032.gpkg │ ├── output_hpc_05334032.gpkg │ ├── output_public_05334032.gpkg │ └── output_work_05334032.gpkg ├── flex_opt ├── test_battery_storage_operation.py ├── test_charging_strategy.py ├── test_check_tech_constraints.py ├── test_costs.py ├── test_heat_pump_operation.py ├── test_q_control.py ├── test_reinforce_grid.py └── test_reinforce_measures.py ├── io ├── test_ding0_import.py ├── test_dsm_import.py ├── test_electromobility_import.py ├── test_generators_import.py ├── test_heat_pump_import.py ├── test_powermodels_io.py ├── test_pypsa_io.py ├── test_storage_import.py └── test_timeseries_import.py ├── network ├── test_components.py ├── test_dsm.py ├── test_electromobility.py ├── test_grids.py ├── test_heat.py ├── test_overlying_grid.py ├── test_results.py ├── test_timeseries.py └── test_topology.py ├── opf └── test_powermodels_opf.py ├── test_edisgo.py ├── test_examples.py └── tools ├── test_geopandas_helper.py ├── test_logger.py ├── test_plots.py ├── test_pseudo_coordinates.py ├── test_spatial_complexity_reduction.py ├── test_temporal_complexity_reduction.py └── test_tools.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | extend-exclude = docs 3 | max-line-length = 88 4 | extend-ignore = E203 5 | count = true 6 | statistics = true 7 | show-source = true 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | reviewers: 8 | - "joda9" 9 | labels: 10 | - "dependencies" 11 | rebase-strategy: "auto" 12 | ignore: 13 | - dependency-name: "pandas" 14 | - dependency-name: "plotly" 15 | - dependency-name: "pypsa" 16 | - dependency-name: "scikit-learn" 17 | - dependency-name: "sqlalchemy" 18 | - package-ecosystem: "github-actions" 19 | directory: "/" 20 | schedule: 21 | interval: "daily" 22 | reviewers: 23 | - "joda9" 24 | labels: 25 | - "dependencies" 26 | rebase-strategy: "auto" 27 | ignore: 28 | - dependency-name: "pandas" 29 | - dependency-name: "plotly" 30 | - dependency-name: "pypsa" 31 | - dependency-name: "scikit-learn" 32 | - dependency-name: "sqlalchemy" 33 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | 15 | # Checklist: 16 | 17 | - [ ] New and adjusted code is formatted using the `pre-commit` hooks 18 | - [ ] New and adjusted code includes type hinting now 19 | - [ ] I have commented my code, particularly in hard-to-understand areas 20 | - [ ] I have made corresponding changes to the documentation 21 | - [ ] I have added tests that prove my fix is effective or that my feature works 22 | - [ ] New and existing unit tests pass locally with my changes 23 | - [ ] The Read the Docs documentation is compiling correctly 24 | - [ ] If new packages are needed, I added them the [setup.py](https://github.com/openego/eDisGo/blob/dev/setup.py), and if needed the [rtd_requirements.txt](https://github.com/openego/eDisGo/blob/dev/rtd_requirements.txt), the [eDisGo_env.yml](https://github.com/openego/eDisGo/blob/dev/eDisGo_env.yml) and the [eDisGo_env_dev.yml](https://github.com/openego/eDisGo/blob/dev/eDisGo_env_dev.yml). 25 | - [ ] I have added new features to the corresponding [whatsnew](https://github.com/openego/eDisGo/tree/dev/doc/whatsnew) file 26 | -------------------------------------------------------------------------------- /.github/workflows/docs-check.yml: -------------------------------------------------------------------------------- 1 | name: "Docs link check" 2 | on: [push] 3 | 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - name: Install dependencies 10 | run: | 11 | sudo apt install pandoc 12 | python -m pip install --upgrade pip 13 | pip install -r rtd_requirements.txt 14 | - name: Check doc links 15 | run: | 16 | sphinx-build . -b linkcheck -d _build/doctrees _build/html 17 | working-directory: ./doc 18 | -------------------------------------------------------------------------------- /.github/workflows/tests-coverage.yml: -------------------------------------------------------------------------------- 1 | # Tests with pytest the package and monitors the covarage and sends it to coveralls.io 2 | # Coverage is only send to coveralls.io when no pytest tests fail 3 | name: "Tests & Coverage" 4 | 5 | on: [push] 6 | 7 | # Cancel jobs on new push 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref || github.run_id }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | build: 14 | name: "${{ matrix.name-suffix }} at py${{ matrix.python-version }} on ${{ matrix.os }}" 15 | runs-on: ${{ matrix.os }} 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | include: 21 | - name-suffix: "coverage" 22 | os: ubuntu-latest 23 | python-version: 3.9 24 | - name-suffix: "basic" 25 | os: ubuntu-latest 26 | python-version: "3.10" 27 | - name-suffix: "basic" 28 | os: ubuntu-latest 29 | python-version: 3.11 30 | - name-suffix: "basic" 31 | os: windows-latest 32 | python-version: 3.9 33 | 34 | steps: 35 | - name: Checkout repo 36 | uses: actions/checkout@v4 37 | 38 | - name: Set up Python 39 | uses: actions/setup-python@v5 40 | with: 41 | python-version: ${{ matrix.python-version }} 42 | 43 | - name: Set up julia 44 | if: runner.os == 'Linux' 45 | uses: julia-actions/setup-julia@v2 46 | with: 47 | version: "1.6" 48 | 49 | - name: Install packages (Linux) 50 | if: runner.os == 'Linux' 51 | run: | 52 | pip install --upgrade pip wheel setuptools 53 | pip install -e "." 54 | 55 | - name: Install packages (Windows) 56 | if: runner.os == 'Windows' 57 | uses: conda-incubator/setup-miniconda@v3 58 | with: 59 | miniconda-version: "latest" 60 | activate-environment: edisgo_env 61 | environment-file: eDisGo_env_dev.yml 62 | python-version: ${{ matrix.python-version }} 63 | 64 | - name: Run tests Linux 65 | if: runner.os == 'Linux' && matrix.name-suffix != 'coverage' 66 | run: | 67 | python -m pip install pytest pytest-notebook 68 | python -m pytest --runslow --runonlinux --disable-warnings --color=yes -v 69 | env: 70 | TOEP_TOKEN_KH: ${{ secrets.TOEP_TOKEN_KH }} 71 | 72 | - name: Run tests Windows 73 | if: runner.os == 'Windows' 74 | run: | 75 | python -m pip install pytest pytest-notebook 76 | python -m pytest --runslow --disable-warnings --color=yes -v 77 | env: 78 | TOEP_TOKEN_KH: ${{ secrets.TOEP_TOKEN_KH }} 79 | 80 | - name: Run tests, coverage and send to coveralls 81 | if: runner.os == 'Linux' && matrix.python-version == 3.9 && matrix.name-suffix == 'coverage' 82 | run: | 83 | pip install pytest pytest-notebook coveralls 84 | coverage run --source=edisgo -m pytest --runslow --runonlinux --disable-warnings --color=yes -v 85 | coveralls 86 | env: 87 | TOEP_TOKEN_KH: ${{ secrets.TOEP_TOKEN_KH }} 88 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 89 | COVERALLS_SERVICE_NAME: github 90 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # exclude project files 2 | .idea/ 3 | 4 | 5 | # exclude certain types of files 6 | *.doctree 7 | *.txt 8 | *.html 9 | *.js 10 | *.inv 11 | *.pyc 12 | *.ttf 13 | *.woff 14 | *.css 15 | *.pkl 16 | *.ipynb_checkpoints 17 | 18 | # exclude locally built docs 19 | doc/_html 20 | 21 | # exclude egg-info 22 | eDisGo.egg-info/ 23 | 24 | # exclude .json files in opf 25 | /edisgo/opf/opf_solutions/*.json 26 | /edisgo/opf/eDisGo_OPF.jl/.vscode 27 | .vscode/settings.json 28 | 29 | *TOEP_TOKEN.* 30 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | profile = black 3 | multi_line_output = 3 4 | lines_between_types = 1 5 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: check-yaml 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/psf/black 9 | rev: 25.1.0 10 | hooks: 11 | - id: black 12 | - repo: https://github.com/pycqa/flake8 13 | rev: 7.1.1 14 | hooks: 15 | - id: flake8 16 | - repo: https://github.com/pycqa/isort 17 | rev: 6.0.0 18 | hooks: 19 | - id: isort 20 | name: isort (python) 21 | - repo: https://github.com/asottile/pyupgrade 22 | rev: v3.19.1 23 | hooks: 24 | - id: pyupgrade 25 | #- repo: https://github.com/pycqa/pylint 26 | # rev: pylint-2.6.0 27 | # hooks: 28 | # - id: pylint 29 | - repo: https://github.com/kynan/nbstripout 30 | rev: 0.8.1 31 | hooks: 32 | - id: nbstripout 33 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | sphinx: 10 | configuration: doc/conf.py 11 | 12 | # Build documentation with MkDocs 13 | #mkdocs: 14 | # configuration: mkdocs.yml 15 | 16 | # Optionally build your docs in additional formats such as PDF and ePub 17 | formats: all 18 | 19 | # Optionally set the version of Python and requirements required to build your docs 20 | python: 21 | install: 22 | - requirements: rtd_requirements.txt 23 | 24 | # Set the version of Python 25 | build: 26 | os: ubuntu-22.04 27 | tools: 28 | python: "3.9" 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Overview 5 | 6 | [![Coverage Status](https://coveralls.io/repos/github/openego/eDisGo/badge.svg?branch=dev)](https://coveralls.io/github/openego/eDisGo?branch=dev) 7 | [![Tests & coverage](https://github.com/openego/eDisGo/actions/workflows/tests-coverage.yml/badge.svg)](https://github.com/openego/eDisGo/actions/workflows/tests-coverage.yml) 8 | 9 | 10 | # eDisGo 11 | 12 | The python package eDisGo serves as a toolbox to evaluate flexibility measures 13 | as an economic alternative to conventional grid expansion in 14 | medium and low voltage grids. 15 | See [documentation](https://edisgo.readthedocs.io/en/dev/) for further information. 16 | 17 | 18 | # LICENSE 19 | 20 | Copyright (C) 2017 Reiner Lemoine Institut gGmbH 21 | 22 | This program is free software: you can redistribute it and/or modify it under 23 | the terms of the GNU Affero General Public License as published by the Free 24 | Software Foundation, either version 3 of the License, or (at your option) any 25 | later version. 26 | 27 | This program is distributed in the hope that it will be useful, but WITHOUT 28 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 29 | FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more 30 | details. 31 | 32 | You should have received a copy of the GNU General Public License along with 33 | this program. If not, see https://www.gnu.org/licenses/. 34 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /doc/configs.rst: -------------------------------------------------------------------------------- 1 | .. _default_configs: 2 | 3 | Default configuration data 4 | ============================ 5 | 6 | Following you find the default configuration files. 7 | 8 | .. _config_db: 9 | 10 | config_db_tables 11 | ------------------- 12 | 13 | The config file ``config_db_tables.cfg`` holds data about which database connection 14 | to use from your saved database connections and which dataprocessing version. 15 | 16 | .. include:: ../edisgo/config/config_db_tables_default.cfg 17 | :literal: 18 | 19 | .. _config_grid_expansion: 20 | 21 | config_grid_expansion 22 | ---------------------- 23 | 24 | The config file ``config_grid_expansion.cfg`` holds data mainly needed to determine 25 | grid expansion needs and costs - these are standard equipment to use in grid expansion and 26 | its costs, as well as allowed voltage deviations and line load factors. 27 | 28 | .. include:: ../edisgo/config/config_grid_expansion_default.cfg 29 | :literal: 30 | 31 | .. _config_timeseries: 32 | 33 | config_timeseries 34 | ---------------------- 35 | 36 | The config file ``config_timeseries.cfg`` holds data to define the two worst-case 37 | scenarions heavy load flow ('load case') and reverse power flow ('feed-in case') 38 | used in conventional grid expansion planning, power factors and modes (inductive 39 | or capacitative) to generate reactive power time series, as well as configurations 40 | of the demandlib in case load time series are generated using the oemof demandlib. 41 | 42 | .. include:: ../edisgo/config/config_timeseries_default.cfg 43 | :literal: 44 | 45 | .. _config_grid: 46 | 47 | config_grid 48 | ---------------------- 49 | 50 | The config file ``config_grid.cfg`` holds data to specify parameters used when 51 | connecting new generators to the grid and where to position disconnecting points. 52 | 53 | .. include:: ../edisgo/config/config_grid_default.cfg 54 | :literal: 55 | -------------------------------------------------------------------------------- /doc/definitions_and_units.rst: -------------------------------------------------------------------------------- 1 | Definition and units 2 | ==================== 3 | 4 | Sign Convention 5 | --------------- 6 | 7 | Generators and Loads in an AC power system can behave either like an inductor or a capacitor. Mathematically, 8 | this has two different sign conventions, either from the generator perspective or from the load perspective. 9 | This is defined by the direction of power flow from the component. 10 | 11 | Both sign conventions are used in eDisGo depending upon the components being defined, similar to pypsa. 12 | 13 | Generator Sign Convention 14 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 15 | .. _generator_sign_convention_label: 16 | .. figure:: images/cosphi-sign-convention_generation.png 17 | 18 | Generator sign convention in detail 19 | 20 | While defining time series for :class:`~.grid.components.Generator`, :class:`~.grid.components.GeneratorFluctuating`, 21 | and :class:`~.grid.components.Storage`, the generator sign convention is used. 22 | 23 | 24 | Load Sign Convention 25 | ^^^^^^^^^^^^^^^^^^^^ 26 | .. _load_sign_convention_label: 27 | .. figure:: images/cosphi-sign-convention_load.png 28 | 29 | Load sign convention in detail 30 | 31 | The time series for :class:`~.grid.components.Load` is defined using the load sign convention. 32 | 33 | 34 | Reactive Power Sign Convention 35 | ------------------------------ 36 | 37 | Generators and Loads in an AC power system can behave either like an inductor or a capacitor. Mathematically, 38 | this has two different sign conventions, either from the generator perspective or from the load perspective. 39 | 40 | Both sign conventions are used in eDisGo, similar to pypsa. While defining time series for 41 | :class:`~.grid.components.Generator`, :class:`~.grid.components.GeneratorFluctuating`, and 42 | :class:`~.grid.components.Storage`, the generator sign convention is used. This means that when 43 | the reactive power (Q) is positive, the component shows capacitive behaviour and when the reactive power (Q) is 44 | negative, the component shows inductive behaviour. 45 | 46 | The time series for :class:`~.grid.components.Load` is defined using the load sign convention. This means 47 | that when the reactive power (Q) is positive, the component shows inductive behaviour and when the 48 | reactive power (Q) is negative, the component shows capacitive behaviour. This is the direct opposite of the 49 | generator sign convention. 50 | 51 | 52 | Units 53 | ----- 54 | .. csv-table:: List of variables and units 55 | :file: units_table.csv 56 | :delim: ; 57 | :header-rows: 1 58 | :widths: 5, 1, 1, 5 59 | :stub-columns: 0 60 | -------------------------------------------------------------------------------- /doc/dev_notes.rst: -------------------------------------------------------------------------------- 1 | .. _dev-notes: 2 | 3 | Notes to developers 4 | =================== 5 | 6 | Installation 7 | ------------ 8 | 9 | Clone the repository from `GitHub `_ and change into 10 | the eDisGo directory: 11 | 12 | .. code-block:: bash 13 | 14 | cd eDisGo 15 | 16 | 17 | Installation using Linux 18 | ~~~~~~~~~~~~~~~~~~~~~~~~ 19 | 20 | To set up a source installation using linux simply use a virtual environment and install 21 | the source code with pip. Make sure to use python3.9 or higher. **After** setting up your virtual environment and activating it run the 22 | following commands within your eDisGo directory: 23 | 24 | .. code-block:: bash 25 | 26 | python -m pip install -e .[dev] # install eDisGo from source 27 | pre-commit install # install pre-commit hooks 28 | 29 | 30 | Installation using Windows 31 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | 33 | For Windows users we recommend using Anaconda and to install the geo stack 34 | using the conda-forge channel prior to installing eDisGo. You may use the provided 35 | `eDisGo_env_dev.yml file `_ 36 | to do so. Create the virtual environment with: 37 | 38 | .. code-block:: bash 39 | 40 | conda env create -f path/to/eDisGo_env_dev.yml # install eDisGo from source 41 | 42 | Activate the newly created environment and install the pre-commit hooks with: 43 | 44 | .. code-block:: bash 45 | 46 | conda activate eDisGo_env_dev 47 | pre-commit install # install pre-commit hooks 48 | 49 | This will install eDisGo with all its dependencies. 50 | 51 | Installation using MacOS 52 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 53 | 54 | We don't have any experience with our package on MacOS yet! If you try eDisGo on MacOS 55 | we would be happy if you let us know about your experience! 56 | 57 | 58 | Code standards 59 | -------------- 60 | 61 | * **pre-commit hooks**: Make sure to use the provided pre-commit hooks 62 | * **pytest**: Make sure that all pytest tests are passing and add tests for every new code base 63 | * **Documentation of `@property` functions**: Put documentation of getter and setter 64 | both in Docstring of getter, see 65 | `on Stackoverflow `_ 66 | * Order of public/private/protected methods, property decorators, etc. in a class: TBD 67 | 68 | 69 | Documentation 70 | ------------- 71 | 72 | You can build the docs locally as follows (executed from top-level eDisGo directory): 73 | 74 | .. code-block:: bash 75 | 76 | sphinx-build -E -a -b html ./doc/ 77 | 78 | To manually check if external links in the documentation work, you can run the following command (internal links are not checked by this): 79 | 80 | .. code-block:: bash 81 | 82 | sphinx-build ./doc/ -b linkcheck -d _build/doctrees _build/html 83 | 84 | Internal links can be checked adding -n option when building the documentation. This will 85 | also raise warnings for type hinting, so it is a bit confusing, but can still be helpful. 86 | 87 | .. code-block:: bash 88 | 89 | sphinx-build -n -E -a -b html ./doc/ 90 | -------------------------------------------------------------------------------- /doc/equipment.rst: -------------------------------------------------------------------------------- 1 | .. _equipment: 2 | 3 | Equipment data 4 | ================= 5 | 6 | The following tables hold all data of cables, lines and transformers used. 7 | 8 | .. _lv_cables_table: 9 | 10 | .. csv-table:: LV cables 11 | :file: ../edisgo/equipment/equipment-parameters_LV_cables.csv 12 | :delim: , 13 | :header-rows: 2 14 | :widths: 3, 1, 1, 1, 1, 1 15 | :stub-columns: 0 16 | 17 | .. _mv_cables_table: 18 | 19 | .. csv-table:: MV cables 20 | :file: ../edisgo/equipment/equipment-parameters_MV_cables.csv 21 | :delim: , 22 | :header-rows: 2 23 | :widths: 4, 1, 1, 1, 1, 1 24 | :stub-columns: 0 25 | 26 | .. _mv_lines_table: 27 | 28 | .. csv-table:: MV overhead lines 29 | :file: ../edisgo/equipment/equipment-parameters_MV_overhead_lines.csv 30 | :delim: , 31 | :header-rows: 2 32 | :widths: 4, 1, 1, 1, 1, 1 33 | :stub-columns: 0 34 | 35 | .. _lv_transformers_table: 36 | 37 | .. csv-table:: LV transformers 38 | :file: ../edisgo/equipment/equipment-parameters_LV_transformers.csv 39 | :delim: , 40 | :header-rows: 2 41 | :widths: 5, 1, 1, 1 42 | :stub-columns: 0 43 | 44 | .. _mv_transformers_table: 45 | 46 | .. csv-table:: MV transformers 47 | :file: ../edisgo/equipment/equipment-parameters_MV_transformers.csv 48 | :delim: , 49 | :header-rows: 2 50 | :widths: 5, 1 51 | :stub-columns: 0 52 | -------------------------------------------------------------------------------- /doc/genindex.rst: -------------------------------------------------------------------------------- 1 | Index 2 | ================== 3 | 4 | :ref:`genindex` 5 | -------------------------------------------------------------------------------- /doc/images/cosphi-sign-convention_generation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/doc/images/cosphi-sign-convention_generation.png -------------------------------------------------------------------------------- /doc/images/cosphi-sign-convention_load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/doc/images/cosphi-sign-convention_load.png -------------------------------------------------------------------------------- /doc/images/edisgo_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/doc/images/edisgo_logo.png -------------------------------------------------------------------------------- /doc/images/grid_expansion_measures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/doc/images/grid_expansion_measures.png -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to the documentation of eDisGo! 2 | ======================================== 3 | 4 | .. figure:: images/edisgo_logo.png 5 | :align: right 6 | :scale: 70% 7 | 8 | The python package eDisGo serves as a toolbox to evaluate flexibility measures 9 | as an economic alternative to conventional grid expansion in 10 | medium and low voltage grids. 11 | 12 | The toolbox currently includes: 13 | 14 | * Data import from external data sources 15 | 16 | * `ding0 `_ tool for synthetic medium and low 17 | voltage grid topologies for the whole of Germany 18 | * `OpenEnergy DataBase (oedb) `_ for 19 | feed-in time series of fluctuating renewables and scenarios for future 20 | power plant park of Germany 21 | * `demandlib `_ for electrical load time series 22 | * `SimBEV `_ and 23 | `TracBEV `_ for charging demand data of electric 24 | vehicles, respectively potential charging point locations 25 | 26 | * Static, non-linear power flow analysis using `PyPSA `_ for 27 | grid issue identification 28 | * Automatic grid reinforcement methodology solving overloading and voltage issues 29 | to determine grid expansion needs and costs based on measures most commonly 30 | taken by German distribution grid operators 31 | * Implementation of different charging strategies of electric vehicles 32 | * Multiperiod optimal power flow based on julia package PowerModels.jl optimizing 33 | storage positioning and/or operation (Currently not maintained) 34 | as well as generator dispatch with regard to minimizing grid expansion costs 35 | * Temporal complexity reduction 36 | * Heuristic for grid-supportive generator curtailment (Currently not maintained) 37 | * Heuristic grid-supportive battery storage integration (Currently not maintained) 38 | 39 | Currently, a method to optimize the flexibility that can be provided by electric 40 | vehicles through controlled charging is being implemented. 41 | Prospectively, demand side management and reactive power management will 42 | be included. 43 | 44 | See :ref:`quickstart` for the first steps. 45 | A deeper guide is provided in :ref:`usage-details`. 46 | Methodologies are explained in detail in :ref:`features-in-detail`. 47 | For those of you who want to contribute see :ref:`dev-notes` and the 48 | API reference. 49 | 50 | eDisGo was initially developed in the 51 | `open_eGo `_ research project as part of 52 | a grid planning tool that can be used to determine the optimal grid and storage 53 | expansion of the German power grid over all voltage levels and has been used in 54 | two publications of the project: 55 | 56 | * `Integrated Techno-Economic Power System Planning of Transmission and Distribution Grids `_ 57 | * `Final report of the open_eGo project (in German) `_ 58 | 59 | Contents 60 | ================== 61 | 62 | .. toctree:: 63 | :maxdepth: 2 64 | 65 | quickstart 66 | usage_details 67 | features_in_detail 68 | dev_notes 69 | definitions_and_units 70 | configs 71 | equipment 72 | whatsnew 73 | genindex 74 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /doc/units_table.csv: -------------------------------------------------------------------------------- 1 | Variable;Symbol;Unit;Comment 2 | Current;I;kA; 3 | Length;l;km; 4 | Active Power;P;MW; 5 | Reactive Power;Q;MVar; 6 | Apparent Power;S;MVA; 7 | Resistance;R;Ohm or Ohm/km;Ohm/km applies to lines 8 | Reactance;X;Ohm or Ohm/km;Ohm/km applies to lines 9 | Voltage;V;kV; 10 | Inductance;L;mH/km; 11 | Capacitance;C;µF/km; 12 | Costs;-;kEUR; 13 | -------------------------------------------------------------------------------- /doc/whatsnew.rst: -------------------------------------------------------------------------------- 1 | What's New 2 | ~~~~~~~~~~ 3 | 4 | Changelog for each release. 5 | 6 | .. contents:: 7 | :depth: 1 8 | :local: 9 | :backlinks: top 10 | 11 | .. include:: whatsnew/v0-2-1.rst 12 | .. include:: whatsnew/v0-2-0.rst 13 | .. include:: whatsnew/v0-1-1.rst 14 | .. include:: whatsnew/v0-1-0.rst 15 | .. include:: whatsnew/v0-0-10.rst 16 | .. include:: whatsnew/v0-0-9.rst 17 | .. include:: whatsnew/v0-0-8.rst 18 | .. include:: whatsnew/v0-0-7.rst 19 | .. include:: whatsnew/v0-0-6.rst 20 | .. include:: whatsnew/v0-0-5.rst 21 | .. include:: whatsnew/v0-0-3.rst 22 | .. include:: whatsnew/v0-0-2.rst 23 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-0-10.rst: -------------------------------------------------------------------------------- 1 | Release v0.0.10 2 | ================ 3 | 4 | Release date: October 18, 2019 5 | 6 | Changes 7 | ------- 8 | * Updated to networkx 2.0 9 | * Changed data of transformers `#240 `_ 10 | * Proper session handling and readonly usage (PR `#160 `_) 11 | 12 | Bug fixes 13 | ---------- 14 | * Corrected calculation of current from pypsa power flow results (PR `#153 `_). 15 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-0-2.rst: -------------------------------------------------------------------------------- 1 | Release v0.0.2 2 | ============== 3 | 4 | Release date: March 15 2018 5 | 6 | The code was heavily revised. Now, eDisGo provides the top-level API class 7 | :class:`~.grid.network.EDisGo` for user interaction. See below for details and 8 | other small changes. 9 | 10 | Changes 11 | ------- 12 | 13 | * Switch disconnector/ disconnecting points are now relocated by eDisGo 14 | `#99 `_. Before, 15 | locations determined by Ding0 were used. Relocation is conducted according to 16 | minimal load differences in both parts of the ring. 17 | * Switch disconnectors are always located in LV stations 18 | `#23 `_ 19 | * Made all round speed improvements as mentioned in the issues `#43 `_ 20 | * The structure of eDisGo and its input data has been extensively revised in order to 21 | make it more consistent and easier to use. We introduced a top-level API class called :class:`~.grid.network.EDisGo` through which all user 22 | input and measures are now handled. The EDisGo class thereby replaces the former Scenario class and parts of the Network class. 23 | See :ref:`edisgo-mwe` for a quick overview of how to use the EDisGo class or :ref:`usage-details` for a more comprehensive 24 | introduction to the edisgo structure and usage. 25 | * We introduce a CLI script to use basic functionality of eDisGo including 26 | parallelization. CLI uses higher level functions to run eDisGo. Consult 27 | :mod:`~.tools.edisgo_run` for further details. 28 | `#93 `_. 29 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-0-3.rst: -------------------------------------------------------------------------------- 1 | Release v0.0.3 2 | ============== 3 | 4 | Release date: July 6 2018 5 | 6 | New features have been included in this release. Major changes being the use of the weather_cell_id and 7 | the inclusion of new methods for distributing the curtailment to be more suitable to network operations. 8 | 9 | Changes 10 | ------- 11 | 12 | * As part of the solution to github issues `#86 `_, 13 | `#98 `_, Weather cell information was of importance due to the changes 14 | in the source of data. The table `ego_renewable_feedin_v031` is now used to provide this feedin time series indexed 15 | using the weather cell id's. Changes were made to ego.io and ding0 to correspondingly allow the use of this table 16 | by eDisGo. 17 | 18 | * A new curtailment method have been included based on the voltages at the nodes with `GeneratorFluctuating` objects. 19 | The method is called `curtail_voltage` and its objective is to increase curtailment at locations where voltages 20 | are very high, thereby alleviating over-voltage issues and also reducing the need for network reinforcement. 21 | 22 | * Add parallelization for custon functions 23 | `#130 `_ 24 | 25 | * Update `ding0 version to v0.1.6 `_ and include 26 | `data processing v.4.2 data `_ 27 | 28 | * Bug Fixes 29 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-0-5.rst: -------------------------------------------------------------------------------- 1 | Release v0.0.5 2 | ============== 3 | 4 | Release date: July 19, 2018 5 | 6 | Most important changes in this release are some major bug fixes, a differentiation of line load factors and 7 | allowed voltage deviations for load and feed-in case in the grid reinforcement and a possibility to update 8 | time series in the pypsa representation. 9 | 10 | Changes 11 | ------- 12 | 13 | * Switch disconnecters in MV rings will now be installed, even if no LV station 14 | exists in the ring `#136 `_ 15 | * Update to new version of ding0 16 | `v0.1.7 `_ 17 | * Consider feed-in and load case in grid expansion methodology 18 | * Enable grid expansion on snapshots 19 | * Bug fixes 20 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-0-6.rst: -------------------------------------------------------------------------------- 1 | Release v0.0.6 2 | ============== 3 | 4 | Release date: September 6, 2018 5 | 6 | This release comes with a bunch of new features such as results output and visualization, speed-up options, a new storage 7 | integration methodology and an option to provide separate allowed voltage deviations for calculation of grid expansion needs. 8 | See list of changes below for more details. 9 | 10 | Changes 11 | ------- 12 | 13 | * A methodolgy to integrate storages in the MV grid to reduce grid expansion costs was added that takes a given storage capacity and operation and allocates it to multiple smaller storages. 14 | This methodology is mainly to be used together with the `eTraGo tool `_ where an optimization of the HV and EHV levels is conducted to calculate 15 | optiomal storage size and operation at each HV/MV substation. 16 | * The voltage-based curtailment methodolgy was adapted to take into account allowed voltage deviations and curtail generators with voltages that exceed the allowed voltage deviation 17 | more than generators with voltages that do not exceed the allowed voltage deviation. 18 | * When conducting grid reinforcement it is now possible to apply separate allowed voltage deviations for different voltage levels (`#108 `_). 19 | Furthermore, an additional check was added at the end of the grid expansion methodology if the 10%-criterion was observed. 20 | * To speed up calculations functions to update the pypsa representation of the edisgo graph after generator import, storage integration and time series update, e.g. after curtailment, were added. 21 | * Also as a means to speed up calculations an option to calculate grid expansion costs for the two worst time steps, characterized by highest and lowest residual load at the HV/MV substation, 22 | was added. 23 | * For the newly added storage integration methodology it was necessary to calculate grid expansion costs without changing the topology of the graph in order to identify feeders with 24 | high grid expansion needs. Therefore, the option to conduct grid reinforcement on a copy of the graph was added to the grid expansion function. 25 | * So far loads and generators always provided or consumed inductive reactive power with the specified power factor. It is now possible to specify whether loads and generators should 26 | behave as inductors or capacitors and to provide a concrete reactive power time series(`#131 `_). 27 | * The Results class was extended by outputs for storages, grid losses and active and reactive power at the HV/MV substation (`#138 `_) 28 | as well as by a function to save all results to csv files. 29 | * A plotting function to plot line loading in the MV grid was added. 30 | * Update `ding0 version to v0.1.8 `_ and include 31 | `data processing v0.4.5 data `_ 32 | * `Bug fix `_ 33 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-0-7.rst: -------------------------------------------------------------------------------- 1 | Release v0.0.7 2 | ============== 3 | 4 | Release date: October 23, 2018 5 | 6 | This release mainly focuses on new plotting functionalities and making reimporting saved results 7 | to further analyze and visualize them more comfortable. 8 | 9 | Changes 10 | ------- 11 | 12 | * new plotting methods in the EDisGo API class (plottings of the MV grid topology showing line loadings, 13 | grid expansion costs, voltages and/or integrated storages and histograms 14 | for voltages and relative line loadings) 15 | * new classes EDisGoReimport, NetworkReimport and ResultsReimport to reimport saved results 16 | and enable all analysis and plotting functionalities offered by the original classes 17 | * bug fixes 18 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-0-8.rst: -------------------------------------------------------------------------------- 1 | Release v0.0.8 2 | ============== 3 | 4 | Release date: October 29, 2018 5 | 6 | Changes 7 | ------- 8 | * added tolerance for curtailment targets slightly higher than generator availability to allow small 9 | rounding errors 10 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-0-9.rst: -------------------------------------------------------------------------------- 1 | Release v0.0.9 2 | ============== 3 | 4 | Release date: December 3, 2018 5 | 6 | Changes 7 | ------- 8 | 9 | * bug fix in determining voltage deviation in LV stations and LV grid 10 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-1-0.rst: -------------------------------------------------------------------------------- 1 | Release v0.1.0 2 | ================ 3 | 4 | Release date: July 26, 2021 5 | 6 | This release comes with some major refactoring. The internal data structure 7 | of the network topologies was changed from a networkx graph structure to 8 | a pandas dataframe structure based on the 9 | `PyPSA `_ data structure. This comes 10 | along with major API changes. 11 | Not all functionality of the previous eDisGo release 0.0.10 is yet refactored 12 | (e.g. the heuristics for grid supportive storage integration and generator 13 | curtailment), but we are working on it and the upcoming releases will 14 | have the full functionality again. 15 | 16 | Besides the refactoring we added extensive tests along with automatic testing 17 | with GitHub Actions and coveralls tool to track test coverage. 18 | 19 | Further, from now on python 3.6 is not supported anymore. Supported python 20 | versions are 3.7, 3.8 and 3.9. 21 | 22 | Changes 23 | ------- 24 | 25 | * Major refactoring `#159 `_ 26 | * Added support for Python 3.7, 3.8 and 3.9 `#181 `_ 27 | * Added GitHub Actions for testing and coverage `#180 `_ 28 | * Adapted to new ding0 release `#184 `_ - loads and generators in the same building are now connected to the same bus instead of separate buses and loads and generators in aggregated load areas are connected via a MV/LV station instead of directly to the HV/MV station) 29 | * Added charging points as new components along with a methodology to integrate them into the grid 30 | * Added multiperiod optimal power flow based on julia package PowerModels.jl optimizing storage positioning and/or operation as well as generator dispatch with regard to minimizing grid expansion costs 31 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-1-1.rst: -------------------------------------------------------------------------------- 1 | Release v0.1.1 2 | ================ 3 | 4 | Release date: July 22, 2022 5 | 6 | This release comes with some minor additions and bug fixes. 7 | 8 | Changes 9 | ------- 10 | 11 | * Added a pull request and issue template 12 | * Fix readthecods API doc 13 | * Consider parallel lines in calculation of x, r and s_nom 14 | * Bug fix calculation of x and r of new lines 15 | * Bug fix of getting a list of all weather cells within grid district 16 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-2-0.rst: -------------------------------------------------------------------------------- 1 | Release v0.2.0 2 | ================ 3 | 4 | Release date: November 10, 2022 5 | 6 | Changes 7 | ------- 8 | 9 | * added pre-commit hooks (flake8, black, isort, pyupgrade) `#229 `_ 10 | * added issue and pull request templates `#220 `_ 11 | * added Windows installation yml and documentation 12 | * added automatic testing for Windows `#317 `_ 13 | * dropped support for python 3.7 14 | * added functionality to set up different loggers with individual logging levels and where to write output `#295 `_ 15 | * added integrity checks of eDisGo object `#231 `_ 16 | * added functionality to save to and load from zip archive `#216 `_ 17 | * added option to not raise error in case power flow did not converge `#207 `_ 18 | * added pyplot `#214 `_ 19 | * added functionality to create geopandas dataframes `#224 `_ 20 | * added functionality to resample time series `#269 `_ 21 | * added tests 22 | * major refactoring of loads and time series 23 | 24 | * restructured time series module to allow more options on how to set component time series `#236 `_ 25 | * added charging points to Topology.loads_df to make eDisGo more flexible when further new load types are added 26 | * peak_load in Topology.loads_df is renamed to p_nom `#242 `_ 27 | * renamed all occurences of feedin in config files to feed-in 28 | * added simultaneity factors for heat pumps and electric vehicles 29 | * grid reinforcement now considers separate simultaneity factors for dimensioning of LV and MV `#252 `_ 30 | 31 | * added interface to electromobility data from tools SimBEV and TracBEV (SimBEV provides data on 32 | standing times, charging demand, etc. per vehicle, whereas TracBEV provides potential charging point locations) 33 | `#174 `_ and 34 | `#191 `_ 35 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-2-1.rst: -------------------------------------------------------------------------------- 1 | Release v0.2.1 2 | ================ 3 | 4 | Release date: April 2, 2023 5 | 6 | Changes 7 | ------- 8 | 9 | * Added automatic resampling when applying a charging strategy `#332 `_ 10 | * Added MV grid ID to logging output `#309 `_ 11 | * Added automatic link checking `#297 `_ 12 | * Bug fix `#346 `_ 13 | -------------------------------------------------------------------------------- /doc/whatsnew/v0-3-0.rst: -------------------------------------------------------------------------------- 1 | Release v0.3.0 2 | ================ 3 | 4 | Release date: , 5 | 6 | Changes 7 | ------- 8 | 9 | * Added functionalities to obtain electromobility, DSM, storage and electricity timeseries data from oedb `#328 `_ 10 | * Added functionalities to obtain heat pump data from oedb `#324 `_ 11 | * Added functionality to resample and check integrity of flexibility bands `#341 `_ 12 | * Added spatial complexity reduction methods `#343 `_ 13 | * Added function to sort buses in lines dataframe such that bus0 is always the upstream bus `#335 `_ 14 | * Changed to_pypsa function such that pypsa network can be build even though not all components have time series `#335 `_ 15 | * Added class holding data from overlying grid, such as curtailment requirements and 16 | conventional generator dispatch `#335 `_ 17 | * Added integrity check for very short lines `#335 `_ 18 | * Refactoring of check_tech_constraints functions `#290 `_ 19 | * Add background map to plots `#346 `_ 20 | * Added method to scale timeseries `#353 `_ 21 | * Added method to iteratively reinforce a grid in case the power flow analysis does not always converge `#353 `_ 22 | * Added method to aggregate LV grid buses to station bus secondary side `#353 `_ 23 | * Adapted codebase to work with pandas 2.0 `#373 `_ 24 | * Added option to run reinforcement with reduced number of time steps `#379 `_ 25 | (adapted in `#395 `_) 26 | * Added optimization method to determine dispatch of flexibilities that lead to minimal network expansion costs `#376 `_ 27 | * Added a new reinforcement method that separate lv grids when the overloading is very high `#380 `_ 28 | * Move function to assign feeder to Topology class and add methods to the Grid class to get information on the feeders `#360 `_ 29 | * Added a storage operation strategy where the storage is charged when PV feed-in is higher than electricity demand of the household and discharged when electricity demand exceeds PV generation `#386 `_ 30 | * Added an estimation of the voltage deviation over a cable when selecting a suitable cable to connect a new component `#411 `_ 31 | * Added clipping of heat pump electrical power at its maximum value #428 32 | -------------------------------------------------------------------------------- /eDisGo_env.yml: -------------------------------------------------------------------------------- 1 | name: eDisGo_env 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - python >= 3.9, <= 3.11 7 | - pip 8 | - pandas >= 1.4, < 2.2.0 9 | - conda-forge::fiona 10 | - conda-forge::geopy 11 | - conda-forge::geopandas 12 | - conda-forge::pyproj 13 | - conda-forge::shapely 14 | - conda-forge::rasterio 15 | - conda-forge::geoalchemy2 16 | - conda-forge::pygeos 17 | - conda-forge::contextily 18 | - conda-forge::descartes 19 | - conda-forge::pypsa == 0.26.2 20 | - pip: 21 | - eDisGo 22 | -------------------------------------------------------------------------------- /eDisGo_env_dev.yml: -------------------------------------------------------------------------------- 1 | name: eDisGo_env_dev 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - python >= 3.9, <= 3.11 7 | - pip 8 | - pandas >= 1.4, < 2.2.0 9 | - conda-forge::fiona 10 | - conda-forge::geopy 11 | - conda-forge::geopandas 12 | - conda-forge::pyproj 13 | - conda-forge::shapely 14 | - conda-forge::rasterio 15 | - conda-forge::geoalchemy2 16 | - conda-forge::pygeos 17 | - conda-forge::contextily 18 | - conda-forge::descartes 19 | - conda-forge::pypsa == 0.26.2 20 | - pip: 21 | - -e .[dev] 22 | -------------------------------------------------------------------------------- /edisgo/__init__.py: -------------------------------------------------------------------------------- 1 | from edisgo.edisgo import EDisGo # noqa: F401 2 | -------------------------------------------------------------------------------- /edisgo/config/config_db_tables_default.cfg: -------------------------------------------------------------------------------- 1 | # This file is part of eDisGo, a python package for distribution grid 2 | # analysis and optimization. 3 | # 4 | # It is developed in the project open_eGo: https://openegoproject.wordpress.com 5 | # 6 | # eDisGo lives on github: https://github.com/openego/edisgo/ 7 | # The documentation is available on RTD: https://edisgo.readthedocs.io/en/dev/ 8 | 9 | [data_source] 10 | 11 | oedb_data_source = versioned 12 | 13 | [model_draft] 14 | 15 | conv_generators_prefix = t_ego_supply_conv_powerplant_ 16 | conv_generators_suffix = _mview 17 | re_generators_prefix = t_ego_supply_res_powerplant_ 18 | re_generators_suffix = _mview 19 | res_feedin_data = EgoRenewableFeedin 20 | load_data = EgoDemandHvmvDemand 21 | load_areas = EgoDemandLoadarea 22 | 23 | #conv_generators_nep2035 = t_ego_supply_conv_powerplant_nep2035_mview 24 | #conv_generators_ego100 = ego_supply_conv_powerplant_ego100_mview 25 | #re_generators_nep2035 = t_ego_supply_res_powerplant_nep2035_mview 26 | #re_generators_ego100 = t_ego_supply_res_powerplant_ego100_mview 27 | 28 | [versioned] 29 | 30 | conv_generators_prefix = t_ego_dp_conv_powerplant_ 31 | conv_generators_suffix = _mview 32 | re_generators_prefix = t_ego_dp_res_powerplant_ 33 | re_generators_suffix = _mview 34 | res_feedin_data = EgoRenewableFeedin 35 | load_data = EgoDemandHvmvDemand 36 | load_areas = EgoDemandLoadarea 37 | 38 | version = v0.4.5 39 | -------------------------------------------------------------------------------- /edisgo/config/config_grid_default.cfg: -------------------------------------------------------------------------------- 1 | # This file is part of eDisGo, a python package for distribution grid 2 | # analysis and optimization. 3 | # 4 | # It is developed in the project open_eGo: https://openegoproject.wordpress.com 5 | # 6 | # eDisGo lives on github: https://github.com/openego/edisgo/ 7 | # The documentation is available on RTD: https://edisgo.readthedocs.io/en/dev/ 8 | 9 | # Config file to specify parameters used when connecting new generators to the grid and 10 | # where to position disconnecting points. 11 | 12 | [geo] 13 | 14 | # WGS84: 4326 15 | srid = 4326 16 | 17 | [grid_connection] 18 | 19 | # branch_detour_factor: 20 | # normally, lines do not go straight from A to B due to obstacles etc. Therefore, a detour factor is used. 21 | # unit: - 22 | branch_detour_factor = 1.3 23 | 24 | # conn_buffer_radius: 25 | # radius used to find connection targets 26 | # unit: m 27 | conn_buffer_radius = 2000 28 | 29 | # conn_buffer_radius_inc: 30 | # radius which is incrementally added to connect_buffer_radius as long as no target is found 31 | # unit: m 32 | conn_buffer_radius_inc = 1000 33 | 34 | # conn_diff_tolerance: 35 | # threshold which is used to determine if 2 objects are on the same position 36 | # unit: - 37 | conn_diff_tolerance = 0.0001 38 | 39 | # Upper limits for nominal capacity in MW at which generators, loads and storage units are 40 | # integrated into a certain voltage level. The voltage levels have the following meaning: 41 | # voltage level 7 = LV grid 42 | # voltage level 6 = LV side of MV-LV station 43 | # voltage level 5 = MV grid 44 | # voltage level 4 = MV side of HV-MS station 45 | # The upper limit of one voltage level at the same time signifies the lower limit of 46 | # the next higher voltage level, i.e. upper limit of voltage limit 7 is lower limit for 47 | # voltage level 6. 48 | upper_limit_voltage_level_7 = 0.1 49 | upper_limit_voltage_level_6 = 0.2 50 | upper_limit_voltage_level_5 = 5.5 51 | upper_limit_voltage_level_4 = 20.0 52 | 53 | # from VDE-AR-N 4100 (VDE-AR-N 4100) Anwendungsregel: 2019-04, table 3 54 | lv_max_voltage_deviation = 0.03 55 | # from VDE-AR-N 4110 (VDE-AR-N 4110) Anwendungsregel: 2023-09, 5.3.2 Zulässige Spannungsänderung 56 | mv_max_voltage_deviation = 0.02 57 | 58 | [disconnecting_point] 59 | 60 | # Positioning of disconnecting points: Can be position at location of most 61 | # balanced load or generation. Choose load, generation, loadgen 62 | position = load 63 | -------------------------------------------------------------------------------- /edisgo/config/config_grid_expansion_default.cfg: -------------------------------------------------------------------------------- 1 | # This file is part of eDisGo, a python package for distribution grid 2 | # analysis and optimization. 3 | # 4 | # It is developed in the project open_eGo: https://openegoproject.wordpress.com 5 | # 6 | # eDisGo lives on github: https://github.com/openego/edisgo/ 7 | # The documentation is available on RTD: https://edisgo.readthedocs.io/en/dev/ 8 | 9 | [grid_expansion_standard_equipment] 10 | 11 | # standard equipment 12 | # ================== 13 | # Standard equipment for grid expansion measures. Source: Rehtanz et. al.: "Verteilnetzstudie für das Land Baden-Württemberg", 2017. 14 | hv_mv_transformer = 40 MVA 15 | mv_lv_transformer = 630 kVA 16 | mv_line_10kv = NA2XS2Y 3x1x185 RM/25 17 | mv_line_20kv = NA2XS2Y 3x1x240 18 | lv_line = NAYY 4x1x150 19 | 20 | [grid_expansion_allowed_voltage_deviations] 21 | 22 | # allowed voltage deviations 23 | # ========================== 24 | 25 | # voltage at HV/MV station's secondary side 26 | # ------------------------------------------ 27 | # hv_mv_trafo_offset: 28 | # offset which is set at HV-MV station 29 | # (pos. if op. voltage is increased, neg. if decreased) 30 | hv_mv_trafo_offset = 0.0 31 | 32 | # hv_mv_trafo_control_deviation: 33 | # control deviation of HV-MV station 34 | # (always pos. in config; pos. or neg. usage depending on case in edisgo) 35 | hv_mv_trafo_control_deviation = 0.0 36 | 37 | # COMBINED MV+LV 38 | # -------------- 39 | # max. allowed voltage rise and drop in case voltage band is not allocated to different 40 | # voltage levels 41 | # (values according to DIN EN 50160) 42 | # caution: offset and control deviation at HV-MV station must be considered in calculations! 43 | mv_lv_max_v_rise = 0.1 44 | mv_lv_max_v_drop = 0.1 45 | 46 | # MV ONLY 47 | # ------- 48 | # max. allowed voltage rise in MV grids 49 | mv_max_v_rise = 0.05 50 | 51 | # max. allowed voltage drop in MV grids 52 | mv_max_v_drop = 0.015 53 | 54 | # LV ONLY 55 | # ------- 56 | # max. allowed voltage rise in LV grids 57 | lv_max_v_rise = 0.035 58 | 59 | # max. allowed voltage rise over MV/LV stations 60 | mv_lv_station_max_v_rise = 0.015 61 | 62 | # max. allowed voltage drop in LV grids 63 | # according to VDE-AR-N 4105 64 | lv_max_v_drop = 0.065 65 | 66 | # max. allowed voltage drop over MV/LV stations 67 | mv_lv_station_max_v_drop = 0.02 68 | 69 | [grid_expansion_load_factors] 70 | 71 | # These are the load factors to use when grid issues in normal grid operation are checked. 72 | # Load factors for n-1 security are set in section grid_expansion_load_factors_n_minus_one. 73 | mv_load_case_transformer = 1.0 74 | mv_load_case_line = 1.0 75 | mv_feed-in_case_transformer = 1.0 76 | mv_feed-in_case_line = 1.0 77 | 78 | lv_load_case_transformer = 1.0 79 | lv_load_case_line = 1.0 80 | lv_feed-in_case_transformer = 1.0 81 | lv_feed-in_case_line = 1.0 82 | 83 | [grid_expansion_load_factors_n_minus_one] 84 | 85 | # These are the load factors to use when n-1 security is checked. Usually, only the 86 | # MV grid components need to be n-1 secure. 87 | # Source: Rehtanz et. al.: "Verteilnetzstudie für das Land Baden-Württemberg", 2017. 88 | 89 | mv_load_case_transformer = 0.5 90 | mv_load_case_line = 0.5 91 | mv_feed-in_case_transformer = 1.0 92 | mv_feed-in_case_line = 1.0 93 | 94 | lv_load_case_transformer = 1.0 95 | lv_load_case_line = 1.0 96 | lv_feed-in_case_transformer = 1.0 97 | lv_feed-in_case_line = 1.0 98 | 99 | # costs 100 | # ============ 101 | 102 | [costs_cables] 103 | 104 | # costs in kEUR/km 105 | # costs for cables without earthwork are taken from [1] (costs for standard 106 | # cables are used here as representative since they have average costs), costs 107 | # including earthwork are taken from [2] 108 | # [1] https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Energie/Unternehmen_Institutionen/Netzentgelte/Anreizregulierung/GA_AnalytischeKostenmodelle.pdf?__blob=publicationFile&v=1 109 | # [2] https://shop.dena.de/fileadmin/denashop/media/Downloads_Dateien/esd/9100_dena-Verteilnetzstudie_Abschlussbericht.pdf 110 | # costs including earthwork costs depend on population density according to [2] 111 | # here "rural" corresponds to a population density of <= 500 people/km² 112 | # and "urban" corresponds to a population density of > 500 people/km² 113 | lv_cable = 9 114 | lv_cable_incl_earthwork_rural = 60 115 | lv_cable_incl_earthwork_urban = 100 116 | mv_cable = 20 117 | mv_cable_incl_earthwork_rural = 80 118 | mv_cable_incl_earthwork_urban = 140 119 | 120 | [costs_transformers] 121 | 122 | # costs in kEUR, source: DENA Verteilnetzstudie 123 | lv = 10 124 | mv = 1000 125 | -------------------------------------------------------------------------------- /edisgo/config/config_opf_julia_default.cfg: -------------------------------------------------------------------------------- 1 | # This file is part of eDisGo, a python package for distribution grid 2 | # analysis and optimization. 3 | # 4 | # It is developed in the project open_eGo: https://openegoproject.wordpress.com 5 | # 6 | # eDisGo lives on github: https://github.com/openego/edisgo/ 7 | # The documentation is available on RTD: https://edisgo.readthedocs.io/en/dev/ 8 | 9 | # This file contains path to julia binary and path to project.toml containing correct julia environment 10 | # julia dir should be in users directory 11 | 12 | [julia_dir] 13 | 14 | julia_bin = julia-1.1.0/bin 15 | -------------------------------------------------------------------------------- /edisgo/config/config_system.cfg: -------------------------------------------------------------------------------- 1 | # This file is part of eDisGo, a python package for distribution grid 2 | # analysis and optimization. 3 | # 4 | # It is developed in the project open_eGo: https://openegoproject.wordpress.com 5 | # 6 | # eDisGo lives on github: https://github.com/openego/edisgo/ 7 | # The documentation is available on RTD: https://edisgo.readthedocs.io/en/dev/ 8 | # 9 | # CAUTION: This is an internal config file, do not modify unless you know what 10 | # you are doing! 11 | 12 | [user_dirs] 13 | 14 | root_dir = .edisgo 15 | config_dir = config 16 | data_dir = data 17 | log_dir = log 18 | output_dir = output 19 | 20 | [system_dirs] 21 | 22 | equipment_dir = equipment 23 | 24 | [equipment] 25 | 26 | equipment_mv_parameters_transformers = equipment-parameters_MV_transformers.csv 27 | equipment_mv_parameters_cables = equipment-parameters_MV_cables.csv 28 | equipment_mv_parameters_overhead_lines = equipment-parameters_MV_overhead_lines.csv 29 | equipment_lv_parameters_transformers = equipment-parameters_LV_transformers.csv 30 | equipment_lv_parameters_cables = equipment-parameters_LV_cables.csv 31 | 32 | [network_parameters] 33 | freq = 50 34 | -------------------------------------------------------------------------------- /edisgo/config/config_timeseries_default.cfg: -------------------------------------------------------------------------------- 1 | # This file is part of eDisGo, a python package for distribution grid 2 | # analysis and optimization. 3 | # 4 | # It is developed in the project open_eGo: https://openegoproject.wordpress.com 5 | # 6 | # eDisGo lives on github: https://github.com/openego/edisgo/ 7 | # The documentation is available on RTD: https://edisgo.readthedocs.io/en/dev/ 8 | 9 | # This file contains relevant data to generate load and feed-in time series. 10 | # Scale factors are used in worst-case scenarios. 11 | # Power factors are used to generate reactive power time series. 12 | 13 | [worst_case_scale_factor] 14 | 15 | # scale factors 16 | # =========================== 17 | # scale factors describe actual power to nominal power ratio of generators and loads in worst-case scenarios 18 | # following values provided by "dena-Verteilnetzstudie. Ausbau- und 19 | # Innovationsbedarf der Stromverteilnetze in Deutschland bis 2030", .p. 98 20 | 21 | # conventional load 22 | # factors taken from "dena-Verteilnetzstudie. Ausbau- und 23 | # Innovationsbedarf der Stromverteilnetze in Deutschland bis 2030", p. 98 24 | mv_feed-in_case_load = 0.15 25 | lv_feed-in_case_load = 0.1 26 | mv_load_case_load = 1.0 27 | lv_load_case_load = 1.0 28 | 29 | # generators 30 | # factors taken from "dena-Verteilnetzstudie. Ausbau- und 31 | # Innovationsbedarf der Stromverteilnetze in Deutschland bis 2030", p. 98 32 | feed-in_case_feed-in_pv = 0.85 33 | feed-in_case_feed-in_wind = 1.0 34 | feed-in_case_feed-in_other = 1.0 35 | load_case_feed-in_pv = 0.0 36 | load_case_feed-in_wind = 0.0 37 | load_case_feed-in_other = 0.0 38 | 39 | # storage units (own values) 40 | feed-in_case_storage = 1.0 41 | load_case_storage = -1.0 42 | 43 | # charging points (temporary own values) 44 | 45 | # simultaneity in feed-in case is in dena study "Integrierte Energiewende" (p. 90) as well assumed to be zero 46 | mv_feed-in_case_cp_home = 0.0 47 | mv_feed-in_case_cp_work = 0.0 48 | mv_feed-in_case_cp_public = 0.0 49 | mv_feed-in_case_cp_hpc = 0.0 50 | 51 | lv_feed-in_case_cp_home = 0.0 52 | lv_feed-in_case_cp_work = 0.0 53 | lv_feed-in_case_cp_public = 0.0 54 | lv_feed-in_case_cp_hpc = 0.0 55 | 56 | # simultaneity in load case should be dependent on number of charging points in the grid 57 | # as well as charging power 58 | # assumed factors for home and work charging higher for LV, as simultaneity of charging 59 | # decreases with the number of charging points 60 | 61 | # simultaneity of 0.2 follows assumptions from dena study "Integrierte Energiewende" (p. 90) where 62 | # simultaneity for 70-500 charging points lies around 20% 63 | mv_load_case_cp_home = 0.2 64 | mv_load_case_cp_work = 0.2 65 | mv_load_case_cp_public = 1.0 66 | mv_load_case_cp_hpc = 1.0 67 | 68 | lv_load_case_cp_home = 1.0 69 | lv_load_case_cp_work = 1.0 70 | lv_load_case_cp_public = 1.0 71 | lv_load_case_cp_hpc = 1.0 72 | 73 | # heat pumps (temporary own values) 74 | 75 | # simultaneity in feed-in case is in dena study "Integrierte Energiewende" (p. 90) as well assumed to be zero 76 | mv_feed-in_case_hp = 0.0 77 | lv_feed-in_case_hp = 0.0 78 | 79 | # simultaneity in load case should be dependent on number of heat pumps in the grid 80 | # simultaneity of 0.8 follows assumptions from dena study "Integrierte Energiewende" (p. 90) where 81 | # simultaneity for 70-500 heat pumps lies around 80% 82 | mv_load_case_hp = 0.8 83 | lv_load_case_hp = 1.0 84 | 85 | [reactive_power_factor] 86 | 87 | # power factors 88 | # =========================== 89 | # power factors used to generate reactive power time series for loads and generators 90 | 91 | mv_generator = 0.9 92 | mv_conventional_load = 0.9 93 | mv_storage_unit = 0.9 94 | mv_charging_point = 1.0 95 | mv_heat_pump = 1.0 96 | lv_generator = 0.95 97 | lv_conventional_load = 0.95 98 | lv_storage_unit = 0.95 99 | lv_charging_point = 1.0 100 | lv_heat_pump = 1.0 101 | 102 | [reactive_power_mode] 103 | 104 | # power factor modes 105 | # =========================== 106 | # power factor modes used to generate reactive power time series for loads and generators 107 | 108 | mv_generator = inductive 109 | mv_conventional_load = inductive 110 | mv_storage_unit = inductive 111 | mv_charging_point = inductive 112 | mv_heat_pump = inductive 113 | lv_generator = inductive 114 | lv_conventional_load = inductive 115 | lv_storage_unit = inductive 116 | lv_charging_point = inductive 117 | lv_heat_pump = inductive 118 | 119 | [demandlib] 120 | 121 | # demandlib data 122 | # =========================== 123 | # data used in the demandlib to generate industrial load profile 124 | # see IndustrialProfile in https://github.com/oemof/demandlib/blob/master/demandlib/particular_profiles.py 125 | # for further information 126 | 127 | # scaling factors for night and day of weekdays and weekend days 128 | week_day = 0.8 129 | week_night = 0.6 130 | weekend_day = 0.6 131 | weekend_night = 0.6 132 | holiday_day = 0.6 133 | holiday_night = 0.6 134 | # tuple specifying the beginning/end of a workday (e.g. 18:00) 135 | day_start = 6:00 136 | day_end = 22:00 137 | -------------------------------------------------------------------------------- /edisgo/equipment/equipment-parameters_LV_cables.csv: -------------------------------------------------------------------------------- 1 | name,U_n,I_max_th,R_per_km,L_per_km,C_per_km 2 | #-,kV,kA,ohm/km,mH/km,uF/km 3 | NAYY 4x1x300,0.4,0.419,0.1,0.279,0 4 | NAYY 4x1x240,0.4,0.364,0.125,0.254,0 5 | NAYY 4x1x185,0.4,0.313,0.164,0.256,0 6 | NAYY 4x1x150,0.4,0.275,0.206,0.256,0 7 | NAYY 4x1x120,0.4,0.245,0.253,0.256,0 8 | NAYY 4x1x95,0.4,0.215,0.320,0.261,0 9 | NAYY 4x1x50,0.4,0.144,0.449,0.270,0 10 | NAYY 4x1x35,0.4,0.123,0.868,0.271,0 11 | -------------------------------------------------------------------------------- /edisgo/equipment/equipment-parameters_LV_transformers.csv: -------------------------------------------------------------------------------- 1 | name,S_nom,u_kr,P_k 2 | #,MVA,%,MW 3 | 100 kVA,0.1,4,0.00175 4 | 160 kVA,0.16,4,0.00235 5 | 250 kVA,0.25,4,0.00325 6 | 400 kVA,0.4,4,0.0046 7 | 630 kVA,0.63,4,0.0065 8 | 800 kVA,0.8,6,0.0084 9 | 1000 kVA,1.0,6,0.00105 10 | -------------------------------------------------------------------------------- /edisgo/equipment/equipment-parameters_MV_cables.csv: -------------------------------------------------------------------------------- 1 | name,U_n,I_max_th,R_per_km,L_per_km,C_per_km 2 | #-,kV,kA,ohm/km,mH/km,uF/km 3 | NA2XS2Y 3x1x185 RM/25,10,0.357,0.164,0.38,0.41 4 | NA2XS2Y 3x1x240 RM/25,10,0.417,0.125,0.36,0.47 5 | NA2XS2Y 3x1x300 RM/25,10,0.466,0.1,0.35,0.495 6 | NA2XS2Y 3x1x400 RM/35,10,0.535,0.078,0.34,0.57 7 | NA2XS2Y 3x1x500 RM/35,10,0.609,0.061,0.32,0.63 8 | NA2XS2Y 3x1x150 RE/25,20,0.319,0.206,0.4011,0.24 9 | NA2XS2Y 3x1x240,20,0.417,0.13,0.3597,0.304 10 | NA2XS(FL)2Y 3x1x300 RM/25,20,0.476,0.1,0.37,0.25 11 | NA2XS(FL)2Y 3x1x400 RM/35,20,0.525,0.078,0.36,0.27 12 | NA2XS(FL)2Y 3x1x500 RM/35,20,0.598,0.06,0.34,0.3 13 | -------------------------------------------------------------------------------- /edisgo/equipment/equipment-parameters_MV_overhead_lines.csv: -------------------------------------------------------------------------------- 1 | name,U_n,I_max_th,R_per_km,L_per_km,C_per_km 2 | #-,kV,kA,ohm/km,mH/km,uF/km 3 | 48-AL1/8-ST1A,10,0.21,0.35,1.11,0.0104 4 | 94-AL1/15-ST1A,10,0.35,0.33,1.05,0.0112 5 | 122-AL1/20-ST1A,10,0.41,0.31,0.99,0.0115 6 | 48-AL1/8-ST1A,20,0.21,0.37,1.18,0.0098 7 | 94-AL1/15-ST1A,20,0.35,0.35,1.11,0.0104 8 | 122-AL1/20-ST1A,20,0.41,0.34,1.08,0.0106 9 | -------------------------------------------------------------------------------- /edisgo/equipment/equipment-parameters_MV_transformers.csv: -------------------------------------------------------------------------------- 1 | name,S_nom 2 | #,MVA 3 | 20 MVA,20 4 | 32 MVA,32 5 | 40 MVA,40 6 | 63 MVA,63 7 | -------------------------------------------------------------------------------- /edisgo/equipment/equipment_data.meta: -------------------------------------------------------------------------------- 1 | {"equipment_mv_parameters_trafos": "equipment-parameters_MV_transformers.csv", "equipment_mv_parameters_cables": "equipment-parameters_MV_cables.csv", "equipment_mv_parameters_lines": "equipment-parameters_MV_overhead_lines.csv", "equipment_lv_parameters_trafos": "equipment-parameters_LV_transformers.csv", "equipment_lv_parameters_cables": "equipment-parameters_LV_cables.csv", "Notes": "Note that only values used for calculation are saved in this table, for more values look into source. Only insert literature values here, calculations in code for better comprehensibility.", "Sources": {"LV_transformers": "Torsten Werth, Netzberechnung mit Erzeugungsprofilen- Grundlagen, Berechnung, Anwendung, Springer,2016", "LV_cables": "FaberKabel Starkstromkabel NAYY-J/-O nach VDE 0276-603"}} 2 | -------------------------------------------------------------------------------- /edisgo/flex_opt/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/edisgo/flex_opt/__init__.py -------------------------------------------------------------------------------- /edisgo/flex_opt/exceptions.py: -------------------------------------------------------------------------------- 1 | class Error(Exception): 2 | """Base class for exceptions in this module.""" 3 | 4 | pass 5 | 6 | 7 | class MaximumIterationError(Error): 8 | """ 9 | Exception raised when maximum number of iterations in network reinforcement 10 | is exceeded. 11 | 12 | Attributes 13 | ----------- 14 | message : str 15 | Explanation of the error 16 | 17 | """ 18 | 19 | def __init__(self, message): 20 | self.message = message 21 | 22 | 23 | class ImpossibleVoltageReduction(Error): 24 | """ 25 | Exception raised when voltage issue cannot be solved. 26 | 27 | Attributes 28 | ----------- 29 | message : str 30 | Explanation of the error 31 | 32 | """ 33 | 34 | def __init__(self, message): 35 | self.message = message 36 | 37 | 38 | class InfeasibleModelError(Error): 39 | """ 40 | Exception raised when OPF can not be solved. 41 | 42 | Attributes 43 | ----------- 44 | message : str 45 | Explanation of the error 46 | 47 | """ 48 | 49 | def __init__(self, message): 50 | self.message = message 51 | -------------------------------------------------------------------------------- /edisgo/flex_opt/heat_pump_operation.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import pandas as pd 4 | 5 | logger = logging.getLogger("edisgo") 6 | 7 | 8 | def operating_strategy( 9 | edisgo_obj, 10 | strategy="uncontrolled", 11 | heat_pump_names=None, 12 | ): 13 | """ 14 | Applies operating strategy to set electrical load time series of heat pumps. 15 | 16 | See :attr:`~.edisgo.EDisGo.apply_heat_pump_operating_strategy` for more information. 17 | 18 | Parameters 19 | ---------- 20 | edisgo_obj : :class:`~.EDisGo` 21 | strategy : str 22 | Defines the operating strategy to apply. See `strategy` parameter in 23 | :attr:`~.edisgo.EDisGo.apply_heat_pump_operating_strategy` for more information. 24 | Default: 'uncontrolled'. 25 | heat_pump_names : list(str) or None 26 | Defines for which heat pumps to apply operating strategy. See `heat_pump_names` 27 | parameter in :attr:`~.edisgo.EDisGo.apply_heat_pump_operating_strategy` for 28 | more information. Default: None. 29 | 30 | """ 31 | if heat_pump_names is None: 32 | heat_pump_names = edisgo_obj.heat_pump.cop_df.columns 33 | 34 | if strategy == "uncontrolled": 35 | ts = ( 36 | edisgo_obj.heat_pump.heat_demand_df.loc[:, heat_pump_names] 37 | / edisgo_obj.heat_pump.cop_df.loc[:, heat_pump_names] 38 | ) 39 | edisgo_obj.timeseries.add_component_time_series( 40 | "loads_active_power", 41 | ts, 42 | ) 43 | else: 44 | raise ValueError( 45 | f"Heat pump operating strategy {strategy} is not a valid option. " 46 | f"The only operating strategy currently implemented is 'uncontrolled'." 47 | ) 48 | 49 | # set reactive power time series to 0 Mvar 50 | edisgo_obj.timeseries.add_component_time_series( 51 | "loads_reactive_power", 52 | pd.DataFrame( 53 | data=0.0, 54 | index=edisgo_obj.timeseries.timeindex, 55 | columns=heat_pump_names, 56 | ), 57 | ) 58 | 59 | logger.debug(f"Heat pump operating strategy {strategy} completed.") 60 | -------------------------------------------------------------------------------- /edisgo/io/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/edisgo/io/__init__.py -------------------------------------------------------------------------------- /edisgo/io/ding0_import.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pandas as pd 4 | 5 | from pypsa import Network as PyPSANetwork 6 | 7 | from edisgo.network.grids import MVGrid 8 | 9 | if "READTHEDOCS" not in os.environ: 10 | from shapely.wkt import loads as wkt_loads 11 | 12 | import logging 13 | 14 | logger = logging.getLogger(__name__) 15 | 16 | 17 | def import_ding0_grid(path, edisgo_obj, legacy_ding0_grids=True): 18 | """ 19 | Import an eDisGo network topology from 20 | `Ding0 data `_. 21 | 22 | This import method is specifically designed to load network topology data in 23 | the format as `Ding0 `_ provides it via 24 | csv files. 25 | 26 | Parameters 27 | ---------- 28 | path : str 29 | Path to ding0 network csv files. 30 | edisgo_obj : :class:`~.EDisGo` 31 | The eDisGo data container object. 32 | legacy_ding0_grids : bool 33 | Allow import of old ding0 grids. Default: True. 34 | 35 | """ 36 | 37 | def sort_transformer_buses(transformers_df): 38 | """ 39 | Sort buses of inserted transformers in a way that bus1 always 40 | represents secondary side of transformer. 41 | """ 42 | voltage_bus0 = edisgo_obj.topology.buses_df.loc[ 43 | transformers_df.bus0 44 | ].v_nom.values 45 | voltage_bus1 = edisgo_obj.topology.buses_df.loc[ 46 | transformers_df.bus1 47 | ].v_nom.values 48 | transformers_df.loc[ 49 | voltage_bus1 > voltage_bus0, ["bus0", "bus1"] 50 | ] = transformers_df.loc[voltage_bus1 > voltage_bus0, ["bus1", "bus0"]].values 51 | return transformers_df 52 | 53 | def sort_hvmv_transformer_buses(transformers_df): 54 | """ 55 | Sort buses of inserted HV/MV transformers in a way that bus1 always 56 | represents secondary side of transformer. 57 | """ 58 | for transformer in transformers_df.index: 59 | if ( 60 | transformers_df.at[transformer, "bus1"] 61 | in edisgo_obj.topology.buses_df.index 62 | ): 63 | continue 64 | 65 | transformers_df.loc[transformer, ["bus0", "bus1"]] = transformers_df.loc[ 66 | transformer, ["bus1", "bus0"] 67 | ].values 68 | 69 | return transformers_df 70 | 71 | grid = PyPSANetwork() 72 | grid.import_from_csv_folder(path) 73 | 74 | # write dataframes to edisgo_obj 75 | edisgo_obj.topology.buses_df = grid.buses[edisgo_obj.topology.buses_df.columns] 76 | edisgo_obj.topology.lines_df = grid.lines[edisgo_obj.topology.lines_df.columns] 77 | if legacy_ding0_grids: 78 | logger.debug("Use ding0 legacy grid import.") 79 | # rename column peak_load to p_set 80 | grid.loads = grid.loads.drop(columns="p_set").rename( 81 | columns={"peak_load": "p_set"} 82 | ) 83 | # set loads without type information to be conventional loads 84 | # this is done, as older ding0 versions do not provide information on the type 85 | # of load and can be done as these ding0 grids only contain conventional loads 86 | loads_without_type = grid.loads[ 87 | (grid.loads.type.isnull()) | (grid.loads.type == "") 88 | ].index 89 | grid.loads.loc[loads_without_type, "type"] = "conventional_load" 90 | # rename retail to cts, as it is in newer ding0 versions called cts 91 | grid.loads.replace(to_replace=["retail"], value="cts", inplace=True) 92 | # set up columns that are added in new ding0 version 93 | grid.loads["building_id"] = None 94 | grid.loads["number_households"] = None 95 | grid.generators["source_id"] = None 96 | else: 97 | edisgo_obj.topology.buses_df["in_building"] = False 98 | grid.generators = grid.generators.rename(columns={"gens_id": "source_id"}) 99 | edisgo_obj.topology.loads_df = grid.loads[edisgo_obj.topology.loads_df.columns] 100 | # drop slack generator from generators 101 | slack = grid.generators.loc[grid.generators.control == "Slack"].index 102 | grid.generators.drop(slack, inplace=True) 103 | edisgo_obj.topology.generators_df = grid.generators[ 104 | edisgo_obj.topology.generators_df.columns 105 | ] 106 | edisgo_obj.topology.storage_units_df = grid.storage_units[ 107 | edisgo_obj.topology.storage_units_df.columns 108 | ] 109 | edisgo_obj.topology.transformers_df = sort_transformer_buses( 110 | grid.transformers.drop(labels=["x_pu", "r_pu"], axis=1).rename( 111 | columns={"r": "r_pu", "x": "x_pu"} 112 | )[edisgo_obj.topology.transformers_df.columns] 113 | ) 114 | edisgo_obj.topology.transformers_hvmv_df = sort_hvmv_transformer_buses( 115 | pd.read_csv(os.path.join(path, "transformers_hvmv.csv"), index_col=[0]).rename( 116 | columns={"r": "r_pu", "x": "x_pu"} 117 | ) 118 | ) 119 | edisgo_obj.topology.switches_df = pd.read_csv( 120 | os.path.join(path, "switches.csv"), index_col=[0] 121 | ) 122 | 123 | edisgo_obj.topology.grid_district = { 124 | "population": grid.mv_grid_district_population, 125 | "geom": wkt_loads(grid.mv_grid_district_geom), 126 | "srid": grid.srid, 127 | } 128 | 129 | # set up medium voltage grid 130 | mv_grid_id = list(set(grid.buses.mv_grid_id))[0] 131 | edisgo_obj.topology.mv_grid = MVGrid(id=mv_grid_id, edisgo_obj=edisgo_obj) 132 | 133 | # check data integrity 134 | edisgo_obj.topology.check_integrity() 135 | -------------------------------------------------------------------------------- /edisgo/network/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/edisgo/network/__init__.py -------------------------------------------------------------------------------- /edisgo/opf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/edisgo/opf/__init__.py -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/Main.jl: -------------------------------------------------------------------------------- 1 | cd(dirname(@__FILE__)) 2 | using Pkg 3 | Pkg.activate("") 4 | Pkg.instantiate() 5 | try 6 | using eDisGo_OPF 7 | using PowerModels 8 | using Ipopt 9 | using JuMP 10 | using JSON 11 | using Gurobi 12 | catch e 13 | Pkg.instantiate() 14 | using eDisGo_OPF 15 | using PowerModels 16 | using Ipopt 17 | using JuMP 18 | using JSON 19 | using Gurobi 20 | end 21 | 22 | 23 | 24 | PowerModels.logger_config!("debug") 25 | json_str = readline(stdin) 26 | ding0_grid = ARGS[1] 27 | results_path = ARGS[2] 28 | method = ARGS[3] 29 | silence_moi = ARGS[4].=="True" 30 | warm_start = ARGS[5].=="True" 31 | 32 | # Set solver attributes 33 | const ipopt = optimizer_with_attributes(Ipopt.Optimizer, MOI.Silent() => silence_moi, "sb" => "yes", "tol"=>1e-6) 34 | function optimize_edisgo() 35 | # read in data and create multinetwork 36 | gurobi = optimizer_with_attributes(Gurobi.Optimizer, MOI.Silent() => silence_moi, "FeasibilityTol"=>1e-4, "BarQCPConvTol"=>1e-4, "BarConvTol"=>1e-4, "BarHomogeneous"=>1) 37 | data_edisgo = eDisGo_OPF.parse_json(json_str) 38 | data_edisgo_mn = PowerModels.make_multinetwork(data_edisgo) 39 | 40 | if method == "soc" # Second order cone 41 | # Solve SOC model 42 | println("Starting convex SOC AC-OPF with Gurobi.") 43 | result_soc, pm = eDisGo_OPF.solve_mn_opf_bf_flex(data_edisgo_mn, SOCBFPowerModelEdisgo, gurobi) 44 | #println("Termination status: "*result_soc["termination_status"]) 45 | if result_soc["termination_status"] != MOI.OPTIMAL 46 | # if result_soc["termination_status"] == MOI.SUBOPTIMAL_TERMINATION 47 | # PowerModels.update_data!(data_edisgo_mn, result_soc["solution"]) 48 | # else 49 | JuMP.compute_conflict!(pm.model) 50 | if MOI.get(pm.model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND 51 | iis_model, _ = copy_conflict(pm.model) 52 | print(iis_model) 53 | end 54 | #end 55 | elseif result_soc["termination_status"] == MOI.OPTIMAL 56 | # Check if SOC constraint is tight 57 | soc_tight, soc_dict = eDisGo_OPF.check_SOC_equality(result_soc, data_edisgo) 58 | # Save SOC violations if SOC is not tight 59 | if !soc_tight 60 | open(joinpath(results_path, ding0_grid*"_"*join(data_edisgo["flexibilities"])*".json"), "w") do f 61 | write(f, JSON.json(soc_dict)) 62 | end 63 | println("SOC solution is not tight!") 64 | end 65 | PowerModels.update_data!(data_edisgo_mn, result_soc["solution"]) 66 | data_edisgo_mn["solve_time"] = result_soc["solve_time"] 67 | data_edisgo_mn["status"] = result_soc["termination_status"] 68 | data_edisgo_mn["solver"] = "Gurobi" 69 | if soc_tight & warm_start 70 | println("Starting warm-start non-convex AC-OPF with IPOPT.") 71 | set_ac_bf_start_values!(data_edisgo_mn["nw"]["1"]) 72 | result_nc_ws, pm = eDisGo_OPF.solve_mn_opf_bf_flex(data_edisgo_mn, NCBFPowerModelEdisgo, ipopt) 73 | PowerModels.update_data!(data_edisgo_mn, result_nc_ws["solution"]) 74 | data_edisgo_mn["solve_time"] = result_nc_ws["solve_time"] 75 | data_edisgo_mn["status"] = result_nc_ws["termination_status"] 76 | data_edisgo_mn["solver"] = "Ipopt" 77 | end 78 | end 79 | elseif method == "nc" # Non-Convex 80 | # Solve NC model 81 | println("Starting cold-start non-convex AC-OPF with IPOPT.") 82 | result, pm = eDisGo_OPF.solve_mn_opf_bf_flex(data_edisgo_mn, NCBFPowerModelEdisgo, ipopt) 83 | PowerModels.update_data!(data_edisgo_mn, result["solution"]) 84 | data_edisgo_mn["solve_time"] = result["solve_time"] 85 | data_edisgo_mn["status"] = result["termination_status"] 86 | data_edisgo_mn["solver"] = "Ipopt" 87 | end 88 | 89 | # Update network data with optimization results and print to stdout 90 | print(JSON.json(data_edisgo_mn)) 91 | end 92 | 93 | if abspath(PROGRAM_FILE) == @__FILE__ 94 | optimize_edisgo() 95 | end 96 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/Project.toml: -------------------------------------------------------------------------------- 1 | name = "eDisGo_OPF" 2 | uuid = "8c767188-7e8f-4256-9955-fc0aecae9b11" 3 | authors = ["Maike Held"] 4 | version = "0.1.0" 5 | 6 | [deps] 7 | Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" 8 | Gurobi = "2e9cd046-0924-5485-92f1-d5272153d98b" 9 | IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" 10 | InfrastructureModels = "2030c09a-7f63-5d83-885d-db604e0e9cc0" 11 | Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" 12 | JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 13 | JuMP = "4076af6c-e467-56ae-b986-b466b2749572" 14 | Memento = "f28f55f0-a522-5efc-85c2-fe41dfb9b2d9" 15 | #Mosek = "6405355b-0ac2-5fba-af84-adbd65488c0e" 16 | #MosekTools = "1ec41992-ff65-5c91-ac43-2df89e9693a4" 17 | PowerModels = "c36e90e8-916a-50a6-bd94-075b64ef4655" 18 | 19 | [compat] 20 | PowerModels = "0.19.6" 21 | julia = "1.6" 22 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/core/constraint.jl: -------------------------------------------------------------------------------- 1 | """ Creates constraints for storage operations (battery, heat, DSM)""" 2 | 3 | function constraint_store_state_initial(pm::AbstractBFModelEdisgo, n::Int, i::Int, energy, charge_eff, discharge_eff, time_elapsed, kind, p_loss) 4 | if kind == "storage" 5 | ps_1 = PowerModels.var(pm, n, :ps, i) 6 | se = PowerModels.var(pm, n, :se, i) 7 | se_end = PowerModels.var(pm, length(PowerModels.nw_ids(pm)), :se, i) 8 | soc_initial = PowerModels.ref(pm, n, :storage)[i]["soc_initial"] 9 | soc_end = PowerModels.ref(pm, n, :storage)[i]["soc_end"] 10 | JuMP.@constraint(pm.model, se - soc_initial == - time_elapsed * ps_1) # Eq. (3.10) i.V.m. Eq. (3.9) für t = 1 bzw. = 0 11 | JuMP.@constraint(pm.model, se_end == soc_end) # Eq. (3.9) für t = tau 12 | elseif kind == "heat_storage" 13 | phs_1 = PowerModels.var(pm, n, :phs, i) 14 | hse = PowerModels.var(pm, n, :hse, i) 15 | hse_end = PowerModels.var(pm, length(PowerModels.nw_ids(pm)), :hse, i) 16 | soc_initial = PowerModels.ref(pm, n, :heat_storage)[i]["soc_initial"] 17 | soc_end = PowerModels.ref(pm, n, :heat_storage)[i]["soc_end"] 18 | JuMP.@constraint(pm.model, hse - soc_initial == - time_elapsed * phs_1) # Eq. (3.23) i.V.m. Eq. (3.22) (t=1) 19 | JuMP.@constraint(pm.model, hse_end == soc_end) # Eq. (3.22) für t = tau 20 | elseif kind == "dsm" 21 | dsme = PowerModels.var(pm, n, :dsme, i) 22 | dsme_end = PowerModels.var(pm, length(PowerModels.nw_ids(pm)), :dsme, i) 23 | pdsm_1 = PowerModels.var(pm, n, :pdsm, i) 24 | JuMP.@constraint(pm.model, dsme - energy == + time_elapsed * pdsm_1) # Eq. (3.33) für t=1 (und Eq. (3.32) für t = 0, da energy=e(0) = 0) 25 | JuMP.@constraint(pm.model, dsme_end == 0) # Eq. (3.32) für t = tau 26 | end 27 | end 28 | 29 | 30 | function constraint_store_state(pm::AbstractBFModelEdisgo, n_1::Int, n_2::Int, i::Int, charge_eff, discharge_eff, time_elapsed, kind, p_loss) 31 | if kind == "storage" 32 | ps_2 = PowerModels.var(pm, n_2, :ps, i) 33 | se_2 = PowerModels.var(pm, n_2, :se, i) 34 | se_1 = PowerModels.var(pm, n_1, :se, i) 35 | 36 | JuMP.@constraint(pm.model, se_2 - se_1 == - time_elapsed*ps_2) # Eq. (3.10) 37 | elseif kind == "heat_storage" 38 | phs_2 = PowerModels.var(pm, n_2, :phs, i) 39 | hse_2 = PowerModels.var(pm, n_2, :hse, i) 40 | hse_1 = PowerModels.var(pm, n_1, :hse, i) 41 | 42 | JuMP.@constraint(pm.model, hse_2 - hse_1 * (1 - p_loss)^(1/24) == - time_elapsed*phs_2) # Eq. (3.23) 43 | elseif kind == "dsm" 44 | pdsm_2 = PowerModels.var(pm, n_2, :pdsm, i) 45 | dsme_2 = PowerModels.var(pm, n_2, :dsme, i) 46 | dsme_1 = PowerModels.var(pm, n_1, :dsme, i) 47 | 48 | JuMP.@constraint(pm.model, dsme_2 - dsme_1 == time_elapsed*pdsm_2) # Eq. (3.33) 49 | end 50 | end 51 | 52 | """ Creates constraints for EV charging per charging park""" 53 | 54 | function constraint_cp_state_initial(pm::AbstractBFModelEdisgo, n::Int, i::Int, eta) 55 | if haskey(PowerModels.ref(pm, n), :time_elapsed) 56 | time_elapsed = PowerModels.ref(pm, n, :time_elapsed) 57 | else 58 | Memento.warn(_LOGGER, "network data should specify time_elapsed, using 1.0 as a default") 59 | time_elapsed = 1.0 60 | end 61 | 62 | cp = PowerModels.ref(pm, n, :electromobility, i) 63 | cpe = PowerModels.var(pm, n, :cpe, i) 64 | pcp_1 = PowerModels.var(pm, n, :pcp, i) 65 | JuMP.@constraint(pm.model, cpe == 0.5*(cp["e_min"]+cp["e_max"]) + time_elapsed * eta * pcp_1) # Eq. (3.25) 66 | 67 | end 68 | 69 | function constraint_cp_state(pm::AbstractBFModelEdisgo, n_1::Int, n_2::Int, i::Int, eta) 70 | if haskey(PowerModels.ref(pm, n_1), :time_elapsed) 71 | time_elapsed = PowerModels.ref(pm, n_1, :time_elapsed) 72 | else 73 | Memento.warn(_LOGGER, "network data should specify time_elapsed, using 1.0 as a default") 74 | time_elapsed = 1.0 75 | end 76 | 77 | pcp_2 = PowerModels.var(pm, n_2, :pcp, i) 78 | cpe_2 = PowerModels.var(pm, n_2, :cpe, i) 79 | cpe_1 = PowerModels.var(pm, n_1, :cpe, i) 80 | 81 | JuMP.@constraint(pm.model, cpe_2 - cpe_1 == time_elapsed * eta * pcp_2) # Eq. (3.26) 82 | 83 | if n_2 == length(collect(PowerModels.nw_ids(pm))) 84 | cp = PowerModels.ref(pm, length(collect(PowerModels.nw_ids(pm))), :electromobility, i) 85 | JuMP.@constraint(pm.model, cpe_2 == 0.5*(cp["e_min"]+cp["e_max"])) # Eq. (3.25) für t=tau 86 | end 87 | end 88 | 89 | """ Creates constraints for heat pump operation""" 90 | 91 | function constraint_hp_operation(pm::AbstractBFModelEdisgo, i::Int, nw::Int=nw_id_default) 92 | hp = PowerModels.ref(pm, nw, :heatpumps, i) 93 | php = PowerModels.var(pm, nw, :php, i) 94 | phs = PowerModels.var(pm, nw, :phs, i) 95 | phss = PowerModels.var(pm, nw, :phss, i) 96 | phps2 = PowerModels.var(pm, nw, :phps2, i) 97 | 98 | 99 | JuMP.@constraint(pm.model, hp["cop"] * (php+phps2) == hp["pd"] + phss - phs) 100 | 101 | end 102 | 103 | """ Creates constraints for high voltage grid requirements""" 104 | 105 | function constraint_HV_requirements(pm::AbstractBFModelEdisgo, i::Int, nw::Int=nw_id_default) 106 | hv_req = PowerModels.ref(pm, nw, :HV_requirements, i) 107 | phvs = PowerModels.var(pm, nw, :phvs, i) 108 | 109 | if hv_req["name"] == "dsm" 110 | pflex = PowerModels.var(pm, nw, :pdsm) 111 | elseif hv_req["name"] == "curt" 112 | pflex = PowerModels.var(pm, nw, :pgc) 113 | elseif hv_req["name"] == "storage" # ToDo: virtual branch p variable instead of ps 114 | # branch = PowerModels.ref(pm, nw, :branch) 115 | # for (i, b) in branch 116 | # if b["storage"] 117 | # Hier die pf Variablen (negativ!) aufsummieren 118 | # end 119 | # end 120 | pflex = PowerModels.var(pm, nw, :ps) 121 | elseif hv_req["name"] == "hp" 122 | pflex = PowerModels.var(pm, nw, :php) 123 | elseif hv_req["name"] == "cp" 124 | pflex = PowerModels.var(pm, nw, :pcp) 125 | end 126 | JuMP.@constraint(pm.model, sum(pflex) + phvs == hv_req["P"]) 127 | 128 | end 129 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/core/constraint_template.jl: -------------------------------------------------------------------------------- 1 | "power balance for radial branch flow model" 2 | function constraint_power_balance_bf(pm::AbstractBFModelEdisgo, i::Int; nw::Int=nw_id_default) 3 | bus_arcs_to = PowerModels.ref(pm, nw, :bus_arcs_to, i) 4 | bus_arcs_from = PowerModels.ref(pm, nw, :bus_arcs_from, i) 5 | bus_lines_to = PowerModels.ref(pm, nw, :bus_lines_to, i) 6 | bus_gens = PowerModels.ref(pm, nw, :bus_gens, i) 7 | bus_gens_nd = PowerModels.ref(pm, nw, :bus_gens_nd, i) 8 | bus_gens_slack = PowerModels.ref(pm, nw, :bus_gens_slack, i) 9 | bus_loads = PowerModels.ref(pm, nw, :bus_loads, i) 10 | bus_storage = PowerModels.ref(pm, nw, :bus_storage, i) 11 | bus_dsm = PowerModels.ref(pm, nw, :bus_dsm, i) 12 | bus_hps = PowerModels.ref(pm, nw, :bus_hps, i) 13 | bus_cps = PowerModels.ref(pm, nw, :bus_cps, i) 14 | 15 | 16 | branch_r = Dict(k => PowerModels.ref(pm, nw, :branch, k, "br_r") for k in bus_lines_to) 17 | branch_x = Dict(k => PowerModels.ref(pm, nw, :branch, k, "br_x") for k in bus_lines_to) 18 | branch_strg_pf = Dict(k => PowerModels.ref(pm, nw, :branch, k, "storage_pf") for k in bus_lines_to) 19 | 20 | bus_pg = Dict(k => PowerModels.ref(pm, nw, :gen, k, "pg") for k in bus_gens) 21 | bus_qg = Dict(k => PowerModels.ref(pm, nw, :gen, k, "qg") for k in bus_gens) 22 | 23 | bus_pg_nd = Dict(k => PowerModels.ref(pm, nw, :gen_nd, k, "pg") for k in bus_gens_nd) 24 | bus_qg_nd = Dict(k => PowerModels.ref(pm, nw, :gen_nd, k, "qg") for k in bus_gens_nd) 25 | 26 | bus_pd = Dict(k => PowerModels.ref(pm, nw, :load, k, "pd") for k in bus_loads) 27 | bus_qd = Dict(k => PowerModels.ref(pm, nw, :load, k, "qd") for k in bus_loads) 28 | 29 | bus_storage_pf = Dict(k => tan(acos(PowerModels.ref(pm, nw, :storage, k, "pf")))*PowerModels.ref(pm, nw, :storage, k, "sign") for k in bus_storage) 30 | bus_dsm_pf = Dict(k => tan(acos(PowerModels.ref(pm, nw, :dsm, k, "pf")))*PowerModels.ref(pm, nw, :dsm, k, "sign") for k in bus_dsm) 31 | bus_hps_pf = Dict(k => tan(acos(PowerModels.ref(pm, nw, :heatpumps, k, "pf")))*PowerModels.ref(pm, nw, :heatpumps, k, "sign") for k in bus_hps) 32 | bus_cps_pf = Dict(k => tan(acos(PowerModels.ref(pm, nw, :electromobility, k, "pf")))*PowerModels.ref(pm, nw, :electromobility, k, "sign") for k in bus_cps) 33 | bus_gen_nd_pf = Dict(k => tan(acos(PowerModels.ref(pm, nw, :gen_nd, k, "pf")))*PowerModels.ref(pm, nw, :gen_nd, k, "sign") for k in bus_gens_nd) 34 | bus_gen_d_pf = Dict(k => tan(acos(PowerModels.ref(pm, nw, :gen, k, "pf")))*PowerModels.ref(pm, nw, :gen, k, "sign") for k in bus_gens) 35 | bus_loads_pf = Dict(k => tan(acos(PowerModels.ref(pm, nw, :load, k, "pf")))*PowerModels.ref(pm, nw, :load, k, "sign") for k in bus_loads) 36 | 37 | constraint_power_balance(pm, nw, i, bus_gens, bus_gens_nd, bus_gens_slack, bus_loads, bus_arcs_to, bus_arcs_from, bus_lines_to, bus_storage, bus_pg, bus_qg, bus_pg_nd, bus_qg_nd, bus_pd, bus_qd, branch_r, branch_x, bus_dsm, bus_hps, bus_cps, bus_storage_pf, bus_dsm_pf, bus_hps_pf, bus_cps_pf, bus_gen_nd_pf, bus_gen_d_pf, bus_loads_pf, branch_strg_pf) 38 | end 39 | 40 | "" 41 | function constraint_voltage_magnitude_difference_radial(pm::AbstractBFModelEdisgo, i::Int; nw::Int=nw_id_default) 42 | branch = PowerModels.ref(pm, nw, :branch, i) 43 | f_bus = branch["f_bus"] 44 | t_bus = branch["t_bus"] 45 | f_idx = (i, f_bus, t_bus) 46 | t_idx = (i, t_bus, f_bus) 47 | 48 | r = branch["br_r"] 49 | x = branch["br_x"] 50 | tm = branch["tap"] 51 | if !(branch["storage"]) 52 | constraint_voltage_magnitude_difference(pm, nw, i, f_bus, t_bus, f_idx, t_idx, r, x, tm) 53 | end 54 | end 55 | 56 | function constraint_store_state(pm::AbstractBFModelEdisgo, i::Int; nw::Int=nw_id_default, kind::String) 57 | storage = PowerModels.ref(pm, nw, Symbol(kind), i) 58 | 59 | if kind == "dsm" 60 | p_loss = 0 61 | elseif kind in("storage", "heat_storage") 62 | p_loss = storage["p_loss"] 63 | end 64 | 65 | if haskey(PowerModels.ref(pm, nw), :time_elapsed) 66 | time_elapsed = PowerModels.ref(pm, nw, :time_elapsed) 67 | else 68 | Memento.warn(_LOGGER, "network data should specify time_elapsed, using 1.0 as a default") 69 | time_elapsed = 1.0 70 | end 71 | 72 | constraint_store_state_initial(pm, nw, i, storage["energy"], storage["charge_efficiency"], storage["discharge_efficiency"], time_elapsed, kind, p_loss) 73 | end 74 | 75 | "" 76 | function constraint_store_state(pm::AbstractBFModelEdisgo, i::Int, nw_1::Int, nw_2::Int, kind::String) 77 | storage = PowerModels.ref(pm, nw_2, Symbol(kind), i) 78 | 79 | if kind == "dsm" 80 | p_loss = 0 81 | elseif kind in("storage", "heat_storage") 82 | p_loss = storage["p_loss"] 83 | end 84 | 85 | if haskey(PowerModels.ref(pm, nw_2), :time_elapsed) 86 | time_elapsed = PowerModels.ref(pm, nw_2, :time_elapsed) 87 | else 88 | Memento.warn(_LOGGER, "network $(nw_2) should specify time_elapsed, using 1.0 as a default") 89 | time_elapsed = 1.0 90 | end 91 | 92 | if haskey(PowerModels.ref(pm, nw_1, Symbol(kind)), i) 93 | constraint_store_state(pm, nw_1, nw_2, i, storage["charge_efficiency"], storage["discharge_efficiency"], time_elapsed, kind, p_loss) 94 | else 95 | # if the storage device has status=0 in nw_1, then the stored energy variable will not exist. Initialize storage from data model instead. 96 | Memento.warn(_LOGGER, "storage component $(i) was not found in network $(nw_1) while building constraint_storage_state between networks $(nw_1) and $(nw_2). Using the energy value from the storage component in network $(nw_2) instead") 97 | constraint_store_state_initial(pm, nw_2, i, storage["energy"], storage["charge_efficiency"], storage["discharge_efficiency"], time_elapsed, kind, p_loss) 98 | end 99 | end 100 | 101 | function constraint_model_current(pm::AbstractPowerModel; nw::Int=nw_id_default) 102 | eDisGo_OPF.constraint_model_current(pm, nw) 103 | end 104 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/core/data.jl: -------------------------------------------------------------------------------- 1 | function set_ac_bf_start_values!(network::Dict{String,<:Any}) 2 | 3 | for (i,gen) in network["gen_nd"] 4 | gen["pgc_start"] = gen["pgc"] 5 | end 6 | 7 | for (i,gen) in network["gen_slack"] 8 | gen["pgs_start"] = gen["pgs"] 9 | gen["qgs_start"] = gen["qgs"] 10 | end 11 | 12 | for (i,dsm) in network["dsm"] 13 | dsm["pdsm_start"] = dsm["pdsm"] 14 | dsm["dsme_start"] = dsm["dsme"] 15 | end 16 | 17 | for (i,s) in network["storage"] 18 | s["ps_start"] = s["ps"] 19 | s["se_start"] = s["se"] 20 | end 21 | 22 | for (i,cp) in network["electromobility"] 23 | cp["pcp_start"] = cp["pcp"] 24 | end 25 | 26 | for (i,hp) in network["heatpumps"] 27 | hp["php_start"] = hp["php"] 28 | end 29 | 30 | for (i,hs) in network["heat_storage"] 31 | hs["phs_start"] = hs["phs"] 32 | hs["hse_start"] = hs["hse"] 33 | end 34 | 35 | end 36 | 37 | """ 38 | checks bus types are suitable for a power flow study, if not, fixes them. 39 | 40 | the primary checks are that all type 2 buses (i.e., PV) have a connected and 41 | active generator and there is a single type 3 bus (i.e., slack bus) with an 42 | active connected generator. 43 | 44 | assumes that the network is a single connected component 45 | """ 46 | function correct_bus_types!(data::Dict{String,<:Any}) 47 | apply_pm!(eDisGo_OPF._correct_bus_types!, data) 48 | end 49 | 50 | "" 51 | function _correct_bus_types!(pm_data::Dict{String,<:Any}) 52 | bus_gens = Dict(bus["index"] => [] for (i,bus) in pm_data["bus"]) 53 | 54 | for (i,gen) in pm_data["gen"] 55 | if gen["gen_status"] != 0 56 | push!(bus_gens[gen["gen_bus"]], i) 57 | end 58 | end 59 | for (i,gen) in pm_data["gen_nd"] 60 | if gen["gen_status"] != 0 61 | push!(bus_gens[gen["gen_bus"]], i) 62 | end 63 | end 64 | for (i,gen) in pm_data["gen_slack"] 65 | if gen["gen_status"] != 0 66 | push!(bus_gens[gen["gen_bus"]], i) 67 | end 68 | end 69 | 70 | slack_found = false 71 | for (i, bus) in pm_data["bus"] 72 | idx = bus["index"] 73 | if bus["bus_type"] == 1 74 | if length(bus_gens[idx]) != 0 # PQ 75 | #Memento.warn(_LOGGER, "active generators found at bus $(bus["bus_i"]), updating to bus type from $(bus["bus_type"]) to 2") 76 | #bus["bus_type"] = 2 77 | end 78 | elseif bus["bus_type"] == 2 # PV 79 | if length(bus_gens[idx]) == 0 80 | Memento.warn(_LOGGER, "no active generators found at bus $(bus["bus_i"]), updating to bus type from $(bus["bus_type"]) to 1") 81 | bus["bus_type"] = 1 82 | end 83 | elseif bus["bus_type"] == 3 # Slack 84 | if length(bus_gens[idx]) != 0 85 | slack_found = true 86 | else 87 | Memento.warn(_LOGGER, "no active generators found at bus $(bus["bus_i"]), updating to bus type from $(bus["bus_type"]) to 1") 88 | bus["bus_type"] = 1 89 | end 90 | elseif bus["bus_type"] == 4 # inactive bus 91 | # do nothing 92 | else # unknown bus type 93 | new_bus_type = 1 94 | if length(bus_gens[idx]) != 0 95 | new_bus_type = 2 96 | end 97 | Memento.warn(_LOGGER, "bus $(bus["bus_i"]) has an unrecongized bus_type $(bus["bus_type"]), updating to bus_type $(new_bus_type)") 98 | bus["bus_type"] = new_bus_type 99 | end 100 | end 101 | 102 | if !slack_found 103 | gen = _biggest_generator(pm_data["gen"]) 104 | if length(gen) > 0 105 | gen_bus = gen["gen_bus"] 106 | ref_bus = pm_data["bus"]["$(gen_bus)"] 107 | ref_bus["bus_type"] = 3 108 | Memento.warn(_LOGGER, "no reference bus found, setting bus $(gen_bus) as reference based on generator $(gen["index"])") 109 | else 110 | Memento.error(_LOGGER, "no generators found in the given network data, correct_bus_types! requires at least one generator at the reference bus") 111 | end 112 | end 113 | 114 | end 115 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/core/solution.jl: -------------------------------------------------------------------------------- 1 | function sol_component_value_radial(aim::AbstractPowerModel, n::Int, comp_name::Symbol, field_name_to::Symbol, comp_ids_to, variables) 2 | for (l, i, j) in comp_ids_to 3 | @assert !haskey(InfrastructureModels.sol(aim, pm_it_sym, n, comp_name, l), field_name_to) 4 | InfrastructureModels.sol(aim, pm_it_sym, n, comp_name, l)[field_name_to] = variables[(l, i, j)] 5 | end 6 | end 7 | 8 | 9 | function check_SOC_equality(result, data_edisgo) 10 | timesteps = keys(result["solution"]["nw"]) 11 | branches = keys(data_edisgo["branch"]) 12 | branches_wo_storage = [branch for branch in branches if !(data_edisgo["branch"][branch]["storage"])] 13 | branch_f_bus = Dict(k => string(data_edisgo["branch"][k]["f_bus"]) for k in branches_wo_storage) 14 | soc_eq_dict = Dict() 15 | soc_tight = true 16 | for t in timesteps 17 | eq_res = Dict(b => (result["solution"]["nw"][t]["branch"][b]["pf"]^2 18 | + result["solution"]["nw"][t]["branch"][b]["qf"]^2 19 | -result["solution"]["nw"][t]["branch"][b]["ccm"]*result["solution"]["nw"][t]["bus"][branch_f_bus[b]]["w"]) for b in branches_wo_storage) 20 | soc_eq_dict[t]= filter(((k,v),) -> v <-1e-1, eq_res) 21 | if length(keys(soc_eq_dict[t])) > 0 22 | soc_tight = false 23 | end 24 | end 25 | return soc_tight, soc_eq_dict 26 | end 27 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/core/types.jl: -------------------------------------------------------------------------------- 1 | "" 2 | 3 | abstract type AbstractBFModelEdisgo <: AbstractBFQPModel end 4 | 5 | """ 6 | Radial branch flow model (eDisGo implementation) 7 | Applicable to problem formulations with `_bf` in the name. 8 | """ 9 | mutable struct BFPowerModelEdisgo <: AbstractBFModelEdisgo @pm_fields end 10 | 11 | abstract type AbstractSOCBFModelEdisgo <: AbstractBFModelEdisgo end 12 | 13 | """ 14 | Second-order cone relaxation of radial branch flow model (eDisGo implementation). 15 | Applicable to problem formulations with `_bf` in the name. 16 | """ 17 | mutable struct SOCBFPowerModelEdisgo <: AbstractSOCBFModelEdisgo @pm_fields end 18 | 19 | 20 | abstract type AbstractNCBFModelEdisgo <: AbstractBFModelEdisgo end 21 | 22 | """ 23 | Non convex radial branch flow model (eDisGo implementation). 24 | Applicable to problem formulations with `_bf` in the name. 25 | """ 26 | mutable struct NCBFPowerModelEdisgo <: AbstractNCBFModelEdisgo @pm_fields end 27 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/eDisGo_OPF.jl: -------------------------------------------------------------------------------- 1 | module eDisGo_OPF 2 | 3 | using PowerModels 4 | using InfrastructureModels 5 | using Memento 6 | using JuMP 7 | using Ipopt 8 | using JSON 9 | using Compat 10 | using Gurobi 11 | 12 | const _pm_global_keys = Set(["time_series", "per_unit"]) 13 | const pm_it_name = "pm" 14 | const pm_it_sym = Symbol(pm_it_name) 15 | 16 | # include functions extending PowerModels functions 17 | include("core/types.jl") 18 | include("core/base.jl") 19 | include("core/constraint.jl") 20 | include("core/constraint_template.jl") 21 | include("core/data.jl") 22 | include("core/objective.jl") 23 | include("core/solution.jl") 24 | include("core/variables.jl") 25 | include("form/bf.jl") 26 | include("prob/opf_bf.jl") 27 | include("io/common.jl") 28 | include("io/json.jl") 29 | #include("../test/opf_test_case.jl") 30 | 31 | # export new types of PowerModels 32 | export BFPowerModelEdisgo, SOCBFPowerModelEdisgo, NCBFPowerModelEdisgo 33 | 34 | end 35 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/io/common.jl: -------------------------------------------------------------------------------- 1 | function correct_network_data!(data::Dict{String,<:Any}) 2 | check_conductors(data) 3 | check_connectivity(data) 4 | check_status(data) 5 | # check_reference_bus(data) 6 | make_per_unit!(data) 7 | 8 | correct_transformer_parameters!(data) 9 | correct_voltage_angle_differences!(data) 10 | correct_thermal_limits!(data) 11 | correct_current_limits!(data) 12 | correct_branch_directions!(data) 13 | 14 | check_branch_loops(data) 15 | correct_dcline_limits!(data) 16 | 17 | # data_ep = _IM.ismultiinfrastructure(data) ? data["it"][pm_it_name] : data 18 | 19 | # if length(data_ep["gen"]) > 0 && any(gen["gen_status"] != 0 for (i, gen) in data_ep["gen"]) 20 | # eDisGo_OPF.correct_bus_types!(data) 21 | # end 22 | 23 | check_voltage_setpoints(data) 24 | check_storage_parameters(data) 25 | check_switch_parameters(data) 26 | 27 | correct_cost_functions!(data) 28 | 29 | simplify_cost_terms!(data) 30 | end 31 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/io/json.jl: -------------------------------------------------------------------------------- 1 | "Parses json from iostream or string" 2 | function parse_json(io::Union{IO,String}; kwargs...)::Dict{String,Any} 3 | pm_data = JSON.parse(io) 4 | 5 | PowerModels._jsonver2juliaver!(pm_data) 6 | 7 | if haskey(pm_data, "conductors") 8 | Memento.warn(_LOGGER, "The JSON data contains the conductor parameter, but only single conductors are supported. Consider using PowerModelsDistribution.") 9 | end 10 | 11 | if get(kwargs, :validate, true) 12 | eDisGo_OPF.correct_network_data!(pm_data) 13 | end 14 | 15 | return pm_data 16 | end 17 | -------------------------------------------------------------------------------- /edisgo/opf/eDisGo_OPF.jl/src/prob/opf_bf.jl: -------------------------------------------------------------------------------- 1 | "Solve multinetwork branch flow OPF with multiple flexibilities" 2 | function solve_mn_opf_bf_flex(file, model_type::Type{T}, optimizer; kwargs...) where T <: AbstractBFModel 3 | return eDisGo_OPF.solve_model(file, model_type, optimizer, build_mn_opf_bf_flex; multinetwork=true, kwargs...) 4 | end 5 | 6 | 7 | "Build multinetwork branch flow OPF with multiple flexibilities" 8 | function build_mn_opf_bf_flex(pm::AbstractBFModelEdisgo) 9 | if PowerModels.ref(pm, 1, :opf_version) in(1, 3) 10 | eDisGo_OPF.variable_max_line_loading(pm, nw=1) # Eq. (3.41) (nur für Version 1 und 3) 11 | end 12 | for (n, network) in PowerModels.nws(pm) 13 | # VARIABLES 14 | if PowerModels.ref(pm, 1, :opf_version) in(1, 2, 3, 4) 15 | eDisGo_OPF.variable_branch_power_radial(pm, nw=n, bounded=false) # keine Begrenzung für Leistung auf Leitungen/Trafos (Strombegrenzung stattdessen) 16 | if PowerModels.ref(pm, 1, :opf_version) in(1, 3) # nur für Version 1 und 3 (ohne Netzrestriktionen) 17 | eDisGo_OPF.variable_branch_current(pm, nw=n, bounded=false) # keine Eq. (3.7)! 18 | eDisGo_OPF.variable_bus_voltage(pm, nw=n, bounded=false) # keine Eq. (3.8)! 19 | eDisGo_OPF.constraint_max_line_loading(pm, n) # Eq. (3.40) 20 | else # nur für Version 2 und 4 (mit Netzrestriktionen) 21 | eDisGo_OPF.variable_branch_current(pm, nw=n) # Eq. (3.7) und (3.7i) 22 | eDisGo_OPF.variable_gen_power_curt(pm, nw=n) # Eq. (3.44) für non-dispatchable Generators 23 | eDisGo_OPF.variable_slack_grid_restrictions(pm, nw=n) # Eq. (3.44)-(3.47) 24 | eDisGo_OPF.variable_bus_voltage(pm, nw=n) # Eq. (3.8) 25 | end 26 | eDisGo_OPF.variable_slack_heat_pump_storage(pm, nw=n) # Eq. (3.44)-(3.47) 27 | eDisGo_OPF.variable_battery_storage(pm, nw=n) # Eq. (3.11) und (3.12) 28 | eDisGo_OPF.variable_heat_storage(pm, nw=n) # Eq. (3.24) 29 | eDisGo_OPF.variable_heat_pump_power(pm, nw=n) # Eq. (3.20) 30 | eDisGo_OPF.variable_cp_power(pm, nw=n) # Eq. (3.27), (3.28) 31 | eDisGo_OPF.variable_dsm_storage_power(pm, nw=n) # Eq. (3.34), (3.35) 32 | eDisGo_OPF.variable_slack_gen(pm, nw=n) # keine Bounds für Slack Generator 33 | 34 | if PowerModels.ref(pm, 1, :opf_version) in(3, 4) # Nicht Teil der MA 35 | eDisGo_OPF.variable_slack_HV_requirements(pm, nw=n) 36 | if PowerModels.ref(pm, 1, :opf_version) in(3) 37 | eDisGo_OPF.variable_gen_power_curt(pm, nw=n) 38 | end 39 | for i in PowerModels.ids(pm, :HV_requirements, nw=n) 40 | eDisGo_OPF.constraint_HV_requirements(pm, i, n) 41 | end 42 | end 43 | else 44 | throw(ArgumentError("OPF version $(PowerModels.ref(pm, 1, :opf_version)) is not implemented! Choose between version 1 to 4.")) 45 | end 46 | 47 | # CONSTRAINTS 48 | for i in PowerModels.ids(pm, :bus, nw=n) 49 | eDisGo_OPF.constraint_power_balance_bf(pm, i, nw=n) # Eq. (3.3ii), (3.4ii) für Version 1 und 3 bzw. (3.3iii), (3.4iii) für Version 2 und 4 50 | end 51 | for i in PowerModels.ids(pm, :branch, nw=n) 52 | eDisGo_OPF.constraint_voltage_magnitude_difference_radial(pm, i, nw=n) # Eq. (3.5) 53 | end 54 | eDisGo_OPF.constraint_model_current(pm, nw=n) # Eq. (3.6) bzw. (3.6i) (je nachdem ob nicht-konvex oder konvex gelöst wird) und (3.6ii) 55 | 56 | 57 | for i in PowerModels.ids(pm, :heatpumps, nw=n) 58 | eDisGo_OPF.constraint_hp_operation(pm, i, n) # Eq. (3.19) 59 | end 60 | 61 | end 62 | 63 | # CONSTRAINTS 64 | network_ids = sort(collect(PowerModels.nw_ids(pm))) 65 | for kind in ["storage", "heat_storage", "dsm"] 66 | n_1 = network_ids[1] 67 | for i in PowerModels.ids(pm, Symbol(kind), nw=n_1) 68 | eDisGo_OPF.constraint_store_state(pm, i, nw=n_1, kind=kind) # Eq. (3.9)+(3.10), (3.22)+(3.23), (3.32)+(3.33) 69 | end 70 | 71 | for n_2 in network_ids[2:end] 72 | for i in PowerModels.ids(pm, Symbol(kind), nw=n_2) 73 | eDisGo_OPF.constraint_store_state(pm, i, n_1, n_2, kind) # Eq. (3.10), (3.23), (3.33) 74 | end 75 | n_1 = n_2 76 | end 77 | end 78 | 79 | n_1 = network_ids[1] 80 | 81 | for i in PowerModels.ids(pm, :electromobility, nw=n_1) 82 | eta = PowerModels.ref(pm, 1, :electromobility)[i]["eta"] 83 | eDisGo_OPF.constraint_cp_state_initial(pm, n_1, i, eta) # Eq. (3.25) 84 | end 85 | 86 | for n_2 in network_ids[2:end] 87 | for i in PowerModels.ids(pm, :electromobility, nw=n_2) 88 | eta = PowerModels.ref(pm, 1, :electromobility)[i]["eta"] 89 | eDisGo_OPF.constraint_cp_state(pm, n_1, n_2, i, eta) # Eq. (3.26) (und (3.25) für letzten Zeitschritt) 90 | end 91 | n_1 = n_2 92 | end 93 | 94 | # OBJECTIVE FUNCTION 95 | if PowerModels.ref(pm, 1, :opf_version) == 1 96 | #eDisGo_OPF.objective_min_losses(pm) 97 | eDisGo_OPF.objective_min_line_loading_max(pm) # Eq. (3.2 ii) 98 | elseif (PowerModels.ref(pm, 1, :opf_version) == 3) # Nicht Teil der MA 99 | eDisGo_OPF.objective_min_line_loading_max_OG(pm) 100 | elseif PowerModels.ref(pm, 1, :opf_version) == 2 101 | eDisGo_OPF.objective_min_losses_slacks(pm) # Eq. (3.2 iii) 102 | elseif PowerModels.ref(pm, 1, :opf_version) == 4 103 | eDisGo_OPF.objective_min_losses_slacks_OG(pm) # Nicht Teil der MA 104 | end 105 | end 106 | -------------------------------------------------------------------------------- /edisgo/opf/opf_solutions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/edisgo/opf/opf_solutions/__init__.py -------------------------------------------------------------------------------- /edisgo/opf/results/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/edisgo/opf/results/__init__.py -------------------------------------------------------------------------------- /edisgo/tools/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from contextlib import contextmanager 4 | 5 | from sqlalchemy.orm import sessionmaker 6 | 7 | if "READTHEDOCS" not in os.environ: 8 | from egoio.tools.db import connection 9 | 10 | Session = sessionmaker(bind=connection(readonly=True)) 11 | 12 | 13 | @contextmanager 14 | def session_scope(): 15 | """Function to ensure that sessions are closed properly.""" 16 | session = Session() 17 | try: 18 | yield session 19 | except Exception: 20 | session.rollback() 21 | raise 22 | finally: 23 | session.close() 24 | -------------------------------------------------------------------------------- /edisgo/tools/networkx_helper.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from networkx import Graph 4 | from pandas import DataFrame 5 | 6 | 7 | def translate_df_to_graph( 8 | buses_df: DataFrame, 9 | lines_df: DataFrame, 10 | transformers_df: DataFrame | None = None, 11 | ) -> Graph: 12 | """ 13 | Translate DataFrames to networkx Graph Object. 14 | 15 | Parameters 16 | ---------- 17 | buses_df : :pandas:`pandas.DataFrame` 18 | Dataframe with all buses to use as Graph nodes. For more information about the 19 | Dataframe see :attr:`~.network.topology.Topology.buses_df`. 20 | lines_df : :pandas:`pandas.DataFrame` 21 | Dataframe with all lines to use as Graph branches. For more information about 22 | the Dataframe see :attr:`~.network.topology.Topology.lines_df` 23 | transformers_df : :pandas:`pandas.DataFrame`, optional 24 | Dataframe with all transformers to use as additional Graph nodes. For more 25 | information about the Dataframe see 26 | :attr:`~.network.topology.Topology.transformers_df` 27 | 28 | Returns 29 | ------- 30 | :networkx:`networkx.Graph<>` 31 | Graph representation of the grid as networkx Ordered Graph, 32 | where lines are represented by edges in the graph, and buses and 33 | transformers are represented by nodes. 34 | 35 | """ 36 | graph = Graph() 37 | 38 | # add nodes 39 | buses = [ 40 | (bus_name, {"pos": (x, y)}) 41 | for bus_name, x, y in buses_df[["x", "y"]].itertuples() 42 | ] 43 | 44 | graph.add_nodes_from(buses) 45 | 46 | # add branches 47 | branches = [ 48 | (bus0, bus1, {"branch_name": line_name, "length": length}) 49 | for line_name, bus0, bus1, length in lines_df[ 50 | ["bus0", "bus1", "length"] 51 | ].itertuples() 52 | ] 53 | 54 | if transformers_df is not None: 55 | branches.extend( 56 | (bus0, bus1, {"branch_name": trafo_name, "length": 0}) 57 | for trafo_name, bus0, bus1 in transformers_df[["bus0", "bus1"]].itertuples() 58 | ) 59 | 60 | graph.add_edges_from(branches) 61 | 62 | return graph 63 | -------------------------------------------------------------------------------- /examples/data/vg250.cpg: -------------------------------------------------------------------------------- 1 | ISO-8859-1 2 | -------------------------------------------------------------------------------- /examples/data/vg250.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/examples/data/vg250.dbf -------------------------------------------------------------------------------- /examples/data/vg250.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] 2 | -------------------------------------------------------------------------------- /examples/data/vg250.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/examples/data/vg250.shp -------------------------------------------------------------------------------- /examples/data/vg250.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/examples/data/vg250.shx -------------------------------------------------------------------------------- /rtd_requirements.txt: -------------------------------------------------------------------------------- 1 | dash < 2.9.0 2 | demandlib < 0.3.0 3 | egoio >= 0.4.7, < 0.5.0 4 | geopy >= 2.0.0, < 2.5.0 5 | jupyter_dash < 0.5.0 6 | matplotlib < 3.11.0 7 | multiprocess < 0.71.0 8 | networkx >= 2.5.0, < 3.5.0 9 | pandas >= 1.4.0, < 2.2.0 10 | plotly < 6.0 11 | pypower < 5.2.0 12 | pyproj >=3.0.0, < 3.8.0 13 | pypsa == 0.26.2 14 | pyyaml < 6.1.0 15 | saio < 0.3.0 16 | scikit-learn < 1.6 17 | sphinx < 8.3.0 18 | sphinx_rtd_theme >= 0.5.2, < 3.1.0 19 | sphinx-autodoc-typehints < 3.2.0 20 | sphinx-autoapi < 3.7.0 21 | sshtunnel < 0.5.0 22 | urllib3 < 2.5.0 23 | workalendar < 17.1.0 24 | astroid == 3.3.10 25 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """Setup""" 2 | 3 | import os 4 | import sys 5 | 6 | from setuptools import find_packages, setup 7 | 8 | if sys.version_info[:2] < (3, 9): 9 | error = ( 10 | "eDisGo requires Python 3.9 or later (%d.%d detected)." % sys.version_info[:2] 11 | ) 12 | sys.stderr.write(error + "\n") 13 | sys.exit(1) 14 | 15 | 16 | def read(fname): 17 | """ 18 | Read a text file. 19 | 20 | Parameters 21 | ---------- 22 | fname : str or PurePath 23 | Path to file 24 | 25 | Returns 26 | ------- 27 | str 28 | File content 29 | 30 | """ 31 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 32 | 33 | 34 | requirements = [ 35 | "contextily < 1.7.0", 36 | "dash < 2.9.0", 37 | "demandlib < 0.3.0", 38 | "descartes < 1.2.0", 39 | "egoio >= 0.4.7, < 0.5.0", 40 | "geoalchemy2 < 0.7.0", 41 | "geopandas >= 0.12.0, < 1.1.0", 42 | "geopy >= 2.0.0, < 2.5.0", 43 | "jupyterlab < 4.5.0", 44 | "jupyter_dash < 0.5.0", 45 | "matplotlib >= 3.3.0, < 3.11.0", 46 | "multiprocess < 0.71.0", 47 | "networkx >= 2.5.0, < 3.5.0", 48 | # newer pandas versions don't work with specified sqlalchemy versions, but upgrading 49 | # sqlalchemy leads to new errors.. should be fixed at some point 50 | "numpy ==1.26.4", 51 | "pandas >= 1.4.0, < 2.2.0", 52 | "plotly < 6.0", 53 | "pydot < 4.1.0", 54 | "pygeos < 0.15.0", 55 | "pypower < 5.2.0", 56 | "pyproj >= 3.0.0, < 3.8.0", 57 | "pypsa == 0.26.2", 58 | "pyyaml < 6.1.0", 59 | "saio < 0.3.0", 60 | "scikit-learn < 1.3.0", 61 | "shapely >= 1.7.0, < 2.1.0", 62 | "sqlalchemy < 1.4.0", 63 | "sshtunnel < 0.5.0", 64 | "urllib3 < 2.5.0", 65 | "workalendar < 17.1.0", 66 | "astroid == 3.3.10", 67 | ] 68 | 69 | dev_requirements = [ 70 | "black < 25.2.0", 71 | "flake8 < 7.3.0", 72 | "isort < 6.1.0", 73 | "pre-commit < 4.3.0", 74 | "pylint < 3.4.0", 75 | "pytest < 8.4.0", 76 | "pytest-notebook < 0.11.0", 77 | "pyupgrade < 3.20.0", 78 | "sphinx < 8.3.0", 79 | "sphinx_rtd_theme >=0.5.2, < 3.1.0", 80 | "sphinx-autodoc-typehints < 3.2.0", 81 | "sphinx-autoapi < 3.7.0", 82 | "astroid == 3.3.10", 83 | ] 84 | 85 | extras = {"dev": dev_requirements} 86 | 87 | setup( 88 | name="eDisGo", 89 | version="0.3.0dev", 90 | packages=find_packages(), 91 | url="https://github.com/openego/eDisGo", 92 | license="GNU Affero General Public License v3.0", 93 | author=( 94 | "birgits, AnyaHe, khelfen, mltja, gplssm, nesnoj, jaappedersen, Elias, " 95 | "boltbeard" 96 | ), 97 | author_email="anya.heider@rl-institut.de", 98 | description="A python package for distribution network analysis and optimization", 99 | long_description=read("README.md"), 100 | long_description_content_type="text/markdown", 101 | install_requires=requirements, 102 | extras_require=extras, 103 | package_data={ 104 | "edisgo": [ 105 | os.path.join("config", "*.cfg"), 106 | os.path.join("equipment", "*.csv"), 107 | ] 108 | }, 109 | ) 110 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | 5 | from edisgo.io.db import engine 6 | 7 | 8 | def pytest_configure(config): 9 | # small self constructed ding0 grid with only 9 LV grids used for general testing 10 | pytest.ding0_test_network_path = os.path.join( 11 | os.path.realpath(os.path.dirname(__file__)), "data/ding0_test_network_1" 12 | ) 13 | # real ding0 grid without georeference in LV used to test import of open_ego data 14 | # from oedb 15 | pytest.ding0_test_network_2_path = os.path.join( 16 | os.path.realpath(os.path.dirname(__file__)), "data/ding0_test_network_2" 17 | ) 18 | # real ding0 grid from newer version of ding0 with georeferenced LV used to test 19 | # import of egon_data data 20 | pytest.ding0_test_network_3_path = os.path.join( 21 | os.path.realpath(os.path.dirname(__file__)), "data/ding0_test_network_3" 22 | ) 23 | 24 | pytest.simbev_example_scenario_path = os.path.join( 25 | os.path.realpath(os.path.dirname(__file__)), "data/simbev_example_scenario" 26 | ) 27 | 28 | pytest.tracbev_example_scenario_path = os.path.join( 29 | os.path.realpath(os.path.dirname(__file__)), "data/tracbev_example_scenario" 30 | ) 31 | 32 | # pytest.egon_data_config_yml = os.path.join( 33 | # "path/to/ssh/config.yml", 34 | # ) 35 | 36 | pytest.engine = engine() 37 | 38 | config.addinivalue_line("markers", "slow: mark test as slow to run") 39 | config.addinivalue_line("markers", "local: mark test as local to run") 40 | 41 | # if config.getoption("--runlocal"): 42 | # pytest.engine_local = engine(path=pytest.egon_data_config_yml, ssh=False) 43 | 44 | 45 | def pytest_addoption(parser): 46 | parser.addoption( 47 | "--runslow", action="store_true", default=False, help="run slow tests" 48 | ) 49 | parser.addoption( 50 | "--runonlinux", 51 | action="store_true", 52 | default=False, 53 | help="run tests that only work on linux", 54 | ) 55 | parser.addoption( 56 | "--runlocal", 57 | action="store_true", 58 | default=False, 59 | help="run tests that only work locally", 60 | ) 61 | 62 | 63 | def pytest_collection_modifyitems(config, items): 64 | if not config.getoption("--runslow"): 65 | skip_slow = pytest.mark.skip(reason="need --runslow option to run") 66 | for item in items: 67 | if "slow" in item.keywords: 68 | item.add_marker(skip_slow) 69 | if not config.getoption("--runlocal"): 70 | skip_local = pytest.mark.skip(reason="need --runlocal option to run") 71 | for item in items: 72 | if "local" in item.keywords: 73 | item.add_marker(skip_local) 74 | if not config.getoption("--runonlinux"): 75 | skip_windows = pytest.mark.skip(reason="need --runonlinux option to run") 76 | for item in items: 77 | if "runonlinux" in item.keywords: 78 | item.add_marker(skip_windows) 79 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_1/ding0_test_network_1.md: -------------------------------------------------------------------------------- 1 | Manually created test network, not created with ding0! 2 | 3 | ding0 mv_grid_id has no real meaning 4 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_1/generators.csv: -------------------------------------------------------------------------------- 1 | name,bus,control,p_nom,type,weather_cell_id,subtype 2 | Generator_1,Bus_Generator_1,PQ,0.775,gas,, 3 | GeneratorFluctuating_2,Bus_GeneratorFluctuating_2,PQ,2.3,wind,1122074,wind_wind_onshore 4 | GeneratorFluctuating_3,Bus_GeneratorFluctuating_3,PQ,2.67,solar,1122075,solar_solar_ground_mounted 5 | GeneratorFluctuating_4,Bus_GeneratorFluctuating_4,PQ,1.93,solar,1122075,solar_solar 6 | GeneratorFluctuating_5,Bus_GeneratorFluctuating_5,PQ,2.3,wind,1122075,wind_wind_onshore 7 | GeneratorFluctuating_6,Bus_GeneratorFluctuating_6,PQ,3.05,wind,1122075,wind_wind_onshore 8 | GeneratorFluctuating_7,Bus_GeneratorFluctuating_7,PQ,3,wind,1122075,wind_wind_onshore 9 | GeneratorFluctuating_8,Bus_GeneratorFluctuating_8,PQ,3,wind,1122075,wind_wind_onshore 10 | GeneratorFluctuating_agg_28,BusBar_lac_1,PQ,3.05,wind,1122075,wind_wind_onshore 11 | GeneratorFluctuating_9,Bus_BranchTee_LVGrid_1_10,PQ,0.005,solar,1122075,solar_solar_roof_mounted 12 | GeneratorFluctuating_10,Bus_BranchTee_LVGrid_1_10,PQ,0.002,solar,1122075,solar_solar_roof_mounted 13 | GeneratorFluctuating_11,Bus_BranchTee_LVGrid_1_8,PQ,0.005,solar,1122075,solar_solar_roof_mounted 14 | GeneratorFluctuating_12,Bus_BranchTee_LVGrid_1_12,PQ,0.011,solar,1122075,solar_solar_roof_mounted 15 | GeneratorFluctuating_13,Bus_BranchTee_LVGrid_1_14,PQ,0.029,solar,1122075,solar_solar_roof_mounted 16 | GeneratorFluctuating_14,Bus_BranchTee_LVGrid_1_14,PQ,0.005,solar,1122075,solar_solar_roof_mounted 17 | GeneratorFluctuating_15,Bus_BranchTee_LVGrid_2_4,PQ,0.006,solar,1122075,solar_solar_roof_mounted 18 | GeneratorFluctuating_16,Bus_GeneratorFluctuating_16,PQ,0.03,solar,1122075,solar_solar_roof_mounted 19 | GeneratorFluctuating_17,Bus_BranchTee_LVGrid_4_2,PQ,0.055,solar,1122075,solar_solar_roof_mounted 20 | GeneratorFluctuating_18,Bus_BranchTee_LVGrid_4_2,PQ,0.01,solar,1122075,solar_solar_roof_mounted 21 | GeneratorFluctuating_19,Bus_GeneratorFluctuating_19,PQ,0.023,solar,1122075,solar_solar_roof_mounted 22 | GeneratorFluctuating_20,Bus_BranchTee_LVGrid_7_6,PQ,0.005,solar,1122075,solar_solar_roof_mounted 23 | GeneratorFluctuating_21,Bus_BranchTee_LVGrid_7_6,PQ,0.036,solar,1122075,solar_solar_roof_mounted 24 | GeneratorFluctuating_22,Bus_BranchTee_LVGrid_7_4,PQ,0.008,solar,1122075,solar_solar_roof_mounted 25 | GeneratorFluctuating_23,Bus_BranchTee_LVGrid_8_2,PQ,0.003,solar,1122075,solar_solar_roof_mounted 26 | GeneratorFluctuating_24,Bus_BranchTee_LVGrid_8_8,PQ,0.003,solar,1122075,solar_solar_roof_mounted 27 | GeneratorFluctuating_25,Bus_BranchTee_LVGrid_8_12,PQ,0.006,solar,1122075,solar_solar_roof_mounted 28 | GeneratorFluctuating_26,Bus_BranchTee_LVGrid_8_10,PQ,0.004,solar,1122075,solar_solar_roof_mounted 29 | GeneratorFluctuating_27,Bus_BranchTee_LVGrid_8_16,PQ,0.021,solar,1122075,solar_solar_roof_mounted 30 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_1/loads.csv: -------------------------------------------------------------------------------- 1 | name,bus,peak_load,sector,annual_consumption 2 | Load_retail_MVGrid_1_Load_aggregated_retail_MVGrid_1_1,BusBar_lac_1,0.31,retail,1520 3 | Load_agricultural_LVGrid_1_1,Bus_BranchTee_LVGrid_1_2,0.0523,agricultural,238 4 | Load_agricultural_LVGrid_1_2,Bus_BranchTee_LVGrid_1_4,0.0523,agricultural,514 5 | Load_agricultural_LVGrid_1_3,Bus_BranchTee_LVGrid_1_6,0.0523,agricultural,664 6 | Load_residential_LVGrid_1_4,Bus_BranchTee_LVGrid_1_8,0.001397,residential,6.1 7 | Load_residential_LVGrid_1_5,Bus_BranchTee_LVGrid_1_10,0.001397,residential,6.1 8 | Load_residential_LVGrid_1_6,Bus_BranchTee_LVGrid_1_12,0.001397,residential,6.1 9 | Load_residential_LVGrid_1_7,Bus_BranchTee_LVGrid_1_14,0.001397,residential,6.1 10 | Load_residential_LVGrid_2_1,Bus_BranchTee_LVGrid_2_2,0.001048,residential,5.7 11 | Load_residential_LVGrid_2_2,Bus_BranchTee_LVGrid_2_4,0.001048,residential,5.7 12 | Load_agricultural_LVGrid_3_1,Bus_BranchTee_LVGrid_3_2,0.051,agricultural,50 13 | Load_residential_LVGrid_3_2,Bus_BranchTee_LVGrid_3_4,0.001209,residential,4.3 14 | Load_residential_LVGrid_3_3,Bus_BranchTee_LVGrid_3_6,0.001209,residential,4.3 15 | Load_residential_LVGrid_3_4,Bus_BranchTee_LVGrid_3_8,0.001209,residential,4.3 16 | Load_residential_LVGrid_4_1,Bus_BranchTee_LVGrid_4_2,0.001354,residential,6.5 17 | Load_industrial_LVGrid_5_1,Bus_BranchTee_LVGrid_5_2,0.07992,industrial,100 18 | Load_agricultural_LVGrid_5_2,Bus_BranchTee_LVGrid_5_4,0.06196,agricultural,450 19 | Load_residential_LVGrid_5_3,Bus_Load_residential_LVGrid_5_3,0.001354,residential,4.7 20 | Load_industrial_LVGrid_6_1,Bus_BranchTee_LVGrid_6_2,0.07992,industrial,580 21 | Load_agricultural_LVGrid_7_1,Bus_BranchTee_LVGrid_7_2,0.06196,agricultural,630 22 | Load_residential_LVGrid_7_2,Bus_BranchTee_LVGrid_7_4,0.001164,residential,5.8 23 | Load_residential_LVGrid_7_3,Bus_BranchTee_LVGrid_7_6,0.001164,residential,5.8 24 | Load_agricultural_LVGrid_8_1,Bus_BranchTee_LVGrid_8_2,0.0478,agricultural,86 25 | Load_residential_LVGrid_8_2,Bus_BranchTee_LVGrid_8_4,0.001222,residential,4.9 26 | Load_residential_LVGrid_8_3,Bus_BranchTee_LVGrid_8_6,0.001222,residential,4.9 27 | Load_residential_LVGrid_8_4,Bus_BranchTee_LVGrid_8_8,0.001222,residential,4.9 28 | Load_residential_LVGrid_8_5,Bus_BranchTee_LVGrid_8_10,0.001222,residential,4.9 29 | Load_residential_LVGrid_8_6,Bus_BranchTee_LVGrid_8_12,0.001222,residential,4.9 30 | Load_residential_LVGrid_8_7,Bus_BranchTee_LVGrid_8_14,0.001222,residential,4.9 31 | Load_residential_LVGrid_8_8,Bus_BranchTee_LVGrid_8_16,0.001222,residential,4.9 32 | Load_residential_LVGrid_8_9,Bus_BranchTee_LVGrid_8_18,0.001222,residential,4.9 33 | Load_residential_LVGrid_8_10,Bus_BranchTee_LVGrid_8_20,0.001222,residential,4.9 34 | Load_residential_LVGrid_8_11,Bus_BranchTee_LVGrid_8_22,0.001222,residential,4.9 35 | Load_residential_LVGrid_8_12,Bus_BranchTee_LVGrid_8_24,0.001222,residential,4.9 36 | Load_residential_LVGrid_8_13,Bus_BranchTee_LVGrid_8_26,0.001222,residential,4.9 37 | Load_residential_LVGrid_8_14,Bus_BranchTee_LVGrid_8_28,0.001222,residential,4.9 38 | Load_agricultural_LVGrid_9_1,Bus_BranchTee_LVGrid_9_2,0.0478,agricultural,279 39 | Load_residential_LVGrid_9_2,Bus_BranchTee_LVGrid_9_4,0.001222,residential,4.9 40 | Load_residential_LVGrid_9_3,Bus_BranchTee_LVGrid_9_6,0.001222,residential,4.9 41 | Load_residential_LVGrid_9_4,Bus_BranchTee_LVGrid_9_8,0.001222,residential,4.9 42 | Load_residential_LVGrid_9_5,Bus_BranchTee_LVGrid_9_10,0.001222,residential,4.9 43 | Load_residential_LVGrid_9_6,Bus_BranchTee_LVGrid_9_12,0.001222,residential,4.9 44 | Load_residential_LVGrid_9_7,Bus_BranchTee_LVGrid_9_14,0.001222,residential,4.9 45 | Load_residential_LVGrid_9_8,Bus_BranchTee_LVGrid_9_16,0.001222,residential,4.9 46 | Load_residential_LVGrid_9_9,Bus_BranchTee_LVGrid_9_18,0.001222,residential,4.9 47 | Load_residential_LVGrid_9_10,Bus_BranchTee_LVGrid_9_20,0.001222,residential,4.9 48 | Load_residential_LVGrid_9_11,Bus_BranchTee_LVGrid_9_22,0.001222,residential,4.9 49 | Load_residential_LVGrid_9_12,Bus_BranchTee_LVGrid_9_24,0.001222,residential,4.9 50 | Load_residential_LVGrid_9_13,Bus_BranchTee_LVGrid_9_26,0.001222,residential,4.9 51 | Load_retail_LVGrid_9_14,Bus_BranchTee_LVGrid_9_28,0.001222,retail,143 52 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_1/storage_units.csv: -------------------------------------------------------------------------------- 1 | name,bus,control,p_nom,capacity,efficiency_store,efficiency_dispatch 2 | Storage_1,Bus_MVStation_1,PQ,0.4,0.4,0.9,0.9 3 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_1/switches.csv: -------------------------------------------------------------------------------- 1 | name,bus_closed,bus_open,branch,type_info 2 | circuit_breaker_1,BusBar_MVGrid_1_LVGrid_4_MV,virtual_BusBar_MVGrid_1_LVGrid_4_MV,Line_10031,Switch Disconnector 3 | circuit_breaker_2,BusBar_MVGrid_1_LVGrid_9_MV,virtual_BusBar_MVGrid_1_LVGrid_9_MV,Line_10016,Switch Disconnector 4 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_1/transformers.csv: -------------------------------------------------------------------------------- 1 | name,bus0,bus1,x,r,s_nom,type_info 2 | LVStation_1_transformer_1,BusBar_MVGrid_1_LVGrid_1_MV,BusBar_MVGrid_1_LVGrid_1_LV,0.016,0.00588,0.16,160 kVA 3 | LVStation_2_transformer_1,BusBar_MVGrid_1_LVGrid_2_MV,BusBar_MVGrid_1_LVGrid_2_LV,0.0246,0.0098,0.05,50 kVA 4 | LVStation_3_transformer_1,BusBar_MVGrid_1_LVGrid_3_MV,BusBar_MVGrid_1_LVGrid_3_LV,0.016,0.007,0.1,100 kVA 5 | LVStation_4_transformer_1,BusBar_MVGrid_1_LVGrid_4_MV,BusBar_MVGrid_1_LVGrid_4_LV,0.0246,0.0098,0.04,40 kVA 6 | LVStation_4_transformer_2,BusBar_MVGrid_1_LVGrid_4_MV,BusBar_MVGrid_1_LVGrid_4_LV,0.0246,0.0098,0.01,10 kVA 7 | LVStation_5_transformer_1,BusBar_MVGrid_1_LVGrid_5_MV,BusBar_MVGrid_1_LVGrid_5_LV,0.016,0.007,0.1,100 kVA 8 | LVStation_6_transformer_1,BusBar_MVGrid_1_LVGrid_6_LV,BusBar_MVGrid_1_LVGrid_6_MV,0.0246,0.0098,0.05,50 kVA 9 | LVStation_7_transformer_1,BusBar_MVGrid_1_LVGrid_7_MV,BusBar_MVGrid_1_LVGrid_7_LV,0.016,0.007,0.1,100 kVA 10 | LVStation_8_transformer_1,BusBar_MVGrid_1_LVGrid_8_MV,BusBar_MVGrid_1_LVGrid_8_LV,0.016,0.007,0.1,100 kVA 11 | LVStation_9_transformer_1,BusBar_MVGrid_1_LVGrid_9_MV,BusBar_MVGrid_1_LVGrid_9_LV,0.016,0.007,0.1,100 kVA 12 | Transformer_lv_load_area_1_1,Bus_MVStation_1,BusBar_lac_1,0.059074106002546,0.0105,1,1.0 MVA 20/0.4 kV 13 | Transformer_lv_load_area_1_2,Bus_MVStation_1,BusBar_lac_1,0.059074106002546,0.0105,1,1.0 MVA 20/0.4 kV 14 | Transformer_lv_load_area_1_3,Bus_MVStation_1,BusBar_lac_1,0.059074106002546,0.0105,1,1.0 MVA 20/0.4 kV 15 | Transformer_lv_load_area_1_4,Bus_MVStation_1,BusBar_lac_1,0.059074106002546,0.0105,1,1.0 MVA 20/0.4 kV 16 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_1/transformers_hvmv.csv: -------------------------------------------------------------------------------- 1 | name,bus0,bus1,x,r,s_nom,type_info 2 | MVStation_1_transformer_1,Bus_primary_MVStation_1,Bus_MVStation_1,,,40,40 MVA 110/20 kV 3 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_2/Ding0_20210416184606.meta: -------------------------------------------------------------------------------- 1 | {"version": "v0.1.9-217-g919ef2c\n", "mv_grid_districts": [2095], "database_tables": {"mv_grid_districts": "EgoDpMvGriddistrict", "lv_load_areas": "EgoDpLoadarea", "lv_grid_district": "EgoDpLvGriddistrict", "mv_stations": "EgoDpHvmvSubstation", "lv_stations": "EgoDpMvlvSubstation", "re_generators": "t_ego_dp_res_powerplant_sq_mview", "conv_generators": "t_ego_dp_conv_powerplant_sq_mview", "version": "v0.4.5"}, "data_version": "v0.4.5", "assumptions": {"load_density_threshold": "1", "voltage_per_km_threshold": "15", "load_factor_mv_trans_lc_normal": "0.6", "load_factor_mv_line_lc_normal": "0.6", "load_factor_mv_cable_lc_normal": "0.6", "load_factor_mv_trans_lc_malfunc": "1.0", "load_factor_mv_line_lc_malfunc": "1.0", "load_factor_mv_cable_lc_malfunc": "1.0", "load_factor_mv_trans_fc_normal": "1.0", "load_factor_mv_line_fc_normal": "1.0", "load_factor_mv_cable_fc_normal": "1.0", "load_factor_lv_trans_lc_normal": "1.0", "load_factor_lv_cable_lc_normal": "1.0", "load_factor_lv_trans_fc_normal": "1.0", "load_factor_lv_cable_fc_normal": "1.0", "cos_phi_load": "0.97", "cos_phi_load_mode": "inductive", "cos_phi_gen": "1", "cos_phi_gen_mode": "capacitive", "frequency": "50", "lv_nominal_voltage": "400", "apartment_house_branch_ratio": "1.5", "population_per_apartment": "2.3", "branch_line_length_retail_industrial": "400", "branch_line_length_agricultural": "800", "max_lv_branch_line": "290", "lv_ria_branch_connection_distance": "30", "branch_detour_factor": "1.3", "load_in_generation_case": "0", "generation_in_load_case": "0", "lv_max_v_level_lc_diff_normal": "0.05", "lv_max_v_level_fc_diff_normal": "0.03", "load_area_sat_load_threshold": "100", "load_area_sat_string_load_threshold": "1000", "load_area_sat_conn_dist_weight": "1", "load_area_sat_string_length_threshold": "2000", "load_area_sat_conn_dist_ring_mod": "100", "load_area_stat_conn_dist_ring_mod": "300", "load_area_sat_buffer_radius": "2000", "load_area_sat_buffer_radius_inc": "1000", "generator_buffer_radius": "2000", "generator_buffer_radius_inc": "1000", "operator_diff_round_digits": "3", "conn_diff_tolerance": "0.0001", "load_area_threshold": "1", "load_area_count_per_ring": "20", "max_half_ring_length": "28", "mv_half_ring_count_max": "8", "mv_station_v_level_operation": "1.0", "mv_max_v_level_lc_diff_normal": "0.05", "mv_max_v_level_fc_diff_normal": "0.02", "mv_max_v_level_lc_diff_malfunc": "0.10"}, "run_id": "20210416184606"} 2 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_2/network.csv: -------------------------------------------------------------------------------- 1 | name,srid,mv_grid_district_geom,mv_grid_district_population 2 | 2095,4326,"MULTIPOLYGON (((6.22171915597056 50.7000442498141, 6.21836845956992 50.7471015719592, 6.33629192568964 50.7650555050617, 6.34759596583486 50.7571800281125, 6.34568089681317 50.756444435602, 6.34226797371834 50.7552653528853, 6.34236507457769 50.754206555517, 6.34280029053606 50.7528165218547, 6.34386049608337 50.7515992884819, 6.34389812234061 50.7505746000382, 6.34265545323108 50.749410318405, 6.34066963834987 50.7479524681052, 6.33863180564131 50.7469788737339, 6.33853794135836 50.7460040011331, 6.33623714292214 50.7436811557718, 6.33534293396888 50.742419868912, 6.33223814184308 50.7405843171146, 6.33087299815527 50.7397219620257, 6.32955821220107 50.7391221653932, 6.32859793103724 50.7385246448353, 6.32750737031633 50.7374190170411, 6.32617005920515 50.733497798846, 6.32609105882311 50.731254507339, 6.32428276996426 50.7264723230418, 6.31945324940308 50.7202617686807, 6.31792977400304 50.7190792064936, 6.31595587005689 50.7167753238285, 6.31497642472233 50.714809181416, 6.3136392509724 50.7127055943527, 6.31277311835504 50.7107430518677, 6.31087482519684 50.7076675485333, 6.30957345348617 50.7049351006726, 6.30826013412194 50.7027152063505, 6.31039032768445 50.7023064921887, 6.31234093605401 50.7014780266615, 6.31238476903152 50.7014614313672, 6.31436570778371 50.700426922247, 6.31285536491118 50.6904524332909, 6.30979284499256 50.6899313850493, 6.30173929856764 50.6885481498806, 6.28616682696403 50.6863821536181, 6.27028771974073 50.6848790430016, 6.27270468868398 50.6943887248798, 6.27269055180282 50.6943882674042, 6.27143814093219 50.6949866929821, 6.25673640983272 50.7019434451649, 6.25672227080525 50.7019429857195, 6.23853436773398 50.7054723497745, 6.22171915597056 50.7000442498141)))",0 3 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_2/switches.csv: -------------------------------------------------------------------------------- 1 | name,bus_closed,bus_open,branch,type_info 2 | circuit_breaker_1,BusBar_mvgd_2095_lvgd_500742_MV,virtual_BusBar_mvgd_2095_lvgd_500742_MV,Branch_LVStation_mvgd_2095_lvgd_170174_LVStation_mvgd_2095_lvgd_500742,Switch Disconnector 3 | circuit_breaker_2,BusBar_mvgd_2095_lvgd_136246_MV,virtual_BusBar_mvgd_2095_lvgd_136246_MV,Branch_LVStation_mvgd_2095_lvgd_136246_MVCableDist_mvgd_2095_2,Switch Disconnector 4 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_2/transformers_hvmv.csv: -------------------------------------------------------------------------------- 1 | name,bus0,bus1,s_nom,r,x,type,type_info 2 | Transformer_mv_grid_2095_1,Busbar_mvgd_2095_HV,Busbar_mvgd_2095_MV,25.0,,,25 MVA 110/10 kV,25 MVA 110/10 kV 3 | Transformer_mv_grid_2095_2,Busbar_mvgd_2095_HV,Busbar_mvgd_2095_MV,25.0,,,25 MVA 110/10 kV,25 MVA 110/10 kV 4 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_3/switches.csv: -------------------------------------------------------------------------------- 1 | name,bus_closed,bus_open,branch,type_info 2 | circuit_breaker_1,BusBar_mvgd_33535_lvgd_1166910000_MV,virtual_BusBar_mvgd_33535_lvgd_1166910000_MV,Branch_LVStation_mvgd_33535_lvgd_1166910000_MVCableDist_mvgd_33535_18,Switch Disconnector 3 | circuit_breaker_2,BusBar_mvgd_33535_lvgd_1164120007_MV,virtual_BusBar_mvgd_33535_lvgd_1164120007_MV,Branch_LVStation_mvgd_33535_lvgd_1164120007_MVCableDist_mvgd_33535_1,Switch Disconnector 4 | circuit_breaker_3,BusBar_mvgd_33535_lvgd_1172800000_MV,virtual_BusBar_mvgd_33535_lvgd_1172800000_MV,Branch_LVStation_mvgd_33535_lvgd_1172800000_MVCableDist_mvgd_33535_32,Switch Disconnector 5 | -------------------------------------------------------------------------------- /tests/data/ding0_test_network_3/transformers_hvmv.csv: -------------------------------------------------------------------------------- 1 | name,bus0,bus1,s_nom,r,x,type,type_info 2 | Transformer_mv_grid_33535_1,Busbar_mvgd_33535_HV,Busbar_mvgd_33535_MV,40.0,,,40 MVA 110/20 kV,40 MVA 110/20 kV 3 | Transformer_mv_grid_33535_2,Busbar_mvgd_33535_HV,Busbar_mvgd_33535_MV,40.0,,,40 MVA 110/20 kV,40 MVA 110/20 kV 4 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_luxury_00000_110kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,5_leisure,public,22.0,24.4444,22.0,0.9907,0.9907,0.0,0,0,41,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.9907,0.9495,0.0,0,0,0,42,46,4.5262 4 | 2,6_home,home,0.0,0.0,0.0,0.9495,0.9495,0.0,0,47,98,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.9495,0.867,0.0,0,0,0,99,137,9.0797 6 | 4,3_shopping,public,0.0,0.0,0.0,0.867,0.867,0.0,0,138,140,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.867,0.8392,0.0,0,0,0,141,143,3.0568 8 | 6,5_leisure,public,22.0,24.4444,22.0,0.8392,0.8392,0.0,0,144,153,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.8392,0.8218,0.0,0,0,0,154,163,1.9136 10 | 8,4_private/ridesharing,public,0.0,0.0,0.0,0.8218,0.8218,0.0,0,164,168,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.8218,0.8154,0.0,0,0,0,169,170,0.7081 12 | 10,3_shopping,public,0.0,0.0,0.0,0.8154,0.8154,0.0,0,171,174,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.8154,0.792,0.0,0,0,0,175,180,2.5694 14 | 12,6_home,home,0.0,0.0,0.0,0.792,0.792,0.0,0,181,247,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.792,0.7879,0.0,0,0,0,248,250,0.4465 16 | 14,3_shopping,public,11.0,12.2222,11.0,0.7879,0.7879,0.0,0,251,254,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.7879,0.7632,0.0,0,0,0,255,258,2.7199 18 | 16,6_home,home,0.0,0.0,0.0,0.7632,0.7632,0.0,0,259,343,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.7632,0.7453,0.0,0,0,0,344,345,1.972 20 | 18,0_work,work,0.0,0.0,0.0,0.7453,0.7453,0.0,0,346,390,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.7453,0.5423,0.0,0,0,0,391,424,22.3323 22 | 20,1_business,public,0.0,0.0,0.0,0.5423,0.5423,0.0,0,425,440,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.5423,0.5292,0.0,0,0,0,441,444,1.4357 24 | 22,4_private/ridesharing,public,0.0,0.0,0.0,0.5292,0.5292,0.0,0,445,448,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.5292,0.4867,0.0,0,0,0,449,451,4.6767 26 | 24,6_home,home,0.0,0.0,0.0,0.4867,0.4867,0.0,0,452,494,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.4867,0.4067,0.0,0,0,0,495,516,8.8008 28 | 26,0_work,work,0.0,0.0,0.0,0.4067,0.4067,0.0,0,517,530,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.4067,0.3874,0.0,0,0,0,531,533,2.1178 30 | 28,6_home,home,0.0,0.0,0.0,0.3874,0.3874,0.0,0,534,618,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.3874,0.3671,0.0,0,0,0,619,625,2.2322 32 | 30,4_private/ridesharing,public,0.0,0.0,0.0,0.3671,0.3671,0.0,0,626,629,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,0.3671,0.3552,0.0,0,0,0,630,632,1.3185 34 | 32,3_shopping,public,0.0,0.0,0.0,0.3552,0.3552,0.0,0,633,634,0,0,0.0 35 | 33,driving,,0.0,0.0,0.0,0.3552,0.3458,0.0,0,0,0,635,636,1.0259 36 | 34,5_leisure,public,0.0,0.0,0.0,0.3458,0.3458,0.0,0,637,642,0,0,0.0 37 | 35,driving,,0.0,0.0,0.0,0.3458,0.3266,0.0,0,0,0,643,648,2.1178 38 | 36,6_home,home,0.0,0.0,0.0,0.3266,0.3266,0.0,0,649,672,0,0,0.0 39 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_luxury_00001_110kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,6_home,home,0.0,0.0,0.0,0.8995,0.8995,0.0,0,0,32,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.8995,0.8946,0.0,0,0,0,33,39,0.5337 4 | 2,3_shopping,public,0.0,0.0,0.0,0.8946,0.8946,0.0,0,40,106,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.8946,0.8874,0.0,0,0,0,107,139,0.7986 6 | 4,4_private/ridesharing,public,0.0,0.0,0.0,0.8874,0.8874,0.0,0,140,146,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.8874,0.8818,0.0,0,0,0,147,148,0.6126 8 | 6,6_home,home,0.0,0.0,0.0,0.8818,0.8818,0.0,0,149,182,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.8818,0.8689,0.0,0,0,0,183,217,1.4146 10 | 8,0_work,work,50.0,55.5556,50.0,0.8689,1.0,14.4159,15,218,232,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,1.0,0.9814,0.0,0,0,0,233,234,2.0414 12 | 10,5_leisure,public,0.0,0.0,0.0,0.9814,0.9814,0.0,0,235,240,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.9814,0.9622,0.0,0,0,0,241,243,2.1178 14 | 12,6_home,home,0.0,0.0,0.0,0.9622,0.9622,0.0,0,244,259,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.9622,0.9376,0.0,0,0,0,260,264,2.7101 16 | 14,4_private/ridesharing,public,50.0,55.5556,50.0,0.9376,0.9376,0.0,0,265,290,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.9376,0.8677,0.0,0,0,0,291,318,7.6859 18 | 16,0_work,work,50.0,55.5556,50.0,0.8677,1.0,14.5552,34,319,352,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,1.0,0.9845,0.0,0,0,0,353,354,1.7029 20 | 18,5_leisure,public,22.0,24.4444,22.0,0.9845,0.9845,0.0,0,355,441,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.9845,0.8147,0.0,0,0,0,442,454,18.6755 22 | 20,6_home,home,0.0,0.0,0.0,0.8147,0.8147,0.0,0,455,535,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.8147,0.7504,0.0,0,0,0,536,540,7.074 24 | 22,3_shopping,public,22.0,24.4444,22.0,0.7504,0.7504,0.0,0,541,543,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.7504,0.6628,0.0,0,0,0,544,553,9.644 26 | 24,6_home,home,0.0,0.0,0.0,0.6628,0.6628,0.0,0,554,622,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.6628,0.6571,0.0,0,0,0,623,625,0.6209 28 | 26,3_shopping,public,50.0,55.5556,50.0,0.6571,0.998,37.5,3,626,628,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.998,0.9651,0.0,0,0,0,629,639,3.6231 30 | 28,6_home,home,0.0,0.0,0.0,0.9651,0.9651,0.0,0,640,672,0,0,0.0 31 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_luxury_00002_110kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,6_home,home,11.0,12.2222,11.0,0.8557,1.0,10.3757,88,0,88,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,1.0,0.9927,0.0,0,0,0,89,132,0.7986 4 | 2,4_private/ridesharing,public,0.0,0.0,0.0,0.9927,0.9927,0.0,0,133,136,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.9927,0.9749,0.0,0,0,0,137,138,1.9673 6 | 4,6_home,home,11.0,12.2222,11.0,0.9749,0.9749,0.0,0,139,230,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.9749,0.9708,0.0,0,0,0,231,234,0.4465 8 | 6,3_shopping,public,50.0,55.5556,50.0,0.9708,0.9708,0.0,0,235,237,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.9708,0.9621,0.0,0,0,0,238,241,0.9579 10 | 8,4_private/ridesharing,public,0.0,0.0,0.0,0.9621,0.9621,0.0,0,242,243,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.9621,0.958,0.0,0,0,0,244,245,0.4465 12 | 10,3_shopping,public,22.0,24.4444,22.0,0.958,0.958,0.0,0,246,249,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.958,0.9018,0.0,0,0,0,250,256,6.182 14 | 12,6_home,home,11.0,12.2222,11.0,0.9018,1.0,10.7987,49,257,305,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,1.0,0.9504,0.0,0,0,0,306,316,5.4561 16 | 14,0_work,work,0.0,0.0,0.0,0.9504,0.9504,0.0,0,317,344,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.9504,0.9421,0.0,0,0,0,345,349,0.9136 18 | 16,6_home,home,11.0,12.2222,11.0,0.9421,1.0,6.3697,3,350,352,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,1.0,0.9783,0.0,0,0,0,353,354,2.3915 20 | 18,4_private/ridesharing,public,0.0,0.0,0.0,0.9783,0.9783,0.0,0,355,356,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.9783,0.9275,0.0,0,0,0,357,367,5.5799 22 | 20,6_home,home,11.0,12.2222,11.0,0.9275,1.0,7.9714,66,368,433,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,1.0,0.9623,0.0,0,0,0,434,436,4.1437 24 | 22,4_private/ridesharing,public,0.0,0.0,0.0,0.9623,0.9623,0.0,0,437,451,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.9623,0.8938,0.0,0,0,0,452,455,7.5367 26 | 24,6_home,home,11.0,12.2222,11.0,0.8938,1.0,11.6804,46,456,501,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,1.0,0.9593,0.0,0,0,0,502,510,4.4806 28 | 26,0_work,work,0.0,0.0,0.0,0.9593,0.9593,0.0,0,511,515,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.9593,0.9497,0.0,0,0,0,516,519,1.0569 30 | 28,3_shopping,public,50.0,55.5556,50.0,0.9497,0.9497,0.0,0,520,524,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.9497,0.9359,0.0,0,0,0,525,526,1.5157 32 | 30,6_home,home,11.0,12.2222,11.0,0.9359,1.0,7.0532,64,527,590,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,1.0,0.9504,0.0,0,0,0,591,606,5.4561 34 | 32,0_work,work,0.0,0.0,0.0,0.9504,0.9504,0.0,0,607,646,0,0,0.0 35 | 33,driving,,0.0,0.0,0.0,0.9504,0.3072,0.0,0,0,0,647,667,70.7569 36 | 34,6_home,home,11.0,12.2222,11.0,0.3072,0.3072,0.0,20,668,672,0,0,0.0 37 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_medium_00000_90kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,6_home,home,0.0,0.0,0.0,0.8263,0.8263,0.0,0,0,55,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.8263,0.8197,0.0,0,0,0,56,58,0.5899 4 | 2,3_shopping,public,0.0,0.0,0.0,0.8197,0.8197,0.0,0,59,63,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.8197,0.8043,0.0,0,0,0,64,67,1.388 6 | 4,6_home,home,0.0,0.0,0.0,0.8043,0.8043,0.0,0,68,128,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.8043,0.75,0.0,0,0,0,129,143,4.8933 8 | 6,0_work,work,0.0,0.0,0.0,0.75,0.75,0.0,0,144,176,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.75,0.744,0.0,0,0,0,177,178,0.5325 10 | 8,4_private/ridesharing,public,0.0,0.0,0.0,0.744,0.744,0.0,0,179,183,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.744,0.7219,0.0,0,0,0,184,223,1.991 12 | 10,0_work,work,0.0,0.0,0.0,0.7219,0.7219,0.0,0,224,237,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.7219,0.7145,0.0,0,0,0,238,239,0.6652 14 | 12,4_private/ridesharing,public,0.0,0.0,0.0,0.7145,0.7145,0.0,0,240,242,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.7145,0.5454,0.0,0,0,0,243,255,15.2255 16 | 14,0_work,work,0.0,0.0,0.0,0.5454,0.5454,0.0,0,256,277,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.5454,0.5383,0.0,0,0,0,278,285,0.6357 18 | 16,6_home,home,0.0,0.0,0.0,0.5383,0.5383,0.0,0,286,366,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.5383,0.5058,0.0,0,0,0,367,412,2.9197 20 | 18,0_work,work,0.0,0.0,0.0,0.5058,0.5058,0.0,0,413,453,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.5058,0.4999,0.0,0,0,0,454,455,0.5325 22 | 20,4_private/ridesharing,public,0.0,0.0,0.0,0.4999,0.4999,0.0,0,456,458,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.4999,0.4829,0.0,0,0,0,459,464,1.5342 24 | 22,3_shopping,public,22.0,24.4444,22.0,0.4829,1.0,46.5403,72,465,536,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,1.0,0.9915,0.0,0,0,0,537,543,0.7611 26 | 24,6_home,home,0.0,0.0,0.0,0.9915,0.9915,0.0,0,544,583,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.9915,0.9836,0.0,0,0,0,584,606,0.714 28 | 26,0_work,work,0.0,0.0,0.0,0.9836,0.9836,0.0,0,607,631,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.9836,0.9637,0.0,0,0,0,632,636,1.7886 30 | 28,1_business,public,3.7,4.1111,3.7,0.9637,0.9637,0.0,0,637,640,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.9637,0.9483,0.0,0,0,0,641,642,1.388 32 | 30,6_home,home,0.0,0.0,0.0,0.9483,0.9483,0.0,0,643,644,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,0.9483,0.935,0.0,0,0,0,645,652,1.196 34 | 32,4_private/ridesharing,public,0.0,0.0,0.0,0.935,0.935,0.0,0,653,654,0,0,0.0 35 | 33,driving,,0.0,0.0,0.0,0.935,0.914,0.0,0,0,0,655,672,0.0 36 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_medium_00001_90kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,0_work,work,22.0,24.4444,22.0,0.8844,1.0,10.4045,37,0,66,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,1.0,0.92,0.0,0,0,0,67,72,7.1987 4 | 2,5_leisure,public,0.0,0.0,0.0,0.92,0.92,0.0,0,73,79,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.92,0.9046,0.0,0,0,0,80,92,1.388 6 | 4,6_home,public,0.0,0.0,0.0,0.9046,0.9046,0.0,0,93,102,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.9046,0.8972,0.0,0,0,0,103,140,0.6652 8 | 6,4_private/ridesharing,public,11.0,12.2222,11.0,0.8972,0.8972,0.0,0,141,147,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.8972,0.8553,0.0,0,0,0,148,152,3.7704 10 | 8,6_home,public,0.0,0.0,0.0,0.8553,0.8553,0.0,0,153,225,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.8553,0.8395,0.0,0,0,0,226,233,1.4185 12 | 10,5_leisure,public,22.0,24.4444,22.0,0.8395,0.8395,0.0,0,234,237,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.8395,0.8004,0.0,0,0,0,238,241,3.5196 14 | 12,6_home,public,0.0,0.0,0.0,0.8004,0.8004,0.0,0,242,246,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.8004,0.769,0.0,0,0,0,247,248,2.8283 16 | 14,5_leisure,public,0.0,0.0,0.0,0.769,0.769,0.0,0,249,253,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.769,0.7536,0.0,0,0,0,254,256,1.388 18 | 16,6_home,public,0.0,0.0,0.0,0.7536,0.7536,0.0,0,257,264,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.7536,0.6454,0.0,0,0,0,265,275,9.7364 20 | 18,5_leisure,public,0.0,0.0,0.0,0.6454,0.6454,0.0,0,276,281,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.6454,0.6413,0.0,0,0,0,282,320,0.3657 22 | 20,2_school,public,0.0,0.0,0.0,0.6413,0.6413,0.0,0,321,322,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.6413,0.4438,0.0,0,0,0,323,341,17.7828 24 | 22,4_private/ridesharing,public,22.0,24.4444,22.0,0.4438,0.6271,16.5,3,342,344,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.6271,0.5959,0.0,0,0,0,345,348,2.8037 26 | 24,0_work,work,22.0,24.4444,22.0,0.5959,1.0,36.3654,27,349,375,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,1.0,0.9929,0.0,0,0,0,376,414,0.6422 28 | 26,1_business,public,0.0,0.0,0.0,0.9929,0.9929,0.0,0,415,422,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.9929,0.9839,0.0,0,0,0,423,424,0.8078 30 | 28,3_shopping,public,0.0,0.0,0.0,0.9839,0.9839,0.0,0,425,427,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.9839,0.9765,0.0,0,0,0,428,430,0.6652 32 | 30,4_private/ridesharing,public,0.0,0.0,0.0,0.9765,0.9765,0.0,0,431,436,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,0.9765,0.9513,0.0,0,0,0,437,441,2.2657 34 | 32,6_home,public,0.0,0.0,0.0,0.9513,0.9513,0.0,0,442,498,0,0,0.0 35 | 33,driving,,0.0,0.0,0.0,0.9513,0.8995,0.0,0,0,0,499,509,4.6611 36 | 34,0_work,work,22.0,24.4444,22.0,0.8995,1.0,9.042,22,510,531,0,0,0.0 37 | 35,driving,,0.0,0.0,0.0,1.0,0.9661,0.0,0,0,0,532,535,3.0537 38 | 36,4_private/ridesharing,public,0.0,0.0,0.0,0.9661,0.9661,0.0,0,536,549,0,0,0.0 39 | 37,driving,,0.0,0.0,0.0,0.9661,0.9548,0.0,0,0,0,550,557,1.0118 40 | 38,6_home,public,0.0,0.0,0.0,0.9548,0.9548,0.0,0,558,624,0,0,0.0 41 | 39,driving,,0.0,0.0,0.0,0.9548,0.9108,0.0,0,0,0,625,627,3.9646 42 | 40,0_work,work,22.0,24.4444,22.0,0.9108,1.0,8.0301,19,628,646,0,0,0.0 43 | 41,driving,,0.0,0.0,0.0,1.0,0.9762,0.0,0,0,0,647,648,2.1403 44 | 42,6_home,public,0.0,0.0,0.0,0.9762,0.9762,0.0,0,649,672,0,0,0.0 45 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_medium_00002_90kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,6_home,home,0.0,0.0,0.0,0.3735,0.3735,0.0,0,0,52,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.3735,0.2,0.0,0,0,0,53,59,15.6172 4 | 2,7_charging_hub,hpc,50.0,55.5556,50.0,0.2,0.3389,12.5,1,60,61,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.3389,0.2,0.0,0,0,0,62,67,12.5 6 | 4,7_charging_hub,hpc,50.0,55.5556,50.0,0.2,0.3389,12.5,1,68,69,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.3389,0.2314,0.0,0,0,0,70,75,9.6743 8 | 6,5_leisure,public,0.0,0.0,0.0,0.2314,0.2314,0.0,0,76,86,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.2314,0.2273,0.0,0,0,0,87,131,0.3719 10 | 8,3_shopping,public,0.0,0.0,0.0,0.2273,0.2273,0.0,0,132,133,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.2273,0.2,0.0,0,0,0,134,141,2.4537 12 | 10,7_charging_hub,hpc,50.0,55.5556,50.0,0.2,0.3389,12.5,1,142,143,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.3389,0.3253,0.0,0,0,0,144,146,1.2205 14 | 12,5_leisure,public,0.0,0.0,0.0,0.3253,0.3253,0.0,0,147,210,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.3253,0.298,0.0,0,0,0,211,220,2.4554 16 | 14,0_work,public,0.0,0.0,0.0,0.298,0.298,0.0,0,221,230,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.298,0.2,0.0,0,0,0,231,236,8.8241 18 | 16,7_charging_hub,hpc,50.0,55.5556,50.0,0.2,0.3389,12.5,1,237,238,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.3389,0.3322,0.0,0,0,0,239,240,0.5989 20 | 18,4_private/ridesharing,public,0.0,0.0,0.0,0.3322,0.3322,0.0,0,241,267,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.3322,0.3243,0.0,0,0,0,268,270,0.7136 22 | 20,5_leisure,public,3.7,4.1111,3.7,0.3243,0.3654,3.7,4,271,274,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.3654,0.3584,0.0,0,0,0,275,277,0.6357 24 | 22,6_home,home,0.0,0.0,0.0,0.3584,0.3584,0.0,0,278,291,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.3584,0.3491,0.0,0,0,0,292,318,0.83 26 | 24,2_school,public,0.0,0.0,0.0,0.3491,0.3491,0.0,0,319,330,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.3491,0.278,0.0,0,0,0,331,338,6.4036 28 | 26,6_home,home,0.0,0.0,0.0,0.278,0.278,0.0,0,339,375,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.278,0.2553,0.0,0,0,0,376,416,2.0427 30 | 28,3_shopping,public,22.0,24.4444,22.0,0.2553,0.4386,16.5,3,417,419,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.4386,0.4242,0.0,0,0,0,420,421,1.2945 32 | 30,0_work,public,0.0,0.0,0.0,0.4242,0.4242,0.0,0,422,463,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,0.4242,0.3768,0.0,0,0,0,464,483,4.272 34 | 32,6_home,home,0.0,0.0,0.0,0.3768,0.3768,0.0,0,484,541,0,0,0.0 35 | 33,driving,,0.0,0.0,0.0,0.3768,0.3492,0.0,0,0,0,542,547,2.4786 36 | 34,3_shopping,public,22.0,24.4444,22.0,0.3492,0.5937,22.0,4,548,551,0,0,0.0 37 | 35,driving,,0.0,0.0,0.0,0.5937,0.5462,0.0,0,0,0,552,556,4.272 38 | 36,6_home,home,0.0,0.0,0.0,0.5462,0.5462,0.0,0,557,560,0,0,0.0 39 | 37,driving,,0.0,0.0,0.0,0.5462,0.5226,0.0,0,0,0,561,567,2.1234 40 | 38,5_leisure,public,11.0,12.2222,11.0,0.5226,1.0,42.9649,42,568,609,0,0,0.0 41 | 39,driving,,0.0,0.0,0.0,1.0,0.9943,0.0,0,0,0,610,611,0.5103 42 | 40,6_home,home,0.0,0.0,0.0,0.9943,0.9943,0.0,0,612,672,0,0,0.0 43 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_mini_00000_60kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,0_work,work,0.0,0.0,0.0,0.3798,0.3798,0.0,0,0,29,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.3798,0.3713,0.0,0,0,0,30,36,0.5086 4 | 2,6_home,public,0.0,0.0,0.0,0.3713,0.3713,0.0,0,37,40,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.3713,0.3553,0.0,0,0,0,41,44,0.9569 6 | 4,4_private/ridesharing,public,0.0,0.0,0.0,0.3553,0.3553,0.0,0,45,48,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.3553,0.3385,0.0,0,0,0,49,52,1.0102 8 | 6,6_home,public,0.0,0.0,0.0,0.3385,0.3385,0.0,0,53,60,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.3385,0.3314,0.0,0,0,0,61,62,0.4261 10 | 8,4_private/ridesharing,public,0.0,0.0,0.0,0.3314,0.3314,0.0,0,63,70,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.3314,0.3238,0.0,0,0,0,71,75,0.4582 12 | 10,5_leisure,public,11.0,12.2222,11.0,0.3238,1.0,40.5741,32,76,107,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,1.0,0.9894,0.0,0,0,0,108,134,0.6384 14 | 12,4_private/ridesharing,public,0.0,0.0,0.0,0.9894,0.9894,0.0,0,135,226,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.9894,0.8069,0.0,0,0,0,227,234,10.9487 16 | 14,5_leisure,public,0.0,0.0,0.0,0.8069,0.8069,0.0,0,235,244,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.8069,0.7399,0.0,0,0,0,245,250,4.02 18 | 16,6_home,public,0.0,0.0,0.0,0.7399,0.7399,0.0,0,251,314,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.7399,0.7195,0.0,0,0,0,315,317,1.2215 20 | 18,0_work,work,0.0,0.0,0.0,0.7195,0.7195,0.0,0,318,319,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.7195,0.6788,0.0,0,0,0,320,321,2.4433 22 | 20,4_private/ridesharing,public,0.0,0.0,0.0,0.6788,0.6788,0.0,0,322,326,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.6788,0.6496,0.0,0,0,0,327,340,1.7507 24 | 22,3_shopping,public,0.0,0.0,0.0,0.6496,0.6496,0.0,0,341,352,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.6496,0.6232,0.0,0,0,0,353,355,1.5862 26 | 24,5_leisure,public,11.0,12.2222,11.0,0.6232,0.8065,11.0,4,356,359,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.8065,0.7964,0.0,0,0,0,360,361,0.6089 28 | 26,6_home,public,0.0,0.0,0.0,0.7964,0.7964,0.0,0,362,451,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.7964,0.7389,0.0,0,0,0,452,509,3.4508 30 | 28,0_work,work,0.0,0.0,0.0,0.7389,0.7389,0.0,0,510,527,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.7389,0.727,0.0,0,0,0,528,529,0.7093 32 | 30,6_home,public,0.0,0.0,0.0,0.727,0.727,0.0,0,530,562,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,0.727,0.6969,0.0,0,0,0,563,569,1.8063 34 | 32,4_private/ridesharing,public,11.0,12.2222,11.0,0.6969,0.6969,0.0,0,570,587,0,0,0.0 35 | 33,driving,,0.0,0.0,0.0,0.6969,0.6859,0.0,0,0,0,588,599,0.6642 36 | 34,0_work,work,0.0,0.0,0.0,0.6859,0.6859,0.0,0,600,640,0,0,0.0 37 | 35,driving,,0.0,0.0,0.0,0.6859,0.6807,0.0,0,0,0,641,642,0.308 38 | 36,6_home,public,0.0,0.0,0.0,0.6807,0.6807,0.0,0,643,672,0,0,0.0 39 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_mini_00001_60kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,6_home,home,0.0,0.0,0.0,0.603,0.603,0.0,0,0,32,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.603,0.5777,0.0,0,0,0,33,44,1.5182 4 | 2,3_shopping,public,11.0,12.2222,11.0,0.5777,0.8527,16.5,6,45,50,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.8527,0.8103,0.0,0,0,0,51,53,2.5495 6 | 4,4_private/ridesharing,public,0.0,0.0,0.0,0.8103,0.8103,0.0,0,54,61,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.8103,0.7784,0.0,0,0,0,62,65,1.9132 8 | 6,6_home,home,0.0,0.0,0.0,0.7784,0.7784,0.0,0,66,68,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.7784,0.7707,0.0,0,0,0,69,70,0.4582 10 | 8,5_leisure,public,11.0,12.2222,11.0,0.7707,0.7707,0.0,0,71,75,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.7707,0.7656,0.0,0,0,0,76,77,0.308 12 | 10,6_home,home,0.0,0.0,0.0,0.7656,0.7656,0.0,0,78,162,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.7656,0.726,0.0,0,0,0,163,165,2.3758 14 | 12,5_leisure,public,11.0,12.2222,11.0,0.726,1.0,16.4399,14,166,179,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,1.0,0.9642,0.0,0,0,0,180,220,2.1504 16 | 14,0_work,public,0.0,0.0,0.0,0.9642,0.9642,0.0,0,221,257,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.9642,0.959,0.0,0,0,0,258,259,0.308 18 | 16,6_home,home,0.0,0.0,0.0,0.959,0.959,0.0,0,260,273,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.959,0.9376,0.0,0,0,0,274,277,1.2857 20 | 18,3_shopping,public,0.0,0.0,0.0,0.9376,0.9376,0.0,0,278,372,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.9376,0.9191,0.0,0,0,0,373,376,1.1106 22 | 20,6_home,home,0.0,0.0,0.0,0.9191,0.9191,0.0,0,377,463,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.9191,0.887,0.0,0,0,0,464,469,1.925 24 | 22,3_shopping,public,11.0,12.2222,11.0,0.887,0.887,0.0,0,470,471,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.887,0.8744,0.0,0,0,0,472,507,0.7571 26 | 24,0_work,public,0.0,0.0,0.0,0.8744,0.8744,0.0,0,508,514,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.8744,0.8568,0.0,0,0,0,515,521,1.0532 28 | 26,3_shopping,public,11.0,12.2222,11.0,0.8568,0.8568,0.0,0,522,524,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.8568,0.7882,0.0,0,0,0,525,540,4.1203 30 | 28,6_home,home,0.0,0.0,0.0,0.7882,0.7882,0.0,0,541,597,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.7882,0.757,0.0,0,0,0,598,603,1.8717 32 | 30,0_work,public,0.0,0.0,0.0,0.757,0.757,0.0,0,604,613,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,0.757,0.7033,0.0,0,0,0,614,620,3.2174 34 | 32,6_home,home,0.0,0.0,0.0,0.7033,0.7033,0.0,0,621,672,0,0,0.0 35 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/bev_mini_00002_60kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,5_leisure,public,11.0,12.2222,11.0,0.9288,0.9288,0.0,0,0,33,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.9288,0.8845,0.0,0,0,0,34,37,2.6557 4 | 2,4_private/ridesharing,public,0.0,0.0,0.0,0.8845,0.8845,0.0,0,38,52,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.8845,0.8777,0.0,0,0,0,53,54,0.4083 6 | 4,6_home,home,0.0,0.0,0.0,0.8777,0.8777,0.0,0,55,73,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.8777,0.8437,0.0,0,0,0,74,78,2.0374 8 | 6,5_leisure,public,0.0,0.0,0.0,0.8437,0.8437,0.0,0,79,168,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.8437,0.8017,0.0,0,0,0,169,221,2.5219 10 | 8,0_work,work,11.0,12.2222,11.0,0.8017,1.0,11.8982,24,222,245,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,1.0,0.9805,0.0,0,0,0,246,252,1.1694 12 | 10,3_shopping,public,11.0,12.2222,11.0,0.9805,0.9805,0.0,0,253,254,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.9805,0.9704,0.0,0,0,0,255,256,0.6089 14 | 12,6_home,home,0.0,0.0,0.0,0.9704,0.9704,0.0,0,257,310,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.9704,0.8772,0.0,0,0,0,311,325,5.5872 16 | 14,0_work,work,11.0,12.2222,11.0,0.8772,1.0,7.3655,39,326,364,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,1.0,0.8761,0.0,0,0,0,365,387,7.4311 18 | 16,6_home,home,0.0,0.0,0.0,0.8761,0.8761,0.0,0,388,394,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.8761,0.8264,0.0,0,0,0,395,410,2.9863 20 | 18,0_work,work,11.0,12.2222,11.0,0.8264,1.0,10.4174,19,411,429,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,1.0,0.9924,0.0,0,0,0,430,431,0.4582 22 | 20,5_leisure,public,11.0,12.2222,11.0,0.9924,0.9924,0.0,0,432,525,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.9924,0.9855,0.0,0,0,0,526,527,0.4138 24 | 22,3_shopping,public,11.0,12.2222,11.0,0.9855,0.9855,0.0,0,528,532,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.9855,0.9722,0.0,0,0,0,533,538,0.7966 26 | 24,5_leisure,public,0.0,0.0,0.0,0.9722,0.9722,0.0,0,539,580,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.9722,0.9178,0.0,0,0,0,581,608,3.265 28 | 26,0_work,work,11.0,12.2222,11.0,0.9178,1.0,4.9336,26,609,634,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,1.0,0.9069,0.0,0,0,0,635,643,5.5867 30 | 28,3_shopping,public,0.0,0.0,0.0,0.9069,0.9069,0.0,0,644,648,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.9069,0.8899,0.0,0,0,0,649,650,1.0222 32 | 30,5_leisure,public,11.0,12.2222,11.0,0.8899,0.8899,0.0,0,651,672,0,0,0.0 33 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/phev_luxury_00000_30kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,6_home,public,3.7,4.1111,3.7,0.8934,1.0,1.3479,7,0,7,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,1.0,0.8633,0.0,0,0,0,8,43,4.1025 4 | 2,3_shopping,public,0.0,0.0,0.0,0.8633,0.8633,0.0,0,44,47,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.8633,0.8322,0.0,0,0,0,48,50,0.9319 6 | 4,6_home,public,3.7,4.1111,3.7,0.8322,1.0,5.0344,60,51,110,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,1.0,0.7887,0.0,0,0,0,111,143,6.3391 8 | 6,4_private/ridesharing,public,0.0,0.0,0.0,0.7887,0.7887,0.0,0,144,148,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.7887,0.7679,0.0,0,0,0,149,150,0.6249 10 | 8,6_home,public,3.7,4.1111,3.7,0.7679,1.0,6.9639,8,151,158,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,1.0,0.6392,0.0,0,0,0,159,220,10.8252 12 | 10,0_work,public,0.0,0.0,0.0,0.6392,0.6392,0.0,0,221,244,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.6392,0.621,0.0,0,0,0,245,246,0.5444 14 | 12,3_shopping,public,0.0,0.0,0.0,0.621,0.621,0.0,0,247,249,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.621,0.5804,0.0,0,0,0,250,252,1.2191 16 | 14,5_leisure,public,11.0,12.2222,11.0,0.5804,1.0,12.5887,6,253,258,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,1.0,0.9404,0.0,0,0,0,259,264,1.7895 18 | 16,4_private/ridesharing,public,0.0,0.0,0.0,0.9404,0.9404,0.0,0,265,269,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.9404,0.8076,0.0,0,0,0,270,273,3.9812 20 | 18,5_leisure,public,0.0,0.0,0.0,0.8076,0.8076,0.0,0,274,276,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.8076,0.7612,0.0,0,0,0,277,285,1.3926 22 | 20,6_home,public,3.7,4.1111,3.7,0.7612,1.0,7.1633,13,286,298,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,1.0,0.9827,0.0,0,0,0,299,320,0.5188 24 | 22,2_school,public,11.0,12.2222,11.0,0.9827,0.9827,0.0,0,321,341,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.9827,0.873,0.0,0,0,0,342,344,3.291 26 | 24,0_work,public,0.0,0.0,0.0,0.873,0.873,0.0,0,345,381,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.873,0.8341,0.0,0,0,0,382,420,1.1671 28 | 26,3_shopping,public,11.0,12.2222,11.0,0.8341,0.8341,0.0,0,421,424,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.8341,0.5881,0.0,0,0,0,425,443,7.3806 30 | 28,6_home,public,3.7,4.1111,3.7,0.5881,0.8347,7.4,8,444,451,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.8347,0.7999,0.0,0,0,0,452,458,1.0465 32 | 30,5_leisure,public,11.0,12.2222,11.0,0.7999,0.7999,0.0,0,459,466,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,0.7999,0.7684,0.0,0,0,0,467,510,0.9453 34 | 32,2_school,public,0.0,0.0,0.0,0.7684,0.7684,0.0,0,511,540,0,0,0.0 35 | 33,driving,,0.0,0.0,0.0,0.7684,0.6112,0.0,0,0,0,541,546,4.7142 36 | 34,4_private/ridesharing,public,0.0,0.0,0.0,0.6112,0.6112,0.0,0,547,552,0,0,0.0 37 | 35,driving,,0.0,0.0,0.0,0.6112,0.0,0.0,0,0,0,553,568,18.3365 38 | 36,6_home,public,3.7,4.1111,3.7,0.0,1.0,30.0,64,569,632,0,0,0.0 39 | 37,driving,,0.0,0.0,0.0,1.0,0.897,0.0,0,0,0,633,641,3.0894 40 | 38,4_private/ridesharing,public,0.0,0.0,0.0,0.897,0.897,0.0,0,642,649,0,0,0.0 41 | 39,driving,,0.0,0.0,0.0,0.897,0.8148,0.0,0,0,0,650,657,2.4673 42 | 40,6_home,public,3.7,4.1111,3.7,0.8148,0.8148,0.0,2,658,672,0,0,0.0 43 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/phev_medium_00000_20kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,5_leisure,public,11.0,12.2222,11.0,0.8557,0.8557,0.0,0,0,59,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.8557,0.7608,0.0,0,0,0,60,61,1.8978 4 | 2,4_private/ridesharing,public,0.0,0.0,0.0,0.7608,0.7608,0.0,0,62,66,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.7608,0.7219,0.0,0,0,0,67,68,0.7768 6 | 4,6_home,public,11.0,12.2222,11.0,0.7219,1.0,5.5612,15,69,83,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,1.0,0.5607,0.0,0,0,0,84,125,8.7857 8 | 6,0_work,work,11.0,12.2222,11.0,0.5607,1.0,8.7857,37,126,162,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,1.0,0.9187,0.0,0,0,0,163,166,1.6269 10 | 8,4_private/ridesharing,public,0.0,0.0,0.0,0.9187,0.9187,0.0,0,167,257,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.9187,0.8798,0.0,0,0,0,258,260,0.7768 12 | 10,6_home,public,11.0,12.2222,11.0,0.8798,1.0,2.4037,40,261,300,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,1.0,0.9032,0.0,0,0,0,301,316,1.9366 14 | 12,3_shopping,public,0.0,0.0,0.0,0.9032,0.9032,0.0,0,317,325,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.9032,0.8668,0.0,0,0,0,326,330,0.7283 16 | 14,5_leisure,public,11.0,12.2222,11.0,0.8668,0.8668,0.0,0,331,407,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.8668,0.8007,0.0,0,0,0,408,414,1.3212 18 | 16,0_work,work,11.0,12.2222,11.0,0.8007,1.0,3.9861,24,415,438,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,1.0,0.878,0.0,0,0,0,439,442,2.4404 20 | 18,6_home,public,11.0,12.2222,11.0,0.878,1.0,2.4404,72,443,514,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,1.0,0.981,0.0,0,0,0,515,518,0.3796 22 | 20,3_shopping,public,0.0,0.0,0.0,0.981,0.981,0.0,0,519,521,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.981,0.8116,0.0,0,0,0,522,530,3.3875 24 | 22,4_private/ridesharing,public,0.0,0.0,0.0,0.8116,0.8116,0.0,0,531,533,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.8116,0.7659,0.0,0,0,0,534,538,0.9154 26 | 24,1_business,public,11.0,12.2222,11.0,0.7659,1.0,4.6826,5,539,543,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,1.0,0.942,0.0,0,0,0,544,546,1.1607 28 | 26,6_home,public,11.0,12.2222,11.0,0.942,1.0,1.1607,89,547,635,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,1.0,0.9119,0.0,0,0,0,636,641,1.7624 30 | 28,4_private/ridesharing,public,0.0,0.0,0.0,0.9119,0.9119,0.0,0,642,643,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.9119,0.7747,0.0,0,0,0,644,648,2.7428 32 | 30,5_leisure,public,11.0,12.2222,11.0,0.7747,1.0,4.5051,7,649,655,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,1.0,0.8268,0.0,0,0,0,656,658,3.4642 34 | 32,6_home,public,11.0,12.2222,11.0,0.8268,0.8268,0.0,63,659,672,0,0,0.0 35 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/5334032/phev_mini_00003_14kWh_SR_Mitte_events.csv: -------------------------------------------------------------------------------- 1 | ,location,use_case,nominal_charging_capacity_kW,grid_charging_capacity_kW,battery_charging_capacity_kW,soc_start,soc_end,chargingdemand_kWh,park_time_timesteps,park_start_timesteps,park_end_timesteps,drive_start_timesteps,drive_end_timesteps,consumption_kWh 2 | 0,6_home,home,0.0,0.0,0.0,0.9191,0.9191,0.0,0,0,17,0,0,0.0 3 | 1,driving,,0.0,0.0,0.0,0.9191,0.8889,0.0,0,0,0,18,30,0.4221 4 | 2,3_shopping,public,3.7,4.1111,3.7,0.8889,0.8889,0.0,0,31,34,0,0,0.0 5 | 3,driving,,0.0,0.0,0.0,0.8889,0.7805,0.0,0,0,0,35,38,1.5176 6 | 4,4_private/ridesharing,public,3.7,4.1111,3.7,0.7805,0.7805,0.0,0,39,41,0,0,0.0 7 | 5,driving,,0.0,0.0,0.0,0.7805,0.7362,0.0,0,0,0,42,43,0.6211 8 | 6,6_home,home,0.0,0.0,0.0,0.7362,0.7362,0.0,0,44,120,0,0,0.0 9 | 7,driving,,0.0,0.0,0.0,0.7362,0.6946,0.0,0,0,0,121,160,0.5824 10 | 8,5_leisure,public,3.7,4.1111,3.7,0.6946,0.6946,0.0,0,161,167,0,0,0.0 11 | 9,driving,,0.0,0.0,0.0,0.6946,0.3066,0.0,0,0,0,168,187,5.431 12 | 10,6_home,home,0.0,0.0,0.0,0.3066,0.3066,0.0,0,188,191,0,0,0.0 13 | 11,driving,,0.0,0.0,0.0,0.3066,0.2312,0.0,0,0,0,192,214,1.0565 14 | 12,0_work,public,0.0,0.0,0.0,0.2312,0.2312,0.0,0,215,245,0,0,0.0 15 | 13,driving,,0.0,0.0,0.0,0.2312,0.1795,0.0,0,0,0,246,255,0.7235 16 | 14,6_home,home,0.0,0.0,0.0,0.1795,0.1795,0.0,0,256,321,0,0,0.0 17 | 15,driving,,0.0,0.0,0.0,0.1795,0.0,0.0,0,0,0,322,328,2.5129 18 | 16,3_shopping,public,3.7,4.1111,3.7,0.0,0.1321,1.85,2,329,330,0,0,0.0 19 | 17,driving,,0.0,0.0,0.0,0.1321,0.0,0.0,0,0,0,331,333,1.85 20 | 18,6_home,home,0.0,0.0,0.0,0.0,0.0,0.0,0,334,352,0,0,0.0 21 | 19,driving,,0.0,0.0,0.0,0.0,0.0,0.0,0,0,0,353,357,0.0 22 | 20,5_leisure,public,0.0,0.0,0.0,0.0,0.0,0.0,0,358,380,0,0,0.0 23 | 21,driving,,0.0,0.0,0.0,0.0,0.0,0.0,0,0,0,381,413,0.0 24 | 22,0_work,public,0.0,0.0,0.0,0.0,0.0,0.0,0,414,453,0,0,0.0 25 | 23,driving,,0.0,0.0,0.0,0.0,0.0,0.0,0,0,0,454,461,0.0 26 | 24,6_home,home,0.0,0.0,0.0,0.0,0.0,0.0,0,462,536,0,0,0.0 27 | 25,driving,,0.0,0.0,0.0,0.0,0.0,0.0,0,0,0,537,545,0.0 28 | 26,4_private/ridesharing,public,3.7,4.1111,3.7,0.0,0.3304,4.625,5,546,550,0,0,0.0 29 | 27,driving,,0.0,0.0,0.0,0.3304,0.2641,0.0,0,0,0,551,554,0.9282 30 | 28,6_home,home,0.0,0.0,0.0,0.2641,0.2641,0.0,0,555,650,0,0,0.0 31 | 29,driving,,0.0,0.0,0.0,0.2641,0.2389,0.0,0,0,0,651,652,0.3523 32 | 30,5_leisure,public,0.0,0.0,0.0,0.2389,0.2389,0.0,0,653,659,0,0,0.0 33 | 31,driving,,0.0,0.0,0.0,0.2389,0.0,0.0,0,0,0,660,668,3.3445 34 | 32,6_home,home,0.0,0.0,0.0,0.0,0.0,0.0,0,669,672,0,0,0.0 35 | -------------------------------------------------------------------------------- /tests/data/simbev_example_scenario/metadata_simbev_run.json: -------------------------------------------------------------------------------- 1 | { 2 | "simBEV_version": "0.1.3", 3 | "scenario": "default_multi", 4 | "timestamp_start": "2022-08-03_152333", 5 | "timestamp_end": "2022-08-03_152348", 6 | "config": { 7 | "region_mode": { 8 | "region_mode": "multi" 9 | }, 10 | "basic": { 11 | "eta_cp": "0.9", 12 | "stepsize": "15", 13 | "start_date": "2011-01-01", 14 | "end_date": "2011-01-07", 15 | "soc_min": "0.2", 16 | "grid_timeseries": "false", 17 | "grid_timeseries_by_usecase": "false" 18 | }, 19 | "rampup_ev": { 20 | "rampup": "regions_mobi_ws.csv" 21 | }, 22 | "tech_data": { 23 | "tech_data": "tech_data.csv" 24 | }, 25 | "charging_probabilities": { 26 | "slow": "charging_point_probability.csv", 27 | "fast": "fast_charging_probability.csv", 28 | "private_charging_home": "0.5", 29 | "private_charging_work": "0.7" 30 | }, 31 | "sim_params": { 32 | "num_threads": "4", 33 | "seed": "3" 34 | } 35 | }, 36 | "tech_data": { 37 | "bev_mini": { 38 | "max_charging_capacity_slow": 11.0, 39 | "max_charging_capacity_fast": 50, 40 | "battery_capacity": 60, 41 | "energy_consumption": 0.1397 42 | }, 43 | "bev_medium": { 44 | "max_charging_capacity_slow": 22.0, 45 | "max_charging_capacity_fast": 50, 46 | "battery_capacity": 90, 47 | "energy_consumption": 0.1746 48 | }, 49 | "bev_luxury": { 50 | "max_charging_capacity_slow": 50.0, 51 | "max_charging_capacity_fast": 150, 52 | "battery_capacity": 110, 53 | "energy_consumption": 0.2096 54 | }, 55 | "phev_mini": { 56 | "max_charging_capacity_slow": 3.7, 57 | "max_charging_capacity_fast": 0, 58 | "battery_capacity": 14, 59 | "energy_consumption": 0.1425 60 | }, 61 | "phev_medium": { 62 | "max_charging_capacity_slow": 11.0, 63 | "max_charging_capacity_fast": 0, 64 | "battery_capacity": 20, 65 | "energy_consumption": 0.1782 66 | }, 67 | "phev_luxury": { 68 | "max_charging_capacity_slow": 11.0, 69 | "max_charging_capacity_fast": 0, 70 | "battery_capacity": 30, 71 | "energy_consumption": 0.2138 72 | } 73 | }, 74 | "charge_prob_slow": { 75 | "work": { 76 | "0": 0.5887, 77 | "3.7": 0.0411, 78 | "11": 0.1645, 79 | "22": 0.1645, 80 | "50": 0.0411 81 | }, 82 | "business": { 83 | "0": 0.64, 84 | "3.7": 0.033, 85 | "11": 0.135, 86 | "22": 0.15, 87 | "50": 0.042 88 | }, 89 | "school": { 90 | "0": 0.5887, 91 | "3.7": 0.0411, 92 | "11": 0.1645, 93 | "22": 0.1645, 94 | "50": 0.0411 95 | }, 96 | "shopping": { 97 | "0": 0.5588, 98 | "3.7": 0.0059, 99 | "11": 0.0618, 100 | "22": 0.253, 101 | "50": 0.1206 102 | }, 103 | "private/ridesharing": { 104 | "0": 0.655, 105 | "3.7": 0.0155, 106 | "11": 0.081, 107 | "22": 0.176, 108 | "50": 0.0725 109 | }, 110 | "leisure": { 111 | "0": 0.6538, 112 | "3.7": 0.0154, 113 | "11": 0.0808, 114 | "22": 0.177, 115 | "50": 0.0731 116 | }, 117 | "home": { 118 | "0": 0.4894, 119 | "3.7": 0.0911, 120 | "11": 0.3402, 121 | "22": 0.0715, 122 | "50": 0.0079 123 | } 124 | }, 125 | "charge_prob_fast": { 126 | "urban": { 127 | "50": 0, 128 | "150": 0.8, 129 | "350": 0.2 130 | }, 131 | "ex-urban": { 132 | "50": 0, 133 | "150": 0.2, 134 | "350": 0.8 135 | } 136 | }, 137 | "car_amount": { 138 | "bev_mini": 60, 139 | "bev_medium": 90, 140 | "bev_luxury": 30, 141 | "phev_mini": 20, 142 | "phev_medium": 40, 143 | "phev_luxury": 10 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /tests/data/tracbev_example_scenario/output_home_05334032.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/tests/data/tracbev_example_scenario/output_home_05334032.gpkg -------------------------------------------------------------------------------- /tests/data/tracbev_example_scenario/output_hpc_05334032.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/tests/data/tracbev_example_scenario/output_hpc_05334032.gpkg -------------------------------------------------------------------------------- /tests/data/tracbev_example_scenario/output_public_05334032.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/tests/data/tracbev_example_scenario/output_public_05334032.gpkg -------------------------------------------------------------------------------- /tests/data/tracbev_example_scenario/output_work_05334032.gpkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openego/eDisGo/63f242a1083700176e1896a637b550be74cd1196/tests/data/tracbev_example_scenario/output_work_05334032.gpkg -------------------------------------------------------------------------------- /tests/flex_opt/test_charging_strategy.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pytest 3 | 4 | from edisgo.edisgo import EDisGo 5 | from edisgo.flex_opt.charging_strategies import charging_strategy 6 | 7 | 8 | class TestChargingStrategy: 9 | """ 10 | Tests all charging strategies implemented in charging_strategies.py. 11 | 12 | """ 13 | 14 | @classmethod 15 | def setup_class(cls): 16 | cls.ding0_path = pytest.ding0_test_network_2_path 17 | cls.simbev_path = pytest.simbev_example_scenario_path 18 | cls.tracbev_path = pytest.tracbev_example_scenario_path 19 | cls.standing_times_path = cls.simbev_path 20 | cls.charging_strategies = ["dumb", "reduced", "residual"] 21 | 22 | cls.edisgo_obj = EDisGo(ding0_grid=cls.ding0_path) 23 | timeindex = pd.date_range("1/1/2011", periods=24 * 7, freq="H") 24 | cls.edisgo_obj.set_timeindex(timeindex) 25 | 26 | cls.edisgo_obj.import_electromobility( 27 | data_source="directory", 28 | charging_processes_dir=cls.simbev_path, 29 | potential_charging_points_dir=cls.tracbev_path, 30 | ) 31 | 32 | def test_charging_strategy(self, caplog): 33 | charging_demand_lst = [] 34 | 35 | ts = self.edisgo_obj.timeseries 36 | 37 | for strategy in self.charging_strategies: 38 | charging_strategy(self.edisgo_obj, strategy=strategy) 39 | 40 | # Check if all charging points have a valid chargingdemand_kWh > 0 41 | df = ts.charging_points_active_power(self.edisgo_obj).loc[ 42 | :, (ts.charging_points_active_power(self.edisgo_obj) <= 0).any(axis=0) 43 | ] 44 | 45 | assert df.shape == ts.charging_points_active_power(self.edisgo_obj).shape 46 | 47 | charging_demand_lst.append( 48 | ts.charging_points_active_power(self.edisgo_obj).sum() 49 | ) 50 | 51 | # Check charging strategy for different timestamp_share_threshold value 52 | charging_strategy( 53 | self.edisgo_obj, strategy="dumb", timestamp_share_threshold=0.5 54 | ) 55 | 56 | # Check if resampling warning is raised 57 | assert ( 58 | "The frequency of the time series data of the edisgo object differs" 59 | in caplog.text 60 | ) 61 | 62 | # Check if all charging points have a valid chargingdemand_kWh > 0 63 | df = ts.charging_points_active_power(self.edisgo_obj).loc[ 64 | :, (ts.charging_points_active_power(self.edisgo_obj) <= 0).any(axis=0) 65 | ] 66 | 67 | assert df.shape == ts.charging_points_active_power(self.edisgo_obj).shape 68 | 69 | # Check charging strategy for different minimum_charging_capacity_factor 70 | charging_strategy( 71 | self.edisgo_obj, strategy="reduced", minimum_charging_capacity_factor=0.5 72 | ) 73 | 74 | # Check if all charging points have a valid chargingdemand_kWh > 0 75 | df = ts.charging_points_active_power(self.edisgo_obj).loc[ 76 | :, (ts.charging_points_active_power(self.edisgo_obj) <= 0).any(axis=0) 77 | ] 78 | 79 | assert df.shape == ts.charging_points_active_power(self.edisgo_obj).shape 80 | 81 | charging_demand_lst.append( 82 | ts.charging_points_active_power(self.edisgo_obj).sum() 83 | ) 84 | 85 | # the chargingdemand_kWh per charging point and therefore in total should 86 | # always be the same 87 | assert all( 88 | (_.round(4) == charging_demand_lst[0].round(4)).all() 89 | for _ in charging_demand_lst 90 | ) 91 | 92 | # ##################### check time index ##################### 93 | assert ts._loads_active_power.index.freqstr == "H" 94 | # change time index to quarter-hourly 95 | timeindex = pd.date_range("1/1/2011", periods=24 * 7, freq="0.25H") 96 | self.edisgo_obj.set_timeindex(timeindex) 97 | charging_strategy(self.edisgo_obj, strategy="dumb") 98 | assert ts._loads_active_power.index.freqstr == "15T" 99 | -------------------------------------------------------------------------------- /tests/flex_opt/test_heat_pump_operation.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pytest 3 | 4 | from edisgo import EDisGo 5 | from edisgo.flex_opt.heat_pump_operation import operating_strategy 6 | 7 | 8 | class TestHeatPumpOperation: 9 | @classmethod 10 | def setup_class(self): 11 | self.timeindex = pd.date_range("1/1/2011 12:00", periods=2, freq="H") 12 | self.cop = pd.DataFrame( 13 | data={ 14 | "hp1": [5.0, 6.0], 15 | "hp2": [7.0, 8.0], 16 | }, 17 | index=self.timeindex, 18 | ) 19 | self.heat_demand = pd.DataFrame( 20 | data={ 21 | "hp1": [1.0, 2.0], 22 | "hp2": [3.0, 4.0], 23 | }, 24 | index=self.timeindex, 25 | ) 26 | self.edisgo = EDisGo( 27 | ding0_grid=pytest.ding0_test_network_path, timeindex=self.timeindex 28 | ) 29 | self.edisgo.heat_pump.cop_df = self.cop 30 | self.edisgo.heat_pump.heat_demand_df = self.heat_demand 31 | 32 | def test_operating_strategy(self): 33 | # test with default parameters 34 | operating_strategy(self.edisgo) 35 | 36 | hp_ts = pd.DataFrame( 37 | data={ 38 | "hp1": [0.2, 1 / 3], 39 | "hp2": [3 / 7, 0.5], 40 | }, 41 | index=self.timeindex, 42 | ) 43 | pd.testing.assert_frame_equal( 44 | self.edisgo.timeseries.loads_active_power, 45 | hp_ts, 46 | ) 47 | hp_ts = pd.DataFrame( 48 | data={ 49 | "hp1": [0.0, 0.0], 50 | "hp2": [0.0, 0.0], 51 | }, 52 | index=self.timeindex, 53 | ) 54 | pd.testing.assert_frame_equal( 55 | self.edisgo.timeseries.loads_reactive_power, 56 | hp_ts, 57 | ) 58 | 59 | # test with providing heat pump names 60 | timestep = self.timeindex[0] 61 | self.edisgo.heat_pump.heat_demand_df.at[timestep, "hp1"] = 0.0 62 | self.edisgo.heat_pump.heat_demand_df.at[timestep, "hp2"] = 0.0 63 | 64 | operating_strategy(self.edisgo, heat_pump_names=["hp1"]) 65 | 66 | assert self.edisgo.timeseries.loads_active_power.at[timestep, "hp1"] == 0.0 67 | assert self.edisgo.timeseries.loads_active_power.at[timestep, "hp2"] == 3 / 7 68 | 69 | # test error raising 70 | msg = "Heat pump operating strategy dummy is not a valid option." 71 | with pytest.raises(ValueError, match=msg): 72 | operating_strategy(self.edisgo, strategy="dummy") 73 | -------------------------------------------------------------------------------- /tests/flex_opt/test_reinforce_grid.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | import numpy as np 4 | import pytest 5 | 6 | from numpy.testing import assert_array_equal 7 | from pandas.testing import assert_frame_equal 8 | 9 | from edisgo import EDisGo 10 | from edisgo.flex_opt.costs import grid_expansion_costs 11 | from edisgo.flex_opt.reinforce_grid import reinforce_grid, run_separate_lv_grids 12 | 13 | 14 | class TestReinforceGrid: 15 | """ 16 | Here, currently only reinforce_grid function is tested. 17 | Other functions in reinforce_grid module are currently tested in test_edisgo module. 18 | """ 19 | 20 | @classmethod 21 | def setup_class(cls): 22 | cls.edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_path) 23 | 24 | cls.edisgo.set_time_series_worst_case_analysis() 25 | 26 | def test_reinforce_grid(self): 27 | modes = [None, "mv", "mvlv", "lv"] 28 | 29 | results_dict = { 30 | mode: reinforce_grid(edisgo=copy.deepcopy(self.edisgo), mode=mode) 31 | for mode in modes 32 | } 33 | 34 | for mode, result in results_dict.items(): 35 | if mode is None: 36 | target = ["mv/lv", "mv", "lv"] 37 | elif mode == "mv": 38 | target = ["mv"] 39 | elif mode == "mvlv": 40 | target = ["mv", "mv/lv"] 41 | elif mode == "lv": 42 | target = ["mv/lv", "lv"] 43 | else: 44 | raise ValueError("Non existing mode") 45 | 46 | assert_array_equal( 47 | np.sort(target), 48 | np.sort(result.grid_expansion_costs.voltage_level.unique()), 49 | ) 50 | 51 | for comparison_mode, comparison_result in results_dict.items(): 52 | if mode != comparison_mode: 53 | with pytest.raises(AssertionError): 54 | assert_frame_equal( 55 | result.equipment_changes, 56 | comparison_result.equipment_changes, 57 | ) 58 | # test reduced analysis 59 | res_reduced = reinforce_grid( 60 | edisgo=copy.deepcopy(self.edisgo), 61 | reduced_analysis=True, 62 | num_steps_loading=2, 63 | ) 64 | assert len(res_reduced.i_res) == 2 65 | 66 | def test_run_separate_lv_grids(self): 67 | edisgo = copy.deepcopy(self.edisgo) 68 | 69 | edisgo.timeseries.scale_timeseries(p_scaling_factor=5, q_scaling_factor=5) 70 | 71 | lv_grids = [copy.deepcopy(g) for g in edisgo.topology.mv_grid.lv_grids] 72 | 73 | run_separate_lv_grids(edisgo) 74 | 75 | edisgo.results.grid_expansion_costs = grid_expansion_costs(edisgo) 76 | lv_grids_new = list(edisgo.topology.mv_grid.lv_grids) 77 | 78 | # check that no new lv grid only consist of the station 79 | for g in lv_grids_new: 80 | if g.id != 0: 81 | assert len(g.buses_df) > 1 82 | 83 | assert len(lv_grids_new) == 26 84 | assert np.isclose(edisgo.results.grid_expansion_costs.total_costs.sum(), 440.06) 85 | 86 | # check if all generators are still present 87 | assert np.isclose( 88 | sum(g.generators_df.p_nom.sum() for g in lv_grids), 89 | sum(g.generators_df.p_nom.sum() for g in lv_grids_new), 90 | ) 91 | 92 | # check if all loads are still present 93 | assert np.isclose( 94 | sum(g.loads_df.p_set.sum() for g in lv_grids), 95 | sum(g.loads_df.p_set.sum() for g in lv_grids_new), 96 | ) 97 | 98 | # check if all storages are still present 99 | assert np.isclose( 100 | sum(g.storage_units_df.p_nom.sum() for g in lv_grids), 101 | sum(g.storage_units_df.p_nom.sum() for g in lv_grids_new), 102 | ) 103 | 104 | # test if power flow works 105 | edisgo.set_time_series_worst_case_analysis() 106 | edisgo.analyze() 107 | -------------------------------------------------------------------------------- /tests/io/test_ding0_import.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import shapely 3 | 4 | from edisgo.io import ding0_import 5 | from edisgo.network.grids import MVGrid 6 | from edisgo.network.topology import Topology 7 | 8 | 9 | class TestImportFromDing0: 10 | @classmethod 11 | def setup_class(self): 12 | self.topology = Topology() 13 | 14 | def test_import_ding0_grid(self): 15 | """Test successful import of ding0 network.""" 16 | 17 | ding0_import.import_ding0_grid(pytest.ding0_test_network_path, self) 18 | 19 | # buses, generators, loads, lines, transformers dataframes 20 | # check number of imported components 21 | assert self.topology.buses_df.shape[0] == 142 22 | assert self.topology.generators_df.shape[0] == 28 23 | assert self.topology.loads_df.shape[0] == 50 24 | assert self.topology.lines_df.shape[0] == 131 25 | assert self.topology.transformers_df.shape[0] == 14 26 | assert self.topology.transformers_hvmv_df.shape[0] == 1 27 | assert self.topology.switches_df.shape[0] == 2 28 | assert self.topology.storage_units_df.shape[0] == 1 29 | 30 | # grid district 31 | assert self.topology.grid_district["population"] == 23358 32 | assert isinstance(self.topology.grid_district["geom"], shapely.geometry.Polygon) 33 | 34 | # grids 35 | assert isinstance(self.topology.mv_grid, MVGrid) 36 | lv_grid = self.topology.get_lv_grid(3) 37 | assert len(lv_grid.buses_df) == 9 38 | 39 | def test_path_error(self): 40 | """Test catching error when path to network does not exist.""" 41 | msg = "Directory wrong_directory does not exist." 42 | with pytest.raises(AssertionError, match=msg): 43 | ding0_import.import_ding0_grid("wrong_directory", self.topology) 44 | 45 | def test_transformer_buses(self): 46 | ding0_import.import_ding0_grid(pytest.ding0_test_network_path, self) 47 | assert ( 48 | self.topology.buses_df.loc[self.topology.transformers_df.bus1].v_nom.values 49 | < self.topology.buses_df.loc[ 50 | self.topology.transformers_df.bus0 51 | ].v_nom.values 52 | ).all() 53 | self.topology.transformers_df.loc[ 54 | "LVStation_7_transformer_1", "bus0" 55 | ] = "Bus_secondary_LVStation_7" 56 | self.topology.transformers_df.loc[ 57 | "LVStation_7_transformer_1", "bus1" 58 | ] = "Bus_primary_LVStation_7" 59 | with pytest.raises(AssertionError): 60 | assert ( 61 | self.topology.buses_df.reindex( 62 | index=self.topology.transformers_df.bus1 63 | ).v_nom.values 64 | < self.topology.buses_df.reindex( 65 | index=self.topology.transformers_df.bus0 66 | ).v_nom.values 67 | ).all() 68 | -------------------------------------------------------------------------------- /tests/io/test_dsm_import.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from edisgo import EDisGo 4 | from edisgo.io import dsm_import 5 | 6 | 7 | class TestDSMImport: 8 | def test_oedb(self): 9 | # test without industrial load 10 | edisgo_object = EDisGo( 11 | ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False 12 | ) 13 | dsm_profiles = dsm_import.oedb( 14 | edisgo_object, scenario="eGon2035", engine=pytest.engine 15 | ) 16 | for dsm_profile in ["e_max", "e_min", "p_max", "p_min"]: 17 | assert dsm_profiles[dsm_profile].shape == (8760, 87) 18 | assert (dsm_profiles["p_min"] <= 0.0).all().all() 19 | assert (dsm_profiles["e_min"] <= 0.0).all().all() 20 | assert (dsm_profiles["p_max"] >= 0.0).all().all() 21 | assert (dsm_profiles["e_max"] >= 0.0).all().all() 22 | 23 | # test with one industrial load 24 | dsm_load = edisgo_object.topology.loads_df[ 25 | (edisgo_object.topology.loads_df.type == "conventional_load") 26 | & (edisgo_object.topology.loads_df.sector == "cts") 27 | ].index[0] 28 | edisgo_object.topology.loads_df.at[dsm_load, "sector"] = "industrial" 29 | edisgo_object.topology.loads_df.at[dsm_load, "building_id"] = 1 30 | 31 | dsm_profiles = dsm_import.oedb( 32 | edisgo_object, scenario="eGon2035", engine=pytest.engine 33 | ) 34 | for dsm_profile in ["e_max", "e_min", "p_max", "p_min"]: 35 | assert dsm_profiles[dsm_profile].shape == (8760, 87) 36 | assert dsm_load in dsm_profiles[dsm_profile].columns 37 | assert (dsm_profiles["p_min"] <= 0.0).all().all() 38 | assert (dsm_profiles["e_min"] <= 0.0).all().all() 39 | assert (dsm_profiles["p_max"] >= 0.0).all().all() 40 | assert (dsm_profiles["e_max"] >= 0.0).all().all() 41 | 42 | def test_get_profiles_per_industrial_load(self): 43 | dsm_profiles = dsm_import.get_profiles_per_industrial_load( 44 | load_ids=[15388, 241, 1], scenario="eGon2035", engine=pytest.engine 45 | ) 46 | for dsm_profile in ["e_max", "e_min", "p_max", "p_min"]: 47 | assert dsm_profiles[dsm_profile].shape == (8760, 3) 48 | assert sorted(dsm_profiles[dsm_profile].columns) == [1, 241, 15388] 49 | assert (dsm_profiles["p_min"] <= 0.0).all().all() 50 | assert (dsm_profiles["e_min"] <= 0.0).all().all() 51 | assert (dsm_profiles["p_max"] >= 0.0).all().all() 52 | assert (dsm_profiles["e_max"] >= 0.0).all().all() 53 | 54 | dsm_profiles = dsm_import.get_profiles_per_industrial_load( 55 | load_ids=[], scenario="eGon2035", engine=pytest.engine 56 | ) 57 | assert dsm_profiles["p_min"].empty 58 | 59 | def test_get_profile_cts(self): 60 | edisgo = EDisGo( 61 | ding0_grid=pytest.ding0_test_network_3_path, legacy_ding0_grids=False 62 | ) 63 | dsm_profiles = dsm_import.get_profile_cts( 64 | edisgo_obj=edisgo, scenario="eGon2035", engine=pytest.engine 65 | ) 66 | for dsm_profile in ["e_max", "e_min", "p_max", "p_min"]: 67 | assert dsm_profiles[dsm_profile].shape == (8760, 85) 68 | assert (dsm_profiles["p_min"] <= 0.0).all().all() 69 | assert (dsm_profiles["e_min"] <= 0.0).all().all() 70 | assert (dsm_profiles["p_max"] >= 0.0).all().all() 71 | assert (dsm_profiles["e_max"] >= 0.0).all().all() 72 | -------------------------------------------------------------------------------- /tests/network/test_components.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pytest 3 | 4 | from edisgo import EDisGo 5 | from edisgo.network.components import Generator, Load, Storage, Switch 6 | 7 | 8 | class TestComponents: 9 | # ToDo add tests for PotentialChargingParks 10 | 11 | @classmethod 12 | def setup_class(self): 13 | self.edisgo_obj = EDisGo(ding0_grid=pytest.ding0_test_network_path) 14 | self.edisgo_obj.set_time_series_worst_case_analysis() 15 | 16 | def test_load_class(self): 17 | """Test Load class getter, setter, methods""" 18 | 19 | load = Load(id="Load_agricultural_LVGrid_1_1", edisgo_obj=self.edisgo_obj) 20 | 21 | # test getter 22 | assert load.id == "Load_agricultural_LVGrid_1_1" 23 | assert load.p_set == 0.0523 24 | assert load.annual_consumption == 238 25 | assert load.sector == "agricultural" 26 | assert load.bus == "Bus_BranchTee_LVGrid_1_2" 27 | assert str(load.grid) == "LVGrid_1" 28 | assert load.voltage_level == "lv" 29 | assert load.geom is None 30 | assert isinstance(load.active_power_timeseries, pd.Series) 31 | assert isinstance(load.reactive_power_timeseries, pd.Series) 32 | 33 | # test setter 34 | load.p_set = 0.06 35 | assert load.p_set == 0.06 36 | load.annual_consumption = 4 37 | assert load.annual_consumption == 4 38 | load.sector = "residential" 39 | assert load.sector == "residential" 40 | load.bus = "Bus_BranchTee_MVGrid_1_1" 41 | assert load.bus == "Bus_BranchTee_MVGrid_1_1" 42 | assert load.grid == self.edisgo_obj.topology.mv_grid 43 | assert load.voltage_level == "mv" 44 | msg = "Given bus ID does not exist." 45 | with pytest.raises(AttributeError, match=msg): 46 | load.bus = "None" 47 | # TODO: add test for active_power_timeseries and reactive_power_timeseries once 48 | # implemented 49 | 50 | def test_generator_class(self): 51 | """Test Generator class getter, setter, methods""" 52 | 53 | gen = Generator(id="GeneratorFluctuating_7", edisgo_obj=self.edisgo_obj) 54 | # GeneratorFluctuating_7,Bus_GeneratorFluctuating_7,PQ,3,wind,1122075,wind_wind_onshore 55 | # test getter 56 | assert gen.id == "GeneratorFluctuating_7" 57 | assert gen.bus == "Bus_GeneratorFluctuating_7" 58 | assert gen.grid == self.edisgo_obj.topology.mv_grid 59 | assert gen.voltage_level == "mv" 60 | assert pytest.approx(gen.geom.x, abs=1e-10) == 7.97127568152858 61 | assert pytest.approx(gen.geom.y, abs=1e-10) == 48.0666552118727 62 | assert gen.nominal_power == 3 63 | assert gen.type == "wind" 64 | assert gen.subtype == "wind_wind_onshore" 65 | assert gen.weather_cell_id == 1122075 66 | assert isinstance(gen.active_power_timeseries, pd.Series) 67 | assert isinstance(gen.reactive_power_timeseries, pd.Series) 68 | 69 | # test setter 70 | gen.nominal_power = 4 71 | assert gen.nominal_power == 4 72 | gen.type = "solar" 73 | assert gen.type == "solar" 74 | gen.subtype = "rooftop" 75 | assert gen.subtype == "rooftop" 76 | gen.weather_cell_id = 2 77 | assert gen.weather_cell_id == 2 78 | gen.bus = "Bus_BranchTee_LVGrid_1_5" 79 | assert gen.bus == "Bus_BranchTee_LVGrid_1_5" 80 | assert str(gen.grid) == "LVGrid_1" 81 | assert gen.voltage_level == "lv" 82 | msg = "Given bus ID does not exist." 83 | with pytest.raises(AttributeError, match=msg): 84 | gen.bus = "None" 85 | 86 | def test_storage_class(self): 87 | """Test Storage class getter, setter, methods""" 88 | 89 | gen = Storage(id="Storage_1", edisgo_obj=self.edisgo_obj) 90 | assert gen.id == "Storage_1" 91 | assert gen.bus == "Bus_MVStation_1" 92 | assert gen.grid == self.edisgo_obj.topology.mv_grid 93 | assert gen.voltage_level == "mv" 94 | assert pytest.approx(gen.geom.x, abs=1e-10) == 7.94859122759009 95 | assert pytest.approx(gen.geom.y, abs=1e-10) == 48.0844553685898 96 | assert gen.nominal_power == 0.4 97 | assert isinstance(gen.active_power_timeseries, pd.Series) 98 | assert isinstance(gen.reactive_power_timeseries, pd.Series) 99 | 100 | # test setter 101 | gen.nominal_power = 4 102 | assert gen.nominal_power == 4 103 | gen.bus = "Bus_BranchTee_LVGrid_1_5" 104 | assert gen.bus == "Bus_BranchTee_LVGrid_1_5" 105 | assert str(gen.grid) == "LVGrid_1" 106 | assert gen.voltage_level == "lv" 107 | msg = "Given bus ID does not exist." 108 | with pytest.raises(AttributeError, match=msg): 109 | gen.bus = "None" 110 | 111 | def test_switch_class(self): 112 | """Test Switch class""" 113 | 114 | switch = Switch(id="circuit_breaker_1", edisgo_obj=self.edisgo_obj) 115 | 116 | # test getter 117 | assert switch.id == "circuit_breaker_1" 118 | assert switch.bus_closed == "BusBar_MVGrid_1_LVGrid_4_MV" 119 | assert switch.bus_open == "virtual_BusBar_MVGrid_1_LVGrid_4_MV" 120 | assert switch.branch == "Line_10031" 121 | assert switch.type == "Switch Disconnector" 122 | assert switch.state == "open" 123 | assert switch.grid == self.edisgo_obj.topology.mv_grid 124 | assert switch.voltage_level == "mv" 125 | 126 | # test setter 127 | switch.type = "test" 128 | assert switch.type == "test" 129 | 130 | # test methods 131 | switch.close() 132 | switch._state = None 133 | assert switch.state == "closed" 134 | switch.open() 135 | switch._state = None 136 | assert switch.state == "open" 137 | -------------------------------------------------------------------------------- /tests/network/test_dsm.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import shutil 4 | 5 | import pandas as pd 6 | import pytest 7 | 8 | from edisgo.network.dsm import DSM 9 | 10 | 11 | class TestDSM: 12 | @pytest.yield_fixture(autouse=True) 13 | def setup_dsm_test_data(self): 14 | timeindex = pd.date_range("1/1/2011 12:00", periods=2, freq="H") 15 | self.p_max = pd.DataFrame( 16 | data={ 17 | "load_1": [5.0, 6.0], 18 | "load_2": [7.0, 8.0], 19 | }, 20 | index=timeindex, 21 | ) 22 | self.p_min = pd.DataFrame( 23 | data={ 24 | "load_1": [1.0, 2.0], 25 | "load_2": [3.0, 4.0], 26 | }, 27 | index=timeindex, 28 | ) 29 | self.e_max = pd.DataFrame( 30 | data={ 31 | "load_1": [9.5, 10.5], 32 | "load_2": [0.9, 0.8], 33 | }, 34 | index=timeindex, 35 | ) 36 | self.e_min = pd.DataFrame( 37 | data={ 38 | "load_1": [9.0, 10.0], 39 | "load_2": [0.7, 0.6], 40 | }, 41 | index=timeindex, 42 | ) 43 | self.dsm = DSM() 44 | self.dsm.p_max = self.p_max 45 | self.dsm.p_min = self.p_min 46 | self.dsm.e_max = self.e_max 47 | self.dsm.e_min = self.e_min 48 | 49 | def test_reduce_memory(self): 50 | # check with default value 51 | assert (self.dsm.p_max.dtypes == "float64").all() 52 | assert (self.dsm.e_max.dtypes == "float64").all() 53 | 54 | self.dsm.reduce_memory() 55 | 56 | assert (self.dsm.p_max.dtypes == "float32").all() 57 | assert (self.dsm.e_max.dtypes == "float32").all() 58 | 59 | # check arguments 60 | self.dsm.reduce_memory(to_type="float16", attr_to_reduce=["p_max"]) 61 | 62 | assert (self.dsm.p_max.dtypes == "float16").all() 63 | assert (self.dsm.e_max.dtypes == "float32").all() 64 | 65 | # check with empty dataframes 66 | self.dsm.e_max = pd.DataFrame() 67 | self.dsm.reduce_memory() 68 | 69 | def test_to_csv(self): 70 | # test with default values 71 | save_dir = os.path.join(os.getcwd(), "dsm_csv") 72 | self.dsm.to_csv(save_dir) 73 | 74 | files_in_dir = os.listdir(save_dir) 75 | assert len(files_in_dir) == 4 76 | assert "p_min.csv" in files_in_dir 77 | assert "p_max.csv" in files_in_dir 78 | assert "e_min.csv" in files_in_dir 79 | assert "e_max.csv" in files_in_dir 80 | 81 | shutil.rmtree(save_dir) 82 | 83 | # test with reduce memory True, to_type = float16 84 | self.dsm.to_csv(save_dir, reduce_memory=True, to_type="float16") 85 | 86 | assert (self.dsm.e_min.dtypes == "float16").all() 87 | files_in_dir = os.listdir(save_dir) 88 | assert len(files_in_dir) == 4 89 | 90 | shutil.rmtree(save_dir, ignore_errors=True) 91 | 92 | def test_from_csv(self): 93 | # write to csv 94 | save_dir = os.path.join(os.getcwd(), "dsm_csv") 95 | self.dsm.to_csv(save_dir) 96 | 97 | # reset DSM object 98 | self.dsm = DSM() 99 | 100 | self.dsm.from_csv(save_dir) 101 | 102 | pd.testing.assert_frame_equal( 103 | self.dsm.p_min, 104 | self.p_min, 105 | check_freq=False, 106 | ) 107 | pd.testing.assert_frame_equal( 108 | self.dsm.e_min, 109 | self.e_min, 110 | check_freq=False, 111 | ) 112 | 113 | shutil.rmtree(save_dir) 114 | 115 | def test_check_integrity(self, caplog): 116 | timeindex = pd.date_range("1/1/2011 12:00", periods=2, freq="H") 117 | # create duplicate entries and loads that do not appear in each DSM dataframe 118 | self.dsm.p_max = pd.concat( 119 | [ 120 | self.dsm.p_max, 121 | pd.DataFrame( 122 | data={ 123 | "load_2": [5.0, 6.0], 124 | "load_3": [7.0, 8.0], 125 | }, 126 | index=timeindex, 127 | ), 128 | ], 129 | axis=1, 130 | ) 131 | self.dsm.p_min = pd.concat( 132 | [ 133 | self.dsm.p_min, 134 | pd.DataFrame( 135 | data={ 136 | "load_2": [5.0, 6.0], 137 | "load_3": [7.0, 8.0], 138 | }, 139 | index=timeindex, 140 | ), 141 | ], 142 | axis=1, 143 | ) 144 | 145 | with caplog.at_level(logging.WARNING): 146 | self.dsm.check_integrity() 147 | assert len(caplog.messages) == 5 148 | assert "DSM timeseries contain the following duplicates:" in caplog.text 149 | assert "DSM timeseries e_min is missing the following entries:" in caplog.text 150 | assert "DSM timeseries e_max is missing the following entries:" in caplog.text 151 | assert ( 152 | "DSM timeseries p_min contains values larger than zero, which is not " 153 | "allowed." in caplog.text 154 | ) 155 | assert ( 156 | "DSM timeseries e_min contains values larger than zero, which is not " 157 | "allowed." in caplog.text 158 | ) 159 | 160 | caplog.clear() 161 | # check for empty DSM class 162 | self.dsm = DSM() 163 | with caplog.at_level(logging.WARNING): 164 | self.dsm.check_integrity() 165 | assert len(caplog.text) == 0 166 | -------------------------------------------------------------------------------- /tests/network/test_results.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | import pandas as pd 5 | 6 | from edisgo.network.results import Results 7 | from edisgo.tools.config import Config 8 | 9 | 10 | class TestResults: 11 | """ 12 | Tests Results class. 13 | 14 | """ 15 | 16 | @classmethod 17 | def setup_class(self): 18 | self.config = Config() 19 | self.results = Results(self) 20 | 21 | def test_to_csv(self): 22 | # create dummy results 23 | timeindex = pd.date_range( 24 | "2011-04-16 00:00:00", "2011-04-16 02:00:00", freq="1H" 25 | ) 26 | self.results.pfa_v_mag_pu_seed = pd.DataFrame( 27 | data=1.1094890328530983, 28 | columns=["bus1", "bus2"], 29 | index=timeindex, 30 | dtype="float64", 31 | ) 32 | self.results.v_res = self.results.pfa_v_mag_pu_seed.copy() 33 | self.results.grid_expansion_costs = pd.DataFrame( 34 | data={"total_costs": [2, 3], "quantity": [1, 1]}, 35 | index=["line1", "transformer2"], 36 | ) 37 | 38 | cur_dir = os.getcwd() 39 | 40 | # test with default values 41 | self.results.to_csv(cur_dir) 42 | 43 | files_in_powerflow_results = os.listdir( 44 | os.path.join(cur_dir, "powerflow_results") 45 | ) 46 | assert len(files_in_powerflow_results) == 1 47 | assert files_in_powerflow_results[0] == "voltages_pu.csv" 48 | files_in_grid_expansion_results = os.listdir( 49 | os.path.join(cur_dir, "grid_expansion_results") 50 | ) 51 | assert len(files_in_grid_expansion_results) == 1 52 | assert files_in_grid_expansion_results[0] == "grid_expansion_costs.csv" 53 | 54 | shutil.rmtree(os.path.join(cur_dir, "powerflow_results")) 55 | 56 | # test with save_seed=True 57 | self.results.to_csv(cur_dir, save_seed=True) 58 | 59 | files_in_powerflow_results = os.listdir( 60 | os.path.join(cur_dir, "powerflow_results") 61 | ) 62 | assert len(files_in_powerflow_results) == 2 63 | assert "pfa_v_mag_pu_seed.csv" in files_in_powerflow_results 64 | 65 | shutil.rmtree(os.path.join(cur_dir, "powerflow_results")) 66 | shutil.rmtree(os.path.join(cur_dir, "grid_expansion_results")) 67 | 68 | # test with provided parameters and reduce memory True 69 | self.results.pfa_p = self.results.v_res 70 | self.results.to_csv( 71 | cur_dir, 72 | parameters={"powerflow_results": ["v_res"]}, 73 | reduce_memory=True, 74 | ) 75 | 76 | files_in_powerflow_results = os.listdir( 77 | os.path.join(cur_dir, "powerflow_results") 78 | ) 79 | assert len(files_in_powerflow_results) == 1 80 | assert "voltages_pu.csv" in files_in_powerflow_results 81 | assert not os.path.isfile( 82 | os.path.join(cur_dir, "grid_expansion_results", "grid_expansion_costs.csv") 83 | ) 84 | assert self.results.v_res.bus1.dtype == "float32" 85 | 86 | shutil.rmtree(os.path.join(cur_dir, "powerflow_results")) 87 | 88 | os.remove(os.path.join(cur_dir, "measures.csv")) 89 | 90 | def test_from_csv(self): 91 | # create dummy results and save to csv 92 | timeindex = pd.date_range( 93 | "2011-04-16 00:00:00", "2011-04-16 02:00:00", freq="1H" 94 | ) 95 | pfa_v_mag_pu_seed = pd.DataFrame( 96 | data=1.1094890328530983, 97 | columns=["bus1", "bus2"], 98 | index=timeindex, 99 | dtype="float64", 100 | ) 101 | self.results.pfa_v_mag_pu_seed = pfa_v_mag_pu_seed 102 | self.results.v_res = self.results.pfa_v_mag_pu_seed.copy() 103 | self.results.pfa_p = self.results.pfa_v_mag_pu_seed.copy() 104 | self.results.pfa_q = self.results.pfa_v_mag_pu_seed.copy() 105 | grid_expansion_costs = pd.DataFrame( 106 | data={"total_costs": [2, 3], "quantity": [1, 1]}, 107 | index=["line1", "transformer2"], 108 | ) 109 | self.results.grid_expansion_costs = grid_expansion_costs 110 | self.results.measures = "test" 111 | 112 | cur_dir = os.getcwd() 113 | 114 | self.results.to_csv(cur_dir, save_seed=True) 115 | 116 | # reset self.results 117 | self.results = Results(self) 118 | 119 | # test with default values 120 | self.results.from_csv(cur_dir) 121 | 122 | pd.testing.assert_frame_equal( 123 | self.results.pfa_v_mag_pu_seed, pfa_v_mag_pu_seed, check_freq=False 124 | ) 125 | pd.testing.assert_frame_equal( 126 | self.results.v_res, pfa_v_mag_pu_seed, check_freq=False 127 | ) 128 | pd.testing.assert_frame_equal( 129 | self.results.grid_expansion_costs, grid_expansion_costs 130 | ) 131 | assert self.results.measures == ["original", "test"] 132 | 133 | # reset self.results 134 | self.results = Results(self) 135 | 136 | # test with given parameters 137 | self.results.from_csv(cur_dir, parameters={"powerflow_results": ["v_res"]}) 138 | 139 | pd.testing.assert_frame_equal( 140 | self.results.v_res, pfa_v_mag_pu_seed, check_freq=False 141 | ) 142 | assert self.results.pfa_v_mag_pu_seed.empty 143 | assert self.results.grid_expansion_costs.empty 144 | 145 | shutil.rmtree(os.path.join(cur_dir, "powerflow_results")) 146 | shutil.rmtree(os.path.join(cur_dir, "grid_expansion_results")) 147 | 148 | os.remove(os.path.join(cur_dir, "measures.csv")) 149 | -------------------------------------------------------------------------------- /tests/test_examples.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | import pytest 5 | import pytest_notebook 6 | 7 | 8 | class TestExamples: 9 | @classmethod 10 | def setup_class(self): 11 | self.examples_dir_path = os.path.join( 12 | os.path.dirname(os.path.dirname(__file__)), "examples" 13 | ) 14 | 15 | @pytest.mark.slow 16 | def test_plot_example_ipynb(self): 17 | path = os.path.join(self.examples_dir_path, "plot_example.ipynb") 18 | notebook = pytest_notebook.notebook.load_notebook(path=path) 19 | result = pytest_notebook.execution.execute_notebook( 20 | notebook, 21 | with_coverage=False, 22 | timeout=600, 23 | ) 24 | if result.exec_error is not None: 25 | print(result.exec_error) 26 | assert result.exec_error is None 27 | 28 | @pytest.mark.slow 29 | def test_electromobility_example_ipynb(self): 30 | path = os.path.join(self.examples_dir_path, "electromobility_example.ipynb") 31 | notebook = pytest_notebook.notebook.load_notebook(path=path) 32 | result = pytest_notebook.execution.execute_notebook( 33 | notebook, 34 | with_coverage=False, 35 | timeout=600, 36 | ) 37 | if result.exec_error is not None: 38 | print(result.exec_error) 39 | assert result.exec_error is None 40 | 41 | @pytest.mark.slow 42 | def test_edisgo_simple_example_ipynb(self): 43 | path = os.path.join(self.examples_dir_path, "edisgo_simple_example.ipynb") 44 | notebook = pytest_notebook.notebook.load_notebook(path=path) 45 | result = pytest_notebook.execution.execute_notebook( 46 | notebook, 47 | with_coverage=False, 48 | timeout=600, 49 | ) 50 | if result.exec_error is not None: 51 | print(result.exec_error) 52 | assert result.exec_error is None 53 | 54 | @classmethod 55 | def teardown_class(cls): 56 | logger = logging.getLogger("edisgo") 57 | logger.handlers.clear() 58 | logger.propagate = True 59 | -------------------------------------------------------------------------------- /tests/tools/test_geopandas_helper.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from edisgo import EDisGo 4 | from edisgo.tools import geopandas_helper 5 | 6 | 7 | class TestGeopandasHelper: 8 | @classmethod 9 | def setup_class(self): 10 | self.edisgo = EDisGo(ding0_grid=pytest.ding0_test_network_path) 11 | 12 | def test_to_geopandas(self): 13 | # further tests of this function are conducted in test_topology.py 14 | # test MV grid 15 | data = geopandas_helper.to_geopandas(self.edisgo.topology.mv_grid, 4326) 16 | assert data.buses_gdf.shape[0] == self.edisgo.topology.mv_grid.buses_df.shape[0] 17 | assert ( 18 | data.buses_gdf.shape[1] 19 | == self.edisgo.topology.mv_grid.buses_df.shape[1] + 1 - 2 20 | ) 21 | assert "geometry" in data.buses_gdf.columns 22 | 23 | assert data.lines_gdf.shape[0] == self.edisgo.topology.mv_grid.lines_df.shape[0] 24 | assert ( 25 | data.lines_gdf.shape[1] 26 | == self.edisgo.topology.mv_grid.lines_df.shape[1] + 2 27 | ) 28 | assert "geometry" in data.lines_gdf.columns 29 | 30 | assert data.loads_gdf.shape[0] == self.edisgo.topology.mv_grid.loads_df.shape[0] 31 | assert ( 32 | data.loads_gdf.shape[1] 33 | == self.edisgo.topology.mv_grid.loads_df.shape[1] + 2 34 | ) 35 | assert "geometry" in data.loads_gdf.columns 36 | 37 | assert ( 38 | data.generators_gdf.shape[0] 39 | == self.edisgo.topology.mv_grid.generators_df.shape[0] 40 | ) 41 | assert ( 42 | data.generators_gdf.shape[1] 43 | == self.edisgo.topology.mv_grid.generators_df.shape[1] + 2 44 | ) 45 | assert "geometry" in data.generators_gdf.columns 46 | 47 | assert ( 48 | data.storage_units_gdf.shape[0] 49 | == self.edisgo.topology.mv_grid.storage_units_df.shape[0] 50 | ) 51 | assert ( 52 | data.storage_units_gdf.shape[1] 53 | == self.edisgo.topology.mv_grid.storage_units_df.shape[1] + 2 54 | ) 55 | assert "geometry" in data.storage_units_gdf.columns 56 | 57 | assert ( 58 | data.transformers_gdf.shape[0] 59 | == self.edisgo.topology.mv_grid.transformers_df.shape[0] 60 | ) 61 | assert ( 62 | data.transformers_gdf.shape[1] 63 | == self.edisgo.topology.mv_grid.transformers_df.shape[1] + 2 64 | ) 65 | assert "geometry" in data.transformers_gdf.columns 66 | -------------------------------------------------------------------------------- /tests/tools/test_logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | import pytest 5 | 6 | from edisgo.tools.logger import setup_logger 7 | 8 | 9 | def check_file_output(filename, output): 10 | with open(filename) as file: 11 | last_line = file.readlines()[-1].split(" ")[3:] 12 | last_line = " ".join(last_line) 13 | assert last_line == output 14 | 15 | 16 | def reset_loggers(filename): 17 | logger = logging.getLogger("edisgo") 18 | logger.handlers.clear() 19 | logger.propagate = True 20 | # try removing file - when run on github for Windows removing the file leads 21 | # to a PermissionError 22 | try: 23 | os.remove(filename) 24 | except PermissionError: 25 | pass 26 | 27 | 28 | class TestClass: 29 | def test_setup_logger(self): 30 | filename = os.path.join( 31 | os.path.expanduser("~"), ".edisgo", "log", "test_log.log" 32 | ) 33 | if os.path.exists(filename): 34 | os.remove(filename) 35 | 36 | setup_logger( 37 | loggers=[ 38 | {"name": "root", "file_level": "debug", "stream_level": "debug"}, 39 | {"name": "edisgo", "file_level": "debug", "stream_level": "debug"}, 40 | ], 41 | file_name="test_log.log", 42 | log_dir="default", 43 | ) 44 | 45 | logger = logging.getLogger("edisgo") 46 | # Test that edisgo logger writes to file. 47 | logger.debug("root") 48 | check_file_output(filename, "edisgo - DEBUG: root\n") 49 | # Test that root logger writes to file. 50 | logging.debug("root") 51 | check_file_output(filename, "root - DEBUG: root\n") 52 | 53 | reset_loggers(filename) 54 | 55 | @pytest.mark.runonlinux 56 | def test_setup_logger_2(self): 57 | """ 58 | This test is only run on linux, as the log file is written to the user 59 | home directory, which is not allowed when tests are run on github. 60 | 61 | """ 62 | 63 | # delete any existing log files 64 | log_files = [_ for _ in os.listdir(os.getcwd()) if ".log" in _] 65 | for log_file in log_files: 66 | os.remove(log_file) 67 | 68 | setup_logger( 69 | loggers=[ 70 | {"name": "edisgo", "file_level": "debug", "stream_level": "debug"}, 71 | ], 72 | reset_loggers=True, 73 | debug_message=True, 74 | ) 75 | logger = logging.getLogger("edisgo") 76 | 77 | filename = [_ for _ in os.listdir(os.getcwd()) if ".log" in _][0] 78 | # Test that edisgo logger writes to file. 79 | logger.debug("edisgo") 80 | check_file_output(filename, "edisgo - DEBUG: edisgo\n") 81 | # Test that root logger doesn't write to file. 82 | logging.debug("root") 83 | check_file_output(filename, "edisgo - DEBUG: edisgo\n") 84 | 85 | reset_loggers(filename) 86 | -------------------------------------------------------------------------------- /tests/tools/test_plots.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | import pytest 4 | 5 | from edisgo import EDisGo 6 | from edisgo.tools.plots import chosen_graph, plot_dash_app, plot_plotly 7 | 8 | 9 | class TestPlots: 10 | @classmethod 11 | def setup_class(cls): 12 | cls.edisgo_root = EDisGo(ding0_grid=pytest.ding0_test_network_path) 13 | cls.edisgo_root.set_time_series_worst_case_analysis() 14 | cls.edisgo_analyzed = copy.deepcopy(cls.edisgo_root) 15 | cls.edisgo_reinforced = copy.deepcopy(cls.edisgo_root) 16 | cls.edisgo_analyzed.analyze() 17 | cls.edisgo_reinforced.reinforce() 18 | cls.edisgo_reinforced.results.equipment_changes.loc[ 19 | "Line_10006", "change" 20 | ] = "added" 21 | 22 | @pytest.mark.parametrize( 23 | "line_color," 24 | "node_color," 25 | "line_result_selection," 26 | "node_result_selection," 27 | "plot_map," 28 | "pseudo_coordinates", 29 | [ 30 | ("loading", "voltage_deviation", "min", "min", True, True), 31 | ("relative_loading", "adjacencies", "max", "max", False, False), 32 | ("reinforce", "adjacencies", "max", "min", True, False), 33 | ], 34 | ) 35 | @pytest.mark.parametrize( 36 | "selected_timesteps", 37 | [ 38 | None, 39 | "1970-01-01 01:00:00", 40 | ["1970-01-01 01:00:00", "1970-01-01 03:00:00"], 41 | ], 42 | ) 43 | @pytest.mark.parametrize( 44 | "node_selection", [False, ["Bus_MVStation_1", "Bus_BranchTee_MVGrid_1_5"]] 45 | ) 46 | @pytest.mark.parametrize( 47 | "edisgo_obj_name", ["edisgo_root", "edisgo_analyzed", "edisgo_reinforced"] 48 | ) 49 | @pytest.mark.parametrize("grid_name", ["None", "LVGrid"]) 50 | def test_plot_plotly( 51 | self, 52 | edisgo_obj_name, 53 | grid_name, 54 | line_color, 55 | node_color, 56 | line_result_selection, 57 | node_result_selection, 58 | selected_timesteps, 59 | plot_map, 60 | pseudo_coordinates, 61 | node_selection, 62 | ): 63 | if edisgo_obj_name == "edisgo_root": 64 | edisgo_obj = self.edisgo_root 65 | elif edisgo_obj_name == "edisgo_analyzed": 66 | edisgo_obj = self.edisgo_analyzed 67 | elif edisgo_obj_name == "edisgo_reinforced": 68 | edisgo_obj = self.edisgo_reinforced 69 | 70 | if grid_name == "None": 71 | grid = None 72 | elif grid_name == "LVGrid": 73 | grid = list(edisgo_obj.topology.mv_grid.lv_grids)[1] 74 | 75 | if (grid_name == "LVGrid") and (node_selection is not False): 76 | with pytest.raises(ValueError): 77 | plot_plotly( 78 | edisgo_obj=edisgo_obj, 79 | grid=grid, 80 | line_color=line_color, 81 | node_color=node_color, 82 | line_result_selection=line_result_selection, 83 | node_result_selection=node_result_selection, 84 | selected_timesteps=selected_timesteps, 85 | plot_map=plot_map, 86 | pseudo_coordinates=pseudo_coordinates, 87 | node_selection=node_selection, 88 | ) 89 | else: 90 | plot_plotly( 91 | edisgo_obj=edisgo_obj, 92 | grid=grid, 93 | line_color=line_color, 94 | node_color=node_color, 95 | line_result_selection=line_result_selection, 96 | node_result_selection=node_result_selection, 97 | selected_timesteps=selected_timesteps, 98 | plot_map=plot_map, 99 | pseudo_coordinates=pseudo_coordinates, 100 | node_selection=node_selection, 101 | ) 102 | 103 | def test_chosen_graph(self): 104 | chosen_graph(edisgo_obj=self.edisgo_root, selected_grid="Grid") 105 | grid = str(self.edisgo_root.topology.mv_grid) 106 | chosen_graph(edisgo_obj=self.edisgo_root, selected_grid=grid) 107 | grid = list(map(str, self.edisgo_root.topology.mv_grid.lv_grids))[0] 108 | chosen_graph(edisgo_obj=self.edisgo_root, selected_grid=grid) 109 | 110 | def test_plot_dash_app(self): 111 | # TODO: at the moment this doesn't really test anything. Add meaningful tests. 112 | # test if any errors occur when only passing one edisgo object 113 | plot_dash_app( 114 | edisgo_objects=self.edisgo_root, 115 | ) 116 | 117 | # test if any errors occur when passing multiple edisgo objects 118 | plot_dash_app( # noqa: F841 119 | edisgo_objects={ 120 | "edisgo_1": self.edisgo_root, 121 | "edisgo_2": self.edisgo_reinforced, 122 | } 123 | ) 124 | -------------------------------------------------------------------------------- /tests/tools/test_pseudo_coordinates.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | 4 | from edisgo import EDisGo 5 | from edisgo.tools.pseudo_coordinates import make_pseudo_coordinates 6 | 7 | 8 | class TestPseudoCoordinates: 9 | @classmethod 10 | def setup_class(cls): 11 | cls.edisgo_root = EDisGo(ding0_grid=pytest.ding0_test_network_path) 12 | 13 | def test_make_pseudo_coordinates(self): 14 | # test coordinates before 15 | coordinates = self.edisgo_root.topology.buses_df.loc[ 16 | "Bus_BranchTee_LVGrid_1_9", ["x", "y"] 17 | ] 18 | assert round(coordinates[0], 5) != round(7.943307, 5) 19 | assert round(coordinates[1], 5) != round(48.080396, 5) 20 | 21 | # make pseudo coordinates 22 | make_pseudo_coordinates(self.edisgo_root, mv_coordinates=True) 23 | 24 | # test if the right coordinates are set for one node 25 | coordinates = self.edisgo_root.topology.buses_df.loc[ 26 | "Bus_BranchTee_LVGrid_1_9", ["x", "y"] 27 | ] 28 | assert round(coordinates[0], 5) == round(7.943307, 5) 29 | assert round(coordinates[1], 5) == round(48.080396, 5) 30 | 31 | assert not self.edisgo_root.topology.buses_df.x.isin([np.NaN]).any() 32 | --------------------------------------------------------------------------------